@chit-run/cli 0.7.0 → 0.9.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 +191 -26
- package/package.json +1 -1
package/dist/chit.js
CHANGED
|
@@ -1473,6 +1473,24 @@ var init_parse = __esm(() => {
|
|
|
1473
1473
|
TEMPLATE_REF_RE = /\{\{\s*([\w.]+)\s*\}\}/g;
|
|
1474
1474
|
});
|
|
1475
1475
|
// ../../packages/core/src/show.ts
|
|
1476
|
+
function participantPermissionDisplay(p) {
|
|
1477
|
+
if (p.permissions.filesystem === "read_only") {
|
|
1478
|
+
return {
|
|
1479
|
+
filesystem: "read_only",
|
|
1480
|
+
readOnlyEnforcement: p.enforcesReadOnly ? "enforced" : "NOT ENFORCED",
|
|
1481
|
+
readOnlyEnforcementClass: p.enforcesReadOnly ? "ok" : "warn"
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
return {
|
|
1485
|
+
filesystem: "write",
|
|
1486
|
+
readOnlyEnforcement: p.enforcesReadOnly ? "not requested (adapter supports)" : "not requested (adapter cannot enforce)",
|
|
1487
|
+
readOnlyEnforcementClass: "info"
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
function participantPermissionText(p) {
|
|
1491
|
+
const display = participantPermissionDisplay(p);
|
|
1492
|
+
return `filesystem=${display.filesystem} read_only_enforcement=${display.readOnlyEnforcement}`;
|
|
1493
|
+
}
|
|
1476
1494
|
function configPairs(c) {
|
|
1477
1495
|
const pairs = [
|
|
1478
1496
|
["model", c.model ?? "default"],
|
|
@@ -1547,8 +1565,7 @@ function renderAscii(m) {
|
|
|
1547
1565
|
out.push("");
|
|
1548
1566
|
out.push("participants:");
|
|
1549
1567
|
for (const [pid, p] of Object.entries(m.participants)) {
|
|
1550
|
-
|
|
1551
|
-
out.push(` ${pid} agent=${p.agentId} session=${p.session} permissions=${p.permissions.filesystem} adapter=${p.adapter} ${enforces}`);
|
|
1568
|
+
out.push(` ${pid} agent=${p.agentId} session=${p.session} ${participantPermissionText(p)} adapter=${p.adapter}`);
|
|
1552
1569
|
if (p.adapter === "unknown") {
|
|
1553
1570
|
out.push(" config unresolved (unknown agent)");
|
|
1554
1571
|
} else {
|
|
@@ -1637,7 +1654,7 @@ function renderHtml(m) {
|
|
|
1637
1654
|
levelColumns.push(renderLevelColumn(m, level));
|
|
1638
1655
|
}
|
|
1639
1656
|
const participantsSection = Object.entries(m.participants).map(([pid, p]) => {
|
|
1640
|
-
const
|
|
1657
|
+
const permission = participantPermissionDisplay(p);
|
|
1641
1658
|
const configBadges = p.adapter === "unknown" ? '<span class="badge warn">config: unresolved (unknown agent)</span>' : configPairs(p.config).map(([k, v]) => `<span class="badge info">${escapeHtml(k)}: ${escapeHtml(v)}</span>`).join(`
|
|
1642
1659
|
`);
|
|
1643
1660
|
return `<div class="participant">
|
|
@@ -1646,8 +1663,8 @@ function renderHtml(m) {
|
|
|
1646
1663
|
<span class="badge info">agent: ${escapeHtml(p.agentId)}</span>
|
|
1647
1664
|
<span class="badge info">adapter: ${escapeHtml(p.adapter)}</span>
|
|
1648
1665
|
<span class="badge info">session: ${escapeHtml(p.session)}</span>
|
|
1649
|
-
<span class="badge info">filesystem: ${escapeHtml(
|
|
1650
|
-
${
|
|
1666
|
+
<span class="badge info">filesystem: ${escapeHtml(permission.filesystem)}</span>
|
|
1667
|
+
<span class="badge ${permission.readOnlyEnforcementClass}">read_only enforcement: ${escapeHtml(permission.readOnlyEnforcement)}</span>
|
|
1651
1668
|
</div>
|
|
1652
1669
|
<div class="participant-config">
|
|
1653
1670
|
${configBadges}
|
|
@@ -10820,6 +10837,11 @@ class ClaudeCliAdapter {
|
|
|
10820
10837
|
if (noProgress)
|
|
10821
10838
|
throw new Error(`claude --print made no progress for ${noProgressMs}ms`);
|
|
10822
10839
|
if (exitCode !== 0) {
|
|
10840
|
+
const rateLimit = detectClaudeRateLimit(`${stdoutText}
|
|
10841
|
+
${stderrText}`);
|
|
10842
|
+
if (rateLimit !== undefined) {
|
|
10843
|
+
throw new Error(`claude --print rate limited${rateLimit ? `: ${rateLimit}` : ` (exit ${exitCode})`}`);
|
|
10844
|
+
}
|
|
10823
10845
|
const cleaned = sanitize(stderrText || stdoutText, sensitive);
|
|
10824
10846
|
const tail = cleaned.trim().split(`
|
|
10825
10847
|
`).slice(-5).join(`
|
|
@@ -10953,6 +10975,42 @@ function parseClaudeResult(stdout) {
|
|
|
10953
10975
|
}
|
|
10954
10976
|
return result;
|
|
10955
10977
|
}
|
|
10978
|
+
function detectClaudeRateLimit(stdout) {
|
|
10979
|
+
const pickStr = (v) => typeof v === "string" && v.trim() !== "" ? v.trim().replace(/\s+/g, " ").slice(0, 120) : undefined;
|
|
10980
|
+
const pickNum = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
|
|
10981
|
+
let found = false;
|
|
10982
|
+
let detail = "";
|
|
10983
|
+
for (const line of stdout.split(`
|
|
10984
|
+
`)) {
|
|
10985
|
+
const trimmed = line.trim();
|
|
10986
|
+
if (!trimmed)
|
|
10987
|
+
continue;
|
|
10988
|
+
let evt;
|
|
10989
|
+
try {
|
|
10990
|
+
evt = JSON.parse(trimmed);
|
|
10991
|
+
} catch {
|
|
10992
|
+
continue;
|
|
10993
|
+
}
|
|
10994
|
+
if (evt.type !== "rate_limit_event")
|
|
10995
|
+
continue;
|
|
10996
|
+
found = true;
|
|
10997
|
+
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;
|
|
10998
|
+
const parts = [];
|
|
10999
|
+
const status = pickStr(rl.status);
|
|
11000
|
+
if (status)
|
|
11001
|
+
parts.push(`status=${status}`);
|
|
11002
|
+
const resetsAt = pickStr(rl.resetsAt);
|
|
11003
|
+
if (resetsAt)
|
|
11004
|
+
parts.push(`resets ${resetsAt}`);
|
|
11005
|
+
const retryAfter = pickNum(rl.retryAfter) ?? pickNum(rl.resetInSeconds);
|
|
11006
|
+
if (retryAfter !== undefined)
|
|
11007
|
+
parts.push(`retry after ${retryAfter}s`);
|
|
11008
|
+
if (rl.isUsingOverage === false)
|
|
11009
|
+
parts.push("overage disabled");
|
|
11010
|
+
detail = parts.join(", ");
|
|
11011
|
+
}
|
|
11012
|
+
return found ? detail : undefined;
|
|
11013
|
+
}
|
|
10956
11014
|
|
|
10957
11015
|
// src/adapters/codex-exec.ts
|
|
10958
11016
|
var DEFAULT_CALL_TIMEOUT_MS2 = 15 * 60000;
|
|
@@ -10972,7 +11030,7 @@ class CodexExecAdapter {
|
|
|
10972
11030
|
const sensitive = findSensitiveValues(this.config.env);
|
|
10973
11031
|
try {
|
|
10974
11032
|
const priorThreadId = getCodexThreadId(req.session);
|
|
10975
|
-
const cmd = this.buildCommand(priorThreadId);
|
|
11033
|
+
const cmd = this.buildCommand(priorThreadId, req.filesystem);
|
|
10976
11034
|
const proc = Bun.spawn({
|
|
10977
11035
|
cmd,
|
|
10978
11036
|
cwd: req.cwd,
|
|
@@ -11049,7 +11107,7 @@ class CodexExecAdapter {
|
|
|
11049
11107
|
throw new Error(message);
|
|
11050
11108
|
}
|
|
11051
11109
|
}
|
|
11052
|
-
buildCommand(priorThreadId) {
|
|
11110
|
+
buildCommand(priorThreadId, filesystem) {
|
|
11053
11111
|
if (priorThreadId) {
|
|
11054
11112
|
return ["codex", "exec", "resume", "--json", "--skip-git-repo-check", priorThreadId, "-"];
|
|
11055
11113
|
}
|
|
@@ -11059,7 +11117,8 @@ class CodexExecAdapter {
|
|
|
11059
11117
|
if (this.config.reasoningEffort) {
|
|
11060
11118
|
cmd.push("-c", `model_reasoning_effort="${this.config.reasoningEffort}"`);
|
|
11061
11119
|
}
|
|
11062
|
-
|
|
11120
|
+
const sandbox = filesystem === "write" ? "workspace-write" : "read-only";
|
|
11121
|
+
cmd.push("--sandbox", sandbox, "--skip-git-repo-check", "-");
|
|
11063
11122
|
return cmd;
|
|
11064
11123
|
}
|
|
11065
11124
|
}
|
|
@@ -12146,6 +12205,9 @@ function computeFingerprint(input) {
|
|
|
12146
12205
|
reasoningEffort: agent.reasoningEffort ?? null,
|
|
12147
12206
|
passModelOnResume: agent.adapter === "claude-cli" ? agent.passModelOnResume : null,
|
|
12148
12207
|
strictMcp: agent.adapter === "claude-cli" ? agent.strictMcp !== false : null,
|
|
12208
|
+
...agent.adapter === "codex-exec" && {
|
|
12209
|
+
codexSandbox: participant.permissions.filesystem === "write" ? "workspace-write" : "read-only"
|
|
12210
|
+
},
|
|
12149
12211
|
baseUrl,
|
|
12150
12212
|
role: participant.role,
|
|
12151
12213
|
session: participant.session,
|
|
@@ -12554,7 +12616,8 @@ async function runConvergeIteration(ctx) {
|
|
|
12554
12616
|
if (!result.ok) {
|
|
12555
12617
|
return {
|
|
12556
12618
|
ok: false,
|
|
12557
|
-
failure: `manifest run failed at step "${result.failedStep}": ${result.error}
|
|
12619
|
+
failure: `manifest run failed at step "${result.failedStep}": ${result.error}`,
|
|
12620
|
+
...result.auditRunId && { auditRunId: result.auditRunId }
|
|
12558
12621
|
};
|
|
12559
12622
|
}
|
|
12560
12623
|
const reviewText = result.outputs.review ?? "";
|
|
@@ -12923,7 +12986,12 @@ async function runJobWorker(jobId, deps) {
|
|
|
12923
12986
|
const workerToken = crypto.randomUUID();
|
|
12924
12987
|
const setPhase = (phase) => {
|
|
12925
12988
|
try {
|
|
12926
|
-
store.update(jobId, (c) => ({
|
|
12989
|
+
store.update(jobId, (c) => ({
|
|
12990
|
+
...c,
|
|
12991
|
+
phase,
|
|
12992
|
+
...c.phase !== phase && { phaseStartedAt: iso2(now()) },
|
|
12993
|
+
lastHeartbeatAt: iso2(now())
|
|
12994
|
+
}));
|
|
12927
12995
|
} catch {}
|
|
12928
12996
|
};
|
|
12929
12997
|
const controller = new AbortController;
|
|
@@ -12946,7 +13014,8 @@ async function runJobWorker(jobId, deps) {
|
|
|
12946
13014
|
pgid: process.pid,
|
|
12947
13015
|
workerToken,
|
|
12948
13016
|
lastHeartbeatAt: iso2(now()),
|
|
12949
|
-
phase: "starting"
|
|
13017
|
+
phase: "starting",
|
|
13018
|
+
phaseStartedAt: iso2(now())
|
|
12950
13019
|
}));
|
|
12951
13020
|
const resolved = resolveExecute(job);
|
|
12952
13021
|
if (!resolved.ok) {
|
|
@@ -12981,6 +13050,7 @@ async function runJobWorker(jobId, deps) {
|
|
|
12981
13050
|
...c,
|
|
12982
13051
|
iteration: i,
|
|
12983
13052
|
phase: "implementing",
|
|
13053
|
+
...c.phase !== "implementing" && { phaseStartedAt: iso2(now()) },
|
|
12984
13054
|
lastHeartbeatAt: iso2(now())
|
|
12985
13055
|
}));
|
|
12986
13056
|
let iter;
|
|
@@ -13010,6 +13080,10 @@ async function runJobWorker(jobId, deps) {
|
|
|
13010
13080
|
return;
|
|
13011
13081
|
}
|
|
13012
13082
|
if (!iter.ok) {
|
|
13083
|
+
if (iter.auditRunId) {
|
|
13084
|
+
const ref = iter.auditRunId;
|
|
13085
|
+
store.update(jobId, (c) => ({ ...c, auditRefs: [...c.auditRefs, ref] }));
|
|
13086
|
+
}
|
|
13013
13087
|
if (controller.signal.aborted) {
|
|
13014
13088
|
stopLoopSafely(job, "cancelled", "cancelled mid-iteration (signal)");
|
|
13015
13089
|
finish(store, jobId, now, "cancelled", { stopStatus: "cancelled" });
|
|
@@ -13022,6 +13096,7 @@ async function runJobWorker(jobId, deps) {
|
|
|
13022
13096
|
store.update(jobId, (c) => ({
|
|
13023
13097
|
...c,
|
|
13024
13098
|
phase: "recording",
|
|
13099
|
+
...c.phase !== "recording" && { phaseStartedAt: iso2(now()) },
|
|
13025
13100
|
iterationsCompleted: i,
|
|
13026
13101
|
lastVerdict: iter.verdict,
|
|
13027
13102
|
auditRefs: iter.auditRunId ? [...c.auditRefs, iter.auditRunId] : c.auditRefs,
|
|
@@ -13062,6 +13137,7 @@ function finish(store, jobId, now, state, extra) {
|
|
|
13062
13137
|
state,
|
|
13063
13138
|
endedAt: iso2(now()),
|
|
13064
13139
|
phase: undefined,
|
|
13140
|
+
phaseStartedAt: undefined,
|
|
13065
13141
|
lastHeartbeatAt: iso2(now()),
|
|
13066
13142
|
...extra.stopStatus !== undefined && { stopStatus: extra.stopStatus },
|
|
13067
13143
|
...extra.failure !== undefined && { failure: extra.failure }
|
|
@@ -35951,6 +36027,7 @@ class StdioServerTransport {
|
|
|
35951
36027
|
}
|
|
35952
36028
|
|
|
35953
36029
|
// src/audit/reader.ts
|
|
36030
|
+
init_src();
|
|
35954
36031
|
var USAGE_KEYS2 = [
|
|
35955
36032
|
"inputTokens",
|
|
35956
36033
|
"outputTokens",
|
|
@@ -36048,6 +36125,30 @@ function listAudit(store, limit) {
|
|
|
36048
36125
|
summaries.sort((a, b) => (b.startedAt ?? "").localeCompare(a.startedAt ?? ""));
|
|
36049
36126
|
return limit !== undefined ? summaries.slice(0, limit) : summaries;
|
|
36050
36127
|
}
|
|
36128
|
+
function receiptTimelineEvent(e) {
|
|
36129
|
+
if (e.type !== "run.started")
|
|
36130
|
+
return e;
|
|
36131
|
+
const { participants: _participants, ...rest } = e;
|
|
36132
|
+
return rest;
|
|
36133
|
+
}
|
|
36134
|
+
function participantReceipts(snapshots) {
|
|
36135
|
+
if (snapshots === undefined)
|
|
36136
|
+
return;
|
|
36137
|
+
return Object.fromEntries(Object.entries(snapshots).map(([pid, p]) => {
|
|
36138
|
+
const permission = participantPermissionDisplay(p);
|
|
36139
|
+
return [
|
|
36140
|
+
pid,
|
|
36141
|
+
{
|
|
36142
|
+
agentId: p.agentId,
|
|
36143
|
+
adapter: p.adapter,
|
|
36144
|
+
session: p.session,
|
|
36145
|
+
filesystem: permission.filesystem,
|
|
36146
|
+
readOnlyEnforcement: permission.readOnlyEnforcement,
|
|
36147
|
+
config: p.config
|
|
36148
|
+
}
|
|
36149
|
+
];
|
|
36150
|
+
}));
|
|
36151
|
+
}
|
|
36051
36152
|
function readBody(store, runId, ref) {
|
|
36052
36153
|
try {
|
|
36053
36154
|
return store.readBlob(runId, ref);
|
|
@@ -36064,21 +36165,22 @@ function hiddenAdapterEventCount(events2) {
|
|
|
36064
36165
|
function auditTimeline(store, runId, events2, opts) {
|
|
36065
36166
|
const rows = opts.verbose ? events2 : events2.filter(isReceiptEvent);
|
|
36066
36167
|
return rows.map((e) => {
|
|
36168
|
+
const row = receiptTimelineEvent(e);
|
|
36067
36169
|
if (!opts.includeBodies)
|
|
36068
|
-
return
|
|
36170
|
+
return row;
|
|
36069
36171
|
if (e.type === "adapter.call.started") {
|
|
36070
|
-
return { ...
|
|
36172
|
+
return { ...row, input: readBody(store, runId, e.inputBlob) };
|
|
36071
36173
|
}
|
|
36072
36174
|
if (e.type === "adapter.event" && e.rawBlob !== undefined) {
|
|
36073
|
-
return { ...
|
|
36175
|
+
return { ...row, raw: readBody(store, runId, e.rawBlob) };
|
|
36074
36176
|
}
|
|
36075
36177
|
if (e.type === "adapter.call.completed") {
|
|
36076
|
-
return { ...
|
|
36178
|
+
return { ...row, output: readBody(store, runId, e.outputBlob) };
|
|
36077
36179
|
}
|
|
36078
36180
|
if (e.type === "step.completed" && e.outputBlob !== undefined) {
|
|
36079
|
-
return { ...
|
|
36181
|
+
return { ...row, output: readBody(store, runId, e.outputBlob) };
|
|
36080
36182
|
}
|
|
36081
|
-
return
|
|
36183
|
+
return row;
|
|
36082
36184
|
});
|
|
36083
36185
|
}
|
|
36084
36186
|
function showAudit(store, runId, opts) {
|
|
@@ -36092,7 +36194,7 @@ function showAudit(store, runId, opts) {
|
|
|
36092
36194
|
out.incompleteReason = describeIncomplete(summary, events2);
|
|
36093
36195
|
const started = events2.find((e) => e.type === "run.started");
|
|
36094
36196
|
if (started?.type === "run.started" && started.participants !== undefined) {
|
|
36095
|
-
out.participants = started.participants;
|
|
36197
|
+
out.participants = participantReceipts(started.participants);
|
|
36096
36198
|
}
|
|
36097
36199
|
if (!opts.verbose) {
|
|
36098
36200
|
const hidden = hiddenAdapterEventCount(events2);
|
|
@@ -36126,6 +36228,40 @@ function isStale(job, nowMs, staleAfterMs = STALE_AFTER_MS) {
|
|
|
36126
36228
|
const heartbeatOld = !Number.isFinite(beat) || nowMs - beat > staleAfterMs;
|
|
36127
36229
|
return heartbeatOld || !pidAlive(job.pid);
|
|
36128
36230
|
}
|
|
36231
|
+
function jobTiming(job, nowMs) {
|
|
36232
|
+
const inFlight = job.state === "queued" || job.state === "running";
|
|
36233
|
+
const timing = {};
|
|
36234
|
+
const startMs = Date.parse(job.startedAt ?? job.createdAt);
|
|
36235
|
+
const endMs = job.endedAt ? Date.parse(job.endedAt) : nowMs;
|
|
36236
|
+
if (Number.isFinite(startMs) && Number.isFinite(endMs) && endMs >= startMs) {
|
|
36237
|
+
timing.elapsedMs = endMs - startMs;
|
|
36238
|
+
}
|
|
36239
|
+
if (inFlight && job.lastHeartbeatAt) {
|
|
36240
|
+
const beat = Date.parse(job.lastHeartbeatAt);
|
|
36241
|
+
if (Number.isFinite(beat) && nowMs >= beat)
|
|
36242
|
+
timing.lastHeartbeatAgeMs = nowMs - beat;
|
|
36243
|
+
}
|
|
36244
|
+
if (job.phase !== undefined && job.phaseStartedAt) {
|
|
36245
|
+
const phaseStart = Date.parse(job.phaseStartedAt);
|
|
36246
|
+
if (Number.isFinite(phaseStart) && nowMs >= phaseStart) {
|
|
36247
|
+
timing.phaseElapsedMs = nowMs - phaseStart;
|
|
36248
|
+
}
|
|
36249
|
+
}
|
|
36250
|
+
return timing;
|
|
36251
|
+
}
|
|
36252
|
+
function formatDuration(ms) {
|
|
36253
|
+
const totalSec = Math.floor(ms / 1000);
|
|
36254
|
+
if (totalSec < 60)
|
|
36255
|
+
return `${totalSec}s`;
|
|
36256
|
+
const totalMin = Math.floor(totalSec / 60);
|
|
36257
|
+
if (totalMin < 60) {
|
|
36258
|
+
const sec = totalSec % 60;
|
|
36259
|
+
return sec ? `${totalMin}m${sec}s` : `${totalMin}m`;
|
|
36260
|
+
}
|
|
36261
|
+
const hours = Math.floor(totalMin / 60);
|
|
36262
|
+
const min = totalMin % 60;
|
|
36263
|
+
return min ? `${hours}h${min}m` : `${hours}h`;
|
|
36264
|
+
}
|
|
36129
36265
|
|
|
36130
36266
|
// src/surfaces/mcp/converge-engine.ts
|
|
36131
36267
|
class ConvergeEngineError extends Error {
|
|
@@ -36578,10 +36714,22 @@ function summarizeRunForStatus(run) {
|
|
|
36578
36714
|
audited: run.recorder !== undefined && run.recorder.lastError === undefined
|
|
36579
36715
|
};
|
|
36580
36716
|
}
|
|
36717
|
+
function runningNextAction(job, timing) {
|
|
36718
|
+
const parts = [];
|
|
36719
|
+
if (timing.elapsedMs !== undefined)
|
|
36720
|
+
parts.push(`running for ${formatDuration(timing.elapsedMs)}`);
|
|
36721
|
+
if (job.phase) {
|
|
36722
|
+
parts.push(timing.phaseElapsedMs !== undefined ? `${job.phase} for ${formatDuration(timing.phaseElapsedMs)}` : job.phase);
|
|
36723
|
+
}
|
|
36724
|
+
const lead = parts.length > 0 ? parts.join(", ") : "in progress";
|
|
36725
|
+
return `${lead}; chit_job_status / chit_job_cancel "${job.jobId}"`;
|
|
36726
|
+
}
|
|
36581
36727
|
function summarizeJobForStatus(job, nowMs) {
|
|
36582
36728
|
const stale = isStale(job, nowMs);
|
|
36583
36729
|
const display = stale ? "stale" : job.state;
|
|
36584
|
-
const
|
|
36730
|
+
const timing = jobTiming(job, nowMs);
|
|
36731
|
+
const latestRef = job.auditRefs.at(-1);
|
|
36732
|
+
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
36733
|
return {
|
|
36586
36734
|
jobId: job.jobId,
|
|
36587
36735
|
loopId: job.loopId,
|
|
@@ -36594,6 +36742,11 @@ function summarizeJobForStatus(job, nowMs) {
|
|
|
36594
36742
|
...job.stopStatus !== undefined && { stopStatus: job.stopStatus },
|
|
36595
36743
|
auditRefs: job.auditRefs,
|
|
36596
36744
|
createdAt: job.createdAt,
|
|
36745
|
+
...timing.elapsedMs !== undefined && { elapsedMs: timing.elapsedMs },
|
|
36746
|
+
...timing.lastHeartbeatAgeMs !== undefined && {
|
|
36747
|
+
lastHeartbeatAgeMs: timing.lastHeartbeatAgeMs
|
|
36748
|
+
},
|
|
36749
|
+
...timing.phaseElapsedMs !== undefined && { phaseElapsedMs: timing.phaseElapsedMs },
|
|
36597
36750
|
nextAction
|
|
36598
36751
|
};
|
|
36599
36752
|
}
|
|
@@ -37118,7 +37271,13 @@ function describeJob(job) {
|
|
|
37118
37271
|
};
|
|
37119
37272
|
}
|
|
37120
37273
|
} catch {}
|
|
37121
|
-
const
|
|
37274
|
+
const timing = jobTiming(job, now);
|
|
37275
|
+
const latestRef = job.auditRefs.at(-1);
|
|
37276
|
+
const runningDetail = [
|
|
37277
|
+
timing.elapsedMs !== undefined ? `running for ${formatDuration(timing.elapsedMs)}` : undefined,
|
|
37278
|
+
job.phase ? timing.phaseElapsedMs !== undefined ? `${job.phase} for ${formatDuration(timing.phaseElapsedMs)}` : job.phase : undefined
|
|
37279
|
+
].filter(Boolean);
|
|
37280
|
+
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
37281
|
return {
|
|
37123
37282
|
jobId: job.jobId,
|
|
37124
37283
|
loopId: job.loopId,
|
|
@@ -37140,12 +37299,18 @@ function describeJob(job) {
|
|
|
37140
37299
|
...job.startedAt !== undefined && { startedAt: job.startedAt },
|
|
37141
37300
|
...job.endedAt !== undefined && { endedAt: job.endedAt },
|
|
37142
37301
|
...job.lastHeartbeatAt !== undefined && { lastHeartbeatAt: job.lastHeartbeatAt },
|
|
37302
|
+
...job.phaseStartedAt !== undefined && { phaseStartedAt: job.phaseStartedAt },
|
|
37303
|
+
...timing.elapsedMs !== undefined && { elapsedMs: timing.elapsedMs },
|
|
37304
|
+
...timing.lastHeartbeatAgeMs !== undefined && {
|
|
37305
|
+
lastHeartbeatAgeMs: timing.lastHeartbeatAgeMs
|
|
37306
|
+
},
|
|
37307
|
+
...timing.phaseElapsedMs !== undefined && { phaseElapsedMs: timing.phaseElapsedMs },
|
|
37143
37308
|
...latest !== undefined && { latest },
|
|
37144
37309
|
nextAction
|
|
37145
37310
|
};
|
|
37146
37311
|
}
|
|
37147
37312
|
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.",
|
|
37313
|
+
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
37314
|
inputSchema: { job_id: exports_external.string() }
|
|
37150
37315
|
}, async ({ job_id }) => {
|
|
37151
37316
|
const job = jobStore.get(job_id);
|
|
@@ -37337,8 +37502,7 @@ participants (recorded config):
|
|
|
37337
37502
|
`);
|
|
37338
37503
|
} else {
|
|
37339
37504
|
for (const [pid, p] of Object.entries(snapshots)) {
|
|
37340
|
-
|
|
37341
|
-
io.out(` ${pid} agent=${p.agentId} session=${p.session} permissions=${p.permissions.filesystem} adapter=${p.adapter} ${enforces}
|
|
37505
|
+
io.out(` ${pid} agent=${p.agentId} session=${p.session} ${participantPermissionText(p)} adapter=${p.adapter}
|
|
37342
37506
|
`);
|
|
37343
37507
|
const pairs = p.adapter === "unknown" ? "unresolved (unknown agent)" : configPairs(p.config).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
37344
37508
|
io.out(` config ${pairs}
|
|
@@ -38092,9 +38256,10 @@ Permission enforcement: each participant's declared permissions are checked
|
|
|
38092
38256
|
against the chosen adapter's capabilities at install time. If the adapter
|
|
38093
38257
|
cannot enforce a permission, the run is rejected unless
|
|
38094
38258
|
--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
|
|
38259
|
+
filesystem read_only today: codex-exec via an OS sandbox (--sandbox read-only
|
|
38260
|
+
for a reviewer, --sandbox workspace-write for a write-capable implementer),
|
|
38261
|
+
claude-cli via --permission-mode plan (a Claude plan-mode permission, not an
|
|
38262
|
+
OS/filesystem sandbox).
|
|
38098
38263
|
|
|
38099
38264
|
Limitations in this build:
|
|
38100
38265
|
- file[] inputs are not yet supported via the CLI.
|