cruo-agent 0.1.6 → 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 +231 -12
- package/package.json +1 -1
package/dist/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.8
|
package/dist/cli.js
CHANGED
|
@@ -45905,6 +45905,14 @@ function stripTokenFlag(argv2) {
|
|
|
45905
45905
|
if (at < 0) return [...argv2];
|
|
45906
45906
|
return [...argv2.slice(0, at), ...argv2.slice(at + 2)];
|
|
45907
45907
|
}
|
|
45908
|
+
function isKnownCommandWord(first) {
|
|
45909
|
+
if (first === void 0) return true;
|
|
45910
|
+
if (first.startsWith("-")) return true;
|
|
45911
|
+
return CRUO_COMMANDS.includes(first);
|
|
45912
|
+
}
|
|
45913
|
+
function nearestCommands(first) {
|
|
45914
|
+
return CRUO_COMMANDS.filter((k) => k[0] === first[0]).slice(0, 3);
|
|
45915
|
+
}
|
|
45908
45916
|
function numericIn(argv2, name, spec = {}) {
|
|
45909
45917
|
const i = argv2.indexOf(`--${name}`);
|
|
45910
45918
|
if (i < 0) return spec.fallback;
|
|
@@ -45939,10 +45947,24 @@ function requiredNumericIn(argv2, name, fallback, spec = {}) {
|
|
|
45939
45947
|
function secondsIn(argv2, name, fallbackSeconds) {
|
|
45940
45948
|
return requiredNumericIn(argv2, name, fallbackSeconds, { unit: "seconds" }) * 1e3;
|
|
45941
45949
|
}
|
|
45942
|
-
var OptionError, flagIn, optIn;
|
|
45950
|
+
var CRUO_COMMANDS, OptionError, flagIn, optIn;
|
|
45943
45951
|
var init_options = __esm({
|
|
45944
45952
|
"src/options.ts"() {
|
|
45945
45953
|
"use strict";
|
|
45954
|
+
CRUO_COMMANDS = [
|
|
45955
|
+
"login",
|
|
45956
|
+
"logout",
|
|
45957
|
+
"agents",
|
|
45958
|
+
"whoami",
|
|
45959
|
+
"usage",
|
|
45960
|
+
"help",
|
|
45961
|
+
"start",
|
|
45962
|
+
"ps",
|
|
45963
|
+
"stop",
|
|
45964
|
+
"pause",
|
|
45965
|
+
"resume",
|
|
45966
|
+
"logs"
|
|
45967
|
+
];
|
|
45946
45968
|
OptionError = class extends Error {
|
|
45947
45969
|
constructor(message) {
|
|
45948
45970
|
super(message);
|
|
@@ -46206,7 +46228,12 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46206
46228
|
cacheRead: 0,
|
|
46207
46229
|
cacheWrite: 0,
|
|
46208
46230
|
cost: 0,
|
|
46209
|
-
measured: 0
|
|
46231
|
+
measured: 0,
|
|
46232
|
+
opening: 0,
|
|
46233
|
+
openingMeasured: 0,
|
|
46234
|
+
sysChars: 0,
|
|
46235
|
+
userChars: 0,
|
|
46236
|
+
charsMeasured: 0
|
|
46210
46237
|
});
|
|
46211
46238
|
const fold = (a, r) => {
|
|
46212
46239
|
a.runs += 1;
|
|
@@ -46220,6 +46247,16 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46220
46247
|
a.cacheWrite += n(r.cache_write_tokens);
|
|
46221
46248
|
a.cost += n(r.cost_usd);
|
|
46222
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
|
+
}
|
|
46223
46260
|
};
|
|
46224
46261
|
const byAgent = /* @__PURE__ */ new Map();
|
|
46225
46262
|
const total = blank();
|
|
@@ -46231,11 +46268,12 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46231
46268
|
const w = Math.max(12, ...[...byAgent.keys()].map((id) => nameOf(id).length));
|
|
46232
46269
|
console.log(
|
|
46233
46270
|
`
|
|
46234
|
-
${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)}`
|
|
46235
46272
|
);
|
|
46236
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";
|
|
46237
46275
|
console.log(
|
|
46238
|
-
` ${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)}`
|
|
46239
46277
|
);
|
|
46240
46278
|
}
|
|
46241
46279
|
if (!opts.issue) {
|
|
@@ -46268,8 +46306,12 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46268
46306
|
console.log(`
|
|
46269
46307
|
run by run`);
|
|
46270
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";
|
|
46271
46313
|
console.log(
|
|
46272
|
-
` ${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)}`
|
|
46273
46315
|
);
|
|
46274
46316
|
}
|
|
46275
46317
|
}
|
|
@@ -46296,6 +46338,35 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
|
|
|
46296
46338
|
} else {
|
|
46297
46339
|
console.log("");
|
|
46298
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
|
+
}
|
|
46299
46370
|
}
|
|
46300
46371
|
var n, pad, rpad, duration3;
|
|
46301
46372
|
var init_usage = __esm({
|
|
@@ -46349,6 +46420,29 @@ function usageIn(text) {
|
|
|
46349
46420
|
const measured = Object.values(out).some((v) => v !== void 0);
|
|
46350
46421
|
return measured ? out : null;
|
|
46351
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
|
+
}
|
|
46352
46446
|
function renderEvent(line) {
|
|
46353
46447
|
let event;
|
|
46354
46448
|
try {
|
|
@@ -46466,6 +46560,17 @@ var init_pacing = __esm({
|
|
|
46466
46560
|
}
|
|
46467
46561
|
});
|
|
46468
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
|
+
|
|
46469
46574
|
// src/worktree.ts
|
|
46470
46575
|
import { execFile as execFile2 } from "node:child_process";
|
|
46471
46576
|
import { mkdir as mkdir2, readdir as readdir2, rm as rm2, stat } from "node:fs/promises";
|
|
@@ -46658,6 +46763,12 @@ async function pollAssigned(ctx) {
|
|
|
46658
46763
|
const project = byProject.get(issue2.project_id);
|
|
46659
46764
|
if (!state || !project) return [];
|
|
46660
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
|
+
}
|
|
46661
46772
|
if (state.category === "completed" || state.category === "canceled") return [];
|
|
46662
46773
|
const said = lastSaid.get(issue2.id);
|
|
46663
46774
|
if (said && issue2.updated_at && said > issue2.updated_at) return [];
|
|
@@ -46692,6 +46803,12 @@ async function poll(ctx, identity) {
|
|
|
46692
46803
|
const state = byState.get(issue2.status_id);
|
|
46693
46804
|
if (!project || !state) return [];
|
|
46694
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
|
+
}
|
|
46695
46812
|
return [
|
|
46696
46813
|
{
|
|
46697
46814
|
ref: `${project.key}-${issue2.number}`,
|
|
@@ -46978,11 +47095,24 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
46978
47095
|
const cwd = worktree?.path ?? options.cwd;
|
|
46979
47096
|
const { path: mcpConfig, cleanup } = await writeMcpConfig();
|
|
46980
47097
|
const streaming = options.usage === true;
|
|
47098
|
+
const builtinTools = [
|
|
47099
|
+
...new Set(
|
|
47100
|
+
options.allow.split(",").map((t) => t.trim()).filter((t) => t !== "" && !t.startsWith("mcp__")).map((t) => t.replace(/\(.*$/, ""))
|
|
47101
|
+
)
|
|
47102
|
+
].join(",");
|
|
47103
|
+
const userPromptText = userPrompt(hit);
|
|
47104
|
+
const systemPromptText = systemPrompt(ctx, identity, worktree);
|
|
46981
47105
|
const args = [
|
|
46982
47106
|
"-p",
|
|
46983
|
-
|
|
47107
|
+
userPromptText,
|
|
46984
47108
|
"--mcp-config",
|
|
46985
47109
|
mcpConfig,
|
|
47110
|
+
// Both, always. See the note above: without `--restricted` the harness
|
|
47111
|
+
// inherits the operator's settings, and without `--tools` it keeps every
|
|
47112
|
+
// built-in that `--restricted` does not itself remove.
|
|
47113
|
+
"--restricted",
|
|
47114
|
+
"--tools",
|
|
47115
|
+
builtinTools,
|
|
46986
47116
|
// Only the server we just described. Without this the harness would also
|
|
46987
47117
|
// load the developer's own .mcp.json — including, on this machine, a Cruo
|
|
46988
47118
|
// token belonging to a human.
|
|
@@ -46990,7 +47120,7 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
46990
47120
|
"--allowedTools",
|
|
46991
47121
|
options.allow,
|
|
46992
47122
|
"--system-prompt",
|
|
46993
|
-
|
|
47123
|
+
systemPromptText,
|
|
46994
47124
|
...options.model ? ["--model", options.model] : [],
|
|
46995
47125
|
// `--verbose` is not optional alongside stream-json: without it the harness
|
|
46996
47126
|
// emits only the final result and the live view is a blank terminal for the
|
|
@@ -47012,6 +47142,7 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47012
47142
|
let tail = "";
|
|
47013
47143
|
let head2 = "";
|
|
47014
47144
|
let pending = "";
|
|
47145
|
+
let openingContext = null;
|
|
47015
47146
|
const addHead = (text) => {
|
|
47016
47147
|
if (head2.length < 2048) head2 += text.slice(0, 2048 - head2.length);
|
|
47017
47148
|
};
|
|
@@ -47030,6 +47161,7 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47030
47161
|
for (const line of lines) {
|
|
47031
47162
|
if (line.trim() === "") continue;
|
|
47032
47163
|
tail = line;
|
|
47164
|
+
if (openingContext === null) openingContext = turnUsageIn(line);
|
|
47033
47165
|
const rendered = renderEvent(line);
|
|
47034
47166
|
if (rendered.text) addHead(rendered.text + "\n");
|
|
47035
47167
|
if (rendered.show) process.stdout.write(rendered.show + "\n");
|
|
@@ -47053,13 +47185,17 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47053
47185
|
durationMs: Date.now() - startedAtMs,
|
|
47054
47186
|
usage: null,
|
|
47055
47187
|
killed,
|
|
47056
|
-
stdoutHead: headFor(head2)
|
|
47188
|
+
stdoutHead: headFor(head2),
|
|
47189
|
+
openingContext: null,
|
|
47190
|
+
systemPromptChars: systemPromptText.length,
|
|
47191
|
+
userPromptChars: userPromptText.length
|
|
47057
47192
|
});
|
|
47058
47193
|
});
|
|
47059
47194
|
child.on("close", (code) => {
|
|
47060
47195
|
clearTimeout(timer);
|
|
47061
47196
|
if (streaming && pending.trim() !== "") {
|
|
47062
47197
|
tail = pending;
|
|
47198
|
+
if (openingContext === null) openingContext = turnUsageIn(pending);
|
|
47063
47199
|
const rendered = renderEvent(pending);
|
|
47064
47200
|
if (rendered.text) addHead(rendered.text + "\n");
|
|
47065
47201
|
if (rendered.show) process.stdout.write(rendered.show + "\n");
|
|
@@ -47072,7 +47208,10 @@ async function invokeHarness(ctx, identity, hit, worktree) {
|
|
|
47072
47208
|
durationMs: Date.now() - startedAtMs,
|
|
47073
47209
|
usage: usageIn(tail),
|
|
47074
47210
|
killed,
|
|
47075
|
-
stdoutHead: headFor(head2)
|
|
47211
|
+
stdoutHead: headFor(head2),
|
|
47212
|
+
openingContext,
|
|
47213
|
+
systemPromptChars: systemPromptText.length,
|
|
47214
|
+
userPromptChars: userPromptText.length
|
|
47076
47215
|
});
|
|
47077
47216
|
});
|
|
47078
47217
|
});
|
|
@@ -47174,6 +47313,16 @@ function announce(status) {
|
|
|
47174
47313
|
}
|
|
47175
47314
|
})();
|
|
47176
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
|
+
}
|
|
47177
47326
|
async function recordRun(ctx, hit, run, outcome) {
|
|
47178
47327
|
const { error: error51 } = await ctx.client.from("harness_runs").insert({
|
|
47179
47328
|
agent_id: ctx.userId,
|
|
@@ -47190,7 +47339,12 @@ async function recordRun(ctx, hit, run, outcome) {
|
|
|
47190
47339
|
output_tokens: run.usage?.outputTokens ?? null,
|
|
47191
47340
|
cache_read_tokens: run.usage?.cacheReadTokens ?? null,
|
|
47192
47341
|
cache_write_tokens: run.usage?.cacheWriteTokens ?? null,
|
|
47193
|
-
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
|
|
47194
47348
|
});
|
|
47195
47349
|
if (error51 && !warnedAboutSpendTable) {
|
|
47196
47350
|
warnedAboutSpendTable = true;
|
|
@@ -47281,6 +47435,7 @@ async function tick(ctx, identity, deadTicks, allowance) {
|
|
|
47281
47435
|
let run;
|
|
47282
47436
|
let committed = 0;
|
|
47283
47437
|
let salvaged = null;
|
|
47438
|
+
const stopBusyBeat = beatWhileBusy(ctx, deadTicks);
|
|
47284
47439
|
try {
|
|
47285
47440
|
run = await invokeHarness(ctx, identity, hit, worktree);
|
|
47286
47441
|
if (worktree) committed = await worktree.commits();
|
|
@@ -47303,6 +47458,7 @@ async function tick(ctx, identity, deadTicks, allowance) {
|
|
|
47303
47458
|
);
|
|
47304
47459
|
}
|
|
47305
47460
|
} finally {
|
|
47461
|
+
stopBusyBeat();
|
|
47306
47462
|
await release(ctx, hit);
|
|
47307
47463
|
}
|
|
47308
47464
|
const code = run.code;
|
|
@@ -47416,6 +47572,22 @@ async function main() {
|
|
|
47416
47572
|
installControls();
|
|
47417
47573
|
const runName = identityName();
|
|
47418
47574
|
if (!options.once && !options.dryRun) {
|
|
47575
|
+
const existing = await liveness(runName, true);
|
|
47576
|
+
if (existing.state === "running") {
|
|
47577
|
+
console.error(
|
|
47578
|
+
`
|
|
47579
|
+
${runName} is already running here (pid ${existing.record.pid}, up ${since(existing.record.startedAt)}).
|
|
47580
|
+
|
|
47581
|
+
Two supervisors for one agent share a token, a queue and a heartbeat,
|
|
47582
|
+
and the second would take over the first one's record \u2014 leaving the
|
|
47583
|
+
first with no way to be stopped except by pid.
|
|
47584
|
+
|
|
47585
|
+
stop it cruo stop ${runName}
|
|
47586
|
+
look at it cruo ps
|
|
47587
|
+
`
|
|
47588
|
+
);
|
|
47589
|
+
process.exit(2);
|
|
47590
|
+
}
|
|
47419
47591
|
await writeRecord({
|
|
47420
47592
|
agent: runName,
|
|
47421
47593
|
pid: process.pid,
|
|
@@ -47522,6 +47694,7 @@ var init_supervisor = __esm({
|
|
|
47522
47694
|
init_harness_signal();
|
|
47523
47695
|
init_process();
|
|
47524
47696
|
init_pacing();
|
|
47697
|
+
init_queries();
|
|
47525
47698
|
init_worktree();
|
|
47526
47699
|
argv = process.argv.slice(2);
|
|
47527
47700
|
flag = (name) => flagIn(argv, name);
|
|
@@ -47962,7 +48135,19 @@ ${name} is not running. Start it with \`cruo start --as ${name}\`.
|
|
|
47962
48135
|
async function startDetached(argv2, asName) {
|
|
47963
48136
|
const { spawn: spawn2 } = await import("node:child_process");
|
|
47964
48137
|
const { open, mkdir: mkdir4 } = await import("node:fs/promises");
|
|
47965
|
-
const
|
|
48138
|
+
const positional = argv2[1] && !argv2[1].startsWith("--") ? argv2[1] : null;
|
|
48139
|
+
if (positional && asName && safeName(positional) !== safeName(asName)) {
|
|
48140
|
+
console.error(
|
|
48141
|
+
`
|
|
48142
|
+
Two different agents named: \`${positional}\` and \`--as ${asName}\`.
|
|
48143
|
+
|
|
48144
|
+
Say one: cruo start ${positional} \u2026
|
|
48145
|
+
or cruo start --as ${asName} \u2026
|
|
48146
|
+
`
|
|
48147
|
+
);
|
|
48148
|
+
process.exit(2);
|
|
48149
|
+
}
|
|
48150
|
+
const name = await targetName(positional, asName);
|
|
47966
48151
|
const already = await liveness(name, true);
|
|
47967
48152
|
if (already.state === "running") {
|
|
47968
48153
|
console.error(
|
|
@@ -47973,10 +48158,30 @@ Stop it first, or use --as <name> to run a different agent.
|
|
|
47973
48158
|
);
|
|
47974
48159
|
process.exit(1);
|
|
47975
48160
|
}
|
|
48161
|
+
const config3 = await readConfig2();
|
|
48162
|
+
const storedKey = Object.keys(config3.agents).find((k) => safeName(k) === name) ?? null;
|
|
48163
|
+
const hasToken = Boolean(process.env.CRUO_TOKEN?.trim()) || argv2.includes("--token") || storedKey !== null;
|
|
48164
|
+
if (!hasToken) {
|
|
48165
|
+
const stored = Object.keys(config3.agents);
|
|
48166
|
+
console.error(
|
|
48167
|
+
`
|
|
48168
|
+
Nothing stored for \`${name}\`, so there is no token to run it with.
|
|
48169
|
+
|
|
48170
|
+
` + (stored.length > 0 ? `Stored: ${stored.join(", ")}
|
|
48171
|
+
Either \`cruo start ${stored[0]}\`, or add this one:
|
|
48172
|
+
` : `Nothing is stored at all. Add one:
|
|
48173
|
+
`) + ` cruo login <token>
|
|
48174
|
+
`
|
|
48175
|
+
);
|
|
48176
|
+
process.exit(2);
|
|
48177
|
+
}
|
|
47976
48178
|
await mkdir4(logDir(), { recursive: true });
|
|
47977
48179
|
const logPath = join4(logDir(), `${name}.log`);
|
|
47978
48180
|
const handle = await open(logPath, "a");
|
|
47979
|
-
const
|
|
48181
|
+
const rest = argv2.slice(positional ? 2 : 1).filter((a) => a !== "--all");
|
|
48182
|
+
const chosen = storedKey ?? positional ?? asName;
|
|
48183
|
+
const withoutAs = rest.filter((a, i, all) => a !== "--as" && all[i - 1] !== "--as");
|
|
48184
|
+
const forwarded = chosen ? ["--as", chosen, ...withoutAs] : withoutAs;
|
|
47980
48185
|
const child = spawn2(process.execPath, [process.argv[1], ...forwarded], {
|
|
47981
48186
|
detached: true,
|
|
47982
48187
|
stdio: ["ignore", handle.fd, handle.fd],
|
|
@@ -48120,6 +48325,20 @@ Usage: cruo login <token> [--as <name>]
|
|
|
48120
48325
|
console.log(USAGE);
|
|
48121
48326
|
return;
|
|
48122
48327
|
}
|
|
48328
|
+
if (!isKnownCommandWord(first)) {
|
|
48329
|
+
const near = nearestCommands(first);
|
|
48330
|
+
console.error(
|
|
48331
|
+
`
|
|
48332
|
+
\`${first}\` is not a cruo command.
|
|
48333
|
+
|
|
48334
|
+
` + (near.length > 0 ? `Did you mean: ${near.map((k) => `cruo ${k}`).join(" ")}
|
|
48335
|
+
|
|
48336
|
+
` : "") + `To run the agent, give no command: cruo [options]
|
|
48337
|
+
Everything it takes: cruo --help
|
|
48338
|
+
`
|
|
48339
|
+
);
|
|
48340
|
+
process.exit(2);
|
|
48341
|
+
}
|
|
48123
48342
|
if (first === "start") return startDetached(argv2, flagValue("--as"));
|
|
48124
48343
|
const flagIndex = argv2.indexOf("--token");
|
|
48125
48344
|
const fromFlag = flagIndex >= 0 ? argv2[flagIndex + 1] : void 0;
|
package/package.json
CHANGED