@chit-run/cli 0.7.0 → 0.8.0
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/dist/chit.js +135 -12
- package/package.json +1 -1
package/dist/chit.js
CHANGED
|
@@ -10820,6 +10820,11 @@ class ClaudeCliAdapter {
|
|
|
10820
10820
|
if (noProgress)
|
|
10821
10821
|
throw new Error(`claude --print made no progress for ${noProgressMs}ms`);
|
|
10822
10822
|
if (exitCode !== 0) {
|
|
10823
|
+
const rateLimit = detectClaudeRateLimit(`${stdoutText}
|
|
10824
|
+
${stderrText}`);
|
|
10825
|
+
if (rateLimit !== undefined) {
|
|
10826
|
+
throw new Error(`claude --print rate limited${rateLimit ? `: ${rateLimit}` : ` (exit ${exitCode})`}`);
|
|
10827
|
+
}
|
|
10823
10828
|
const cleaned = sanitize(stderrText || stdoutText, sensitive);
|
|
10824
10829
|
const tail = cleaned.trim().split(`
|
|
10825
10830
|
`).slice(-5).join(`
|
|
@@ -10953,6 +10958,42 @@ function parseClaudeResult(stdout) {
|
|
|
10953
10958
|
}
|
|
10954
10959
|
return result;
|
|
10955
10960
|
}
|
|
10961
|
+
function detectClaudeRateLimit(stdout) {
|
|
10962
|
+
const pickStr = (v) => typeof v === "string" && v.trim() !== "" ? v.trim().replace(/\s+/g, " ").slice(0, 120) : undefined;
|
|
10963
|
+
const pickNum = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
|
|
10964
|
+
let found = false;
|
|
10965
|
+
let detail = "";
|
|
10966
|
+
for (const line of stdout.split(`
|
|
10967
|
+
`)) {
|
|
10968
|
+
const trimmed = line.trim();
|
|
10969
|
+
if (!trimmed)
|
|
10970
|
+
continue;
|
|
10971
|
+
let evt;
|
|
10972
|
+
try {
|
|
10973
|
+
evt = JSON.parse(trimmed);
|
|
10974
|
+
} catch {
|
|
10975
|
+
continue;
|
|
10976
|
+
}
|
|
10977
|
+
if (evt.type !== "rate_limit_event")
|
|
10978
|
+
continue;
|
|
10979
|
+
found = true;
|
|
10980
|
+
const rl = evt.rate_limit_info && typeof evt.rate_limit_info === "object" ? evt.rate_limit_info : evt.rate_limit && typeof evt.rate_limit === "object" ? evt.rate_limit : evt;
|
|
10981
|
+
const parts = [];
|
|
10982
|
+
const status = pickStr(rl.status);
|
|
10983
|
+
if (status)
|
|
10984
|
+
parts.push(`status=${status}`);
|
|
10985
|
+
const resetsAt = pickStr(rl.resetsAt);
|
|
10986
|
+
if (resetsAt)
|
|
10987
|
+
parts.push(`resets ${resetsAt}`);
|
|
10988
|
+
const retryAfter = pickNum(rl.retryAfter) ?? pickNum(rl.resetInSeconds);
|
|
10989
|
+
if (retryAfter !== undefined)
|
|
10990
|
+
parts.push(`retry after ${retryAfter}s`);
|
|
10991
|
+
if (rl.isUsingOverage === false)
|
|
10992
|
+
parts.push("overage disabled");
|
|
10993
|
+
detail = parts.join(", ");
|
|
10994
|
+
}
|
|
10995
|
+
return found ? detail : undefined;
|
|
10996
|
+
}
|
|
10956
10997
|
|
|
10957
10998
|
// src/adapters/codex-exec.ts
|
|
10958
10999
|
var DEFAULT_CALL_TIMEOUT_MS2 = 15 * 60000;
|
|
@@ -10972,7 +11013,7 @@ class CodexExecAdapter {
|
|
|
10972
11013
|
const sensitive = findSensitiveValues(this.config.env);
|
|
10973
11014
|
try {
|
|
10974
11015
|
const priorThreadId = getCodexThreadId(req.session);
|
|
10975
|
-
const cmd = this.buildCommand(priorThreadId);
|
|
11016
|
+
const cmd = this.buildCommand(priorThreadId, req.filesystem);
|
|
10976
11017
|
const proc = Bun.spawn({
|
|
10977
11018
|
cmd,
|
|
10978
11019
|
cwd: req.cwd,
|
|
@@ -11049,7 +11090,7 @@ class CodexExecAdapter {
|
|
|
11049
11090
|
throw new Error(message);
|
|
11050
11091
|
}
|
|
11051
11092
|
}
|
|
11052
|
-
buildCommand(priorThreadId) {
|
|
11093
|
+
buildCommand(priorThreadId, filesystem) {
|
|
11053
11094
|
if (priorThreadId) {
|
|
11054
11095
|
return ["codex", "exec", "resume", "--json", "--skip-git-repo-check", priorThreadId, "-"];
|
|
11055
11096
|
}
|
|
@@ -11059,7 +11100,8 @@ class CodexExecAdapter {
|
|
|
11059
11100
|
if (this.config.reasoningEffort) {
|
|
11060
11101
|
cmd.push("-c", `model_reasoning_effort="${this.config.reasoningEffort}"`);
|
|
11061
11102
|
}
|
|
11062
|
-
|
|
11103
|
+
const sandbox = filesystem === "write" ? "workspace-write" : "read-only";
|
|
11104
|
+
cmd.push("--sandbox", sandbox, "--skip-git-repo-check", "-");
|
|
11063
11105
|
return cmd;
|
|
11064
11106
|
}
|
|
11065
11107
|
}
|
|
@@ -12146,6 +12188,9 @@ function computeFingerprint(input) {
|
|
|
12146
12188
|
reasoningEffort: agent.reasoningEffort ?? null,
|
|
12147
12189
|
passModelOnResume: agent.adapter === "claude-cli" ? agent.passModelOnResume : null,
|
|
12148
12190
|
strictMcp: agent.adapter === "claude-cli" ? agent.strictMcp !== false : null,
|
|
12191
|
+
...agent.adapter === "codex-exec" && {
|
|
12192
|
+
codexSandbox: participant.permissions.filesystem === "write" ? "workspace-write" : "read-only"
|
|
12193
|
+
},
|
|
12149
12194
|
baseUrl,
|
|
12150
12195
|
role: participant.role,
|
|
12151
12196
|
session: participant.session,
|
|
@@ -12554,7 +12599,8 @@ async function runConvergeIteration(ctx) {
|
|
|
12554
12599
|
if (!result.ok) {
|
|
12555
12600
|
return {
|
|
12556
12601
|
ok: false,
|
|
12557
|
-
failure: `manifest run failed at step "${result.failedStep}": ${result.error}
|
|
12602
|
+
failure: `manifest run failed at step "${result.failedStep}": ${result.error}`,
|
|
12603
|
+
...result.auditRunId && { auditRunId: result.auditRunId }
|
|
12558
12604
|
};
|
|
12559
12605
|
}
|
|
12560
12606
|
const reviewText = result.outputs.review ?? "";
|
|
@@ -12923,7 +12969,12 @@ async function runJobWorker(jobId, deps) {
|
|
|
12923
12969
|
const workerToken = crypto.randomUUID();
|
|
12924
12970
|
const setPhase = (phase) => {
|
|
12925
12971
|
try {
|
|
12926
|
-
store.update(jobId, (c) => ({
|
|
12972
|
+
store.update(jobId, (c) => ({
|
|
12973
|
+
...c,
|
|
12974
|
+
phase,
|
|
12975
|
+
...c.phase !== phase && { phaseStartedAt: iso2(now()) },
|
|
12976
|
+
lastHeartbeatAt: iso2(now())
|
|
12977
|
+
}));
|
|
12927
12978
|
} catch {}
|
|
12928
12979
|
};
|
|
12929
12980
|
const controller = new AbortController;
|
|
@@ -12946,7 +12997,8 @@ async function runJobWorker(jobId, deps) {
|
|
|
12946
12997
|
pgid: process.pid,
|
|
12947
12998
|
workerToken,
|
|
12948
12999
|
lastHeartbeatAt: iso2(now()),
|
|
12949
|
-
phase: "starting"
|
|
13000
|
+
phase: "starting",
|
|
13001
|
+
phaseStartedAt: iso2(now())
|
|
12950
13002
|
}));
|
|
12951
13003
|
const resolved = resolveExecute(job);
|
|
12952
13004
|
if (!resolved.ok) {
|
|
@@ -12981,6 +13033,7 @@ async function runJobWorker(jobId, deps) {
|
|
|
12981
13033
|
...c,
|
|
12982
13034
|
iteration: i,
|
|
12983
13035
|
phase: "implementing",
|
|
13036
|
+
...c.phase !== "implementing" && { phaseStartedAt: iso2(now()) },
|
|
12984
13037
|
lastHeartbeatAt: iso2(now())
|
|
12985
13038
|
}));
|
|
12986
13039
|
let iter;
|
|
@@ -13010,6 +13063,10 @@ async function runJobWorker(jobId, deps) {
|
|
|
13010
13063
|
return;
|
|
13011
13064
|
}
|
|
13012
13065
|
if (!iter.ok) {
|
|
13066
|
+
if (iter.auditRunId) {
|
|
13067
|
+
const ref = iter.auditRunId;
|
|
13068
|
+
store.update(jobId, (c) => ({ ...c, auditRefs: [...c.auditRefs, ref] }));
|
|
13069
|
+
}
|
|
13013
13070
|
if (controller.signal.aborted) {
|
|
13014
13071
|
stopLoopSafely(job, "cancelled", "cancelled mid-iteration (signal)");
|
|
13015
13072
|
finish(store, jobId, now, "cancelled", { stopStatus: "cancelled" });
|
|
@@ -13022,6 +13079,7 @@ async function runJobWorker(jobId, deps) {
|
|
|
13022
13079
|
store.update(jobId, (c) => ({
|
|
13023
13080
|
...c,
|
|
13024
13081
|
phase: "recording",
|
|
13082
|
+
...c.phase !== "recording" && { phaseStartedAt: iso2(now()) },
|
|
13025
13083
|
iterationsCompleted: i,
|
|
13026
13084
|
lastVerdict: iter.verdict,
|
|
13027
13085
|
auditRefs: iter.auditRunId ? [...c.auditRefs, iter.auditRunId] : c.auditRefs,
|
|
@@ -13062,6 +13120,7 @@ function finish(store, jobId, now, state, extra) {
|
|
|
13062
13120
|
state,
|
|
13063
13121
|
endedAt: iso2(now()),
|
|
13064
13122
|
phase: undefined,
|
|
13123
|
+
phaseStartedAt: undefined,
|
|
13065
13124
|
lastHeartbeatAt: iso2(now()),
|
|
13066
13125
|
...extra.stopStatus !== undefined && { stopStatus: extra.stopStatus },
|
|
13067
13126
|
...extra.failure !== undefined && { failure: extra.failure }
|
|
@@ -36126,6 +36185,40 @@ function isStale(job, nowMs, staleAfterMs = STALE_AFTER_MS) {
|
|
|
36126
36185
|
const heartbeatOld = !Number.isFinite(beat) || nowMs - beat > staleAfterMs;
|
|
36127
36186
|
return heartbeatOld || !pidAlive(job.pid);
|
|
36128
36187
|
}
|
|
36188
|
+
function jobTiming(job, nowMs) {
|
|
36189
|
+
const inFlight = job.state === "queued" || job.state === "running";
|
|
36190
|
+
const timing = {};
|
|
36191
|
+
const startMs = Date.parse(job.startedAt ?? job.createdAt);
|
|
36192
|
+
const endMs = job.endedAt ? Date.parse(job.endedAt) : nowMs;
|
|
36193
|
+
if (Number.isFinite(startMs) && Number.isFinite(endMs) && endMs >= startMs) {
|
|
36194
|
+
timing.elapsedMs = endMs - startMs;
|
|
36195
|
+
}
|
|
36196
|
+
if (inFlight && job.lastHeartbeatAt) {
|
|
36197
|
+
const beat = Date.parse(job.lastHeartbeatAt);
|
|
36198
|
+
if (Number.isFinite(beat) && nowMs >= beat)
|
|
36199
|
+
timing.lastHeartbeatAgeMs = nowMs - beat;
|
|
36200
|
+
}
|
|
36201
|
+
if (job.phase !== undefined && job.phaseStartedAt) {
|
|
36202
|
+
const phaseStart = Date.parse(job.phaseStartedAt);
|
|
36203
|
+
if (Number.isFinite(phaseStart) && nowMs >= phaseStart) {
|
|
36204
|
+
timing.phaseElapsedMs = nowMs - phaseStart;
|
|
36205
|
+
}
|
|
36206
|
+
}
|
|
36207
|
+
return timing;
|
|
36208
|
+
}
|
|
36209
|
+
function formatDuration(ms) {
|
|
36210
|
+
const totalSec = Math.floor(ms / 1000);
|
|
36211
|
+
if (totalSec < 60)
|
|
36212
|
+
return `${totalSec}s`;
|
|
36213
|
+
const totalMin = Math.floor(totalSec / 60);
|
|
36214
|
+
if (totalMin < 60) {
|
|
36215
|
+
const sec = totalSec % 60;
|
|
36216
|
+
return sec ? `${totalMin}m${sec}s` : `${totalMin}m`;
|
|
36217
|
+
}
|
|
36218
|
+
const hours = Math.floor(totalMin / 60);
|
|
36219
|
+
const min = totalMin % 60;
|
|
36220
|
+
return min ? `${hours}h${min}m` : `${hours}h`;
|
|
36221
|
+
}
|
|
36129
36222
|
|
|
36130
36223
|
// src/surfaces/mcp/converge-engine.ts
|
|
36131
36224
|
class ConvergeEngineError extends Error {
|
|
@@ -36578,10 +36671,22 @@ function summarizeRunForStatus(run) {
|
|
|
36578
36671
|
audited: run.recorder !== undefined && run.recorder.lastError === undefined
|
|
36579
36672
|
};
|
|
36580
36673
|
}
|
|
36674
|
+
function runningNextAction(job, timing) {
|
|
36675
|
+
const parts = [];
|
|
36676
|
+
if (timing.elapsedMs !== undefined)
|
|
36677
|
+
parts.push(`running for ${formatDuration(timing.elapsedMs)}`);
|
|
36678
|
+
if (job.phase) {
|
|
36679
|
+
parts.push(timing.phaseElapsedMs !== undefined ? `${job.phase} for ${formatDuration(timing.phaseElapsedMs)}` : job.phase);
|
|
36680
|
+
}
|
|
36681
|
+
const lead = parts.length > 0 ? parts.join(", ") : "in progress";
|
|
36682
|
+
return `${lead}; chit_job_status / chit_job_cancel "${job.jobId}"`;
|
|
36683
|
+
}
|
|
36581
36684
|
function summarizeJobForStatus(job, nowMs) {
|
|
36582
36685
|
const stale = isStale(job, nowMs);
|
|
36583
36686
|
const display = stale ? "stale" : job.state;
|
|
36584
|
-
const
|
|
36687
|
+
const timing = jobTiming(job, nowMs);
|
|
36688
|
+
const latestRef = job.auditRefs.at(-1);
|
|
36689
|
+
const nextAction = display === "running" ? runningNextAction(job, timing) : display === "queued" ? "queued; the worker is starting" : display === "stale" ? `worker appears dead; chit_job_status "${job.jobId}" to inspect, then start a fresh job` : `${display}${job.stopStatus ? ` (${job.stopStatus})` : ""}; chit_job_status "${job.jobId}"${latestRef ? ` or chit_audit_show ${latestRef}` : ""}`;
|
|
36585
36690
|
return {
|
|
36586
36691
|
jobId: job.jobId,
|
|
36587
36692
|
loopId: job.loopId,
|
|
@@ -36594,6 +36699,11 @@ function summarizeJobForStatus(job, nowMs) {
|
|
|
36594
36699
|
...job.stopStatus !== undefined && { stopStatus: job.stopStatus },
|
|
36595
36700
|
auditRefs: job.auditRefs,
|
|
36596
36701
|
createdAt: job.createdAt,
|
|
36702
|
+
...timing.elapsedMs !== undefined && { elapsedMs: timing.elapsedMs },
|
|
36703
|
+
...timing.lastHeartbeatAgeMs !== undefined && {
|
|
36704
|
+
lastHeartbeatAgeMs: timing.lastHeartbeatAgeMs
|
|
36705
|
+
},
|
|
36706
|
+
...timing.phaseElapsedMs !== undefined && { phaseElapsedMs: timing.phaseElapsedMs },
|
|
36597
36707
|
nextAction
|
|
36598
36708
|
};
|
|
36599
36709
|
}
|
|
@@ -37118,7 +37228,13 @@ function describeJob(job) {
|
|
|
37118
37228
|
};
|
|
37119
37229
|
}
|
|
37120
37230
|
} catch {}
|
|
37121
|
-
const
|
|
37231
|
+
const timing = jobTiming(job, now);
|
|
37232
|
+
const latestRef = job.auditRefs.at(-1);
|
|
37233
|
+
const runningDetail = [
|
|
37234
|
+
timing.elapsedMs !== undefined ? `running for ${formatDuration(timing.elapsedMs)}` : undefined,
|
|
37235
|
+
job.phase ? timing.phaseElapsedMs !== undefined ? `${job.phase} for ${formatDuration(timing.phaseElapsedMs)}` : job.phase : undefined
|
|
37236
|
+
].filter(Boolean);
|
|
37237
|
+
const nextAction = display === "running" ? `${runningDetail.length > 0 ? `${runningDetail.join(", ")}; ` : ""}chit_job_cancel to stop, or wait and poll again` : display === "queued" ? "queued; the worker is starting" : display === "stale" ? `worker appears dead; inspect with chit_job_status${latestRef ? ` (chit_audit_show ${latestRef} for the transcript)` : ""}, then start a fresh job` : `${display}${job.stopStatus ? ` (${job.stopStatus})` : ""}; ${latestRef ? `open a transcript with chit_audit_show ${latestRef}` : "no audit transcript was recorded"}`;
|
|
37122
37238
|
return {
|
|
37123
37239
|
jobId: job.jobId,
|
|
37124
37240
|
loopId: job.loopId,
|
|
@@ -37140,12 +37256,18 @@ function describeJob(job) {
|
|
|
37140
37256
|
...job.startedAt !== undefined && { startedAt: job.startedAt },
|
|
37141
37257
|
...job.endedAt !== undefined && { endedAt: job.endedAt },
|
|
37142
37258
|
...job.lastHeartbeatAt !== undefined && { lastHeartbeatAt: job.lastHeartbeatAt },
|
|
37259
|
+
...job.phaseStartedAt !== undefined && { phaseStartedAt: job.phaseStartedAt },
|
|
37260
|
+
...timing.elapsedMs !== undefined && { elapsedMs: timing.elapsedMs },
|
|
37261
|
+
...timing.lastHeartbeatAgeMs !== undefined && {
|
|
37262
|
+
lastHeartbeatAgeMs: timing.lastHeartbeatAgeMs
|
|
37263
|
+
},
|
|
37264
|
+
...timing.phaseElapsedMs !== undefined && { phaseElapsedMs: timing.phaseElapsedMs },
|
|
37143
37265
|
...latest !== undefined && { latest },
|
|
37144
37266
|
nextAction
|
|
37145
37267
|
};
|
|
37146
37268
|
}
|
|
37147
37269
|
server.registerTool("chit_job_status", {
|
|
37148
|
-
description: "Show one background job: state (queued/running/completed/cancelled/failed, or derived `stale` when the worker is gone), current phase, loop id, iterations, last verdict, audit refs, and the latest iteration's changed files / workspace warnings / usage. Read-only.",
|
|
37270
|
+
description: "Show one background job: state (queued/running/completed/cancelled/failed, or derived `stale` when the worker is gone), current phase, timing fields (elapsedMs, lastHeartbeatAgeMs, phaseElapsedMs), loop id, iterations, last verdict, audit refs, and the latest iteration's changed files / workspace warnings / usage. Read-only.",
|
|
37149
37271
|
inputSchema: { job_id: exports_external.string() }
|
|
37150
37272
|
}, async ({ job_id }) => {
|
|
37151
37273
|
const job = jobStore.get(job_id);
|
|
@@ -38092,9 +38214,10 @@ Permission enforcement: each participant's declared permissions are checked
|
|
|
38092
38214
|
against the chosen adapter's capabilities at install time. If the adapter
|
|
38093
38215
|
cannot enforce a permission, the run is rejected unless
|
|
38094
38216
|
--allow-unenforced-permissions is set. Both built-in adapters enforce
|
|
38095
|
-
filesystem read_only today: codex-exec via --sandbox read-only
|
|
38096
|
-
|
|
38097
|
-
not an
|
|
38217
|
+
filesystem read_only today: codex-exec via an OS sandbox (--sandbox read-only
|
|
38218
|
+
for a reviewer, --sandbox workspace-write for a write-capable implementer),
|
|
38219
|
+
claude-cli via --permission-mode plan (a Claude plan-mode permission, not an
|
|
38220
|
+
OS/filesystem sandbox).
|
|
38098
38221
|
|
|
38099
38222
|
Limitations in this build:
|
|
38100
38223
|
- file[] inputs are not yet supported via the CLI.
|