zelari-code 2.3.0 → 2.5.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/cli/budget/historySummary.js +40 -2
- package/dist/cli/budget/historySummary.js.map +1 -1
- package/dist/cli/budget/modelContextBuilder.js +126 -0
- package/dist/cli/budget/modelContextBuilder.js.map +1 -0
- package/dist/cli/budget/persistCompact.js +67 -0
- package/dist/cli/budget/persistCompact.js.map +1 -0
- package/dist/cli/budget/tokenBudget.js +47 -13
- package/dist/cli/budget/tokenBudget.js.map +1 -1
- package/dist/cli/compaction.js +5 -0
- package/dist/cli/compaction.js.map +1 -1
- package/dist/cli/gauntlet/blind.js +38 -0
- package/dist/cli/gauntlet/blind.js.map +1 -0
- package/dist/cli/gauntlet/complete.js +90 -0
- package/dist/cli/gauntlet/complete.js.map +1 -0
- package/dist/cli/gauntlet/decompose.js +163 -0
- package/dist/cli/gauntlet/decompose.js.map +1 -0
- package/dist/cli/gauntlet/events.js +30 -0
- package/dist/cli/gauntlet/events.js.map +1 -0
- package/dist/cli/gauntlet/loop.js +142 -0
- package/dist/cli/gauntlet/loop.js.map +1 -0
- package/dist/cli/gauntlet/policy.js +61 -0
- package/dist/cli/gauntlet/policy.js.map +1 -0
- package/dist/cli/gauntlet/prompts.js +70 -0
- package/dist/cli/gauntlet/prompts.js.map +1 -0
- package/dist/cli/gauntlet/run.js +213 -0
- package/dist/cli/gauntlet/run.js.map +1 -0
- package/dist/cli/gauntlet/schedule.js +34 -0
- package/dist/cli/gauntlet/schedule.js.map +1 -0
- package/dist/cli/gauntlet/verdict.js +58 -0
- package/dist/cli/gauntlet/verdict.js.map +1 -0
- package/dist/cli/headless.js +11 -0
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/headlessSpine.js +3 -2
- package/dist/cli/headlessSpine.js.map +1 -1
- package/dist/cli/hooks/historyCompaction.js +56 -8
- package/dist/cli/hooks/historyCompaction.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +52 -68
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/main.bundled.js +2654 -908
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/metrics.js +16 -0
- package/dist/cli/metrics.js.map +1 -1
- package/dist/cli/runHeadless.js +109 -10
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/sessionSpine.js +65 -7
- package/dist/cli/sessionSpine.js.map +1 -1
- package/dist/cli/toolRegistry.js +13 -6
- package/dist/cli/toolRegistry.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -595,8 +595,8 @@ async function runGrokOAuthFlow(options = {}) {
|
|
|
595
595
|
);
|
|
596
596
|
} catch {
|
|
597
597
|
}
|
|
598
|
-
const
|
|
599
|
-
const effectiveTimeout = Math.min(
|
|
598
|
+
const timeoutMs2 = options.timeoutMs ?? DEFAULT_OAUTH_TIMEOUT_MS;
|
|
599
|
+
const effectiveTimeout = Math.min(timeoutMs2, deviceAuth.expiresIn * 1e3);
|
|
600
600
|
return pollForDeviceToken({
|
|
601
601
|
clientId: clientId2,
|
|
602
602
|
deviceCode: deviceAuth.deviceCode,
|
|
@@ -739,7 +739,7 @@ function generateOAuthState() {
|
|
|
739
739
|
}
|
|
740
740
|
async function waitForLoopbackCallback(options) {
|
|
741
741
|
const host = options.host ?? "127.0.0.1";
|
|
742
|
-
const
|
|
742
|
+
const timeoutMs2 = options.timeoutMs ?? 3e5;
|
|
743
743
|
const expectedPath = options.path.startsWith("/") ? options.path : `/${options.path}`;
|
|
744
744
|
return new Promise((resolve3, reject) => {
|
|
745
745
|
let settled = false;
|
|
@@ -759,12 +759,12 @@ async function waitForLoopbackCallback(options) {
|
|
|
759
759
|
const ok = Boolean(result.code) && !result.error;
|
|
760
760
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
761
761
|
res.end(oauthResultHtml(ok, result.errorDescription ?? result.error));
|
|
762
|
-
|
|
762
|
+
finish2(result);
|
|
763
763
|
});
|
|
764
764
|
const timer = setTimeout(() => {
|
|
765
|
-
|
|
766
|
-
},
|
|
767
|
-
const
|
|
765
|
+
finish2(void 0, new Error(`Timed out waiting for OAuth callback on http://${host}:${options.port}`));
|
|
766
|
+
}, timeoutMs2);
|
|
767
|
+
const finish2 = (value, err) => {
|
|
768
768
|
if (settled) return;
|
|
769
769
|
settled = true;
|
|
770
770
|
clearTimeout(timer);
|
|
@@ -773,7 +773,7 @@ async function waitForLoopbackCallback(options) {
|
|
|
773
773
|
else resolve3(value ?? {});
|
|
774
774
|
});
|
|
775
775
|
};
|
|
776
|
-
server.on("error", (err) =>
|
|
776
|
+
server.on("error", (err) => finish2(void 0, err));
|
|
777
777
|
server.listen(options.port, host);
|
|
778
778
|
});
|
|
779
779
|
}
|
|
@@ -971,8 +971,8 @@ async function pollChatgptDeviceAuth(options) {
|
|
|
971
971
|
const clientId2 = options.clientId || process.env.CHATGPT_OAUTH_CLIENT_ID || DEFAULT_CHATGPT_CLIENT_ID;
|
|
972
972
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
973
973
|
const sleep = options.sleepImpl ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
974
|
-
const
|
|
975
|
-
const deadline = Date.now() +
|
|
974
|
+
const timeoutMs2 = options.timeoutMs ?? 3e5;
|
|
975
|
+
const deadline = Date.now() + timeoutMs2;
|
|
976
976
|
let interval = options.interval ?? 5;
|
|
977
977
|
let authorizationCode;
|
|
978
978
|
let codeVerifier;
|
|
@@ -19419,9 +19419,9 @@ function assertHttpUrl(raw) {
|
|
|
19419
19419
|
}
|
|
19420
19420
|
return url2;
|
|
19421
19421
|
}
|
|
19422
|
-
async function fetchWithTimeout(url2, init, outerSignal,
|
|
19422
|
+
async function fetchWithTimeout(url2, init, outerSignal, timeoutMs2) {
|
|
19423
19423
|
const ctrl = new AbortController();
|
|
19424
|
-
const timer = setTimeout(() => ctrl.abort(new Error(`timeout after ${
|
|
19424
|
+
const timer = setTimeout(() => ctrl.abort(new Error(`timeout after ${timeoutMs2}ms`)), timeoutMs2);
|
|
19425
19425
|
const onOuterAbort = () => ctrl.abort(outerSignal?.reason);
|
|
19426
19426
|
outerSignal?.addEventListener("abort", onOuterAbort, { once: true });
|
|
19427
19427
|
try {
|
|
@@ -23327,8 +23327,8 @@ var init_lifecycleHookRunner = __esm({
|
|
|
23327
23327
|
/** Execute a single hook, swallowing every failure into an allow. */
|
|
23328
23328
|
async runHookSafely(hook, payload) {
|
|
23329
23329
|
try {
|
|
23330
|
-
const
|
|
23331
|
-
const raw = hook.url ? await this.postHttp(hook.url, payload,
|
|
23330
|
+
const timeoutMs2 = hook.timeoutMs ?? this.defaultTimeoutMs;
|
|
23331
|
+
const raw = hook.url ? await this.postHttp(hook.url, payload, timeoutMs2) : await this.execCommand(hook.command ?? "", payload, timeoutMs2, hook.cwd);
|
|
23332
23332
|
const decision = parseJson(raw);
|
|
23333
23333
|
if (!decision) {
|
|
23334
23334
|
this.logger(`hook "${hook.name}" returned invalid JSON (fail-open): ${raw.slice(0, 200)}`);
|
|
@@ -23345,7 +23345,7 @@ var init_lifecycleHookRunner = __esm({
|
|
|
23345
23345
|
}
|
|
23346
23346
|
}
|
|
23347
23347
|
/** Spawn `command`, write JSON payload to stdin, read stdout until close. */
|
|
23348
|
-
execCommand(command, payload,
|
|
23348
|
+
execCommand(command, payload, timeoutMs2, cwd) {
|
|
23349
23349
|
return new Promise((resolve3, reject) => {
|
|
23350
23350
|
const child = spawn2(command, {
|
|
23351
23351
|
shell: true,
|
|
@@ -23357,8 +23357,8 @@ var init_lifecycleHookRunner = __esm({
|
|
|
23357
23357
|
let stderr = "";
|
|
23358
23358
|
const timer = setTimeout(() => {
|
|
23359
23359
|
child.kill("SIGKILL");
|
|
23360
|
-
reject(new Error(`timed out after ${
|
|
23361
|
-
},
|
|
23360
|
+
reject(new Error(`timed out after ${timeoutMs2}ms`));
|
|
23361
|
+
}, timeoutMs2);
|
|
23362
23362
|
child.stdout?.on("data", (d) => {
|
|
23363
23363
|
stdout += d.toString();
|
|
23364
23364
|
});
|
|
@@ -23384,9 +23384,9 @@ var init_lifecycleHookRunner = __esm({
|
|
|
23384
23384
|
});
|
|
23385
23385
|
}
|
|
23386
23386
|
/** POST JSON payload; resolve with the response body text. */
|
|
23387
|
-
async postHttp(url2, payload,
|
|
23387
|
+
async postHttp(url2, payload, timeoutMs2) {
|
|
23388
23388
|
const ctrl = new AbortController();
|
|
23389
|
-
const timer = setTimeout(() => ctrl.abort(),
|
|
23389
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs2);
|
|
23390
23390
|
try {
|
|
23391
23391
|
const res = await fetch(url2, {
|
|
23392
23392
|
method: "POST",
|
|
@@ -27962,7 +27962,7 @@ function deepFreeze(value) {
|
|
|
27962
27962
|
return Object.freeze(value);
|
|
27963
27963
|
}
|
|
27964
27964
|
async function runInSandbox(opts) {
|
|
27965
|
-
const { bundleCode, sdk, timeoutMs } = opts;
|
|
27965
|
+
const { bundleCode, sdk, timeoutMs: timeoutMs2 } = opts;
|
|
27966
27966
|
if (!opts.skipFootgunScan) {
|
|
27967
27967
|
const footguns = scanForFootguns(bundleCode);
|
|
27968
27968
|
if (footguns.length > 0) {
|
|
@@ -27982,7 +27982,7 @@ async function runInSandbox(opts) {
|
|
|
27982
27982
|
});
|
|
27983
27983
|
const start = Date.now();
|
|
27984
27984
|
const vmOpts = {
|
|
27985
|
-
timeout: Math.max(1,
|
|
27985
|
+
timeout: Math.max(1, timeoutMs2),
|
|
27986
27986
|
displayErrors: true,
|
|
27987
27987
|
breakOnSigint: true
|
|
27988
27988
|
};
|
|
@@ -27992,7 +27992,7 @@ async function runInSandbox(opts) {
|
|
|
27992
27992
|
} catch (err) {
|
|
27993
27993
|
const msg = err && typeof err === "object" && "message" in err ? String(err.message ?? "") : String(err);
|
|
27994
27994
|
if (/timed out/i.test(msg)) {
|
|
27995
|
-
throw new PlanError("budget_exceeded", `script exceeded ${
|
|
27995
|
+
throw new PlanError("budget_exceeded", `script exceeded ${timeoutMs2}ms budget`);
|
|
27996
27996
|
}
|
|
27997
27997
|
if (opts.signal?.aborted) {
|
|
27998
27998
|
throw new PlanError("cancelled", "script aborted by host");
|
|
@@ -28340,6 +28340,292 @@ var init_types8 = __esm({
|
|
|
28340
28340
|
}
|
|
28341
28341
|
});
|
|
28342
28342
|
|
|
28343
|
+
// packages/core/dist/session/compactionState.js
|
|
28344
|
+
function asPositiveInt(value) {
|
|
28345
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
|
|
28346
|
+
}
|
|
28347
|
+
function recordOf(value) {
|
|
28348
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
28349
|
+
}
|
|
28350
|
+
function recordsOf(value) {
|
|
28351
|
+
return Array.isArray(value) ? value.map(recordOf).filter((v) => v !== void 0) : [];
|
|
28352
|
+
}
|
|
28353
|
+
function stringsOf(value) {
|
|
28354
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
28355
|
+
}
|
|
28356
|
+
function addBounded(target, value, maxLength = 260) {
|
|
28357
|
+
const normalized = value.trim().replace(/\\/g, "/");
|
|
28358
|
+
if (normalized && normalized.length <= maxLength)
|
|
28359
|
+
target.add(normalized);
|
|
28360
|
+
}
|
|
28361
|
+
function collectPaths(value, target, depth = 0) {
|
|
28362
|
+
if (depth > 4 || value === null || value === void 0)
|
|
28363
|
+
return;
|
|
28364
|
+
if (Array.isArray(value)) {
|
|
28365
|
+
for (const item of value)
|
|
28366
|
+
collectPaths(item, target, depth + 1);
|
|
28367
|
+
return;
|
|
28368
|
+
}
|
|
28369
|
+
const record2 = recordOf(value);
|
|
28370
|
+
if (record2) {
|
|
28371
|
+
for (const [key, item] of Object.entries(record2)) {
|
|
28372
|
+
if (typeof item === "string" && ["path", "file", "filepath", "filePath", "file_path", "target", "cwd"].includes(key)) {
|
|
28373
|
+
addBounded(target, item);
|
|
28374
|
+
} else {
|
|
28375
|
+
collectPaths(item, target, depth + 1);
|
|
28376
|
+
}
|
|
28377
|
+
}
|
|
28378
|
+
return;
|
|
28379
|
+
}
|
|
28380
|
+
if (typeof value !== "string")
|
|
28381
|
+
return;
|
|
28382
|
+
const pathLike = /(?:^|[\s"'])((?:[\w.@-]+[\\/])+[\w.@-]+\.[A-Za-z0-9]{1,10})/g;
|
|
28383
|
+
let match;
|
|
28384
|
+
while ((match = pathLike.exec(value)) !== null && target.size < 64) {
|
|
28385
|
+
addBounded(target, match[1]);
|
|
28386
|
+
}
|
|
28387
|
+
}
|
|
28388
|
+
function evidenceFromResults(results) {
|
|
28389
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28390
|
+
const out = [];
|
|
28391
|
+
for (const result of results) {
|
|
28392
|
+
for (const raw of recordsOf(result.evidence)) {
|
|
28393
|
+
const seq = asPositiveInt(raw.seq);
|
|
28394
|
+
const tier = typeof raw.tier === "string" ? raw.tier : void 0;
|
|
28395
|
+
const ref = typeof raw.ref === "string" ? raw.ref : void 0;
|
|
28396
|
+
const digest = typeof raw.digest === "string" ? raw.digest : void 0;
|
|
28397
|
+
const capturedAt = typeof raw.capturedAt === "number" && Number.isInteger(raw.capturedAt) ? raw.capturedAt : void 0;
|
|
28398
|
+
if (seq === void 0 && tier === void 0 && ref === void 0 && digest === void 0)
|
|
28399
|
+
continue;
|
|
28400
|
+
const key = [seq ?? "", tier ?? "", ref ?? "", digest ?? ""].join("|");
|
|
28401
|
+
if (seen.has(key))
|
|
28402
|
+
continue;
|
|
28403
|
+
seen.add(key);
|
|
28404
|
+
out.push({
|
|
28405
|
+
...seq !== void 0 ? { seq } : {},
|
|
28406
|
+
...tier !== void 0 ? { tier } : {},
|
|
28407
|
+
...ref !== void 0 ? { ref } : {},
|
|
28408
|
+
...digest !== void 0 ? { digest } : {},
|
|
28409
|
+
...capturedAt !== void 0 ? { capturedAt } : {}
|
|
28410
|
+
});
|
|
28411
|
+
}
|
|
28412
|
+
}
|
|
28413
|
+
return out;
|
|
28414
|
+
}
|
|
28415
|
+
function buildCompactionStateSnapshot(events, toSeq) {
|
|
28416
|
+
const scoped = events.filter((event) => event.seq <= toSeq);
|
|
28417
|
+
const latestVerification = [...scoped].reverse().find((event) => event.kind === "verification.run");
|
|
28418
|
+
const verificationData = latestVerification?.data ?? {};
|
|
28419
|
+
const native = recordOf(verificationData.native);
|
|
28420
|
+
const results = recordsOf(native?.results ?? verificationData.results);
|
|
28421
|
+
const criteriaRaw = recordsOf(native?.criteria ?? verificationData.criteria);
|
|
28422
|
+
const statusById = new Map(results.filter((result) => typeof result.criterionId === "string").map((result) => [String(result.criterionId), String(result.status ?? "unknown")]));
|
|
28423
|
+
const evidenceState = recordOf(verificationData.evidence);
|
|
28424
|
+
const satisfied = stringsOf(evidenceState?.satisfied);
|
|
28425
|
+
const unsatisfiedRaw = recordsOf(evidenceState?.unsatisfied);
|
|
28426
|
+
const activeCriteria = criteriaRaw.filter((criterion) => typeof criterion.id === "string").map((criterion) => ({
|
|
28427
|
+
id: String(criterion.id),
|
|
28428
|
+
required: criterion.required !== false,
|
|
28429
|
+
...statusById.has(String(criterion.id)) ? { status: statusById.get(String(criterion.id)) } : {}
|
|
28430
|
+
}));
|
|
28431
|
+
if (activeCriteria.length === 0) {
|
|
28432
|
+
const ids = /* @__PURE__ */ new Set([
|
|
28433
|
+
...results.map((result) => String(result.criterionId ?? "")).filter(Boolean),
|
|
28434
|
+
...satisfied,
|
|
28435
|
+
...unsatisfiedRaw.map((issue2) => String(issue2.id ?? "")).filter(Boolean)
|
|
28436
|
+
]);
|
|
28437
|
+
for (const id of ids) {
|
|
28438
|
+
activeCriteria.push({
|
|
28439
|
+
id,
|
|
28440
|
+
required: true,
|
|
28441
|
+
status: statusById.get(id) ?? (satisfied.includes(id) ? "pass" : "unknown")
|
|
28442
|
+
});
|
|
28443
|
+
}
|
|
28444
|
+
}
|
|
28445
|
+
const unresolvedIssues = unsatisfiedRaw.length > 0 ? unsatisfiedRaw.filter((issue2) => typeof issue2.id === "string").map((issue2) => ({
|
|
28446
|
+
id: String(issue2.id),
|
|
28447
|
+
status: String(issue2.status ?? "unknown"),
|
|
28448
|
+
...typeof issue2.reason === "string" ? { reason: issue2.reason } : {}
|
|
28449
|
+
})) : results.filter((result) => String(result.status ?? "unknown") !== "pass").map((result) => ({
|
|
28450
|
+
id: String(result.criterionId ?? "unknown"),
|
|
28451
|
+
status: String(result.status ?? "unknown"),
|
|
28452
|
+
...typeof result.detail === "string" ? { reason: result.detail } : {}
|
|
28453
|
+
}));
|
|
28454
|
+
const affectedFiles = /* @__PURE__ */ new Set();
|
|
28455
|
+
for (const event of scoped.slice(-500)) {
|
|
28456
|
+
if (event.kind === "tool.call" || event.kind === "tool.result" || event.kind === "verification.evidence") {
|
|
28457
|
+
collectPaths(event.data, affectedFiles);
|
|
28458
|
+
}
|
|
28459
|
+
}
|
|
28460
|
+
const userConstraints = /* @__PURE__ */ new Set();
|
|
28461
|
+
for (const event of scoped) {
|
|
28462
|
+
if (event.kind !== "user.message")
|
|
28463
|
+
continue;
|
|
28464
|
+
for (const constraint of stringsOf(event.data.constraints ?? event.data.userConstraints)) {
|
|
28465
|
+
addBounded(userConstraints, constraint, 320);
|
|
28466
|
+
}
|
|
28467
|
+
const messageText = typeof event.data.text === "string" ? event.data.text : "";
|
|
28468
|
+
for (const line of messageText.split(/\r?\n/)) {
|
|
28469
|
+
if (CONSTRAINT_RE.test(line))
|
|
28470
|
+
addBounded(userConstraints, line, 320);
|
|
28471
|
+
if (userConstraints.size >= 12)
|
|
28472
|
+
break;
|
|
28473
|
+
}
|
|
28474
|
+
}
|
|
28475
|
+
const lastMissionPhase = [...scoped].reverse().find((event) => event.kind === "mission.phase");
|
|
28476
|
+
const lastMissionAdvice = [...scoped].reverse().find((event) => event.kind === "mission.progress");
|
|
28477
|
+
const missionState = lastMissionPhase || lastMissionAdvice ? {
|
|
28478
|
+
...typeof lastMissionPhase?.data.phase === "string" ? { phase: lastMissionPhase.data.phase } : {},
|
|
28479
|
+
...typeof lastMissionAdvice?.data.recommendation === "string" ? { recommendation: lastMissionAdvice.data.recommendation } : {},
|
|
28480
|
+
...stringsOf(lastMissionAdvice?.data.blockers).length > 0 ? { blockers: stringsOf(lastMissionAdvice?.data.blockers) } : {}
|
|
28481
|
+
} : void 0;
|
|
28482
|
+
return {
|
|
28483
|
+
version: 1,
|
|
28484
|
+
activeCriteria,
|
|
28485
|
+
unresolvedIssues,
|
|
28486
|
+
...latestVerification ? {
|
|
28487
|
+
latestVerification: {
|
|
28488
|
+
seq: latestVerification.seq,
|
|
28489
|
+
...typeof verificationData.verdict === "string" ? { verdict: verificationData.verdict } : {},
|
|
28490
|
+
...typeof verificationData.summary === "string" ? { summary: verificationData.summary } : {}
|
|
28491
|
+
}
|
|
28492
|
+
} : {},
|
|
28493
|
+
retainedEvidenceRefs: evidenceFromResults(results),
|
|
28494
|
+
affectedFiles: [...affectedFiles].slice(0, 64),
|
|
28495
|
+
userConstraints: [...userConstraints].slice(-12),
|
|
28496
|
+
...missionState ? { missionState } : {}
|
|
28497
|
+
};
|
|
28498
|
+
}
|
|
28499
|
+
function formatCompactionStateSnapshot(snapshot) {
|
|
28500
|
+
const lines = ['<compaction-state version="1">'];
|
|
28501
|
+
if (snapshot.activeCriteria.length > 0) {
|
|
28502
|
+
lines.push("activeCriteria: " + JSON.stringify(snapshot.activeCriteria));
|
|
28503
|
+
}
|
|
28504
|
+
if (snapshot.unresolvedIssues.length > 0) {
|
|
28505
|
+
lines.push("unresolvedIssues: " + JSON.stringify(snapshot.unresolvedIssues));
|
|
28506
|
+
}
|
|
28507
|
+
if (snapshot.latestVerification) {
|
|
28508
|
+
lines.push("latestVerification: " + JSON.stringify(snapshot.latestVerification));
|
|
28509
|
+
}
|
|
28510
|
+
if (snapshot.affectedFiles.length > 0) {
|
|
28511
|
+
lines.push("affectedFiles: " + JSON.stringify(snapshot.affectedFiles));
|
|
28512
|
+
}
|
|
28513
|
+
if (snapshot.userConstraints.length > 0) {
|
|
28514
|
+
lines.push("userConstraints: " + JSON.stringify(snapshot.userConstraints));
|
|
28515
|
+
}
|
|
28516
|
+
if (snapshot.missionState) {
|
|
28517
|
+
lines.push("missionState: " + JSON.stringify(snapshot.missionState));
|
|
28518
|
+
}
|
|
28519
|
+
lines.push("</compaction-state>");
|
|
28520
|
+
return lines.join("\n");
|
|
28521
|
+
}
|
|
28522
|
+
var CONSTRAINT_RE;
|
|
28523
|
+
var init_compactionState = __esm({
|
|
28524
|
+
"packages/core/dist/session/compactionState.js"() {
|
|
28525
|
+
"use strict";
|
|
28526
|
+
CONSTRAINT_RE = /\b(must|never|required|only|do not|don't|constraint|vincolo|deve|devono|non\s+deve|senza)\b/i;
|
|
28527
|
+
}
|
|
28528
|
+
});
|
|
28529
|
+
|
|
28530
|
+
// packages/core/dist/session/compaction.js
|
|
28531
|
+
function asPositiveInt2(value) {
|
|
28532
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
|
|
28533
|
+
}
|
|
28534
|
+
function checkpointContent(data) {
|
|
28535
|
+
const cp = data.checkpoint;
|
|
28536
|
+
if (cp && typeof cp === "object") {
|
|
28537
|
+
const content = cp.content;
|
|
28538
|
+
if (typeof content === "string")
|
|
28539
|
+
return content;
|
|
28540
|
+
}
|
|
28541
|
+
if (typeof data.summary === "string")
|
|
28542
|
+
return data.summary;
|
|
28543
|
+
return "[session compacted]";
|
|
28544
|
+
}
|
|
28545
|
+
function checkpointRole(data) {
|
|
28546
|
+
const cp = data.checkpoint;
|
|
28547
|
+
if (cp && typeof cp === "object") {
|
|
28548
|
+
const role = cp.role;
|
|
28549
|
+
if (role === "user" || role === "system")
|
|
28550
|
+
return role;
|
|
28551
|
+
}
|
|
28552
|
+
return "system";
|
|
28553
|
+
}
|
|
28554
|
+
function strategyOf(data) {
|
|
28555
|
+
return data.strategy === "extractive" || data.strategy === "llm" ? data.strategy : void 0;
|
|
28556
|
+
}
|
|
28557
|
+
function parseCompactedEvent(event) {
|
|
28558
|
+
if (event.kind !== "session.compacted")
|
|
28559
|
+
return null;
|
|
28560
|
+
const fromSeq = asPositiveInt2(event.data.fromSeq);
|
|
28561
|
+
const toSeq = asPositiveInt2(event.data.toSeq);
|
|
28562
|
+
if (fromSeq === void 0 || toSeq === void 0 || fromSeq > toSeq)
|
|
28563
|
+
return null;
|
|
28564
|
+
if (event.seq <= toSeq)
|
|
28565
|
+
return null;
|
|
28566
|
+
const sourceRaw = event.data.sourceEventSeqs;
|
|
28567
|
+
const sourceEventSeqs = Array.isArray(sourceRaw) ? sourceRaw.filter((n) => typeof n === "number" && Number.isInteger(n) && n > 0) : void 0;
|
|
28568
|
+
return {
|
|
28569
|
+
seq: event.seq,
|
|
28570
|
+
fromSeq,
|
|
28571
|
+
toSeq,
|
|
28572
|
+
role: checkpointRole(event.data),
|
|
28573
|
+
content: checkpointContent(event.data),
|
|
28574
|
+
...strategyOf(event.data) ? { strategy: strategyOf(event.data) } : {},
|
|
28575
|
+
...sourceEventSeqs && sourceEventSeqs.length > 0 ? { sourceEventSeqs } : {}
|
|
28576
|
+
};
|
|
28577
|
+
}
|
|
28578
|
+
function coveringCompactions(events) {
|
|
28579
|
+
const effective = events.map(parseCompactedEvent).filter((c) => c !== null).map((c) => ({
|
|
28580
|
+
...c,
|
|
28581
|
+
...c.sourceEventSeqs ? { sourceEventSeqs: [...c.sourceEventSeqs] } : {}
|
|
28582
|
+
})).sort((a, b) => a.seq - b.seq);
|
|
28583
|
+
let changed = true;
|
|
28584
|
+
while (changed) {
|
|
28585
|
+
changed = false;
|
|
28586
|
+
for (let i = 0; i < effective.length; i++) {
|
|
28587
|
+
const earlier = effective[i];
|
|
28588
|
+
let target;
|
|
28589
|
+
for (let j = i + 1; j < effective.length; j++) {
|
|
28590
|
+
const later = effective[j];
|
|
28591
|
+
if (earlier.seq >= later.fromSeq && earlier.seq <= later.toSeq) {
|
|
28592
|
+
target = later;
|
|
28593
|
+
}
|
|
28594
|
+
}
|
|
28595
|
+
if (!target)
|
|
28596
|
+
continue;
|
|
28597
|
+
target.fromSeq = Math.min(target.fromSeq, earlier.fromSeq);
|
|
28598
|
+
target.toSeq = Math.max(target.toSeq, earlier.toSeq);
|
|
28599
|
+
if (earlier.sourceEventSeqs?.length) {
|
|
28600
|
+
target.sourceEventSeqs = [
|
|
28601
|
+
.../* @__PURE__ */ new Set([...target.sourceEventSeqs ?? [], ...earlier.sourceEventSeqs])
|
|
28602
|
+
];
|
|
28603
|
+
}
|
|
28604
|
+
effective.splice(i, 1);
|
|
28605
|
+
changed = true;
|
|
28606
|
+
break;
|
|
28607
|
+
}
|
|
28608
|
+
}
|
|
28609
|
+
return effective;
|
|
28610
|
+
}
|
|
28611
|
+
function shadowedSeqSet(coverings) {
|
|
28612
|
+
const set2 = /* @__PURE__ */ new Set();
|
|
28613
|
+
for (const c of coverings) {
|
|
28614
|
+
for (let s = c.fromSeq; s <= c.toSeq; s++)
|
|
28615
|
+
set2.add(s);
|
|
28616
|
+
}
|
|
28617
|
+
return set2;
|
|
28618
|
+
}
|
|
28619
|
+
function isSeqShadowed(seq, coverings) {
|
|
28620
|
+
return coverings.some((c) => seq >= c.fromSeq && seq <= c.toSeq);
|
|
28621
|
+
}
|
|
28622
|
+
var init_compaction = __esm({
|
|
28623
|
+
"packages/core/dist/session/compaction.js"() {
|
|
28624
|
+
"use strict";
|
|
28625
|
+
init_compactionState();
|
|
28626
|
+
}
|
|
28627
|
+
});
|
|
28628
|
+
|
|
28343
28629
|
// packages/core/dist/session/modelSurface.js
|
|
28344
28630
|
function isModelSurfaceEvent(event) {
|
|
28345
28631
|
return MODEL_SURFACE_KINDS.has(event.kind);
|
|
@@ -28348,8 +28634,33 @@ function asString(value) {
|
|
|
28348
28634
|
return typeof value === "string" ? value : void 0;
|
|
28349
28635
|
}
|
|
28350
28636
|
function deriveMessages(events, options = {}) {
|
|
28637
|
+
const coverings = coveringCompactions(events);
|
|
28638
|
+
const orderedCoverings = [...coverings].sort((a, b) => a.fromSeq - b.fromSeq || a.seq - b.seq);
|
|
28639
|
+
const compactBySeq = new Map(coverings.map((c) => [c.seq, c]));
|
|
28351
28640
|
const messages = [];
|
|
28641
|
+
let nextCheckpoint = 0;
|
|
28642
|
+
const pushCheckpoint = (compact) => {
|
|
28643
|
+
messages.push({
|
|
28644
|
+
role: compact.role,
|
|
28645
|
+
content: compact.content,
|
|
28646
|
+
seq: compact.seq,
|
|
28647
|
+
compactedFromSeq: compact.fromSeq,
|
|
28648
|
+
compactedToSeq: compact.toSeq,
|
|
28649
|
+
...compact.sourceEventSeqs ? { sourceEventSeqs: compact.sourceEventSeqs } : {}
|
|
28650
|
+
});
|
|
28651
|
+
};
|
|
28652
|
+
const pushDueCheckpoints = (seq) => {
|
|
28653
|
+
while (nextCheckpoint < orderedCoverings.length && orderedCoverings[nextCheckpoint].fromSeq <= seq) {
|
|
28654
|
+
pushCheckpoint(orderedCoverings[nextCheckpoint]);
|
|
28655
|
+
nextCheckpoint += 1;
|
|
28656
|
+
}
|
|
28657
|
+
};
|
|
28352
28658
|
for (const e of events) {
|
|
28659
|
+
pushDueCheckpoints(e.seq);
|
|
28660
|
+
if (compactBySeq.has(e.seq))
|
|
28661
|
+
continue;
|
|
28662
|
+
if (isSeqShadowed(e.seq, coverings))
|
|
28663
|
+
continue;
|
|
28353
28664
|
if (!isModelSurfaceEvent(e))
|
|
28354
28665
|
continue;
|
|
28355
28666
|
const d = e.data;
|
|
@@ -28394,6 +28705,7 @@ function deriveMessages(events, options = {}) {
|
|
|
28394
28705
|
break;
|
|
28395
28706
|
}
|
|
28396
28707
|
}
|
|
28708
|
+
pushDueCheckpoints(Number.POSITIVE_INFINITY);
|
|
28397
28709
|
return messages;
|
|
28398
28710
|
}
|
|
28399
28711
|
function pairToolCalls(events) {
|
|
@@ -28421,6 +28733,7 @@ var MODEL_SURFACE_KINDS;
|
|
|
28421
28733
|
var init_modelSurface = __esm({
|
|
28422
28734
|
"packages/core/dist/session/modelSurface.js"() {
|
|
28423
28735
|
"use strict";
|
|
28736
|
+
init_compaction();
|
|
28424
28737
|
MODEL_SURFACE_KINDS = /* @__PURE__ */ new Set([
|
|
28425
28738
|
"user.message",
|
|
28426
28739
|
"assistant.message",
|
|
@@ -28438,6 +28751,14 @@ function derivedToAgentMessages(messages) {
|
|
|
28438
28751
|
const agent = { role: m.role, content: m.content };
|
|
28439
28752
|
if (m.toolCallId !== void 0)
|
|
28440
28753
|
agent.toolCallId = m.toolCallId;
|
|
28754
|
+
if (m.seq !== void 0)
|
|
28755
|
+
agent.seq = m.seq;
|
|
28756
|
+
if (m.compactedFromSeq !== void 0)
|
|
28757
|
+
agent.compactedFromSeq = m.compactedFromSeq;
|
|
28758
|
+
if (m.compactedToSeq !== void 0)
|
|
28759
|
+
agent.compactedToSeq = m.compactedToSeq;
|
|
28760
|
+
if (m.sourceEventSeqs !== void 0)
|
|
28761
|
+
agent.sourceEventSeqs = [...m.sourceEventSeqs];
|
|
28441
28762
|
out.push(agent);
|
|
28442
28763
|
}
|
|
28443
28764
|
return out;
|
|
@@ -29081,8 +29402,97 @@ function validateSessionTrace(events, mode = "minimal") {
|
|
|
29081
29402
|
message: `session.ended seq ${firstEnded.seq} precedes verification.run seq ${firstVerification.seq}`
|
|
29082
29403
|
});
|
|
29083
29404
|
}
|
|
29405
|
+
pushCompactionViolations(events, knownSeq, pairs, violations);
|
|
29084
29406
|
return violations;
|
|
29085
29407
|
}
|
|
29408
|
+
function pushCompactionViolations(events, knownSeq, pairs, violations) {
|
|
29409
|
+
for (const e of events) {
|
|
29410
|
+
if (e.kind !== "session.compacted")
|
|
29411
|
+
continue;
|
|
29412
|
+
const fromSeq = asSeq(e.data.fromSeq);
|
|
29413
|
+
const toSeq = asSeq(e.data.toSeq);
|
|
29414
|
+
if (fromSeq === void 0 && toSeq === void 0)
|
|
29415
|
+
continue;
|
|
29416
|
+
if (fromSeq === void 0 || toSeq === void 0 || fromSeq > toSeq) {
|
|
29417
|
+
violations.push({
|
|
29418
|
+
code: "COMPACTION_RANGE_INVALID",
|
|
29419
|
+
seq: e.seq,
|
|
29420
|
+
message: `session.compacted seq ${e.seq} has invalid fromSeq/toSeq`
|
|
29421
|
+
});
|
|
29422
|
+
continue;
|
|
29423
|
+
}
|
|
29424
|
+
if (e.seq <= toSeq) {
|
|
29425
|
+
violations.push({
|
|
29426
|
+
code: "COMPACTION_EVENT_INSIDE_RANGE",
|
|
29427
|
+
seq: e.seq,
|
|
29428
|
+
message: `session.compacted seq ${e.seq} must be > toSeq ${toSeq}`
|
|
29429
|
+
});
|
|
29430
|
+
}
|
|
29431
|
+
if (!knownSeq.has(fromSeq) || !knownSeq.has(toSeq)) {
|
|
29432
|
+
violations.push({
|
|
29433
|
+
code: "COMPACTION_BOUNDARY_SEQ_MISSING",
|
|
29434
|
+
seq: e.seq,
|
|
29435
|
+
message: `session.compacted seq ${e.seq} range endpoints must exist in the trace`
|
|
29436
|
+
});
|
|
29437
|
+
}
|
|
29438
|
+
const checkpoint = e.data.checkpoint;
|
|
29439
|
+
if (!checkpoint || typeof checkpoint !== "object" || !["user", "system"].includes(String(checkpoint.role ?? "")) || typeof checkpoint.content !== "string") {
|
|
29440
|
+
violations.push({
|
|
29441
|
+
code: "COMPACTION_CHECKPOINT_INVALID",
|
|
29442
|
+
seq: e.seq,
|
|
29443
|
+
message: `session.compacted seq ${e.seq} must carry a user/system checkpoint with string content`
|
|
29444
|
+
});
|
|
29445
|
+
}
|
|
29446
|
+
const sourceRaw = e.data.sourceEventSeqs;
|
|
29447
|
+
if (Array.isArray(sourceRaw)) {
|
|
29448
|
+
for (const raw of sourceRaw) {
|
|
29449
|
+
const s = asSeq(raw);
|
|
29450
|
+
if (s === void 0) {
|
|
29451
|
+
violations.push({
|
|
29452
|
+
code: "COMPACTION_SOURCE_SEQ_INVALID",
|
|
29453
|
+
seq: e.seq,
|
|
29454
|
+
message: "sourceEventSeqs entries must be positive integers"
|
|
29455
|
+
});
|
|
29456
|
+
} else if (!knownSeq.has(s)) {
|
|
29457
|
+
violations.push({
|
|
29458
|
+
code: "COMPACTION_SOURCE_SEQ_MISSING",
|
|
29459
|
+
seq: e.seq,
|
|
29460
|
+
message: `sourceEventSeqs ${s} is not an event in this trace`
|
|
29461
|
+
});
|
|
29462
|
+
} else if (s < fromSeq || s > toSeq) {
|
|
29463
|
+
violations.push({
|
|
29464
|
+
code: "COMPACTION_SOURCE_SEQ_OUTSIDE_RANGE",
|
|
29465
|
+
seq: e.seq,
|
|
29466
|
+
message: `sourceEventSeqs ${s} is outside ${fromSeq}..${toSeq}`
|
|
29467
|
+
});
|
|
29468
|
+
}
|
|
29469
|
+
}
|
|
29470
|
+
}
|
|
29471
|
+
for (const pair of pairs) {
|
|
29472
|
+
const callSeq = pair.call.seq;
|
|
29473
|
+
const callInside = callSeq >= fromSeq && callSeq <= toSeq;
|
|
29474
|
+
if (!pair.result) {
|
|
29475
|
+
if (callInside) {
|
|
29476
|
+
violations.push({
|
|
29477
|
+
code: "COMPACTION_ACTIVE_TOOL_CALL",
|
|
29478
|
+
seq: e.seq,
|
|
29479
|
+
message: `tool.call seq ${callSeq} is compacted before a result or interruption`
|
|
29480
|
+
});
|
|
29481
|
+
}
|
|
29482
|
+
continue;
|
|
29483
|
+
}
|
|
29484
|
+
const resultSeq = pair.result.seq;
|
|
29485
|
+
const resultInside = resultSeq >= fromSeq && resultSeq <= toSeq;
|
|
29486
|
+
if (callInside !== resultInside) {
|
|
29487
|
+
violations.push({
|
|
29488
|
+
code: "COMPACTION_TOOL_PAIR_SPLIT",
|
|
29489
|
+
seq: e.seq,
|
|
29490
|
+
message: `tool pair ${callSeq}/${resultSeq} is split by range ${fromSeq}..${toSeq}`
|
|
29491
|
+
});
|
|
29492
|
+
}
|
|
29493
|
+
}
|
|
29494
|
+
}
|
|
29495
|
+
}
|
|
29086
29496
|
var init_invariants = __esm({
|
|
29087
29497
|
"packages/core/dist/session/invariants.js"() {
|
|
29088
29498
|
"use strict";
|
|
@@ -29096,6 +29506,7 @@ var init_session = __esm({
|
|
|
29096
29506
|
"use strict";
|
|
29097
29507
|
init_types8();
|
|
29098
29508
|
init_modelSurface();
|
|
29509
|
+
init_compaction();
|
|
29099
29510
|
init_agentAdapter();
|
|
29100
29511
|
init_writer();
|
|
29101
29512
|
init_replay();
|
|
@@ -29237,7 +29648,7 @@ var init_nodeProviders = __esm({
|
|
|
29237
29648
|
async exec(command, options = {}) {
|
|
29238
29649
|
const started = Date.now();
|
|
29239
29650
|
const cwd = this.workspace.resolve(options.cwd ?? ".");
|
|
29240
|
-
const
|
|
29651
|
+
const timeoutMs2 = options.timeoutMs ?? this.defaults.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
29241
29652
|
const maxChars = options.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
29242
29653
|
const isWindows = process.platform === "win32";
|
|
29243
29654
|
const file2 = isWindows ? "cmd.exe" : "/bin/sh";
|
|
@@ -29260,7 +29671,7 @@ var init_nodeProviders = __esm({
|
|
|
29260
29671
|
const timer = setTimeout(() => {
|
|
29261
29672
|
timedOut = true;
|
|
29262
29673
|
killTree(child);
|
|
29263
|
-
},
|
|
29674
|
+
}, timeoutMs2);
|
|
29264
29675
|
child.stdout?.on("data", (d) => {
|
|
29265
29676
|
stdout = append(stdout, d.toString("utf-8"));
|
|
29266
29677
|
});
|
|
@@ -30198,9 +30609,9 @@ var init_sessionEvidence = __esm({
|
|
|
30198
30609
|
|
|
30199
30610
|
// packages/core/dist/verification/criteriaPack.v1.js
|
|
30200
30611
|
function codingCriteriaPack(options = {}) {
|
|
30201
|
-
const
|
|
30612
|
+
const timeoutMs2 = options.commandTimeoutMs ?? 6e5;
|
|
30202
30613
|
const withDefault = (o, d) => o === void 0 ? d : o;
|
|
30203
|
-
const command = (command2) => command2 ? { kind: "command", command: command2, timeoutMs } : void 0;
|
|
30614
|
+
const command = (command2) => command2 ? { kind: "command", command: command2, timeoutMs: timeoutMs2 } : void 0;
|
|
30204
30615
|
const criteria = [
|
|
30205
30616
|
{
|
|
30206
30617
|
id: "correctness.error-signals",
|
|
@@ -30764,6 +31175,7 @@ __export(dist_exports, {
|
|
|
30764
31175
|
applyRetryIfMissing: () => applyRetryIfMissing,
|
|
30765
31176
|
auditDegradedBanner: () => auditDegradedBanner,
|
|
30766
31177
|
auditSynthesisTiers: () => auditSynthesisTiers,
|
|
31178
|
+
buildCompactionStateSnapshot: () => buildCompactionStateSnapshot,
|
|
30767
31179
|
buildCouncilCompletion: () => buildCouncilCompletion,
|
|
30768
31180
|
buildCustomParameters: () => buildCustomParameters,
|
|
30769
31181
|
buildDeliveryFixPrompt: () => buildDeliveryFixPrompt,
|
|
@@ -30802,6 +31214,7 @@ __export(dist_exports, {
|
|
|
30802
31214
|
councilTierFromSize: () => councilTierFromSize,
|
|
30803
31215
|
countByStatus: () => countByStatus,
|
|
30804
31216
|
countEmittedWriteTools: () => countEmittedWriteTools,
|
|
31217
|
+
coveringCompactions: () => coveringCompactions,
|
|
30805
31218
|
createBrainEvent: () => createBrainEvent,
|
|
30806
31219
|
createDefaultSystemPromptConfig: () => createDefaultSystemPromptConfig,
|
|
30807
31220
|
createExecutionContext: () => createExecutionContext,
|
|
@@ -30834,6 +31247,7 @@ __export(dist_exports, {
|
|
|
30834
31247
|
findSkillsByIds: () => findSkillsByIds,
|
|
30835
31248
|
findSkillsByTag: () => findSkillsByTag,
|
|
30836
31249
|
forkSession: () => forkSession,
|
|
31250
|
+
formatCompactionStateSnapshot: () => formatCompactionStateSnapshot,
|
|
30837
31251
|
formatLessonsForContext: () => formatLessonsForContext,
|
|
30838
31252
|
getAgent: () => getAgent,
|
|
30839
31253
|
getAllTools: () => getAllTools,
|
|
@@ -30881,6 +31295,7 @@ __export(dist_exports, {
|
|
|
30881
31295
|
isGeneratedPath: () => isGeneratedPath,
|
|
30882
31296
|
isModelSurfaceEvent: () => isModelSurfaceEvent,
|
|
30883
31297
|
isReviewerKind: () => isReviewerKind,
|
|
31298
|
+
isSeqShadowed: () => isSeqShadowed,
|
|
30884
31299
|
isSettled: () => isSettled,
|
|
30885
31300
|
isStatusTheaterUnit: () => isStatusTheaterUnit,
|
|
30886
31301
|
isValidTool: () => isValidTool,
|
|
@@ -30903,6 +31318,7 @@ __export(dist_exports, {
|
|
|
30903
31318
|
normalizeToolName: () => normalizeToolName,
|
|
30904
31319
|
pairToolCalls: () => pairToolCalls,
|
|
30905
31320
|
parseClarificationRequest: () => parseClarificationRequest,
|
|
31321
|
+
parseCompactedEvent: () => parseCompactedEvent,
|
|
30906
31322
|
parseEvidenceTier: () => parseEvidenceTier,
|
|
30907
31323
|
parseMinimaxStyleToolCalls: () => parseMinimaxStyleToolCalls,
|
|
30908
31324
|
parseNameOnlyDiff: () => parseNameOnlyDiff,
|
|
@@ -30959,6 +31375,7 @@ __export(dist_exports, {
|
|
|
30959
31375
|
selectParallelWave: () => selectParallelWave,
|
|
30960
31376
|
setWorkspaceStubs: () => setWorkspaceStubs,
|
|
30961
31377
|
sha256Hex: () => sha256Hex,
|
|
31378
|
+
shadowedSeqSet: () => shadowedSeqSet,
|
|
30962
31379
|
shouldRetryMember: () => shouldRetryMember,
|
|
30963
31380
|
sideEffectForTool: () => sideEffectForTool,
|
|
30964
31381
|
slugify: () => slugify2,
|
|
@@ -31302,12 +31719,46 @@ function mapBrainEventToSpine(ev) {
|
|
|
31302
31719
|
durationMs: ev.durationMs
|
|
31303
31720
|
}
|
|
31304
31721
|
};
|
|
31305
|
-
case "session_compacted":
|
|
31306
|
-
|
|
31307
|
-
|
|
31308
|
-
|
|
31309
|
-
|
|
31310
|
-
|
|
31722
|
+
case "session_compacted": {
|
|
31723
|
+
const compact = ev;
|
|
31724
|
+
const data = { summary: compact.summary ?? "" };
|
|
31725
|
+
if (typeof compact.messagesRemoved === "number") data.messagesRemoved = compact.messagesRemoved;
|
|
31726
|
+
if (typeof compact.fromSeq === "number" && typeof compact.toSeq === "number") {
|
|
31727
|
+
data.fromSeq = compact.fromSeq;
|
|
31728
|
+
data.toSeq = compact.toSeq;
|
|
31729
|
+
}
|
|
31730
|
+
if (compact.checkpoint && typeof compact.checkpoint === "object") data.checkpoint = compact.checkpoint;
|
|
31731
|
+
if (compact.strategy === "extractive" || compact.strategy === "llm") data.strategy = compact.strategy;
|
|
31732
|
+
if (Array.isArray(compact.sourceEventSeqs)) data.sourceEventSeqs = compact.sourceEventSeqs;
|
|
31733
|
+
if (Array.isArray(compact.retainedCriterionIds)) {
|
|
31734
|
+
data.retainedCriterionIds = compact.retainedCriterionIds;
|
|
31735
|
+
}
|
|
31736
|
+
if (Array.isArray(compact.retainedEvidenceRefs)) {
|
|
31737
|
+
data.retainedEvidenceRefs = compact.retainedEvidenceRefs;
|
|
31738
|
+
}
|
|
31739
|
+
if (compact.retainedState && typeof compact.retainedState === "object") {
|
|
31740
|
+
data.retainedState = compact.retainedState;
|
|
31741
|
+
}
|
|
31742
|
+
if (compact.stateSnapshot && typeof compact.stateSnapshot === "object") data.stateSnapshot = compact.stateSnapshot;
|
|
31743
|
+
if (typeof compact.sourceRequestFingerprint === "string") {
|
|
31744
|
+
data.sourceRequestFingerprint = compact.sourceRequestFingerprint;
|
|
31745
|
+
}
|
|
31746
|
+
if (typeof compact.headerFingerprint === "string") data.headerFingerprint = compact.headerFingerprint;
|
|
31747
|
+
if (typeof compact.sourceEstimatedTokens === "number") {
|
|
31748
|
+
data.sourceEstimatedTokens = compact.sourceEstimatedTokens;
|
|
31749
|
+
}
|
|
31750
|
+
if (typeof compact.cacheReuseExpected === "boolean") data.cacheReuseExpected = compact.cacheReuseExpected;
|
|
31751
|
+
if (typeof compact.inputTokens === "number") data.inputTokens = compact.inputTokens;
|
|
31752
|
+
if (typeof compact.outputTokens === "number") data.outputTokens = compact.outputTokens;
|
|
31753
|
+
if (typeof compact.savedTokens === "number") data.savedTokens = compact.savedTokens;
|
|
31754
|
+
if (typeof compact.recompactionRate === "number") data.recompactionRate = compact.recompactionRate;
|
|
31755
|
+
if (compact.summaryStrategy === "extractive" || compact.summaryStrategy === "llm") {
|
|
31756
|
+
data.summaryStrategy = compact.summaryStrategy;
|
|
31757
|
+
}
|
|
31758
|
+
if (typeof compact.provider === "string") data.provider = compact.provider;
|
|
31759
|
+
if (typeof compact.model === "string") data.model = compact.model;
|
|
31760
|
+
return { kind: "session.compacted", actor: ACTOR_SYSTEM, data };
|
|
31761
|
+
}
|
|
31311
31762
|
case "agent_start":
|
|
31312
31763
|
return {
|
|
31313
31764
|
kind: "note",
|
|
@@ -31421,6 +31872,16 @@ var init_sessionSpine = __esm({
|
|
|
31421
31872
|
if (!report || report.events.length === 0) return null;
|
|
31422
31873
|
return deriveMessages(report.events);
|
|
31423
31874
|
}
|
|
31875
|
+
/** Deterministic operational state retained beside a compact checkpoint. */
|
|
31876
|
+
async compactionStateSnapshot(toSeq) {
|
|
31877
|
+
if (this.status !== "active" && this.status !== "closed") return null;
|
|
31878
|
+
await this.flush();
|
|
31879
|
+
const report = await readSessionLog(
|
|
31880
|
+
path21.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
31881
|
+
).catch(() => null);
|
|
31882
|
+
if (!report || report.events.length === 0) return null;
|
|
31883
|
+
return buildCompactionStateSnapshot(report.events, toSeq);
|
|
31884
|
+
}
|
|
31424
31885
|
/**
|
|
31425
31886
|
* E2.1 (ADR-0023 × ADR-0021): last recognizable strict verification record
|
|
31426
31887
|
* in this session's log — the completion verdict is reconstructible from
|
|
@@ -31567,6 +32028,7 @@ var init_sessionSpine = __esm({
|
|
|
31567
32028
|
}
|
|
31568
32029
|
async flush() {
|
|
31569
32030
|
await this.inner.flush?.();
|
|
32031
|
+
await this.spine?.flush();
|
|
31570
32032
|
}
|
|
31571
32033
|
async close() {
|
|
31572
32034
|
await this.inner.close();
|
|
@@ -31867,6 +32329,21 @@ async function readMetrics(file2) {
|
|
|
31867
32329
|
}
|
|
31868
32330
|
return out;
|
|
31869
32331
|
}
|
|
32332
|
+
function recordCompactionMetrics(sessionId2, provider, model, metrics) {
|
|
32333
|
+
getMetricsLogger().record({
|
|
32334
|
+
kind: "compaction",
|
|
32335
|
+
sessionId: sessionId2,
|
|
32336
|
+
provider,
|
|
32337
|
+
model,
|
|
32338
|
+
compactionCount: metrics.count,
|
|
32339
|
+
compactionInputTokens: metrics.inputTokens,
|
|
32340
|
+
compactionOutputTokens: metrics.outputTokens,
|
|
32341
|
+
compactionSavedTokens: metrics.savedTokens,
|
|
32342
|
+
compactionRecompactionRate: metrics.recompactionRate,
|
|
32343
|
+
compactionSummaryStrategy: metrics.summaryStrategy,
|
|
32344
|
+
compactionRestoreFailures: metrics.restoreFailures
|
|
32345
|
+
});
|
|
32346
|
+
}
|
|
31870
32347
|
function getMetricsLogger() {
|
|
31871
32348
|
if (!_singleton) {
|
|
31872
32349
|
_singleton = new MetricsLogger();
|
|
@@ -33281,7 +33758,7 @@ var init_registry2 = __esm({
|
|
|
33281
33758
|
if (!parsed.success) {
|
|
33282
33759
|
return typedErr(`Invalid input: ${parsed.error.message}`);
|
|
33283
33760
|
}
|
|
33284
|
-
const
|
|
33761
|
+
const timeoutMs2 = options.timeoutMs ?? tool.timeoutMs ?? 3e4;
|
|
33285
33762
|
const parentSignal = options.signal;
|
|
33286
33763
|
const controller = new AbortController();
|
|
33287
33764
|
let timer;
|
|
@@ -33331,8 +33808,8 @@ var init_registry2 = __esm({
|
|
|
33331
33808
|
timer = setTimeout(() => {
|
|
33332
33809
|
if (!controller.signal.aborted)
|
|
33333
33810
|
controller.abort();
|
|
33334
|
-
reject(new Error(`Tool "${name}" timed out after ${
|
|
33335
|
-
},
|
|
33811
|
+
reject(new Error(`Tool "${name}" timed out after ${timeoutMs2}ms`));
|
|
33812
|
+
}, timeoutMs2);
|
|
33336
33813
|
})
|
|
33337
33814
|
]);
|
|
33338
33815
|
if (result.ok) {
|
|
@@ -33678,11 +34155,11 @@ async function runDiagnosticsForFile(file2, options = {}) {
|
|
|
33678
34155
|
const provider = providerForFile(file2, options.providers);
|
|
33679
34156
|
if (!provider) return [];
|
|
33680
34157
|
const cwd = options.cwd ?? process.cwd();
|
|
33681
|
-
const
|
|
34158
|
+
const timeoutMs2 = options.timeoutMs ?? 5e3;
|
|
33682
34159
|
const runner = options.runner ?? defaultRunner;
|
|
33683
34160
|
try {
|
|
33684
34161
|
const bin = options.runner ? provider.bin : resolveBin(provider.bin, cwd);
|
|
33685
|
-
const result = await runner(bin, provider.args(file2), { cwd, timeoutMs });
|
|
34162
|
+
const result = await runner(bin, provider.args(file2), { cwd, timeoutMs: timeoutMs2 });
|
|
33686
34163
|
return provider.parse(result.stdout, file2);
|
|
33687
34164
|
} catch {
|
|
33688
34165
|
return [];
|
|
@@ -35184,7 +35661,7 @@ function renderVerdict(verdict, candidateCount) {
|
|
|
35184
35661
|
return lines.join("\n");
|
|
35185
35662
|
}
|
|
35186
35663
|
function createKrakenSelectTool(deps) {
|
|
35187
|
-
const
|
|
35664
|
+
const timeoutMs2 = deps.timeoutMs ?? 12e4;
|
|
35188
35665
|
return {
|
|
35189
35666
|
name: "kraken_select",
|
|
35190
35667
|
description: "Compare the candidate research reports spawned this turn (task purpose=candidate) and select the hypothesis best supported by OBSERVED EVIDENCE. A dedicated verifier call (default: the current model) judges grounded vs unsupported claims; degraded observations are never treated as proof of absence. Returns the selected candidate, a rationale, and requiredChecks the implementation must pass. Call it ONCE per turn, after candidate tentacles finished and BEFORE implementing. If it reports needs_more_evidence, either spawn ONE more differentiated candidate or proceed with your own judgment.",
|
|
@@ -35241,7 +35718,7 @@ function createKrakenSelectTool(deps) {
|
|
|
35241
35718
|
model: id.model,
|
|
35242
35719
|
provider: id.provider,
|
|
35243
35720
|
tools: [],
|
|
35244
|
-
signal: AbortSignal.timeout(
|
|
35721
|
+
signal: AbortSignal.timeout(timeoutMs2)
|
|
35245
35722
|
});
|
|
35246
35723
|
judgingUsage = usage;
|
|
35247
35724
|
if (raw.trim().length === 0) throw new Error("empty verifier response");
|
|
@@ -38792,7 +39269,7 @@ exec node "$(dirname "$0")/askpass.cjs"
|
|
|
38792
39269
|
}
|
|
38793
39270
|
return sh;
|
|
38794
39271
|
}
|
|
38795
|
-
function runSsh(target, remoteCommand,
|
|
39272
|
+
function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
38796
39273
|
return new Promise((resolve3) => {
|
|
38797
39274
|
if (target.auth === "password" && !getSshPassword(target.id)) {
|
|
38798
39275
|
resolve3({
|
|
@@ -38832,7 +39309,7 @@ function runSsh(target, remoteCommand, timeoutMs = 6e4) {
|
|
|
38832
39309
|
stdout,
|
|
38833
39310
|
stderr: stderr + "\n[ssh] timeout"
|
|
38834
39311
|
});
|
|
38835
|
-
},
|
|
39312
|
+
}, timeoutMs2);
|
|
38836
39313
|
child.on("error", (err) => {
|
|
38837
39314
|
clearTimeout(timer);
|
|
38838
39315
|
resolve3({
|
|
@@ -39061,7 +39538,7 @@ async function readChecks(cwd) {
|
|
|
39061
39538
|
return [];
|
|
39062
39539
|
}
|
|
39063
39540
|
}
|
|
39064
|
-
function runShell(command, cwd,
|
|
39541
|
+
function runShell(command, cwd, timeoutMs2, signal) {
|
|
39065
39542
|
return new Promise((resolve3) => {
|
|
39066
39543
|
const isWin = process.platform === "win32";
|
|
39067
39544
|
const child = spawn10(isWin ? "cmd.exe" : "/bin/sh", isWin ? ["/c", command] : ["-c", command], {
|
|
@@ -39073,7 +39550,7 @@ function runShell(command, cwd, timeoutMs, signal) {
|
|
|
39073
39550
|
let stdout = "";
|
|
39074
39551
|
let stderr = "";
|
|
39075
39552
|
let settled = false;
|
|
39076
|
-
const
|
|
39553
|
+
const finish2 = (exitCode) => {
|
|
39077
39554
|
if (settled) return;
|
|
39078
39555
|
settled = true;
|
|
39079
39556
|
resolve3({ exitCode, stdout, stderr });
|
|
@@ -39083,8 +39560,8 @@ function runShell(command, cwd, timeoutMs, signal) {
|
|
|
39083
39560
|
child.kill("SIGTERM");
|
|
39084
39561
|
} catch {
|
|
39085
39562
|
}
|
|
39086
|
-
|
|
39087
|
-
},
|
|
39563
|
+
finish2(124);
|
|
39564
|
+
}, timeoutMs2);
|
|
39088
39565
|
if (signal) {
|
|
39089
39566
|
if (signal.aborted) {
|
|
39090
39567
|
try {
|
|
@@ -39092,7 +39569,7 @@ function runShell(command, cwd, timeoutMs, signal) {
|
|
|
39092
39569
|
} catch {
|
|
39093
39570
|
}
|
|
39094
39571
|
clearTimeout(timer);
|
|
39095
|
-
|
|
39572
|
+
finish2(130);
|
|
39096
39573
|
return;
|
|
39097
39574
|
}
|
|
39098
39575
|
signal.addEventListener(
|
|
@@ -39103,7 +39580,7 @@ function runShell(command, cwd, timeoutMs, signal) {
|
|
|
39103
39580
|
} catch {
|
|
39104
39581
|
}
|
|
39105
39582
|
clearTimeout(timer);
|
|
39106
|
-
|
|
39583
|
+
finish2(130);
|
|
39107
39584
|
},
|
|
39108
39585
|
{ once: true }
|
|
39109
39586
|
);
|
|
@@ -39118,11 +39595,11 @@ function runShell(command, cwd, timeoutMs, signal) {
|
|
|
39118
39595
|
});
|
|
39119
39596
|
child.on("error", () => {
|
|
39120
39597
|
clearTimeout(timer);
|
|
39121
|
-
|
|
39598
|
+
finish2(1);
|
|
39122
39599
|
});
|
|
39123
39600
|
child.on("close", (code) => {
|
|
39124
39601
|
clearTimeout(timer);
|
|
39125
|
-
|
|
39602
|
+
finish2(code ?? 1);
|
|
39126
39603
|
});
|
|
39127
39604
|
});
|
|
39128
39605
|
}
|
|
@@ -39144,9 +39621,9 @@ async function runBacktest(cwd, signal) {
|
|
|
39144
39621
|
const results = [];
|
|
39145
39622
|
for (const c of checks) {
|
|
39146
39623
|
const expectExit = c.expectExit ?? 0;
|
|
39147
|
-
const
|
|
39624
|
+
const timeoutMs2 = c.timeoutMs ?? 12e4;
|
|
39148
39625
|
const start = Date.now();
|
|
39149
|
-
const { exitCode, stdout, stderr } = await runShell(c.command, cwd,
|
|
39626
|
+
const { exitCode, stdout, stderr } = await runShell(c.command, cwd, timeoutMs2, signal);
|
|
39150
39627
|
const combined = `${stdout}${stderr}`;
|
|
39151
39628
|
const preview = combined.slice(0, 400);
|
|
39152
39629
|
let ok = exitCode === expectExit;
|
|
@@ -39858,8 +40335,9 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
39858
40335
|
if (hooks) registry4.setLifecycleHooks(hooks);
|
|
39859
40336
|
const readOnly = options.readOnly === true || options.planMode === true || profile === "explore";
|
|
39860
40337
|
const verifyMode = profile === "verify";
|
|
39861
|
-
const
|
|
39862
|
-
const
|
|
40338
|
+
const gauntletParent = options.gauntletParent === true;
|
|
40339
|
+
const allowMutators = !readOnly && !verifyMode && !gauntletParent;
|
|
40340
|
+
const allowBash = (allowMutators || verifyMode) && !gauntletParent;
|
|
39863
40341
|
const permPolicy = options.permissionPolicy ?? defaultPermissionPolicy();
|
|
39864
40342
|
const withPerm = (t) => wrapWithPermissions(t, permPolicy, options.onPermissionAsk);
|
|
39865
40343
|
registry4.register(withPerm(safeReadFile));
|
|
@@ -39892,21 +40370,21 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
39892
40370
|
if (allowBash) {
|
|
39893
40371
|
registry4.register(withPerm(safeBash));
|
|
39894
40372
|
}
|
|
39895
|
-
const askUserTool = options.readOnly === true || profile === "explore" || profile === "verify" ? null : createAskUserTool(options.onAskUser);
|
|
40373
|
+
const askUserTool = options.readOnly === true || profile === "explore" || profile === "verify" || gauntletParent ? null : createAskUserTool(options.onAskUser);
|
|
39896
40374
|
if (askUserTool) {
|
|
39897
40375
|
registry4.register(withPerm(askUserTool));
|
|
39898
40376
|
}
|
|
39899
|
-
const enableSkill = options.enableSkill !== false && options.readOnly !== true && profile !== "explore" && profile !== "verify";
|
|
40377
|
+
const enableSkill = options.enableSkill !== false && options.readOnly !== true && !gauntletParent && profile !== "explore" && profile !== "verify";
|
|
39900
40378
|
const skillTool = enableSkill ? withPerm(createSkillTool({ cwd: root })) : null;
|
|
39901
40379
|
if (skillTool) {
|
|
39902
40380
|
registry4.register(skillTool);
|
|
39903
40381
|
}
|
|
39904
|
-
const enableTodos = options.enableTodos !== false && options.readOnly !== true && profile === "full";
|
|
40382
|
+
const enableTodos = options.enableTodos !== false && options.readOnly !== true && !gauntletParent && profile === "full";
|
|
39905
40383
|
const todoWrite = enableTodos ? withPerm(createTodoWriteTool()) : null;
|
|
39906
40384
|
const todoRead = enableTodos ? withPerm(createTodoReadTool()) : null;
|
|
39907
40385
|
if (todoWrite) registry4.register(todoWrite);
|
|
39908
40386
|
if (todoRead) registry4.register(todoRead);
|
|
39909
|
-
const enablePlanTasks = options.enablePlanTasks !== false && options.readOnly !== true && (profile === "full" || options.planMode === true) && profile !== "explore" && profile !== "verify" && profile !== "general";
|
|
40387
|
+
const enablePlanTasks = options.enablePlanTasks !== false && options.readOnly !== true && !gauntletParent && (profile === "full" || options.planMode === true) && profile !== "explore" && profile !== "verify" && profile !== "general";
|
|
39910
40388
|
const planTaskToolsWrapped = (enablePlanTasks ? createPlanTaskTools({ projectRoot: root, onTaskEvent: options.onTaskEvent }) : []).map((t) => withPerm(t));
|
|
39911
40389
|
for (const t of planTaskToolsWrapped) {
|
|
39912
40390
|
registry4.register(t);
|
|
@@ -39957,7 +40435,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
39957
40435
|
permissions: semanticTool.permissions ?? []
|
|
39958
40436
|
});
|
|
39959
40437
|
}
|
|
39960
|
-
if (!readOnly && process.env.ZELARI_BROWSER !== "0") {
|
|
40438
|
+
if (!readOnly && !gauntletParent && process.env.ZELARI_BROWSER !== "0") {
|
|
39961
40439
|
const browserTool = createBrowserTool();
|
|
39962
40440
|
registry4.register(browserTool);
|
|
39963
40441
|
tools.push({
|
|
@@ -39966,7 +40444,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
39966
40444
|
permissions: browserTool.permissions ?? []
|
|
39967
40445
|
});
|
|
39968
40446
|
}
|
|
39969
|
-
if (!readOnly && process.env.ZELARI_SSH !== "0") {
|
|
40447
|
+
if (!readOnly && !gauntletParent && process.env.ZELARI_SSH !== "0") {
|
|
39970
40448
|
for (const t of createSshTools()) {
|
|
39971
40449
|
registry4.register(t);
|
|
39972
40450
|
tools.push({
|
|
@@ -39976,7 +40454,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
39976
40454
|
});
|
|
39977
40455
|
}
|
|
39978
40456
|
}
|
|
39979
|
-
if (!readOnly) {
|
|
40457
|
+
if (!readOnly && !gauntletParent) {
|
|
39980
40458
|
for (const t of createWorldModelTools()) {
|
|
39981
40459
|
const safe = wrapWithAudit(t, audit, sessionId2);
|
|
39982
40460
|
registry4.register(safe);
|
|
@@ -40202,10 +40680,10 @@ function wrapWithDiagnostics(original, root, runner) {
|
|
|
40202
40680
|
const filePath = value && typeof value === "object" && typeof value.path === "string" ? value.path : void 0;
|
|
40203
40681
|
if (!filePath) return result;
|
|
40204
40682
|
try {
|
|
40205
|
-
const
|
|
40683
|
+
const timeoutMs2 = Number(process.env.ZELARI_DIAGNOSTICS_TIMEOUT_MS) || 5e3;
|
|
40206
40684
|
const diags = await runDiagnosticsForFile(filePath, {
|
|
40207
40685
|
cwd: root,
|
|
40208
|
-
timeoutMs,
|
|
40686
|
+
timeoutMs: timeoutMs2,
|
|
40209
40687
|
...runner ? { runner } : {}
|
|
40210
40688
|
});
|
|
40211
40689
|
const formatted = formatDiagnostics(diags, { relativeTo: root });
|
|
@@ -40353,711 +40831,171 @@ var init_toolRegistry = __esm({
|
|
|
40353
40831
|
}
|
|
40354
40832
|
});
|
|
40355
40833
|
|
|
40356
|
-
// src/cli/
|
|
40357
|
-
|
|
40358
|
-
|
|
40359
|
-
|
|
40360
|
-
|
|
40361
|
-
|
|
40362
|
-
describePhase: () => describePhase,
|
|
40363
|
-
nextPhase: () => nextPhase,
|
|
40364
|
-
parsePhase: () => parsePhase
|
|
40365
|
-
});
|
|
40366
|
-
function parsePhase(input) {
|
|
40367
|
-
const v = input.trim().toLowerCase();
|
|
40368
|
-
return PHASES.includes(v) ? v : null;
|
|
40834
|
+
// src/cli/state/fileStateStore.ts
|
|
40835
|
+
import { createHash as createHash11, randomUUID as randomUUID2 } from "node:crypto";
|
|
40836
|
+
import { promises as fs21 } from "node:fs";
|
|
40837
|
+
import * as path41 from "node:path";
|
|
40838
|
+
function shortId() {
|
|
40839
|
+
return randomUUID2().replace(/-/g, "").slice(0, 12);
|
|
40369
40840
|
}
|
|
40370
|
-
function
|
|
40371
|
-
|
|
40841
|
+
async function writeJsonAtomic(filePath, data) {
|
|
40842
|
+
await fs21.mkdir(path41.dirname(filePath), { recursive: true });
|
|
40843
|
+
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
40844
|
+
await fs21.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
40845
|
+
await fs21.rename(tmp, filePath);
|
|
40372
40846
|
}
|
|
40373
|
-
function
|
|
40374
|
-
|
|
40375
|
-
|
|
40376
|
-
|
|
40377
|
-
|
|
40378
|
-
|
|
40847
|
+
async function readJsonFile(filePath) {
|
|
40848
|
+
try {
|
|
40849
|
+
const raw = await fs21.readFile(filePath, "utf8");
|
|
40850
|
+
return JSON.parse(raw);
|
|
40851
|
+
} catch {
|
|
40852
|
+
return null;
|
|
40379
40853
|
}
|
|
40380
40854
|
}
|
|
40381
|
-
|
|
40382
|
-
|
|
40383
|
-
|
|
40384
|
-
|
|
40385
|
-
|
|
40386
|
-
|
|
40387
|
-
|
|
40388
|
-
|
|
40389
|
-
|
|
40390
|
-
|
|
40391
|
-
|
|
40392
|
-
|
|
40393
|
-
|
|
40394
|
-
"linkDocuments"
|
|
40395
|
-
// Soft writes that only touch .zelari / plan paths are still gated in
|
|
40396
|
-
// toolRegistry by path when needed; write_file/edit_file stay DENIED.
|
|
40397
|
-
]);
|
|
40398
|
-
PLAN_BLOCKED_TOOLS = /* @__PURE__ */ new Set([
|
|
40399
|
-
"write_file",
|
|
40400
|
-
"edit_file",
|
|
40401
|
-
"apply_diff",
|
|
40402
|
-
"bash"
|
|
40403
|
-
]);
|
|
40404
|
-
}
|
|
40405
|
-
});
|
|
40406
|
-
|
|
40407
|
-
// src/cli/mode.ts
|
|
40408
|
-
function nextMode(current) {
|
|
40409
|
-
const i = MODES.indexOf(current);
|
|
40410
|
-
return MODES[(i + 1) % MODES.length] ?? "kraken";
|
|
40855
|
+
function defaultSummary(input, discoveries) {
|
|
40856
|
+
if (input.summary?.trim()) return input.summary.trim();
|
|
40857
|
+
const lines = [
|
|
40858
|
+
`# ${input.label}`,
|
|
40859
|
+
"",
|
|
40860
|
+
`- mode: ${input.mode}`,
|
|
40861
|
+
input.layer ? `- layer: ${input.layer}` : null,
|
|
40862
|
+
`- verification: ran=${input.verification.ran} ok=${input.verification.ok}`,
|
|
40863
|
+
"",
|
|
40864
|
+
"## Discoveries",
|
|
40865
|
+
...discoveries.map((d) => `- [${d.kind}] ${d.summary}`)
|
|
40866
|
+
].filter((x) => x !== null);
|
|
40867
|
+
return lines.join("\n");
|
|
40411
40868
|
}
|
|
40412
|
-
function
|
|
40413
|
-
const
|
|
40414
|
-
|
|
40415
|
-
return MODE_ALIASES[v] ?? null;
|
|
40869
|
+
function stripStored(s) {
|
|
40870
|
+
const { artifactDir: _a3, ...meta3 } = s;
|
|
40871
|
+
return meta3;
|
|
40416
40872
|
}
|
|
40417
|
-
function
|
|
40418
|
-
|
|
40419
|
-
case "council":
|
|
40420
|
-
return "council \u2014 multi-member plan/design (Caronte\u2026Lucifero; build needs ZELARI_COUNCIL_CAN_BUILD=1)";
|
|
40421
|
-
case "zelari":
|
|
40422
|
-
return "zelari \u2014 mission: plan@council \u2192 build@kraken (legacy: ZELARI_BUILD_VIA_AGENT=0)";
|
|
40423
|
-
default:
|
|
40424
|
-
return "kraken \u2014 super-agent lead (spawns explore/general/verify tentacles; default implementer)";
|
|
40425
|
-
}
|
|
40873
|
+
function isStateEnabled(env = process.env) {
|
|
40874
|
+
return env.ZELARI_STATE !== "0";
|
|
40426
40875
|
}
|
|
40427
|
-
|
|
40428
|
-
|
|
40429
|
-
|
|
40430
|
-
|
|
40431
|
-
|
|
40432
|
-
|
|
40433
|
-
|
|
40434
|
-
|
|
40435
|
-
};
|
|
40436
|
-
}
|
|
40437
|
-
});
|
|
40438
|
-
|
|
40439
|
-
// src/cli/headless.ts
|
|
40440
|
-
import { readFileSync as readFileSync22 } from "node:fs";
|
|
40441
|
-
function defaultProfileForMode(mode) {
|
|
40442
|
-
switch (mode) {
|
|
40443
|
-
case "council":
|
|
40444
|
-
return "council/v1";
|
|
40445
|
-
case "zelari":
|
|
40446
|
-
return "mission/v1";
|
|
40447
|
-
default:
|
|
40448
|
-
return "kraken/v1";
|
|
40876
|
+
async function getStateStore(projectRoot, env = process.env) {
|
|
40877
|
+
if (!isStateEnabled(env)) return new NoopDurableStateStore();
|
|
40878
|
+
const store6 = new FileDurableStateStore();
|
|
40879
|
+
try {
|
|
40880
|
+
await store6.init(projectRoot);
|
|
40881
|
+
return store6;
|
|
40882
|
+
} catch {
|
|
40883
|
+
return new NoopDurableStateStore();
|
|
40449
40884
|
}
|
|
40450
40885
|
}
|
|
40451
|
-
function
|
|
40452
|
-
|
|
40453
|
-
|
|
40454
|
-
|
|
40455
|
-
|
|
40456
|
-
|
|
40457
|
-
|
|
40458
|
-
|
|
40459
|
-
|
|
40460
|
-
|
|
40461
|
-
|
|
40462
|
-
|
|
40463
|
-
|
|
40464
|
-
|
|
40465
|
-
|
|
40466
|
-
|
|
40467
|
-
|
|
40468
|
-
|
|
40469
|
-
|
|
40470
|
-
|
|
40471
|
-
|
|
40472
|
-
|
|
40473
|
-
|
|
40474
|
-
|
|
40475
|
-
if (arg === "--headless") continue;
|
|
40476
|
-
if (arg === "--output") {
|
|
40477
|
-
const next = argv[i + 1];
|
|
40478
|
-
if (next === "json" || next === "plain") {
|
|
40479
|
-
output = next;
|
|
40480
|
-
i++;
|
|
40481
|
-
} else {
|
|
40482
|
-
return {
|
|
40483
|
-
options: null,
|
|
40484
|
-
error: `--output requires 'json' or 'plain', got '${next ?? "(missing)"}'`
|
|
40485
|
-
};
|
|
40886
|
+
function hashStablePrompt(stable) {
|
|
40887
|
+
return createHash11("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
|
|
40888
|
+
}
|
|
40889
|
+
var DEFAULT_MATERIALIZE_CHARS, FileDurableStateStore, NoopDurableStateStore;
|
|
40890
|
+
var init_fileStateStore = __esm({
|
|
40891
|
+
"src/cli/state/fileStateStore.ts"() {
|
|
40892
|
+
"use strict";
|
|
40893
|
+
DEFAULT_MATERIALIZE_CHARS = 4e3;
|
|
40894
|
+
FileDurableStateStore = class {
|
|
40895
|
+
root = "";
|
|
40896
|
+
stateDir = "";
|
|
40897
|
+
commitsDir = "";
|
|
40898
|
+
artifactsDir = "";
|
|
40899
|
+
headPath = "";
|
|
40900
|
+
indexPath = "";
|
|
40901
|
+
async init(projectRoot) {
|
|
40902
|
+
this.root = projectRoot;
|
|
40903
|
+
this.stateDir = path41.join(projectRoot, ".zelari", "state");
|
|
40904
|
+
this.commitsDir = path41.join(this.stateDir, "commits");
|
|
40905
|
+
this.artifactsDir = path41.join(this.stateDir, "artifacts");
|
|
40906
|
+
this.headPath = path41.join(this.stateDir, "HEAD.json");
|
|
40907
|
+
this.indexPath = path41.join(this.stateDir, "index.jsonl");
|
|
40908
|
+
await fs21.mkdir(this.commitsDir, { recursive: true });
|
|
40909
|
+
await fs21.mkdir(this.artifactsDir, { recursive: true });
|
|
40486
40910
|
}
|
|
40487
|
-
|
|
40488
|
-
|
|
40489
|
-
|
|
40490
|
-
|
|
40491
|
-
|
|
40492
|
-
if (next) {
|
|
40493
|
-
try {
|
|
40494
|
-
const fromFile = readFileSync22(next, "utf-8");
|
|
40495
|
-
if (fromFile.trim()) task = fromFile;
|
|
40496
|
-
} catch {
|
|
40911
|
+
async commit(input) {
|
|
40912
|
+
if (!input.force && input.verification.ran && !input.verification.ok) {
|
|
40913
|
+
throw new Error(
|
|
40914
|
+
"DurableStateStore.commit refused: verification ran and failed (pass force:true for soft commit)"
|
|
40915
|
+
);
|
|
40497
40916
|
}
|
|
40498
|
-
|
|
40499
|
-
|
|
40500
|
-
|
|
40501
|
-
|
|
40502
|
-
|
|
40503
|
-
|
|
40504
|
-
|
|
40505
|
-
|
|
40506
|
-
|
|
40507
|
-
|
|
40508
|
-
|
|
40917
|
+
const discoveries = input.discoveries ?? [];
|
|
40918
|
+
const parent = await this.head();
|
|
40919
|
+
const id = shortId();
|
|
40920
|
+
const artifactRel = path41.join("artifacts", id);
|
|
40921
|
+
const artifactAbs = path41.join(this.artifactsDir, id);
|
|
40922
|
+
await fs21.mkdir(artifactAbs, { recursive: true });
|
|
40923
|
+
const summary = defaultSummary(input, discoveries);
|
|
40924
|
+
await fs21.writeFile(path41.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
|
|
40925
|
+
await writeJsonAtomic(path41.join(artifactAbs, "discoveries.json"), discoveries);
|
|
40926
|
+
await writeJsonAtomic(path41.join(artifactAbs, "verification.json"), input.verification);
|
|
40927
|
+
const meta3 = {
|
|
40928
|
+
id,
|
|
40929
|
+
parentId: parent?.id ?? null,
|
|
40930
|
+
createdAt: Date.now(),
|
|
40931
|
+
sessionId: input.sessionId,
|
|
40932
|
+
mode: input.mode,
|
|
40933
|
+
layer: input.layer,
|
|
40934
|
+
label: input.label,
|
|
40935
|
+
workspaceCheckpointId: input.workspaceCheckpointId,
|
|
40936
|
+
verification: {
|
|
40937
|
+
...input.verification,
|
|
40938
|
+
reportPath: input.verification.reportPath ?? path41.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
|
|
40939
|
+
},
|
|
40940
|
+
changedPaths: input.changedPaths ?? [],
|
|
40941
|
+
stablePromptHash: input.stablePromptHash,
|
|
40942
|
+
discoveryCount: discoveries.length,
|
|
40943
|
+
artifactDir: artifactRel.replace(/\\/g, "/")
|
|
40509
40944
|
};
|
|
40945
|
+
await writeJsonAtomic(path41.join(this.commitsDir, `${id}.json`), meta3);
|
|
40946
|
+
await writeJsonAtomic(this.headPath, { id, updatedAt: meta3.createdAt });
|
|
40947
|
+
await fs21.appendFile(this.indexPath, JSON.stringify({ id, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
|
|
40948
|
+
return stripStored(meta3);
|
|
40510
40949
|
}
|
|
40511
|
-
|
|
40512
|
-
|
|
40513
|
-
|
|
40514
|
-
|
|
40515
|
-
const next = argv[i + 1];
|
|
40516
|
-
const parsed = next ? parsePhase(next) : null;
|
|
40517
|
-
if (!parsed) {
|
|
40518
|
-
return {
|
|
40519
|
-
options: null,
|
|
40520
|
-
error: `--phase requires 'plan' or 'build', got '${next ?? "(missing)"}'`
|
|
40521
|
-
};
|
|
40950
|
+
async head() {
|
|
40951
|
+
const head = await readJsonFile(this.headPath);
|
|
40952
|
+
if (!head?.id) return null;
|
|
40953
|
+
return this.get(head.id);
|
|
40522
40954
|
}
|
|
40523
|
-
|
|
40524
|
-
|
|
40525
|
-
|
|
40526
|
-
|
|
40527
|
-
|
|
40528
|
-
|
|
40529
|
-
|
|
40530
|
-
|
|
40531
|
-
|
|
40532
|
-
|
|
40533
|
-
if (next) {
|
|
40534
|
-
let raw = null;
|
|
40535
|
-
if (arg === "--history-file") {
|
|
40536
|
-
try {
|
|
40537
|
-
raw = readFileSync22(next, "utf-8");
|
|
40538
|
-
} catch {
|
|
40539
|
-
raw = null;
|
|
40540
|
-
}
|
|
40541
|
-
} else {
|
|
40542
|
-
raw = next;
|
|
40955
|
+
async get(id) {
|
|
40956
|
+
const stored = await readJsonFile(path41.join(this.commitsDir, `${id}.json`));
|
|
40957
|
+
return stored ? stripStored(stored) : null;
|
|
40958
|
+
}
|
|
40959
|
+
async list(limit = 20) {
|
|
40960
|
+
let raw;
|
|
40961
|
+
try {
|
|
40962
|
+
raw = await fs21.readFile(this.indexPath, "utf8");
|
|
40963
|
+
} catch {
|
|
40964
|
+
return [];
|
|
40543
40965
|
}
|
|
40544
|
-
|
|
40966
|
+
const ids = [];
|
|
40967
|
+
for (const line of raw.split("\n")) {
|
|
40968
|
+
const t = line.trim();
|
|
40969
|
+
if (!t) continue;
|
|
40545
40970
|
try {
|
|
40546
|
-
const
|
|
40547
|
-
if (
|
|
40548
|
-
history2 = parsedHist.filter(
|
|
40549
|
-
(m) => !!m && typeof m === "object" && typeof m.role === "string"
|
|
40550
|
-
).map((m) => {
|
|
40551
|
-
const role = String(m.role);
|
|
40552
|
-
const raw2 = m.content;
|
|
40553
|
-
const content = typeof raw2 === "string" ? raw2 : raw2 == null ? "" : typeof raw2 === "object" ? JSON.stringify(raw2) : String(raw2);
|
|
40554
|
-
const msg = {
|
|
40555
|
-
role,
|
|
40556
|
-
content
|
|
40557
|
-
};
|
|
40558
|
-
if (typeof m.toolCallId === "string") {
|
|
40559
|
-
msg.toolCallId = m.toolCallId;
|
|
40560
|
-
}
|
|
40561
|
-
return msg;
|
|
40562
|
-
}).filter(
|
|
40563
|
-
(m) => m.role === "user" || m.role === "assistant" || m.role === "tool" || m.role === "system"
|
|
40564
|
-
);
|
|
40565
|
-
}
|
|
40971
|
+
const row = JSON.parse(t);
|
|
40972
|
+
if (row.id) ids.push(row.id);
|
|
40566
40973
|
} catch {
|
|
40567
40974
|
}
|
|
40568
40975
|
}
|
|
40569
|
-
|
|
40976
|
+
const slice = ids.slice(-Math.max(1, limit)).reverse();
|
|
40977
|
+
const out = [];
|
|
40978
|
+
for (const id of slice) {
|
|
40979
|
+
const m = await this.get(id);
|
|
40980
|
+
if (m) out.push(m);
|
|
40981
|
+
}
|
|
40982
|
+
return out;
|
|
40570
40983
|
}
|
|
40571
|
-
|
|
40572
|
-
|
|
40573
|
-
|
|
40574
|
-
|
|
40575
|
-
const parsed = JSON.parse(next);
|
|
40576
|
-
if (Array.isArray(parsed)) {
|
|
40577
|
-
todos2 = parsed.filter(
|
|
40578
|
-
(t) => !!t && typeof t === "object" && typeof t.content === "string"
|
|
40579
|
-
).map((t) => ({
|
|
40580
|
-
id: typeof t.id === "string" ? t.id : void 0,
|
|
40581
|
-
content: String(t.content).slice(0, 500),
|
|
40582
|
-
status: t.status
|
|
40583
|
-
}));
|
|
40584
|
-
}
|
|
40585
|
-
} catch {
|
|
40984
|
+
async setHead(id) {
|
|
40985
|
+
const meta3 = await this.get(id);
|
|
40986
|
+
if (!meta3) {
|
|
40987
|
+
throw new Error(`DurableStateStore.setHead: unknown commit ${id}`);
|
|
40586
40988
|
}
|
|
40587
|
-
|
|
40989
|
+
await writeJsonAtomic(this.headPath, { id, updatedAt: Date.now() });
|
|
40990
|
+
return meta3;
|
|
40588
40991
|
}
|
|
40589
|
-
|
|
40590
|
-
|
|
40591
|
-
|
|
40592
|
-
|
|
40593
|
-
|
|
40594
|
-
|
|
40595
|
-
|
|
40596
|
-
try {
|
|
40597
|
-
resolveProfile(next);
|
|
40598
|
-
} catch (err) {
|
|
40599
|
-
return {
|
|
40600
|
-
options: null,
|
|
40601
|
-
error: err instanceof Error ? err.message : String(err)
|
|
40602
|
-
};
|
|
40603
|
-
}
|
|
40604
|
-
profile = next;
|
|
40605
|
-
i++;
|
|
40606
|
-
} else if (arg === "--resume") {
|
|
40607
|
-
const next = argv[i + 1];
|
|
40608
|
-
if (!next || next.startsWith("--")) {
|
|
40609
|
-
return { options: null, error: `--resume requires a session id, got '${next ?? "(missing)"}'` };
|
|
40610
|
-
}
|
|
40611
|
-
resumeSessionId = next;
|
|
40612
|
-
i++;
|
|
40613
|
-
} else if (arg === "--export-session") {
|
|
40614
|
-
const next = argv[i + 1];
|
|
40615
|
-
if (!next || next.startsWith("--")) {
|
|
40616
|
-
return { options: null, error: `--export-session requires a path (or - for stdout), got '${next ?? "(missing)"}'` };
|
|
40617
|
-
}
|
|
40618
|
-
exportSessionPath = next;
|
|
40619
|
-
i++;
|
|
40620
|
-
} else if (arg === "--strict-done") {
|
|
40621
|
-
strictDone = true;
|
|
40622
|
-
} else if (arg === "--no-strict-done") {
|
|
40623
|
-
strictDone = false;
|
|
40624
|
-
process.env.ZELARI_MISSION_STRICT = "0";
|
|
40625
|
-
} else if (arg === "--kraken-graph") {
|
|
40626
|
-
krakenGraph = argv[i + 1];
|
|
40627
|
-
i++;
|
|
40628
|
-
} else if (arg === "--kraken-graph-file") {
|
|
40629
|
-
const next = argv[i + 1];
|
|
40630
|
-
if (next) {
|
|
40631
|
-
try {
|
|
40632
|
-
const fromFile = readFileSync22(next, "utf-8");
|
|
40633
|
-
if (fromFile.trim()) krakenGraph = fromFile;
|
|
40634
|
-
} catch {
|
|
40635
|
-
}
|
|
40636
|
-
}
|
|
40637
|
-
i++;
|
|
40638
|
-
} else if (arg === "--plan-only") {
|
|
40639
|
-
planOnly = true;
|
|
40640
|
-
} else if (arg === "--run-plan") {
|
|
40641
|
-
runPlan = argv[i + 1];
|
|
40642
|
-
i++;
|
|
40643
|
-
}
|
|
40644
|
-
}
|
|
40645
|
-
if (councilFlag && !modeExplicit) {
|
|
40646
|
-
mode = "council";
|
|
40647
|
-
} else if (councilFlag && modeExplicit && mode !== "council") {
|
|
40648
|
-
return {
|
|
40649
|
-
options: null,
|
|
40650
|
-
error: `--council conflicts with --mode ${mode}`
|
|
40651
|
-
};
|
|
40652
|
-
}
|
|
40653
|
-
if (task && krakenGraph) {
|
|
40654
|
-
return { options: null, error: "--task and --kraken-graph are mutually exclusive" };
|
|
40655
|
-
}
|
|
40656
|
-
if ((!task || task.trim().length === 0) && (!krakenGraph || krakenGraph.trim().length === 0)) {
|
|
40657
|
-
return { options: null, error: "--headless requires --task <prompt> or --kraken-graph <goal>" };
|
|
40658
|
-
}
|
|
40659
|
-
return {
|
|
40660
|
-
options: {
|
|
40661
|
-
task: task ?? "",
|
|
40662
|
-
output,
|
|
40663
|
-
mode,
|
|
40664
|
-
phase: phase2,
|
|
40665
|
-
useCouncil: mode === "council",
|
|
40666
|
-
provider,
|
|
40667
|
-
model,
|
|
40668
|
-
...history2 && history2.length > 0 ? { history: history2 } : {},
|
|
40669
|
-
...todos2 && todos2.length > 0 ? { todos: todos2 } : {},
|
|
40670
|
-
...once ? { once: true } : {},
|
|
40671
|
-
...profile ? { profile } : {},
|
|
40672
|
-
...resumeSessionId ? { resumeSessionId } : {},
|
|
40673
|
-
...exportSessionPath ? { exportSessionPath } : {},
|
|
40674
|
-
...strictDone ? { strictDone: true } : {},
|
|
40675
|
-
...krakenGraph ? { krakenGraph } : {},
|
|
40676
|
-
...planOnly ? { planOnly: true } : {},
|
|
40677
|
-
...runPlan ? { runPlan } : {}
|
|
40678
|
-
}
|
|
40679
|
-
};
|
|
40680
|
-
}
|
|
40681
|
-
async function resolveHeadlessKey(providerId) {
|
|
40682
|
-
const spec = PROVIDERS.find((p3) => p3.id === providerId);
|
|
40683
|
-
if (!spec) {
|
|
40684
|
-
return { error: `unknown provider: '${providerId}'` };
|
|
40685
|
-
}
|
|
40686
|
-
const resolved = await resolveApiKeyWithMeta(providerId);
|
|
40687
|
-
if (!resolved || !resolved.apiKey) {
|
|
40688
|
-
return {
|
|
40689
|
-
error: `no API key for provider '${providerId}'.
|
|
40690
|
-
Set the env var ${spec.envVar} or save a key via /login.`
|
|
40691
|
-
};
|
|
40692
|
-
}
|
|
40693
|
-
const { resolveBaseUrl: resolveBaseUrl2 } = await Promise.resolve().then(() => (init_openai_compatible(), openai_compatible_exports));
|
|
40694
|
-
return {
|
|
40695
|
-
apiKey: resolved.apiKey,
|
|
40696
|
-
baseUrl: resolveBaseUrl2(providerId)
|
|
40697
|
-
};
|
|
40698
|
-
}
|
|
40699
|
-
function resolveHeadlessProvider(opts) {
|
|
40700
|
-
const provider = opts.provider ?? getActiveProvider().id;
|
|
40701
|
-
const model = opts.model ?? getModelForProvider(provider);
|
|
40702
|
-
return { provider, model };
|
|
40703
|
-
}
|
|
40704
|
-
function emitEvent(event) {
|
|
40705
|
-
process.stdout.write(JSON.stringify(event) + "\n");
|
|
40706
|
-
}
|
|
40707
|
-
var init_headless = __esm({
|
|
40708
|
-
"src/cli/headless.ts"() {
|
|
40709
|
-
"use strict";
|
|
40710
|
-
init_keyStore();
|
|
40711
|
-
init_providerConfig();
|
|
40712
|
-
init_openai_compatible();
|
|
40713
|
-
init_phase();
|
|
40714
|
-
init_mode();
|
|
40715
|
-
init_runtime2();
|
|
40716
|
-
}
|
|
40717
|
-
});
|
|
40718
|
-
|
|
40719
|
-
// src/cli/headlessSpine.ts
|
|
40720
|
-
var headlessSpine_exports = {};
|
|
40721
|
-
__export(headlessSpine_exports, {
|
|
40722
|
-
derivedModelSeed: () => derivedModelSeed,
|
|
40723
|
-
exportSessionById: () => exportSessionById,
|
|
40724
|
-
missionStateFromSpine: () => missionStateFromSpine,
|
|
40725
|
-
openHeadlessSpine: () => openHeadlessSpine,
|
|
40726
|
-
resolveHeadlessProfileId: () => resolveHeadlessProfileId,
|
|
40727
|
-
seedHeadlessModelHistory: () => seedHeadlessModelHistory,
|
|
40728
|
-
sessionStartedEvent: () => sessionStartedEvent
|
|
40729
|
-
});
|
|
40730
|
-
function sessionStartedEvent(handle) {
|
|
40731
|
-
return {
|
|
40732
|
-
type: "session_started",
|
|
40733
|
-
sessionId: handle.sessionId,
|
|
40734
|
-
spine: handle.spine.status
|
|
40735
|
-
};
|
|
40736
|
-
}
|
|
40737
|
-
function resolveHeadlessProfileId(mode, explicit) {
|
|
40738
|
-
if (explicit) return resolveProfile(explicit).id;
|
|
40739
|
-
return defaultProfileForMode(mode ?? "kraken");
|
|
40740
|
-
}
|
|
40741
|
-
async function openHeadlessSpine(opts) {
|
|
40742
|
-
const profileId = resolveHeadlessProfileId(opts.mode, opts.profile);
|
|
40743
|
-
let profileTools = [];
|
|
40744
|
-
try {
|
|
40745
|
-
profileTools = resolveProfile(profileId).tools;
|
|
40746
|
-
} catch {
|
|
40747
|
-
profileTools = [];
|
|
40748
|
-
}
|
|
40749
|
-
const extra = {
|
|
40750
|
-
profile: profileId,
|
|
40751
|
-
workspace: opts.workspace ?? process.cwd(),
|
|
40752
|
-
toolManifestHash: profileTools.length > 0 ? toolManifestHash(profileTools) : void 0
|
|
40753
|
-
};
|
|
40754
|
-
const mirrorOpts = {
|
|
40755
|
-
baseDir: opts.baseDir,
|
|
40756
|
-
quiet: opts.quiet,
|
|
40757
|
-
extraStarted: extra
|
|
40758
|
-
};
|
|
40759
|
-
const spine = await SessionSpineMirror.adopt(opts.sessionId, mirrorOpts);
|
|
40760
|
-
if (spine.status === "active") {
|
|
40761
|
-
spine.note("headless.profile", { profile: profileId, mode: opts.mode ?? "kraken" });
|
|
40762
|
-
}
|
|
40763
|
-
return {
|
|
40764
|
-
sessionId: opts.sessionId,
|
|
40765
|
-
profileId,
|
|
40766
|
-
spine,
|
|
40767
|
-
observe(ev) {
|
|
40768
|
-
if (ev && typeof ev === "object" && "type" in ev) {
|
|
40769
|
-
spine.mirrorBrainEvent(ev);
|
|
40770
|
-
}
|
|
40771
|
-
},
|
|
40772
|
-
userMessage(text) {
|
|
40773
|
-
spine.userMessage(text);
|
|
40774
|
-
},
|
|
40775
|
-
verificationRun(payload) {
|
|
40776
|
-
spine.verificationRun(payload);
|
|
40777
|
-
},
|
|
40778
|
-
appendEvent(input) {
|
|
40779
|
-
return spine.appendEvent(input);
|
|
40780
|
-
},
|
|
40781
|
-
lastVerificationRun() {
|
|
40782
|
-
return spine.lastVerificationRun();
|
|
40783
|
-
},
|
|
40784
|
-
missionPhase(phase2, note) {
|
|
40785
|
-
spine.missionPhase(phase2, note);
|
|
40786
|
-
},
|
|
40787
|
-
missionProgress(advice) {
|
|
40788
|
-
spine.missionProgress(advice);
|
|
40789
|
-
},
|
|
40790
|
-
note(text, data) {
|
|
40791
|
-
spine.note(text, data);
|
|
40792
|
-
},
|
|
40793
|
-
async close(reason = "host-exit") {
|
|
40794
|
-
await spine.close(reason);
|
|
40795
|
-
},
|
|
40796
|
-
async interrupt(note) {
|
|
40797
|
-
if (note) spine.note("headless.interrupt", { note });
|
|
40798
|
-
await spine.release();
|
|
40799
|
-
},
|
|
40800
|
-
async exportJson() {
|
|
40801
|
-
try {
|
|
40802
|
-
const store6 = new SessionStore(resolveSessionsDir({ baseDir: opts.baseDir }));
|
|
40803
|
-
if (!await store6.exists(opts.sessionId)) return null;
|
|
40804
|
-
return await exportSessionJson(store6, opts.sessionId);
|
|
40805
|
-
} catch {
|
|
40806
|
-
return null;
|
|
40807
|
-
}
|
|
40808
|
-
}
|
|
40809
|
-
};
|
|
40810
|
-
}
|
|
40811
|
-
async function exportSessionById(sessionId2, baseDir) {
|
|
40812
|
-
try {
|
|
40813
|
-
const store6 = SessionStore.withDefaults(baseDir ? { baseDir } : {});
|
|
40814
|
-
if (!await store6.exists(sessionId2)) {
|
|
40815
|
-
return { ok: false, error: `session not found: ${sessionId2}` };
|
|
40816
|
-
}
|
|
40817
|
-
return { ok: true, json: await exportSessionJson(store6, sessionId2) };
|
|
40818
|
-
} catch (err) {
|
|
40819
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
40820
|
-
}
|
|
40821
|
-
}
|
|
40822
|
-
async function missionStateFromSpine(sessionId2, baseDir) {
|
|
40823
|
-
try {
|
|
40824
|
-
const store6 = SessionStore.withDefaults(baseDir ? { baseDir } : {});
|
|
40825
|
-
if (!await store6.exists(sessionId2)) return null;
|
|
40826
|
-
const projection = await store6.projection(sessionId2);
|
|
40827
|
-
return deriveMissionState(projection);
|
|
40828
|
-
} catch {
|
|
40829
|
-
return null;
|
|
40830
|
-
}
|
|
40831
|
-
}
|
|
40832
|
-
async function seedHeadlessModelHistory(handle, legacy) {
|
|
40833
|
-
const mirror = handle.spine;
|
|
40834
|
-
const legacySeed = filterLegacySeed(legacy);
|
|
40835
|
-
if (mirror.status !== "active") {
|
|
40836
|
-
return { history: legacySeed, importedCount: 0, source: "legacy-fallback" };
|
|
40837
|
-
}
|
|
40838
|
-
const existing = await mirror.derivedPriorTurns();
|
|
40839
|
-
if (existing && existing.length > 0) {
|
|
40840
|
-
return { history: derivedModelSeed(existing), importedCount: 0, source: "spine" };
|
|
40841
|
-
}
|
|
40842
|
-
if (legacySeed.length === 0) {
|
|
40843
|
-
return { history: [], importedCount: 0, source: "spine" };
|
|
40844
|
-
}
|
|
40845
|
-
for (const m of legacySeed) {
|
|
40846
|
-
if (m.role === "user") {
|
|
40847
|
-
mirror.userMessage(m.content);
|
|
40848
|
-
} else {
|
|
40849
|
-
mirror.assistantMessage(m.content, { imported: "legacy-history" });
|
|
40850
|
-
}
|
|
40851
|
-
}
|
|
40852
|
-
await mirror.flush();
|
|
40853
|
-
const derived = await mirror.derivedPriorTurns() ?? [];
|
|
40854
|
-
return {
|
|
40855
|
-
history: derivedModelSeed(derived),
|
|
40856
|
-
importedCount: legacySeed.length,
|
|
40857
|
-
source: "spine-import"
|
|
40858
|
-
};
|
|
40859
|
-
}
|
|
40860
|
-
function filterLegacySeed(legacy) {
|
|
40861
|
-
return (legacy ?? []).filter((m) => m.role === "user" || m.role === "assistant").map(
|
|
40862
|
-
(m) => m.role === "assistant" && m.content ? {
|
|
40863
|
-
role: "assistant",
|
|
40864
|
-
content: cleanAgentContent(m.content, {
|
|
40865
|
-
stripQuestion: false,
|
|
40866
|
-
stripThink: false
|
|
40867
|
-
})
|
|
40868
|
-
} : { role: m.role, content: m.content ?? "" }
|
|
40869
|
-
).filter((m) => (m.content ?? "").trim().length > 0);
|
|
40870
|
-
}
|
|
40871
|
-
function derivedModelSeed(derived) {
|
|
40872
|
-
return derivedToAgentMessages(derived).map(
|
|
40873
|
-
(m) => m.role === "system" ? { role: "user", content: m.content } : m
|
|
40874
|
-
).map(
|
|
40875
|
-
(m) => m.role === "assistant" && m.content ? {
|
|
40876
|
-
role: "assistant",
|
|
40877
|
-
content: cleanAgentContent(m.content, {
|
|
40878
|
-
stripQuestion: false,
|
|
40879
|
-
stripThink: false
|
|
40880
|
-
})
|
|
40881
|
-
} : m
|
|
40882
|
-
).filter((m) => m.role === "user" || m.role === "assistant").filter((m) => (m.content ?? "").trim().length > 0);
|
|
40883
|
-
}
|
|
40884
|
-
var init_headlessSpine = __esm({
|
|
40885
|
-
"src/cli/headlessSpine.ts"() {
|
|
40886
|
-
"use strict";
|
|
40887
|
-
init_dist();
|
|
40888
|
-
init_session();
|
|
40889
|
-
init_mission2();
|
|
40890
|
-
init_runtime2();
|
|
40891
|
-
init_sessionSpine();
|
|
40892
|
-
init_headless();
|
|
40893
|
-
}
|
|
40894
|
-
});
|
|
40895
|
-
|
|
40896
|
-
// src/cli/state/fileStateStore.ts
|
|
40897
|
-
import { createHash as createHash11, randomUUID as randomUUID2 } from "node:crypto";
|
|
40898
|
-
import { promises as fs21 } from "node:fs";
|
|
40899
|
-
import * as path41 from "node:path";
|
|
40900
|
-
function shortId() {
|
|
40901
|
-
return randomUUID2().replace(/-/g, "").slice(0, 12);
|
|
40902
|
-
}
|
|
40903
|
-
async function writeJsonAtomic(filePath, data) {
|
|
40904
|
-
await fs21.mkdir(path41.dirname(filePath), { recursive: true });
|
|
40905
|
-
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
40906
|
-
await fs21.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
40907
|
-
await fs21.rename(tmp, filePath);
|
|
40908
|
-
}
|
|
40909
|
-
async function readJsonFile(filePath) {
|
|
40910
|
-
try {
|
|
40911
|
-
const raw = await fs21.readFile(filePath, "utf8");
|
|
40912
|
-
return JSON.parse(raw);
|
|
40913
|
-
} catch {
|
|
40914
|
-
return null;
|
|
40915
|
-
}
|
|
40916
|
-
}
|
|
40917
|
-
function defaultSummary(input, discoveries) {
|
|
40918
|
-
if (input.summary?.trim()) return input.summary.trim();
|
|
40919
|
-
const lines = [
|
|
40920
|
-
`# ${input.label}`,
|
|
40921
|
-
"",
|
|
40922
|
-
`- mode: ${input.mode}`,
|
|
40923
|
-
input.layer ? `- layer: ${input.layer}` : null,
|
|
40924
|
-
`- verification: ran=${input.verification.ran} ok=${input.verification.ok}`,
|
|
40925
|
-
"",
|
|
40926
|
-
"## Discoveries",
|
|
40927
|
-
...discoveries.map((d) => `- [${d.kind}] ${d.summary}`)
|
|
40928
|
-
].filter((x) => x !== null);
|
|
40929
|
-
return lines.join("\n");
|
|
40930
|
-
}
|
|
40931
|
-
function stripStored(s) {
|
|
40932
|
-
const { artifactDir: _a3, ...meta3 } = s;
|
|
40933
|
-
return meta3;
|
|
40934
|
-
}
|
|
40935
|
-
function isStateEnabled(env = process.env) {
|
|
40936
|
-
return env.ZELARI_STATE !== "0";
|
|
40937
|
-
}
|
|
40938
|
-
async function getStateStore(projectRoot, env = process.env) {
|
|
40939
|
-
if (!isStateEnabled(env)) return new NoopDurableStateStore();
|
|
40940
|
-
const store6 = new FileDurableStateStore();
|
|
40941
|
-
try {
|
|
40942
|
-
await store6.init(projectRoot);
|
|
40943
|
-
return store6;
|
|
40944
|
-
} catch {
|
|
40945
|
-
return new NoopDurableStateStore();
|
|
40946
|
-
}
|
|
40947
|
-
}
|
|
40948
|
-
function hashStablePrompt(stable) {
|
|
40949
|
-
return createHash11("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
|
|
40950
|
-
}
|
|
40951
|
-
var DEFAULT_MATERIALIZE_CHARS, FileDurableStateStore, NoopDurableStateStore;
|
|
40952
|
-
var init_fileStateStore = __esm({
|
|
40953
|
-
"src/cli/state/fileStateStore.ts"() {
|
|
40954
|
-
"use strict";
|
|
40955
|
-
DEFAULT_MATERIALIZE_CHARS = 4e3;
|
|
40956
|
-
FileDurableStateStore = class {
|
|
40957
|
-
root = "";
|
|
40958
|
-
stateDir = "";
|
|
40959
|
-
commitsDir = "";
|
|
40960
|
-
artifactsDir = "";
|
|
40961
|
-
headPath = "";
|
|
40962
|
-
indexPath = "";
|
|
40963
|
-
async init(projectRoot) {
|
|
40964
|
-
this.root = projectRoot;
|
|
40965
|
-
this.stateDir = path41.join(projectRoot, ".zelari", "state");
|
|
40966
|
-
this.commitsDir = path41.join(this.stateDir, "commits");
|
|
40967
|
-
this.artifactsDir = path41.join(this.stateDir, "artifacts");
|
|
40968
|
-
this.headPath = path41.join(this.stateDir, "HEAD.json");
|
|
40969
|
-
this.indexPath = path41.join(this.stateDir, "index.jsonl");
|
|
40970
|
-
await fs21.mkdir(this.commitsDir, { recursive: true });
|
|
40971
|
-
await fs21.mkdir(this.artifactsDir, { recursive: true });
|
|
40972
|
-
}
|
|
40973
|
-
async commit(input) {
|
|
40974
|
-
if (!input.force && input.verification.ran && !input.verification.ok) {
|
|
40975
|
-
throw new Error(
|
|
40976
|
-
"DurableStateStore.commit refused: verification ran and failed (pass force:true for soft commit)"
|
|
40977
|
-
);
|
|
40978
|
-
}
|
|
40979
|
-
const discoveries = input.discoveries ?? [];
|
|
40980
|
-
const parent = await this.head();
|
|
40981
|
-
const id = shortId();
|
|
40982
|
-
const artifactRel = path41.join("artifacts", id);
|
|
40983
|
-
const artifactAbs = path41.join(this.artifactsDir, id);
|
|
40984
|
-
await fs21.mkdir(artifactAbs, { recursive: true });
|
|
40985
|
-
const summary = defaultSummary(input, discoveries);
|
|
40986
|
-
await fs21.writeFile(path41.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
|
|
40987
|
-
await writeJsonAtomic(path41.join(artifactAbs, "discoveries.json"), discoveries);
|
|
40988
|
-
await writeJsonAtomic(path41.join(artifactAbs, "verification.json"), input.verification);
|
|
40989
|
-
const meta3 = {
|
|
40990
|
-
id,
|
|
40991
|
-
parentId: parent?.id ?? null,
|
|
40992
|
-
createdAt: Date.now(),
|
|
40993
|
-
sessionId: input.sessionId,
|
|
40994
|
-
mode: input.mode,
|
|
40995
|
-
layer: input.layer,
|
|
40996
|
-
label: input.label,
|
|
40997
|
-
workspaceCheckpointId: input.workspaceCheckpointId,
|
|
40998
|
-
verification: {
|
|
40999
|
-
...input.verification,
|
|
41000
|
-
reportPath: input.verification.reportPath ?? path41.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
|
|
41001
|
-
},
|
|
41002
|
-
changedPaths: input.changedPaths ?? [],
|
|
41003
|
-
stablePromptHash: input.stablePromptHash,
|
|
41004
|
-
discoveryCount: discoveries.length,
|
|
41005
|
-
artifactDir: artifactRel.replace(/\\/g, "/")
|
|
41006
|
-
};
|
|
41007
|
-
await writeJsonAtomic(path41.join(this.commitsDir, `${id}.json`), meta3);
|
|
41008
|
-
await writeJsonAtomic(this.headPath, { id, updatedAt: meta3.createdAt });
|
|
41009
|
-
await fs21.appendFile(this.indexPath, JSON.stringify({ id, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
|
|
41010
|
-
return stripStored(meta3);
|
|
41011
|
-
}
|
|
41012
|
-
async head() {
|
|
41013
|
-
const head = await readJsonFile(this.headPath);
|
|
41014
|
-
if (!head?.id) return null;
|
|
41015
|
-
return this.get(head.id);
|
|
41016
|
-
}
|
|
41017
|
-
async get(id) {
|
|
41018
|
-
const stored = await readJsonFile(path41.join(this.commitsDir, `${id}.json`));
|
|
41019
|
-
return stored ? stripStored(stored) : null;
|
|
41020
|
-
}
|
|
41021
|
-
async list(limit = 20) {
|
|
41022
|
-
let raw;
|
|
41023
|
-
try {
|
|
41024
|
-
raw = await fs21.readFile(this.indexPath, "utf8");
|
|
41025
|
-
} catch {
|
|
41026
|
-
return [];
|
|
41027
|
-
}
|
|
41028
|
-
const ids = [];
|
|
41029
|
-
for (const line of raw.split("\n")) {
|
|
41030
|
-
const t = line.trim();
|
|
41031
|
-
if (!t) continue;
|
|
41032
|
-
try {
|
|
41033
|
-
const row = JSON.parse(t);
|
|
41034
|
-
if (row.id) ids.push(row.id);
|
|
41035
|
-
} catch {
|
|
41036
|
-
}
|
|
41037
|
-
}
|
|
41038
|
-
const slice = ids.slice(-Math.max(1, limit)).reverse();
|
|
41039
|
-
const out = [];
|
|
41040
|
-
for (const id of slice) {
|
|
41041
|
-
const m = await this.get(id);
|
|
41042
|
-
if (m) out.push(m);
|
|
41043
|
-
}
|
|
41044
|
-
return out;
|
|
41045
|
-
}
|
|
41046
|
-
async setHead(id) {
|
|
41047
|
-
const meta3 = await this.get(id);
|
|
41048
|
-
if (!meta3) {
|
|
41049
|
-
throw new Error(`DurableStateStore.setHead: unknown commit ${id}`);
|
|
41050
|
-
}
|
|
41051
|
-
await writeJsonAtomic(this.headPath, { id, updatedAt: Date.now() });
|
|
41052
|
-
return meta3;
|
|
41053
|
-
}
|
|
41054
|
-
async loadDiscoveries(id) {
|
|
41055
|
-
const meta3 = id ? await this.get(id) : await this.head();
|
|
41056
|
-
if (!meta3) return [];
|
|
41057
|
-
const stored = await readJsonFile(path41.join(this.commitsDir, `${meta3.id}.json`));
|
|
41058
|
-
if (!stored?.artifactDir) return [];
|
|
41059
|
-
const discPath = path41.join(this.stateDir, stored.artifactDir, "discoveries.json");
|
|
41060
|
-
return await readJsonFile(discPath) ?? [];
|
|
40992
|
+
async loadDiscoveries(id) {
|
|
40993
|
+
const meta3 = id ? await this.get(id) : await this.head();
|
|
40994
|
+
if (!meta3) return [];
|
|
40995
|
+
const stored = await readJsonFile(path41.join(this.commitsDir, `${meta3.id}.json`));
|
|
40996
|
+
if (!stored?.artifactDir) return [];
|
|
40997
|
+
const discPath = path41.join(this.stateDir, stored.artifactDir, "discoveries.json");
|
|
40998
|
+
return await readJsonFile(discPath) ?? [];
|
|
41061
40999
|
}
|
|
41062
41000
|
async materializeContext(id, maxChars = DEFAULT_MATERIALIZE_CHARS) {
|
|
41063
41001
|
const meta3 = id ? await this.get(id) : await this.head();
|
|
@@ -41227,25 +41165,37 @@ function extractiveHistorySummary(dropped, opts) {
|
|
|
41227
41165
|
if (dropped.length === 0) return "No prior turns.";
|
|
41228
41166
|
const userGoals = [];
|
|
41229
41167
|
const assistantNotes = [];
|
|
41168
|
+
const userConstraints = [];
|
|
41169
|
+
const unresolved = [];
|
|
41170
|
+
const verification = [];
|
|
41171
|
+
const decisions = [];
|
|
41230
41172
|
const tools = /* @__PURE__ */ new Map();
|
|
41231
41173
|
const files = /* @__PURE__ */ new Set();
|
|
41232
41174
|
let toolResults = 0;
|
|
41233
41175
|
for (const m of dropped) {
|
|
41234
41176
|
if (m.role === "user" && m.content.trim()) {
|
|
41235
|
-
|
|
41177
|
+
const goal = oneLine(m.content, 220);
|
|
41178
|
+
userGoals.push(goal);
|
|
41179
|
+
if (/\b(must|never|required|only|do not|constraint|vincolo|deve|senza)\b/i.test(goal)) userConstraints.push(goal);
|
|
41236
41180
|
} else if (m.role === "assistant") {
|
|
41237
41181
|
if (m.content.trim()) {
|
|
41238
|
-
|
|
41182
|
+
const note = oneLine(m.content, 220);
|
|
41183
|
+
assistantNotes.push(note);
|
|
41184
|
+
if (/\b(fail|failed|error|unresolved|remaining|todo|blocked|gap|errore|fallit|irrisolt|manca)\b/i.test(note)) unresolved.push(note);
|
|
41185
|
+
if (/\b(test|typecheck|build|verify|verification|passed|failed|green|red)\b/i.test(note)) verification.push(note);
|
|
41186
|
+
if (/\b(decid|decision|chosen|choose|scelt|adopt|implement)\b/i.test(note)) decisions.push(note);
|
|
41239
41187
|
}
|
|
41240
41188
|
if (m.toolCalls) {
|
|
41241
41189
|
for (const tc of m.toolCalls) {
|
|
41242
41190
|
tools.set(tc.name, (tools.get(tc.name) ?? 0) + 1);
|
|
41243
|
-
|
|
41191
|
+
collectPaths2(tc.args, files);
|
|
41244
41192
|
}
|
|
41245
41193
|
}
|
|
41246
41194
|
} else if (m.role === "tool") {
|
|
41247
41195
|
toolResults += 1;
|
|
41248
41196
|
collectPathsFromText(m.content, files);
|
|
41197
|
+
if (/\b(fail|failed|error|exception|blocked|errore|fallit)\b/i.test(m.content)) unresolved.push(oneLine(m.content, 220));
|
|
41198
|
+
if (/\b(test|typecheck|build|verify|passed|failed|success)\b/i.test(m.content)) verification.push(oneLine(m.content, 220));
|
|
41249
41199
|
}
|
|
41250
41200
|
}
|
|
41251
41201
|
const parts = [
|
|
@@ -41256,6 +41206,22 @@ function extractiveHistorySummary(dropped, opts) {
|
|
|
41256
41206
|
parts.push("## User goals / requests");
|
|
41257
41207
|
for (const g of userGoals.slice(-6)) parts.push(`- ${g}`);
|
|
41258
41208
|
}
|
|
41209
|
+
if (userConstraints.length) {
|
|
41210
|
+
parts.push("## User constraints (preserve exactly)");
|
|
41211
|
+
for (const item of [...new Set(userConstraints)].slice(-8)) parts.push(`- ${item}`);
|
|
41212
|
+
}
|
|
41213
|
+
if (unresolved.length) {
|
|
41214
|
+
parts.push("## Unresolved failures / pending repair");
|
|
41215
|
+
for (const item of [...new Set(unresolved)].slice(-8)) parts.push(`- ${item}`);
|
|
41216
|
+
}
|
|
41217
|
+
if (verification.length) {
|
|
41218
|
+
parts.push("## Latest verification state");
|
|
41219
|
+
for (const item of [...new Set(verification)].slice(-6)) parts.push(`- ${item}`);
|
|
41220
|
+
}
|
|
41221
|
+
if (decisions.length) {
|
|
41222
|
+
parts.push("## Recent active decisions");
|
|
41223
|
+
for (const item of [...new Set(decisions)].slice(-6)) parts.push(`- ${item}`);
|
|
41224
|
+
}
|
|
41259
41225
|
if (assistantNotes.length) {
|
|
41260
41226
|
parts.push("## Assistant conclusions (truncated)");
|
|
41261
41227
|
for (const a of assistantNotes.slice(-5)) parts.push(`- ${a}`);
|
|
@@ -41282,7 +41248,7 @@ function oneLine(s, max) {
|
|
|
41282
41248
|
if (t.length <= max) return t;
|
|
41283
41249
|
return `${t.slice(0, max - 1)}\u2026`;
|
|
41284
41250
|
}
|
|
41285
|
-
function
|
|
41251
|
+
function collectPaths2(args, out) {
|
|
41286
41252
|
if (!args || typeof args !== "object") return;
|
|
41287
41253
|
const obj = args;
|
|
41288
41254
|
for (const key of ["path", "file", "filepath", "filePath", "target", "cwd"]) {
|
|
@@ -41401,6 +41367,36 @@ Be concise.
|
|
|
41401
41367
|
});
|
|
41402
41368
|
|
|
41403
41369
|
// src/cli/hooks/historyCompaction.ts
|
|
41370
|
+
function compactedRangeFromDropped(dropped) {
|
|
41371
|
+
if (dropped.length === 0) return void 0;
|
|
41372
|
+
const seqs = [];
|
|
41373
|
+
const sources = [];
|
|
41374
|
+
for (const m of dropped) {
|
|
41375
|
+
const hasCompactRange = typeof m.compactedFromSeq === "number" && Number.isInteger(m.compactedFromSeq) && m.compactedFromSeq > 0 && typeof m.compactedToSeq === "number" && Number.isInteger(m.compactedToSeq) && m.compactedToSeq >= m.compactedFromSeq;
|
|
41376
|
+
if (hasCompactRange) {
|
|
41377
|
+
seqs.push(m.compactedFromSeq, m.compactedToSeq);
|
|
41378
|
+
sources.push(...m.sourceEventSeqs ?? []);
|
|
41379
|
+
if (typeof m.seq === "number" && Number.isInteger(m.seq) && m.seq > 0) {
|
|
41380
|
+
seqs.push(m.seq);
|
|
41381
|
+
sources.push(m.seq);
|
|
41382
|
+
}
|
|
41383
|
+
continue;
|
|
41384
|
+
}
|
|
41385
|
+
if (typeof m.seq !== "number" || !Number.isInteger(m.seq) || m.seq < 1) return void 0;
|
|
41386
|
+
seqs.push(m.seq);
|
|
41387
|
+
sources.push(m.seq);
|
|
41388
|
+
}
|
|
41389
|
+
return {
|
|
41390
|
+
fromSeq: Math.min(...seqs),
|
|
41391
|
+
toSeq: Math.max(...seqs),
|
|
41392
|
+
sourceEventSeqs: [...new Set(sources)]
|
|
41393
|
+
};
|
|
41394
|
+
}
|
|
41395
|
+
function withDroppedRange(result, dropped, strategy) {
|
|
41396
|
+
const range = compactedRangeFromDropped(dropped);
|
|
41397
|
+
if (!range) return { ...result, strategy };
|
|
41398
|
+
return { ...result, ...range, strategy };
|
|
41399
|
+
}
|
|
41404
41400
|
function resolveMaxMessages(opts) {
|
|
41405
41401
|
const envTurns = envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 6, min: 0 });
|
|
41406
41402
|
let turns = opts?.maxMessages ? Math.ceil(opts.maxMessages / 4) : envTurns;
|
|
@@ -41474,16 +41470,25 @@ function pruneToolResultsDetailed(messages, opts) {
|
|
|
41474
41470
|
function compactHistory(messages, opts) {
|
|
41475
41471
|
return compactHistoryDetailed(messages, opts).messages;
|
|
41476
41472
|
}
|
|
41477
|
-
function buildCheckpointMessage(summaryText) {
|
|
41473
|
+
function buildCheckpointMessage(summaryText, range) {
|
|
41478
41474
|
return {
|
|
41479
41475
|
role: "user",
|
|
41480
|
-
content: CHECKPOINT_WRAPPER_PREFIX + "\n\n<compacted-summary>\n" + summaryText + "\n</compacted-summary>"
|
|
41476
|
+
content: CHECKPOINT_WRAPPER_PREFIX + "\n\n<compacted-summary>\n" + summaryText + "\n</compacted-summary>",
|
|
41477
|
+
...range ? {
|
|
41478
|
+
compactedFromSeq: range.fromSeq,
|
|
41479
|
+
compactedToSeq: range.toSeq,
|
|
41480
|
+
sourceEventSeqs: [...range.sourceEventSeqs]
|
|
41481
|
+
} : {}
|
|
41481
41482
|
};
|
|
41482
41483
|
}
|
|
41483
41484
|
function compactHistoryDetailed(messages, opts) {
|
|
41484
41485
|
const maxMessages = resolveMaxMessages(opts);
|
|
41485
41486
|
if (maxMessages === 0) {
|
|
41486
|
-
return
|
|
41487
|
+
return withDroppedRange(
|
|
41488
|
+
{ messages: [], compacted: true, messagesRemoved: messages.length, summary: "" },
|
|
41489
|
+
messages,
|
|
41490
|
+
"extractive"
|
|
41491
|
+
);
|
|
41487
41492
|
}
|
|
41488
41493
|
if (messages.length <= maxMessages * 2 && !opts?.force) {
|
|
41489
41494
|
return {
|
|
@@ -41504,19 +41509,25 @@ function compactHistoryDetailed(messages, opts) {
|
|
|
41504
41509
|
};
|
|
41505
41510
|
}
|
|
41506
41511
|
const droppedMsgs = messages.slice(0, cut);
|
|
41512
|
+
const droppedRange = compactedRangeFromDropped(droppedMsgs);
|
|
41507
41513
|
const pruned = pruneToolResultsDetailed(messages.slice(cut));
|
|
41508
41514
|
const kept = pruned.messages;
|
|
41509
41515
|
const summaryText = extractiveHistorySummary(droppedMsgs);
|
|
41510
41516
|
const summary = buildCheckpointMessage(
|
|
41511
|
-
summaryText || `${COMPACT_MARKER} ${cut} earlier message(s) dropped
|
|
41517
|
+
summaryText || `${COMPACT_MARKER} ${cut} earlier message(s) dropped.`,
|
|
41518
|
+
droppedRange
|
|
41519
|
+
);
|
|
41520
|
+
return withDroppedRange(
|
|
41521
|
+
{
|
|
41522
|
+
messages: [summary, ...kept],
|
|
41523
|
+
compacted: true,
|
|
41524
|
+
messagesRemoved: cut,
|
|
41525
|
+
summary: summary.content,
|
|
41526
|
+
prunedToolResults: pruned.stats.pruned
|
|
41527
|
+
},
|
|
41528
|
+
droppedMsgs,
|
|
41529
|
+
"extractive"
|
|
41512
41530
|
);
|
|
41513
|
-
return {
|
|
41514
|
-
messages: [summary, ...kept],
|
|
41515
|
-
compacted: true,
|
|
41516
|
-
messagesRemoved: cut,
|
|
41517
|
-
summary: summary.content,
|
|
41518
|
-
prunedToolResults: pruned.stats.pruned
|
|
41519
|
-
};
|
|
41520
41531
|
}
|
|
41521
41532
|
async function compactHistoryAsync(messages, opts) {
|
|
41522
41533
|
const base = compactHistoryDetailed(messages, opts);
|
|
@@ -41552,16 +41563,21 @@ async function compactHistoryAsync(messages, opts) {
|
|
|
41552
41563
|
}
|
|
41553
41564
|
const pruned = pruneToolResultsDetailed(messages.slice(cut));
|
|
41554
41565
|
const kept = pruned.messages;
|
|
41555
|
-
const summary = buildCheckpointMessage(summaryText);
|
|
41556
|
-
|
|
41557
|
-
|
|
41558
|
-
|
|
41559
|
-
|
|
41560
|
-
|
|
41561
|
-
|
|
41562
|
-
|
|
41563
|
-
|
|
41564
|
-
|
|
41566
|
+
const summary = buildCheckpointMessage(summaryText, compactedRangeFromDropped(droppedMsgs));
|
|
41567
|
+
const usedLlm = summaryText !== extractive && summaryText.trim().length > 40;
|
|
41568
|
+
return withDroppedRange(
|
|
41569
|
+
{
|
|
41570
|
+
messages: [summary, ...kept],
|
|
41571
|
+
compacted: true,
|
|
41572
|
+
messagesRemoved: cut,
|
|
41573
|
+
summary: summaryText,
|
|
41574
|
+
prunedToolResults: pruned.stats.pruned,
|
|
41575
|
+
cacheReuseExpected,
|
|
41576
|
+
replayExactPrefix
|
|
41577
|
+
},
|
|
41578
|
+
droppedMsgs,
|
|
41579
|
+
usedLlm ? "llm" : "extractive"
|
|
41580
|
+
);
|
|
41565
41581
|
}
|
|
41566
41582
|
function roughTokens(msgs) {
|
|
41567
41583
|
let n = 0;
|
|
@@ -41845,6 +41861,553 @@ var init_phaseState = __esm({
|
|
|
41845
41861
|
}
|
|
41846
41862
|
});
|
|
41847
41863
|
|
|
41864
|
+
// src/cli/phase.ts
|
|
41865
|
+
var phase_exports = {};
|
|
41866
|
+
__export(phase_exports, {
|
|
41867
|
+
PHASES: () => PHASES,
|
|
41868
|
+
PLAN_ALLOWED_WRITE_TOOLS: () => PLAN_ALLOWED_WRITE_TOOLS,
|
|
41869
|
+
PLAN_BLOCKED_TOOLS: () => PLAN_BLOCKED_TOOLS,
|
|
41870
|
+
describePhase: () => describePhase,
|
|
41871
|
+
nextPhase: () => nextPhase,
|
|
41872
|
+
parsePhase: () => parsePhase
|
|
41873
|
+
});
|
|
41874
|
+
function parsePhase(input) {
|
|
41875
|
+
const v = input.trim().toLowerCase();
|
|
41876
|
+
return PHASES.includes(v) ? v : null;
|
|
41877
|
+
}
|
|
41878
|
+
function nextPhase(current) {
|
|
41879
|
+
return current === "plan" ? "build" : "plan";
|
|
41880
|
+
}
|
|
41881
|
+
function describePhase(phase2) {
|
|
41882
|
+
switch (phase2) {
|
|
41883
|
+
case "plan":
|
|
41884
|
+
return "plan \u2014 explore & design only (no project writes; plan files allowed)";
|
|
41885
|
+
default:
|
|
41886
|
+
return "build \u2014 implement with full tools";
|
|
41887
|
+
}
|
|
41888
|
+
}
|
|
41889
|
+
var PHASES, PLAN_ALLOWED_WRITE_TOOLS, PLAN_BLOCKED_TOOLS;
|
|
41890
|
+
var init_phase = __esm({
|
|
41891
|
+
"src/cli/phase.ts"() {
|
|
41892
|
+
"use strict";
|
|
41893
|
+
PHASES = ["plan", "build"];
|
|
41894
|
+
PLAN_ALLOWED_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
41895
|
+
// Workspace plan/docs — intentional plan-mode outputs
|
|
41896
|
+
"createPlan",
|
|
41897
|
+
"createTask",
|
|
41898
|
+
"updateTask",
|
|
41899
|
+
"createMilestone",
|
|
41900
|
+
"createDocument",
|
|
41901
|
+
"createDecision",
|
|
41902
|
+
"linkDocuments"
|
|
41903
|
+
// Soft writes that only touch .zelari / plan paths are still gated in
|
|
41904
|
+
// toolRegistry by path when needed; write_file/edit_file stay DENIED.
|
|
41905
|
+
]);
|
|
41906
|
+
PLAN_BLOCKED_TOOLS = /* @__PURE__ */ new Set([
|
|
41907
|
+
"write_file",
|
|
41908
|
+
"edit_file",
|
|
41909
|
+
"apply_diff",
|
|
41910
|
+
"bash"
|
|
41911
|
+
]);
|
|
41912
|
+
}
|
|
41913
|
+
});
|
|
41914
|
+
|
|
41915
|
+
// src/cli/mode.ts
|
|
41916
|
+
function nextMode(current) {
|
|
41917
|
+
const i = MODES.indexOf(current);
|
|
41918
|
+
return MODES[(i + 1) % MODES.length] ?? "kraken";
|
|
41919
|
+
}
|
|
41920
|
+
function parseMode(input) {
|
|
41921
|
+
const v = input.trim().toLowerCase();
|
|
41922
|
+
if (MODES.includes(v)) return v;
|
|
41923
|
+
return MODE_ALIASES[v] ?? null;
|
|
41924
|
+
}
|
|
41925
|
+
function describeMode(mode) {
|
|
41926
|
+
switch (mode) {
|
|
41927
|
+
case "council":
|
|
41928
|
+
return "council \u2014 multi-member plan/design (Caronte\u2026Lucifero; build needs ZELARI_COUNCIL_CAN_BUILD=1)";
|
|
41929
|
+
case "zelari":
|
|
41930
|
+
return "zelari \u2014 mission: plan@council \u2192 build@kraken (legacy: ZELARI_BUILD_VIA_AGENT=0)";
|
|
41931
|
+
default:
|
|
41932
|
+
return "kraken \u2014 super-agent lead (spawns explore/general/verify tentacles; default implementer)";
|
|
41933
|
+
}
|
|
41934
|
+
}
|
|
41935
|
+
var MODES, MODE_ALIASES;
|
|
41936
|
+
var init_mode = __esm({
|
|
41937
|
+
"src/cli/mode.ts"() {
|
|
41938
|
+
"use strict";
|
|
41939
|
+
MODES = ["kraken", "council", "zelari"];
|
|
41940
|
+
MODE_ALIASES = {
|
|
41941
|
+
agent: "kraken",
|
|
41942
|
+
single: "kraken"
|
|
41943
|
+
};
|
|
41944
|
+
}
|
|
41945
|
+
});
|
|
41946
|
+
|
|
41947
|
+
// src/cli/headless.ts
|
|
41948
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
41949
|
+
function defaultProfileForMode(mode) {
|
|
41950
|
+
switch (mode) {
|
|
41951
|
+
case "council":
|
|
41952
|
+
return "council/v1";
|
|
41953
|
+
case "zelari":
|
|
41954
|
+
return "mission/v1";
|
|
41955
|
+
default:
|
|
41956
|
+
return "kraken/v1";
|
|
41957
|
+
}
|
|
41958
|
+
}
|
|
41959
|
+
function parseHeadlessFlags(argv) {
|
|
41960
|
+
if (!argv.includes("--headless")) {
|
|
41961
|
+
return { options: null };
|
|
41962
|
+
}
|
|
41963
|
+
let task;
|
|
41964
|
+
let output = "json";
|
|
41965
|
+
let mode = "kraken";
|
|
41966
|
+
let phase2 = "build";
|
|
41967
|
+
let modeExplicit = false;
|
|
41968
|
+
let councilFlag = false;
|
|
41969
|
+
let provider;
|
|
41970
|
+
let model;
|
|
41971
|
+
let history2;
|
|
41972
|
+
let todos2;
|
|
41973
|
+
let once = false;
|
|
41974
|
+
let profile;
|
|
41975
|
+
let resumeSessionId;
|
|
41976
|
+
let exportSessionPath;
|
|
41977
|
+
let strictDone = false;
|
|
41978
|
+
let krakenGraph;
|
|
41979
|
+
let planOnly = process.env.ZELARI_KRAKEN_PLAN_ONLY === "1" || process.env.ZELARI_KRAKEN_PLAN_ONLY === "true";
|
|
41980
|
+
let runPlan = process.env.ZELARI_KRAKEN_RUN_PLAN;
|
|
41981
|
+
let gauntlet = process.env.ZELARI_GAUNTLET === "1" || process.env.ZELARI_GAUNTLET === "true";
|
|
41982
|
+
for (let i = 0; i < argv.length; i++) {
|
|
41983
|
+
const arg = argv[i];
|
|
41984
|
+
if (arg === "--headless") continue;
|
|
41985
|
+
if (arg === "--output") {
|
|
41986
|
+
const next = argv[i + 1];
|
|
41987
|
+
if (next === "json" || next === "plain") {
|
|
41988
|
+
output = next;
|
|
41989
|
+
i++;
|
|
41990
|
+
} else {
|
|
41991
|
+
return {
|
|
41992
|
+
options: null,
|
|
41993
|
+
error: `--output requires 'json' or 'plain', got '${next ?? "(missing)"}'`
|
|
41994
|
+
};
|
|
41995
|
+
}
|
|
41996
|
+
} else if (arg === "--task") {
|
|
41997
|
+
task = argv[i + 1];
|
|
41998
|
+
i++;
|
|
41999
|
+
} else if (arg === "--task-file") {
|
|
42000
|
+
const next = argv[i + 1];
|
|
42001
|
+
if (next) {
|
|
42002
|
+
try {
|
|
42003
|
+
const fromFile = readFileSync22(next, "utf-8");
|
|
42004
|
+
if (fromFile.trim()) task = fromFile;
|
|
42005
|
+
} catch {
|
|
42006
|
+
}
|
|
42007
|
+
}
|
|
42008
|
+
i++;
|
|
42009
|
+
} else if (arg === "--council") {
|
|
42010
|
+
councilFlag = true;
|
|
42011
|
+
} else if (arg === "--mode") {
|
|
42012
|
+
const next = argv[i + 1];
|
|
42013
|
+
const parsed = next ? parseMode(next) : null;
|
|
42014
|
+
if (!parsed) {
|
|
42015
|
+
return {
|
|
42016
|
+
options: null,
|
|
42017
|
+
error: `--mode requires 'kraken', 'council', or 'zelari' (agent=alias), got '${next ?? "(missing)"}'`
|
|
42018
|
+
};
|
|
42019
|
+
}
|
|
42020
|
+
mode = parsed;
|
|
42021
|
+
modeExplicit = true;
|
|
42022
|
+
i++;
|
|
42023
|
+
} else if (arg === "--phase") {
|
|
42024
|
+
const next = argv[i + 1];
|
|
42025
|
+
const parsed = next ? parsePhase(next) : null;
|
|
42026
|
+
if (!parsed) {
|
|
42027
|
+
return {
|
|
42028
|
+
options: null,
|
|
42029
|
+
error: `--phase requires 'plan' or 'build', got '${next ?? "(missing)"}'`
|
|
42030
|
+
};
|
|
42031
|
+
}
|
|
42032
|
+
phase2 = parsed;
|
|
42033
|
+
i++;
|
|
42034
|
+
} else if (arg === "--provider") {
|
|
42035
|
+
provider = argv[i + 1];
|
|
42036
|
+
i++;
|
|
42037
|
+
} else if (arg === "--model") {
|
|
42038
|
+
model = argv[i + 1];
|
|
42039
|
+
i++;
|
|
42040
|
+
} else if (arg === "--history" || arg === "--history-file") {
|
|
42041
|
+
const next = argv[i + 1];
|
|
42042
|
+
if (next) {
|
|
42043
|
+
let raw = null;
|
|
42044
|
+
if (arg === "--history-file") {
|
|
42045
|
+
try {
|
|
42046
|
+
raw = readFileSync22(next, "utf-8");
|
|
42047
|
+
} catch {
|
|
42048
|
+
raw = null;
|
|
42049
|
+
}
|
|
42050
|
+
} else {
|
|
42051
|
+
raw = next;
|
|
42052
|
+
}
|
|
42053
|
+
if (raw) {
|
|
42054
|
+
try {
|
|
42055
|
+
const parsedHist = JSON.parse(raw);
|
|
42056
|
+
if (Array.isArray(parsedHist)) {
|
|
42057
|
+
history2 = parsedHist.filter(
|
|
42058
|
+
(m) => !!m && typeof m === "object" && typeof m.role === "string"
|
|
42059
|
+
).map((m) => {
|
|
42060
|
+
const role = String(m.role);
|
|
42061
|
+
const raw2 = m.content;
|
|
42062
|
+
const content = typeof raw2 === "string" ? raw2 : raw2 == null ? "" : typeof raw2 === "object" ? JSON.stringify(raw2) : String(raw2);
|
|
42063
|
+
const msg = {
|
|
42064
|
+
role,
|
|
42065
|
+
content
|
|
42066
|
+
};
|
|
42067
|
+
if (typeof m.toolCallId === "string") {
|
|
42068
|
+
msg.toolCallId = m.toolCallId;
|
|
42069
|
+
}
|
|
42070
|
+
return msg;
|
|
42071
|
+
}).filter(
|
|
42072
|
+
(m) => m.role === "user" || m.role === "assistant" || m.role === "tool" || m.role === "system"
|
|
42073
|
+
);
|
|
42074
|
+
}
|
|
42075
|
+
} catch {
|
|
42076
|
+
}
|
|
42077
|
+
}
|
|
42078
|
+
i++;
|
|
42079
|
+
}
|
|
42080
|
+
} else if (arg === "--todos") {
|
|
42081
|
+
const next = argv[i + 1];
|
|
42082
|
+
if (next) {
|
|
42083
|
+
try {
|
|
42084
|
+
const parsed = JSON.parse(next);
|
|
42085
|
+
if (Array.isArray(parsed)) {
|
|
42086
|
+
todos2 = parsed.filter(
|
|
42087
|
+
(t) => !!t && typeof t === "object" && typeof t.content === "string"
|
|
42088
|
+
).map((t) => ({
|
|
42089
|
+
id: typeof t.id === "string" ? t.id : void 0,
|
|
42090
|
+
content: String(t.content).slice(0, 500),
|
|
42091
|
+
status: t.status
|
|
42092
|
+
}));
|
|
42093
|
+
}
|
|
42094
|
+
} catch {
|
|
42095
|
+
}
|
|
42096
|
+
i++;
|
|
42097
|
+
}
|
|
42098
|
+
} else if (arg === "--once") {
|
|
42099
|
+
once = true;
|
|
42100
|
+
} else if (arg === "--profile") {
|
|
42101
|
+
const next = argv[i + 1];
|
|
42102
|
+
if (!next || next.startsWith("--")) {
|
|
42103
|
+
return { options: null, error: `--profile requires a profile id (e.g. kraken/v1), got '${next ?? "(missing)"}'` };
|
|
42104
|
+
}
|
|
42105
|
+
try {
|
|
42106
|
+
resolveProfile(next);
|
|
42107
|
+
} catch (err) {
|
|
42108
|
+
return {
|
|
42109
|
+
options: null,
|
|
42110
|
+
error: err instanceof Error ? err.message : String(err)
|
|
42111
|
+
};
|
|
42112
|
+
}
|
|
42113
|
+
profile = next;
|
|
42114
|
+
i++;
|
|
42115
|
+
} else if (arg === "--resume") {
|
|
42116
|
+
const next = argv[i + 1];
|
|
42117
|
+
if (!next || next.startsWith("--")) {
|
|
42118
|
+
return { options: null, error: `--resume requires a session id, got '${next ?? "(missing)"}'` };
|
|
42119
|
+
}
|
|
42120
|
+
resumeSessionId = next;
|
|
42121
|
+
i++;
|
|
42122
|
+
} else if (arg === "--export-session") {
|
|
42123
|
+
const next = argv[i + 1];
|
|
42124
|
+
if (!next || next.startsWith("--")) {
|
|
42125
|
+
return { options: null, error: `--export-session requires a path (or - for stdout), got '${next ?? "(missing)"}'` };
|
|
42126
|
+
}
|
|
42127
|
+
exportSessionPath = next;
|
|
42128
|
+
i++;
|
|
42129
|
+
} else if (arg === "--strict-done") {
|
|
42130
|
+
strictDone = true;
|
|
42131
|
+
} else if (arg === "--no-strict-done") {
|
|
42132
|
+
strictDone = false;
|
|
42133
|
+
process.env.ZELARI_MISSION_STRICT = "0";
|
|
42134
|
+
} else if (arg === "--kraken-graph") {
|
|
42135
|
+
krakenGraph = argv[i + 1];
|
|
42136
|
+
i++;
|
|
42137
|
+
} else if (arg === "--kraken-graph-file") {
|
|
42138
|
+
const next = argv[i + 1];
|
|
42139
|
+
if (next) {
|
|
42140
|
+
try {
|
|
42141
|
+
const fromFile = readFileSync22(next, "utf-8");
|
|
42142
|
+
if (fromFile.trim()) krakenGraph = fromFile;
|
|
42143
|
+
} catch {
|
|
42144
|
+
}
|
|
42145
|
+
}
|
|
42146
|
+
i++;
|
|
42147
|
+
} else if (arg === "--plan-only") {
|
|
42148
|
+
planOnly = true;
|
|
42149
|
+
} else if (arg === "--run-plan") {
|
|
42150
|
+
runPlan = argv[i + 1];
|
|
42151
|
+
i++;
|
|
42152
|
+
} else if (arg === "--gauntlet") {
|
|
42153
|
+
gauntlet = true;
|
|
42154
|
+
} else if (arg === "--no-gauntlet") {
|
|
42155
|
+
gauntlet = false;
|
|
42156
|
+
}
|
|
42157
|
+
}
|
|
42158
|
+
if (councilFlag && !modeExplicit) {
|
|
42159
|
+
mode = "council";
|
|
42160
|
+
} else if (councilFlag && modeExplicit && mode !== "council") {
|
|
42161
|
+
return {
|
|
42162
|
+
options: null,
|
|
42163
|
+
error: `--council conflicts with --mode ${mode}`
|
|
42164
|
+
};
|
|
42165
|
+
}
|
|
42166
|
+
if (task && krakenGraph) {
|
|
42167
|
+
return { options: null, error: "--task and --kraken-graph are mutually exclusive" };
|
|
42168
|
+
}
|
|
42169
|
+
if ((!task || task.trim().length === 0) && (!krakenGraph || krakenGraph.trim().length === 0)) {
|
|
42170
|
+
return { options: null, error: "--headless requires --task <prompt> or --kraken-graph <goal>" };
|
|
42171
|
+
}
|
|
42172
|
+
return {
|
|
42173
|
+
options: {
|
|
42174
|
+
task: task ?? "",
|
|
42175
|
+
output,
|
|
42176
|
+
mode,
|
|
42177
|
+
phase: phase2,
|
|
42178
|
+
useCouncil: mode === "council",
|
|
42179
|
+
provider,
|
|
42180
|
+
model,
|
|
42181
|
+
...history2 && history2.length > 0 ? { history: history2 } : {},
|
|
42182
|
+
...todos2 && todos2.length > 0 ? { todos: todos2 } : {},
|
|
42183
|
+
...once ? { once: true } : {},
|
|
42184
|
+
...profile ? { profile } : {},
|
|
42185
|
+
...resumeSessionId ? { resumeSessionId } : {},
|
|
42186
|
+
...exportSessionPath ? { exportSessionPath } : {},
|
|
42187
|
+
...strictDone ? { strictDone: true } : {},
|
|
42188
|
+
...krakenGraph ? { krakenGraph } : {},
|
|
42189
|
+
...planOnly ? { planOnly: true } : {},
|
|
42190
|
+
...runPlan ? { runPlan } : {},
|
|
42191
|
+
...gauntlet ? { gauntlet: true } : {}
|
|
42192
|
+
}
|
|
42193
|
+
};
|
|
42194
|
+
}
|
|
42195
|
+
async function resolveHeadlessKey(providerId) {
|
|
42196
|
+
const spec = PROVIDERS.find((p3) => p3.id === providerId);
|
|
42197
|
+
if (!spec) {
|
|
42198
|
+
return { error: `unknown provider: '${providerId}'` };
|
|
42199
|
+
}
|
|
42200
|
+
const resolved = await resolveApiKeyWithMeta(providerId);
|
|
42201
|
+
if (!resolved || !resolved.apiKey) {
|
|
42202
|
+
return {
|
|
42203
|
+
error: `no API key for provider '${providerId}'.
|
|
42204
|
+
Set the env var ${spec.envVar} or save a key via /login.`
|
|
42205
|
+
};
|
|
42206
|
+
}
|
|
42207
|
+
const { resolveBaseUrl: resolveBaseUrl2 } = await Promise.resolve().then(() => (init_openai_compatible(), openai_compatible_exports));
|
|
42208
|
+
return {
|
|
42209
|
+
apiKey: resolved.apiKey,
|
|
42210
|
+
baseUrl: resolveBaseUrl2(providerId)
|
|
42211
|
+
};
|
|
42212
|
+
}
|
|
42213
|
+
function resolveHeadlessProvider(opts) {
|
|
42214
|
+
const provider = opts.provider ?? getActiveProvider().id;
|
|
42215
|
+
const model = opts.model ?? getModelForProvider(provider);
|
|
42216
|
+
return { provider, model };
|
|
42217
|
+
}
|
|
42218
|
+
function emitEvent(event) {
|
|
42219
|
+
process.stdout.write(JSON.stringify(event) + "\n");
|
|
42220
|
+
}
|
|
42221
|
+
var init_headless = __esm({
|
|
42222
|
+
"src/cli/headless.ts"() {
|
|
42223
|
+
"use strict";
|
|
42224
|
+
init_keyStore();
|
|
42225
|
+
init_providerConfig();
|
|
42226
|
+
init_openai_compatible();
|
|
42227
|
+
init_phase();
|
|
42228
|
+
init_mode();
|
|
42229
|
+
init_runtime2();
|
|
42230
|
+
}
|
|
42231
|
+
});
|
|
42232
|
+
|
|
42233
|
+
// src/cli/headlessSpine.ts
|
|
42234
|
+
var headlessSpine_exports = {};
|
|
42235
|
+
__export(headlessSpine_exports, {
|
|
42236
|
+
derivedModelSeed: () => derivedModelSeed,
|
|
42237
|
+
exportSessionById: () => exportSessionById,
|
|
42238
|
+
missionStateFromSpine: () => missionStateFromSpine,
|
|
42239
|
+
openHeadlessSpine: () => openHeadlessSpine,
|
|
42240
|
+
resolveHeadlessProfileId: () => resolveHeadlessProfileId,
|
|
42241
|
+
seedHeadlessModelHistory: () => seedHeadlessModelHistory,
|
|
42242
|
+
sessionStartedEvent: () => sessionStartedEvent
|
|
42243
|
+
});
|
|
42244
|
+
function sessionStartedEvent(handle) {
|
|
42245
|
+
return {
|
|
42246
|
+
type: "session_started",
|
|
42247
|
+
sessionId: handle.sessionId,
|
|
42248
|
+
spine: handle.spine.status
|
|
42249
|
+
};
|
|
42250
|
+
}
|
|
42251
|
+
function resolveHeadlessProfileId(mode, explicit) {
|
|
42252
|
+
if (explicit) return resolveProfile(explicit).id;
|
|
42253
|
+
return defaultProfileForMode(mode ?? "kraken");
|
|
42254
|
+
}
|
|
42255
|
+
async function openHeadlessSpine(opts) {
|
|
42256
|
+
const profileId = resolveHeadlessProfileId(opts.mode, opts.profile);
|
|
42257
|
+
let profileTools = [];
|
|
42258
|
+
try {
|
|
42259
|
+
profileTools = resolveProfile(profileId).tools;
|
|
42260
|
+
} catch {
|
|
42261
|
+
profileTools = [];
|
|
42262
|
+
}
|
|
42263
|
+
const extra = {
|
|
42264
|
+
profile: profileId,
|
|
42265
|
+
workspace: opts.workspace ?? process.cwd(),
|
|
42266
|
+
toolManifestHash: profileTools.length > 0 ? toolManifestHash(profileTools) : void 0
|
|
42267
|
+
};
|
|
42268
|
+
const mirrorOpts = {
|
|
42269
|
+
baseDir: opts.baseDir,
|
|
42270
|
+
quiet: opts.quiet,
|
|
42271
|
+
extraStarted: extra
|
|
42272
|
+
};
|
|
42273
|
+
const spine = await SessionSpineMirror.adopt(opts.sessionId, mirrorOpts);
|
|
42274
|
+
if (spine.status === "active") {
|
|
42275
|
+
spine.note("headless.profile", { profile: profileId, mode: opts.mode ?? "kraken" });
|
|
42276
|
+
}
|
|
42277
|
+
return {
|
|
42278
|
+
sessionId: opts.sessionId,
|
|
42279
|
+
profileId,
|
|
42280
|
+
spine,
|
|
42281
|
+
observe(ev) {
|
|
42282
|
+
if (ev && typeof ev === "object" && "type" in ev) {
|
|
42283
|
+
spine.mirrorBrainEvent(ev);
|
|
42284
|
+
}
|
|
42285
|
+
},
|
|
42286
|
+
userMessage(text) {
|
|
42287
|
+
spine.userMessage(text);
|
|
42288
|
+
},
|
|
42289
|
+
verificationRun(payload) {
|
|
42290
|
+
spine.verificationRun(payload);
|
|
42291
|
+
},
|
|
42292
|
+
appendEvent(input) {
|
|
42293
|
+
return spine.appendEvent(input);
|
|
42294
|
+
},
|
|
42295
|
+
lastVerificationRun() {
|
|
42296
|
+
return spine.lastVerificationRun();
|
|
42297
|
+
},
|
|
42298
|
+
missionPhase(phase2, note) {
|
|
42299
|
+
spine.missionPhase(phase2, note);
|
|
42300
|
+
},
|
|
42301
|
+
missionProgress(advice) {
|
|
42302
|
+
spine.missionProgress(advice);
|
|
42303
|
+
},
|
|
42304
|
+
note(text, data) {
|
|
42305
|
+
spine.note(text, data);
|
|
42306
|
+
},
|
|
42307
|
+
async close(reason = "host-exit") {
|
|
42308
|
+
await spine.close(reason);
|
|
42309
|
+
},
|
|
42310
|
+
async interrupt(note) {
|
|
42311
|
+
if (note) spine.note("headless.interrupt", { note });
|
|
42312
|
+
await spine.release();
|
|
42313
|
+
},
|
|
42314
|
+
async exportJson() {
|
|
42315
|
+
try {
|
|
42316
|
+
const store6 = new SessionStore(resolveSessionsDir({ baseDir: opts.baseDir }));
|
|
42317
|
+
if (!await store6.exists(opts.sessionId)) return null;
|
|
42318
|
+
return await exportSessionJson(store6, opts.sessionId);
|
|
42319
|
+
} catch {
|
|
42320
|
+
return null;
|
|
42321
|
+
}
|
|
42322
|
+
}
|
|
42323
|
+
};
|
|
42324
|
+
}
|
|
42325
|
+
async function exportSessionById(sessionId2, baseDir) {
|
|
42326
|
+
try {
|
|
42327
|
+
const store6 = SessionStore.withDefaults(baseDir ? { baseDir } : {});
|
|
42328
|
+
if (!await store6.exists(sessionId2)) {
|
|
42329
|
+
return { ok: false, error: `session not found: ${sessionId2}` };
|
|
42330
|
+
}
|
|
42331
|
+
return { ok: true, json: await exportSessionJson(store6, sessionId2) };
|
|
42332
|
+
} catch (err) {
|
|
42333
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
42334
|
+
}
|
|
42335
|
+
}
|
|
42336
|
+
async function missionStateFromSpine(sessionId2, baseDir) {
|
|
42337
|
+
try {
|
|
42338
|
+
const store6 = SessionStore.withDefaults(baseDir ? { baseDir } : {});
|
|
42339
|
+
if (!await store6.exists(sessionId2)) return null;
|
|
42340
|
+
const projection = await store6.projection(sessionId2);
|
|
42341
|
+
return deriveMissionState(projection);
|
|
42342
|
+
} catch {
|
|
42343
|
+
return null;
|
|
42344
|
+
}
|
|
42345
|
+
}
|
|
42346
|
+
async function seedHeadlessModelHistory(handle, legacy) {
|
|
42347
|
+
const mirror = handle.spine;
|
|
42348
|
+
const legacySeed = filterLegacySeed(legacy);
|
|
42349
|
+
if (mirror.status !== "active") {
|
|
42350
|
+
return { history: legacySeed, importedCount: 0, source: "legacy-fallback" };
|
|
42351
|
+
}
|
|
42352
|
+
const existing = await mirror.derivedPriorTurns();
|
|
42353
|
+
if (existing && existing.length > 0) {
|
|
42354
|
+
return { history: derivedModelSeed(existing), importedCount: 0, source: "spine" };
|
|
42355
|
+
}
|
|
42356
|
+
if (legacySeed.length === 0) {
|
|
42357
|
+
return { history: [], importedCount: 0, source: "spine" };
|
|
42358
|
+
}
|
|
42359
|
+
for (const m of legacySeed) {
|
|
42360
|
+
if (m.role === "user") {
|
|
42361
|
+
mirror.userMessage(m.content);
|
|
42362
|
+
} else {
|
|
42363
|
+
mirror.assistantMessage(m.content, { imported: "legacy-history" });
|
|
42364
|
+
}
|
|
42365
|
+
}
|
|
42366
|
+
await mirror.flush();
|
|
42367
|
+
const derived = await mirror.derivedPriorTurns() ?? [];
|
|
42368
|
+
return {
|
|
42369
|
+
history: derivedModelSeed(derived),
|
|
42370
|
+
importedCount: legacySeed.length,
|
|
42371
|
+
source: "spine-import"
|
|
42372
|
+
};
|
|
42373
|
+
}
|
|
42374
|
+
function filterLegacySeed(legacy) {
|
|
42375
|
+
return (legacy ?? []).filter((m) => m.role === "user" || m.role === "assistant").map(
|
|
42376
|
+
(m) => m.role === "assistant" && m.content ? {
|
|
42377
|
+
role: "assistant",
|
|
42378
|
+
content: cleanAgentContent(m.content, {
|
|
42379
|
+
stripQuestion: false,
|
|
42380
|
+
stripThink: false
|
|
42381
|
+
})
|
|
42382
|
+
} : { role: m.role, content: m.content ?? "" }
|
|
42383
|
+
).filter((m) => (m.content ?? "").trim().length > 0);
|
|
42384
|
+
}
|
|
42385
|
+
function derivedModelSeed(derived) {
|
|
42386
|
+
return derivedToAgentMessages(derived).map(
|
|
42387
|
+
(m) => m.role === "system" ? { ...m, role: "user" } : m
|
|
42388
|
+
).map(
|
|
42389
|
+
(m) => m.role === "assistant" && m.content ? {
|
|
42390
|
+
...m,
|
|
42391
|
+
content: cleanAgentContent(m.content, {
|
|
42392
|
+
stripQuestion: false,
|
|
42393
|
+
stripThink: false
|
|
42394
|
+
}),
|
|
42395
|
+
...m.seq !== void 0 ? { seq: m.seq } : {}
|
|
42396
|
+
} : m
|
|
42397
|
+
).filter((m) => m.role === "user" || m.role === "assistant").filter((m) => (m.content ?? "").trim().length > 0);
|
|
42398
|
+
}
|
|
42399
|
+
var init_headlessSpine = __esm({
|
|
42400
|
+
"src/cli/headlessSpine.ts"() {
|
|
42401
|
+
"use strict";
|
|
42402
|
+
init_dist();
|
|
42403
|
+
init_session();
|
|
42404
|
+
init_mission2();
|
|
42405
|
+
init_runtime2();
|
|
42406
|
+
init_sessionSpine();
|
|
42407
|
+
init_headless();
|
|
42408
|
+
}
|
|
42409
|
+
});
|
|
42410
|
+
|
|
41848
42411
|
// src/cli/provider/localCli/claudeStreamJson.ts
|
|
41849
42412
|
function textBlock(text) {
|
|
41850
42413
|
return { type: "text", text };
|
|
@@ -41985,10 +42548,10 @@ __export(claudeProvider_exports, {
|
|
|
41985
42548
|
createLocalCliProvider: () => createLocalCliProvider
|
|
41986
42549
|
});
|
|
41987
42550
|
import { spawn as spawn11 } from "node:child_process";
|
|
41988
|
-
function waitForExit(child,
|
|
42551
|
+
function waitForExit(child, timeoutMs2 = 2e3) {
|
|
41989
42552
|
return new Promise((resolve3) => {
|
|
41990
42553
|
if (child.exitCode != null) return resolve3(child.exitCode);
|
|
41991
|
-
const timer = setTimeout(() => resolve3(child.exitCode ?? null),
|
|
42554
|
+
const timer = setTimeout(() => resolve3(child.exitCode ?? null), timeoutMs2);
|
|
41992
42555
|
timer.unref?.();
|
|
41993
42556
|
child.once("exit", (code) => {
|
|
41994
42557
|
clearTimeout(timer);
|
|
@@ -43559,10 +44122,10 @@ function distTagForVersion(version2) {
|
|
|
43559
44122
|
function registryUrlForTag(tag = distTagForVersion(getCurrentVersion())) {
|
|
43560
44123
|
return `https://registry.npmjs.org/zelari-code/${tag}`;
|
|
43561
44124
|
}
|
|
43562
|
-
async function fetchLatestVersion(fetcher = fetch, registryUrl = REGISTRY_URL,
|
|
44125
|
+
async function fetchLatestVersion(fetcher = fetch, registryUrl = REGISTRY_URL, timeoutMs2 = 5e3) {
|
|
43563
44126
|
try {
|
|
43564
44127
|
const controller = new AbortController();
|
|
43565
|
-
const timer = setTimeout(() => controller.abort(),
|
|
44128
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs2);
|
|
43566
44129
|
const response = await fetcher(registryUrl, { signal: controller.signal });
|
|
43567
44130
|
clearTimeout(timer);
|
|
43568
44131
|
if (!response.ok) {
|
|
@@ -43732,11 +44295,11 @@ var init_mcpClient = __esm({
|
|
|
43732
44295
|
* Call a tool. Returns the concatenated text content; non-text content
|
|
43733
44296
|
* items are summarized by type. Throws when the server flags isError.
|
|
43734
44297
|
*/
|
|
43735
|
-
async callTool(name, args,
|
|
44298
|
+
async callTool(name, args, timeoutMs2 = DEFAULT_REQUEST_TIMEOUT_MS) {
|
|
43736
44299
|
const res = await this.request(
|
|
43737
44300
|
"tools/call",
|
|
43738
44301
|
{ name, arguments: args },
|
|
43739
|
-
|
|
44302
|
+
timeoutMs2
|
|
43740
44303
|
);
|
|
43741
44304
|
const text = (res.content ?? []).map(
|
|
43742
44305
|
(c) => c.type === "text" && typeof c.text === "string" ? c.text : `[${c.type ?? "unknown"} content]`
|
|
@@ -43753,7 +44316,7 @@ var init_mcpClient = __esm({
|
|
|
43753
44316
|
this.child = null;
|
|
43754
44317
|
}
|
|
43755
44318
|
// ── JSON-RPC plumbing ────────────────────────────────────────────────
|
|
43756
|
-
request(method, params,
|
|
44319
|
+
request(method, params, timeoutMs2 = DEFAULT_REQUEST_TIMEOUT_MS) {
|
|
43757
44320
|
const child = this.child;
|
|
43758
44321
|
if (!child)
|
|
43759
44322
|
return Promise.reject(new Error(`[mcp:${this.serverName}] not started`));
|
|
@@ -43764,10 +44327,10 @@ var init_mcpClient = __esm({
|
|
|
43764
44327
|
this.pending.delete(id);
|
|
43765
44328
|
reject(
|
|
43766
44329
|
new Error(
|
|
43767
|
-
`[mcp:${this.serverName}] ${method} timed out after ${
|
|
44330
|
+
`[mcp:${this.serverName}] ${method} timed out after ${timeoutMs2}ms`
|
|
43768
44331
|
)
|
|
43769
44332
|
);
|
|
43770
|
-
},
|
|
44333
|
+
}, timeoutMs2);
|
|
43771
44334
|
this.pending.set(id, { resolve: resolve3, reject, timer });
|
|
43772
44335
|
child.stdin.write(payload + "\n", (err) => {
|
|
43773
44336
|
if (err) {
|
|
@@ -44841,7 +45404,7 @@ function pickSmokeScript(scripts) {
|
|
|
44841
45404
|
}
|
|
44842
45405
|
return null;
|
|
44843
45406
|
}
|
|
44844
|
-
async function runProjectSmoke(projectRoot,
|
|
45407
|
+
async function runProjectSmoke(projectRoot, timeoutMs2 = DEFAULT_TIMEOUT_MS3) {
|
|
44845
45408
|
if (process.env["ZELARI_SMOKE"] === "0") {
|
|
44846
45409
|
return { ran: false, reason: "ZELARI_SMOKE=0 (disabled)" };
|
|
44847
45410
|
}
|
|
@@ -44874,7 +45437,7 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS3) {
|
|
|
44874
45437
|
let stdout = "";
|
|
44875
45438
|
let stderr = "";
|
|
44876
45439
|
let settled = false;
|
|
44877
|
-
const
|
|
45440
|
+
const finish2 = (result) => {
|
|
44878
45441
|
if (settled) return;
|
|
44879
45442
|
settled = true;
|
|
44880
45443
|
clearTimeout(timer);
|
|
@@ -44882,15 +45445,15 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS3) {
|
|
|
44882
45445
|
};
|
|
44883
45446
|
const timer = setTimeout(() => {
|
|
44884
45447
|
child.kill("SIGTERM");
|
|
44885
|
-
|
|
45448
|
+
finish2({
|
|
44886
45449
|
ran: true,
|
|
44887
45450
|
ok: false,
|
|
44888
45451
|
script,
|
|
44889
45452
|
exitCode: -1,
|
|
44890
45453
|
output: stdout + stderr,
|
|
44891
|
-
reason: `smoke timeout after ${
|
|
45454
|
+
reason: `smoke timeout after ${timeoutMs2}ms`
|
|
44892
45455
|
});
|
|
44893
|
-
},
|
|
45456
|
+
}, timeoutMs2);
|
|
44894
45457
|
child.stdout?.on("data", (chunk) => {
|
|
44895
45458
|
stdout += chunk.toString("utf8");
|
|
44896
45459
|
});
|
|
@@ -44898,7 +45461,7 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS3) {
|
|
|
44898
45461
|
stderr += chunk.toString("utf8");
|
|
44899
45462
|
});
|
|
44900
45463
|
child.on("error", (err) => {
|
|
44901
|
-
|
|
45464
|
+
finish2({
|
|
44902
45465
|
ran: true,
|
|
44903
45466
|
ok: false,
|
|
44904
45467
|
script,
|
|
@@ -44910,7 +45473,7 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS3) {
|
|
|
44910
45473
|
child.on("close", (code) => {
|
|
44911
45474
|
const exitCode = code ?? -1;
|
|
44912
45475
|
const ok = exitCode === 0;
|
|
44913
|
-
|
|
45476
|
+
finish2({
|
|
44914
45477
|
ran: true,
|
|
44915
45478
|
ok,
|
|
44916
45479
|
script,
|
|
@@ -46519,7 +47082,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
46519
47082
|
const closeAll = server.closeAllConnections;
|
|
46520
47083
|
if (typeof closeAll === "function") closeAll.call(server);
|
|
46521
47084
|
let done = false;
|
|
46522
|
-
const
|
|
47085
|
+
const finish2 = () => {
|
|
46523
47086
|
if (done) return;
|
|
46524
47087
|
done = true;
|
|
46525
47088
|
if (process.platform !== "win32") {
|
|
@@ -46528,8 +47091,8 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
46528
47091
|
res();
|
|
46529
47092
|
}
|
|
46530
47093
|
};
|
|
46531
|
-
server.close(() =>
|
|
46532
|
-
setTimeout(
|
|
47094
|
+
server.close(() => finish2());
|
|
47095
|
+
setTimeout(finish2, 1e3).unref?.();
|
|
46533
47096
|
})
|
|
46534
47097
|
});
|
|
46535
47098
|
});
|
|
@@ -46966,13 +47529,13 @@ async function createDefaultLlmClient(opts) {
|
|
|
46966
47529
|
const llm = await resolveLlm(opts);
|
|
46967
47530
|
return {
|
|
46968
47531
|
async complete({ system, user }) {
|
|
46969
|
-
const
|
|
47532
|
+
const timeoutMs2 = resolvePlannerTimeoutMs();
|
|
46970
47533
|
const controller = new AbortController();
|
|
46971
47534
|
let timedOut = false;
|
|
46972
|
-
const t =
|
|
47535
|
+
const t = timeoutMs2 > 0 ? setTimeout(() => {
|
|
46973
47536
|
timedOut = true;
|
|
46974
47537
|
controller.abort();
|
|
46975
|
-
},
|
|
47538
|
+
}, timeoutMs2) : void 0;
|
|
46976
47539
|
try {
|
|
46977
47540
|
const url2 = `${llm.baseUrl.replace(/\/$/, "")}/chat/completions`;
|
|
46978
47541
|
let res;
|
|
@@ -46998,7 +47561,7 @@ async function createDefaultLlmClient(opts) {
|
|
|
46998
47561
|
} catch (err) {
|
|
46999
47562
|
if (timedOut) {
|
|
47000
47563
|
throw new PlannerTransportError(
|
|
47001
|
-
`Planner request timed out after ${Math.round(
|
|
47564
|
+
`Planner request timed out after ${Math.round(timeoutMs2 / 1e3)}s (no response). Raise ZELARI_KRAKEN_PLANNER_TIMEOUT_MS, or set ZELARI_KRAKEN_PLANNER_MODEL to a faster non-reasoning model.`
|
|
47002
47565
|
);
|
|
47003
47566
|
}
|
|
47004
47567
|
throw new PlannerTransportError(
|
|
@@ -49381,10 +49944,10 @@ async function validateApiKey(providerId, apiKey, options = {}) {
|
|
|
49381
49944
|
return { ok: true, skipped: true, reason: "no_base_url" };
|
|
49382
49945
|
}
|
|
49383
49946
|
const probeUrl = options.probeUrl ?? `${spec.baseUrl.replace(/\/+$/, "")}/models`;
|
|
49384
|
-
const
|
|
49947
|
+
const timeoutMs2 = options.timeoutMs ?? 5e3;
|
|
49385
49948
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
49386
49949
|
const controller = new AbortController();
|
|
49387
|
-
const timer = setTimeout(() => controller.abort(),
|
|
49950
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs2);
|
|
49388
49951
|
try {
|
|
49389
49952
|
const response = await fetchImpl(probeUrl, {
|
|
49390
49953
|
method: "GET",
|
|
@@ -49413,7 +49976,7 @@ async function validateApiKey(providerId, apiKey, options = {}) {
|
|
|
49413
49976
|
return {
|
|
49414
49977
|
ok: false,
|
|
49415
49978
|
reason: isAbort ? "network" : "network",
|
|
49416
|
-
detail: isAbort ? `timeout after ${
|
|
49979
|
+
detail: isAbort ? `timeout after ${timeoutMs2}ms` : msg,
|
|
49417
49980
|
durationMs
|
|
49418
49981
|
};
|
|
49419
49982
|
} finally {
|
|
@@ -50182,6 +50745,864 @@ var init_atMentions = __esm({
|
|
|
50182
50745
|
}
|
|
50183
50746
|
});
|
|
50184
50747
|
|
|
50748
|
+
// src/cli/gauntlet/policy.ts
|
|
50749
|
+
var policy_exports = {};
|
|
50750
|
+
__export(policy_exports, {
|
|
50751
|
+
DEFAULT_MAX_PARALLEL: () => DEFAULT_MAX_PARALLEL2,
|
|
50752
|
+
DEFAULT_MAX_PIECES: () => DEFAULT_MAX_PIECES,
|
|
50753
|
+
DEFAULT_MAX_ROUNDS: () => DEFAULT_MAX_ROUNDS,
|
|
50754
|
+
DEFAULT_WALL_MS: () => DEFAULT_WALL_MS,
|
|
50755
|
+
GAUNTLET_PARENT_BLOCKED_TOOLS: () => GAUNTLET_PARENT_BLOCKED_TOOLS,
|
|
50756
|
+
isGauntletFlagOn: () => isGauntletFlagOn,
|
|
50757
|
+
resolveGauntletCaps: () => resolveGauntletCaps,
|
|
50758
|
+
shouldRunGauntletHostLoop: () => shouldRunGauntletHostLoop
|
|
50759
|
+
});
|
|
50760
|
+
function envInt(raw, fallback, min, max) {
|
|
50761
|
+
if (raw === void 0 || raw === "") return fallback;
|
|
50762
|
+
const n = Number.parseInt(raw, 10);
|
|
50763
|
+
if (!Number.isFinite(n)) return fallback;
|
|
50764
|
+
return Math.min(max, Math.max(min, n));
|
|
50765
|
+
}
|
|
50766
|
+
function isGauntletFlagOn(explicit, env = process.env) {
|
|
50767
|
+
if (explicit === true) return true;
|
|
50768
|
+
if (explicit === false) return false;
|
|
50769
|
+
const raw = env.ZELARI_GAUNTLET;
|
|
50770
|
+
if (!raw) return false;
|
|
50771
|
+
return raw === "1" || raw.toLowerCase() === "true";
|
|
50772
|
+
}
|
|
50773
|
+
function resolveGauntletCaps(env = process.env) {
|
|
50774
|
+
const wallRaw = env.ZELARI_GAUNTLET_WALL_MS;
|
|
50775
|
+
let wallClockMs = DEFAULT_WALL_MS;
|
|
50776
|
+
if (wallRaw !== void 0 && wallRaw !== "") {
|
|
50777
|
+
const n = Number.parseInt(wallRaw, 10);
|
|
50778
|
+
if (Number.isFinite(n) && n >= 0) wallClockMs = n;
|
|
50779
|
+
}
|
|
50780
|
+
return {
|
|
50781
|
+
maxPieces: envInt(env.ZELARI_GAUNTLET_MAX_PIECES, DEFAULT_MAX_PIECES, 1, 16),
|
|
50782
|
+
maxRounds: envInt(env.ZELARI_GAUNTLET_MAX_ROUNDS, DEFAULT_MAX_ROUNDS, 1, 8),
|
|
50783
|
+
maxParallel: envInt(env.ZELARI_GAUNTLET_MAX_PARALLEL, DEFAULT_MAX_PARALLEL2, 1, 4),
|
|
50784
|
+
wallClockMs
|
|
50785
|
+
};
|
|
50786
|
+
}
|
|
50787
|
+
function shouldRunGauntletHostLoop(opts) {
|
|
50788
|
+
if (!isGauntletFlagOn(opts.gauntlet)) return false;
|
|
50789
|
+
if (opts.krakenGraph) return false;
|
|
50790
|
+
if (opts.useCouncil || opts.mode === "council" || opts.mode === "zelari") return false;
|
|
50791
|
+
const phase2 = opts.phase ?? "build";
|
|
50792
|
+
return phase2 !== "plan";
|
|
50793
|
+
}
|
|
50794
|
+
var DEFAULT_MAX_PIECES, DEFAULT_MAX_ROUNDS, DEFAULT_MAX_PARALLEL2, DEFAULT_WALL_MS, GAUNTLET_PARENT_BLOCKED_TOOLS;
|
|
50795
|
+
var init_policy = __esm({
|
|
50796
|
+
"src/cli/gauntlet/policy.ts"() {
|
|
50797
|
+
"use strict";
|
|
50798
|
+
DEFAULT_MAX_PIECES = 6;
|
|
50799
|
+
DEFAULT_MAX_ROUNDS = 3;
|
|
50800
|
+
DEFAULT_MAX_PARALLEL2 = 2;
|
|
50801
|
+
DEFAULT_WALL_MS = 45 * 60 * 1e3;
|
|
50802
|
+
GAUNTLET_PARENT_BLOCKED_TOOLS = [
|
|
50803
|
+
"write_file",
|
|
50804
|
+
"edit_file",
|
|
50805
|
+
"apply_diff",
|
|
50806
|
+
"bash"
|
|
50807
|
+
];
|
|
50808
|
+
}
|
|
50809
|
+
});
|
|
50810
|
+
|
|
50811
|
+
// src/cli/gauntlet/complete.ts
|
|
50812
|
+
function timeoutMs(env = process.env) {
|
|
50813
|
+
const raw = env.ZELARI_GAUNTLET_DECOMPOSE_TIMEOUT_MS;
|
|
50814
|
+
if (raw === void 0 || raw === "") return DEFAULT_TIMEOUT_MS4;
|
|
50815
|
+
const n = Number.parseInt(raw, 10);
|
|
50816
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_TIMEOUT_MS4;
|
|
50817
|
+
}
|
|
50818
|
+
async function gauntletComplete(args, opts) {
|
|
50819
|
+
const provider = opts.provider;
|
|
50820
|
+
const meta3 = await resolveApiKeyWithMeta(provider);
|
|
50821
|
+
if (!meta3?.apiKey) {
|
|
50822
|
+
throw new Error(`No API key for provider '${provider}'`);
|
|
50823
|
+
}
|
|
50824
|
+
const baseUrl = resolveBaseUrl(provider);
|
|
50825
|
+
if (!baseUrl) {
|
|
50826
|
+
throw new Error(`No base URL for provider '${provider}'`);
|
|
50827
|
+
}
|
|
50828
|
+
const model = process.env.ZELARI_KRAKEN_PLANNER_MODEL?.trim() || opts.model || getModelForProvider(provider) || getProviderConfig().modelByProvider[provider] || "";
|
|
50829
|
+
if (!model) throw new Error(`No model for provider '${provider}'`);
|
|
50830
|
+
const ms = timeoutMs();
|
|
50831
|
+
const controller = new AbortController();
|
|
50832
|
+
const onParentAbort = () => controller.abort();
|
|
50833
|
+
opts.signal?.addEventListener("abort", onParentAbort, { once: true });
|
|
50834
|
+
let timedOut = false;
|
|
50835
|
+
const timer = ms > 0 ? setTimeout(() => {
|
|
50836
|
+
timedOut = true;
|
|
50837
|
+
controller.abort();
|
|
50838
|
+
}, ms) : void 0;
|
|
50839
|
+
try {
|
|
50840
|
+
const url2 = `${baseUrl.replace(/\/$/, "")}/chat/completions`;
|
|
50841
|
+
const res = await fetch(url2, {
|
|
50842
|
+
method: "POST",
|
|
50843
|
+
signal: controller.signal,
|
|
50844
|
+
headers: {
|
|
50845
|
+
"content-type": "application/json",
|
|
50846
|
+
authorization: `Bearer ${meta3.apiKey}`
|
|
50847
|
+
},
|
|
50848
|
+
body: JSON.stringify({
|
|
50849
|
+
model,
|
|
50850
|
+
temperature: 0.2,
|
|
50851
|
+
max_tokens: DEFAULT_MAX_TOKENS,
|
|
50852
|
+
stream: false,
|
|
50853
|
+
messages: [
|
|
50854
|
+
{ role: "system", content: args.system },
|
|
50855
|
+
{ role: "user", content: args.user }
|
|
50856
|
+
]
|
|
50857
|
+
})
|
|
50858
|
+
});
|
|
50859
|
+
if (!res.ok) {
|
|
50860
|
+
const errBody = await res.text().catch(() => "");
|
|
50861
|
+
throw new Error(`decompose HTTP ${res.status}${errBody ? `: ${errBody.slice(0, 160)}` : ""}`);
|
|
50862
|
+
}
|
|
50863
|
+
const json2 = await res.json();
|
|
50864
|
+
const msg = json2.choices?.[0]?.message;
|
|
50865
|
+
const text = msg?.content?.trim() || msg?.reasoning_content?.trim() || "";
|
|
50866
|
+
if (!text) throw new Error("decompose: empty model response");
|
|
50867
|
+
return text;
|
|
50868
|
+
} catch (err) {
|
|
50869
|
+
if (timedOut) {
|
|
50870
|
+
throw new Error(
|
|
50871
|
+
`decompose timed out after ${Math.round(ms / 1e3)}s \u2014 using a single piece. Raise ZELARI_GAUNTLET_DECOMPOSE_TIMEOUT_MS or set ZELARI_KRAKEN_PLANNER_MODEL to a fast model.`
|
|
50872
|
+
);
|
|
50873
|
+
}
|
|
50874
|
+
throw err instanceof Error ? err : new Error(String(err));
|
|
50875
|
+
} finally {
|
|
50876
|
+
if (timer) clearTimeout(timer);
|
|
50877
|
+
opts.signal?.removeEventListener("abort", onParentAbort);
|
|
50878
|
+
}
|
|
50879
|
+
}
|
|
50880
|
+
var DEFAULT_TIMEOUT_MS4, DEFAULT_MAX_TOKENS;
|
|
50881
|
+
var init_complete = __esm({
|
|
50882
|
+
"src/cli/gauntlet/complete.ts"() {
|
|
50883
|
+
"use strict";
|
|
50884
|
+
init_providerConfig();
|
|
50885
|
+
init_keyStore();
|
|
50886
|
+
init_openai_compatible();
|
|
50887
|
+
DEFAULT_TIMEOUT_MS4 = 6e4;
|
|
50888
|
+
DEFAULT_MAX_TOKENS = 2048;
|
|
50889
|
+
}
|
|
50890
|
+
});
|
|
50891
|
+
|
|
50892
|
+
// src/cli/gauntlet/decompose.ts
|
|
50893
|
+
function fallbackPieces(goal) {
|
|
50894
|
+
const prompt = goal.trim() || "Complete the user Goal.";
|
|
50895
|
+
return [
|
|
50896
|
+
{
|
|
50897
|
+
id: "g1",
|
|
50898
|
+
label: labelFromGoal(prompt),
|
|
50899
|
+
prompt,
|
|
50900
|
+
acceptance: []
|
|
50901
|
+
}
|
|
50902
|
+
];
|
|
50903
|
+
}
|
|
50904
|
+
function labelFromGoal(goal) {
|
|
50905
|
+
const line = goal.trim().split(/\r?\n/, 1)[0] ?? "Goal";
|
|
50906
|
+
return line.slice(0, MAX_LABEL) || "Goal";
|
|
50907
|
+
}
|
|
50908
|
+
function parsePiecesJson(raw, maxPieces) {
|
|
50909
|
+
if (!raw || typeof raw !== "object") return null;
|
|
50910
|
+
const rec = raw;
|
|
50911
|
+
const list = rec.pieces ?? rec.nodes;
|
|
50912
|
+
if (!Array.isArray(list) || list.length === 0) return null;
|
|
50913
|
+
const out = [];
|
|
50914
|
+
for (let i = 0; i < list.length && out.length < maxPieces; i++) {
|
|
50915
|
+
const item = list[i];
|
|
50916
|
+
if (!item || typeof item !== "object") continue;
|
|
50917
|
+
const row = item;
|
|
50918
|
+
const prompt = typeof row.prompt === "string" ? row.prompt.trim() : typeof row.goal === "string" ? row.goal.trim() : "";
|
|
50919
|
+
if (!prompt) continue;
|
|
50920
|
+
const id = typeof row.id === "string" && row.id.trim() ? row.id.trim().slice(0, 32) : `g${out.length + 1}`;
|
|
50921
|
+
const label = typeof row.label === "string" && row.label.trim() ? row.label.trim().slice(0, MAX_LABEL) : labelFromGoal(prompt);
|
|
50922
|
+
const acceptance = Array.isArray(row.acceptance) ? row.acceptance.filter((a) => typeof a === "string" && a.trim().length > 0).map((a) => a.trim()).slice(0, MAX_ACCEPTANCE) : [];
|
|
50923
|
+
const scope = Array.isArray(row.scope) ? row.scope.filter((s) => typeof s === "string" && s.trim().length > 0).map((s) => s.trim()).slice(0, 16) : void 0;
|
|
50924
|
+
const bar = Array.isArray(row.bar) ? row.bar.filter((s) => typeof s === "string" && s.trim().length > 0).map((s) => s.trim()).slice(0, 4) : void 0;
|
|
50925
|
+
out.push({
|
|
50926
|
+
id: uniqueId2(id, out),
|
|
50927
|
+
label,
|
|
50928
|
+
prompt: prompt.slice(0, MAX_PROMPT),
|
|
50929
|
+
acceptance,
|
|
50930
|
+
...scope && scope.length > 0 ? { scope } : {},
|
|
50931
|
+
...bar && bar.length > 0 ? { bar } : {}
|
|
50932
|
+
});
|
|
50933
|
+
}
|
|
50934
|
+
return out.length > 0 ? out : null;
|
|
50935
|
+
}
|
|
50936
|
+
function formatHistoryNote(messages, maxMessages = 4, each = 400) {
|
|
50937
|
+
const slice = messages.filter((m) => m.role === "user" || m.role === "assistant").slice(-maxMessages);
|
|
50938
|
+
if (slice.length === 0) return "";
|
|
50939
|
+
return slice.map((m) => {
|
|
50940
|
+
const body = m.content.replace(/\s+/g, " ").trim().slice(0, each);
|
|
50941
|
+
return `${m.role}: ${body}`;
|
|
50942
|
+
}).join("\n");
|
|
50943
|
+
}
|
|
50944
|
+
function buildDecomposeUser(opts) {
|
|
50945
|
+
const parts = [
|
|
50946
|
+
`Max pieces: ${opts.maxPieces}`,
|
|
50947
|
+
"",
|
|
50948
|
+
"## Goal",
|
|
50949
|
+
opts.goal.trim() || "(empty)"
|
|
50950
|
+
];
|
|
50951
|
+
if (opts.historyNote?.trim()) {
|
|
50952
|
+
parts.push("", "## Prior turns (context only \u2014 the Goal above is authoritative)", opts.historyNote.trim());
|
|
50953
|
+
}
|
|
50954
|
+
if (opts.workspace?.trim()) {
|
|
50955
|
+
parts.push("", "## Workspace", opts.workspace.trim());
|
|
50956
|
+
}
|
|
50957
|
+
return parts.join("\n");
|
|
50958
|
+
}
|
|
50959
|
+
function piecesFromModelText(text, maxPieces) {
|
|
50960
|
+
try {
|
|
50961
|
+
const json2 = extractJsonObject(text, { requireKey: "pieces" });
|
|
50962
|
+
return parsePiecesJson(json2, maxPieces);
|
|
50963
|
+
} catch {
|
|
50964
|
+
return null;
|
|
50965
|
+
}
|
|
50966
|
+
}
|
|
50967
|
+
async function decomposeGoal(opts) {
|
|
50968
|
+
const fallback = fallbackPieces(opts.goal);
|
|
50969
|
+
if (!opts.complete) return { pieces: fallback, source: "fallback" };
|
|
50970
|
+
try {
|
|
50971
|
+
const text = await opts.complete({
|
|
50972
|
+
system: GAUNTLET_DECOMPOSE_SYSTEM,
|
|
50973
|
+
user: buildDecomposeUser(opts)
|
|
50974
|
+
});
|
|
50975
|
+
const parsed = piecesFromModelText(text, opts.maxPieces);
|
|
50976
|
+
if (parsed && parsed.length > 0) return { pieces: parsed, source: "llm" };
|
|
50977
|
+
return { pieces: fallback, source: "fallback", error: "decompose JSON unusable" };
|
|
50978
|
+
} catch (err) {
|
|
50979
|
+
return {
|
|
50980
|
+
pieces: fallback,
|
|
50981
|
+
source: "fallback",
|
|
50982
|
+
error: err instanceof Error ? err.message : String(err)
|
|
50983
|
+
};
|
|
50984
|
+
}
|
|
50985
|
+
}
|
|
50986
|
+
function uniqueId2(id, existing) {
|
|
50987
|
+
if (!existing.some((p3) => p3.id === id)) return id;
|
|
50988
|
+
let n = 2;
|
|
50989
|
+
while (existing.some((p3) => p3.id === `${id}-${n}`)) n += 1;
|
|
50990
|
+
return `${id}-${n}`;
|
|
50991
|
+
}
|
|
50992
|
+
var MAX_LABEL, MAX_PROMPT, MAX_ACCEPTANCE, GAUNTLET_DECOMPOSE_SYSTEM;
|
|
50993
|
+
var init_decompose = __esm({
|
|
50994
|
+
"src/cli/gauntlet/decompose.ts"() {
|
|
50995
|
+
"use strict";
|
|
50996
|
+
init_planner();
|
|
50997
|
+
MAX_LABEL = 80;
|
|
50998
|
+
MAX_PROMPT = 8e3;
|
|
50999
|
+
MAX_ACCEPTANCE = 8;
|
|
51000
|
+
GAUNTLET_DECOMPOSE_SYSTEM = [
|
|
51001
|
+
"Decompose the user Goal into independently shippable Gauntlet pieces.",
|
|
51002
|
+
"Return ONLY JSON (no markdown, no prose):",
|
|
51003
|
+
'{ "pieces": [ { "id": string, "label": string, "prompt": string, "scope"?: string[], "acceptance"?: string[], "bar"?: string[] } ] }',
|
|
51004
|
+
"Rules:",
|
|
51005
|
+
"- 1 to N pieces (N is given in the user message). Prefer fewer. One piece is valid when the goal is atomic.",
|
|
51006
|
+
'- "prompt" is self-contained: the builder will not see this conversation.',
|
|
51007
|
+
'- "scope" is a path allowlist so disjoint pieces can run in parallel. Omit if unsure (forces sequential).',
|
|
51008
|
+
'- "acceptance" is checkable (file, command, observable). Never subjective ("elegant").',
|
|
51009
|
+
'- "bar" (optional) is on-disk reference path(s) the critic compares against blindly (gold file, screenshot, test).',
|
|
51010
|
+
"- Use paths from the workspace listing. Do not invent a tree.",
|
|
51011
|
+
"- Decompose the USER GOAL literally. Do not enlarge it into a different project."
|
|
51012
|
+
].join("\n");
|
|
51013
|
+
}
|
|
51014
|
+
});
|
|
51015
|
+
|
|
51016
|
+
// src/cli/gauntlet/events.ts
|
|
51017
|
+
function gauntletProgressEvent(sessionId2, progress) {
|
|
51018
|
+
return {
|
|
51019
|
+
type: "gauntlet_progress",
|
|
51020
|
+
sessionId: sessionId2,
|
|
51021
|
+
ts: Date.now(),
|
|
51022
|
+
progress
|
|
51023
|
+
};
|
|
51024
|
+
}
|
|
51025
|
+
function formatGauntletSummary(results, opts) {
|
|
51026
|
+
if (results.length === 0) {
|
|
51027
|
+
if (opts?.timedOut) return "Gauntlet stopped: wall clock. No pieces finished.";
|
|
51028
|
+
if (opts?.cancelled) return "Gauntlet cancelled. No pieces finished.";
|
|
51029
|
+
return "Gauntlet: no pieces ran.";
|
|
51030
|
+
}
|
|
51031
|
+
const head = opts?.timedOut ? "Gauntlet stopped: wall clock." : opts?.cancelled ? "Gauntlet cancelled." : "Gauntlet finished.";
|
|
51032
|
+
const lines = [head, ""];
|
|
51033
|
+
for (const r of results) {
|
|
51034
|
+
const gap = r.gap ? ` \u2014 ${r.gap}` : "";
|
|
51035
|
+
const win = r.winner ? ` [A/B ${r.winner}]` : "";
|
|
51036
|
+
lines.push(`- ${r.label} (${r.id}): ${r.verdict} after ${r.rounds} round(s)${win}${gap}`);
|
|
51037
|
+
}
|
|
51038
|
+
return lines.join("\n");
|
|
51039
|
+
}
|
|
51040
|
+
var init_events3 = __esm({
|
|
51041
|
+
"src/cli/gauntlet/events.ts"() {
|
|
51042
|
+
"use strict";
|
|
51043
|
+
}
|
|
51044
|
+
});
|
|
51045
|
+
|
|
51046
|
+
// src/cli/gauntlet/blind.ts
|
|
51047
|
+
function assignBlindLabels(items, rand = Math.random) {
|
|
51048
|
+
if (rand() < 0.5) {
|
|
51049
|
+
return { A: items[0], B: items[1], firstLabel: "A" };
|
|
51050
|
+
}
|
|
51051
|
+
return { A: items[1], B: items[0], firstLabel: "B" };
|
|
51052
|
+
}
|
|
51053
|
+
function qualityBarSection(bars, rand = Math.random) {
|
|
51054
|
+
if (!bars || bars.length === 0) return "";
|
|
51055
|
+
if (bars.length === 1) {
|
|
51056
|
+
return [
|
|
51057
|
+
"## Quality bar (blind)",
|
|
51058
|
+
"Inspect this reference on disk. PASS only if the work in Scope meets or beats it.",
|
|
51059
|
+
"Do not assume the new files are better \u2014 compare concretely.",
|
|
51060
|
+
`- ${bars[0]}`
|
|
51061
|
+
].join("\n");
|
|
51062
|
+
}
|
|
51063
|
+
const pair = assignBlindLabels([bars[0], bars[1]], rand);
|
|
51064
|
+
return [
|
|
51065
|
+
"## Blind A/B",
|
|
51066
|
+
"Two unlabeled artifacts on disk. Compare them against the piece acceptance.",
|
|
51067
|
+
'Do not assume which is newer or which you are "supposed" to prefer.',
|
|
51068
|
+
`A: ${pair.A}`,
|
|
51069
|
+
`B: ${pair.B}`,
|
|
51070
|
+
"Also emit: WINNER: A | B | TIE"
|
|
51071
|
+
].join("\n");
|
|
51072
|
+
}
|
|
51073
|
+
function parseBlindWinner(text) {
|
|
51074
|
+
const m = WINNER_RE.exec(text);
|
|
51075
|
+
if (!m) return void 0;
|
|
51076
|
+
const v = m[1].toUpperCase();
|
|
51077
|
+
if (v === "A" || v === "B" || v === "TIE") return v;
|
|
51078
|
+
return void 0;
|
|
51079
|
+
}
|
|
51080
|
+
var WINNER_RE;
|
|
51081
|
+
var init_blind = __esm({
|
|
51082
|
+
"src/cli/gauntlet/blind.ts"() {
|
|
51083
|
+
"use strict";
|
|
51084
|
+
WINNER_RE = /\bWINNER:\s*(A|B|TIE)\b/i;
|
|
51085
|
+
}
|
|
51086
|
+
});
|
|
51087
|
+
|
|
51088
|
+
// src/cli/gauntlet/verdict.ts
|
|
51089
|
+
function parseGauntletVerdict(text, opts = {}) {
|
|
51090
|
+
const evidence = (opts.toolTraceCount ?? 0) > 0;
|
|
51091
|
+
if (opts.builderFailed) {
|
|
51092
|
+
return {
|
|
51093
|
+
kind: "GAP",
|
|
51094
|
+
gap: (opts.builderError ?? "builder failed").trim() || "builder failed",
|
|
51095
|
+
evidence
|
|
51096
|
+
};
|
|
51097
|
+
}
|
|
51098
|
+
const raw = (text ?? "").trim();
|
|
51099
|
+
if (!raw) {
|
|
51100
|
+
return { kind: "BLOCKED", gap: "critic produced no output", evidence };
|
|
51101
|
+
}
|
|
51102
|
+
const explicit = VERDICT_RE.exec(raw);
|
|
51103
|
+
let kind = explicit ? explicit[1].toUpperCase() : void 0;
|
|
51104
|
+
const reports = [...raw.matchAll(REPORT_STATUS_RE)].map((m) => m[1].toLowerCase());
|
|
51105
|
+
const anyFail = reports.includes("fail");
|
|
51106
|
+
const anyUnknown = reports.includes("unknown");
|
|
51107
|
+
const anyPass = reports.includes("pass");
|
|
51108
|
+
if (!kind) {
|
|
51109
|
+
if (anyFail) kind = "GAP";
|
|
51110
|
+
else if (anyPass && !anyUnknown) kind = "PASS";
|
|
51111
|
+
else if (anyUnknown && !anyPass) kind = "BLOCKED";
|
|
51112
|
+
else kind = "BLOCKED";
|
|
51113
|
+
}
|
|
51114
|
+
const gapMatch = GAP_RE.exec(raw);
|
|
51115
|
+
let gap = gapMatch ? gapMatch[1].trim() : void 0;
|
|
51116
|
+
if (kind === "GAP" && !gap) {
|
|
51117
|
+
gap = anyFail ? "a verify-report check failed" : "critic named a gap without a GAP: line";
|
|
51118
|
+
}
|
|
51119
|
+
if (kind === "PASS" && !evidence) {
|
|
51120
|
+
return {
|
|
51121
|
+
kind: "GAP",
|
|
51122
|
+
gap: "unknown \u2260 pass: critic declared PASS without tool evidence",
|
|
51123
|
+
evidence: false
|
|
51124
|
+
};
|
|
51125
|
+
}
|
|
51126
|
+
if (kind === "PASS" && anyFail) {
|
|
51127
|
+
return {
|
|
51128
|
+
kind: "GAP",
|
|
51129
|
+
gap: gap ?? "verify-report contains a fail",
|
|
51130
|
+
evidence
|
|
51131
|
+
};
|
|
51132
|
+
}
|
|
51133
|
+
return { kind, ...gap ? { gap } : {}, evidence };
|
|
51134
|
+
}
|
|
51135
|
+
var VERDICT_RE, GAP_RE, REPORT_STATUS_RE;
|
|
51136
|
+
var init_verdict2 = __esm({
|
|
51137
|
+
"src/cli/gauntlet/verdict.ts"() {
|
|
51138
|
+
"use strict";
|
|
51139
|
+
VERDICT_RE = /\bVERDICT:\s*(PASS|GAP|BLOCKED)\b/i;
|
|
51140
|
+
GAP_RE = /\bGAP:\s*(.+)/i;
|
|
51141
|
+
REPORT_STATUS_RE = /^status:\s*(pass|fail|unknown)\b/gim;
|
|
51142
|
+
}
|
|
51143
|
+
});
|
|
51144
|
+
|
|
51145
|
+
// src/cli/gauntlet/prompts.ts
|
|
51146
|
+
function builderUserPrompt(piece, gap, briefing) {
|
|
51147
|
+
const parts = [
|
|
51148
|
+
`You are the BUILDER for one Gauntlet piece. Implement it on disk.`,
|
|
51149
|
+
`Do not spawn sub-agents. Stay inside Scope if provided.`
|
|
51150
|
+
];
|
|
51151
|
+
if (briefing?.trim()) {
|
|
51152
|
+
parts.push("", "## Workspace briefing (do not treat as already-done work)", briefing.trim());
|
|
51153
|
+
}
|
|
51154
|
+
parts.push("", `## Piece: ${piece.label}`, piece.prompt.trim());
|
|
51155
|
+
if (piece.scope && piece.scope.length > 0) {
|
|
51156
|
+
parts.push("", "## Scope", ...piece.scope.map((s) => `- ${s}`));
|
|
51157
|
+
}
|
|
51158
|
+
if (piece.acceptance.length > 0) {
|
|
51159
|
+
parts.push("", "## Acceptance", ...piece.acceptance.map((a) => `- ${a}`));
|
|
51160
|
+
}
|
|
51161
|
+
if (gap && gap.trim()) {
|
|
51162
|
+
parts.push(
|
|
51163
|
+
"",
|
|
51164
|
+
"## Previous critic GAP (fix ONLY this)",
|
|
51165
|
+
gap.trim(),
|
|
51166
|
+
"Do not widen scope. Re-check the acceptance after the fix."
|
|
51167
|
+
);
|
|
51168
|
+
}
|
|
51169
|
+
parts.push("", "Return: files touched, what changed, residual risks.");
|
|
51170
|
+
return parts.join("\n");
|
|
51171
|
+
}
|
|
51172
|
+
function criticUserPrompt(piece, round, rand) {
|
|
51173
|
+
const parts = [
|
|
51174
|
+
`Round ${round}. Inspect the current tree against this piece.`,
|
|
51175
|
+
"Do not edit files. Do not take the builder's word \u2014 open files / run checks.",
|
|
51176
|
+
"",
|
|
51177
|
+
`## Piece: ${piece.label}`,
|
|
51178
|
+
piece.prompt.trim()
|
|
51179
|
+
];
|
|
51180
|
+
if (piece.scope && piece.scope.length > 0) {
|
|
51181
|
+
parts.push("", "## Scope", ...piece.scope.map((s) => `- ${s}`));
|
|
51182
|
+
}
|
|
51183
|
+
if (piece.acceptance.length > 0) {
|
|
51184
|
+
parts.push("", "## Acceptance (check each)", ...piece.acceptance.map((a) => `- ${a}`));
|
|
51185
|
+
} else {
|
|
51186
|
+
parts.push(
|
|
51187
|
+
"",
|
|
51188
|
+
"## Acceptance",
|
|
51189
|
+
"- The piece prompt is satisfied by files on disk.",
|
|
51190
|
+
"- Relevant typecheck/tests pass when the project has them."
|
|
51191
|
+
);
|
|
51192
|
+
}
|
|
51193
|
+
const bar = qualityBarSection(piece.bar, rand);
|
|
51194
|
+
if (bar) parts.push("", bar);
|
|
51195
|
+
return parts.join("\n");
|
|
51196
|
+
}
|
|
51197
|
+
var GAUNTLET_CRITIC_SYSTEM;
|
|
51198
|
+
var init_prompts = __esm({
|
|
51199
|
+
"src/cli/gauntlet/prompts.ts"() {
|
|
51200
|
+
"use strict";
|
|
51201
|
+
init_blind();
|
|
51202
|
+
GAUNTLET_CRITIC_SYSTEM = [
|
|
51203
|
+
"You are a ruthless VERIFY critic in a Gauntlet Loop.",
|
|
51204
|
+
"Inspect the REAL files and commands on disk. Do not trust a builder self-report.",
|
|
51205
|
+
"You have no builder transcript \u2014 only the Goal, Scope, Acceptance, and the tree.",
|
|
51206
|
+
"OBSERVATION INTEGRITY: unknown \u2260 pass. EMPTY/degraded tools are not evidence.",
|
|
51207
|
+
"Name at most ONE biggest remaining gap. Do not write a laundry list.",
|
|
51208
|
+
"You may read files and run test/build commands via bash. Prefer targeted checks.",
|
|
51209
|
+
"",
|
|
51210
|
+
"End with BOTH:",
|
|
51211
|
+
"1. One <verify-report> block per acceptance criterion:",
|
|
51212
|
+
"<verify-report>",
|
|
51213
|
+
"check: <criterion text as given>",
|
|
51214
|
+
"status: pass | fail | unknown",
|
|
51215
|
+
"note: <one line of evidence (command or file + outcome)>",
|
|
51216
|
+
"</verify-report>",
|
|
51217
|
+
"2. A trailer on its own lines:",
|
|
51218
|
+
"VERDICT: PASS | GAP | BLOCKED",
|
|
51219
|
+
"GAP: <single biggest remaining gap; omit on PASS>",
|
|
51220
|
+
"3. If a Blind A/B section is present, also emit WINNER: A | B | TIE"
|
|
51221
|
+
].join("\n");
|
|
51222
|
+
}
|
|
51223
|
+
});
|
|
51224
|
+
|
|
51225
|
+
// src/cli/gauntlet/schedule.ts
|
|
51226
|
+
function piecesCanRunInParallel(a, b) {
|
|
51227
|
+
return disjointScopeSets(a.scope, b.scope);
|
|
51228
|
+
}
|
|
51229
|
+
function scheduleWaves(pieces, maxParallel) {
|
|
51230
|
+
const cap3 = Math.max(1, maxParallel);
|
|
51231
|
+
const remaining = [...pieces];
|
|
51232
|
+
const waves = [];
|
|
51233
|
+
while (remaining.length > 0) {
|
|
51234
|
+
const wave = [];
|
|
51235
|
+
const leftover = [];
|
|
51236
|
+
for (const p3 of remaining) {
|
|
51237
|
+
if (wave.length >= cap3) {
|
|
51238
|
+
leftover.push(p3);
|
|
51239
|
+
continue;
|
|
51240
|
+
}
|
|
51241
|
+
if (wave.length === 0 || wave.every((w) => piecesCanRunInParallel(w, p3))) {
|
|
51242
|
+
wave.push(p3);
|
|
51243
|
+
} else {
|
|
51244
|
+
leftover.push(p3);
|
|
51245
|
+
}
|
|
51246
|
+
}
|
|
51247
|
+
waves.push(wave);
|
|
51248
|
+
remaining.splice(0, remaining.length, ...leftover);
|
|
51249
|
+
}
|
|
51250
|
+
return waves;
|
|
51251
|
+
}
|
|
51252
|
+
var init_schedule = __esm({
|
|
51253
|
+
"src/cli/gauntlet/schedule.ts"() {
|
|
51254
|
+
"use strict";
|
|
51255
|
+
init_dist();
|
|
51256
|
+
}
|
|
51257
|
+
});
|
|
51258
|
+
|
|
51259
|
+
// src/cli/gauntlet/loop.ts
|
|
51260
|
+
async function runGauntletLoop(args) {
|
|
51261
|
+
const { caps, deps } = args;
|
|
51262
|
+
const pieces = args.pieces.slice(0, caps.maxPieces);
|
|
51263
|
+
const started = (deps.now ?? Date.now)();
|
|
51264
|
+
const results = [];
|
|
51265
|
+
const emitProgress = (partial2) => {
|
|
51266
|
+
const progress = {
|
|
51267
|
+
...partial2,
|
|
51268
|
+
elapsedMs: (deps.now ?? Date.now)() - started
|
|
51269
|
+
};
|
|
51270
|
+
deps.emit(gauntletProgressEvent(deps.sessionId, progress));
|
|
51271
|
+
deps.note?.("gauntlet.progress", progress);
|
|
51272
|
+
};
|
|
51273
|
+
const wall = caps.wallClockMs === void 0 ? DEFAULT_WALL_MS : caps.wallClockMs;
|
|
51274
|
+
const expired = () => wall > 0 && (deps.now ?? Date.now)() - started >= wall;
|
|
51275
|
+
const aborted2 = () => Boolean(deps.signal?.aborted);
|
|
51276
|
+
const stop = () => aborted2() || expired();
|
|
51277
|
+
const indexOf = (piece) => pieces.findIndex((p3) => p3.id === piece.id);
|
|
51278
|
+
const runOnePiece = async (piece) => {
|
|
51279
|
+
let last = {
|
|
51280
|
+
kind: "BLOCKED",
|
|
51281
|
+
gap: "no round ran",
|
|
51282
|
+
evidence: false
|
|
51283
|
+
};
|
|
51284
|
+
let gap;
|
|
51285
|
+
let winner;
|
|
51286
|
+
let rounds = 0;
|
|
51287
|
+
const i = Math.max(0, indexOf(piece));
|
|
51288
|
+
for (let round = 1; round <= caps.maxRounds; round++) {
|
|
51289
|
+
if (stop()) break;
|
|
51290
|
+
rounds = round;
|
|
51291
|
+
const phase2 = gap ? "repairing" : "building";
|
|
51292
|
+
emitProgress({
|
|
51293
|
+
phase: phase2,
|
|
51294
|
+
pieceId: piece.id,
|
|
51295
|
+
pieceLabel: piece.label,
|
|
51296
|
+
pieceIndex: i,
|
|
51297
|
+
pieceCount: pieces.length,
|
|
51298
|
+
round,
|
|
51299
|
+
maxRounds: caps.maxRounds
|
|
51300
|
+
});
|
|
51301
|
+
const built = await deps.runBuilder({
|
|
51302
|
+
piece,
|
|
51303
|
+
prompt: builderUserPrompt(piece, gap, deps.briefing),
|
|
51304
|
+
round
|
|
51305
|
+
});
|
|
51306
|
+
if (stop()) break;
|
|
51307
|
+
emitProgress({
|
|
51308
|
+
phase: "critiquing",
|
|
51309
|
+
pieceId: piece.id,
|
|
51310
|
+
pieceLabel: piece.label,
|
|
51311
|
+
pieceIndex: i,
|
|
51312
|
+
pieceCount: pieces.length,
|
|
51313
|
+
round,
|
|
51314
|
+
maxRounds: caps.maxRounds
|
|
51315
|
+
});
|
|
51316
|
+
const criticized = await deps.runCritic({
|
|
51317
|
+
piece,
|
|
51318
|
+
prompt: criticUserPrompt(piece, round),
|
|
51319
|
+
systemPrompt: GAUNTLET_CRITIC_SYSTEM,
|
|
51320
|
+
round
|
|
51321
|
+
});
|
|
51322
|
+
last = parseGauntletVerdict(criticized.result, {
|
|
51323
|
+
toolTraceCount: criticized.toolTraceCount ?? 0,
|
|
51324
|
+
builderFailed: !built.ok,
|
|
51325
|
+
builderError: built.error
|
|
51326
|
+
});
|
|
51327
|
+
winner = parseBlindWinner(criticized.result) ?? winner;
|
|
51328
|
+
emitProgress({
|
|
51329
|
+
phase: last.kind === "PASS" ? "settled" : last.kind === "BLOCKED" ? "blocked" : "repairing",
|
|
51330
|
+
pieceId: piece.id,
|
|
51331
|
+
pieceLabel: piece.label,
|
|
51332
|
+
pieceIndex: i,
|
|
51333
|
+
pieceCount: pieces.length,
|
|
51334
|
+
round,
|
|
51335
|
+
maxRounds: caps.maxRounds,
|
|
51336
|
+
verdict: last.kind,
|
|
51337
|
+
gap: last.gap,
|
|
51338
|
+
winner
|
|
51339
|
+
});
|
|
51340
|
+
if (last.kind === "PASS" || last.kind === "BLOCKED") break;
|
|
51341
|
+
gap = last.gap;
|
|
51342
|
+
}
|
|
51343
|
+
return {
|
|
51344
|
+
id: piece.id,
|
|
51345
|
+
label: piece.label,
|
|
51346
|
+
verdict: last,
|
|
51347
|
+
rounds,
|
|
51348
|
+
...winner ? { winner } : {}
|
|
51349
|
+
};
|
|
51350
|
+
};
|
|
51351
|
+
for (const wave of scheduleWaves(pieces, caps.maxParallel)) {
|
|
51352
|
+
if (stop()) return finish(results, { cancelled: aborted2(), timedOut: expired() });
|
|
51353
|
+
if (wave.length === 1) {
|
|
51354
|
+
results.push(await runOnePiece(wave[0]));
|
|
51355
|
+
} else {
|
|
51356
|
+
const waveResults = await Promise.all(wave.map((p3) => runOnePiece(p3)));
|
|
51357
|
+
results.push(...waveResults);
|
|
51358
|
+
}
|
|
51359
|
+
if (stop()) return finish(results, { cancelled: aborted2(), timedOut: expired() });
|
|
51360
|
+
}
|
|
51361
|
+
return finish(results, { cancelled: aborted2(), timedOut: expired() });
|
|
51362
|
+
}
|
|
51363
|
+
function finish(results, flags) {
|
|
51364
|
+
const cancelled = flags.timedOut ? false : flags.cancelled;
|
|
51365
|
+
const timedOut = flags.timedOut;
|
|
51366
|
+
const settled = !cancelled && !timedOut && results.length > 0 && results.every((r) => r.verdict.kind === "PASS");
|
|
51367
|
+
return {
|
|
51368
|
+
settled,
|
|
51369
|
+
cancelled,
|
|
51370
|
+
timedOut,
|
|
51371
|
+
pieces: results,
|
|
51372
|
+
summary: formatGauntletSummary(
|
|
51373
|
+
results.map((r) => ({
|
|
51374
|
+
id: r.id,
|
|
51375
|
+
label: r.label,
|
|
51376
|
+
verdict: r.verdict.kind,
|
|
51377
|
+
rounds: r.rounds,
|
|
51378
|
+
gap: r.verdict.gap,
|
|
51379
|
+
winner: r.winner
|
|
51380
|
+
})),
|
|
51381
|
+
{ timedOut, cancelled }
|
|
51382
|
+
)
|
|
51383
|
+
};
|
|
51384
|
+
}
|
|
51385
|
+
var init_loop = __esm({
|
|
51386
|
+
"src/cli/gauntlet/loop.ts"() {
|
|
51387
|
+
"use strict";
|
|
51388
|
+
init_blind();
|
|
51389
|
+
init_policy();
|
|
51390
|
+
init_verdict2();
|
|
51391
|
+
init_prompts();
|
|
51392
|
+
init_schedule();
|
|
51393
|
+
init_events3();
|
|
51394
|
+
}
|
|
51395
|
+
});
|
|
51396
|
+
|
|
51397
|
+
// src/cli/gauntlet/run.ts
|
|
51398
|
+
var run_exports = {};
|
|
51399
|
+
__export(run_exports, {
|
|
51400
|
+
runHeadlessGauntlet: () => runHeadlessGauntlet
|
|
51401
|
+
});
|
|
51402
|
+
async function runHeadlessGauntlet(opts, provider, model) {
|
|
51403
|
+
const sessionId2 = opts.resumeSessionId ?? crypto.randomUUID();
|
|
51404
|
+
const spine = await openHeadlessSpine({
|
|
51405
|
+
sessionId: sessionId2,
|
|
51406
|
+
mode: opts.mode,
|
|
51407
|
+
profile: opts.profile,
|
|
51408
|
+
workspace: process.cwd()
|
|
51409
|
+
});
|
|
51410
|
+
emitEvent(sessionStartedEvent(spine));
|
|
51411
|
+
const seeded = await seedHeadlessModelHistory(spine, opts.history);
|
|
51412
|
+
if (opts.task) spine.userMessage(opts.task);
|
|
51413
|
+
spine.note("gauntlet.start", { goal: opts.task.slice(0, 200) });
|
|
51414
|
+
const abort = new AbortController();
|
|
51415
|
+
const onSigint = () => {
|
|
51416
|
+
emitEvent({ type: "log", message: "[gauntlet] SIGINT \u2014 cancelling" });
|
|
51417
|
+
abort.abort();
|
|
51418
|
+
};
|
|
51419
|
+
process.once("SIGINT", onSigint);
|
|
51420
|
+
const wallMs = resolveGauntletCaps().wallClockMs ?? 0;
|
|
51421
|
+
const wallTimer = wallMs > 0 ? setTimeout(() => {
|
|
51422
|
+
emitEvent({ type: "log", message: "[gauntlet] wall clock \u2014 aborting tentacles" });
|
|
51423
|
+
abort.abort();
|
|
51424
|
+
}, wallMs) : void 0;
|
|
51425
|
+
const cwd = process.cwd();
|
|
51426
|
+
const audit = new AuditLogger();
|
|
51427
|
+
const createSubAgentContext = createKrakenSubAgentContextFactory({
|
|
51428
|
+
root: cwd,
|
|
51429
|
+
audit,
|
|
51430
|
+
sessionId: sessionId2,
|
|
51431
|
+
provider,
|
|
51432
|
+
model
|
|
51433
|
+
});
|
|
51434
|
+
const deps = {
|
|
51435
|
+
createSubAgentContext,
|
|
51436
|
+
allowWorktree: false,
|
|
51437
|
+
harnessFactory: (config2) => {
|
|
51438
|
+
const harness = new AgentHarness(config2);
|
|
51439
|
+
return {
|
|
51440
|
+
async *run() {
|
|
51441
|
+
for await (const ev of harness.run()) {
|
|
51442
|
+
if (ev.type === "thinking_delta" || ev.type === "tool_execution_start" || ev.type === "tool_execution_end") {
|
|
51443
|
+
emitEvent(ev);
|
|
51444
|
+
spine.observe(ev);
|
|
51445
|
+
}
|
|
51446
|
+
yield ev;
|
|
51447
|
+
}
|
|
51448
|
+
},
|
|
51449
|
+
cancel: () => harness.cancel()
|
|
51450
|
+
};
|
|
51451
|
+
}
|
|
51452
|
+
};
|
|
51453
|
+
const emit = (event) => {
|
|
51454
|
+
if (opts.output === "json") emitEvent(event);
|
|
51455
|
+
else if (typeof event.message === "string") {
|
|
51456
|
+
process.stderr.write(`${event.message}
|
|
51457
|
+
`);
|
|
51458
|
+
}
|
|
51459
|
+
};
|
|
51460
|
+
emitEvent({ type: "agent_start", model, provider, role: "gauntlet" });
|
|
51461
|
+
emit({ type: "log", message: "[gauntlet] host loop \u2014 builder/critic rounds, parent cannot write" });
|
|
51462
|
+
const caps = resolveGauntletCaps();
|
|
51463
|
+
const workspace = buildWorkspaceSummary(cwd, { maxChars: 2500 });
|
|
51464
|
+
const historyNote = formatHistoryNote(seeded.history);
|
|
51465
|
+
emitEvent(
|
|
51466
|
+
gauntletProgressEvent(sessionId2, {
|
|
51467
|
+
phase: "decomposing",
|
|
51468
|
+
pieceId: "",
|
|
51469
|
+
pieceLabel: "Goal",
|
|
51470
|
+
pieceIndex: 0,
|
|
51471
|
+
pieceCount: 1,
|
|
51472
|
+
round: 0,
|
|
51473
|
+
maxRounds: caps.maxRounds,
|
|
51474
|
+
elapsedMs: 0
|
|
51475
|
+
})
|
|
51476
|
+
);
|
|
51477
|
+
try {
|
|
51478
|
+
const decomposed = await decomposeGoal({
|
|
51479
|
+
goal: opts.task,
|
|
51480
|
+
maxPieces: caps.maxPieces,
|
|
51481
|
+
workspace,
|
|
51482
|
+
historyNote,
|
|
51483
|
+
complete: (req) => gauntletComplete(req, { provider, model, signal: abort.signal })
|
|
51484
|
+
});
|
|
51485
|
+
spine.note("gauntlet.decompose", {
|
|
51486
|
+
source: decomposed.source,
|
|
51487
|
+
count: decomposed.pieces.length,
|
|
51488
|
+
...decomposed.error ? { error: decomposed.error.slice(0, 240) } : {}
|
|
51489
|
+
});
|
|
51490
|
+
emit({
|
|
51491
|
+
type: "log",
|
|
51492
|
+
message: `[gauntlet] ${decomposed.pieces.length} piece(s) from ${decomposed.source}${decomposed.error ? ` (${decomposed.error.slice(0, 80)})` : ""}`
|
|
51493
|
+
});
|
|
51494
|
+
const result = await runGauntletLoop({
|
|
51495
|
+
pieces: decomposed.pieces,
|
|
51496
|
+
caps,
|
|
51497
|
+
deps: {
|
|
51498
|
+
sessionId: sessionId2,
|
|
51499
|
+
signal: abort.signal,
|
|
51500
|
+
emit,
|
|
51501
|
+
briefing: workspace.slice(0, 1200),
|
|
51502
|
+
note: (text, data) => spine.note(text, data),
|
|
51503
|
+
runBuilder: async ({ piece, prompt, round }) => {
|
|
51504
|
+
emit({
|
|
51505
|
+
type: "log",
|
|
51506
|
+
message: `[gauntlet] ${piece.id} round ${round}/${caps.maxRounds} builder`
|
|
51507
|
+
});
|
|
51508
|
+
const tent = await runTentacle({
|
|
51509
|
+
deps,
|
|
51510
|
+
agent: "general",
|
|
51511
|
+
thoroughness: "medium",
|
|
51512
|
+
parentCwd: cwd,
|
|
51513
|
+
sessionId: sessionId2,
|
|
51514
|
+
signal: abort.signal,
|
|
51515
|
+
args: {
|
|
51516
|
+
description: `gauntlet-builder ${piece.id} r${round}`,
|
|
51517
|
+
prompt,
|
|
51518
|
+
...piece.scope ? { scope: piece.scope } : {},
|
|
51519
|
+
...piece.acceptance.length > 0 ? { acceptance: piece.acceptance } : {}
|
|
51520
|
+
}
|
|
51521
|
+
});
|
|
51522
|
+
if (!tent.ok) return { ok: false, result: "", error: tent.error };
|
|
51523
|
+
return {
|
|
51524
|
+
ok: true,
|
|
51525
|
+
result: tent.result,
|
|
51526
|
+
toolTraceCount: tent.toolTrace?.length ?? 0
|
|
51527
|
+
};
|
|
51528
|
+
},
|
|
51529
|
+
runCritic: async ({ piece, prompt, systemPrompt, round }) => {
|
|
51530
|
+
emit({
|
|
51531
|
+
type: "log",
|
|
51532
|
+
message: `[gauntlet] ${piece.id} round ${round}/${caps.maxRounds} critic`
|
|
51533
|
+
});
|
|
51534
|
+
const tent = await runTentacle({
|
|
51535
|
+
deps,
|
|
51536
|
+
agent: "verify",
|
|
51537
|
+
thoroughness: "medium",
|
|
51538
|
+
parentCwd: cwd,
|
|
51539
|
+
sessionId: sessionId2,
|
|
51540
|
+
signal: abort.signal,
|
|
51541
|
+
systemPromptOverride: systemPrompt,
|
|
51542
|
+
args: {
|
|
51543
|
+
description: `gauntlet-critic ${piece.id} r${round}`,
|
|
51544
|
+
prompt,
|
|
51545
|
+
...piece.scope ? { scope: piece.scope } : {},
|
|
51546
|
+
...piece.acceptance.length > 0 ? { acceptance: piece.acceptance } : {}
|
|
51547
|
+
}
|
|
51548
|
+
});
|
|
51549
|
+
if (!tent.ok) {
|
|
51550
|
+
return { ok: false, result: tent.error, error: tent.error, toolTraceCount: 0 };
|
|
51551
|
+
}
|
|
51552
|
+
return {
|
|
51553
|
+
ok: true,
|
|
51554
|
+
result: tent.result,
|
|
51555
|
+
toolTraceCount: tent.toolTrace?.length ?? 0
|
|
51556
|
+
};
|
|
51557
|
+
}
|
|
51558
|
+
}
|
|
51559
|
+
});
|
|
51560
|
+
emitEvent({ type: "message_start", role: "assistant" });
|
|
51561
|
+
emitEvent({ type: "message_delta", delta: result.summary });
|
|
51562
|
+
emitEvent({ type: "message_end", totalLength: result.summary.length });
|
|
51563
|
+
emitEvent({
|
|
51564
|
+
type: "agent_end",
|
|
51565
|
+
reason: result.cancelled || result.timedOut ? "cancelled" : result.settled ? "completed" : "error"
|
|
51566
|
+
});
|
|
51567
|
+
if (result.timedOut) {
|
|
51568
|
+
emit({ type: "log", message: `[gauntlet] wall clock (${Math.round(wallMs / 6e4)}m)` });
|
|
51569
|
+
await spine.interrupt("gauntlet-wall-clock");
|
|
51570
|
+
return 1;
|
|
51571
|
+
}
|
|
51572
|
+
if (result.cancelled) {
|
|
51573
|
+
await spine.interrupt("gauntlet-cancelled");
|
|
51574
|
+
return 1;
|
|
51575
|
+
}
|
|
51576
|
+
await spine.close(result.settled ? "gauntlet-pass" : "gauntlet-incomplete");
|
|
51577
|
+
return result.settled ? 0 : 3;
|
|
51578
|
+
} catch (err) {
|
|
51579
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
51580
|
+
emitEvent({ type: "error", severity: "fatal", message: msg, code: "gauntlet" });
|
|
51581
|
+
await spine.interrupt(`gauntlet-error: ${msg}`).catch(() => void 0);
|
|
51582
|
+
return 2;
|
|
51583
|
+
} finally {
|
|
51584
|
+
if (wallTimer) clearTimeout(wallTimer);
|
|
51585
|
+
process.removeListener("SIGINT", onSigint);
|
|
51586
|
+
}
|
|
51587
|
+
}
|
|
51588
|
+
var init_run = __esm({
|
|
51589
|
+
"src/cli/gauntlet/run.ts"() {
|
|
51590
|
+
"use strict";
|
|
51591
|
+
init_harness();
|
|
51592
|
+
init_headless();
|
|
51593
|
+
init_headlessSpine();
|
|
51594
|
+
init_auditLogger();
|
|
51595
|
+
init_toolRegistry();
|
|
51596
|
+
init_taskTool();
|
|
51597
|
+
init_complete();
|
|
51598
|
+
init_decompose();
|
|
51599
|
+
init_events3();
|
|
51600
|
+
init_loop();
|
|
51601
|
+
init_policy();
|
|
51602
|
+
init_workspaceSummary();
|
|
51603
|
+
}
|
|
51604
|
+
});
|
|
51605
|
+
|
|
50185
51606
|
// src/cli/triggerLock.ts
|
|
50186
51607
|
var triggerLock_exports = {};
|
|
50187
51608
|
__export(triggerLock_exports, {
|
|
@@ -50956,7 +52377,7 @@ function startPermissionMcpServer(opts) {
|
|
|
50956
52377
|
}
|
|
50957
52378
|
return { error: { code: -32601, message: `method not found: ${method}` } };
|
|
50958
52379
|
}
|
|
50959
|
-
async function callApprove(args,
|
|
52380
|
+
async function callApprove(args, timeoutMs2) {
|
|
50960
52381
|
const toolName = typeof args.tool_name === "string" ? args.tool_name : "";
|
|
50961
52382
|
if (!toolName) {
|
|
50962
52383
|
return { error: { code: -32602, message: "approve requires a string tool_name" } };
|
|
@@ -50975,7 +52396,7 @@ function startPermissionMcpServer(opts) {
|
|
|
50975
52396
|
toolUseId: typeof args.tool_use_id === "string" ? args.tool_use_id : void 0,
|
|
50976
52397
|
suggestions
|
|
50977
52398
|
},
|
|
50978
|
-
{ requestTimeoutMs:
|
|
52399
|
+
{ requestTimeoutMs: timeoutMs2 }
|
|
50979
52400
|
);
|
|
50980
52401
|
const result = res.behavior === "allow" ? {
|
|
50981
52402
|
behavior: "allow",
|
|
@@ -50995,7 +52416,7 @@ function startPermissionMcpServer(opts) {
|
|
|
50995
52416
|
);
|
|
50996
52417
|
}
|
|
50997
52418
|
}
|
|
50998
|
-
async function callAskUser(args,
|
|
52419
|
+
async function callAskUser(args, timeoutMs2) {
|
|
50999
52420
|
const question = typeof args.question === "string" ? args.question : "";
|
|
51000
52421
|
if (!question) {
|
|
51001
52422
|
return { error: { code: -32602, message: "ask_user requires a string question" } };
|
|
@@ -51013,7 +52434,7 @@ function startPermissionMcpServer(opts) {
|
|
|
51013
52434
|
choices,
|
|
51014
52435
|
context
|
|
51015
52436
|
},
|
|
51016
|
-
{ requestTimeoutMs:
|
|
52437
|
+
{ requestTimeoutMs: timeoutMs2 }
|
|
51017
52438
|
);
|
|
51018
52439
|
const text = res.behavior === "allow" && typeof res.answer === "string" ? res.answer : res.message ?? "No answer was given \u2014 use your best judgment.";
|
|
51019
52440
|
return textResult(text);
|
|
@@ -55861,8 +57282,8 @@ async function readPackageScripts(cwd = process.cwd()) {
|
|
|
55861
57282
|
return {};
|
|
55862
57283
|
}
|
|
55863
57284
|
}
|
|
55864
|
-
function buildNativeCriteria(commands,
|
|
55865
|
-
const pack = codingCriteriaPack({ ...commands, commandTimeoutMs:
|
|
57285
|
+
function buildNativeCriteria(commands, timeoutMs2) {
|
|
57286
|
+
const pack = codingCriteriaPack({ ...commands, commandTimeoutMs: timeoutMs2 });
|
|
55866
57287
|
return pack.criteria.filter(
|
|
55867
57288
|
(c) => !(c.required && (!c.check || c.check.kind === "none"))
|
|
55868
57289
|
);
|
|
@@ -56127,9 +57548,6 @@ function strictGateEventPayload(evaluation) {
|
|
|
56127
57548
|
};
|
|
56128
57549
|
}
|
|
56129
57550
|
|
|
56130
|
-
// src/cli/hooks/useChatTurn.ts
|
|
56131
|
-
init_headlessSpine();
|
|
56132
|
-
|
|
56133
57551
|
// src/cli/hooks/permissionPicker.ts
|
|
56134
57552
|
init_toolPermissions();
|
|
56135
57553
|
|
|
@@ -56164,7 +57582,7 @@ ${detail}
|
|
|
56164
57582
|
let settled = false;
|
|
56165
57583
|
const askTimeoutMs = askUserTimeoutMs();
|
|
56166
57584
|
let cancelAskTimeout = () => void 0;
|
|
56167
|
-
const
|
|
57585
|
+
const finish2 = (ok, note) => {
|
|
56168
57586
|
if (settled) return;
|
|
56169
57587
|
settled = true;
|
|
56170
57588
|
cancelAskTimeout();
|
|
@@ -56173,7 +57591,7 @@ ${detail}
|
|
|
56173
57591
|
resolve3(ok);
|
|
56174
57592
|
};
|
|
56175
57593
|
cancelAskTimeout = armPickerTimeout(
|
|
56176
|
-
() =>
|
|
57594
|
+
() => finish2(
|
|
56177
57595
|
false,
|
|
56178
57596
|
`[permission] ask for "${req.toolName}" timed out after ${Math.round(
|
|
56179
57597
|
askTimeoutMs / 1e3
|
|
@@ -56202,12 +57620,12 @@ ${detail}
|
|
|
56202
57620
|
onAnswer: (value) => {
|
|
56203
57621
|
const v = value.trim().toLowerCase();
|
|
56204
57622
|
if (v === "deny" || v.startsWith("deny")) {
|
|
56205
|
-
|
|
57623
|
+
finish2(false);
|
|
56206
57624
|
return;
|
|
56207
57625
|
}
|
|
56208
57626
|
if (v === "always-tool" || v.includes("always") && v.includes("tool")) {
|
|
56209
57627
|
grantSessionTool(req.toolName);
|
|
56210
|
-
|
|
57628
|
+
finish2(
|
|
56211
57629
|
true,
|
|
56212
57630
|
`[permission] Granted "${req.toolName}" for this session (tool).`
|
|
56213
57631
|
);
|
|
@@ -56216,19 +57634,19 @@ ${detail}
|
|
|
56216
57634
|
if (v === "always-cat" || v.includes("always") && !v.includes("tool")) {
|
|
56217
57635
|
for (const c of cats) grantSessionCategory(c);
|
|
56218
57636
|
grantSessionTool(req.toolName);
|
|
56219
|
-
|
|
57637
|
+
finish2(
|
|
56220
57638
|
true,
|
|
56221
57639
|
`[permission] Granted ${catLabel} (+ ${req.toolName}) for this session.`
|
|
56222
57640
|
);
|
|
56223
57641
|
return;
|
|
56224
57642
|
}
|
|
56225
57643
|
if (v === "allow" || v.startsWith("allow") || v === "yes" || v === "y" || v === "1") {
|
|
56226
|
-
|
|
57644
|
+
finish2(true);
|
|
56227
57645
|
return;
|
|
56228
57646
|
}
|
|
56229
|
-
|
|
57647
|
+
finish2(false);
|
|
56230
57648
|
},
|
|
56231
|
-
onCancel: () =>
|
|
57649
|
+
onCancel: () => finish2(false)
|
|
56232
57650
|
});
|
|
56233
57651
|
});
|
|
56234
57652
|
}
|
|
@@ -56278,6 +57696,15 @@ init_envNumber();
|
|
|
56278
57696
|
init_historyCompaction();
|
|
56279
57697
|
init_observationStore();
|
|
56280
57698
|
init_capabilities();
|
|
57699
|
+
function mergeCompactRange(into, r) {
|
|
57700
|
+
if (r.fromSeq !== void 0 && r.toSeq !== void 0) {
|
|
57701
|
+
into.fromSeq = into.fromSeq === void 0 ? r.fromSeq : Math.min(into.fromSeq, r.fromSeq);
|
|
57702
|
+
into.toSeq = into.toSeq === void 0 ? r.toSeq : Math.max(into.toSeq, r.toSeq);
|
|
57703
|
+
if (r.sourceEventSeqs) into.sourceSeqs.push(...r.sourceEventSeqs);
|
|
57704
|
+
}
|
|
57705
|
+
if (r.strategy === "llm") into.strategy = "llm";
|
|
57706
|
+
else if (r.strategy && !into.strategy) into.strategy = r.strategy;
|
|
57707
|
+
}
|
|
56281
57708
|
function estimateTokens(text) {
|
|
56282
57709
|
if (!text) return 0;
|
|
56283
57710
|
return Math.max(1, Math.ceil(text.length / 4));
|
|
@@ -56321,21 +57748,23 @@ async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
|
56321
57748
|
const warnings = [];
|
|
56322
57749
|
let { historyTurns, maxToolLoopIterations } = phaseKnobs(phase2);
|
|
56323
57750
|
const envelope = opts?.requestSnapshot ?? null;
|
|
56324
|
-
const
|
|
56325
|
-
|
|
56326
|
-
|
|
56327
|
-
|
|
56328
|
-
|
|
57751
|
+
const surface = envelope?.snapshot ?? opts?.requestSurface ?? null;
|
|
57752
|
+
const replayBase = surface ? {
|
|
57753
|
+
provider: surface.provider,
|
|
57754
|
+
model: surface.model,
|
|
57755
|
+
systemMessages: surface.systemMessages,
|
|
57756
|
+
tools: surface.tools
|
|
56329
57757
|
} : opts?.providerStream ? { provider: "local", model: opts?.model ?? "unknown", systemMessages: [], tools: [] } : null;
|
|
56330
|
-
const headerTokens =
|
|
57758
|
+
const headerTokens = surface ? estimateSystemTokensLite(surface.systemMessages) + estimateToolSchemaTokensLite(surface.tools) : 0;
|
|
56331
57759
|
const convTokensOf = (h) => estimateConversationTokensLite(h);
|
|
56332
57760
|
let hist = history2;
|
|
56333
|
-
let estimated =
|
|
57761
|
+
let estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
56334
57762
|
let occupancy = Math.min(1, estimated / contextLimit);
|
|
56335
57763
|
let compactSummary = "";
|
|
56336
57764
|
let messagesRemoved = 0;
|
|
56337
57765
|
let cacheReuseExpected;
|
|
56338
57766
|
let prunedTotal = 0;
|
|
57767
|
+
const compactRange = { sourceSeqs: [] };
|
|
56339
57768
|
if (occupancy >= compact.warnAt && occupancy < compact.compactAt) {
|
|
56340
57769
|
warnings.push(
|
|
56341
57770
|
`[budget] context ~${Math.round(occupancy * 100)}% full (${estimated}/${contextLimit} tok full-request est.) \u2014 consider /compact or shorter replies.`
|
|
@@ -56346,7 +57775,7 @@ async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
|
56346
57775
|
if (pruned.stats.pruned > 0) {
|
|
56347
57776
|
hist = pruned.messages;
|
|
56348
57777
|
prunedTotal += pruned.stats.pruned;
|
|
56349
|
-
estimated =
|
|
57778
|
+
estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
56350
57779
|
occupancy = Math.min(1, estimated / contextLimit);
|
|
56351
57780
|
warnings.push(
|
|
56352
57781
|
`[budget] pruned ${pruned.stats.pruned} oversized tool result(s) \u2192 ${Math.round(occupancy * 100)}% (${estimated} tok).`
|
|
@@ -56358,11 +57787,12 @@ async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
|
56358
57787
|
if (r.compacted) {
|
|
56359
57788
|
messagesRemoved += r.messagesRemoved;
|
|
56360
57789
|
if (r.summary) compactSummary = r.summary;
|
|
57790
|
+
mergeCompactRange(compactRange, r);
|
|
56361
57791
|
if (r.cacheReuseExpected !== void 0) {
|
|
56362
57792
|
cacheReuseExpected = r.cacheReuseExpected;
|
|
56363
57793
|
}
|
|
56364
57794
|
}
|
|
56365
|
-
estimated =
|
|
57795
|
+
estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
56366
57796
|
occupancy = Math.min(1, estimated / contextLimit);
|
|
56367
57797
|
warnings.push(
|
|
56368
57798
|
`[budget] ${label} \u2014 kept ~${forcedTurns} turns (${estimated} tok est.` + (r.messagesRemoved ? `, removed ${r.messagesRemoved} msgs` : "") + (r.cacheReuseExpected === false ? ", cache reuse NOT expected (model override)" : "") + ")."
|
|
@@ -56418,12 +57848,18 @@ async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
|
56418
57848
|
warnings,
|
|
56419
57849
|
maxToolLoopIterations,
|
|
56420
57850
|
historyTurns,
|
|
56421
|
-
estimatedHistoryTokens:
|
|
57851
|
+
estimatedHistoryTokens: surface ? convTokensOf(hist) : estimated,
|
|
56422
57852
|
contextLimit,
|
|
56423
57853
|
occupancy,
|
|
56424
57854
|
compactSummary: compactSummary || void 0,
|
|
56425
57855
|
messagesRemoved: messagesRemoved || void 0,
|
|
56426
|
-
...
|
|
57856
|
+
...compactRange.fromSeq !== void 0 && compactRange.toSeq !== void 0 ? {
|
|
57857
|
+
compactedFromSeq: compactRange.fromSeq,
|
|
57858
|
+
compactedToSeq: compactRange.toSeq,
|
|
57859
|
+
compactSourceSeqs: compactRange.sourceSeqs,
|
|
57860
|
+
compactStrategy: compactRange.strategy
|
|
57861
|
+
} : {},
|
|
57862
|
+
...surface ? { contextPressureTokens: estimated } : {},
|
|
56427
57863
|
...cacheReuseExpected !== void 0 ? { cacheReuseExpected } : {},
|
|
56428
57864
|
...cacheMetricsLine ? { cacheMetricsLine } : {}
|
|
56429
57865
|
};
|
|
@@ -56458,6 +57894,231 @@ function estimateConversationTokensLite(messages) {
|
|
|
56458
57894
|
return n;
|
|
56459
57895
|
}
|
|
56460
57896
|
|
|
57897
|
+
// src/cli/budget/requestMeter.ts
|
|
57898
|
+
init_harness();
|
|
57899
|
+
function estimateTokensLocal(text) {
|
|
57900
|
+
if (!text) return 0;
|
|
57901
|
+
return Math.max(1, Math.ceil(text.length / 4));
|
|
57902
|
+
}
|
|
57903
|
+
var MESSAGE_OVERHEAD_TOKENS = 4;
|
|
57904
|
+
function estimateMessageTokens(m) {
|
|
57905
|
+
let n = MESSAGE_OVERHEAD_TOKENS + estimateTokensLocal(m.content ?? "");
|
|
57906
|
+
if (m.toolCalls) {
|
|
57907
|
+
for (const tc of m.toolCalls) {
|
|
57908
|
+
n += estimateTokensLocal(tc.name) + estimateTokensLocal(tc.id);
|
|
57909
|
+
n += estimateTokensLocal(JSON.stringify(tc.args ?? {}));
|
|
57910
|
+
}
|
|
57911
|
+
}
|
|
57912
|
+
if (m.reasoningContent) n += estimateTokensLocal(m.reasoningContent);
|
|
57913
|
+
if (m.toolCallId) n += estimateTokensLocal(m.toolCallId);
|
|
57914
|
+
return n;
|
|
57915
|
+
}
|
|
57916
|
+
function estimateToolSchemaTokens(tools) {
|
|
57917
|
+
let n = 0;
|
|
57918
|
+
for (const t of tools) {
|
|
57919
|
+
n += estimateTokensLocal(t.name) + estimateTokensLocal(t.description ?? "");
|
|
57920
|
+
n += estimateTokensLocal(JSON.stringify(t.parameters ?? {}));
|
|
57921
|
+
}
|
|
57922
|
+
return n + tools.length * MESSAGE_OVERHEAD_TOKENS;
|
|
57923
|
+
}
|
|
57924
|
+
function estimateSystemTokens(systemMessages) {
|
|
57925
|
+
let n = 0;
|
|
57926
|
+
for (const m of systemMessages) n += estimateMessageTokens(m);
|
|
57927
|
+
return n;
|
|
57928
|
+
}
|
|
57929
|
+
function estimateConversationTokens(conversation) {
|
|
57930
|
+
let n = 0;
|
|
57931
|
+
for (const m of conversation) n += estimateMessageTokens(m);
|
|
57932
|
+
return n;
|
|
57933
|
+
}
|
|
57934
|
+
function createFingerprintOnly(input) {
|
|
57935
|
+
return sha256Hex(
|
|
57936
|
+
stableStringify({
|
|
57937
|
+
provider: input.provider,
|
|
57938
|
+
model: input.model,
|
|
57939
|
+
systemMessages: input.systemMessages,
|
|
57940
|
+
tools: canonicalTools(input.tools)
|
|
57941
|
+
})
|
|
57942
|
+
);
|
|
57943
|
+
}
|
|
57944
|
+
function measureRequest(input) {
|
|
57945
|
+
const estimatedHeaderTokens = estimateSystemTokens(input.systemMessages) + estimateToolSchemaTokens(input.tools);
|
|
57946
|
+
const currentConversationTokens = estimateConversationTokens(input.conversation);
|
|
57947
|
+
let headerAnchored = false;
|
|
57948
|
+
let headerTokens = estimatedHeaderTokens;
|
|
57949
|
+
const anchorUsage = input.anchor?.usage;
|
|
57950
|
+
const anchorSnapshot = input.anchor?.snapshot;
|
|
57951
|
+
if (anchorUsage && anchorSnapshot) {
|
|
57952
|
+
const currentHeaderFp = createFingerprintOnly({
|
|
57953
|
+
provider: anchorSnapshot.provider,
|
|
57954
|
+
model: anchorSnapshot.model,
|
|
57955
|
+
systemMessages: input.systemMessages,
|
|
57956
|
+
tools: input.tools
|
|
57957
|
+
});
|
|
57958
|
+
if (currentHeaderFp === anchorSnapshot.headerFingerprint) {
|
|
57959
|
+
const anchorConv = estimateConversationTokens(anchorSnapshot.conversation);
|
|
57960
|
+
const headerFromUsage = Math.max(0, anchorUsage.promptTokens - anchorConv);
|
|
57961
|
+
if (headerFromUsage > 0) {
|
|
57962
|
+
headerTokens = headerFromUsage;
|
|
57963
|
+
headerAnchored = true;
|
|
57964
|
+
}
|
|
57965
|
+
}
|
|
57966
|
+
}
|
|
57967
|
+
const estimatedPromptTokens = headerTokens + currentConversationTokens;
|
|
57968
|
+
const reservedOutput = input.reservedOutputTokens ?? 0;
|
|
57969
|
+
const contextPressureTokens = estimatedPromptTokens + reservedOutput;
|
|
57970
|
+
return {
|
|
57971
|
+
estimatedPromptTokens,
|
|
57972
|
+
estimatedHeaderTokens,
|
|
57973
|
+
headerAnchored,
|
|
57974
|
+
contextPressureTokens,
|
|
57975
|
+
occupancy: Math.min(1, contextPressureTokens / input.contextLimit),
|
|
57976
|
+
purpose: input.purpose ?? "conversation"
|
|
57977
|
+
};
|
|
57978
|
+
}
|
|
57979
|
+
|
|
57980
|
+
// src/cli/budget/persistCompact.ts
|
|
57981
|
+
init_dist();
|
|
57982
|
+
init_session();
|
|
57983
|
+
init_headlessSpine();
|
|
57984
|
+
function compactEventPayload(budget, stateSnapshot, telemetry) {
|
|
57985
|
+
const summary = budget.compactSummary ?? "";
|
|
57986
|
+
const first = budget.history[0];
|
|
57987
|
+
const narrative = first?.role === "user" && first.content.includes("<compacted-summary>") ? first.content : summary;
|
|
57988
|
+
const checkpointContent2 = stateSnapshot ? formatCompactionStateSnapshot(stateSnapshot) + "\n\n" + narrative : narrative;
|
|
57989
|
+
const ranged = budget.compactedFromSeq !== void 0 && budget.compactedToSeq !== void 0;
|
|
57990
|
+
return {
|
|
57991
|
+
summary,
|
|
57992
|
+
messagesRemoved: budget.messagesRemoved ?? 0,
|
|
57993
|
+
...telemetry ? { ...telemetry } : {},
|
|
57994
|
+
...ranged ? {
|
|
57995
|
+
fromSeq: budget.compactedFromSeq,
|
|
57996
|
+
toSeq: budget.compactedToSeq,
|
|
57997
|
+
checkpoint: { role: "user", content: checkpointContent2 },
|
|
57998
|
+
...budget.compactStrategy ? { strategy: budget.compactStrategy } : {},
|
|
57999
|
+
...budget.compactSourceSeqs && budget.compactSourceSeqs.length > 0 ? { sourceEventSeqs: budget.compactSourceSeqs } : {},
|
|
58000
|
+
...stateSnapshot ? {
|
|
58001
|
+
retainedCriterionIds: stateSnapshot.activeCriteria.filter((criterion) => criterion.required).map((criterion) => criterion.id),
|
|
58002
|
+
retainedEvidenceRefs: stateSnapshot.retainedEvidenceRefs,
|
|
58003
|
+
retainedState: {
|
|
58004
|
+
unresolvedIssueIds: stateSnapshot.unresolvedIssues.map((issue2) => issue2.id),
|
|
58005
|
+
affectedFiles: stateSnapshot.affectedFiles,
|
|
58006
|
+
...stateSnapshot.missionState?.phase ? { missionStateRef: "phase:" + stateSnapshot.missionState.phase } : {}
|
|
58007
|
+
},
|
|
58008
|
+
stateSnapshot
|
|
58009
|
+
} : {}
|
|
58010
|
+
} : {}
|
|
58011
|
+
};
|
|
58012
|
+
}
|
|
58013
|
+
|
|
58014
|
+
// src/cli/budget/modelContextBuilder.ts
|
|
58015
|
+
init_headlessSpine();
|
|
58016
|
+
function messageWasRecompacted(message, history2) {
|
|
58017
|
+
if (message.compactedFromSeq === void 0) return false;
|
|
58018
|
+
return !history2.some((candidate) => candidate.seq !== void 0 && candidate.seq === message.seq);
|
|
58019
|
+
}
|
|
58020
|
+
async function sessionHistory(session) {
|
|
58021
|
+
if (!session || session.status !== "active") return null;
|
|
58022
|
+
const derived = await session.derivedPriorTurns();
|
|
58023
|
+
if (!derived || derived.length === 0) return null;
|
|
58024
|
+
return derivedModelSeed(derived);
|
|
58025
|
+
}
|
|
58026
|
+
async function buildModelContext(input) {
|
|
58027
|
+
const derived = await sessionHistory(input.session);
|
|
58028
|
+
const source = derived ? "session" : "fallback";
|
|
58029
|
+
const sourceHistory = derived ?? [...input.fallbackHistory];
|
|
58030
|
+
const inputTokens = estimateHistoryTokens(sourceHistory);
|
|
58031
|
+
const requestSurface = input.systemMessages || input.tools ? {
|
|
58032
|
+
provider: input.provider ?? "local",
|
|
58033
|
+
model: input.model ?? "unknown",
|
|
58034
|
+
systemMessages: input.systemMessages ?? [],
|
|
58035
|
+
tools: input.tools ?? []
|
|
58036
|
+
} : null;
|
|
58037
|
+
let budget = await applyBudgetPolicyAsync(sourceHistory, input.phase, {
|
|
58038
|
+
model: input.model,
|
|
58039
|
+
sessionTokens: input.sessionTokens,
|
|
58040
|
+
sessionId: input.sessionId,
|
|
58041
|
+
signal: input.signal,
|
|
58042
|
+
requestSnapshot: input.requestSnapshot,
|
|
58043
|
+
requestSurface,
|
|
58044
|
+
providerStream: input.providerStream
|
|
58045
|
+
});
|
|
58046
|
+
let history2 = budget.history;
|
|
58047
|
+
let compactionPayload;
|
|
58048
|
+
let durableCompaction = false;
|
|
58049
|
+
let reconstructedFromSession = false;
|
|
58050
|
+
let compactionMetrics;
|
|
58051
|
+
if ((budget.messagesRemoved ?? 0) > 0) {
|
|
58052
|
+
const ranged = budget.compactedFromSeq !== void 0 && budget.compactedToSeq !== void 0;
|
|
58053
|
+
const stateSnapshot = ranged && input.session?.compactionStateSnapshot ? await input.session.compactionStateSnapshot(budget.compactedToSeq) : null;
|
|
58054
|
+
const outputTokens = estimateHistoryTokens(budget.history);
|
|
58055
|
+
const telemetry = {
|
|
58056
|
+
inputTokens,
|
|
58057
|
+
outputTokens,
|
|
58058
|
+
savedTokens: Math.max(0, inputTokens - outputTokens),
|
|
58059
|
+
recompactionRate: sourceHistory.some(
|
|
58060
|
+
(message) => messageWasRecompacted(message, budget.history)
|
|
58061
|
+
) ? 1 : 0,
|
|
58062
|
+
summaryStrategy: budget.compactStrategy ?? "extractive",
|
|
58063
|
+
...budget.compactStrategy === "llm" && input.provider ? { provider: input.provider } : {},
|
|
58064
|
+
...budget.compactStrategy === "llm" && input.model ? { model: input.model } : {}
|
|
58065
|
+
};
|
|
58066
|
+
compactionPayload = compactEventPayload(budget, stateSnapshot, telemetry);
|
|
58067
|
+
if (input.persistCompaction) {
|
|
58068
|
+
await input.persistCompaction(compactionPayload, budget);
|
|
58069
|
+
await input.session?.flush?.();
|
|
58070
|
+
if (ranged && input.session?.status === "active") {
|
|
58071
|
+
const replayed = await sessionHistory(input.session);
|
|
58072
|
+
if (replayed) {
|
|
58073
|
+
history2 = replayed;
|
|
58074
|
+
durableCompaction = true;
|
|
58075
|
+
reconstructedFromSession = true;
|
|
58076
|
+
}
|
|
58077
|
+
}
|
|
58078
|
+
}
|
|
58079
|
+
compactionMetrics = {
|
|
58080
|
+
count: 1,
|
|
58081
|
+
...telemetry,
|
|
58082
|
+
restoreFailures: ranged && input.persistCompaction && !reconstructedFromSession ? 1 : 0
|
|
58083
|
+
};
|
|
58084
|
+
input.onCompactionMetric?.(compactionMetrics);
|
|
58085
|
+
}
|
|
58086
|
+
if (requestSurface) {
|
|
58087
|
+
const measured = measureRequest({
|
|
58088
|
+
systemMessages: requestSurface.systemMessages,
|
|
58089
|
+
tools: requestSurface.tools,
|
|
58090
|
+
conversation: history2,
|
|
58091
|
+
anchor: input.requestSnapshot,
|
|
58092
|
+
contextLimit: budget.contextLimit,
|
|
58093
|
+
reservedOutputTokens: 8192
|
|
58094
|
+
});
|
|
58095
|
+
budget = {
|
|
58096
|
+
...budget,
|
|
58097
|
+
history: history2,
|
|
58098
|
+
estimatedHistoryTokens: estimateHistoryTokens(history2),
|
|
58099
|
+
occupancy: measured.occupancy,
|
|
58100
|
+
contextPressureTokens: measured.contextPressureTokens
|
|
58101
|
+
};
|
|
58102
|
+
} else {
|
|
58103
|
+
const estimated = estimateHistoryTokens(history2);
|
|
58104
|
+
budget = {
|
|
58105
|
+
...budget,
|
|
58106
|
+
history: history2,
|
|
58107
|
+
estimatedHistoryTokens: estimated,
|
|
58108
|
+
occupancy: Math.min(1, estimated / budget.contextLimit)
|
|
58109
|
+
};
|
|
58110
|
+
}
|
|
58111
|
+
return {
|
|
58112
|
+
history: history2,
|
|
58113
|
+
budget,
|
|
58114
|
+
source,
|
|
58115
|
+
...compactionPayload ? { compactionPayload } : {},
|
|
58116
|
+
...compactionMetrics ? { compactionMetrics } : {},
|
|
58117
|
+
durableCompaction,
|
|
58118
|
+
reconstructedFromSession
|
|
58119
|
+
};
|
|
58120
|
+
}
|
|
58121
|
+
|
|
56461
58122
|
// src/cli/hooks/useChatTurn.ts
|
|
56462
58123
|
init_requestSnapshotStore();
|
|
56463
58124
|
function useChatTurn(params) {
|
|
@@ -56493,19 +58154,7 @@ function useChatTurn(params) {
|
|
|
56493
58154
|
try {
|
|
56494
58155
|
const anchored = maybeAnchorShortAnswer(userText);
|
|
56495
58156
|
const effectiveUserText = anchored ?? userText;
|
|
56496
|
-
let historyForModel;
|
|
56497
|
-
{
|
|
56498
|
-
const mirror = writerRef.current?.spine ?? null;
|
|
56499
|
-
let spineSeed = null;
|
|
56500
|
-
if (mirror && mirror.status === "active") {
|
|
56501
|
-
const derived = await mirror.derivedPriorTurns();
|
|
56502
|
-
if (derived && derived.length > 0) {
|
|
56503
|
-
spineSeed = derivedModelSeed(derived);
|
|
56504
|
-
}
|
|
56505
|
-
}
|
|
56506
|
-
historyForModel = spineSeed ?? getHistory();
|
|
56507
|
-
}
|
|
56508
|
-
writerRef.current?.spine?.userMessage(effectiveUserText);
|
|
58157
|
+
let historyForModel = getHistory();
|
|
56509
58158
|
const localCli = (process.env.ZELARI_LOCAL_CLI ?? "").trim();
|
|
56510
58159
|
let localCliProvider = null;
|
|
56511
58160
|
if (localCli) {
|
|
@@ -56547,7 +58196,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
56547
58196
|
let settled = false;
|
|
56548
58197
|
const askTimeoutMs = askUserTimeoutMs();
|
|
56549
58198
|
let cancelAskTimeout = () => void 0;
|
|
56550
|
-
const
|
|
58199
|
+
const finish2 = (value) => {
|
|
56551
58200
|
if (settled) return;
|
|
56552
58201
|
settled = true;
|
|
56553
58202
|
cancelAskTimeout();
|
|
@@ -56563,7 +58212,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
56563
58212
|
)}s \u2014 proseguo con assunzione documentata (ZELARI_ASK_USER_TIMEOUT_MS).`,
|
|
56564
58213
|
Date.now()
|
|
56565
58214
|
);
|
|
56566
|
-
|
|
58215
|
+
finish2(null);
|
|
56567
58216
|
},
|
|
56568
58217
|
askTimeoutMs
|
|
56569
58218
|
);
|
|
@@ -56571,8 +58220,8 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
56571
58220
|
kind: "clarification",
|
|
56572
58221
|
title: req.question,
|
|
56573
58222
|
items: choices.map((c) => ({ value: c, label: c })),
|
|
56574
|
-
onAnswer: (value) =>
|
|
56575
|
-
onCancel: () =>
|
|
58223
|
+
onAnswer: (value) => finish2(value),
|
|
58224
|
+
onCancel: () => finish2(null)
|
|
56576
58225
|
});
|
|
56577
58226
|
}) : void 0;
|
|
56578
58227
|
const onPermissionAsk = setPicker2 ? createPermissionAskHandler({
|
|
@@ -56634,33 +58283,42 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
56634
58283
|
});
|
|
56635
58284
|
}
|
|
56636
58285
|
const cwd = process.cwd();
|
|
56637
|
-
const
|
|
58286
|
+
const requestSnapshot = getRequestSnapshotWithUsage(sessionId2);
|
|
58287
|
+
const modelContext = await buildModelContext({
|
|
58288
|
+
fallbackHistory: historyForModel,
|
|
58289
|
+
session: writerRef.current?.spine ?? null,
|
|
58290
|
+
phase: workPhase,
|
|
56638
58291
|
model: getActiveModel(),
|
|
58292
|
+
provider: envConfig?.providerId ?? (localCli || "local"),
|
|
56639
58293
|
sessionId: sessionId2,
|
|
56640
|
-
|
|
56641
|
-
|
|
56642
|
-
|
|
56643
|
-
|
|
58294
|
+
requestSnapshot,
|
|
58295
|
+
providerStream,
|
|
58296
|
+
onCompactionMetric: (metrics2) => recordCompactionMetrics(
|
|
58297
|
+
sessionId2,
|
|
58298
|
+
envConfig?.providerId ?? (localCli || "local"),
|
|
58299
|
+
getActiveModel(),
|
|
58300
|
+
metrics2
|
|
58301
|
+
),
|
|
58302
|
+
persistCompaction: async (payload, compactBudget) => {
|
|
58303
|
+
const compactionEvent = createBrainEvent("session_compacted", sessionId2, {
|
|
58304
|
+
...payload,
|
|
58305
|
+
...requestSnapshot ? {
|
|
58306
|
+
sourceRequestFingerprint: requestSnapshot.snapshot.requestFingerprint,
|
|
58307
|
+
headerFingerprint: requestSnapshot.snapshot.headerFingerprint
|
|
58308
|
+
} : {},
|
|
58309
|
+
...compactBudget.contextPressureTokens !== void 0 ? { sourceEstimatedTokens: compactBudget.contextPressureTokens } : {},
|
|
58310
|
+
...compactBudget.cacheReuseExpected !== void 0 ? { cacheReuseExpected: compactBudget.cacheReuseExpected } : {}
|
|
58311
|
+
});
|
|
58312
|
+
await writerRef.current?.append(compactionEvent);
|
|
58313
|
+
}
|
|
56644
58314
|
});
|
|
56645
|
-
|
|
56646
|
-
|
|
56647
|
-
|
|
56648
|
-
|
|
56649
|
-
|
|
56650
|
-
const envelope = getRequestSnapshotWithUsage(sessionId2);
|
|
56651
|
-
const compactionEvent = createBrainEvent("session_compacted", sessionId2, {
|
|
56652
|
-
summary: budget.compactSummary ?? "",
|
|
56653
|
-
messagesRemoved: budget.messagesRemoved ?? 0,
|
|
56654
|
-
...envelope ? {
|
|
56655
|
-
sourceRequestFingerprint: envelope.snapshot.requestFingerprint,
|
|
56656
|
-
headerFingerprint: envelope.snapshot.headerFingerprint
|
|
56657
|
-
} : {},
|
|
56658
|
-
...budget.contextPressureTokens !== void 0 ? { sourceEstimatedTokens: budget.contextPressureTokens } : {},
|
|
56659
|
-
...budget.cacheReuseExpected !== void 0 ? { cacheReuseExpected: budget.cacheReuseExpected } : {}
|
|
56660
|
-
});
|
|
56661
|
-
void writerRef.current?.append(compactionEvent);
|
|
58315
|
+
const budget = modelContext.budget;
|
|
58316
|
+
historyForModel = modelContext.history;
|
|
58317
|
+
setHistory(historyForModel);
|
|
58318
|
+
for (const warning of budget.warnings) {
|
|
58319
|
+
appendSystem(setMessages, warning, Date.now());
|
|
56662
58320
|
}
|
|
56663
|
-
|
|
58321
|
+
writerRef.current?.spine?.userMessage(effectiveUserText);
|
|
56664
58322
|
historySeedLen = historyForModel.length;
|
|
56665
58323
|
let composedWorkspace = "";
|
|
56666
58324
|
let composedInstructions = "";
|
|
@@ -57299,33 +58957,33 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
57299
58957
|
return { completionOk: false, ran: false };
|
|
57300
58958
|
}
|
|
57301
58959
|
setBusy(true);
|
|
57302
|
-
|
|
57303
|
-
|
|
57304
|
-
|
|
57305
|
-
|
|
57306
|
-
|
|
57307
|
-
|
|
57308
|
-
|
|
57309
|
-
|
|
58960
|
+
const anchored = maybeAnchorShortAnswer(text);
|
|
58961
|
+
const effectiveText = anchored ?? text;
|
|
58962
|
+
const councilContext = await buildModelContext({
|
|
58963
|
+
fallbackHistory: getHistory(),
|
|
58964
|
+
session: writerRef.current?.spine ?? null,
|
|
58965
|
+
phase: getPhase(),
|
|
58966
|
+
model: envConfig.model,
|
|
58967
|
+
provider: envConfig.providerId,
|
|
58968
|
+
sessionId: sessionId2,
|
|
58969
|
+
onCompactionMetric: (metrics) => recordCompactionMetrics(
|
|
58970
|
+
sessionId2,
|
|
58971
|
+
envConfig.providerId,
|
|
58972
|
+
envConfig.model,
|
|
58973
|
+
metrics
|
|
58974
|
+
),
|
|
58975
|
+
persistCompaction: async (payload) => {
|
|
58976
|
+
await writerRef.current?.append(
|
|
58977
|
+
createBrainEvent("session_compacted", sessionId2, payload)
|
|
58978
|
+
);
|
|
57310
58979
|
}
|
|
57311
|
-
}
|
|
57312
|
-
const councilBudget = await applyBudgetPolicyAsync(councilHistory, getPhase(), {
|
|
57313
|
-
model: envConfig.model
|
|
57314
58980
|
});
|
|
57315
|
-
|
|
57316
|
-
|
|
57317
|
-
|
|
58981
|
+
const councilBudget = councilContext.budget;
|
|
58982
|
+
setHistory(councilContext.history);
|
|
58983
|
+
for (const warning of councilBudget.warnings) {
|
|
58984
|
+
appendSystem(setMessages, warning, Date.now());
|
|
57318
58985
|
}
|
|
57319
|
-
|
|
57320
|
-
void writerRef.current?.append(
|
|
57321
|
-
createBrainEvent("session_compacted", sessionId2, {
|
|
57322
|
-
summary: councilBudget.compactSummary ?? "",
|
|
57323
|
-
messagesRemoved: councilBudget.messagesRemoved ?? 0
|
|
57324
|
-
})
|
|
57325
|
-
);
|
|
57326
|
-
}
|
|
57327
|
-
const anchored = maybeAnchorShortAnswer(text);
|
|
57328
|
-
const effectiveText = anchored ?? text;
|
|
58986
|
+
writerRef.current?.spine?.userMessage(effectiveText);
|
|
57329
58987
|
appendSystem(
|
|
57330
58988
|
setMessages,
|
|
57331
58989
|
`[phase] ${describePhase(getPhase())}`,
|
|
@@ -57361,7 +59019,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
57361
59019
|
let settled = false;
|
|
57362
59020
|
const askTimeoutMs = askUserTimeoutMs();
|
|
57363
59021
|
let cancelAskTimeout = () => void 0;
|
|
57364
|
-
const
|
|
59022
|
+
const finish2 = (value) => {
|
|
57365
59023
|
if (settled) return;
|
|
57366
59024
|
settled = true;
|
|
57367
59025
|
cancelAskTimeout();
|
|
@@ -57377,7 +59035,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
57377
59035
|
)}s \u2014 il membro prosegue con assunzione documentata (ZELARI_ASK_USER_TIMEOUT_MS).`,
|
|
57378
59036
|
Date.now()
|
|
57379
59037
|
);
|
|
57380
|
-
|
|
59038
|
+
finish2(null);
|
|
57381
59039
|
},
|
|
57382
59040
|
askTimeoutMs
|
|
57383
59041
|
);
|
|
@@ -57385,8 +59043,8 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
57385
59043
|
kind: "clarification",
|
|
57386
59044
|
title: req.question,
|
|
57387
59045
|
items: choices.map((c) => ({ value: c, label: c })),
|
|
57388
|
-
onAnswer: (value) =>
|
|
57389
|
-
onCancel: () =>
|
|
59046
|
+
onAnswer: (value) => finish2(value),
|
|
59047
|
+
onCancel: () => finish2(null)
|
|
57390
59048
|
});
|
|
57391
59049
|
}) : void 0;
|
|
57392
59050
|
let phaseRunMode = overrides.runMode ?? (workPhase === "plan" ? "design-phase" : "implementation");
|
|
@@ -57530,7 +59188,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
57530
59188
|
Date.now()
|
|
57531
59189
|
);
|
|
57532
59190
|
let settled = false;
|
|
57533
|
-
const
|
|
59191
|
+
const finish2 = (value) => {
|
|
57534
59192
|
if (settled) return;
|
|
57535
59193
|
settled = true;
|
|
57536
59194
|
setPicker2(null);
|
|
@@ -57540,8 +59198,8 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
57540
59198
|
kind: "clarification",
|
|
57541
59199
|
title: req.question,
|
|
57542
59200
|
items: choices.map((c) => ({ value: c, label: c })),
|
|
57543
|
-
onAnswer: (value) =>
|
|
57544
|
-
onCancel: () =>
|
|
59201
|
+
onAnswer: (value) => finish2(value),
|
|
59202
|
+
onCancel: () => finish2(null)
|
|
57545
59203
|
});
|
|
57546
59204
|
}) : void 0
|
|
57547
59205
|
})) {
|
|
@@ -58146,7 +59804,7 @@ function usePermissionBroker(opts) {
|
|
|
58146
59804
|
}
|
|
58147
59805
|
let settled = false;
|
|
58148
59806
|
let cancelWaitTimeout;
|
|
58149
|
-
const
|
|
59807
|
+
const finish2 = (value) => {
|
|
58150
59808
|
if (settled) return;
|
|
58151
59809
|
settled = true;
|
|
58152
59810
|
cancelWaitTimeout?.();
|
|
@@ -58162,7 +59820,7 @@ function usePermissionBroker(opts) {
|
|
|
58162
59820
|
)}s \u2014 richiesta annullata.`,
|
|
58163
59821
|
Date.now()
|
|
58164
59822
|
);
|
|
58165
|
-
|
|
59823
|
+
finish2(null);
|
|
58166
59824
|
}, waitTimeoutMs);
|
|
58167
59825
|
appendSystem(
|
|
58168
59826
|
setMessages,
|
|
@@ -58174,8 +59832,8 @@ function usePermissionBroker(opts) {
|
|
|
58174
59832
|
kind: "clarification",
|
|
58175
59833
|
title: req.question,
|
|
58176
59834
|
items: choices.map((c) => ({ value: c, label: c })),
|
|
58177
|
-
onAnswer: (value) =>
|
|
58178
|
-
onCancel: () =>
|
|
59835
|
+
onAnswer: (value) => finish2(value),
|
|
59836
|
+
onCancel: () => finish2(null)
|
|
58179
59837
|
});
|
|
58180
59838
|
});
|
|
58181
59839
|
void startPermissionBroker(socketPath, {
|
|
@@ -62280,7 +63938,7 @@ function verifierReviewEnabled(selection = loadVerifierModelSelection(), env = p
|
|
|
62280
63938
|
if (v === "1" || v === "true" || v === "on") return true;
|
|
62281
63939
|
return selection.mode === "fixed";
|
|
62282
63940
|
}
|
|
62283
|
-
function makeVerifierCallModel(loadStream, identity,
|
|
63941
|
+
function makeVerifierCallModel(loadStream, identity, timeoutMs2 = 12e4) {
|
|
62284
63942
|
return async ({ system, user }) => {
|
|
62285
63943
|
const stream = await loadStream(identity.provider, identity.model);
|
|
62286
63944
|
if (!stream) {
|
|
@@ -62294,7 +63952,7 @@ function makeVerifierCallModel(loadStream, identity, timeoutMs = 12e4) {
|
|
|
62294
63952
|
model: identity.model,
|
|
62295
63953
|
provider: identity.provider,
|
|
62296
63954
|
tools: [],
|
|
62297
|
-
signal: AbortSignal.timeout(
|
|
63955
|
+
signal: AbortSignal.timeout(timeoutMs2)
|
|
62298
63956
|
});
|
|
62299
63957
|
return { text, provider: identity.provider, model: identity.model };
|
|
62300
63958
|
};
|
|
@@ -62339,6 +63997,7 @@ async function runAdvisoryVerifierReview(evaluation, deps = {}) {
|
|
|
62339
63997
|
}
|
|
62340
63998
|
|
|
62341
63999
|
// src/cli/runHeadless.ts
|
|
64000
|
+
init_metrics2();
|
|
62342
64001
|
init_headlessSpine();
|
|
62343
64002
|
async function runHeadless(opts) {
|
|
62344
64003
|
resetTaskSpawnCount();
|
|
@@ -62451,6 +64110,18 @@ ${err.stack}` : "";
|
|
|
62451
64110
|
if (opts.krakenGraph) {
|
|
62452
64111
|
return runHeadlessKrakenGraph(opts, provider, model);
|
|
62453
64112
|
}
|
|
64113
|
+
const { shouldRunGauntletHostLoop: shouldRunGauntletHostLoop2 } = await Promise.resolve().then(() => (init_policy(), policy_exports));
|
|
64114
|
+
if (shouldRunGauntletHostLoop2(opts)) {
|
|
64115
|
+
const { runHeadlessGauntlet: runHeadlessGauntlet2 } = await Promise.resolve().then(() => (init_run(), run_exports));
|
|
64116
|
+
return runHeadlessGauntlet2(opts, provider, model);
|
|
64117
|
+
}
|
|
64118
|
+
if (opts.gauntlet) {
|
|
64119
|
+
const why = opts.krakenGraph ? "kraken-graph owns dispatch" : (opts.phase ?? "build") === "plan" ? "PLAN is already write-stripped; host loop is BUILD-only" : "mode is not kraken-build";
|
|
64120
|
+
const line = `[gauntlet] flag set but host loop skipped (${why})`;
|
|
64121
|
+
if (opts.output === "json") emitEvent({ type: "log", message: line });
|
|
64122
|
+
else process.stderr.write(`[zelari-code --headless] ${line}
|
|
64123
|
+
`);
|
|
64124
|
+
}
|
|
62454
64125
|
if (mode === "zelari") {
|
|
62455
64126
|
return runHeadlessZelari(opts, provider, model, providerStream);
|
|
62456
64127
|
}
|
|
@@ -62662,11 +64333,11 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
62662
64333
|
});
|
|
62663
64334
|
const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
|
|
62664
64335
|
emitEvent(sessionStartedEvent(spine));
|
|
62665
|
-
if (opts.task) spine.userMessage(opts.task);
|
|
62666
64336
|
resetKrakenCandidates();
|
|
62667
64337
|
resetKrakenTurnMetrics();
|
|
62668
64338
|
const { registry: toolRegistry } = createBuiltinToolRegistry({
|
|
62669
64339
|
planMode: planModeFromOpts(opts),
|
|
64340
|
+
gauntletParent: Boolean(opts.gauntlet) && !planModeFromOpts(opts),
|
|
62670
64341
|
// Fase 1 (ADR-0020): anchor tentacles to the provider/model THIS run
|
|
62671
64342
|
// resolved (--provider/--model opts or Desktop's selector), mirroring
|
|
62672
64343
|
// what the kraken-graph path already does for its executor.
|
|
@@ -62811,14 +64482,38 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
62811
64482
|
}
|
|
62812
64483
|
];
|
|
62813
64484
|
}
|
|
62814
|
-
const
|
|
64485
|
+
const modelContext = await buildModelContext({
|
|
64486
|
+
fallbackHistory: seededHistory.history,
|
|
64487
|
+
session: spine.spine,
|
|
64488
|
+
phase: opts.phase ?? "build",
|
|
64489
|
+
model,
|
|
64490
|
+
provider,
|
|
64491
|
+
systemMessages,
|
|
64492
|
+
tools,
|
|
64493
|
+
sessionId: spine.sessionId,
|
|
64494
|
+
providerStream,
|
|
64495
|
+
onCompactionMetric: (metrics) => recordCompactionMetrics(spine.sessionId, provider, model, metrics),
|
|
64496
|
+
persistCompaction: async (payload) => {
|
|
64497
|
+
await spine.appendEvent({
|
|
64498
|
+
kind: "session.compacted",
|
|
64499
|
+
actor: { type: "system" },
|
|
64500
|
+
data: { ...payload }
|
|
64501
|
+
});
|
|
64502
|
+
}
|
|
64503
|
+
});
|
|
64504
|
+
const historySeed = modelContext.history;
|
|
64505
|
+
for (const warning of modelContext.budget.warnings) {
|
|
64506
|
+
if (opts.output === "json") emitEvent({ type: "log", message: warning });
|
|
64507
|
+
else process.stderr.write("[zelari-code --headless] " + warning + "\n");
|
|
64508
|
+
}
|
|
62815
64509
|
const effectiveTask = buildAgentUserWithHistory(opts.task, historySeed);
|
|
64510
|
+
if (opts.task) spine.userMessage(effectiveTask);
|
|
62816
64511
|
const maxToolLoop = (() => {
|
|
62817
64512
|
const n = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, {
|
|
62818
64513
|
default: 30,
|
|
62819
64514
|
min: 1
|
|
62820
64515
|
});
|
|
62821
|
-
return n;
|
|
64516
|
+
return Math.min(n, modelContext.budget.maxToolLoopIterations);
|
|
62822
64517
|
})();
|
|
62823
64518
|
async function runSinglePass(messages, passSessionId) {
|
|
62824
64519
|
const harness = new AgentHarness({
|
|
@@ -63119,7 +64814,6 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
63119
64814
|
});
|
|
63120
64815
|
const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
|
|
63121
64816
|
emitEvent(sessionStartedEvent(spine));
|
|
63122
|
-
if (opts.task) spine.userMessage(opts.task);
|
|
63123
64817
|
const { shouldAllowCouncilBuild: shouldAllowCouncilBuild2 } = await Promise.resolve().then(() => (init_buildPolicy(), buildPolicy_exports));
|
|
63124
64818
|
let councilRunMode = planModeFromOpts(opts) ? "design-phase" : "implementation";
|
|
63125
64819
|
let softGated = false;
|
|
@@ -63136,8 +64830,36 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
63136
64830
|
);
|
|
63137
64831
|
const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
|
|
63138
64832
|
const feedbackStore = new FeedbackStore2();
|
|
63139
|
-
const
|
|
64833
|
+
const contextTools = toolRegistry.toOpenAITools().map((tool) => ({
|
|
64834
|
+
name: tool.function.name,
|
|
64835
|
+
description: tool.function.description,
|
|
64836
|
+
parameters: tool.function.parameters
|
|
64837
|
+
}));
|
|
64838
|
+
const councilContext = await buildModelContext({
|
|
64839
|
+
fallbackHistory: seededHistory.history,
|
|
64840
|
+
session: spine.spine,
|
|
64841
|
+
phase: councilRunMode === "design-phase" ? "plan" : "build",
|
|
64842
|
+
model,
|
|
64843
|
+
provider,
|
|
64844
|
+
tools: contextTools,
|
|
64845
|
+
sessionId: spine.sessionId,
|
|
64846
|
+
providerStream,
|
|
64847
|
+
onCompactionMetric: (metrics) => recordCompactionMetrics(spine.sessionId, provider, model, metrics),
|
|
64848
|
+
persistCompaction: async (payload) => {
|
|
64849
|
+
await spine.appendEvent({
|
|
64850
|
+
kind: "session.compacted",
|
|
64851
|
+
actor: { type: "system" },
|
|
64852
|
+
data: { ...payload }
|
|
64853
|
+
});
|
|
64854
|
+
}
|
|
64855
|
+
});
|
|
64856
|
+
const historySeed = councilContext.history;
|
|
64857
|
+
for (const warning of councilContext.budget.warnings) {
|
|
64858
|
+
if (opts.output === "json") emitEvent({ type: "log", message: warning });
|
|
64859
|
+
else process.stderr.write("[zelari-code --headless] " + warning + "\n");
|
|
64860
|
+
}
|
|
63140
64861
|
const effectiveTask = buildCouncilTaskWithHistory(opts.task, historySeed);
|
|
64862
|
+
if (opts.task) spine.userMessage(effectiveTask);
|
|
63141
64863
|
let exitCode = 0;
|
|
63142
64864
|
const scrub = createStreamScrubber2();
|
|
63143
64865
|
let lastAssistantText = "";
|
|
@@ -63247,7 +64969,6 @@ async function runHeadlessZelari(opts, provider, model, providerStream) {
|
|
|
63247
64969
|
});
|
|
63248
64970
|
const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
|
|
63249
64971
|
emitEvent(sessionStartedEvent(spine));
|
|
63250
|
-
if (opts.task) spine.userMessage(opts.task);
|
|
63251
64972
|
spine.missionPhase("design", "mission-start");
|
|
63252
64973
|
const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
63253
64974
|
const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
|
|
@@ -63279,8 +65000,33 @@ async function runHeadlessZelari(opts, provider, model, providerStream) {
|
|
|
63279
65000
|
process.stderr.write(message + "\n");
|
|
63280
65001
|
}
|
|
63281
65002
|
};
|
|
63282
|
-
const
|
|
65003
|
+
const contextTools = toolRegistry.toOpenAITools().map((tool) => ({
|
|
65004
|
+
name: tool.function.name,
|
|
65005
|
+
description: tool.function.description,
|
|
65006
|
+
parameters: tool.function.parameters
|
|
65007
|
+
}));
|
|
65008
|
+
const missionContext = await buildModelContext({
|
|
65009
|
+
fallbackHistory: seededHistory.history,
|
|
65010
|
+
session: spine.spine,
|
|
65011
|
+
phase: opts.phase ?? "build",
|
|
65012
|
+
model,
|
|
65013
|
+
provider,
|
|
65014
|
+
tools: contextTools,
|
|
65015
|
+
sessionId: spine.sessionId,
|
|
65016
|
+
providerStream,
|
|
65017
|
+
onCompactionMetric: (metrics) => recordCompactionMetrics(spine.sessionId, provider, model, metrics),
|
|
65018
|
+
persistCompaction: async (payload) => {
|
|
65019
|
+
await spine.appendEvent({
|
|
65020
|
+
kind: "session.compacted",
|
|
65021
|
+
actor: { type: "system" },
|
|
65022
|
+
data: { ...payload }
|
|
65023
|
+
});
|
|
65024
|
+
}
|
|
65025
|
+
});
|
|
65026
|
+
const historySeed = missionContext.history;
|
|
65027
|
+
for (const warning of missionContext.budget.warnings) emit(warning);
|
|
63283
65028
|
const missionTask = buildCouncilTaskWithHistory(opts.task, historySeed);
|
|
65029
|
+
if (opts.task) spine.userMessage(missionTask);
|
|
63284
65030
|
emit(`[zelari] mission brief
|
|
63285
65031
|
${JSON.stringify({ deliverable: brief.deliverableThisMission, mvp: brief.sliceMvp?.title }, null, 0)}`);
|
|
63286
65032
|
if (buildViaAgent) {
|