feat(S-301): Test-drive and implement async default for run and dispatch

This commit is contained in:
2026-05-19 21:42:58 -05:00
parent e11c36b7d8
commit 62840b908e
2 changed files with 468 additions and 62 deletions
+95 -39
View File
@@ -1,6 +1,7 @@
import minimist from "minimist";
import { detectClients as realDetectClients } from "./detect.js";
import { executePrompt as realExecutePrompt } from "./execute.js";
import { startJob as realStartJob } from "./jobs.js";
import { resolveClient as realResolveClient } from "./dispatch.js";
import { resolveConfig as realResolveConfig } from "./config.js";
import { CLIENT_NAMES } from "./constants.js";
@@ -9,6 +10,7 @@ import {
type ClientInfo,
type ExecResult,
type DebugInfo,
type Job,
ClientNotFoundError,
} from "./types.js";
@@ -19,6 +21,11 @@ export interface CliDeps {
prompt: string,
options?: { timeoutMs?: number; debug?: boolean; onDebug?: (info: DebugInfo) => void }
) => Promise<ExecResult>;
startJob?: (
client: ClientName,
prompt: string,
options?: { timeoutMs?: number; debug?: boolean; onDebug?: (info: DebugInfo) => void }
) => Promise<Job>;
resolveClient?: (
prompt: string,
config?: { client?: ClientName; defaultClient?: ClientName }
@@ -46,6 +53,7 @@ export async function main(
): Promise<number> {
const detectClients = deps.detectClients ?? realDetectClients;
const executePrompt = deps.executePrompt ?? realExecutePrompt;
const startJob = deps.startJob ?? realStartJob;
const resolveClient = deps.resolveClient ?? realResolveClient;
const resolveConfig = deps.resolveConfig ?? realResolveConfig;
const stdoutWrite = deps.stdoutWrite ?? ((c: string) => process.stdout.write(c));
@@ -57,7 +65,7 @@ export async function main(
const args = minimist(parseArgs, {
string: ["client", "prompt", "timeout"],
boolean: ["json", "text", "help", "debug"],
boolean: ["json", "text", "help", "debug", "sync"],
alias: { h: "help" },
});
@@ -123,27 +131,51 @@ export async function main(
const timeoutMs =
Number.isFinite(parsedTimeout) ? parsedTimeout : config.timeout;
try {
const result = await executePrompt(client, prompt, {
timeoutMs,
debug,
onDebug: debug ? (info) => stderrWrite(JSON.stringify(info) + "\n") : undefined,
});
if (jsonMode) {
console.log(JSON.stringify(result, null, 2));
} else {
if (result.stdout) stdoutWrite(result.stdout);
if (result.stderr) stderrWrite(result.stderr);
if (args.sync) {
try {
const result = await executePrompt(client, prompt, {
timeoutMs,
debug,
onDebug: debug ? (info) => stderrWrite(JSON.stringify(info) + "\n") : undefined,
});
if (jsonMode) {
console.log(JSON.stringify(result, null, 2));
} else {
if (result.stdout) stdoutWrite(result.stdout);
if (result.stderr) stderrWrite(result.stderr);
}
return 0;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
if (jsonMode) {
console.error(JSON.stringify({ error: message }, null, 2));
} else {
console.error(message);
}
return 1;
}
return 0;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
if (jsonMode) {
console.error(JSON.stringify({ error: message }, null, 2));
} else {
console.error(message);
} else {
try {
const job = await startJob(client, prompt, {
timeoutMs,
debug,
onDebug: debug ? (info) => stderrWrite(JSON.stringify(info) + "\n") : undefined,
});
if (jsonMode) {
console.log(JSON.stringify({ jobId: job.id, client: job.client, status: job.status }, null, 2));
} else {
console.log(`Job ${job.id} started (${job.client}): ${job.status}`);
}
return 0;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
if (jsonMode) {
console.error(JSON.stringify({ error: message }, null, 2));
} else {
console.error(message);
}
return 1;
}
return 1;
}
}
@@ -185,27 +217,51 @@ export async function main(
const timeoutMs =
Number.isFinite(parsedTimeout) ? parsedTimeout : config.timeout;
try {
const result = await executePrompt(client, prompt, {
timeoutMs,
debug,
onDebug: debug ? (info) => stderrWrite(JSON.stringify(info) + "\n") : undefined,
});
if (jsonMode) {
console.log(JSON.stringify(result, null, 2));
} else {
if (result.stdout) stdoutWrite(result.stdout);
if (result.stderr) stderrWrite(result.stderr);
if (args.sync) {
try {
const result = await executePrompt(client, prompt, {
timeoutMs,
debug,
onDebug: debug ? (info) => stderrWrite(JSON.stringify(info) + "\n") : undefined,
});
if (jsonMode) {
console.log(JSON.stringify(result, null, 2));
} else {
if (result.stdout) stdoutWrite(result.stdout);
if (result.stderr) stderrWrite(result.stderr);
}
return 0;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
if (jsonMode) {
console.error(JSON.stringify({ error: message }, null, 2));
} else {
console.error(message);
}
return 1;
}
return 0;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
if (jsonMode) {
console.error(JSON.stringify({ error: message }, null, 2));
} else {
console.error(message);
} else {
try {
const job = await startJob(client, prompt, {
timeoutMs,
debug,
onDebug: debug ? (info) => stderrWrite(JSON.stringify(info) + "\n") : undefined,
});
if (jsonMode) {
console.log(JSON.stringify({ jobId: job.id, client: job.client, status: job.status }, null, 2));
} else {
console.log(`Job ${job.id} started (${job.client}): ${job.status}`);
}
return 0;
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
if (jsonMode) {
console.error(JSON.stringify({ error: message }, null, 2));
} else {
console.error(message);
}
return 1;
}
return 1;
}
}