zelari-code 2.4.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/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 +1891 -1023
- 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 +91 -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/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -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();
|
|
@@ -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();
|
|
@@ -40354,717 +40831,171 @@ var init_toolRegistry = __esm({
|
|
|
40354
40831
|
}
|
|
40355
40832
|
});
|
|
40356
40833
|
|
|
40357
|
-
// src/cli/
|
|
40358
|
-
|
|
40359
|
-
|
|
40360
|
-
|
|
40361
|
-
|
|
40362
|
-
|
|
40363
|
-
describePhase: () => describePhase,
|
|
40364
|
-
nextPhase: () => nextPhase,
|
|
40365
|
-
parsePhase: () => parsePhase
|
|
40366
|
-
});
|
|
40367
|
-
function parsePhase(input) {
|
|
40368
|
-
const v = input.trim().toLowerCase();
|
|
40369
|
-
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);
|
|
40370
40840
|
}
|
|
40371
|
-
function
|
|
40372
|
-
|
|
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);
|
|
40373
40846
|
}
|
|
40374
|
-
function
|
|
40375
|
-
|
|
40376
|
-
|
|
40377
|
-
|
|
40378
|
-
|
|
40379
|
-
|
|
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;
|
|
40380
40853
|
}
|
|
40381
40854
|
}
|
|
40382
|
-
|
|
40383
|
-
|
|
40384
|
-
|
|
40385
|
-
|
|
40386
|
-
|
|
40387
|
-
|
|
40388
|
-
|
|
40389
|
-
|
|
40390
|
-
|
|
40391
|
-
|
|
40392
|
-
|
|
40393
|
-
|
|
40394
|
-
|
|
40395
|
-
"linkDocuments"
|
|
40396
|
-
// Soft writes that only touch .zelari / plan paths are still gated in
|
|
40397
|
-
// toolRegistry by path when needed; write_file/edit_file stay DENIED.
|
|
40398
|
-
]);
|
|
40399
|
-
PLAN_BLOCKED_TOOLS = /* @__PURE__ */ new Set([
|
|
40400
|
-
"write_file",
|
|
40401
|
-
"edit_file",
|
|
40402
|
-
"apply_diff",
|
|
40403
|
-
"bash"
|
|
40404
|
-
]);
|
|
40405
|
-
}
|
|
40406
|
-
});
|
|
40407
|
-
|
|
40408
|
-
// src/cli/mode.ts
|
|
40409
|
-
function nextMode(current) {
|
|
40410
|
-
const i = MODES.indexOf(current);
|
|
40411
|
-
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");
|
|
40412
40868
|
}
|
|
40413
|
-
function
|
|
40414
|
-
const
|
|
40415
|
-
|
|
40416
|
-
return MODE_ALIASES[v] ?? null;
|
|
40869
|
+
function stripStored(s) {
|
|
40870
|
+
const { artifactDir: _a3, ...meta3 } = s;
|
|
40871
|
+
return meta3;
|
|
40417
40872
|
}
|
|
40418
|
-
function
|
|
40419
|
-
|
|
40420
|
-
case "council":
|
|
40421
|
-
return "council \u2014 multi-member plan/design (Caronte\u2026Lucifero; build needs ZELARI_COUNCIL_CAN_BUILD=1)";
|
|
40422
|
-
case "zelari":
|
|
40423
|
-
return "zelari \u2014 mission: plan@council \u2192 build@kraken (legacy: ZELARI_BUILD_VIA_AGENT=0)";
|
|
40424
|
-
default:
|
|
40425
|
-
return "kraken \u2014 super-agent lead (spawns explore/general/verify tentacles; default implementer)";
|
|
40426
|
-
}
|
|
40873
|
+
function isStateEnabled(env = process.env) {
|
|
40874
|
+
return env.ZELARI_STATE !== "0";
|
|
40427
40875
|
}
|
|
40428
|
-
|
|
40429
|
-
|
|
40430
|
-
|
|
40431
|
-
|
|
40432
|
-
|
|
40433
|
-
|
|
40434
|
-
|
|
40435
|
-
|
|
40436
|
-
};
|
|
40437
|
-
}
|
|
40438
|
-
});
|
|
40439
|
-
|
|
40440
|
-
// src/cli/headless.ts
|
|
40441
|
-
import { readFileSync as readFileSync22 } from "node:fs";
|
|
40442
|
-
function defaultProfileForMode(mode) {
|
|
40443
|
-
switch (mode) {
|
|
40444
|
-
case "council":
|
|
40445
|
-
return "council/v1";
|
|
40446
|
-
case "zelari":
|
|
40447
|
-
return "mission/v1";
|
|
40448
|
-
default:
|
|
40449
|
-
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();
|
|
40450
40884
|
}
|
|
40451
40885
|
}
|
|
40452
|
-
function
|
|
40453
|
-
|
|
40454
|
-
|
|
40455
|
-
|
|
40456
|
-
|
|
40457
|
-
|
|
40458
|
-
|
|
40459
|
-
|
|
40460
|
-
|
|
40461
|
-
|
|
40462
|
-
|
|
40463
|
-
|
|
40464
|
-
|
|
40465
|
-
|
|
40466
|
-
|
|
40467
|
-
|
|
40468
|
-
|
|
40469
|
-
|
|
40470
|
-
|
|
40471
|
-
|
|
40472
|
-
|
|
40473
|
-
|
|
40474
|
-
|
|
40475
|
-
|
|
40476
|
-
const arg = argv[i];
|
|
40477
|
-
if (arg === "--headless") continue;
|
|
40478
|
-
if (arg === "--output") {
|
|
40479
|
-
const next = argv[i + 1];
|
|
40480
|
-
if (next === "json" || next === "plain") {
|
|
40481
|
-
output = next;
|
|
40482
|
-
i++;
|
|
40483
|
-
} else {
|
|
40484
|
-
return {
|
|
40485
|
-
options: null,
|
|
40486
|
-
error: `--output requires 'json' or 'plain', got '${next ?? "(missing)"}'`
|
|
40487
|
-
};
|
|
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 });
|
|
40488
40910
|
}
|
|
40489
|
-
|
|
40490
|
-
|
|
40491
|
-
|
|
40492
|
-
|
|
40493
|
-
|
|
40494
|
-
if (next) {
|
|
40495
|
-
try {
|
|
40496
|
-
const fromFile = readFileSync22(next, "utf-8");
|
|
40497
|
-
if (fromFile.trim()) task = fromFile;
|
|
40498
|
-
} 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
|
+
);
|
|
40499
40916
|
}
|
|
40500
|
-
|
|
40501
|
-
|
|
40502
|
-
|
|
40503
|
-
|
|
40504
|
-
|
|
40505
|
-
|
|
40506
|
-
|
|
40507
|
-
|
|
40508
|
-
|
|
40509
|
-
|
|
40510
|
-
|
|
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, "/")
|
|
40511
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);
|
|
40512
40949
|
}
|
|
40513
|
-
|
|
40514
|
-
|
|
40515
|
-
|
|
40516
|
-
|
|
40517
|
-
const next = argv[i + 1];
|
|
40518
|
-
const parsed = next ? parsePhase(next) : null;
|
|
40519
|
-
if (!parsed) {
|
|
40520
|
-
return {
|
|
40521
|
-
options: null,
|
|
40522
|
-
error: `--phase requires 'plan' or 'build', got '${next ?? "(missing)"}'`
|
|
40523
|
-
};
|
|
40950
|
+
async head() {
|
|
40951
|
+
const head = await readJsonFile(this.headPath);
|
|
40952
|
+
if (!head?.id) return null;
|
|
40953
|
+
return this.get(head.id);
|
|
40524
40954
|
}
|
|
40525
|
-
|
|
40526
|
-
|
|
40527
|
-
|
|
40528
|
-
|
|
40529
|
-
|
|
40530
|
-
|
|
40531
|
-
|
|
40532
|
-
|
|
40533
|
-
|
|
40534
|
-
|
|
40535
|
-
if (next) {
|
|
40536
|
-
let raw = null;
|
|
40537
|
-
if (arg === "--history-file") {
|
|
40538
|
-
try {
|
|
40539
|
-
raw = readFileSync22(next, "utf-8");
|
|
40540
|
-
} catch {
|
|
40541
|
-
raw = null;
|
|
40542
|
-
}
|
|
40543
|
-
} else {
|
|
40544
|
-
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 [];
|
|
40545
40965
|
}
|
|
40546
|
-
|
|
40966
|
+
const ids = [];
|
|
40967
|
+
for (const line of raw.split("\n")) {
|
|
40968
|
+
const t = line.trim();
|
|
40969
|
+
if (!t) continue;
|
|
40547
40970
|
try {
|
|
40548
|
-
const
|
|
40549
|
-
if (
|
|
40550
|
-
history2 = parsedHist.filter(
|
|
40551
|
-
(m) => !!m && typeof m === "object" && typeof m.role === "string"
|
|
40552
|
-
).map((m) => {
|
|
40553
|
-
const role = String(m.role);
|
|
40554
|
-
const raw2 = m.content;
|
|
40555
|
-
const content = typeof raw2 === "string" ? raw2 : raw2 == null ? "" : typeof raw2 === "object" ? JSON.stringify(raw2) : String(raw2);
|
|
40556
|
-
const msg = {
|
|
40557
|
-
role,
|
|
40558
|
-
content
|
|
40559
|
-
};
|
|
40560
|
-
if (typeof m.toolCallId === "string") {
|
|
40561
|
-
msg.toolCallId = m.toolCallId;
|
|
40562
|
-
}
|
|
40563
|
-
return msg;
|
|
40564
|
-
}).filter(
|
|
40565
|
-
(m) => m.role === "user" || m.role === "assistant" || m.role === "tool" || m.role === "system"
|
|
40566
|
-
);
|
|
40567
|
-
}
|
|
40971
|
+
const row = JSON.parse(t);
|
|
40972
|
+
if (row.id) ids.push(row.id);
|
|
40568
40973
|
} catch {
|
|
40569
40974
|
}
|
|
40570
40975
|
}
|
|
40571
|
-
|
|
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;
|
|
40572
40983
|
}
|
|
40573
|
-
|
|
40574
|
-
|
|
40575
|
-
|
|
40576
|
-
|
|
40577
|
-
const parsed = JSON.parse(next);
|
|
40578
|
-
if (Array.isArray(parsed)) {
|
|
40579
|
-
todos2 = parsed.filter(
|
|
40580
|
-
(t) => !!t && typeof t === "object" && typeof t.content === "string"
|
|
40581
|
-
).map((t) => ({
|
|
40582
|
-
id: typeof t.id === "string" ? t.id : void 0,
|
|
40583
|
-
content: String(t.content).slice(0, 500),
|
|
40584
|
-
status: t.status
|
|
40585
|
-
}));
|
|
40586
|
-
}
|
|
40587
|
-
} catch {
|
|
40984
|
+
async setHead(id) {
|
|
40985
|
+
const meta3 = await this.get(id);
|
|
40986
|
+
if (!meta3) {
|
|
40987
|
+
throw new Error(`DurableStateStore.setHead: unknown commit ${id}`);
|
|
40588
40988
|
}
|
|
40589
|
-
|
|
40989
|
+
await writeJsonAtomic(this.headPath, { id, updatedAt: Date.now() });
|
|
40990
|
+
return meta3;
|
|
40590
40991
|
}
|
|
40591
|
-
|
|
40592
|
-
|
|
40593
|
-
|
|
40594
|
-
|
|
40595
|
-
|
|
40596
|
-
|
|
40597
|
-
|
|
40598
|
-
try {
|
|
40599
|
-
resolveProfile(next);
|
|
40600
|
-
} catch (err) {
|
|
40601
|
-
return {
|
|
40602
|
-
options: null,
|
|
40603
|
-
error: err instanceof Error ? err.message : String(err)
|
|
40604
|
-
};
|
|
40605
|
-
}
|
|
40606
|
-
profile = next;
|
|
40607
|
-
i++;
|
|
40608
|
-
} else if (arg === "--resume") {
|
|
40609
|
-
const next = argv[i + 1];
|
|
40610
|
-
if (!next || next.startsWith("--")) {
|
|
40611
|
-
return { options: null, error: `--resume requires a session id, got '${next ?? "(missing)"}'` };
|
|
40612
|
-
}
|
|
40613
|
-
resumeSessionId = next;
|
|
40614
|
-
i++;
|
|
40615
|
-
} else if (arg === "--export-session") {
|
|
40616
|
-
const next = argv[i + 1];
|
|
40617
|
-
if (!next || next.startsWith("--")) {
|
|
40618
|
-
return { options: null, error: `--export-session requires a path (or - for stdout), got '${next ?? "(missing)"}'` };
|
|
40619
|
-
}
|
|
40620
|
-
exportSessionPath = next;
|
|
40621
|
-
i++;
|
|
40622
|
-
} else if (arg === "--strict-done") {
|
|
40623
|
-
strictDone = true;
|
|
40624
|
-
} else if (arg === "--no-strict-done") {
|
|
40625
|
-
strictDone = false;
|
|
40626
|
-
process.env.ZELARI_MISSION_STRICT = "0";
|
|
40627
|
-
} else if (arg === "--kraken-graph") {
|
|
40628
|
-
krakenGraph = argv[i + 1];
|
|
40629
|
-
i++;
|
|
40630
|
-
} else if (arg === "--kraken-graph-file") {
|
|
40631
|
-
const next = argv[i + 1];
|
|
40632
|
-
if (next) {
|
|
40633
|
-
try {
|
|
40634
|
-
const fromFile = readFileSync22(next, "utf-8");
|
|
40635
|
-
if (fromFile.trim()) krakenGraph = fromFile;
|
|
40636
|
-
} catch {
|
|
40637
|
-
}
|
|
40638
|
-
}
|
|
40639
|
-
i++;
|
|
40640
|
-
} else if (arg === "--plan-only") {
|
|
40641
|
-
planOnly = true;
|
|
40642
|
-
} else if (arg === "--run-plan") {
|
|
40643
|
-
runPlan = argv[i + 1];
|
|
40644
|
-
i++;
|
|
40645
|
-
} else if (arg === "--gauntlet") {
|
|
40646
|
-
gauntlet = true;
|
|
40647
|
-
} else if (arg === "--no-gauntlet") {
|
|
40648
|
-
gauntlet = false;
|
|
40649
|
-
}
|
|
40650
|
-
}
|
|
40651
|
-
if (councilFlag && !modeExplicit) {
|
|
40652
|
-
mode = "council";
|
|
40653
|
-
} else if (councilFlag && modeExplicit && mode !== "council") {
|
|
40654
|
-
return {
|
|
40655
|
-
options: null,
|
|
40656
|
-
error: `--council conflicts with --mode ${mode}`
|
|
40657
|
-
};
|
|
40658
|
-
}
|
|
40659
|
-
if (task && krakenGraph) {
|
|
40660
|
-
return { options: null, error: "--task and --kraken-graph are mutually exclusive" };
|
|
40661
|
-
}
|
|
40662
|
-
if ((!task || task.trim().length === 0) && (!krakenGraph || krakenGraph.trim().length === 0)) {
|
|
40663
|
-
return { options: null, error: "--headless requires --task <prompt> or --kraken-graph <goal>" };
|
|
40664
|
-
}
|
|
40665
|
-
return {
|
|
40666
|
-
options: {
|
|
40667
|
-
task: task ?? "",
|
|
40668
|
-
output,
|
|
40669
|
-
mode,
|
|
40670
|
-
phase: phase2,
|
|
40671
|
-
useCouncil: mode === "council",
|
|
40672
|
-
provider,
|
|
40673
|
-
model,
|
|
40674
|
-
...history2 && history2.length > 0 ? { history: history2 } : {},
|
|
40675
|
-
...todos2 && todos2.length > 0 ? { todos: todos2 } : {},
|
|
40676
|
-
...once ? { once: true } : {},
|
|
40677
|
-
...profile ? { profile } : {},
|
|
40678
|
-
...resumeSessionId ? { resumeSessionId } : {},
|
|
40679
|
-
...exportSessionPath ? { exportSessionPath } : {},
|
|
40680
|
-
...strictDone ? { strictDone: true } : {},
|
|
40681
|
-
...krakenGraph ? { krakenGraph } : {},
|
|
40682
|
-
...planOnly ? { planOnly: true } : {},
|
|
40683
|
-
...runPlan ? { runPlan } : {},
|
|
40684
|
-
...gauntlet ? { gauntlet: true } : {}
|
|
40685
|
-
}
|
|
40686
|
-
};
|
|
40687
|
-
}
|
|
40688
|
-
async function resolveHeadlessKey(providerId) {
|
|
40689
|
-
const spec = PROVIDERS.find((p3) => p3.id === providerId);
|
|
40690
|
-
if (!spec) {
|
|
40691
|
-
return { error: `unknown provider: '${providerId}'` };
|
|
40692
|
-
}
|
|
40693
|
-
const resolved = await resolveApiKeyWithMeta(providerId);
|
|
40694
|
-
if (!resolved || !resolved.apiKey) {
|
|
40695
|
-
return {
|
|
40696
|
-
error: `no API key for provider '${providerId}'.
|
|
40697
|
-
Set the env var ${spec.envVar} or save a key via /login.`
|
|
40698
|
-
};
|
|
40699
|
-
}
|
|
40700
|
-
const { resolveBaseUrl: resolveBaseUrl2 } = await Promise.resolve().then(() => (init_openai_compatible(), openai_compatible_exports));
|
|
40701
|
-
return {
|
|
40702
|
-
apiKey: resolved.apiKey,
|
|
40703
|
-
baseUrl: resolveBaseUrl2(providerId)
|
|
40704
|
-
};
|
|
40705
|
-
}
|
|
40706
|
-
function resolveHeadlessProvider(opts) {
|
|
40707
|
-
const provider = opts.provider ?? getActiveProvider().id;
|
|
40708
|
-
const model = opts.model ?? getModelForProvider(provider);
|
|
40709
|
-
return { provider, model };
|
|
40710
|
-
}
|
|
40711
|
-
function emitEvent(event) {
|
|
40712
|
-
process.stdout.write(JSON.stringify(event) + "\n");
|
|
40713
|
-
}
|
|
40714
|
-
var init_headless = __esm({
|
|
40715
|
-
"src/cli/headless.ts"() {
|
|
40716
|
-
"use strict";
|
|
40717
|
-
init_keyStore();
|
|
40718
|
-
init_providerConfig();
|
|
40719
|
-
init_openai_compatible();
|
|
40720
|
-
init_phase();
|
|
40721
|
-
init_mode();
|
|
40722
|
-
init_runtime2();
|
|
40723
|
-
}
|
|
40724
|
-
});
|
|
40725
|
-
|
|
40726
|
-
// src/cli/headlessSpine.ts
|
|
40727
|
-
var headlessSpine_exports = {};
|
|
40728
|
-
__export(headlessSpine_exports, {
|
|
40729
|
-
derivedModelSeed: () => derivedModelSeed,
|
|
40730
|
-
exportSessionById: () => exportSessionById,
|
|
40731
|
-
missionStateFromSpine: () => missionStateFromSpine,
|
|
40732
|
-
openHeadlessSpine: () => openHeadlessSpine,
|
|
40733
|
-
resolveHeadlessProfileId: () => resolveHeadlessProfileId,
|
|
40734
|
-
seedHeadlessModelHistory: () => seedHeadlessModelHistory,
|
|
40735
|
-
sessionStartedEvent: () => sessionStartedEvent
|
|
40736
|
-
});
|
|
40737
|
-
function sessionStartedEvent(handle) {
|
|
40738
|
-
return {
|
|
40739
|
-
type: "session_started",
|
|
40740
|
-
sessionId: handle.sessionId,
|
|
40741
|
-
spine: handle.spine.status
|
|
40742
|
-
};
|
|
40743
|
-
}
|
|
40744
|
-
function resolveHeadlessProfileId(mode, explicit) {
|
|
40745
|
-
if (explicit) return resolveProfile(explicit).id;
|
|
40746
|
-
return defaultProfileForMode(mode ?? "kraken");
|
|
40747
|
-
}
|
|
40748
|
-
async function openHeadlessSpine(opts) {
|
|
40749
|
-
const profileId = resolveHeadlessProfileId(opts.mode, opts.profile);
|
|
40750
|
-
let profileTools = [];
|
|
40751
|
-
try {
|
|
40752
|
-
profileTools = resolveProfile(profileId).tools;
|
|
40753
|
-
} catch {
|
|
40754
|
-
profileTools = [];
|
|
40755
|
-
}
|
|
40756
|
-
const extra = {
|
|
40757
|
-
profile: profileId,
|
|
40758
|
-
workspace: opts.workspace ?? process.cwd(),
|
|
40759
|
-
toolManifestHash: profileTools.length > 0 ? toolManifestHash(profileTools) : void 0
|
|
40760
|
-
};
|
|
40761
|
-
const mirrorOpts = {
|
|
40762
|
-
baseDir: opts.baseDir,
|
|
40763
|
-
quiet: opts.quiet,
|
|
40764
|
-
extraStarted: extra
|
|
40765
|
-
};
|
|
40766
|
-
const spine = await SessionSpineMirror.adopt(opts.sessionId, mirrorOpts);
|
|
40767
|
-
if (spine.status === "active") {
|
|
40768
|
-
spine.note("headless.profile", { profile: profileId, mode: opts.mode ?? "kraken" });
|
|
40769
|
-
}
|
|
40770
|
-
return {
|
|
40771
|
-
sessionId: opts.sessionId,
|
|
40772
|
-
profileId,
|
|
40773
|
-
spine,
|
|
40774
|
-
observe(ev) {
|
|
40775
|
-
if (ev && typeof ev === "object" && "type" in ev) {
|
|
40776
|
-
spine.mirrorBrainEvent(ev);
|
|
40777
|
-
}
|
|
40778
|
-
},
|
|
40779
|
-
userMessage(text) {
|
|
40780
|
-
spine.userMessage(text);
|
|
40781
|
-
},
|
|
40782
|
-
verificationRun(payload) {
|
|
40783
|
-
spine.verificationRun(payload);
|
|
40784
|
-
},
|
|
40785
|
-
appendEvent(input) {
|
|
40786
|
-
return spine.appendEvent(input);
|
|
40787
|
-
},
|
|
40788
|
-
lastVerificationRun() {
|
|
40789
|
-
return spine.lastVerificationRun();
|
|
40790
|
-
},
|
|
40791
|
-
missionPhase(phase2, note) {
|
|
40792
|
-
spine.missionPhase(phase2, note);
|
|
40793
|
-
},
|
|
40794
|
-
missionProgress(advice) {
|
|
40795
|
-
spine.missionProgress(advice);
|
|
40796
|
-
},
|
|
40797
|
-
note(text, data) {
|
|
40798
|
-
spine.note(text, data);
|
|
40799
|
-
},
|
|
40800
|
-
async close(reason = "host-exit") {
|
|
40801
|
-
await spine.close(reason);
|
|
40802
|
-
},
|
|
40803
|
-
async interrupt(note) {
|
|
40804
|
-
if (note) spine.note("headless.interrupt", { note });
|
|
40805
|
-
await spine.release();
|
|
40806
|
-
},
|
|
40807
|
-
async exportJson() {
|
|
40808
|
-
try {
|
|
40809
|
-
const store6 = new SessionStore(resolveSessionsDir({ baseDir: opts.baseDir }));
|
|
40810
|
-
if (!await store6.exists(opts.sessionId)) return null;
|
|
40811
|
-
return await exportSessionJson(store6, opts.sessionId);
|
|
40812
|
-
} catch {
|
|
40813
|
-
return null;
|
|
40814
|
-
}
|
|
40815
|
-
}
|
|
40816
|
-
};
|
|
40817
|
-
}
|
|
40818
|
-
async function exportSessionById(sessionId2, baseDir) {
|
|
40819
|
-
try {
|
|
40820
|
-
const store6 = SessionStore.withDefaults(baseDir ? { baseDir } : {});
|
|
40821
|
-
if (!await store6.exists(sessionId2)) {
|
|
40822
|
-
return { ok: false, error: `session not found: ${sessionId2}` };
|
|
40823
|
-
}
|
|
40824
|
-
return { ok: true, json: await exportSessionJson(store6, sessionId2) };
|
|
40825
|
-
} catch (err) {
|
|
40826
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
40827
|
-
}
|
|
40828
|
-
}
|
|
40829
|
-
async function missionStateFromSpine(sessionId2, baseDir) {
|
|
40830
|
-
try {
|
|
40831
|
-
const store6 = SessionStore.withDefaults(baseDir ? { baseDir } : {});
|
|
40832
|
-
if (!await store6.exists(sessionId2)) return null;
|
|
40833
|
-
const projection = await store6.projection(sessionId2);
|
|
40834
|
-
return deriveMissionState(projection);
|
|
40835
|
-
} catch {
|
|
40836
|
-
return null;
|
|
40837
|
-
}
|
|
40838
|
-
}
|
|
40839
|
-
async function seedHeadlessModelHistory(handle, legacy) {
|
|
40840
|
-
const mirror = handle.spine;
|
|
40841
|
-
const legacySeed = filterLegacySeed(legacy);
|
|
40842
|
-
if (mirror.status !== "active") {
|
|
40843
|
-
return { history: legacySeed, importedCount: 0, source: "legacy-fallback" };
|
|
40844
|
-
}
|
|
40845
|
-
const existing = await mirror.derivedPriorTurns();
|
|
40846
|
-
if (existing && existing.length > 0) {
|
|
40847
|
-
return { history: derivedModelSeed(existing), importedCount: 0, source: "spine" };
|
|
40848
|
-
}
|
|
40849
|
-
if (legacySeed.length === 0) {
|
|
40850
|
-
return { history: [], importedCount: 0, source: "spine" };
|
|
40851
|
-
}
|
|
40852
|
-
for (const m of legacySeed) {
|
|
40853
|
-
if (m.role === "user") {
|
|
40854
|
-
mirror.userMessage(m.content);
|
|
40855
|
-
} else {
|
|
40856
|
-
mirror.assistantMessage(m.content, { imported: "legacy-history" });
|
|
40857
|
-
}
|
|
40858
|
-
}
|
|
40859
|
-
await mirror.flush();
|
|
40860
|
-
const derived = await mirror.derivedPriorTurns() ?? [];
|
|
40861
|
-
return {
|
|
40862
|
-
history: derivedModelSeed(derived),
|
|
40863
|
-
importedCount: legacySeed.length,
|
|
40864
|
-
source: "spine-import"
|
|
40865
|
-
};
|
|
40866
|
-
}
|
|
40867
|
-
function filterLegacySeed(legacy) {
|
|
40868
|
-
return (legacy ?? []).filter((m) => m.role === "user" || m.role === "assistant").map(
|
|
40869
|
-
(m) => m.role === "assistant" && m.content ? {
|
|
40870
|
-
role: "assistant",
|
|
40871
|
-
content: cleanAgentContent(m.content, {
|
|
40872
|
-
stripQuestion: false,
|
|
40873
|
-
stripThink: false
|
|
40874
|
-
})
|
|
40875
|
-
} : { role: m.role, content: m.content ?? "" }
|
|
40876
|
-
).filter((m) => (m.content ?? "").trim().length > 0);
|
|
40877
|
-
}
|
|
40878
|
-
function derivedModelSeed(derived) {
|
|
40879
|
-
return derivedToAgentMessages(derived).map(
|
|
40880
|
-
(m) => m.role === "system" ? { role: "user", content: m.content } : m
|
|
40881
|
-
).map(
|
|
40882
|
-
(m) => m.role === "assistant" && m.content ? {
|
|
40883
|
-
role: "assistant",
|
|
40884
|
-
content: cleanAgentContent(m.content, {
|
|
40885
|
-
stripQuestion: false,
|
|
40886
|
-
stripThink: false
|
|
40887
|
-
})
|
|
40888
|
-
} : m
|
|
40889
|
-
).filter((m) => m.role === "user" || m.role === "assistant").filter((m) => (m.content ?? "").trim().length > 0);
|
|
40890
|
-
}
|
|
40891
|
-
var init_headlessSpine = __esm({
|
|
40892
|
-
"src/cli/headlessSpine.ts"() {
|
|
40893
|
-
"use strict";
|
|
40894
|
-
init_dist();
|
|
40895
|
-
init_session();
|
|
40896
|
-
init_mission2();
|
|
40897
|
-
init_runtime2();
|
|
40898
|
-
init_sessionSpine();
|
|
40899
|
-
init_headless();
|
|
40900
|
-
}
|
|
40901
|
-
});
|
|
40902
|
-
|
|
40903
|
-
// src/cli/state/fileStateStore.ts
|
|
40904
|
-
import { createHash as createHash11, randomUUID as randomUUID2 } from "node:crypto";
|
|
40905
|
-
import { promises as fs21 } from "node:fs";
|
|
40906
|
-
import * as path41 from "node:path";
|
|
40907
|
-
function shortId() {
|
|
40908
|
-
return randomUUID2().replace(/-/g, "").slice(0, 12);
|
|
40909
|
-
}
|
|
40910
|
-
async function writeJsonAtomic(filePath, data) {
|
|
40911
|
-
await fs21.mkdir(path41.dirname(filePath), { recursive: true });
|
|
40912
|
-
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
40913
|
-
await fs21.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
40914
|
-
await fs21.rename(tmp, filePath);
|
|
40915
|
-
}
|
|
40916
|
-
async function readJsonFile(filePath) {
|
|
40917
|
-
try {
|
|
40918
|
-
const raw = await fs21.readFile(filePath, "utf8");
|
|
40919
|
-
return JSON.parse(raw);
|
|
40920
|
-
} catch {
|
|
40921
|
-
return null;
|
|
40922
|
-
}
|
|
40923
|
-
}
|
|
40924
|
-
function defaultSummary(input, discoveries) {
|
|
40925
|
-
if (input.summary?.trim()) return input.summary.trim();
|
|
40926
|
-
const lines = [
|
|
40927
|
-
`# ${input.label}`,
|
|
40928
|
-
"",
|
|
40929
|
-
`- mode: ${input.mode}`,
|
|
40930
|
-
input.layer ? `- layer: ${input.layer}` : null,
|
|
40931
|
-
`- verification: ran=${input.verification.ran} ok=${input.verification.ok}`,
|
|
40932
|
-
"",
|
|
40933
|
-
"## Discoveries",
|
|
40934
|
-
...discoveries.map((d) => `- [${d.kind}] ${d.summary}`)
|
|
40935
|
-
].filter((x) => x !== null);
|
|
40936
|
-
return lines.join("\n");
|
|
40937
|
-
}
|
|
40938
|
-
function stripStored(s) {
|
|
40939
|
-
const { artifactDir: _a3, ...meta3 } = s;
|
|
40940
|
-
return meta3;
|
|
40941
|
-
}
|
|
40942
|
-
function isStateEnabled(env = process.env) {
|
|
40943
|
-
return env.ZELARI_STATE !== "0";
|
|
40944
|
-
}
|
|
40945
|
-
async function getStateStore(projectRoot, env = process.env) {
|
|
40946
|
-
if (!isStateEnabled(env)) return new NoopDurableStateStore();
|
|
40947
|
-
const store6 = new FileDurableStateStore();
|
|
40948
|
-
try {
|
|
40949
|
-
await store6.init(projectRoot);
|
|
40950
|
-
return store6;
|
|
40951
|
-
} catch {
|
|
40952
|
-
return new NoopDurableStateStore();
|
|
40953
|
-
}
|
|
40954
|
-
}
|
|
40955
|
-
function hashStablePrompt(stable) {
|
|
40956
|
-
return createHash11("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
|
|
40957
|
-
}
|
|
40958
|
-
var DEFAULT_MATERIALIZE_CHARS, FileDurableStateStore, NoopDurableStateStore;
|
|
40959
|
-
var init_fileStateStore = __esm({
|
|
40960
|
-
"src/cli/state/fileStateStore.ts"() {
|
|
40961
|
-
"use strict";
|
|
40962
|
-
DEFAULT_MATERIALIZE_CHARS = 4e3;
|
|
40963
|
-
FileDurableStateStore = class {
|
|
40964
|
-
root = "";
|
|
40965
|
-
stateDir = "";
|
|
40966
|
-
commitsDir = "";
|
|
40967
|
-
artifactsDir = "";
|
|
40968
|
-
headPath = "";
|
|
40969
|
-
indexPath = "";
|
|
40970
|
-
async init(projectRoot) {
|
|
40971
|
-
this.root = projectRoot;
|
|
40972
|
-
this.stateDir = path41.join(projectRoot, ".zelari", "state");
|
|
40973
|
-
this.commitsDir = path41.join(this.stateDir, "commits");
|
|
40974
|
-
this.artifactsDir = path41.join(this.stateDir, "artifacts");
|
|
40975
|
-
this.headPath = path41.join(this.stateDir, "HEAD.json");
|
|
40976
|
-
this.indexPath = path41.join(this.stateDir, "index.jsonl");
|
|
40977
|
-
await fs21.mkdir(this.commitsDir, { recursive: true });
|
|
40978
|
-
await fs21.mkdir(this.artifactsDir, { recursive: true });
|
|
40979
|
-
}
|
|
40980
|
-
async commit(input) {
|
|
40981
|
-
if (!input.force && input.verification.ran && !input.verification.ok) {
|
|
40982
|
-
throw new Error(
|
|
40983
|
-
"DurableStateStore.commit refused: verification ran and failed (pass force:true for soft commit)"
|
|
40984
|
-
);
|
|
40985
|
-
}
|
|
40986
|
-
const discoveries = input.discoveries ?? [];
|
|
40987
|
-
const parent = await this.head();
|
|
40988
|
-
const id = shortId();
|
|
40989
|
-
const artifactRel = path41.join("artifacts", id);
|
|
40990
|
-
const artifactAbs = path41.join(this.artifactsDir, id);
|
|
40991
|
-
await fs21.mkdir(artifactAbs, { recursive: true });
|
|
40992
|
-
const summary = defaultSummary(input, discoveries);
|
|
40993
|
-
await fs21.writeFile(path41.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
|
|
40994
|
-
await writeJsonAtomic(path41.join(artifactAbs, "discoveries.json"), discoveries);
|
|
40995
|
-
await writeJsonAtomic(path41.join(artifactAbs, "verification.json"), input.verification);
|
|
40996
|
-
const meta3 = {
|
|
40997
|
-
id,
|
|
40998
|
-
parentId: parent?.id ?? null,
|
|
40999
|
-
createdAt: Date.now(),
|
|
41000
|
-
sessionId: input.sessionId,
|
|
41001
|
-
mode: input.mode,
|
|
41002
|
-
layer: input.layer,
|
|
41003
|
-
label: input.label,
|
|
41004
|
-
workspaceCheckpointId: input.workspaceCheckpointId,
|
|
41005
|
-
verification: {
|
|
41006
|
-
...input.verification,
|
|
41007
|
-
reportPath: input.verification.reportPath ?? path41.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
|
|
41008
|
-
},
|
|
41009
|
-
changedPaths: input.changedPaths ?? [],
|
|
41010
|
-
stablePromptHash: input.stablePromptHash,
|
|
41011
|
-
discoveryCount: discoveries.length,
|
|
41012
|
-
artifactDir: artifactRel.replace(/\\/g, "/")
|
|
41013
|
-
};
|
|
41014
|
-
await writeJsonAtomic(path41.join(this.commitsDir, `${id}.json`), meta3);
|
|
41015
|
-
await writeJsonAtomic(this.headPath, { id, updatedAt: meta3.createdAt });
|
|
41016
|
-
await fs21.appendFile(this.indexPath, JSON.stringify({ id, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
|
|
41017
|
-
return stripStored(meta3);
|
|
41018
|
-
}
|
|
41019
|
-
async head() {
|
|
41020
|
-
const head = await readJsonFile(this.headPath);
|
|
41021
|
-
if (!head?.id) return null;
|
|
41022
|
-
return this.get(head.id);
|
|
41023
|
-
}
|
|
41024
|
-
async get(id) {
|
|
41025
|
-
const stored = await readJsonFile(path41.join(this.commitsDir, `${id}.json`));
|
|
41026
|
-
return stored ? stripStored(stored) : null;
|
|
41027
|
-
}
|
|
41028
|
-
async list(limit = 20) {
|
|
41029
|
-
let raw;
|
|
41030
|
-
try {
|
|
41031
|
-
raw = await fs21.readFile(this.indexPath, "utf8");
|
|
41032
|
-
} catch {
|
|
41033
|
-
return [];
|
|
41034
|
-
}
|
|
41035
|
-
const ids = [];
|
|
41036
|
-
for (const line of raw.split("\n")) {
|
|
41037
|
-
const t = line.trim();
|
|
41038
|
-
if (!t) continue;
|
|
41039
|
-
try {
|
|
41040
|
-
const row = JSON.parse(t);
|
|
41041
|
-
if (row.id) ids.push(row.id);
|
|
41042
|
-
} catch {
|
|
41043
|
-
}
|
|
41044
|
-
}
|
|
41045
|
-
const slice = ids.slice(-Math.max(1, limit)).reverse();
|
|
41046
|
-
const out = [];
|
|
41047
|
-
for (const id of slice) {
|
|
41048
|
-
const m = await this.get(id);
|
|
41049
|
-
if (m) out.push(m);
|
|
41050
|
-
}
|
|
41051
|
-
return out;
|
|
41052
|
-
}
|
|
41053
|
-
async setHead(id) {
|
|
41054
|
-
const meta3 = await this.get(id);
|
|
41055
|
-
if (!meta3) {
|
|
41056
|
-
throw new Error(`DurableStateStore.setHead: unknown commit ${id}`);
|
|
41057
|
-
}
|
|
41058
|
-
await writeJsonAtomic(this.headPath, { id, updatedAt: Date.now() });
|
|
41059
|
-
return meta3;
|
|
41060
|
-
}
|
|
41061
|
-
async loadDiscoveries(id) {
|
|
41062
|
-
const meta3 = id ? await this.get(id) : await this.head();
|
|
41063
|
-
if (!meta3) return [];
|
|
41064
|
-
const stored = await readJsonFile(path41.join(this.commitsDir, `${meta3.id}.json`));
|
|
41065
|
-
if (!stored?.artifactDir) return [];
|
|
41066
|
-
const discPath = path41.join(this.stateDir, stored.artifactDir, "discoveries.json");
|
|
41067
|
-
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) ?? [];
|
|
41068
40999
|
}
|
|
41069
41000
|
async materializeContext(id, maxChars = DEFAULT_MATERIALIZE_CHARS) {
|
|
41070
41001
|
const meta3 = id ? await this.get(id) : await this.head();
|
|
@@ -41234,25 +41165,37 @@ function extractiveHistorySummary(dropped, opts) {
|
|
|
41234
41165
|
if (dropped.length === 0) return "No prior turns.";
|
|
41235
41166
|
const userGoals = [];
|
|
41236
41167
|
const assistantNotes = [];
|
|
41168
|
+
const userConstraints = [];
|
|
41169
|
+
const unresolved = [];
|
|
41170
|
+
const verification = [];
|
|
41171
|
+
const decisions = [];
|
|
41237
41172
|
const tools = /* @__PURE__ */ new Map();
|
|
41238
41173
|
const files = /* @__PURE__ */ new Set();
|
|
41239
41174
|
let toolResults = 0;
|
|
41240
41175
|
for (const m of dropped) {
|
|
41241
41176
|
if (m.role === "user" && m.content.trim()) {
|
|
41242
|
-
|
|
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);
|
|
41243
41180
|
} else if (m.role === "assistant") {
|
|
41244
41181
|
if (m.content.trim()) {
|
|
41245
|
-
|
|
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);
|
|
41246
41187
|
}
|
|
41247
41188
|
if (m.toolCalls) {
|
|
41248
41189
|
for (const tc of m.toolCalls) {
|
|
41249
41190
|
tools.set(tc.name, (tools.get(tc.name) ?? 0) + 1);
|
|
41250
|
-
|
|
41191
|
+
collectPaths2(tc.args, files);
|
|
41251
41192
|
}
|
|
41252
41193
|
}
|
|
41253
41194
|
} else if (m.role === "tool") {
|
|
41254
41195
|
toolResults += 1;
|
|
41255
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));
|
|
41256
41199
|
}
|
|
41257
41200
|
}
|
|
41258
41201
|
const parts = [
|
|
@@ -41263,6 +41206,22 @@ function extractiveHistorySummary(dropped, opts) {
|
|
|
41263
41206
|
parts.push("## User goals / requests");
|
|
41264
41207
|
for (const g of userGoals.slice(-6)) parts.push(`- ${g}`);
|
|
41265
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
|
+
}
|
|
41266
41225
|
if (assistantNotes.length) {
|
|
41267
41226
|
parts.push("## Assistant conclusions (truncated)");
|
|
41268
41227
|
for (const a of assistantNotes.slice(-5)) parts.push(`- ${a}`);
|
|
@@ -41289,7 +41248,7 @@ function oneLine(s, max) {
|
|
|
41289
41248
|
if (t.length <= max) return t;
|
|
41290
41249
|
return `${t.slice(0, max - 1)}\u2026`;
|
|
41291
41250
|
}
|
|
41292
|
-
function
|
|
41251
|
+
function collectPaths2(args, out) {
|
|
41293
41252
|
if (!args || typeof args !== "object") return;
|
|
41294
41253
|
const obj = args;
|
|
41295
41254
|
for (const key of ["path", "file", "filepath", "filePath", "target", "cwd"]) {
|
|
@@ -41408,6 +41367,36 @@ Be concise.
|
|
|
41408
41367
|
});
|
|
41409
41368
|
|
|
41410
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
|
+
}
|
|
41411
41400
|
function resolveMaxMessages(opts) {
|
|
41412
41401
|
const envTurns = envNumber(process.env.ZELARI_HISTORY_TURNS, { default: 6, min: 0 });
|
|
41413
41402
|
let turns = opts?.maxMessages ? Math.ceil(opts.maxMessages / 4) : envTurns;
|
|
@@ -41481,16 +41470,25 @@ function pruneToolResultsDetailed(messages, opts) {
|
|
|
41481
41470
|
function compactHistory(messages, opts) {
|
|
41482
41471
|
return compactHistoryDetailed(messages, opts).messages;
|
|
41483
41472
|
}
|
|
41484
|
-
function buildCheckpointMessage(summaryText) {
|
|
41473
|
+
function buildCheckpointMessage(summaryText, range) {
|
|
41485
41474
|
return {
|
|
41486
41475
|
role: "user",
|
|
41487
|
-
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
|
+
} : {}
|
|
41488
41482
|
};
|
|
41489
41483
|
}
|
|
41490
41484
|
function compactHistoryDetailed(messages, opts) {
|
|
41491
41485
|
const maxMessages = resolveMaxMessages(opts);
|
|
41492
41486
|
if (maxMessages === 0) {
|
|
41493
|
-
return
|
|
41487
|
+
return withDroppedRange(
|
|
41488
|
+
{ messages: [], compacted: true, messagesRemoved: messages.length, summary: "" },
|
|
41489
|
+
messages,
|
|
41490
|
+
"extractive"
|
|
41491
|
+
);
|
|
41494
41492
|
}
|
|
41495
41493
|
if (messages.length <= maxMessages * 2 && !opts?.force) {
|
|
41496
41494
|
return {
|
|
@@ -41511,19 +41509,25 @@ function compactHistoryDetailed(messages, opts) {
|
|
|
41511
41509
|
};
|
|
41512
41510
|
}
|
|
41513
41511
|
const droppedMsgs = messages.slice(0, cut);
|
|
41512
|
+
const droppedRange = compactedRangeFromDropped(droppedMsgs);
|
|
41514
41513
|
const pruned = pruneToolResultsDetailed(messages.slice(cut));
|
|
41515
41514
|
const kept = pruned.messages;
|
|
41516
41515
|
const summaryText = extractiveHistorySummary(droppedMsgs);
|
|
41517
41516
|
const summary = buildCheckpointMessage(
|
|
41518
|
-
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"
|
|
41519
41530
|
);
|
|
41520
|
-
return {
|
|
41521
|
-
messages: [summary, ...kept],
|
|
41522
|
-
compacted: true,
|
|
41523
|
-
messagesRemoved: cut,
|
|
41524
|
-
summary: summary.content,
|
|
41525
|
-
prunedToolResults: pruned.stats.pruned
|
|
41526
|
-
};
|
|
41527
41531
|
}
|
|
41528
41532
|
async function compactHistoryAsync(messages, opts) {
|
|
41529
41533
|
const base = compactHistoryDetailed(messages, opts);
|
|
@@ -41559,16 +41563,21 @@ async function compactHistoryAsync(messages, opts) {
|
|
|
41559
41563
|
}
|
|
41560
41564
|
const pruned = pruneToolResultsDetailed(messages.slice(cut));
|
|
41561
41565
|
const kept = pruned.messages;
|
|
41562
|
-
const summary = buildCheckpointMessage(summaryText);
|
|
41563
|
-
|
|
41564
|
-
|
|
41565
|
-
|
|
41566
|
-
|
|
41567
|
-
|
|
41568
|
-
|
|
41569
|
-
|
|
41570
|
-
|
|
41571
|
-
|
|
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
|
+
);
|
|
41572
41581
|
}
|
|
41573
41582
|
function roughTokens(msgs) {
|
|
41574
41583
|
let n = 0;
|
|
@@ -41603,252 +41612,799 @@ function recordRequestUsage(sessionId2, usage) {
|
|
|
41603
41612
|
if (!entry) return;
|
|
41604
41613
|
entry.usage = usage;
|
|
41605
41614
|
}
|
|
41606
|
-
function getRequestSnapshotWithUsage(sessionId2) {
|
|
41607
|
-
return store5.get(sessionId2) ?? null;
|
|
41615
|
+
function getRequestSnapshotWithUsage(sessionId2) {
|
|
41616
|
+
return store5.get(sessionId2) ?? null;
|
|
41617
|
+
}
|
|
41618
|
+
function clearAllRequestSnapshots() {
|
|
41619
|
+
store5.clear();
|
|
41620
|
+
}
|
|
41621
|
+
var store5;
|
|
41622
|
+
var init_requestSnapshotStore = __esm({
|
|
41623
|
+
"src/cli/budget/requestSnapshotStore.ts"() {
|
|
41624
|
+
"use strict";
|
|
41625
|
+
store5 = /* @__PURE__ */ new Map();
|
|
41626
|
+
}
|
|
41627
|
+
});
|
|
41628
|
+
|
|
41629
|
+
// src/cli/hooks/conversationContext.ts
|
|
41630
|
+
var conversationContext_exports = {};
|
|
41631
|
+
__export(conversationContext_exports, {
|
|
41632
|
+
_resetConversationContextForTests: () => _resetConversationContextForTests,
|
|
41633
|
+
appendMessages: () => appendMessages,
|
|
41634
|
+
buildAgentUserWithHistory: () => buildAgentUserWithHistory,
|
|
41635
|
+
buildContinueUserMessage: () => buildContinueUserMessage,
|
|
41636
|
+
buildCouncilTaskWithHistory: () => buildCouncilTaskWithHistory,
|
|
41637
|
+
clearHistory: () => clearHistory,
|
|
41638
|
+
compactInPlace: () => compactInPlace,
|
|
41639
|
+
expectsDiskImplementation: () => expectsDiskImplementation,
|
|
41640
|
+
formatHistoryForCouncil: () => formatHistoryForCouncil,
|
|
41641
|
+
formatHistoryMessages: () => formatHistoryMessages,
|
|
41642
|
+
getHistory: () => getHistory,
|
|
41643
|
+
getLastClarification: () => getLastClarification,
|
|
41644
|
+
hydrateHistory: () => hydrateHistory,
|
|
41645
|
+
isShortContinueReply: () => isShortContinueReply,
|
|
41646
|
+
maybeAnchorShortAnswer: () => maybeAnchorShortAnswer,
|
|
41647
|
+
serializeHistory: () => serializeHistory,
|
|
41648
|
+
setHistory: () => setHistory,
|
|
41649
|
+
setLastClarification: () => setLastClarification
|
|
41650
|
+
});
|
|
41651
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
41652
|
+
import { join as join19 } from "node:path";
|
|
41653
|
+
function getHistory() {
|
|
41654
|
+
return history;
|
|
41655
|
+
}
|
|
41656
|
+
function setHistory(messages) {
|
|
41657
|
+
const projected = applySessionSurface(messages);
|
|
41658
|
+
history = projected === messages ? [...messages] : projected;
|
|
41659
|
+
}
|
|
41660
|
+
function compactInPlace(cwd = process.cwd()) {
|
|
41661
|
+
const durableStatePresent = existsSync25(join19(cwd, ".zelari", "state", "HEAD.json"));
|
|
41662
|
+
history = applySessionSurface(compactHistory(history, { durableStatePresent }));
|
|
41663
|
+
}
|
|
41664
|
+
function appendMessages(msgs) {
|
|
41665
|
+
if (msgs.length === 0) return;
|
|
41666
|
+
history = applySessionSurface(history.concat(msgs));
|
|
41667
|
+
}
|
|
41668
|
+
function clearHistory() {
|
|
41669
|
+
history = [];
|
|
41670
|
+
lastClarification = null;
|
|
41671
|
+
clearAllRequestSnapshots();
|
|
41672
|
+
clearSessionTodos();
|
|
41673
|
+
clearSessionPermissionGrants();
|
|
41674
|
+
}
|
|
41675
|
+
function serializeHistory() {
|
|
41676
|
+
return [...history];
|
|
41677
|
+
}
|
|
41678
|
+
function hydrateHistory(messages) {
|
|
41679
|
+
const projected = applySessionSurface(messages);
|
|
41680
|
+
history = projected === messages ? [...messages] : projected;
|
|
41681
|
+
}
|
|
41682
|
+
function getLastClarification() {
|
|
41683
|
+
return lastClarification;
|
|
41684
|
+
}
|
|
41685
|
+
function setLastClarification(c) {
|
|
41686
|
+
lastClarification = c ? { question: c.question, choices: c.choices, at: Date.now() } : null;
|
|
41687
|
+
}
|
|
41688
|
+
function maybeAnchorShortAnswer(userText) {
|
|
41689
|
+
const clar = lastClarification;
|
|
41690
|
+
if (!clar) return null;
|
|
41691
|
+
const trimmed = userText.trim();
|
|
41692
|
+
if (!trimmed) return null;
|
|
41693
|
+
if (trimmed.length > 80 || trimmed.includes("\n")) return null;
|
|
41694
|
+
const lower = trimmed.toLowerCase();
|
|
41695
|
+
const choices = clar.choices;
|
|
41696
|
+
const matched = choices.find((c) => c.toLowerCase() === lower) ?? choices.find((c) => c.toLowerCase().startsWith(lower)) ?? choices.find((c) => lower.startsWith(c.toLowerCase().slice(0, Math.min(4, c.length))));
|
|
41697
|
+
let choiceLabel = matched ?? null;
|
|
41698
|
+
if (!choiceLabel && /^\d{1,2}$/.test(trimmed)) {
|
|
41699
|
+
const idx = Number.parseInt(trimmed, 10) - 1;
|
|
41700
|
+
if (idx >= 0 && idx < choices.length) choiceLabel = choices[idx] ?? null;
|
|
41701
|
+
}
|
|
41702
|
+
if (!choiceLabel && trimmed.length > 24) return null;
|
|
41703
|
+
const picked = choiceLabel ?? trimmed;
|
|
41704
|
+
return `The user is answering your previous clarifying question.
|
|
41705
|
+
Question: ${clar.question}
|
|
41706
|
+
Choices were: ${choices.join(" | ")}
|
|
41707
|
+
User's answer: ${picked}
|
|
41708
|
+
Proceed using this answer; do not re-ask the same question unless the answer is still ambiguous.`;
|
|
41709
|
+
}
|
|
41710
|
+
function formatHistoryForCouncil(maxTurns = 4) {
|
|
41711
|
+
return formatHistoryMessages(history, maxTurns);
|
|
41712
|
+
}
|
|
41713
|
+
function formatHistoryMessages(messages, maxTurns = 6, maxTotalChars = 12e3) {
|
|
41714
|
+
if (messages.length === 0) return "";
|
|
41715
|
+
let turns = 0;
|
|
41716
|
+
const chunk = [];
|
|
41717
|
+
for (let i = messages.length - 1; i >= 0 && turns < maxTurns; i--) {
|
|
41718
|
+
const m = messages[i];
|
|
41719
|
+
if (m.role === "user") {
|
|
41720
|
+
chunk.push(`User: ${truncate(m.content, 800)}`);
|
|
41721
|
+
turns += 1;
|
|
41722
|
+
} else if (m.role === "assistant" && m.content.trim()) {
|
|
41723
|
+
chunk.push(`Assistant: ${truncate(m.content, 2e3)}`);
|
|
41724
|
+
}
|
|
41725
|
+
}
|
|
41726
|
+
if (chunk.length === 0) return "";
|
|
41727
|
+
let body = ["## Prior conversation (rolling context)", ...chunk.reverse()].join(
|
|
41728
|
+
"\n"
|
|
41729
|
+
);
|
|
41730
|
+
if (body.length > maxTotalChars) {
|
|
41731
|
+
body = `\u2026
|
|
41732
|
+
${body.slice(body.length - maxTotalChars)}`;
|
|
41733
|
+
}
|
|
41734
|
+
return body;
|
|
41735
|
+
}
|
|
41736
|
+
function isShortContinueReply(task) {
|
|
41737
|
+
const trimmed = task.trim();
|
|
41738
|
+
if (!trimmed) return false;
|
|
41739
|
+
if (SHORT_CONTINUE.test(trimmed)) return true;
|
|
41740
|
+
if (trimmed.length <= 80 && !trimmed.includes("\n") && SHORT_CONTINUE_LOOSE.test(trimmed)) {
|
|
41741
|
+
return true;
|
|
41742
|
+
}
|
|
41743
|
+
return false;
|
|
41744
|
+
}
|
|
41745
|
+
function buildContinueUserMessage(task, prior, opts) {
|
|
41746
|
+
if (!isShortContinueReply(task) || prior.length === 0) return null;
|
|
41747
|
+
const lastAsst = [...prior].reverse().find((m) => m.role === "assistant" && (m.content ?? "").trim());
|
|
41748
|
+
if (!lastAsst) return null;
|
|
41749
|
+
const max = opts?.maxPriorChars ?? 8e3;
|
|
41750
|
+
const trimmed = task.trim();
|
|
41751
|
+
return `The user says "${trimmed}" \u2014 this is a CONTINUATION of an existing multi-turn session (the Desktop phase may have switched plan\u2194build; mode may have changed). This is NOT a new conversation and you DO have prior context below.
|
|
41752
|
+
|
|
41753
|
+
## CRITICAL \u2014 plan text \u2260 done on disk
|
|
41754
|
+
The prior assistant output is a PLAN / SPEC / PROPOSAL (or analysis). It is NOT proof that project files already contain those changes.
|
|
41755
|
+
The user CONFIRMED the plan and wants you to IMPLEMENT it ON DISK NOW.
|
|
41756
|
+
- You MUST use write_file and/or edit_file (and bash when needed) to apply every planned change.
|
|
41757
|
+
- Reading files alone is incomplete. Do not stop after read_file/list_files/grep.
|
|
41758
|
+
- Do NOT claim "already implemented" / "tutto fatto" unless you verified the changes exist on disk in THIS turn (read after your own successful writes).
|
|
41759
|
+
- Do NOT restart from zero or re-ask for the overall goal.
|
|
41760
|
+
|
|
41761
|
+
## Prior assistant output (plan to implement \u2014 authoritative)
|
|
41762
|
+
${truncate(lastAsst.content, max)}
|
|
41763
|
+
|
|
41764
|
+
## Instruction
|
|
41765
|
+
Implement the plan on disk now with mutating tools, then briefly list the files you wrote/edited.`;
|
|
41766
|
+
}
|
|
41767
|
+
function expectsDiskImplementation(task, phase2, prior) {
|
|
41768
|
+
if ((phase2 ?? "build") === "plan") return false;
|
|
41769
|
+
const trimmed = task.trim();
|
|
41770
|
+
if (!trimmed) return false;
|
|
41771
|
+
if (isShortContinueReply(trimmed)) return true;
|
|
41772
|
+
if (/\b(implement|implementa|scrivi|scriviamo|applica|modifica|fix|write|edit|crea|aggiungi|aggiorna|apply|patch)\b/i.test(
|
|
41773
|
+
trimmed
|
|
41774
|
+
)) {
|
|
41775
|
+
return true;
|
|
41776
|
+
}
|
|
41777
|
+
if (prior && prior.length > 0 && isShortContinueReply(trimmed)) {
|
|
41778
|
+
const lastAsst = [...prior].reverse().find((m) => m.role === "assistant" && (m.content ?? "").trim());
|
|
41779
|
+
if (lastAsst && /\b(se confermi|passo alla|scriv|implement|on disk|write_file|modifiche proposte|riepilogo delle modifiche)\b/i.test(
|
|
41780
|
+
lastAsst.content
|
|
41781
|
+
)) {
|
|
41782
|
+
return true;
|
|
41783
|
+
}
|
|
41784
|
+
}
|
|
41785
|
+
return false;
|
|
41786
|
+
}
|
|
41787
|
+
function buildCouncilTaskWithHistory(task, prior) {
|
|
41788
|
+
const messages = prior ?? [];
|
|
41789
|
+
const trimmed = task.trim();
|
|
41790
|
+
let userPart = maybeAnchorShortAnswer(task) ?? task;
|
|
41791
|
+
const continued = buildContinueUserMessage(trimmed, messages, {
|
|
41792
|
+
maxPriorChars: 4500
|
|
41793
|
+
});
|
|
41794
|
+
if (continued) {
|
|
41795
|
+
userPart = continued;
|
|
41796
|
+
}
|
|
41797
|
+
const block = formatHistoryMessages(messages, 6, 12e3);
|
|
41798
|
+
if (!block) return userPart;
|
|
41799
|
+
if (userPart.includes("Prior assistant output")) {
|
|
41800
|
+
return userPart;
|
|
41801
|
+
}
|
|
41802
|
+
return `${block}
|
|
41803
|
+
|
|
41804
|
+
## Current user request
|
|
41805
|
+
${userPart}`;
|
|
41806
|
+
}
|
|
41807
|
+
function buildAgentUserWithHistory(task, prior) {
|
|
41808
|
+
const messages = prior ?? [];
|
|
41809
|
+
const anchored = maybeAnchorShortAnswer(task);
|
|
41810
|
+
if (anchored) return anchored;
|
|
41811
|
+
return buildContinueUserMessage(task, messages, { maxPriorChars: 8e3 }) ?? task;
|
|
41812
|
+
}
|
|
41813
|
+
function truncate(s, max) {
|
|
41814
|
+
const t = s.replace(/\s+/g, " ").trim();
|
|
41815
|
+
if (t.length <= max) return t;
|
|
41816
|
+
return `${t.slice(0, max - 1)}\u2026`;
|
|
41817
|
+
}
|
|
41818
|
+
function _resetConversationContextForTests() {
|
|
41819
|
+
history = [];
|
|
41820
|
+
lastClarification = null;
|
|
41821
|
+
clearSessionTodos();
|
|
41822
|
+
clearSessionPermissionGrants();
|
|
41823
|
+
}
|
|
41824
|
+
var history, lastClarification, SHORT_CONTINUE, SHORT_CONTINUE_LOOSE;
|
|
41825
|
+
var init_conversationContext = __esm({
|
|
41826
|
+
"src/cli/hooks/conversationContext.ts"() {
|
|
41827
|
+
"use strict";
|
|
41828
|
+
init_toolPermissions();
|
|
41829
|
+
init_sessionTodos();
|
|
41830
|
+
init_historyCompaction();
|
|
41831
|
+
init_requestSnapshotStore();
|
|
41832
|
+
init_observationStore();
|
|
41833
|
+
history = [];
|
|
41834
|
+
lastClarification = null;
|
|
41835
|
+
SHORT_CONTINUE = /^(procedi|continua|continue|go\s*ahead|go|ok|okay|sì|si|yes|vai|avanti|next|proceed|conferma|confermo|applica|fai|scrivi|esegui|implementa|vai pure|fai pure|ok procedi|sì procedi|si procedi)$/i;
|
|
41836
|
+
SHORT_CONTINUE_LOOSE = /\b(procedi|continua|continue|conferma|confermo|applica|implementa|scriv[ia]|esegui|vai pure|fai pure|go ahead|proceed)\b/i;
|
|
41837
|
+
}
|
|
41838
|
+
});
|
|
41839
|
+
|
|
41840
|
+
// src/cli/phaseState.ts
|
|
41841
|
+
var phaseState_exports = {};
|
|
41842
|
+
__export(phaseState_exports, {
|
|
41843
|
+
_resetPhaseForTests: () => _resetPhaseForTests,
|
|
41844
|
+
getPhase: () => getPhase,
|
|
41845
|
+
setPhase: () => setPhase
|
|
41846
|
+
});
|
|
41847
|
+
function getPhase() {
|
|
41848
|
+
return phase;
|
|
41849
|
+
}
|
|
41850
|
+
function setPhase(next) {
|
|
41851
|
+
phase = next;
|
|
41852
|
+
}
|
|
41853
|
+
function _resetPhaseForTests() {
|
|
41854
|
+
phase = "build";
|
|
41855
|
+
}
|
|
41856
|
+
var phase;
|
|
41857
|
+
var init_phaseState = __esm({
|
|
41858
|
+
"src/cli/phaseState.ts"() {
|
|
41859
|
+
"use strict";
|
|
41860
|
+
phase = "build";
|
|
41861
|
+
}
|
|
41862
|
+
});
|
|
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 };
|
|
41608
42217
|
}
|
|
41609
|
-
function
|
|
41610
|
-
|
|
42218
|
+
function emitEvent(event) {
|
|
42219
|
+
process.stdout.write(JSON.stringify(event) + "\n");
|
|
41611
42220
|
}
|
|
41612
|
-
var
|
|
41613
|
-
|
|
41614
|
-
"src/cli/budget/requestSnapshotStore.ts"() {
|
|
42221
|
+
var init_headless = __esm({
|
|
42222
|
+
"src/cli/headless.ts"() {
|
|
41615
42223
|
"use strict";
|
|
41616
|
-
|
|
42224
|
+
init_keyStore();
|
|
42225
|
+
init_providerConfig();
|
|
42226
|
+
init_openai_compatible();
|
|
42227
|
+
init_phase();
|
|
42228
|
+
init_mode();
|
|
42229
|
+
init_runtime2();
|
|
41617
42230
|
}
|
|
41618
42231
|
});
|
|
41619
42232
|
|
|
41620
|
-
// src/cli/
|
|
41621
|
-
var
|
|
41622
|
-
__export(
|
|
41623
|
-
|
|
41624
|
-
|
|
41625
|
-
|
|
41626
|
-
|
|
41627
|
-
|
|
41628
|
-
|
|
41629
|
-
|
|
41630
|
-
expectsDiskImplementation: () => expectsDiskImplementation,
|
|
41631
|
-
formatHistoryForCouncil: () => formatHistoryForCouncil,
|
|
41632
|
-
formatHistoryMessages: () => formatHistoryMessages,
|
|
41633
|
-
getHistory: () => getHistory,
|
|
41634
|
-
getLastClarification: () => getLastClarification,
|
|
41635
|
-
hydrateHistory: () => hydrateHistory,
|
|
41636
|
-
isShortContinueReply: () => isShortContinueReply,
|
|
41637
|
-
maybeAnchorShortAnswer: () => maybeAnchorShortAnswer,
|
|
41638
|
-
serializeHistory: () => serializeHistory,
|
|
41639
|
-
setHistory: () => setHistory,
|
|
41640
|
-
setLastClarification: () => setLastClarification
|
|
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
|
|
41641
42243
|
});
|
|
41642
|
-
|
|
41643
|
-
|
|
41644
|
-
|
|
41645
|
-
|
|
41646
|
-
|
|
41647
|
-
|
|
41648
|
-
const projected = applySessionSurface(messages);
|
|
41649
|
-
history = projected === messages ? [...messages] : projected;
|
|
41650
|
-
}
|
|
41651
|
-
function compactInPlace(cwd = process.cwd()) {
|
|
41652
|
-
const durableStatePresent = existsSync25(join19(cwd, ".zelari", "state", "HEAD.json"));
|
|
41653
|
-
history = applySessionSurface(compactHistory(history, { durableStatePresent }));
|
|
41654
|
-
}
|
|
41655
|
-
function appendMessages(msgs) {
|
|
41656
|
-
if (msgs.length === 0) return;
|
|
41657
|
-
history = applySessionSurface(history.concat(msgs));
|
|
41658
|
-
}
|
|
41659
|
-
function clearHistory() {
|
|
41660
|
-
history = [];
|
|
41661
|
-
lastClarification = null;
|
|
41662
|
-
clearAllRequestSnapshots();
|
|
41663
|
-
clearSessionTodos();
|
|
41664
|
-
clearSessionPermissionGrants();
|
|
41665
|
-
}
|
|
41666
|
-
function serializeHistory() {
|
|
41667
|
-
return [...history];
|
|
41668
|
-
}
|
|
41669
|
-
function hydrateHistory(messages) {
|
|
41670
|
-
const projected = applySessionSurface(messages);
|
|
41671
|
-
history = projected === messages ? [...messages] : projected;
|
|
41672
|
-
}
|
|
41673
|
-
function getLastClarification() {
|
|
41674
|
-
return lastClarification;
|
|
42244
|
+
function sessionStartedEvent(handle) {
|
|
42245
|
+
return {
|
|
42246
|
+
type: "session_started",
|
|
42247
|
+
sessionId: handle.sessionId,
|
|
42248
|
+
spine: handle.spine.status
|
|
42249
|
+
};
|
|
41675
42250
|
}
|
|
41676
|
-
function
|
|
41677
|
-
|
|
42251
|
+
function resolveHeadlessProfileId(mode, explicit) {
|
|
42252
|
+
if (explicit) return resolveProfile(explicit).id;
|
|
42253
|
+
return defaultProfileForMode(mode ?? "kraken");
|
|
41678
42254
|
}
|
|
41679
|
-
function
|
|
41680
|
-
const
|
|
41681
|
-
|
|
41682
|
-
|
|
41683
|
-
|
|
41684
|
-
|
|
41685
|
-
|
|
41686
|
-
const choices = clar.choices;
|
|
41687
|
-
const matched = choices.find((c) => c.toLowerCase() === lower) ?? choices.find((c) => c.toLowerCase().startsWith(lower)) ?? choices.find((c) => lower.startsWith(c.toLowerCase().slice(0, Math.min(4, c.length))));
|
|
41688
|
-
let choiceLabel = matched ?? null;
|
|
41689
|
-
if (!choiceLabel && /^\d{1,2}$/.test(trimmed)) {
|
|
41690
|
-
const idx = Number.parseInt(trimmed, 10) - 1;
|
|
41691
|
-
if (idx >= 0 && idx < choices.length) choiceLabel = choices[idx] ?? null;
|
|
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 = [];
|
|
41692
42262
|
}
|
|
41693
|
-
|
|
41694
|
-
|
|
41695
|
-
|
|
41696
|
-
|
|
41697
|
-
|
|
41698
|
-
|
|
41699
|
-
|
|
41700
|
-
|
|
41701
|
-
|
|
41702
|
-
|
|
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
|
+
};
|
|
41703
42324
|
}
|
|
41704
|
-
function
|
|
41705
|
-
|
|
41706
|
-
|
|
41707
|
-
|
|
41708
|
-
|
|
41709
|
-
const m = messages[i];
|
|
41710
|
-
if (m.role === "user") {
|
|
41711
|
-
chunk.push(`User: ${truncate(m.content, 800)}`);
|
|
41712
|
-
turns += 1;
|
|
41713
|
-
} else if (m.role === "assistant" && m.content.trim()) {
|
|
41714
|
-
chunk.push(`Assistant: ${truncate(m.content, 2e3)}`);
|
|
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}` };
|
|
41715
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) };
|
|
41716
42334
|
}
|
|
41717
|
-
if (chunk.length === 0) return "";
|
|
41718
|
-
let body = ["## Prior conversation (rolling context)", ...chunk.reverse()].join(
|
|
41719
|
-
"\n"
|
|
41720
|
-
);
|
|
41721
|
-
if (body.length > maxTotalChars) {
|
|
41722
|
-
body = `\u2026
|
|
41723
|
-
${body.slice(body.length - maxTotalChars)}`;
|
|
41724
|
-
}
|
|
41725
|
-
return body;
|
|
41726
42335
|
}
|
|
41727
|
-
function
|
|
41728
|
-
|
|
41729
|
-
|
|
41730
|
-
|
|
41731
|
-
|
|
41732
|
-
return
|
|
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;
|
|
41733
42344
|
}
|
|
41734
|
-
return false;
|
|
41735
|
-
}
|
|
41736
|
-
function buildContinueUserMessage(task, prior, opts) {
|
|
41737
|
-
if (!isShortContinueReply(task) || prior.length === 0) return null;
|
|
41738
|
-
const lastAsst = [...prior].reverse().find((m) => m.role === "assistant" && (m.content ?? "").trim());
|
|
41739
|
-
if (!lastAsst) return null;
|
|
41740
|
-
const max = opts?.maxPriorChars ?? 8e3;
|
|
41741
|
-
const trimmed = task.trim();
|
|
41742
|
-
return `The user says "${trimmed}" \u2014 this is a CONTINUATION of an existing multi-turn session (the Desktop phase may have switched plan\u2194build; mode may have changed). This is NOT a new conversation and you DO have prior context below.
|
|
41743
|
-
|
|
41744
|
-
## CRITICAL \u2014 plan text \u2260 done on disk
|
|
41745
|
-
The prior assistant output is a PLAN / SPEC / PROPOSAL (or analysis). It is NOT proof that project files already contain those changes.
|
|
41746
|
-
The user CONFIRMED the plan and wants you to IMPLEMENT it ON DISK NOW.
|
|
41747
|
-
- You MUST use write_file and/or edit_file (and bash when needed) to apply every planned change.
|
|
41748
|
-
- Reading files alone is incomplete. Do not stop after read_file/list_files/grep.
|
|
41749
|
-
- Do NOT claim "already implemented" / "tutto fatto" unless you verified the changes exist on disk in THIS turn (read after your own successful writes).
|
|
41750
|
-
- Do NOT restart from zero or re-ask for the overall goal.
|
|
41751
|
-
|
|
41752
|
-
## Prior assistant output (plan to implement \u2014 authoritative)
|
|
41753
|
-
${truncate(lastAsst.content, max)}
|
|
41754
|
-
|
|
41755
|
-
## Instruction
|
|
41756
|
-
Implement the plan on disk now with mutating tools, then briefly list the files you wrote/edited.`;
|
|
41757
42345
|
}
|
|
41758
|
-
function
|
|
41759
|
-
|
|
41760
|
-
const
|
|
41761
|
-
if (
|
|
41762
|
-
|
|
41763
|
-
if (/\b(implement|implementa|scrivi|scriviamo|applica|modifica|fix|write|edit|crea|aggiungi|aggiorna|apply|patch)\b/i.test(
|
|
41764
|
-
trimmed
|
|
41765
|
-
)) {
|
|
41766
|
-
return true;
|
|
41767
|
-
}
|
|
41768
|
-
if (prior && prior.length > 0 && isShortContinueReply(trimmed)) {
|
|
41769
|
-
const lastAsst = [...prior].reverse().find((m) => m.role === "assistant" && (m.content ?? "").trim());
|
|
41770
|
-
if (lastAsst && /\b(se confermi|passo alla|scriv|implement|on disk|write_file|modifiche proposte|riepilogo delle modifiche)\b/i.test(
|
|
41771
|
-
lastAsst.content
|
|
41772
|
-
)) {
|
|
41773
|
-
return true;
|
|
41774
|
-
}
|
|
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" };
|
|
41775
42351
|
}
|
|
41776
|
-
|
|
41777
|
-
|
|
41778
|
-
|
|
41779
|
-
const messages = prior ?? [];
|
|
41780
|
-
const trimmed = task.trim();
|
|
41781
|
-
let userPart = maybeAnchorShortAnswer(task) ?? task;
|
|
41782
|
-
const continued = buildContinueUserMessage(trimmed, messages, {
|
|
41783
|
-
maxPriorChars: 4500
|
|
41784
|
-
});
|
|
41785
|
-
if (continued) {
|
|
41786
|
-
userPart = continued;
|
|
42352
|
+
const existing = await mirror.derivedPriorTurns();
|
|
42353
|
+
if (existing && existing.length > 0) {
|
|
42354
|
+
return { history: derivedModelSeed(existing), importedCount: 0, source: "spine" };
|
|
41787
42355
|
}
|
|
41788
|
-
|
|
41789
|
-
|
|
41790
|
-
if (userPart.includes("Prior assistant output")) {
|
|
41791
|
-
return userPart;
|
|
42356
|
+
if (legacySeed.length === 0) {
|
|
42357
|
+
return { history: [], importedCount: 0, source: "spine" };
|
|
41792
42358
|
}
|
|
41793
|
-
|
|
41794
|
-
|
|
41795
|
-
|
|
41796
|
-
|
|
41797
|
-
}
|
|
41798
|
-
|
|
41799
|
-
const messages = prior ?? [];
|
|
41800
|
-
const anchored = maybeAnchorShortAnswer(task);
|
|
41801
|
-
if (anchored) return anchored;
|
|
41802
|
-
return buildContinueUserMessage(task, messages, { maxPriorChars: 8e3 }) ?? task;
|
|
41803
|
-
}
|
|
41804
|
-
function truncate(s, max) {
|
|
41805
|
-
const t = s.replace(/\s+/g, " ").trim();
|
|
41806
|
-
if (t.length <= max) return t;
|
|
41807
|
-
return `${t.slice(0, max - 1)}\u2026`;
|
|
41808
|
-
}
|
|
41809
|
-
function _resetConversationContextForTests() {
|
|
41810
|
-
history = [];
|
|
41811
|
-
lastClarification = null;
|
|
41812
|
-
clearSessionTodos();
|
|
41813
|
-
clearSessionPermissionGrants();
|
|
41814
|
-
}
|
|
41815
|
-
var history, lastClarification, SHORT_CONTINUE, SHORT_CONTINUE_LOOSE;
|
|
41816
|
-
var init_conversationContext = __esm({
|
|
41817
|
-
"src/cli/hooks/conversationContext.ts"() {
|
|
41818
|
-
"use strict";
|
|
41819
|
-
init_toolPermissions();
|
|
41820
|
-
init_sessionTodos();
|
|
41821
|
-
init_historyCompaction();
|
|
41822
|
-
init_requestSnapshotStore();
|
|
41823
|
-
init_observationStore();
|
|
41824
|
-
history = [];
|
|
41825
|
-
lastClarification = null;
|
|
41826
|
-
SHORT_CONTINUE = /^(procedi|continua|continue|go\s*ahead|go|ok|okay|sì|si|yes|vai|avanti|next|proceed|conferma|confermo|applica|fai|scrivi|esegui|implementa|vai pure|fai pure|ok procedi|sì procedi|si procedi)$/i;
|
|
41827
|
-
SHORT_CONTINUE_LOOSE = /\b(procedi|continua|continue|conferma|confermo|applica|implementa|scriv[ia]|esegui|vai pure|fai pure|go ahead|proceed)\b/i;
|
|
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
|
+
}
|
|
41828
42365
|
}
|
|
41829
|
-
|
|
41830
|
-
|
|
41831
|
-
|
|
41832
|
-
|
|
41833
|
-
|
|
41834
|
-
|
|
41835
|
-
|
|
41836
|
-
setPhase: () => setPhase
|
|
41837
|
-
});
|
|
41838
|
-
function getPhase() {
|
|
41839
|
-
return phase;
|
|
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
|
+
};
|
|
41840
42373
|
}
|
|
41841
|
-
function
|
|
41842
|
-
|
|
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);
|
|
41843
42384
|
}
|
|
41844
|
-
function
|
|
41845
|
-
|
|
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);
|
|
41846
42398
|
}
|
|
41847
|
-
var
|
|
41848
|
-
|
|
41849
|
-
"src/cli/phaseState.ts"() {
|
|
42399
|
+
var init_headlessSpine = __esm({
|
|
42400
|
+
"src/cli/headlessSpine.ts"() {
|
|
41850
42401
|
"use strict";
|
|
41851
|
-
|
|
42402
|
+
init_dist();
|
|
42403
|
+
init_session();
|
|
42404
|
+
init_mission2();
|
|
42405
|
+
init_runtime2();
|
|
42406
|
+
init_sessionSpine();
|
|
42407
|
+
init_headless();
|
|
41852
42408
|
}
|
|
41853
42409
|
});
|
|
41854
42410
|
|
|
@@ -56992,9 +57548,6 @@ function strictGateEventPayload(evaluation) {
|
|
|
56992
57548
|
};
|
|
56993
57549
|
}
|
|
56994
57550
|
|
|
56995
|
-
// src/cli/hooks/useChatTurn.ts
|
|
56996
|
-
init_headlessSpine();
|
|
56997
|
-
|
|
56998
57551
|
// src/cli/hooks/permissionPicker.ts
|
|
56999
57552
|
init_toolPermissions();
|
|
57000
57553
|
|
|
@@ -57143,6 +57696,15 @@ init_envNumber();
|
|
|
57143
57696
|
init_historyCompaction();
|
|
57144
57697
|
init_observationStore();
|
|
57145
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
|
+
}
|
|
57146
57708
|
function estimateTokens(text) {
|
|
57147
57709
|
if (!text) return 0;
|
|
57148
57710
|
return Math.max(1, Math.ceil(text.length / 4));
|
|
@@ -57186,21 +57748,23 @@ async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
|
57186
57748
|
const warnings = [];
|
|
57187
57749
|
let { historyTurns, maxToolLoopIterations } = phaseKnobs(phase2);
|
|
57188
57750
|
const envelope = opts?.requestSnapshot ?? null;
|
|
57189
|
-
const
|
|
57190
|
-
|
|
57191
|
-
|
|
57192
|
-
|
|
57193
|
-
|
|
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
|
|
57194
57757
|
} : opts?.providerStream ? { provider: "local", model: opts?.model ?? "unknown", systemMessages: [], tools: [] } : null;
|
|
57195
|
-
const headerTokens =
|
|
57758
|
+
const headerTokens = surface ? estimateSystemTokensLite(surface.systemMessages) + estimateToolSchemaTokensLite(surface.tools) : 0;
|
|
57196
57759
|
const convTokensOf = (h) => estimateConversationTokensLite(h);
|
|
57197
57760
|
let hist = history2;
|
|
57198
|
-
let estimated =
|
|
57761
|
+
let estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
57199
57762
|
let occupancy = Math.min(1, estimated / contextLimit);
|
|
57200
57763
|
let compactSummary = "";
|
|
57201
57764
|
let messagesRemoved = 0;
|
|
57202
57765
|
let cacheReuseExpected;
|
|
57203
57766
|
let prunedTotal = 0;
|
|
57767
|
+
const compactRange = { sourceSeqs: [] };
|
|
57204
57768
|
if (occupancy >= compact.warnAt && occupancy < compact.compactAt) {
|
|
57205
57769
|
warnings.push(
|
|
57206
57770
|
`[budget] context ~${Math.round(occupancy * 100)}% full (${estimated}/${contextLimit} tok full-request est.) \u2014 consider /compact or shorter replies.`
|
|
@@ -57211,7 +57775,7 @@ async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
|
57211
57775
|
if (pruned.stats.pruned > 0) {
|
|
57212
57776
|
hist = pruned.messages;
|
|
57213
57777
|
prunedTotal += pruned.stats.pruned;
|
|
57214
|
-
estimated =
|
|
57778
|
+
estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
57215
57779
|
occupancy = Math.min(1, estimated / contextLimit);
|
|
57216
57780
|
warnings.push(
|
|
57217
57781
|
`[budget] pruned ${pruned.stats.pruned} oversized tool result(s) \u2192 ${Math.round(occupancy * 100)}% (${estimated} tok).`
|
|
@@ -57223,11 +57787,12 @@ async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
|
57223
57787
|
if (r.compacted) {
|
|
57224
57788
|
messagesRemoved += r.messagesRemoved;
|
|
57225
57789
|
if (r.summary) compactSummary = r.summary;
|
|
57790
|
+
mergeCompactRange(compactRange, r);
|
|
57226
57791
|
if (r.cacheReuseExpected !== void 0) {
|
|
57227
57792
|
cacheReuseExpected = r.cacheReuseExpected;
|
|
57228
57793
|
}
|
|
57229
57794
|
}
|
|
57230
|
-
estimated =
|
|
57795
|
+
estimated = surface ? headerTokens + convTokensOf(hist) + RESERVED_OUTPUT_TOKENS : estimateHistoryTokens(hist) + sessionExtra;
|
|
57231
57796
|
occupancy = Math.min(1, estimated / contextLimit);
|
|
57232
57797
|
warnings.push(
|
|
57233
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)" : "") + ")."
|
|
@@ -57283,12 +57848,18 @@ async function applyBudgetPolicyAsync(history2, phase2, opts) {
|
|
|
57283
57848
|
warnings,
|
|
57284
57849
|
maxToolLoopIterations,
|
|
57285
57850
|
historyTurns,
|
|
57286
|
-
estimatedHistoryTokens:
|
|
57851
|
+
estimatedHistoryTokens: surface ? convTokensOf(hist) : estimated,
|
|
57287
57852
|
contextLimit,
|
|
57288
57853
|
occupancy,
|
|
57289
57854
|
compactSummary: compactSummary || void 0,
|
|
57290
57855
|
messagesRemoved: messagesRemoved || void 0,
|
|
57291
|
-
...
|
|
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 } : {},
|
|
57292
57863
|
...cacheReuseExpected !== void 0 ? { cacheReuseExpected } : {},
|
|
57293
57864
|
...cacheMetricsLine ? { cacheMetricsLine } : {}
|
|
57294
57865
|
};
|
|
@@ -57323,6 +57894,231 @@ function estimateConversationTokensLite(messages) {
|
|
|
57323
57894
|
return n;
|
|
57324
57895
|
}
|
|
57325
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
|
+
|
|
57326
58122
|
// src/cli/hooks/useChatTurn.ts
|
|
57327
58123
|
init_requestSnapshotStore();
|
|
57328
58124
|
function useChatTurn(params) {
|
|
@@ -57358,19 +58154,7 @@ function useChatTurn(params) {
|
|
|
57358
58154
|
try {
|
|
57359
58155
|
const anchored = maybeAnchorShortAnswer(userText);
|
|
57360
58156
|
const effectiveUserText = anchored ?? userText;
|
|
57361
|
-
let historyForModel;
|
|
57362
|
-
{
|
|
57363
|
-
const mirror = writerRef.current?.spine ?? null;
|
|
57364
|
-
let spineSeed = null;
|
|
57365
|
-
if (mirror && mirror.status === "active") {
|
|
57366
|
-
const derived = await mirror.derivedPriorTurns();
|
|
57367
|
-
if (derived && derived.length > 0) {
|
|
57368
|
-
spineSeed = derivedModelSeed(derived);
|
|
57369
|
-
}
|
|
57370
|
-
}
|
|
57371
|
-
historyForModel = spineSeed ?? getHistory();
|
|
57372
|
-
}
|
|
57373
|
-
writerRef.current?.spine?.userMessage(effectiveUserText);
|
|
58157
|
+
let historyForModel = getHistory();
|
|
57374
58158
|
const localCli = (process.env.ZELARI_LOCAL_CLI ?? "").trim();
|
|
57375
58159
|
let localCliProvider = null;
|
|
57376
58160
|
if (localCli) {
|
|
@@ -57499,33 +58283,42 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
57499
58283
|
});
|
|
57500
58284
|
}
|
|
57501
58285
|
const cwd = process.cwd();
|
|
57502
|
-
const
|
|
58286
|
+
const requestSnapshot = getRequestSnapshotWithUsage(sessionId2);
|
|
58287
|
+
const modelContext = await buildModelContext({
|
|
58288
|
+
fallbackHistory: historyForModel,
|
|
58289
|
+
session: writerRef.current?.spine ?? null,
|
|
58290
|
+
phase: workPhase,
|
|
57503
58291
|
model: getActiveModel(),
|
|
58292
|
+
provider: envConfig?.providerId ?? (localCli || "local"),
|
|
57504
58293
|
sessionId: sessionId2,
|
|
57505
|
-
|
|
57506
|
-
|
|
57507
|
-
|
|
57508
|
-
|
|
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
|
+
}
|
|
57509
58314
|
});
|
|
57510
|
-
|
|
57511
|
-
|
|
57512
|
-
|
|
57513
|
-
|
|
57514
|
-
|
|
57515
|
-
const envelope = getRequestSnapshotWithUsage(sessionId2);
|
|
57516
|
-
const compactionEvent = createBrainEvent("session_compacted", sessionId2, {
|
|
57517
|
-
summary: budget.compactSummary ?? "",
|
|
57518
|
-
messagesRemoved: budget.messagesRemoved ?? 0,
|
|
57519
|
-
...envelope ? {
|
|
57520
|
-
sourceRequestFingerprint: envelope.snapshot.requestFingerprint,
|
|
57521
|
-
headerFingerprint: envelope.snapshot.headerFingerprint
|
|
57522
|
-
} : {},
|
|
57523
|
-
...budget.contextPressureTokens !== void 0 ? { sourceEstimatedTokens: budget.contextPressureTokens } : {},
|
|
57524
|
-
...budget.cacheReuseExpected !== void 0 ? { cacheReuseExpected: budget.cacheReuseExpected } : {}
|
|
57525
|
-
});
|
|
57526
|
-
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());
|
|
57527
58320
|
}
|
|
57528
|
-
|
|
58321
|
+
writerRef.current?.spine?.userMessage(effectiveUserText);
|
|
57529
58322
|
historySeedLen = historyForModel.length;
|
|
57530
58323
|
let composedWorkspace = "";
|
|
57531
58324
|
let composedInstructions = "";
|
|
@@ -58164,33 +58957,33 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
58164
58957
|
return { completionOk: false, ran: false };
|
|
58165
58958
|
}
|
|
58166
58959
|
setBusy(true);
|
|
58167
|
-
|
|
58168
|
-
|
|
58169
|
-
|
|
58170
|
-
|
|
58171
|
-
|
|
58172
|
-
|
|
58173
|
-
|
|
58174
|
-
|
|
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
|
+
);
|
|
58175
58979
|
}
|
|
58176
|
-
}
|
|
58177
|
-
const councilBudget = await applyBudgetPolicyAsync(councilHistory, getPhase(), {
|
|
58178
|
-
model: envConfig.model
|
|
58179
58980
|
});
|
|
58180
|
-
|
|
58181
|
-
|
|
58182
|
-
|
|
58183
|
-
|
|
58184
|
-
if ((councilBudget.messagesRemoved ?? 0) > 0) {
|
|
58185
|
-
void writerRef.current?.append(
|
|
58186
|
-
createBrainEvent("session_compacted", sessionId2, {
|
|
58187
|
-
summary: councilBudget.compactSummary ?? "",
|
|
58188
|
-
messagesRemoved: councilBudget.messagesRemoved ?? 0
|
|
58189
|
-
})
|
|
58190
|
-
);
|
|
58981
|
+
const councilBudget = councilContext.budget;
|
|
58982
|
+
setHistory(councilContext.history);
|
|
58983
|
+
for (const warning of councilBudget.warnings) {
|
|
58984
|
+
appendSystem(setMessages, warning, Date.now());
|
|
58191
58985
|
}
|
|
58192
|
-
|
|
58193
|
-
const effectiveText = anchored ?? text;
|
|
58986
|
+
writerRef.current?.spine?.userMessage(effectiveText);
|
|
58194
58987
|
appendSystem(
|
|
58195
58988
|
setMessages,
|
|
58196
58989
|
`[phase] ${describePhase(getPhase())}`,
|
|
@@ -63204,6 +63997,7 @@ async function runAdvisoryVerifierReview(evaluation, deps = {}) {
|
|
|
63204
63997
|
}
|
|
63205
63998
|
|
|
63206
63999
|
// src/cli/runHeadless.ts
|
|
64000
|
+
init_metrics2();
|
|
63207
64001
|
init_headlessSpine();
|
|
63208
64002
|
async function runHeadless(opts) {
|
|
63209
64003
|
resetTaskSpawnCount();
|
|
@@ -63539,7 +64333,6 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
63539
64333
|
});
|
|
63540
64334
|
const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
|
|
63541
64335
|
emitEvent(sessionStartedEvent(spine));
|
|
63542
|
-
if (opts.task) spine.userMessage(opts.task);
|
|
63543
64336
|
resetKrakenCandidates();
|
|
63544
64337
|
resetKrakenTurnMetrics();
|
|
63545
64338
|
const { registry: toolRegistry } = createBuiltinToolRegistry({
|
|
@@ -63689,14 +64482,38 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
|
|
|
63689
64482
|
}
|
|
63690
64483
|
];
|
|
63691
64484
|
}
|
|
63692
|
-
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
|
+
}
|
|
63693
64509
|
const effectiveTask = buildAgentUserWithHistory(opts.task, historySeed);
|
|
64510
|
+
if (opts.task) spine.userMessage(effectiveTask);
|
|
63694
64511
|
const maxToolLoop = (() => {
|
|
63695
64512
|
const n = envNumber(process.env.ZELARI_MAX_TOOL_LOOP_ITERATIONS, {
|
|
63696
64513
|
default: 30,
|
|
63697
64514
|
min: 1
|
|
63698
64515
|
});
|
|
63699
|
-
return n;
|
|
64516
|
+
return Math.min(n, modelContext.budget.maxToolLoopIterations);
|
|
63700
64517
|
})();
|
|
63701
64518
|
async function runSinglePass(messages, passSessionId) {
|
|
63702
64519
|
const harness = new AgentHarness({
|
|
@@ -63997,7 +64814,6 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
63997
64814
|
});
|
|
63998
64815
|
const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
|
|
63999
64816
|
emitEvent(sessionStartedEvent(spine));
|
|
64000
|
-
if (opts.task) spine.userMessage(opts.task);
|
|
64001
64817
|
const { shouldAllowCouncilBuild: shouldAllowCouncilBuild2 } = await Promise.resolve().then(() => (init_buildPolicy(), buildPolicy_exports));
|
|
64002
64818
|
let councilRunMode = planModeFromOpts(opts) ? "design-phase" : "implementation";
|
|
64003
64819
|
let softGated = false;
|
|
@@ -64014,8 +64830,36 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
64014
64830
|
);
|
|
64015
64831
|
const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
|
|
64016
64832
|
const feedbackStore = new FeedbackStore2();
|
|
64017
|
-
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
|
+
}
|
|
64018
64861
|
const effectiveTask = buildCouncilTaskWithHistory(opts.task, historySeed);
|
|
64862
|
+
if (opts.task) spine.userMessage(effectiveTask);
|
|
64019
64863
|
let exitCode = 0;
|
|
64020
64864
|
const scrub = createStreamScrubber2();
|
|
64021
64865
|
let lastAssistantText = "";
|
|
@@ -64125,7 +64969,6 @@ async function runHeadlessZelari(opts, provider, model, providerStream) {
|
|
|
64125
64969
|
});
|
|
64126
64970
|
const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
|
|
64127
64971
|
emitEvent(sessionStartedEvent(spine));
|
|
64128
|
-
if (opts.task) spine.userMessage(opts.task);
|
|
64129
64972
|
spine.missionPhase("design", "mission-start");
|
|
64130
64973
|
const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
64131
64974
|
const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
|
|
@@ -64157,8 +65000,33 @@ async function runHeadlessZelari(opts, provider, model, providerStream) {
|
|
|
64157
65000
|
process.stderr.write(message + "\n");
|
|
64158
65001
|
}
|
|
64159
65002
|
};
|
|
64160
|
-
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);
|
|
64161
65028
|
const missionTask = buildCouncilTaskWithHistory(opts.task, historySeed);
|
|
65029
|
+
if (opts.task) spine.userMessage(missionTask);
|
|
64162
65030
|
emit(`[zelari] mission brief
|
|
64163
65031
|
${JSON.stringify({ deliverable: brief.deliverableThisMission, mvp: brief.sliceMvp?.title }, null, 0)}`);
|
|
64164
65032
|
if (buildViaAgent) {
|