Files
gitea-axi/src/subprocess.ts
alexion 38026f963d feat: scaffold CLI and minimal issue list (task 0001)
Tracer bullet for gitea-axi: runnable npm package on axi-sdk-js with
gitea-js as the sole HTTP layer, ESM on Node 20+.

- issue list with --state/--limit, default fields, count line from
  X-Total-Count, type=issues guard, explicit empty state, and next-step
  suggestions
- repo context detection from the git origin remote (SSH/scp/HTTPS),
  tea credential discovery with the three-way login-matching split, and
  -R/--repo and --login overrides (flag > env > auto)
- token retrieval via tea login helper get: tea's login list JSON
  carries no token (ADR 0001 amended)
- full AxiError classification table with path-based 404 split, TOON
  errors on stdout, exit codes 0/1/2
- test mode (GITEA_AXI_API_URL/TOKEN/REPO) suppressing subprocesses,
  fixture server, and vitest suites driving the CLI seam (50 tests)
2026-07-11 07:11:07 -04:00

56 lines
1.4 KiB
TypeScript

import { spawn } from "node:child_process";
export interface SubprocessResult {
enoent: boolean;
code: number | null;
stdout: string;
stderr: string;
}
export interface SubprocessOptions {
cwd?: string;
env: Record<string, string | undefined>;
stdin?: string;
}
export function runSubprocess(
command: string,
args: string[],
options: SubprocessOptions,
): Promise<SubprocessResult> {
return new Promise((resolve, reject) => {
const child = spawn(command, args, {
cwd: options.cwd,
env: options.env as NodeJS.ProcessEnv,
stdio: ["pipe", "pipe", "pipe"],
});
let stdout = "";
let stderr = "";
child.stdout.setEncoding("utf8");
child.stderr.setEncoding("utf8");
child.stdout.on("data", (chunk: string) => {
stdout += chunk;
});
child.stderr.on("data", (chunk: string) => {
stderr += chunk;
});
child.on("error", (error: NodeJS.ErrnoException) => {
if (error.code === "ENOENT") {
resolve({ enoent: true, code: null, stdout, stderr });
} else {
reject(error);
}
});
child.on("close", (code) => {
resolve({ enoent: false, code, stdout, stderr });
});
if (options.stdin !== undefined) {
// The child may exit without reading stdin; a late write then raises
// EPIPE, which must not crash the parent.
child.stdin.on("error", () => {});
child.stdin.write(options.stdin);
}
child.stdin.end();
});
}