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)
56 lines
1.4 KiB
TypeScript
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();
|
|
});
|
|
}
|