cruo-agent 0.1.7 → 0.1.8
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/VERSION +1 -1
- package/dist/cli.js +133 -9
- package/package.json +1 -1
package/dist/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.8
|
package/dist/cli.js
CHANGED
|
@@ -46228,7 +46228,12 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46228
46228
|
cacheRead: 0,
|
|
46229
46229
|
cacheWrite: 0,
|
|
46230
46230
|
cost: 0,
|
|
46231
|
-
measured: 0
|
|
46231
|
+
measured: 0,
|
|
46232
|
+
opening: 0,
|
|
46233
|
+
openingMeasured: 0,
|
|
46234
|
+
sysChars: 0,
|
|
46235
|
+
userChars: 0,
|
|
46236
|
+
charsMeasured: 0
|
|
46232
46237
|
});
|
|
46233
46238
|
const fold = (a, r) => {
|
|
46234
46239
|
a.runs += 1;
|
|
@@ -46242,6 +46247,16 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46242
46247
|
a.cacheWrite += n(r.cache_write_tokens);
|
|
46243
46248
|
a.cost += n(r.cost_usd);
|
|
46244
46249
|
if (r.input_tokens !== null || r.cost_usd !== null) a.measured += 1;
|
|
46250
|
+
const openingKnown = r.opening_context_input_tokens !== null || r.opening_context_cache_read_tokens !== null || r.opening_context_cache_write_tokens !== null;
|
|
46251
|
+
if (openingKnown) {
|
|
46252
|
+
a.opening += n(r.opening_context_input_tokens) + n(r.opening_context_cache_read_tokens) + n(r.opening_context_cache_write_tokens);
|
|
46253
|
+
a.openingMeasured += 1;
|
|
46254
|
+
}
|
|
46255
|
+
if (r.system_prompt_chars !== null || r.user_prompt_chars !== null) {
|
|
46256
|
+
a.sysChars += n(r.system_prompt_chars);
|
|
46257
|
+
a.userChars += n(r.user_prompt_chars);
|
|
46258
|
+
a.charsMeasured += 1;
|
|
46259
|
+
}
|
|
46245
46260
|
};
|
|
46246
46261
|
const byAgent = /* @__PURE__ */ new Map();
|
|
46247
46262
|
const total = blank();
|
|
@@ -46253,11 +46268,12 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46253
46268
|
const w = Math.max(12, ...[...byAgent.keys()].map((id) => nameOf(id).length));
|
|
46254
46269
|
console.log(
|
|
46255
46270
|
`
|
|
46256
|
-
${pad("agent", w)} ${rpad("runs", 5)} ${rpad("useful", 7)} ${rpad("dead", 5)} ${rpad("time", 7)} ${rpad("in", 8)} ${rpad("out", 8)} ${rpad("cost", 9)}`
|
|
46271
|
+
${pad("agent", w)} ${rpad("runs", 5)} ${rpad("useful", 7)} ${rpad("dead", 5)} ${rpad("time", 7)} ${rpad("in", 8)} ${rpad("out", 8)} ${rpad("opening", 8)} ${rpad("cost", 9)}`
|
|
46257
46272
|
);
|
|
46258
46273
|
for (const [id, a] of [...byAgent].sort((x, y) => y[1].runs - x[1].runs)) {
|
|
46274
|
+
const openingAvg = a.openingMeasured > 0 ? compact(Math.round(a.opening / a.openingMeasured)) : "\u2014";
|
|
46259
46275
|
console.log(
|
|
46260
|
-
` ${pad(nameOf(id), w)} ${rpad(String(a.runs), 5)} ${rpad(String(a.productive), 7)} ${rpad(String(a.neverRan), 5)} ${rpad(duration3(a.ms), 7)} ${rpad(compact(a.input + a.cacheRead), 8)} ${rpad(compact(a.output), 8)} ${rpad(a.cost > 0 ? `$${a.cost.toFixed(2)}` : "\u2014", 9)}`
|
|
46276
|
+
` ${pad(nameOf(id), w)} ${rpad(String(a.runs), 5)} ${rpad(String(a.productive), 7)} ${rpad(String(a.neverRan), 5)} ${rpad(duration3(a.ms), 7)} ${rpad(compact(a.input + a.cacheRead), 8)} ${rpad(compact(a.output), 8)} ${rpad(openingAvg, 8)} ${rpad(a.cost > 0 ? `$${a.cost.toFixed(2)}` : "\u2014", 9)}`
|
|
46261
46277
|
);
|
|
46262
46278
|
}
|
|
46263
46279
|
if (!opts.issue) {
|
|
@@ -46290,8 +46306,12 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46290
46306
|
console.log(`
|
|
46291
46307
|
run by run`);
|
|
46292
46308
|
for (const r of rows) {
|
|
46309
|
+
const openingKnown = r.opening_context_input_tokens !== null || r.opening_context_cache_read_tokens !== null || r.opening_context_cache_write_tokens !== null;
|
|
46310
|
+
const opening = openingKnown ? compact(
|
|
46311
|
+
n(r.opening_context_input_tokens) + n(r.opening_context_cache_read_tokens) + n(r.opening_context_cache_write_tokens)
|
|
46312
|
+
) : "\u2014";
|
|
46293
46313
|
console.log(
|
|
46294
|
-
` ${r.started_at.slice(0, 16).replace("T", " ")} ${pad(r.outcome, 13)} ${rpad(duration3(r.duration_ms), 6)} ${rpad(compact(n(r.output_tokens)), 7)} out ${nameOf(r.agent_id)}`
|
|
46314
|
+
` ${r.started_at.slice(0, 16).replace("T", " ")} ${pad(r.outcome, 13)} ${rpad(duration3(r.duration_ms), 6)} ${rpad(compact(n(r.output_tokens)), 7)} out ${rpad(opening, 7)} opening ${nameOf(r.agent_id)}`
|
|
46295
46315
|
);
|
|
46296
46316
|
}
|
|
46297
46317
|
}
|
|
@@ -46318,6 +46338,35 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46318
46338
|
} else {
|
|
46319
46339
|
console.log("");
|
|
46320
46340
|
}
|
|
46341
|
+
if (total.openingMeasured === 0) {
|
|
46342
|
+
console.log(
|
|
46343
|
+
` No opening-context figure: needs --usage AND a harness that reports
|
|
46344
|
+
per-turn usage on its own events, which is stricter than reporting a
|
|
46345
|
+
final total \u2014 some harnesses do the second and not the first.
|
|
46346
|
+
`
|
|
46347
|
+
);
|
|
46348
|
+
} else {
|
|
46349
|
+
const avg = Math.round(total.opening / total.openingMeasured);
|
|
46350
|
+
console.log(
|
|
46351
|
+
` opening context \u2014 what was loaded before any work happened, not a slice of "in":
|
|
46352
|
+
avg ${compact(avg)} tokens over ${total.openingMeasured} of ${total.runs} run(s) that reported a first turn.`
|
|
46353
|
+
);
|
|
46354
|
+
if (total.charsMeasured > 0) {
|
|
46355
|
+
const sysAvg = Math.round(total.sysChars / total.charsMeasured);
|
|
46356
|
+
const userAvg = Math.round(total.userChars / total.charsMeasured);
|
|
46357
|
+
console.log(
|
|
46358
|
+
` Known by source: the system prompt averaged ${sysAvg} chars, the user prompt
|
|
46359
|
+
${userAvg} \u2014 CHARACTERS, not tokens, because no tokenizer runs here, so this is
|
|
46360
|
+
not subtracted from the ${compact(avg)}-token figure above. The rest of the
|
|
46361
|
+
opening context \u2014 CLAUDE.md, the docs it points at, the card and its comments,
|
|
46362
|
+
and the MCP tool schemas \u2014 is read by the harness itself, off a filesystem and
|
|
46363
|
+
a tool list the supervisor cannot see, and is NOT broken down any further.
|
|
46364
|
+
`
|
|
46365
|
+
);
|
|
46366
|
+
} else {
|
|
46367
|
+
console.log("");
|
|
46368
|
+
}
|
|
46369
|
+
}
|
|
46321
46370
|
}
|
|
46322
46371
|
var n, pad, rpad, duration3;
|
|
46323
46372
|
var init_usage = __esm({
|
|
@@ -46371,6 +46420,29 @@ function usageIn(text) {
|
|
|
46371
46420
|
const measured = Object.values(out).some((v) => v !== void 0);
|
|
46372
46421
|
return measured ? out : null;
|
|
46373
46422
|
}
|
|
46423
|
+
function turnUsageIn(line) {
|
|
46424
|
+
let event;
|
|
46425
|
+
try {
|
|
46426
|
+
event = JSON.parse(line);
|
|
46427
|
+
} catch {
|
|
46428
|
+
return null;
|
|
46429
|
+
}
|
|
46430
|
+
if (typeof event !== "object" || event === null) return null;
|
|
46431
|
+
const e = event;
|
|
46432
|
+
if (e.type !== "assistant") return null;
|
|
46433
|
+
const message = e.message;
|
|
46434
|
+
const usage = message?.usage;
|
|
46435
|
+
if (!usage || typeof usage !== "object") return null;
|
|
46436
|
+
const out = {
|
|
46437
|
+
model: typeof message?.model === "string" ? message.model : void 0,
|
|
46438
|
+
inputTokens: num(usage.input_tokens) ?? num(usage.inputTokens),
|
|
46439
|
+
outputTokens: num(usage.output_tokens) ?? num(usage.outputTokens),
|
|
46440
|
+
cacheReadTokens: num(usage.cache_read_input_tokens) ?? num(usage.cacheReadInputTokens),
|
|
46441
|
+
cacheWriteTokens: num(usage.cache_creation_input_tokens) ?? num(usage.cacheCreationInputTokens)
|
|
46442
|
+
};
|
|
46443
|
+
const measured = Object.values(out).some((v) => v !== void 0);
|
|
46444
|
+
return measured ? out : null;
|
|
46445
|
+
}
|
|
46374
46446
|
function renderEvent(line) {
|
|
46375
46447
|
let event;
|
|
46376
46448
|
try {
|
|
@@ -46488,6 +46560,17 @@ var init_pacing = __esm({
|
|
|
46488
46560
|
}
|
|
46489
46561
|
});
|
|
46490
46562
|
|
|
46563
|
+
// src/queries.ts
|
|
46564
|
+
function blocksAgentPickup(state) {
|
|
46565
|
+
return state.requires_human === true;
|
|
46566
|
+
}
|
|
46567
|
+
var init_queries = __esm({
|
|
46568
|
+
"src/queries.ts"() {
|
|
46569
|
+
"use strict";
|
|
46570
|
+
init_dist();
|
|
46571
|
+
}
|
|
46572
|
+
});
|
|
46573
|
+
|
|
46491
46574
|
// src/worktree.ts
|
|
46492
46575
|
import { execFile as execFile2 } from "node:child_process";
|
|
46493
46576
|
import { mkdir as mkdir2, readdir as readdir2, rm as rm2, stat } from "node:fs/promises";
|
|
@@ -46680,6 +46763,12 @@ async function pollAssigned(ctx) {
|
|
|
46680
46763
|
const project = byProject.get(issue2.project_id);
|
|
46681
46764
|
if (!state || !project) return [];
|
|
46682
46765
|
if (options.project && project.key !== options.project) return [];
|
|
46766
|
+
if (blocksAgentPickup(state)) {
|
|
46767
|
+
log(
|
|
46768
|
+
` ${project.key}-${issue2.number} is in ${state.name}, which requires a human \u2014 not starting`
|
|
46769
|
+
);
|
|
46770
|
+
return [];
|
|
46771
|
+
}
|
|
46683
46772
|
if (state.category === "completed" || state.category === "canceled") return [];
|
|
46684
46773
|
const said = lastSaid.get(issue2.id);
|
|
46685
46774
|
if (said && issue2.updated_at && said > issue2.updated_at) return [];
|
|
@@ -46714,6 +46803,12 @@ async function poll(ctx, identity) {
|
|
|
46714
46803
|
const state = byState.get(issue2.status_id);
|
|
46715
46804
|
if (!project || !state) return [];
|
|
46716
46805
|
if (options.project && project.key !== options.project) return [];
|
|
46806
|
+
if (blocksAgentPickup(state)) {
|
|
46807
|
+
log(
|
|
46808
|
+
` ${project.key}-${issue2.number} is in ${state.name}, which requires a human \u2014 not starting`
|
|
46809
|
+
);
|
|
46810
|
+
return [];
|
|
46811
|
+
}
|
|
46717
46812
|
return [
|
|
46718
46813
|
{
|
|
46719
46814
|
ref: `${project.key}-${issue2.number}`,
|
|
@@ -47005,9 +47100,11 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47005
47100
|
options.allow.split(",").map((t) => t.trim()).filter((t) => t !== "" && !t.startsWith("mcp__")).map((t) => t.replace(/\(.*$/, ""))
|
|
47006
47101
|
)
|
|
47007
47102
|
].join(",");
|
|
47103
|
+
const userPromptText = userPrompt(hit);
|
|
47104
|
+
const systemPromptText = systemPrompt(ctx, identity, worktree);
|
|
47008
47105
|
const args = [
|
|
47009
47106
|
"-p",
|
|
47010
|
-
|
|
47107
|
+
userPromptText,
|
|
47011
47108
|
"--mcp-config",
|
|
47012
47109
|
mcpConfig,
|
|
47013
47110
|
// Both, always. See the note above: without `--restricted` the harness
|
|
@@ -47023,7 +47120,7 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47023
47120
|
"--allowedTools",
|
|
47024
47121
|
options.allow,
|
|
47025
47122
|
"--system-prompt",
|
|
47026
|
-
|
|
47123
|
+
systemPromptText,
|
|
47027
47124
|
...options.model ? ["--model", options.model] : [],
|
|
47028
47125
|
// `--verbose` is not optional alongside stream-json: without it the harness
|
|
47029
47126
|
// emits only the final result and the live view is a blank terminal for the
|
|
@@ -47045,6 +47142,7 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47045
47142
|
let tail = "";
|
|
47046
47143
|
let head2 = "";
|
|
47047
47144
|
let pending = "";
|
|
47145
|
+
let openingContext = null;
|
|
47048
47146
|
const addHead = (text) => {
|
|
47049
47147
|
if (head2.length < 2048) head2 += text.slice(0, 2048 - head2.length);
|
|
47050
47148
|
};
|
|
@@ -47063,6 +47161,7 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47063
47161
|
for (const line of lines) {
|
|
47064
47162
|
if (line.trim() === "") continue;
|
|
47065
47163
|
tail = line;
|
|
47164
|
+
if (openingContext === null) openingContext = turnUsageIn(line);
|
|
47066
47165
|
const rendered = renderEvent(line);
|
|
47067
47166
|
if (rendered.text) addHead(rendered.text + "\n");
|
|
47068
47167
|
if (rendered.show) process.stdout.write(rendered.show + "\n");
|
|
@@ -47086,13 +47185,17 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47086
47185
|
durationMs: Date.now() - startedAtMs,
|
|
47087
47186
|
usage: null,
|
|
47088
47187
|
killed,
|
|
47089
|
-
stdoutHead: headFor(head2)
|
|
47188
|
+
stdoutHead: headFor(head2),
|
|
47189
|
+
openingContext: null,
|
|
47190
|
+
systemPromptChars: systemPromptText.length,
|
|
47191
|
+
userPromptChars: userPromptText.length
|
|
47090
47192
|
});
|
|
47091
47193
|
});
|
|
47092
47194
|
child.on("close", (code) => {
|
|
47093
47195
|
clearTimeout(timer);
|
|
47094
47196
|
if (streaming && pending.trim() !== "") {
|
|
47095
47197
|
tail = pending;
|
|
47198
|
+
if (openingContext === null) openingContext = turnUsageIn(pending);
|
|
47096
47199
|
const rendered = renderEvent(pending);
|
|
47097
47200
|
if (rendered.text) addHead(rendered.text + "\n");
|
|
47098
47201
|
if (rendered.show) process.stdout.write(rendered.show + "\n");
|
|
@@ -47105,7 +47208,10 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47105
47208
|
durationMs: Date.now() - startedAtMs,
|
|
47106
47209
|
usage: usageIn(tail),
|
|
47107
47210
|
killed,
|
|
47108
|
-
stdoutHead: headFor(head2)
|
|
47211
|
+
stdoutHead: headFor(head2),
|
|
47212
|
+
openingContext,
|
|
47213
|
+
systemPromptChars: systemPromptText.length,
|
|
47214
|
+
userPromptChars: userPromptText.length
|
|
47109
47215
|
});
|
|
47110
47216
|
});
|
|
47111
47217
|
});
|
|
@@ -47207,6 +47313,16 @@ function announce(status) {
|
|
|
47207
47313
|
}
|
|
47208
47314
|
})();
|
|
47209
47315
|
}
|
|
47316
|
+
function beatWhileBusy(ctx, deadTicks) {
|
|
47317
|
+
const timer = setInterval(() => {
|
|
47318
|
+
void beat(ctx, { holding: lastHolding, deadTicks, intervalMs: options.intervalMs }).catch(
|
|
47319
|
+
() => {
|
|
47320
|
+
}
|
|
47321
|
+
);
|
|
47322
|
+
}, options.intervalMs);
|
|
47323
|
+
timer.unref?.();
|
|
47324
|
+
return () => clearInterval(timer);
|
|
47325
|
+
}
|
|
47210
47326
|
async function recordRun(ctx, hit, run, outcome) {
|
|
47211
47327
|
const { error: error51 } = await ctx.client.from("harness_runs").insert({
|
|
47212
47328
|
agent_id: ctx.userId,
|
|
@@ -47223,7 +47339,12 @@ async function recordRun(ctx, hit, run, outcome) {
|
|
|
47223
47339
|
output_tokens: run.usage?.outputTokens ?? null,
|
|
47224
47340
|
cache_read_tokens: run.usage?.cacheReadTokens ?? null,
|
|
47225
47341
|
cache_write_tokens: run.usage?.cacheWriteTokens ?? null,
|
|
47226
|
-
cost_usd: run.usage?.costUsd ?? null
|
|
47342
|
+
cost_usd: run.usage?.costUsd ?? null,
|
|
47343
|
+
opening_context_input_tokens: run.openingContext?.inputTokens ?? null,
|
|
47344
|
+
opening_context_cache_read_tokens: run.openingContext?.cacheReadTokens ?? null,
|
|
47345
|
+
opening_context_cache_write_tokens: run.openingContext?.cacheWriteTokens ?? null,
|
|
47346
|
+
system_prompt_chars: run.systemPromptChars,
|
|
47347
|
+
user_prompt_chars: run.userPromptChars
|
|
47227
47348
|
});
|
|
47228
47349
|
if (error51 && !warnedAboutSpendTable) {
|
|
47229
47350
|
warnedAboutSpendTable = true;
|
|
@@ -47314,6 +47435,7 @@ async function tick(ctx, identity, deadTicks, allowance) {
|
|
|
47314
47435
|
let run;
|
|
47315
47436
|
let committed = 0;
|
|
47316
47437
|
let salvaged = null;
|
|
47438
|
+
const stopBusyBeat = beatWhileBusy(ctx, deadTicks);
|
|
47317
47439
|
try {
|
|
47318
47440
|
run = await invokeHarness(ctx, identity, hit, worktree);
|
|
47319
47441
|
if (worktree) committed = await worktree.commits();
|
|
@@ -47336,6 +47458,7 @@ async function tick(ctx, identity, deadTicks, allowance) {
|
|
|
47336
47458
|
);
|
|
47337
47459
|
}
|
|
47338
47460
|
} finally {
|
|
47461
|
+
stopBusyBeat();
|
|
47339
47462
|
await release(ctx, hit);
|
|
47340
47463
|
}
|
|
47341
47464
|
const code = run.code;
|
|
@@ -47571,6 +47694,7 @@ var init_supervisor = __esm({
|
|
|
47571
47694
|
init_harness_signal();
|
|
47572
47695
|
init_process();
|
|
47573
47696
|
init_pacing();
|
|
47697
|
+
init_queries();
|
|
47574
47698
|
init_worktree();
|
|
47575
47699
|
argv = process.argv.slice(2);
|
|
47576
47700
|
flag = (name) => flagIn(argv, name);
|
package/package.json
CHANGED