@claudexor/cli 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +22 -0
- package/dist/args.d.ts +12 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +88 -0
- package/dist/args.js.map +1 -0
- package/dist/attachment-resolver.d.ts +11 -0
- package/dist/attachment-resolver.d.ts.map +1 -0
- package/dist/attachment-resolver.js +61 -0
- package/dist/attachment-resolver.js.map +1 -0
- package/dist/capabilities.d.ts +13 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +90 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/claudexord.d.ts +3 -0
- package/dist/claudexord.d.ts.map +1 -0
- package/dist/claudexord.js +564 -0
- package/dist/claudexord.js.map +1 -0
- package/dist/cli-io.d.ts +28 -0
- package/dist/cli-io.d.ts.map +1 -0
- package/dist/cli-io.js +37 -0
- package/dist/cli-io.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1459 -0
- package/dist/cli.js.map +1 -0
- package/dist/command-registry.d.ts +105 -0
- package/dist/command-registry.d.ts.map +1 -0
- package/dist/command-registry.js +516 -0
- package/dist/command-registry.js.map +1 -0
- package/dist/daemon-lifecycle.d.ts +18 -0
- package/dist/daemon-lifecycle.d.ts.map +1 -0
- package/dist/daemon-lifecycle.js +62 -0
- package/dist/daemon-lifecycle.js.map +1 -0
- package/dist/daemon-run.d.ts +86 -0
- package/dist/daemon-run.d.ts.map +1 -0
- package/dist/daemon-run.js +269 -0
- package/dist/daemon-run.js.map +1 -0
- package/dist/decision.d.ts +18 -0
- package/dist/decision.d.ts.map +1 -0
- package/dist/decision.js +46 -0
- package/dist/decision.js.map +1 -0
- package/dist/live.d.ts +26 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +311 -0
- package/dist/live.js.map +1 -0
- package/dist/mcp-runner.d.ts +41 -0
- package/dist/mcp-runner.d.ts.map +1 -0
- package/dist/mcp-runner.js +306 -0
- package/dist/mcp-runner.js.map +1 -0
- package/dist/ops-commands.d.ts +11 -0
- package/dist/ops-commands.d.ts.map +1 -0
- package/dist/ops-commands.js +358 -0
- package/dist/ops-commands.js.map +1 -0
- package/dist/orchestrate-options.d.ts +9 -0
- package/dist/orchestrate-options.d.ts.map +1 -0
- package/dist/orchestrate-options.js +16 -0
- package/dist/orchestrate-options.js.map +1 -0
- package/dist/orphan-reaper.d.ts +9 -0
- package/dist/orphan-reaper.d.ts.map +1 -0
- package/dist/orphan-reaper.js +97 -0
- package/dist/orphan-reaper.js.map +1 -0
- package/dist/orphan-sweeper.d.ts +7 -0
- package/dist/orphan-sweeper.d.ts.map +1 -0
- package/dist/orphan-sweeper.js +289 -0
- package/dist/orphan-sweeper.js.map +1 -0
- package/dist/plugins.d.ts +44 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +1383 -0
- package/dist/plugins.js.map +1 -0
- package/dist/primary-output.d.ts +14 -0
- package/dist/primary-output.d.ts.map +1 -0
- package/dist/primary-output.js +34 -0
- package/dist/primary-output.js.map +1 -0
- package/dist/registry.d.ts +26 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +71 -0
- package/dist/registry.js.map +1 -0
- package/dist/release.d.ts +14 -0
- package/dist/release.d.ts.map +1 -0
- package/dist/release.js +49 -0
- package/dist/release.js.map +1 -0
- package/dist/repl.d.ts +26 -0
- package/dist/repl.d.ts.map +1 -0
- package/dist/repl.js +277 -0
- package/dist/repl.js.map +1 -0
- package/dist/review-command.d.ts +3 -0
- package/dist/review-command.d.ts.map +1 -0
- package/dist/review-command.js +83 -0
- package/dist/review-command.js.map +1 -0
- package/dist/reviewer-options.d.ts +18 -0
- package/dist/reviewer-options.d.ts.map +1 -0
- package/dist/reviewer-options.js +110 -0
- package/dist/reviewer-options.js.map +1 -0
- package/dist/run-options.d.ts +8 -0
- package/dist/run-options.d.ts.map +1 -0
- package/dist/run-options.js +50 -0
- package/dist/run-options.js.map +1 -0
- package/dist/run-secret-scan.d.ts +2 -0
- package/dist/run-secret-scan.d.ts.map +1 -0
- package/dist/run-secret-scan.js +5 -0
- package/dist/run-secret-scan.js.map +1 -0
- package/dist/settings-command.d.ts +3 -0
- package/dist/settings-command.d.ts.map +1 -0
- package/dist/settings-command.js +202 -0
- package/dist/settings-command.js.map +1 -0
- package/dist/settings-display.d.ts +3 -0
- package/dist/settings-display.d.ts.map +1 -0
- package/dist/settings-display.js +33 -0
- package/dist/settings-display.js.map +1 -0
- package/dist/settings-service.d.ts +15 -0
- package/dist/settings-service.d.ts.map +1 -0
- package/dist/settings-service.js +91 -0
- package/dist/settings-service.js.map +1 -0
- package/dist/setup-jobs.d.ts +28 -0
- package/dist/setup-jobs.d.ts.map +1 -0
- package/dist/setup-jobs.js +477 -0
- package/dist/setup-jobs.js.map +1 -0
- package/dist/spec.d.ts +84 -0
- package/dist/spec.d.ts.map +1 -0
- package/dist/spec.js +438 -0
- package/dist/spec.js.map +1 -0
- package/dist/trust-command.d.ts +3 -0
- package/dist/trust-command.d.ts.map +1 -0
- package/dist/trust-command.js +80 -0
- package/dist/trust-command.js.map +1 -0
- package/dist/trust-services.d.ts +7 -0
- package/dist/trust-services.d.ts.map +1 -0
- package/dist/trust-services.js +35 -0
- package/dist/trust-services.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type DaemonClient as DaemonClientType } from "@claudexor/daemon";
|
|
2
|
+
import { type ControlApiAddress } from "./live.js";
|
|
3
|
+
/**
|
|
4
|
+
* Ensure a daemon (and its control API) is running and return a connected
|
|
5
|
+
* client + control-api address. Connects to the existing socket; if unreachable,
|
|
6
|
+
* AUTO-STARTS claudexord as a detached process and waits (bounded) for both the
|
|
7
|
+
* socket and the control-api.json pointer to come up. FAILS LOUDLY if the daemon
|
|
8
|
+
* cannot be started — never silently falls back to an in-process run (the apply
|
|
9
|
+
* gate refuses a run no daemon tracks, so an in-process run is un-unblockable).
|
|
10
|
+
*/
|
|
11
|
+
export declare function ensureDaemon(timeoutMs?: number): Promise<{
|
|
12
|
+
client: DaemonClientType;
|
|
13
|
+
addr: ControlApiAddress;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Connect to an ALREADY-RUNNING daemon + control API WITHOUT ever spawning one.
|
|
17
|
+
* Returns null when no token exists, the socket is unreachable, or the control
|
|
18
|
+
* API is down. Used by read-only-looking run lookups (inspect/apply) so a typo'd
|
|
19
|
+
* run id reports "no such run" instead of silently launching a background daemon
|
|
20
|
+
* (`ensureDaemon`, by contrast, auto-starts and is reserved for paths that act —
|
|
21
|
+
* enqueue/decision).
|
|
22
|
+
*/
|
|
23
|
+
export declare function connectDaemonIfRunning(): Promise<{
|
|
24
|
+
client: DaemonClientType;
|
|
25
|
+
addr: ControlApiAddress;
|
|
26
|
+
} | null>;
|
|
27
|
+
/**
|
|
28
|
+
* Poll until the daemon (socket + control API) is fully ready, or the timeout
|
|
29
|
+
* elapses. Lets `claudexor daemon start` return only once a subsequent `status`
|
|
30
|
+
* is guaranteed to succeed (no start/status race).
|
|
31
|
+
*/
|
|
32
|
+
export declare function waitForDaemonReady(timeoutMs?: number): Promise<{
|
|
33
|
+
client: DaemonClientType;
|
|
34
|
+
addr: ControlApiAddress;
|
|
35
|
+
} | null>;
|
|
36
|
+
export interface DaemonRunOutcome {
|
|
37
|
+
runId: string;
|
|
38
|
+
runDir: string;
|
|
39
|
+
/** The daemon job state (honest terminal: succeeded | blocked | failed | no_op | ...). */
|
|
40
|
+
status: string;
|
|
41
|
+
jobId: string;
|
|
42
|
+
error?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Enqueue a run via the control API and wait until the daemon binds its
|
|
46
|
+
* runId/runDir, then (optionally) wait for it to reach a terminal state.
|
|
47
|
+
* The run lives under the DAEMON dir, not project-local: apply/decision/inspect
|
|
48
|
+
* resolve it via the daemon/registry, and a blocked run is unblockable through
|
|
49
|
+
* `claudexor decision`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function enqueueAndAwait(client: DaemonClientType, addr: ControlApiAddress, body: Record<string, unknown>, opts?: {
|
|
52
|
+
waitForTerminal: boolean;
|
|
53
|
+
startTimeoutMs?: number;
|
|
54
|
+
/** Invoked each terminal-wait iteration once the run is bound (MCP uses
|
|
55
|
+
* this to bridge pendingInteractions -> host elicitation). Awaited: a
|
|
56
|
+
* long answer round-trip pauses status polling, never the run itself. */
|
|
57
|
+
onPollTick?: (info: {
|
|
58
|
+
runId: string;
|
|
59
|
+
}) => void | Promise<void>;
|
|
60
|
+
}): Promise<DaemonRunOutcome>;
|
|
61
|
+
/** Daemon job state -> CLI exit code (success terminals are 0; everything else 1). */
|
|
62
|
+
export declare function exitCodeForState(state: string): number;
|
|
63
|
+
/**
|
|
64
|
+
* The run's derived apply-gate verdict from GET /runs/:id (single producer:
|
|
65
|
+
* the delivery gate via the control API). Soft-fails to null — a detail
|
|
66
|
+
* hiccup must never eat a finished run's result. Shared by the CLI post-run
|
|
67
|
+
* hints and the MCP structured results so both surfaces tell the same truth.
|
|
68
|
+
*/
|
|
69
|
+
export declare function fetchApplyEligibility(addr: ControlApiAddress, runId: string): Promise<{
|
|
70
|
+
eligible: boolean;
|
|
71
|
+
state: string | null;
|
|
72
|
+
reason: string | null;
|
|
73
|
+
requiredAction: string | null;
|
|
74
|
+
} | null>;
|
|
75
|
+
/**
|
|
76
|
+
* Machine-readable reason for a non-success DAEMON terminal (P2). `blocked` is a
|
|
77
|
+
* needs-human terminal that carries no `error`, so surface the actionable decision
|
|
78
|
+
* hint (mirrors text mode); other non-success terminals use the error or a state
|
|
79
|
+
* label. Success terminals return undefined (no `summary` key emitted).
|
|
80
|
+
*/
|
|
81
|
+
export declare function daemonOutcomeSummary(out: {
|
|
82
|
+
runId: string;
|
|
83
|
+
status: string;
|
|
84
|
+
error?: string;
|
|
85
|
+
}): string | undefined;
|
|
86
|
+
//# sourceMappingURL=daemon-run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-run.d.ts","sourceRoot":"","sources":["../src/daemon-run.ts"],"names":[],"mappings":"AAIA,OAAO,EAML,KAAK,YAAY,IAAI,gBAAgB,EACtC,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AA0BtE;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAkDrH;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GAAG,IAAI,CAAC,CAQpH;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GAAG,IAAI,CAAC,CAQlI;AAgBD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,iBAAiB,EACvB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,GAAE;IACJ,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;6EAEyE;IACzE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAsF3B;AAED,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAAC,CAanH;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAO/G"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { DaemonClient, daemonDir, defaultSocketPath, ensureToken, readToken, } from "@claudexor/daemon";
|
|
6
|
+
import { harnessRuntimeEnv } from "@claudexor/core";
|
|
7
|
+
import { controlApiAddress } from "./live.js";
|
|
8
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
9
|
+
/** Is something accepting on the daemon socket right now? (cheap reachability probe). */
|
|
10
|
+
async function daemonReachable(client) {
|
|
11
|
+
try {
|
|
12
|
+
await client.health();
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Is the daemon's control-api up and answering /healthz right now? */
|
|
20
|
+
async function controlApiReachable() {
|
|
21
|
+
try {
|
|
22
|
+
const addr = controlApiAddress();
|
|
23
|
+
const res = await fetch(`${addr.baseUrl}/healthz`, { signal: AbortSignal.timeout(1500) });
|
|
24
|
+
return res.ok ? addr : null;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Ensure a daemon (and its control API) is running and return a connected
|
|
32
|
+
* client + control-api address. Connects to the existing socket; if unreachable,
|
|
33
|
+
* AUTO-STARTS claudexord as a detached process and waits (bounded) for both the
|
|
34
|
+
* socket and the control-api.json pointer to come up. FAILS LOUDLY if the daemon
|
|
35
|
+
* cannot be started — never silently falls back to an in-process run (the apply
|
|
36
|
+
* gate refuses a run no daemon tracks, so an in-process run is un-unblockable).
|
|
37
|
+
*/
|
|
38
|
+
export async function ensureDaemon(timeoutMs = 30_000) {
|
|
39
|
+
const token = ensureToken();
|
|
40
|
+
const socketPath = defaultSocketPath();
|
|
41
|
+
let client = new DaemonClient(socketPath, token);
|
|
42
|
+
const ok = await daemonReachable(client);
|
|
43
|
+
if (!ok) {
|
|
44
|
+
// Auto-start the daemon entry (the same one `claudexor daemon start` spawns).
|
|
45
|
+
const daemonScript = fileURLToPath(new URL("./claudexord.js", import.meta.url));
|
|
46
|
+
if (!existsSync(daemonScript)) {
|
|
47
|
+
throw new Error(`cannot auto-start the daemon: entry not found at ${daemonScript} (run \`pnpm build\`)`);
|
|
48
|
+
}
|
|
49
|
+
const child = spawn(process.execPath, [daemonScript], { detached: true, stdio: "ignore", env: harnessRuntimeEnv() });
|
|
50
|
+
child.unref();
|
|
51
|
+
// Wait for the socket to accept connections (health round-trip).
|
|
52
|
+
const deadline = Date.now() + timeoutMs;
|
|
53
|
+
let started = false;
|
|
54
|
+
while (Date.now() < deadline) {
|
|
55
|
+
await sleep(150);
|
|
56
|
+
// Re-read the token: ensureToken() above generated it before spawn, and the
|
|
57
|
+
// daemon reuses the same per-user token file, so this client stays valid.
|
|
58
|
+
client = new DaemonClient(socketPath, token);
|
|
59
|
+
if (await daemonReachable(client)) {
|
|
60
|
+
started = true;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (!started) {
|
|
65
|
+
throw new Error(`daemon did not come up within ${Math.round(timeoutMs / 1000)}s after auto-start (socket ${socketPath}); check \`claudexor daemon logs\``);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// The control API (HTTP/SSE viewport over the daemon) is what streams events
|
|
69
|
+
// and resolves the run for apply/decision. Wait for its pointer to be written.
|
|
70
|
+
let addr = await controlApiReachable();
|
|
71
|
+
if (!addr) {
|
|
72
|
+
const deadline = Date.now() + 10_000;
|
|
73
|
+
while (Date.now() < deadline && !addr) {
|
|
74
|
+
await sleep(150);
|
|
75
|
+
addr = await controlApiReachable();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!addr) {
|
|
79
|
+
throw new Error(`daemon is up but its control API is not reachable (no ${daemonDir()}/control-api.json); it may be disabled by CLAUDEXOR_NO_CONTROL_API=1`);
|
|
80
|
+
}
|
|
81
|
+
return { client, addr };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Connect to an ALREADY-RUNNING daemon + control API WITHOUT ever spawning one.
|
|
85
|
+
* Returns null when no token exists, the socket is unreachable, or the control
|
|
86
|
+
* API is down. Used by read-only-looking run lookups (inspect/apply) so a typo'd
|
|
87
|
+
* run id reports "no such run" instead of silently launching a background daemon
|
|
88
|
+
* (`ensureDaemon`, by contrast, auto-starts and is reserved for paths that act —
|
|
89
|
+
* enqueue/decision).
|
|
90
|
+
*/
|
|
91
|
+
export async function connectDaemonIfRunning() {
|
|
92
|
+
const token = readToken();
|
|
93
|
+
if (!token)
|
|
94
|
+
return null;
|
|
95
|
+
const client = new DaemonClient(defaultSocketPath(), token);
|
|
96
|
+
if (!(await daemonReachable(client)))
|
|
97
|
+
return null;
|
|
98
|
+
const addr = await controlApiReachable();
|
|
99
|
+
if (!addr)
|
|
100
|
+
return null;
|
|
101
|
+
return { client, addr };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Poll until the daemon (socket + control API) is fully ready, or the timeout
|
|
105
|
+
* elapses. Lets `claudexor daemon start` return only once a subsequent `status`
|
|
106
|
+
* is guaranteed to succeed (no start/status race).
|
|
107
|
+
*/
|
|
108
|
+
export async function waitForDaemonReady(timeoutMs = 15_000) {
|
|
109
|
+
const deadline = Date.now() + timeoutMs;
|
|
110
|
+
for (;;) {
|
|
111
|
+
const conn = await connectDaemonIfRunning();
|
|
112
|
+
if (conn)
|
|
113
|
+
return conn;
|
|
114
|
+
if (Date.now() >= deadline)
|
|
115
|
+
return null;
|
|
116
|
+
await sleep(150);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const TERMINAL_STATES = new Set([
|
|
120
|
+
"succeeded",
|
|
121
|
+
"no_op",
|
|
122
|
+
"ungated",
|
|
123
|
+
"review_not_run",
|
|
124
|
+
"blocked",
|
|
125
|
+
"failed",
|
|
126
|
+
"cancelled",
|
|
127
|
+
"interrupted",
|
|
128
|
+
"exhausted",
|
|
129
|
+
"not_converged",
|
|
130
|
+
"stuck_no_progress",
|
|
131
|
+
]);
|
|
132
|
+
/**
|
|
133
|
+
* Enqueue a run via the control API and wait until the daemon binds its
|
|
134
|
+
* runId/runDir, then (optionally) wait for it to reach a terminal state.
|
|
135
|
+
* The run lives under the DAEMON dir, not project-local: apply/decision/inspect
|
|
136
|
+
* resolve it via the daemon/registry, and a blocked run is unblockable through
|
|
137
|
+
* `claudexor decision`.
|
|
138
|
+
*/
|
|
139
|
+
export async function enqueueAndAwait(client, addr, body, opts = { waitForTerminal: true }) {
|
|
140
|
+
const startRes = await fetch(`${addr.baseUrl}/runs`, {
|
|
141
|
+
method: "POST",
|
|
142
|
+
headers: { Authorization: `Bearer ${addr.token}`, "content-type": "application/json" },
|
|
143
|
+
body: JSON.stringify(body),
|
|
144
|
+
});
|
|
145
|
+
const startText = await startRes.text();
|
|
146
|
+
const start = startText ? JSON.parse(startText) : {};
|
|
147
|
+
if (!startRes.ok) {
|
|
148
|
+
throw new Error(typeof start["error"] === "string" ? start["error"] : `run enqueue failed (HTTP ${startRes.status})`);
|
|
149
|
+
}
|
|
150
|
+
const jobId = String(start["jobId"] ?? "");
|
|
151
|
+
let runId = typeof start["runId"] === "string" ? start["runId"] : "";
|
|
152
|
+
let runDir = typeof start["runDir"] === "string" ? start["runDir"] : "";
|
|
153
|
+
// Ctrl-C while the CLI waits on a daemon run must CANCEL THE RUN, not just
|
|
154
|
+
// kill the waiting CLI (which would leave the daemon mutating the tree with
|
|
155
|
+
// nobody watching — the orphan the audit called out). First signal posts the
|
|
156
|
+
// typed cancel and keeps waiting for the honest terminal; a second signal
|
|
157
|
+
// force-quits the CLI (the daemon still owns the cancel).
|
|
158
|
+
let sigCount = 0;
|
|
159
|
+
const onSignal = () => {
|
|
160
|
+
sigCount += 1;
|
|
161
|
+
if (sigCount >= 2)
|
|
162
|
+
process.exit(130);
|
|
163
|
+
process.stderr.write("\ncancelling daemon run (Ctrl-C again to detach)...\n");
|
|
164
|
+
void fetch(`${addr.baseUrl}/runs/${encodeURIComponent(jobId)}/control`, {
|
|
165
|
+
method: "POST",
|
|
166
|
+
headers: { Authorization: `Bearer ${addr.token}`, "content-type": "application/json" },
|
|
167
|
+
body: JSON.stringify({ control: { kind: "cancel", reason: "ctrl-c on the waiting CLI" } }),
|
|
168
|
+
}).then(async (res) => {
|
|
169
|
+
if (!res.ok) {
|
|
170
|
+
process.stderr.write(`cancel request failed: HTTP ${res.status} ${(await res.text()).slice(0, 200)}\n`);
|
|
171
|
+
}
|
|
172
|
+
}).catch((err) => {
|
|
173
|
+
process.stderr.write(`cancel request failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
process.on("SIGINT", onSignal);
|
|
177
|
+
process.on("SIGTERM", onSignal);
|
|
178
|
+
const removeSignalHandlers = () => {
|
|
179
|
+
process.removeListener("SIGINT", onSignal);
|
|
180
|
+
process.removeListener("SIGTERM", onSignal);
|
|
181
|
+
};
|
|
182
|
+
try {
|
|
183
|
+
// A 202 (queued) response carries only the jobId; poll the daemon socket
|
|
184
|
+
// until the run binds its id/dir (single canonical state source).
|
|
185
|
+
const startDeadline = Date.now() + (opts.startTimeoutMs ?? 30_000);
|
|
186
|
+
while ((!runId || !runDir) && Date.now() < startDeadline) {
|
|
187
|
+
if (!jobId)
|
|
188
|
+
break;
|
|
189
|
+
const rec = await client.status(jobId);
|
|
190
|
+
if (rec.runId && rec.runDir) {
|
|
191
|
+
runId = rec.runId;
|
|
192
|
+
runDir = rec.runDir;
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
if (TERMINAL_STATES.has(rec.state) && !rec.runDir) {
|
|
196
|
+
// Terminal with no runDir = the run never materialized (e.g. validation
|
|
197
|
+
// failure pre-run-dir). Surface it honestly.
|
|
198
|
+
return { runId: rec.runId ?? "", runDir: "", status: rec.state, jobId, error: rec.error };
|
|
199
|
+
}
|
|
200
|
+
await sleep(120);
|
|
201
|
+
}
|
|
202
|
+
if (!runId || !runDir) {
|
|
203
|
+
throw new Error(`run did not start within the timeout (jobId ${jobId})`);
|
|
204
|
+
}
|
|
205
|
+
if (!opts.waitForTerminal) {
|
|
206
|
+
// The caller keeps watching this run (text mode streams it); hand the
|
|
207
|
+
// signal responsibility back with the outcome.
|
|
208
|
+
const rec = jobId ? await client.status(jobId) : null;
|
|
209
|
+
return { runId, runDir, status: rec?.state ?? "running", jobId };
|
|
210
|
+
}
|
|
211
|
+
// Poll the daemon socket for the terminal job state (the canonical outcome).
|
|
212
|
+
for (;;) {
|
|
213
|
+
const rec = await client.status(jobId);
|
|
214
|
+
if (TERMINAL_STATES.has(rec.state)) {
|
|
215
|
+
return { runId: rec.runId ?? runId, runDir: rec.runDir ?? runDir, status: rec.state, jobId, error: rec.error };
|
|
216
|
+
}
|
|
217
|
+
if (opts.onPollTick)
|
|
218
|
+
await opts.onPollTick({ runId: rec.runId ?? runId });
|
|
219
|
+
await sleep(250);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
removeSignalHandlers();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/** Daemon job state -> CLI exit code (success terminals are 0; everything else 1). */
|
|
227
|
+
export function exitCodeForState(state) {
|
|
228
|
+
return state === "succeeded" || state === "no_op" || state === "ungated" || state === "review_not_run" ? 0 : 1;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* The run's derived apply-gate verdict from GET /runs/:id (single producer:
|
|
232
|
+
* the delivery gate via the control API). Soft-fails to null — a detail
|
|
233
|
+
* hiccup must never eat a finished run's result. Shared by the CLI post-run
|
|
234
|
+
* hints and the MCP structured results so both surfaces tell the same truth.
|
|
235
|
+
*/
|
|
236
|
+
export async function fetchApplyEligibility(addr, runId) {
|
|
237
|
+
if (!runId)
|
|
238
|
+
return null;
|
|
239
|
+
try {
|
|
240
|
+
const res = await fetch(`${addr.baseUrl}/runs/${encodeURIComponent(runId)}`, {
|
|
241
|
+
headers: { authorization: `Bearer ${addr.token}` },
|
|
242
|
+
});
|
|
243
|
+
if (!res.ok)
|
|
244
|
+
return null;
|
|
245
|
+
const detail = (await res.json());
|
|
246
|
+
const v = detail["applyEligibility"];
|
|
247
|
+
return v && typeof v === "object" ? v : null;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Machine-readable reason for a non-success DAEMON terminal (P2). `blocked` is a
|
|
255
|
+
* needs-human terminal that carries no `error`, so surface the actionable decision
|
|
256
|
+
* hint (mirrors text mode); other non-success terminals use the error or a state
|
|
257
|
+
* label. Success terminals return undefined (no `summary` key emitted).
|
|
258
|
+
*/
|
|
259
|
+
export function daemonOutcomeSummary(out) {
|
|
260
|
+
if (out.error)
|
|
261
|
+
return out.error;
|
|
262
|
+
if (exitCodeForState(out.status) === 0)
|
|
263
|
+
return undefined;
|
|
264
|
+
if (out.status === "blocked") {
|
|
265
|
+
return `run blocked: needs a human decision — claudexor decision ${out.runId} --accept-risk | --rerun --feedback "..."`;
|
|
266
|
+
}
|
|
267
|
+
return `run ${out.status}`;
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=daemon-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-run.js","sourceRoot":"","sources":["../src/daemon-run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ParsedArgs } from "./args.js";
|
|
2
|
+
export type DecisionResolution = {
|
|
3
|
+
ok: true;
|
|
4
|
+
action: string;
|
|
5
|
+
body: Record<string, unknown>;
|
|
6
|
+
} | {
|
|
7
|
+
ok: false;
|
|
8
|
+
message: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Pure mapping of `claudexor decision` flags to a typed RunDecisionAction
|
|
12
|
+
* request body. Exactly one action flag is required; rerun needs --feedback;
|
|
13
|
+
* accept-clean-patch may carry a validated --apply-mode. Returns an honest
|
|
14
|
+
* error message instead of a body when the flags are invalid (the command
|
|
15
|
+
* surfaces it on stderr and exits 2).
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveDecisionBody(args: ParsedArgs): DecisionResolution;
|
|
18
|
+
//# sourceMappingURL=decision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.d.ts","sourceRoot":"","sources":["../src/decision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAa/D,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAC3D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,kBAAkB,CA2BxE"}
|
package/dist/decision.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { flagBool, flagStr } from "./args.js";
|
|
2
|
+
/** The five typed RunDecisionAction values, mapped from their CLI action flags. */
|
|
3
|
+
const ACTION_FLAGS = [
|
|
4
|
+
{ flag: "accept-risk", action: "accept_risk" },
|
|
5
|
+
{ flag: "override", action: "override_needs_human" },
|
|
6
|
+
{ flag: "revert", action: "revert_run" },
|
|
7
|
+
{ flag: "accept-clean-patch", action: "accept_clean_patch" },
|
|
8
|
+
{ flag: "rerun", action: "rerun_with_feedback" },
|
|
9
|
+
];
|
|
10
|
+
const APPLY_MODES = ["artifact_only", "apply", "branch", "commit", "pr"];
|
|
11
|
+
/**
|
|
12
|
+
* Pure mapping of `claudexor decision` flags to a typed RunDecisionAction
|
|
13
|
+
* request body. Exactly one action flag is required; rerun needs --feedback;
|
|
14
|
+
* accept-clean-patch may carry a validated --apply-mode. Returns an honest
|
|
15
|
+
* error message instead of a body when the flags are invalid (the command
|
|
16
|
+
* surfaces it on stderr and exits 2).
|
|
17
|
+
*/
|
|
18
|
+
export function resolveDecisionBody(args) {
|
|
19
|
+
const chosen = ACTION_FLAGS.filter((f) => flagBool(args, f.flag));
|
|
20
|
+
if (chosen.length === 0) {
|
|
21
|
+
return { ok: false, message: "one action is required (--accept-risk | --override | --revert | --accept-clean-patch | --rerun)" };
|
|
22
|
+
}
|
|
23
|
+
if (chosen.length > 1) {
|
|
24
|
+
return { ok: false, message: `only one action at a time (got ${chosen.map((c) => `--${c.flag}`).join(", ")})` };
|
|
25
|
+
}
|
|
26
|
+
const action = chosen[0].action;
|
|
27
|
+
const body = { action };
|
|
28
|
+
if (action === "rerun_with_feedback") {
|
|
29
|
+
const feedback = flagStr(args, "feedback");
|
|
30
|
+
if (!feedback || !feedback.trim()) {
|
|
31
|
+
return { ok: false, message: '--rerun requires --feedback "<text>"' };
|
|
32
|
+
}
|
|
33
|
+
body["feedback"] = feedback;
|
|
34
|
+
}
|
|
35
|
+
if (action === "accept_clean_patch") {
|
|
36
|
+
const applyMode = flagStr(args, "apply-mode");
|
|
37
|
+
if (applyMode !== undefined) {
|
|
38
|
+
if (!APPLY_MODES.includes(applyMode)) {
|
|
39
|
+
return { ok: false, message: `invalid --apply-mode '${applyMode}' (expected apply|branch|commit|pr|artifact_only)` };
|
|
40
|
+
}
|
|
41
|
+
body["applyMode"] = applyMode;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return { ok: true, action, body };
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=decision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision.js","sourceRoot":"","sources":["../src/decision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAmB,MAAM,WAAW,CAAC;AAE/D,mFAAmF;AACnF,MAAM,YAAY,GAAuC;IACvD,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE;IAC9C,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,sBAAsB,EAAE;IACpD,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE;IACxC,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,EAAE,oBAAoB,EAAE;IAC5D,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,EAAE;CACjD,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;AAMzE;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAgB;IAClD,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,iGAAiG,EAAE,CAAC;IACnI,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,kCAAkC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;IAClH,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC;IACjC,MAAM,IAAI,GAA4B,EAAE,MAAM,EAAE,CAAC;IACjD,IAAI,MAAM,KAAK,qBAAqB,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YAClC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC;QACxE,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC;IAC9B,CAAC;IACD,IAAI,MAAM,KAAK,oBAAoB,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC9C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBACrC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,yBAAyB,SAAS,mDAAmD,EAAE,CAAC;YACvH,CAAC;YACD,IAAI,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACpC,CAAC"}
|
package/dist/live.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { InteractionAnswerSet, InteractionQuestion } from "@claudexor/schema";
|
|
2
|
+
/**
|
|
3
|
+
* One concise line per run event for live terminal progress. Returns null for
|
|
4
|
+
* noise (heartbeats, raw harness deltas we do not surface in a TTY).
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatRunEventLine(ev: Record<string, unknown>): string | null;
|
|
7
|
+
/**
|
|
8
|
+
* Prompt the questions on the controlling TTY. Returns null on a non-TTY
|
|
9
|
+
* stdin or when the deadline passes (the engine then declines benignly).
|
|
10
|
+
*/
|
|
11
|
+
export declare function promptQuestionsOnTty(interactionId: string, questions: InteractionQuestion[], timeoutAt?: string): Promise<InteractionAnswerSet | null>;
|
|
12
|
+
export interface ControlApiAddress {
|
|
13
|
+
baseUrl: string;
|
|
14
|
+
token: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function controlApiAddress(): ControlApiAddress;
|
|
17
|
+
/**
|
|
18
|
+
* `claudexor follow <run_id>`: live SSE tail of a daemon-backed run with full
|
|
19
|
+
* replay (persisted seq), bounded reconnects via Last-Event-ID, and
|
|
20
|
+
* interactive TTY answering of harness questions. Exit honesty: a
|
|
21
|
+
* stream that ends WITHOUT a terminal event is a LOSS (exit 1, "stream
|
|
22
|
+
* lost"), never a silent success — success requires an observed terminal or
|
|
23
|
+
* an `end` frame the server sent after one.
|
|
24
|
+
*/
|
|
25
|
+
export declare function followRun(runId: string, json: boolean): Promise<number>;
|
|
26
|
+
//# sourceMappingURL=live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAQnF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAoD7E;AAMD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,mBAAmB,EAAE,EAChC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAoDtC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,iBAAiB,IAAI,iBAAiB,CAKrD;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAkG7E"}
|