zelari-code 2.37.2 → 2.38.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/asyncLimit.js +53 -0
- package/dist/cli/asyncLimit.js.map +1 -0
- package/dist/cli/budget/restoreRuntime.js +10 -5
- package/dist/cli/budget/restoreRuntime.js.map +1 -1
- package/dist/cli/crossProviderFailover.js +32 -0
- package/dist/cli/crossProviderFailover.js.map +1 -1
- package/dist/cli/harnessState.js +7 -3
- package/dist/cli/harnessState.js.map +1 -1
- package/dist/cli/headless/liveTurnAbort.js +1 -1
- package/dist/cli/headless/liveTurnAbort.js.map +1 -1
- package/dist/cli/headless/runOneTurn.js +15 -5
- package/dist/cli/headless/runOneTurn.js.map +1 -1
- package/dist/cli/headlessSpine.js +7 -3
- package/dist/cli/headlessSpine.js.map +1 -1
- package/dist/cli/kraken/cachedShell.js +162 -0
- package/dist/cli/kraken/cachedShell.js.map +1 -0
- package/dist/cli/kraken/contractCompiler.js +6 -1
- package/dist/cli/kraken/contractCompiler.js.map +1 -1
- package/dist/cli/kraken/executor.js +27 -17
- package/dist/cli/kraken/executor.js.map +1 -1
- package/dist/cli/kraken/nativeVerification.js +9 -1
- package/dist/cli/kraken/nativeVerification.js.map +1 -1
- package/dist/cli/kraken/worktreeCleanupBatch.js +110 -0
- package/dist/cli/kraken/worktreeCleanupBatch.js.map +1 -0
- package/dist/cli/main.bundled.js +1323 -510
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/memory/legacyImport.js +66 -14
- package/dist/cli/memory/legacyImport.js.map +1 -1
- package/dist/cli/memory/sqliteBackend.js +19 -5
- package/dist/cli/memory/sqliteBackend.js.map +1 -1
- package/dist/cli/providerFailover.js +21 -2
- package/dist/cli/providerFailover.js.map +1 -1
- package/dist/cli/runHeadless.js +32 -1
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/serve/harnessServer.js +6 -2
- package/dist/cli/serve/harnessServer.js.map +1 -1
- package/dist/cli/serve/sessionControl.js.map +1 -1
- package/dist/cli/sessionSpine.js +26 -10
- package/dist/cli/sessionSpine.js.map +1 -1
- package/dist/cli/toolRegistry.js +23 -4
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/krakenModel.js +72 -9
- package/dist/cli/tools/krakenModel.js.map +1 -1
- package/dist/cli/tools/krakenRadio.js +60 -3
- package/dist/cli/tools/krakenRadio.js.map +1 -1
- package/dist/cli/tools/krakenWorktree.js +105 -4
- package/dist/cli/tools/krakenWorktree.js.map +1 -1
- package/dist/cli/tools/taskTool.js +64 -40
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/dist/cli/tools/tentacleHeartbeat.js +47 -0
- package/dist/cli/tools/tentacleHeartbeat.js.map +1 -0
- package/package.json +3 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -19560,11 +19560,11 @@ var init_listFiles = __esm({
|
|
|
19560
19560
|
return 1;
|
|
19561
19561
|
return a.name.localeCompare(b.name);
|
|
19562
19562
|
});
|
|
19563
|
-
const
|
|
19564
|
-
const truncated = entries.length >
|
|
19563
|
+
const MAX_ENTRIES3 = 500;
|
|
19564
|
+
const truncated = entries.length > MAX_ENTRIES3;
|
|
19565
19565
|
const warnings = entries.length === 0 ? ["DIR_EMPTY"] : [];
|
|
19566
19566
|
const status = entries.length === 0 ? "empty" : truncated ? "partial" : "complete";
|
|
19567
|
-
return typedOk({ dir: target, entries: truncated ? entries.slice(0,
|
|
19567
|
+
return typedOk({ dir: target, entries: truncated ? entries.slice(0, MAX_ENTRIES3) : entries, truncated }, {
|
|
19568
19568
|
status,
|
|
19569
19569
|
counts: { filesWalked: entries.length },
|
|
19570
19570
|
...warnings.length > 0 ? { warnings } : {},
|
|
@@ -22452,6 +22452,12 @@ var init_worktreeWorkspace = __esm({
|
|
|
22452
22452
|
|
|
22453
22453
|
// packages/core/dist/core/requestSnapshot.js
|
|
22454
22454
|
import { createHash as createHash3 } from "node:crypto";
|
|
22455
|
+
function resolveRequestSnapshotMode(env = process.env) {
|
|
22456
|
+
const raw = env.ZELARI_REQUEST_SNAPSHOT?.trim().toLowerCase();
|
|
22457
|
+
if (raw === "lite" || raw === "off")
|
|
22458
|
+
return raw;
|
|
22459
|
+
return "full";
|
|
22460
|
+
}
|
|
22455
22461
|
function stableStringify(value) {
|
|
22456
22462
|
if (value === null || typeof value !== "object")
|
|
22457
22463
|
return JSON.stringify(value) ?? "null";
|
|
@@ -22467,43 +22473,96 @@ function stableStringify(value) {
|
|
|
22467
22473
|
function sha256Hex(input) {
|
|
22468
22474
|
return createHash3("sha256").update(input, "utf8").digest("hex").slice(0, 32);
|
|
22469
22475
|
}
|
|
22470
|
-
function
|
|
22476
|
+
function cloneMessagesDeep(messages) {
|
|
22471
22477
|
return structuredClone(messages);
|
|
22472
22478
|
}
|
|
22479
|
+
function cloneMessagesLite(messages) {
|
|
22480
|
+
return messages.map((m) => ({ ...m }));
|
|
22481
|
+
}
|
|
22473
22482
|
function canonicalTools(tools) {
|
|
22474
22483
|
return [...tools].sort((a, b) => a.name.localeCompare(b.name));
|
|
22475
22484
|
}
|
|
22485
|
+
function cloneToolsDeep(tools) {
|
|
22486
|
+
return canonicalTools(tools).map((t) => structuredClone(t));
|
|
22487
|
+
}
|
|
22488
|
+
function cloneToolsLite(tools) {
|
|
22489
|
+
return canonicalTools(tools).map((t) => ({ ...t }));
|
|
22490
|
+
}
|
|
22491
|
+
function __resetRequestSnapshotMemoForTests() {
|
|
22492
|
+
headerMemo = null;
|
|
22493
|
+
}
|
|
22476
22494
|
function createRoutedRequestSnapshot(params) {
|
|
22495
|
+
const mode = params.mode ?? resolveRequestSnapshotMode();
|
|
22477
22496
|
let split = 0;
|
|
22478
22497
|
while (split < params.messages.length && params.messages[split].role === "system") {
|
|
22479
22498
|
split++;
|
|
22480
22499
|
}
|
|
22481
|
-
const
|
|
22482
|
-
const
|
|
22483
|
-
const
|
|
22484
|
-
const
|
|
22485
|
-
|
|
22486
|
-
|
|
22487
|
-
|
|
22488
|
-
tools
|
|
22489
|
-
|
|
22490
|
-
|
|
22491
|
-
|
|
22492
|
-
|
|
22493
|
-
|
|
22494
|
-
|
|
22495
|
-
|
|
22496
|
-
|
|
22497
|
-
|
|
22498
|
-
|
|
22499
|
-
|
|
22500
|
+
const lite = mode === "lite";
|
|
22501
|
+
const cloneMsg = lite ? cloneMessagesLite : cloneMessagesDeep;
|
|
22502
|
+
const systemMessages = cloneMsg(params.messages.slice(0, split));
|
|
22503
|
+
const conversation = cloneMsg(params.messages.slice(split));
|
|
22504
|
+
const createdAt = Date.now();
|
|
22505
|
+
const { provider, model } = params;
|
|
22506
|
+
if (!lite) {
|
|
22507
|
+
const tools2 = cloneToolsDeep(params.tools);
|
|
22508
|
+
const header = stableStringify({ provider, model, systemMessages, tools: tools2 });
|
|
22509
|
+
const request = stableStringify({
|
|
22510
|
+
provider,
|
|
22511
|
+
model,
|
|
22512
|
+
systemMessages,
|
|
22513
|
+
tools: tools2,
|
|
22514
|
+
conversation
|
|
22515
|
+
});
|
|
22516
|
+
return {
|
|
22517
|
+
provider,
|
|
22518
|
+
model,
|
|
22519
|
+
systemMessages,
|
|
22520
|
+
conversation,
|
|
22521
|
+
tools: tools2,
|
|
22522
|
+
headerFingerprint: sha256Hex(header),
|
|
22523
|
+
requestFingerprint: sha256Hex(request),
|
|
22524
|
+
createdAt
|
|
22525
|
+
};
|
|
22526
|
+
}
|
|
22527
|
+
const systemKey = sha256Hex(stableStringify(systemMessages));
|
|
22528
|
+
let tools;
|
|
22529
|
+
let headerFp;
|
|
22530
|
+
if (headerMemo && headerMemo.toolsRef === params.tools && headerMemo.provider === provider && headerMemo.model === model && headerMemo.systemKey === systemKey) {
|
|
22531
|
+
tools = headerMemo.tools;
|
|
22532
|
+
headerFp = headerMemo.headerFingerprint;
|
|
22533
|
+
} else {
|
|
22534
|
+
tools = cloneToolsLite(params.tools);
|
|
22535
|
+
}
|
|
22536
|
+
let requestFp;
|
|
22537
|
+
const snap = {
|
|
22538
|
+
provider,
|
|
22539
|
+
model,
|
|
22500
22540
|
systemMessages,
|
|
22501
22541
|
conversation,
|
|
22502
22542
|
tools,
|
|
22503
|
-
|
|
22504
|
-
|
|
22505
|
-
|
|
22543
|
+
createdAt,
|
|
22544
|
+
get headerFingerprint() {
|
|
22545
|
+
if (headerFp === void 0) {
|
|
22546
|
+
headerFp = sha256Hex(stableStringify({ provider, model, systemMessages, tools }));
|
|
22547
|
+
headerMemo = {
|
|
22548
|
+
toolsRef: params.tools,
|
|
22549
|
+
provider,
|
|
22550
|
+
model,
|
|
22551
|
+
systemKey,
|
|
22552
|
+
tools,
|
|
22553
|
+
headerFingerprint: headerFp
|
|
22554
|
+
};
|
|
22555
|
+
}
|
|
22556
|
+
return headerFp;
|
|
22557
|
+
},
|
|
22558
|
+
get requestFingerprint() {
|
|
22559
|
+
if (requestFp === void 0) {
|
|
22560
|
+
requestFp = sha256Hex(stableStringify({ provider, model, systemMessages, tools, conversation }));
|
|
22561
|
+
}
|
|
22562
|
+
return requestFp;
|
|
22563
|
+
}
|
|
22506
22564
|
};
|
|
22565
|
+
return snap;
|
|
22507
22566
|
}
|
|
22508
22567
|
function compareReplayPrefix(snapshot, messages) {
|
|
22509
22568
|
const base2 = snapshot.conversation;
|
|
@@ -22517,9 +22576,11 @@ function compareReplayPrefix(snapshot, messages) {
|
|
|
22517
22576
|
}
|
|
22518
22577
|
return { exact: true, matchingMessages: matching };
|
|
22519
22578
|
}
|
|
22579
|
+
var headerMemo;
|
|
22520
22580
|
var init_requestSnapshot = __esm({
|
|
22521
22581
|
"packages/core/dist/core/requestSnapshot.js"() {
|
|
22522
22582
|
"use strict";
|
|
22583
|
+
headerMemo = null;
|
|
22523
22584
|
}
|
|
22524
22585
|
});
|
|
22525
22586
|
|
|
@@ -23520,15 +23581,22 @@ async function readSessionLog(filePath) {
|
|
|
23520
23581
|
}
|
|
23521
23582
|
throw err;
|
|
23522
23583
|
}
|
|
23584
|
+
return parseSessionLogText(filePath, content);
|
|
23585
|
+
}
|
|
23586
|
+
function parseSessionLogText(filePath, content) {
|
|
23587
|
+
const { events, issues } = parseSessionLogLines(content.split("\n"));
|
|
23588
|
+
return { path: filePath, events, issues, ok: issues.length === 0 };
|
|
23589
|
+
}
|
|
23590
|
+
function parseSessionLogLines(lines, opts = {}) {
|
|
23523
23591
|
const events = [];
|
|
23524
23592
|
const issues = [];
|
|
23525
|
-
|
|
23526
|
-
|
|
23593
|
+
const base2 = opts.linesConsumed ?? 0;
|
|
23594
|
+
let expected = opts.expected ?? 1;
|
|
23527
23595
|
for (let i = 0; i < lines.length; i++) {
|
|
23528
23596
|
const trimmed = lines[i].trim();
|
|
23529
23597
|
if (!trimmed)
|
|
23530
23598
|
continue;
|
|
23531
|
-
const lineNo = i + 1;
|
|
23599
|
+
const lineNo = base2 + i + 1;
|
|
23532
23600
|
let parsed;
|
|
23533
23601
|
try {
|
|
23534
23602
|
parsed = JSON.parse(trimmed);
|
|
@@ -23562,7 +23630,7 @@ async function readSessionLog(filePath) {
|
|
|
23562
23630
|
expected = envelope.seq + 1;
|
|
23563
23631
|
}
|
|
23564
23632
|
}
|
|
23565
|
-
return {
|
|
23633
|
+
return { events, issues, expected, linesConsumed: base2 + lines.length };
|
|
23566
23634
|
}
|
|
23567
23635
|
function parseVerification(e) {
|
|
23568
23636
|
const raw = Array.isArray(e.data.results) ? e.data.results : [];
|
|
@@ -23810,7 +23878,7 @@ async function createExecutionContext(options = {}) {
|
|
|
23810
23878
|
workspaceKind: workspace.kind
|
|
23811
23879
|
}
|
|
23812
23880
|
});
|
|
23813
|
-
const
|
|
23881
|
+
const fs49 = options.fs ?? new NodeFsProvider(workspace);
|
|
23814
23882
|
const shell = options.shell ?? new NodeShellProvider(workspace);
|
|
23815
23883
|
const subagent = options.subagent ?? NOOP_SUBAGENT_PROVIDER;
|
|
23816
23884
|
const env = options.env ?? process.env;
|
|
@@ -23818,7 +23886,7 @@ async function createExecutionContext(options = {}) {
|
|
|
23818
23886
|
sessionId: sessionId2,
|
|
23819
23887
|
profile,
|
|
23820
23888
|
workspace,
|
|
23821
|
-
fs:
|
|
23889
|
+
fs: fs49,
|
|
23822
23890
|
shell,
|
|
23823
23891
|
subagent,
|
|
23824
23892
|
appendSessionEvent: (input) => writer.append(input),
|
|
@@ -25589,6 +25657,60 @@ var init_scopeDiscipline = __esm({
|
|
|
25589
25657
|
}
|
|
25590
25658
|
});
|
|
25591
25659
|
|
|
25660
|
+
// packages/core/dist/verification/commandConcurrency.js
|
|
25661
|
+
function isVerifyParallelEnabled(env = process.env) {
|
|
25662
|
+
const raw = env.ZELARI_VERIFY_PARALLEL?.trim().toLowerCase();
|
|
25663
|
+
return raw !== void 0 && PARALLEL_TRUTHY.has(raw);
|
|
25664
|
+
}
|
|
25665
|
+
function resolveCommandConcurrency(env = process.env) {
|
|
25666
|
+
if (!isVerifyParallelEnabled(env))
|
|
25667
|
+
return 1;
|
|
25668
|
+
const raw = Number(env.ZELARI_VERIFY_CONCURRENCY);
|
|
25669
|
+
if (!Number.isFinite(raw) || raw <= 0)
|
|
25670
|
+
return DEFAULT_COMMAND_CONCURRENCY;
|
|
25671
|
+
return Math.floor(raw);
|
|
25672
|
+
}
|
|
25673
|
+
var DEFAULT_COMMAND_CONCURRENCY, PARALLEL_TRUTHY;
|
|
25674
|
+
var init_commandConcurrency = __esm({
|
|
25675
|
+
"packages/core/dist/verification/commandConcurrency.js"() {
|
|
25676
|
+
"use strict";
|
|
25677
|
+
DEFAULT_COMMAND_CONCURRENCY = 3;
|
|
25678
|
+
PARALLEL_TRUTHY = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
|
|
25679
|
+
}
|
|
25680
|
+
});
|
|
25681
|
+
|
|
25682
|
+
// packages/core/dist/verification/runWithLimit.js
|
|
25683
|
+
async function runWithLimit(items, limit, fn) {
|
|
25684
|
+
const slots = Math.min(items.length, Math.max(1, Number.isFinite(limit) ? Math.floor(limit) : 1));
|
|
25685
|
+
if (slots <= 0)
|
|
25686
|
+
return;
|
|
25687
|
+
let cursor = 0;
|
|
25688
|
+
let failed = false;
|
|
25689
|
+
let firstError;
|
|
25690
|
+
const worker = async () => {
|
|
25691
|
+
while (!failed && cursor < items.length) {
|
|
25692
|
+
const index = cursor;
|
|
25693
|
+
cursor += 1;
|
|
25694
|
+
try {
|
|
25695
|
+
await fn(items[index], index);
|
|
25696
|
+
} catch (err) {
|
|
25697
|
+
if (!failed) {
|
|
25698
|
+
failed = true;
|
|
25699
|
+
firstError = err;
|
|
25700
|
+
}
|
|
25701
|
+
}
|
|
25702
|
+
}
|
|
25703
|
+
};
|
|
25704
|
+
await Promise.all(Array.from({ length: slots }, () => worker()));
|
|
25705
|
+
if (failed)
|
|
25706
|
+
throw firstError;
|
|
25707
|
+
}
|
|
25708
|
+
var init_runWithLimit = __esm({
|
|
25709
|
+
"packages/core/dist/verification/runWithLimit.js"() {
|
|
25710
|
+
"use strict";
|
|
25711
|
+
}
|
|
25712
|
+
});
|
|
25713
|
+
|
|
25592
25714
|
// packages/core/dist/verification/engine.js
|
|
25593
25715
|
import { createHash as createHash8 } from "node:crypto";
|
|
25594
25716
|
function defaultSha256(input) {
|
|
@@ -25597,11 +25719,14 @@ function defaultSha256(input) {
|
|
|
25597
25719
|
function tail(text, max = 400) {
|
|
25598
25720
|
return text.length > max ? `\u2026${text.slice(text.length - max)}` : text;
|
|
25599
25721
|
}
|
|
25600
|
-
var VerificationEngine;
|
|
25722
|
+
var CACHED_DETAIL_NOTE, VerificationEngine;
|
|
25601
25723
|
var init_engine = __esm({
|
|
25602
25724
|
"packages/core/dist/verification/engine.js"() {
|
|
25603
25725
|
"use strict";
|
|
25604
25726
|
init_scopeDiscipline();
|
|
25727
|
+
init_commandConcurrency();
|
|
25728
|
+
init_runWithLimit();
|
|
25729
|
+
CACHED_DETAIL_NOTE = "cached \u2014 tree unchanged since last run";
|
|
25605
25730
|
VerificationEngine = class {
|
|
25606
25731
|
services;
|
|
25607
25732
|
options;
|
|
@@ -25612,8 +25737,15 @@ var init_engine = __esm({
|
|
|
25612
25737
|
/** Evaluate criteria deterministically; optionally emit the spine event. */
|
|
25613
25738
|
async evaluate(criteria, context = {}) {
|
|
25614
25739
|
const results = [];
|
|
25615
|
-
|
|
25616
|
-
|
|
25740
|
+
const limit = this.options.commandConcurrency ?? resolveCommandConcurrency();
|
|
25741
|
+
if (limit <= 1) {
|
|
25742
|
+
for (const criterion of criteria) {
|
|
25743
|
+
results.push(await this.evaluateOne(criterion, context.scope));
|
|
25744
|
+
}
|
|
25745
|
+
} else {
|
|
25746
|
+
await runWithLimit(criteria, limit, async (criterion, index) => {
|
|
25747
|
+
results[index] = await this.evaluateOne(criterion, context.scope);
|
|
25748
|
+
});
|
|
25617
25749
|
}
|
|
25618
25750
|
if (this.options.emit) {
|
|
25619
25751
|
try {
|
|
@@ -25704,13 +25836,18 @@ var init_engine = __esm({
|
|
|
25704
25836
|
}
|
|
25705
25837
|
}
|
|
25706
25838
|
async evalCommand(check2, done) {
|
|
25707
|
-
const
|
|
25839
|
+
const sha2562 = this.options.sha256 ?? defaultSha256;
|
|
25708
25840
|
const shell = this.services.shell;
|
|
25709
25841
|
if (!shell) {
|
|
25710
25842
|
return done({ status: "unknown", evidence: [], detail: "shell provider unavailable" });
|
|
25711
25843
|
}
|
|
25712
25844
|
const result = await shell.exec(check2.command, { timeoutMs: check2.timeoutMs });
|
|
25713
|
-
const digest =
|
|
25845
|
+
const digest = sha2562(result.stdout);
|
|
25846
|
+
const cached2 = result.cached === true;
|
|
25847
|
+
const finish2 = (patch) => cached2 ? done({
|
|
25848
|
+
...patch,
|
|
25849
|
+
detail: patch.detail ? `${patch.detail} (${CACHED_DETAIL_NOTE})` : CACHED_DETAIL_NOTE
|
|
25850
|
+
}) : done(patch);
|
|
25714
25851
|
const seq = await this.emitEvidence({
|
|
25715
25852
|
observation: "command",
|
|
25716
25853
|
command: check2.command,
|
|
@@ -25718,7 +25855,9 @@ var init_engine = __esm({
|
|
|
25718
25855
|
timedOut: result.timedOut,
|
|
25719
25856
|
digest,
|
|
25720
25857
|
stdoutTail: tail(result.stdout),
|
|
25721
|
-
stderrTail: tail(result.stderr)
|
|
25858
|
+
stderrTail: tail(result.stderr),
|
|
25859
|
+
// Additive (optional) field: replay of older logs without it still parses.
|
|
25860
|
+
...cached2 ? { cached: true } : {}
|
|
25722
25861
|
});
|
|
25723
25862
|
const evidence = [
|
|
25724
25863
|
{
|
|
@@ -25730,32 +25869,32 @@ var init_engine = __esm({
|
|
|
25730
25869
|
}
|
|
25731
25870
|
];
|
|
25732
25871
|
if (result.timedOut) {
|
|
25733
|
-
return
|
|
25872
|
+
return finish2({ status: "unknown", evidence, detail: `command timed out (${check2.timeoutMs ?? "default"}ms)` });
|
|
25734
25873
|
}
|
|
25735
25874
|
const expectExit = check2.expectExit ?? 0;
|
|
25736
25875
|
if (result.exitCode !== expectExit) {
|
|
25737
|
-
return
|
|
25876
|
+
return finish2({
|
|
25738
25877
|
status: "fail",
|
|
25739
25878
|
evidence,
|
|
25740
25879
|
detail: `exit ${result.exitCode} (expected ${expectExit}) \u2014 stderr: ${tail(result.stderr)}`
|
|
25741
25880
|
});
|
|
25742
25881
|
}
|
|
25743
25882
|
if (check2.expectStdoutIncludes && !result.stdout.includes(check2.expectStdoutIncludes)) {
|
|
25744
|
-
return
|
|
25883
|
+
return finish2({
|
|
25745
25884
|
status: "fail",
|
|
25746
25885
|
evidence,
|
|
25747
25886
|
detail: `stdout missing "${check2.expectStdoutIncludes}" \u2014 got: ${tail(result.stdout)}`
|
|
25748
25887
|
});
|
|
25749
25888
|
}
|
|
25750
|
-
return
|
|
25889
|
+
return finish2({ status: "pass", evidence });
|
|
25751
25890
|
}
|
|
25752
25891
|
/**
|
|
25753
25892
|
* F3: the fs observation is logged to the spine (path, existence, optional
|
|
25754
25893
|
* content digest) and the returned ref carries the event seq when the
|
|
25755
25894
|
* emitter resolved one.
|
|
25756
25895
|
*/
|
|
25757
|
-
async fsEvidence(observation, path101,
|
|
25758
|
-
const digest =
|
|
25896
|
+
async fsEvidence(observation, path101, sha2562, content, extra = {}) {
|
|
25897
|
+
const digest = sha2562 && content !== void 0 ? sha2562(content) : void 0;
|
|
25759
25898
|
const seq = await this.emitEvidence({ observation, path: path101, ...extra, ...digest ? { digest } : {} });
|
|
25760
25899
|
return {
|
|
25761
25900
|
tier: "fs-observation",
|
|
@@ -25766,26 +25905,26 @@ var init_engine = __esm({
|
|
|
25766
25905
|
};
|
|
25767
25906
|
}
|
|
25768
25907
|
async evalFileExists(check2, done) {
|
|
25769
|
-
const
|
|
25770
|
-
const
|
|
25771
|
-
if (!
|
|
25908
|
+
const sha2562 = this.options.sha256 ?? defaultSha256;
|
|
25909
|
+
const fs49 = this.services.fs;
|
|
25910
|
+
if (!fs49)
|
|
25772
25911
|
return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
|
|
25773
|
-
const exists = await
|
|
25912
|
+
const exists = await fs49.exists(check2.path);
|
|
25774
25913
|
if (!exists) {
|
|
25775
25914
|
await this.emitEvidence({ observation: "file-exists", path: check2.path, exists: false });
|
|
25776
25915
|
return done({ status: "fail", evidence: [], detail: `file not found: ${check2.path}` });
|
|
25777
25916
|
}
|
|
25778
|
-
const content = await
|
|
25917
|
+
const content = await fs49.readFile(check2.path).catch(() => "");
|
|
25779
25918
|
return done({
|
|
25780
25919
|
status: "pass",
|
|
25781
|
-
evidence: [await this.fsEvidence("file-exists", check2.path,
|
|
25920
|
+
evidence: [await this.fsEvidence("file-exists", check2.path, sha2562, content, { exists: true })]
|
|
25782
25921
|
});
|
|
25783
25922
|
}
|
|
25784
25923
|
async evalFileAbsent(check2, done) {
|
|
25785
|
-
const
|
|
25786
|
-
if (!
|
|
25924
|
+
const fs49 = this.services.fs;
|
|
25925
|
+
if (!fs49)
|
|
25787
25926
|
return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
|
|
25788
|
-
const exists = await
|
|
25927
|
+
const exists = await fs49.exists(check2.path);
|
|
25789
25928
|
if (exists) {
|
|
25790
25929
|
await this.emitEvidence({ observation: "file-absent", path: check2.path, exists: true });
|
|
25791
25930
|
return done({ status: "fail", evidence: [], detail: `file still present: ${check2.path}` });
|
|
@@ -25796,18 +25935,18 @@ var init_engine = __esm({
|
|
|
25796
25935
|
});
|
|
25797
25936
|
}
|
|
25798
25937
|
async evalFileContains(check2, done) {
|
|
25799
|
-
const
|
|
25800
|
-
const
|
|
25801
|
-
if (!
|
|
25938
|
+
const sha2562 = this.options.sha256 ?? defaultSha256;
|
|
25939
|
+
const fs49 = this.services.fs;
|
|
25940
|
+
if (!fs49)
|
|
25802
25941
|
return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
|
|
25803
25942
|
let content;
|
|
25804
25943
|
try {
|
|
25805
|
-
content = await
|
|
25944
|
+
content = await fs49.readFile(check2.path);
|
|
25806
25945
|
} catch {
|
|
25807
25946
|
await this.emitEvidence({ observation: "file-contains", path: check2.path, readable: false });
|
|
25808
25947
|
return done({ status: "fail", evidence: [], detail: `file not readable: ${check2.path}` });
|
|
25809
25948
|
}
|
|
25810
|
-
const evidence = [await this.fsEvidence("file-contains", check2.path,
|
|
25949
|
+
const evidence = [await this.fsEvidence("file-contains", check2.path, sha2562, content)];
|
|
25811
25950
|
let hit;
|
|
25812
25951
|
try {
|
|
25813
25952
|
hit = new RegExp(check2.pattern, "m").test(content);
|
|
@@ -26355,6 +26494,7 @@ __export(verification_exports, {
|
|
|
26355
26494
|
CommandCheckSchema: () => CommandCheckSchema,
|
|
26356
26495
|
CriterionSchema: () => CriterionSchema,
|
|
26357
26496
|
CriterionSourceSchema: () => CriterionSourceSchema,
|
|
26497
|
+
DEFAULT_COMMAND_CONCURRENCY: () => DEFAULT_COMMAND_CONCURRENCY,
|
|
26358
26498
|
DEFAULT_VERIFIER_CONFIG: () => DEFAULT_VERIFIER_CONFIG,
|
|
26359
26499
|
DETERMINISTIC_EVIDENCE_TIERS: () => DETERMINISTIC_EVIDENCE_TIERS,
|
|
26360
26500
|
DeterministicCheckSchema: () => DeterministicCheckSchema,
|
|
@@ -26383,9 +26523,11 @@ __export(verification_exports, {
|
|
|
26383
26523
|
evaluateResourceReserveGate: () => evaluateResourceReserveGate,
|
|
26384
26524
|
isEventBackedEvidence: () => isEventBackedEvidence,
|
|
26385
26525
|
isGeneratedPath: () => isGeneratedPath,
|
|
26526
|
+
isVerifyParallelEnabled: () => isVerifyParallelEnabled,
|
|
26386
26527
|
lastVerificationRun: () => lastVerificationRun,
|
|
26387
26528
|
parseNameOnlyDiff: () => parseNameOnlyDiff,
|
|
26388
26529
|
parseVerificationRunPayload: () => parseVerificationRunPayload,
|
|
26530
|
+
resolveCommandConcurrency: () => resolveCommandConcurrency,
|
|
26389
26531
|
snapshotToCompletionEvaluation: () => snapshotToCompletionEvaluation,
|
|
26390
26532
|
strictBuildGate: () => strictBuildGate,
|
|
26391
26533
|
verificationCostRatio: () => verificationCostRatio,
|
|
@@ -26402,6 +26544,7 @@ var init_verification = __esm({
|
|
|
26402
26544
|
init_metrics();
|
|
26403
26545
|
init_verifier();
|
|
26404
26546
|
init_scopeDiscipline();
|
|
26547
|
+
init_commandConcurrency();
|
|
26405
26548
|
init_resourceReserveGate();
|
|
26406
26549
|
}
|
|
26407
26550
|
});
|
|
@@ -26749,6 +26892,102 @@ var init_verificationAdapters = __esm({
|
|
|
26749
26892
|
}
|
|
26750
26893
|
});
|
|
26751
26894
|
|
|
26895
|
+
// src/cli/kraken/cachedShell.ts
|
|
26896
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
26897
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
26898
|
+
import { promisify } from "node:util";
|
|
26899
|
+
function verifyCacheEnabled(env = process.env) {
|
|
26900
|
+
const v = env.ZELARI_VERIFY_CACHE?.toLowerCase();
|
|
26901
|
+
if (v === "0" || v === "off" || v === "false") return false;
|
|
26902
|
+
return true;
|
|
26903
|
+
}
|
|
26904
|
+
function sha256(input) {
|
|
26905
|
+
return createHash9("sha256").update(input).digest("hex");
|
|
26906
|
+
}
|
|
26907
|
+
async function readTreeState(root) {
|
|
26908
|
+
try {
|
|
26909
|
+
const opts = { maxBuffer: GIT_MAX_BUFFER, timeout: GIT_TIMEOUT_MS, windowsHide: true };
|
|
26910
|
+
const [head, status] = await Promise.all([
|
|
26911
|
+
execFileAsync("git", ["-C", root, "rev-parse", "HEAD"], opts),
|
|
26912
|
+
execFileAsync("git", ["-C", root, "status", "--porcelain", "--untracked-files=all"], opts)
|
|
26913
|
+
]);
|
|
26914
|
+
return `HEAD:${String(head.stdout).trim()}|${sha256(String(status.stdout))}`;
|
|
26915
|
+
} catch {
|
|
26916
|
+
return null;
|
|
26917
|
+
}
|
|
26918
|
+
}
|
|
26919
|
+
function wrapWithVerifyCache(shell, options = {}) {
|
|
26920
|
+
const env = options.env ?? process.env;
|
|
26921
|
+
if (!verifyCacheEnabled(env)) return shell;
|
|
26922
|
+
return new CachedShellProvider(shell, options);
|
|
26923
|
+
}
|
|
26924
|
+
var execFileAsync, MAX_ENTRIES, TREE_TTL_MS, GIT_MAX_BUFFER, GIT_TIMEOUT_MS, cache, CachedShellProvider;
|
|
26925
|
+
var init_cachedShell = __esm({
|
|
26926
|
+
"src/cli/kraken/cachedShell.ts"() {
|
|
26927
|
+
"use strict";
|
|
26928
|
+
execFileAsync = promisify(execFile2);
|
|
26929
|
+
MAX_ENTRIES = 32;
|
|
26930
|
+
TREE_TTL_MS = 5e3;
|
|
26931
|
+
GIT_MAX_BUFFER = 8 * 1024 * 1024;
|
|
26932
|
+
GIT_TIMEOUT_MS = 1e4;
|
|
26933
|
+
cache = /* @__PURE__ */ new Map();
|
|
26934
|
+
CachedShellProvider = class {
|
|
26935
|
+
constructor(inner, options = {}) {
|
|
26936
|
+
this.inner = inner;
|
|
26937
|
+
this.root = options.root ?? process.cwd();
|
|
26938
|
+
}
|
|
26939
|
+
root;
|
|
26940
|
+
/**
|
|
26941
|
+
* Tree token memo, PER INSTANCE (5 s TTL). Deliberately not module-level: a
|
|
26942
|
+
* stale token would keep matching the pre-write key for up to the TTL and
|
|
26943
|
+
* serve the PRE-repair result after the repair wrote files — a false PASS
|
|
26944
|
+
* window on the gate. Every evaluation builds its own decorator, so a write
|
|
26945
|
+
* made between evaluations is always observed; the memo only avoids
|
|
26946
|
+
* re-running git for the sibling criteria of the SAME evaluation.
|
|
26947
|
+
*/
|
|
26948
|
+
treeMemo;
|
|
26949
|
+
async treeState() {
|
|
26950
|
+
const now = Date.now();
|
|
26951
|
+
if (this.treeMemo && now - this.treeMemo.at < TREE_TTL_MS) return this.treeMemo.value;
|
|
26952
|
+
const value = await readTreeState(this.root);
|
|
26953
|
+
this.treeMemo = { at: now, value };
|
|
26954
|
+
return value;
|
|
26955
|
+
}
|
|
26956
|
+
async exec(command, options = {}) {
|
|
26957
|
+
const tree = await this.treeState();
|
|
26958
|
+
if (tree === null) return await this.inner.exec(command, options);
|
|
26959
|
+
const key = sha256(
|
|
26960
|
+
JSON.stringify({
|
|
26961
|
+
command,
|
|
26962
|
+
cwd: options.cwd ?? "",
|
|
26963
|
+
timeoutMs: options.timeoutMs ?? null,
|
|
26964
|
+
tree,
|
|
26965
|
+
// Additive safety field: two evaluation roots in ONE process must
|
|
26966
|
+
// never collide on the same relative cwd.
|
|
26967
|
+
root: this.root
|
|
26968
|
+
})
|
|
26969
|
+
);
|
|
26970
|
+
const started = Date.now();
|
|
26971
|
+
const hit = cache.get(key);
|
|
26972
|
+
if (hit !== void 0) {
|
|
26973
|
+
cache.delete(key);
|
|
26974
|
+
cache.set(key, hit);
|
|
26975
|
+
return { ...hit, cached: true, durationMs: Date.now() - started };
|
|
26976
|
+
}
|
|
26977
|
+
const result = await this.inner.exec(command, options);
|
|
26978
|
+
if (!result.timedOut && result.exitCode !== null) {
|
|
26979
|
+
cache.set(key, { ...result });
|
|
26980
|
+
if (cache.size > MAX_ENTRIES) {
|
|
26981
|
+
const oldest = cache.keys().next().value;
|
|
26982
|
+
if (oldest !== void 0) cache.delete(oldest);
|
|
26983
|
+
}
|
|
26984
|
+
}
|
|
26985
|
+
return result;
|
|
26986
|
+
}
|
|
26987
|
+
};
|
|
26988
|
+
}
|
|
26989
|
+
});
|
|
26990
|
+
|
|
26752
26991
|
// src/cli/kraken/nativeVerification.ts
|
|
26753
26992
|
var nativeVerification_exports = {};
|
|
26754
26993
|
__export(nativeVerification_exports, {
|
|
@@ -26829,7 +27068,7 @@ async function evaluateNativePack(deps = {}) {
|
|
|
26829
27068
|
if (!commands.typecheckCommand && !commands.testCommand && !commands.buildCommand) return null;
|
|
26830
27069
|
const criteria = buildNativeCriteria(commands, packTimeoutMs(env));
|
|
26831
27070
|
if (criteria.length === 0) return null;
|
|
26832
|
-
const shell = deps.shell ?? new NodeShellProvider(new LocalWorkspace(cwd));
|
|
27071
|
+
const shell = deps.shell ?? wrapWithVerifyCache(new NodeShellProvider(new LocalWorkspace(cwd)), { root: cwd, env });
|
|
26833
27072
|
const engine = deps.emit ? new VerificationEngine({ shell }, { emit: deps.emit }) : new VerificationEngine({ shell });
|
|
26834
27073
|
const results = await engine.evaluate(criteria, { packId: ZELARI_CODING_PACK_ID });
|
|
26835
27074
|
return { packId: ZELARI_CODING_PACK_ID, criteria, results };
|
|
@@ -26841,6 +27080,7 @@ var init_nativeVerification = __esm({
|
|
|
26841
27080
|
init_runtime();
|
|
26842
27081
|
init_verification();
|
|
26843
27082
|
init_verificationAdapters();
|
|
27083
|
+
init_cachedShell();
|
|
26844
27084
|
EMPTY_PLAN = {
|
|
26845
27085
|
typecheckCommand: null,
|
|
26846
27086
|
testCommand: null,
|
|
@@ -27207,7 +27447,7 @@ async function evaluateContractCriteria(contract, deps = {}) {
|
|
|
27207
27447
|
const cwd = deps.cwd ?? process.cwd();
|
|
27208
27448
|
const criteria = compileVerificationCriteria(contract, { timeoutMs: deps.timeoutMs });
|
|
27209
27449
|
if (criteria.length === 0) return null;
|
|
27210
|
-
const shell = deps.shell ?? new NodeShellProvider(new LocalWorkspace(cwd));
|
|
27450
|
+
const shell = deps.shell ?? wrapWithVerifyCache(new NodeShellProvider(new LocalWorkspace(cwd)), { root: cwd });
|
|
27211
27451
|
const engine = deps.emit ? new VerificationEngine({ shell }, { emit: deps.emit }) : new VerificationEngine({ shell });
|
|
27212
27452
|
const results = await engine.evaluate(criteria, { packId: CONTRACT_CRITERIA_PACK_ID });
|
|
27213
27453
|
return { criteria, results };
|
|
@@ -27219,6 +27459,7 @@ var init_contractCompiler = __esm({
|
|
|
27219
27459
|
init_runtime();
|
|
27220
27460
|
init_verification();
|
|
27221
27461
|
init_policyEngine();
|
|
27462
|
+
init_cachedShell();
|
|
27222
27463
|
CONTRACT_CRITERIA_PACK_ID = "task-contract/v1";
|
|
27223
27464
|
CONTRACT_COMMAND_TIMEOUT_MS = 6e5;
|
|
27224
27465
|
MAX_COMMAND_LENGTH = 512;
|
|
@@ -27242,7 +27483,7 @@ __export(verificationBridge_exports, {
|
|
|
27242
27483
|
strictGateEventPayload: () => strictGateEventPayload,
|
|
27243
27484
|
strictGateExitCode: () => strictGateExitCode
|
|
27244
27485
|
});
|
|
27245
|
-
import { createHash as
|
|
27486
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
27246
27487
|
function strictDoneEnabled(surface = "kraken", env = process.env) {
|
|
27247
27488
|
if (surface === "mission") {
|
|
27248
27489
|
const v2 = env.ZELARI_MISSION_STRICT;
|
|
@@ -27318,7 +27559,7 @@ function krakenResultsToContract(requiredChecks, results, now = Date.now()) {
|
|
|
27318
27559
|
return { criteria, results: verifications };
|
|
27319
27560
|
}
|
|
27320
27561
|
function sha256Hex2(input) {
|
|
27321
|
-
return
|
|
27562
|
+
return createHash10("sha256").update(input).digest("hex");
|
|
27322
27563
|
}
|
|
27323
27564
|
function matchNoteToToolTrace(note, trace) {
|
|
27324
27565
|
const n = normalize3(note);
|
|
@@ -28993,6 +29234,9 @@ var init_AgentHarness = __esm({
|
|
|
28993
29234
|
maxToolLoopIterations;
|
|
28994
29235
|
maxToolLoopHardCap;
|
|
28995
29236
|
cancelled = false;
|
|
29237
|
+
/** Host-supplied cancel cause (`turn_timeout` vs user Stop). */
|
|
29238
|
+
cancelReason;
|
|
29239
|
+
cancelEventEmitted = false;
|
|
28996
29240
|
activeController = null;
|
|
28997
29241
|
queue = [];
|
|
28998
29242
|
/**
|
|
@@ -29347,13 +29591,28 @@ ${shared.content}`,
|
|
|
29347
29591
|
* After cancel() returns, the harness should be discarded by the
|
|
29348
29592
|
* caller (the run() generator finishes after the current turn ends).
|
|
29349
29593
|
* For mid-stream interrupt + new-prompt injection, see Task C.3.2.
|
|
29594
|
+
*
|
|
29595
|
+
* `reason` is optional host context: `turn_timeout` is the Desktop sidecar
|
|
29596
|
+
* idle watchdog (not a user Stop). The error event message must not claim
|
|
29597
|
+
* the user cancelled when they did not.
|
|
29350
29598
|
*/
|
|
29351
|
-
cancel() {
|
|
29599
|
+
cancel(reason) {
|
|
29352
29600
|
if (this.cancelled)
|
|
29353
29601
|
return;
|
|
29354
29602
|
this.cancelled = true;
|
|
29603
|
+
if (reason)
|
|
29604
|
+
this.cancelReason = reason;
|
|
29355
29605
|
this.activeController?.abort();
|
|
29356
29606
|
}
|
|
29607
|
+
buildCancelEvent() {
|
|
29608
|
+
this.cancelEventEmitted = true;
|
|
29609
|
+
const watchdog = this.cancelReason === "turn_timeout";
|
|
29610
|
+
return createBrainEvent("error", this.sessionId, {
|
|
29611
|
+
severity: "cancelled",
|
|
29612
|
+
message: watchdog ? "Turn cancelled: Desktop idle watchdog saw no events (silent model thinking or a tentacle with no tools). This was not a user Stop." : "Run cancelled by user.",
|
|
29613
|
+
code: watchdog ? "turn_timeout" : "cancelled"
|
|
29614
|
+
});
|
|
29615
|
+
}
|
|
29357
29616
|
/** Current size of the queued user-prompt buffer. */
|
|
29358
29617
|
get queueLength() {
|
|
29359
29618
|
return this.queue.length;
|
|
@@ -29398,6 +29657,7 @@ ${shared.content}`,
|
|
|
29398
29657
|
async *run() {
|
|
29399
29658
|
const startTime = Date.now();
|
|
29400
29659
|
this.activeController = new AbortController();
|
|
29660
|
+
this.cancelEventEmitted = false;
|
|
29401
29661
|
this.toolCallCache = /* @__PURE__ */ new Map();
|
|
29402
29662
|
this.toolCallCounts = /* @__PURE__ */ new Map();
|
|
29403
29663
|
this.textToolReentries = 0;
|
|
@@ -29643,6 +29903,11 @@ ${shared.content}`,
|
|
|
29643
29903
|
} catch {
|
|
29644
29904
|
}
|
|
29645
29905
|
}
|
|
29906
|
+
if (this.cancelled && !this.cancelEventEmitted) {
|
|
29907
|
+
const cancelEvent = this.buildCancelEvent();
|
|
29908
|
+
this.emit(cancelEvent);
|
|
29909
|
+
yield cancelEvent;
|
|
29910
|
+
}
|
|
29646
29911
|
const agentEnd = createBrainEvent("agent_end", this.sessionId, {
|
|
29647
29912
|
reason: hadError ? "error" : this.cancelled ? "cancelled" : "completed",
|
|
29648
29913
|
durationMs: Date.now() - startTime,
|
|
@@ -29705,6 +29970,8 @@ ${shared.content}`,
|
|
|
29705
29970
|
emitSnapshot(tools, generation, messages = this.messagesForProvider()) {
|
|
29706
29971
|
if (!this.config.onRequestSnapshot)
|
|
29707
29972
|
return;
|
|
29973
|
+
if (resolveRequestSnapshotMode() === "off")
|
|
29974
|
+
return;
|
|
29708
29975
|
try {
|
|
29709
29976
|
this.config.onRequestSnapshot(createRoutedRequestSnapshot({
|
|
29710
29977
|
messages,
|
|
@@ -29754,11 +30021,7 @@ ${shared.content}`,
|
|
|
29754
30021
|
let lastLoopCheckLen = 0;
|
|
29755
30022
|
for await (const delta of stream) {
|
|
29756
30023
|
if (this.cancelled) {
|
|
29757
|
-
const cancelEvent =
|
|
29758
|
-
severity: "cancelled",
|
|
29759
|
-
message: "Run cancelled by user.",
|
|
29760
|
-
code: "cancelled"
|
|
29761
|
-
});
|
|
30024
|
+
const cancelEvent = this.buildCancelEvent();
|
|
29762
30025
|
this.emit(cancelEvent);
|
|
29763
30026
|
yield cancelEvent;
|
|
29764
30027
|
break;
|
|
@@ -31002,6 +31265,7 @@ __export(harness_exports, {
|
|
|
31002
31265
|
TEXT_TOOLS_PARTIAL_USER: () => TEXT_TOOLS_PARTIAL_USER,
|
|
31003
31266
|
TOOL_CALL_TRUNCATED_RECOVERY_MARKER: () => TOOL_CALL_TRUNCATED_RECOVERY_MARKER,
|
|
31004
31267
|
TOOL_CALL_TRUNCATED_RECOVERY_USER: () => TOOL_CALL_TRUNCATED_RECOVERY_USER,
|
|
31268
|
+
__resetRequestSnapshotMemoForTests: () => __resetRequestSnapshotMemoForTests,
|
|
31005
31269
|
canonicalTools: () => canonicalTools,
|
|
31006
31270
|
collapseLoopedAssistantText: () => collapseLoopedAssistantText,
|
|
31007
31271
|
compareReplayPrefix: () => compareReplayPrefix,
|
|
@@ -31024,6 +31288,7 @@ __export(harness_exports, {
|
|
|
31024
31288
|
recordRequest: () => recordRequest,
|
|
31025
31289
|
recordToolResult: () => recordToolResult,
|
|
31026
31290
|
recordUsage: () => recordUsage,
|
|
31291
|
+
resolveRequestSnapshotMode: () => resolveRequestSnapshotMode,
|
|
31027
31292
|
runExtensionPreToolUse: () => runExtensionPreToolUse,
|
|
31028
31293
|
sha256Hex: () => sha256Hex,
|
|
31029
31294
|
splitHookCommandLine: () => splitHookCommandLine,
|
|
@@ -37360,6 +37625,146 @@ var init_agentAdapter = __esm({
|
|
|
37360
37625
|
}
|
|
37361
37626
|
});
|
|
37362
37627
|
|
|
37628
|
+
// packages/core/dist/session/replayCache.js
|
|
37629
|
+
import { promises as fs14 } from "node:fs";
|
|
37630
|
+
function isReplayCacheEnabled(env = process.env) {
|
|
37631
|
+
const v = (env.ZELARI_SPINE_REPLAY_CACHE ?? "").trim().toLowerCase();
|
|
37632
|
+
return v === "1" || v === "true" || v === "yes" || v === "on";
|
|
37633
|
+
}
|
|
37634
|
+
function utf8IncompleteTailBytes(buf) {
|
|
37635
|
+
const max = Math.min(4, buf.length);
|
|
37636
|
+
for (let back = 1; back <= max; back++) {
|
|
37637
|
+
const b = buf[buf.length - back];
|
|
37638
|
+
if (b < 128)
|
|
37639
|
+
return 0;
|
|
37640
|
+
if (b >= 192) {
|
|
37641
|
+
const need = b >= 240 ? 4 : b >= 224 ? 3 : 2;
|
|
37642
|
+
return back >= need ? 0 : need - back;
|
|
37643
|
+
}
|
|
37644
|
+
}
|
|
37645
|
+
return 0;
|
|
37646
|
+
}
|
|
37647
|
+
async function readAt(fh, position, length) {
|
|
37648
|
+
const buf = Buffer.allocUnsafe(length);
|
|
37649
|
+
let done = 0;
|
|
37650
|
+
while (done < length) {
|
|
37651
|
+
const { bytesRead } = await fh.read(buf, done, length - done, position + done);
|
|
37652
|
+
if (bytesRead === 0)
|
|
37653
|
+
break;
|
|
37654
|
+
done += bytesRead;
|
|
37655
|
+
}
|
|
37656
|
+
return done === length ? buf : buf.subarray(0, done);
|
|
37657
|
+
}
|
|
37658
|
+
function toReport(filePath, entry) {
|
|
37659
|
+
const events = entry.events.slice();
|
|
37660
|
+
const issues = entry.issues.slice();
|
|
37661
|
+
return { path: filePath, events, issues, ok: issues.length === 0 };
|
|
37662
|
+
}
|
|
37663
|
+
async function readSessionLogCached(filePath, cache4, env = process.env) {
|
|
37664
|
+
if (!cache4 || !isReplayCacheEnabled(env))
|
|
37665
|
+
return readSessionLog(filePath);
|
|
37666
|
+
return cache4.read(filePath);
|
|
37667
|
+
}
|
|
37668
|
+
var NL, SessionLogCache;
|
|
37669
|
+
var init_replayCache = __esm({
|
|
37670
|
+
"packages/core/dist/session/replayCache.js"() {
|
|
37671
|
+
"use strict";
|
|
37672
|
+
init_replay();
|
|
37673
|
+
NL = 10;
|
|
37674
|
+
SessionLogCache = class {
|
|
37675
|
+
entries = /* @__PURE__ */ new Map();
|
|
37676
|
+
/** Files currently cached (diagnostics). */
|
|
37677
|
+
get size() {
|
|
37678
|
+
return this.entries.size;
|
|
37679
|
+
}
|
|
37680
|
+
/** The cached entry for `filePath` (copy; tests + diagnostics), if any. */
|
|
37681
|
+
peek(filePath) {
|
|
37682
|
+
const entry = this.entries.get(filePath);
|
|
37683
|
+
return entry ? { ...entry } : void 0;
|
|
37684
|
+
}
|
|
37685
|
+
/** Read the log, incrementally when a usable entry exists. */
|
|
37686
|
+
async read(filePath) {
|
|
37687
|
+
const cached2 = this.entries.get(filePath);
|
|
37688
|
+
let stat8;
|
|
37689
|
+
try {
|
|
37690
|
+
stat8 = await fs14.stat(filePath);
|
|
37691
|
+
} catch (err) {
|
|
37692
|
+
if (err.code === "ENOENT") {
|
|
37693
|
+
this.entries.delete(filePath);
|
|
37694
|
+
return { path: filePath, events: [], issues: [], ok: true };
|
|
37695
|
+
}
|
|
37696
|
+
throw err;
|
|
37697
|
+
}
|
|
37698
|
+
if (cached2 && stat8.size >= cached2.byteSize && stat8.mtimeMs >= cached2.mtimeMs) {
|
|
37699
|
+
if (stat8.size > cached2.byteSize)
|
|
37700
|
+
return this.extend(filePath, cached2, stat8);
|
|
37701
|
+
return toReport(filePath, cached2);
|
|
37702
|
+
}
|
|
37703
|
+
return this.full(filePath, stat8);
|
|
37704
|
+
}
|
|
37705
|
+
/** Append-path read: only the bytes written since the last read are parsed. */
|
|
37706
|
+
async extend(filePath, cached2, stat8) {
|
|
37707
|
+
const fh = await fs14.open(filePath, "r");
|
|
37708
|
+
let chunk;
|
|
37709
|
+
try {
|
|
37710
|
+
chunk = await readAt(fh, cached2.byteSize, stat8.size - cached2.byteSize);
|
|
37711
|
+
} finally {
|
|
37712
|
+
await fh.close();
|
|
37713
|
+
}
|
|
37714
|
+
const nl = chunk.lastIndexOf(NL);
|
|
37715
|
+
const headEnd = nl === -1 ? 0 : nl + 1;
|
|
37716
|
+
const tail2 = chunk.subarray(headEnd);
|
|
37717
|
+
const keep = tail2.subarray(0, tail2.length - utf8IncompleteTailBytes(tail2));
|
|
37718
|
+
const head = cached2.partial + chunk.subarray(0, headEnd).toString("utf8");
|
|
37719
|
+
const lines = headEnd > 0 ? head.split("\n").slice(0, -1) : [];
|
|
37720
|
+
const parsed = parseSessionLogLines(lines, {
|
|
37721
|
+
expected: cached2.expectedSeq,
|
|
37722
|
+
linesConsumed: cached2.linesConsumed
|
|
37723
|
+
});
|
|
37724
|
+
const entry = {
|
|
37725
|
+
byteSize: cached2.byteSize + headEnd + keep.length,
|
|
37726
|
+
mtimeMs: stat8.mtimeMs,
|
|
37727
|
+
events: parsed.events.length > 0 ? cached2.events.concat(parsed.events) : cached2.events,
|
|
37728
|
+
issues: parsed.issues.length > 0 ? cached2.issues.concat(parsed.issues) : cached2.issues,
|
|
37729
|
+
expectedSeq: parsed.expected,
|
|
37730
|
+
partial: (headEnd > 0 ? "" : cached2.partial) + keep.toString("utf8"),
|
|
37731
|
+
linesConsumed: parsed.linesConsumed
|
|
37732
|
+
};
|
|
37733
|
+
this.entries.set(filePath, entry);
|
|
37734
|
+
return toReport(filePath, entry);
|
|
37735
|
+
}
|
|
37736
|
+
/** Cold / rotated read: same parse as `readSessionLog`, then seed the entry. */
|
|
37737
|
+
async full(filePath, stat8) {
|
|
37738
|
+
let content;
|
|
37739
|
+
try {
|
|
37740
|
+
content = await fs14.readFile(filePath, "utf-8");
|
|
37741
|
+
} catch (err) {
|
|
37742
|
+
if (err.code === "ENOENT") {
|
|
37743
|
+
this.entries.delete(filePath);
|
|
37744
|
+
return { path: filePath, events: [], issues: [], ok: true };
|
|
37745
|
+
}
|
|
37746
|
+
throw err;
|
|
37747
|
+
}
|
|
37748
|
+
const lines = content.split("\n");
|
|
37749
|
+
const parsed = parseSessionLogLines(lines);
|
|
37750
|
+
const linesConsumed = content.length === 0 ? 0 : content.endsWith("\n") ? lines.length - 1 : lines.length;
|
|
37751
|
+
const entry = {
|
|
37752
|
+
// Bytes actually read (never the pre-read stat: the log may have grown).
|
|
37753
|
+
byteSize: Buffer.byteLength(content, "utf8"),
|
|
37754
|
+
mtimeMs: stat8.mtimeMs,
|
|
37755
|
+
events: parsed.events,
|
|
37756
|
+
issues: parsed.issues,
|
|
37757
|
+
expectedSeq: parsed.expected,
|
|
37758
|
+
partial: "",
|
|
37759
|
+
linesConsumed
|
|
37760
|
+
};
|
|
37761
|
+
this.entries.set(filePath, entry);
|
|
37762
|
+
return { path: filePath, events: entry.events.slice(), issues: entry.issues.slice(), ok: entry.issues.length === 0 };
|
|
37763
|
+
}
|
|
37764
|
+
};
|
|
37765
|
+
}
|
|
37766
|
+
});
|
|
37767
|
+
|
|
37363
37768
|
// packages/core/dist/session/lineage.js
|
|
37364
37769
|
async function forkSession(store6, parentSessionId, options = {}) {
|
|
37365
37770
|
const parent = await store6.read(parentSessionId);
|
|
@@ -37923,6 +38328,7 @@ var init_session = __esm({
|
|
|
37923
38328
|
init_agentAdapter();
|
|
37924
38329
|
init_writer();
|
|
37925
38330
|
init_replay();
|
|
38331
|
+
init_replayCache();
|
|
37926
38332
|
init_store();
|
|
37927
38333
|
init_lineage();
|
|
37928
38334
|
init_exportSession();
|
|
@@ -38416,12 +38822,12 @@ var CORE_VERSION;
|
|
|
38416
38822
|
var init_version = __esm({
|
|
38417
38823
|
"packages/core/dist/version.js"() {
|
|
38418
38824
|
"use strict";
|
|
38419
|
-
CORE_VERSION = "2.
|
|
38825
|
+
CORE_VERSION = "2.38.0";
|
|
38420
38826
|
}
|
|
38421
38827
|
});
|
|
38422
38828
|
|
|
38423
38829
|
// packages/core/dist/runtime/fingerprints.js
|
|
38424
|
-
import { createHash as
|
|
38830
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
38425
38831
|
function toolFingerprintHash(tools) {
|
|
38426
38832
|
const canonical = [...tools].map((t) => ({
|
|
38427
38833
|
name: t.name,
|
|
@@ -38430,7 +38836,7 @@ function toolFingerprintHash(tools) {
|
|
|
38430
38836
|
...t.outputContractVersion !== void 0 ? { outputContractVersion: t.outputContractVersion } : {},
|
|
38431
38837
|
...t.capabilityFlags !== void 0 ? { capabilityFlags: [...t.capabilityFlags].sort() } : {}
|
|
38432
38838
|
})).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
38433
|
-
return
|
|
38839
|
+
return createHash11("sha256").update(stableStringify(canonical)).digest("hex");
|
|
38434
38840
|
}
|
|
38435
38841
|
function skillFingerprintHash(skills) {
|
|
38436
38842
|
const canonical = [...skills].map((s) => ({
|
|
@@ -38438,7 +38844,7 @@ function skillFingerprintHash(skills) {
|
|
|
38438
38844
|
...s.version !== void 0 ? { version: s.version } : {},
|
|
38439
38845
|
...s.contentDigest !== void 0 ? { contentDigest: s.contentDigest } : {}
|
|
38440
38846
|
})).sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
38441
|
-
return
|
|
38847
|
+
return createHash11("sha256").update(stableStringify(canonical)).digest("hex");
|
|
38442
38848
|
}
|
|
38443
38849
|
var init_fingerprints = __esm({
|
|
38444
38850
|
"packages/core/dist/runtime/fingerprints.js"() {
|
|
@@ -38476,6 +38882,7 @@ __export(dist_exports, {
|
|
|
38476
38882
|
CommandCheckSchema: () => CommandCheckSchema,
|
|
38477
38883
|
CriterionSchema: () => CriterionSchema,
|
|
38478
38884
|
CriterionSourceSchema: () => CriterionSourceSchema,
|
|
38885
|
+
DEFAULT_COMMAND_CONCURRENCY: () => DEFAULT_COMMAND_CONCURRENCY,
|
|
38479
38886
|
DEFAULT_CONTEXT_POLICY: () => DEFAULT_CONTEXT_POLICY,
|
|
38480
38887
|
DEFAULT_HEARTBEAT_STALE_MS: () => DEFAULT_HEARTBEAT_STALE_MS,
|
|
38481
38888
|
DEFAULT_MAX_NODES: () => DEFAULT_MAX_NODES,
|
|
@@ -38602,6 +39009,7 @@ __export(dist_exports, {
|
|
|
38602
39009
|
SessionActorSchema: () => SessionActorSchema,
|
|
38603
39010
|
SessionEventEnvelopeSchema: () => SessionEventEnvelopeSchema,
|
|
38604
39011
|
SessionJsonlWriter: () => SessionJsonlWriter,
|
|
39012
|
+
SessionLogCache: () => SessionLogCache,
|
|
38605
39013
|
SessionLogLockedError: () => SessionLogLockedError,
|
|
38606
39014
|
SessionLogWriter: () => SessionLogWriter,
|
|
38607
39015
|
SessionStore: () => SessionStore,
|
|
@@ -38640,6 +39048,7 @@ __export(dist_exports, {
|
|
|
38640
39048
|
WorkspacePathEscapeError: () => WorkspacePathEscapeError,
|
|
38641
39049
|
WorktreeWorkspace: () => WorktreeWorkspace,
|
|
38642
39050
|
ZELARI_CODING_PACK_ID: () => ZELARI_CODING_PACK_ID,
|
|
39051
|
+
__resetRequestSnapshotMemoForTests: () => __resetRequestSnapshotMemoForTests,
|
|
38643
39052
|
analyzeScope: () => analyzeScope,
|
|
38644
39053
|
applyCompletionRetry: () => applyCompletionRetry,
|
|
38645
39054
|
applyDeterministicAutofix: () => applyDeterministicAutofix,
|
|
@@ -38801,6 +39210,7 @@ __export(dist_exports, {
|
|
|
38801
39210
|
isFollowUpControlEvent: () => isFollowUpControlEvent,
|
|
38802
39211
|
isGeneratedPath: () => isGeneratedPath,
|
|
38803
39212
|
isModelSurfaceEvent: () => isModelSurfaceEvent,
|
|
39213
|
+
isReplayCacheEnabled: () => isReplayCacheEnabled,
|
|
38804
39214
|
isReviewerKind: () => isReviewerKind,
|
|
38805
39215
|
isSearchTool: () => isSearchTool,
|
|
38806
39216
|
isSeqShadowed: () => isSeqShadowed,
|
|
@@ -38809,6 +39219,7 @@ __export(dist_exports, {
|
|
|
38809
39219
|
isSteerControlEvent: () => isSteerControlEvent,
|
|
38810
39220
|
isValidTool: () => isValidTool,
|
|
38811
39221
|
isVerificationReserveProtected: () => isVerificationReserveProtected,
|
|
39222
|
+
isVerifyParallelEnabled: () => isVerifyParallelEnabled,
|
|
38812
39223
|
isVerifyToolCheckSkipped: () => isVerifyToolCheckSkipped,
|
|
38813
39224
|
jaccardSimilarity: () => jaccardSimilarity,
|
|
38814
39225
|
jsonBytes: () => jsonBytes,
|
|
@@ -38847,6 +39258,8 @@ __export(dist_exports, {
|
|
|
38847
39258
|
parseNameOnlyDiff: () => parseNameOnlyDiff,
|
|
38848
39259
|
parsePersonaVerdict: () => parsePersonaVerdict,
|
|
38849
39260
|
parseProjectRootFromWorkspaceContext: () => parseProjectRootFromWorkspaceContext,
|
|
39261
|
+
parseSessionLogLines: () => parseSessionLogLines,
|
|
39262
|
+
parseSessionLogText: () => parseSessionLogText,
|
|
38850
39263
|
parseTextToolCalls: () => parseTextToolCalls,
|
|
38851
39264
|
parseTextToolCallsDetailed: () => parseTextToolCallsDetailed,
|
|
38852
39265
|
parseThinking: () => parseThinking,
|
|
@@ -38864,6 +39277,7 @@ __export(dist_exports, {
|
|
|
38864
39277
|
readLessonsDeduped: () => readLessonsDeduped,
|
|
38865
39278
|
readSession: () => readSession,
|
|
38866
39279
|
readSessionLog: () => readSessionLog,
|
|
39280
|
+
readSessionLogCached: () => readSessionLogCached,
|
|
38867
39281
|
recallLessons: () => recallLessons,
|
|
38868
39282
|
recencyScore: () => recencyScore,
|
|
38869
39283
|
recordRequest: () => recordRequest,
|
|
@@ -38880,6 +39294,7 @@ __export(dist_exports, {
|
|
|
38880
39294
|
renderSteers: () => renderSteers,
|
|
38881
39295
|
replayChairmanTextTools: () => replayChairmanTextTools,
|
|
38882
39296
|
resolveAgentSkills: () => resolveAgentSkills,
|
|
39297
|
+
resolveCommandConcurrency: () => resolveCommandConcurrency,
|
|
38883
39298
|
resolveCouncilRunMode: () => resolveCouncilRunMode,
|
|
38884
39299
|
resolveHeartbeatStaleMs: () => resolveHeartbeatStaleMs,
|
|
38885
39300
|
resolveInterventions: () => resolveInterventions,
|
|
@@ -38887,6 +39302,7 @@ __export(dist_exports, {
|
|
|
38887
39302
|
resolveMaxTentacles: () => resolveMaxTentacles,
|
|
38888
39303
|
resolvePlanTimeoutMs: () => resolvePlanTimeoutMs,
|
|
38889
39304
|
resolveProfile: () => resolveProfile,
|
|
39305
|
+
resolveRequestSnapshotMode: () => resolveRequestSnapshotMode,
|
|
38890
39306
|
resolveResponseLanguage: () => resolveResponseLanguage,
|
|
38891
39307
|
resolveRoleSystemPrompt: () => resolveRoleSystemPrompt,
|
|
38892
39308
|
resolveSessionsDir: () => resolveSessionsDir,
|
|
@@ -39121,7 +39537,7 @@ var init_graphStatus = __esm({
|
|
|
39121
39537
|
});
|
|
39122
39538
|
|
|
39123
39539
|
// src/cli/sessionManager.ts
|
|
39124
|
-
import { promises as
|
|
39540
|
+
import { promises as fs15, existsSync as existsSync13, readFileSync as readFileSync15, writeFileSync as writeFileSync11, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, statSync } from "node:fs";
|
|
39125
39541
|
import path30 from "node:path";
|
|
39126
39542
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
39127
39543
|
function getSessionBaseDir() {
|
|
@@ -39131,7 +39547,7 @@ function getCurrentSessionFile() {
|
|
|
39131
39547
|
return currentSessionPath();
|
|
39132
39548
|
}
|
|
39133
39549
|
async function ensureSessionDir() {
|
|
39134
|
-
await
|
|
39550
|
+
await fs15.mkdir(getSessionBaseDir(), { recursive: true });
|
|
39135
39551
|
}
|
|
39136
39552
|
function getCurrentSessionId() {
|
|
39137
39553
|
const file2 = getCurrentSessionFile();
|
|
@@ -39181,7 +39597,7 @@ async function listSessions() {
|
|
|
39181
39597
|
const baseDir = getSessionBaseDir();
|
|
39182
39598
|
let entries;
|
|
39183
39599
|
try {
|
|
39184
|
-
entries = await
|
|
39600
|
+
entries = await fs15.readdir(baseDir);
|
|
39185
39601
|
} catch (err) {
|
|
39186
39602
|
if (err.code === "ENOENT") return [];
|
|
39187
39603
|
throw err;
|
|
@@ -39571,16 +39987,16 @@ var init_budgetRuntime = __esm({
|
|
|
39571
39987
|
|
|
39572
39988
|
// src/cli/budget/restoreRuntime.ts
|
|
39573
39989
|
import path31 from "node:path";
|
|
39574
|
-
async function restoreBudgetRuntimeFromSession(budget, sessionId2, baseDir) {
|
|
39990
|
+
async function restoreBudgetRuntimeFromSession(budget, sessionId2, baseDir, cache4) {
|
|
39575
39991
|
const eventsPath = path31.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
|
|
39576
|
-
const report = await
|
|
39992
|
+
const report = await readSessionLogCached(eventsPath, cache4).catch(() => null);
|
|
39577
39993
|
if (!report || report.events.length === 0) return false;
|
|
39578
39994
|
budget.adoptLedgerFromEvents(report.events);
|
|
39579
39995
|
return true;
|
|
39580
39996
|
}
|
|
39581
|
-
async function lastHarnessManifestHash(sessionId2, baseDir) {
|
|
39997
|
+
async function lastHarnessManifestHash(sessionId2, baseDir, cache4) {
|
|
39582
39998
|
const eventsPath = path31.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
|
|
39583
|
-
const report = await
|
|
39999
|
+
const report = await readSessionLogCached(eventsPath, cache4).catch(() => null);
|
|
39584
40000
|
if (!report) return null;
|
|
39585
40001
|
for (let i = report.events.length - 1; i >= 0; i--) {
|
|
39586
40002
|
const e = report.events[i];
|
|
@@ -40046,7 +40462,7 @@ async function wrapSessionWriter(inner, sessionId2, options = {}) {
|
|
|
40046
40462
|
enforcement: resolveResourceEnforcement()
|
|
40047
40463
|
});
|
|
40048
40464
|
if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
|
|
40049
|
-
await restoreBudgetRuntimeFromSession(budget, sessionId2, options.baseDir);
|
|
40465
|
+
await restoreBudgetRuntimeFromSession(budget, sessionId2, options.baseDir, spine.replayCache);
|
|
40050
40466
|
}
|
|
40051
40467
|
spine.attachBudgetRuntime(budget);
|
|
40052
40468
|
await noteHarnessLifecycle(
|
|
@@ -40077,7 +40493,7 @@ async function noteHarnessLifecycle(spine, sessionId2, profileId, budget, baseDi
|
|
|
40077
40493
|
resourcePolicy: budget.policy
|
|
40078
40494
|
});
|
|
40079
40495
|
if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
|
|
40080
|
-
if (await lastHarnessManifestHash(sessionId2, baseDir) === null) {
|
|
40496
|
+
if (await lastHarnessManifestHash(sessionId2, baseDir, spine.replayCache) === null) {
|
|
40081
40497
|
spine.harnessManifest(manifest, manifestHash);
|
|
40082
40498
|
}
|
|
40083
40499
|
} else {
|
|
@@ -40127,6 +40543,13 @@ var init_sessionSpine = __esm({
|
|
|
40127
40543
|
/** Seq the log continued from when adopting an existing session. */
|
|
40128
40544
|
resumedFromSeq;
|
|
40129
40545
|
sessionsDir;
|
|
40546
|
+
/**
|
|
40547
|
+
* PERF-4a: session log cache — ONE per session (this mirror). Every read of
|
|
40548
|
+
* `<sessionId>/events.jsonl` goes through it; the kill switch
|
|
40549
|
+
* ZELARI_SPINE_REPLAY_CACHE defaults OFF (see @zelari/core/session
|
|
40550
|
+
* replayCache.ts), and shared with the host helpers that take a cache.
|
|
40551
|
+
*/
|
|
40552
|
+
replayCache = new SessionLogCache();
|
|
40130
40553
|
/**
|
|
40131
40554
|
* Adopt a 1.x sessionId into the spine: continue the seq when the log
|
|
40132
40555
|
* already exists (resume), otherwise start fresh with `session.started`.
|
|
@@ -40137,7 +40560,10 @@ var init_sessionSpine = __esm({
|
|
|
40137
40560
|
if (!spineEnabled()) return mirror;
|
|
40138
40561
|
try {
|
|
40139
40562
|
const sessionDir = path33.join(mirror.sessionsDir, sessionId2);
|
|
40140
|
-
const report = await
|
|
40563
|
+
const report = await readSessionLogCached(
|
|
40564
|
+
path33.join(sessionDir, "events.jsonl"),
|
|
40565
|
+
mirror.replayCache
|
|
40566
|
+
);
|
|
40141
40567
|
const existed = report.events.length > 0 || report.issues.length > 0;
|
|
40142
40568
|
if (report.events.some((e) => e.kind === "task.contract" || e.kind === "user.message")) {
|
|
40143
40569
|
mirror.contractSeeded = true;
|
|
@@ -40312,8 +40738,9 @@ var init_sessionSpine = __esm({
|
|
|
40312
40738
|
*/
|
|
40313
40739
|
async derivedPriorTurns() {
|
|
40314
40740
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
40315
|
-
const report = await
|
|
40316
|
-
path33.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
40741
|
+
const report = await readSessionLogCached(
|
|
40742
|
+
path33.join(this.sessionsDir, this.sessionId, "events.jsonl"),
|
|
40743
|
+
this.replayCache
|
|
40317
40744
|
).catch(() => null);
|
|
40318
40745
|
if (!report || report.events.length === 0) return null;
|
|
40319
40746
|
return deriveMessages(report.events);
|
|
@@ -40322,8 +40749,9 @@ var init_sessionSpine = __esm({
|
|
|
40322
40749
|
async compactionStateSnapshot(toSeq) {
|
|
40323
40750
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
40324
40751
|
await this.flush();
|
|
40325
|
-
const report = await
|
|
40326
|
-
path33.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
40752
|
+
const report = await readSessionLogCached(
|
|
40753
|
+
path33.join(this.sessionsDir, this.sessionId, "events.jsonl"),
|
|
40754
|
+
this.replayCache
|
|
40327
40755
|
).catch(() => null);
|
|
40328
40756
|
if (!report || report.events.length === 0) return null;
|
|
40329
40757
|
return buildCompactionStateSnapshot(report.events, toSeq);
|
|
@@ -40335,8 +40763,9 @@ var init_sessionSpine = __esm({
|
|
|
40335
40763
|
*/
|
|
40336
40764
|
async lastVerificationRun() {
|
|
40337
40765
|
if (this.status !== "active" && this.status !== "closed") return null;
|
|
40338
|
-
const report = await
|
|
40339
|
-
path33.join(this.sessionsDir, this.sessionId, "events.jsonl")
|
|
40766
|
+
const report = await readSessionLogCached(
|
|
40767
|
+
path33.join(this.sessionsDir, this.sessionId, "events.jsonl"),
|
|
40768
|
+
this.replayCache
|
|
40340
40769
|
).catch(() => null);
|
|
40341
40770
|
if (!report) return null;
|
|
40342
40771
|
return lastVerificationRun(report.events);
|
|
@@ -40472,7 +40901,7 @@ var init_sessionSpine = __esm({
|
|
|
40472
40901
|
seq = seq.then(async (s) => {
|
|
40473
40902
|
try {
|
|
40474
40903
|
const eventsPath = path33.join(this.sessionsDir, this.sessionId, "events.jsonl");
|
|
40475
|
-
const report = await
|
|
40904
|
+
const report = await readSessionLogCached(eventsPath, this.replayCache).catch(() => null);
|
|
40476
40905
|
if (!report || typeof s !== "number") return s;
|
|
40477
40906
|
const current = latestTaskContract(report.events);
|
|
40478
40907
|
if (!current) return s;
|
|
@@ -40740,7 +41169,7 @@ async function loadObservationIndex(sessionId2, baseDir) {
|
|
|
40740
41169
|
mtimeMs = 0;
|
|
40741
41170
|
}
|
|
40742
41171
|
}
|
|
40743
|
-
const hit =
|
|
41172
|
+
const hit = cache2.get(sessionId2);
|
|
40744
41173
|
if (hit && !exists) return hit;
|
|
40745
41174
|
if (hit && hit.filePath === filePath && hit.mtimeMs === mtimeMs) return hit;
|
|
40746
41175
|
const events = existsSync15(filePath) ? await readSession(filePath) : [];
|
|
@@ -40769,12 +41198,12 @@ async function loadObservationIndex(sessionId2, baseDir) {
|
|
|
40769
41198
|
if (e.toolCallId) byToolCallId.set(e.toolCallId, seq);
|
|
40770
41199
|
}
|
|
40771
41200
|
const index = { filePath, mtimeMs, bySeq, byToolCallId, names };
|
|
40772
|
-
|
|
41201
|
+
cache2.set(sessionId2, index);
|
|
40773
41202
|
return index;
|
|
40774
41203
|
}
|
|
40775
41204
|
function invalidateObservationIndex(sessionId2) {
|
|
40776
|
-
if (sessionId2)
|
|
40777
|
-
else
|
|
41205
|
+
if (sessionId2) cache2.delete(sessionId2);
|
|
41206
|
+
else cache2.clear();
|
|
40778
41207
|
}
|
|
40779
41208
|
async function getObservationBySeq(sessionId2, seq, baseDir) {
|
|
40780
41209
|
const index = await loadObservationIndex(sessionId2, baseDir);
|
|
@@ -40782,7 +41211,7 @@ async function getObservationBySeq(sessionId2, seq, baseDir) {
|
|
|
40782
41211
|
}
|
|
40783
41212
|
function lookupSeqSync(sessionId2, toolCallId, baseDir) {
|
|
40784
41213
|
const filePath = sessionFilePath(sessionId2, baseDir);
|
|
40785
|
-
const hit =
|
|
41214
|
+
const hit = cache2.get(sessionId2);
|
|
40786
41215
|
if (hit && hit.filePath === filePath) return hit.byToolCallId.get(toolCallId);
|
|
40787
41216
|
return void 0;
|
|
40788
41217
|
}
|
|
@@ -40797,10 +41226,10 @@ function emptyIndex(sessionId2, baseDir) {
|
|
|
40797
41226
|
}
|
|
40798
41227
|
function ingestLiveEvent(sessionId2, event, baseDir) {
|
|
40799
41228
|
if (!sessionId2) return;
|
|
40800
|
-
let index =
|
|
41229
|
+
let index = cache2.get(sessionId2);
|
|
40801
41230
|
if (!index) {
|
|
40802
41231
|
index = emptyIndex(sessionId2, baseDir);
|
|
40803
|
-
|
|
41232
|
+
cache2.set(sessionId2, index);
|
|
40804
41233
|
}
|
|
40805
41234
|
if (isToolStart(event)) {
|
|
40806
41235
|
index.names.set(event.toolCallId, event.toolName);
|
|
@@ -40828,19 +41257,19 @@ function applySessionSurface(messages) {
|
|
|
40828
41257
|
const lookup = sid ? (id3) => lookupSeqSync(sid, id3) : void 0;
|
|
40829
41258
|
return projectSessionSurface(messages, void 0, lookup).messages;
|
|
40830
41259
|
}
|
|
40831
|
-
var
|
|
41260
|
+
var cache2;
|
|
40832
41261
|
var init_observationStore = __esm({
|
|
40833
41262
|
"src/cli/hooks/observationStore.ts"() {
|
|
40834
41263
|
"use strict";
|
|
40835
41264
|
init_harness();
|
|
40836
41265
|
init_sessionManager();
|
|
40837
41266
|
init_sessionSurface();
|
|
40838
|
-
|
|
41267
|
+
cache2 = /* @__PURE__ */ new Map();
|
|
40839
41268
|
}
|
|
40840
41269
|
});
|
|
40841
41270
|
|
|
40842
41271
|
// packages/core/dist/core/tools/toolOutputSpill.js
|
|
40843
|
-
import { createHash as
|
|
41272
|
+
import { createHash as createHash12, randomBytes as randomBytes3 } from "node:crypto";
|
|
40844
41273
|
import { existsSync as existsSync16, mkdirSync as mkdirSync7, writeFileSync as writeFileSync12 } from "node:fs";
|
|
40845
41274
|
import { homedir as homedir5, tmpdir as tmpdir2 } from "node:os";
|
|
40846
41275
|
import { join as join14 } from "node:path";
|
|
@@ -40870,7 +41299,7 @@ function spillToolOutput(fullText, meta3) {
|
|
|
40870
41299
|
if (!existsSync16(dir)) {
|
|
40871
41300
|
mkdirSync7(dir, { recursive: true });
|
|
40872
41301
|
}
|
|
40873
|
-
const hash3 =
|
|
41302
|
+
const hash3 = createHash12("sha256").update(fullText).digest("hex").slice(0, 12);
|
|
40874
41303
|
const stamp = Date.now().toString(36);
|
|
40875
41304
|
const rnd = randomBytes3(3).toString("hex");
|
|
40876
41305
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
@@ -41173,7 +41602,7 @@ var init_registry2 = __esm({
|
|
|
41173
41602
|
|
|
41174
41603
|
// src/cli/safety/sandboxPath.ts
|
|
41175
41604
|
import path35 from "node:path";
|
|
41176
|
-
import
|
|
41605
|
+
import fs16 from "node:fs";
|
|
41177
41606
|
function normalizedCase(p3) {
|
|
41178
41607
|
return IS_CASE_FOLDING ? p3.toLowerCase() : p3;
|
|
41179
41608
|
}
|
|
@@ -41207,7 +41636,7 @@ function assertRealAncestorContained(resolvedLexical, realRoot, userPath) {
|
|
|
41207
41636
|
for (; ; ) {
|
|
41208
41637
|
if (probe === path35.dirname(probe)) break;
|
|
41209
41638
|
try {
|
|
41210
|
-
realProbe =
|
|
41639
|
+
realProbe = fs16.realpathSync(probe);
|
|
41211
41640
|
break;
|
|
41212
41641
|
} catch (err) {
|
|
41213
41642
|
if (err?.code === "ENOENT") {
|
|
@@ -41235,7 +41664,7 @@ function resolveSandboxedCore(userPath, options = {}) {
|
|
|
41235
41664
|
assertLexicalContainment(resolved, root, userPath);
|
|
41236
41665
|
let realRoot = null;
|
|
41237
41666
|
try {
|
|
41238
|
-
realRoot =
|
|
41667
|
+
realRoot = fs16.realpathSync(root);
|
|
41239
41668
|
} catch {
|
|
41240
41669
|
return resolved;
|
|
41241
41670
|
}
|
|
@@ -41254,7 +41683,7 @@ function verifyContainment(resolvedAbsolute, options = {}) {
|
|
|
41254
41683
|
assertLexicalContainment(resolved, root, resolvedAbsolute);
|
|
41255
41684
|
let realRoot = null;
|
|
41256
41685
|
try {
|
|
41257
|
-
realRoot =
|
|
41686
|
+
realRoot = fs16.realpathSync(root);
|
|
41258
41687
|
} catch {
|
|
41259
41688
|
return;
|
|
41260
41689
|
}
|
|
@@ -41278,7 +41707,7 @@ var init_sandboxPath = __esm({
|
|
|
41278
41707
|
});
|
|
41279
41708
|
|
|
41280
41709
|
// src/cli/tools/krakenRadio.ts
|
|
41281
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync16, readdirSync as readdirSync3 } from "node:fs";
|
|
41710
|
+
import { appendFileSync as appendFileSync2, closeSync, existsSync as existsSync17, mkdirSync as mkdirSync8, openSync, readFileSync as readFileSync16, readdirSync as readdirSync3, writeSync } from "node:fs";
|
|
41282
41711
|
import path36 from "node:path";
|
|
41283
41712
|
function radioDir(cwd) {
|
|
41284
41713
|
return path36.join(cwd, ".zelari", "radio");
|
|
@@ -41287,6 +41716,35 @@ function radioPath(cwd, sessionId2) {
|
|
|
41287
41716
|
const safe = (sessionId2 || "default").replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
41288
41717
|
return path36.join(radioDir(cwd), `${safe}.jsonl`);
|
|
41289
41718
|
}
|
|
41719
|
+
function appendRadioLine(file2, line) {
|
|
41720
|
+
try {
|
|
41721
|
+
const cached2 = radioFds.get(file2);
|
|
41722
|
+
if (cached2 !== void 0) {
|
|
41723
|
+
writeSync(cached2, line, null, "utf8");
|
|
41724
|
+
return;
|
|
41725
|
+
}
|
|
41726
|
+
if (radioFds.size >= MAX_CACHED_RADIO_FDS) {
|
|
41727
|
+
appendFileSync2(file2, line, "utf8");
|
|
41728
|
+
return;
|
|
41729
|
+
}
|
|
41730
|
+
const fd = openSync(file2, "a");
|
|
41731
|
+
writeSync(fd, line, null, "utf8");
|
|
41732
|
+
radioFds.set(file2, fd);
|
|
41733
|
+
} catch {
|
|
41734
|
+
const stale = radioFds.get(file2);
|
|
41735
|
+
if (stale !== void 0) {
|
|
41736
|
+
radioFds.delete(file2);
|
|
41737
|
+
try {
|
|
41738
|
+
closeSync(stale);
|
|
41739
|
+
} catch {
|
|
41740
|
+
}
|
|
41741
|
+
}
|
|
41742
|
+
try {
|
|
41743
|
+
appendFileSync2(file2, line, "utf8");
|
|
41744
|
+
} catch {
|
|
41745
|
+
}
|
|
41746
|
+
}
|
|
41747
|
+
}
|
|
41290
41748
|
function appendKrakenRadio(cwd, sessionId2, event) {
|
|
41291
41749
|
try {
|
|
41292
41750
|
const dir = radioDir(cwd);
|
|
@@ -41312,8 +41770,8 @@ function appendKrakenRadio(cwd, sessionId2, event) {
|
|
|
41312
41770
|
...event.symbolsA !== void 0 ? { symbolsA: event.symbolsA } : {},
|
|
41313
41771
|
...event.symbolsB !== void 0 ? { symbolsB: event.symbolsB } : {}
|
|
41314
41772
|
};
|
|
41315
|
-
|
|
41316
|
-
|
|
41773
|
+
appendRadioLine(radioPath(cwd, sessionId2), `${JSON.stringify(row)}
|
|
41774
|
+
`);
|
|
41317
41775
|
} catch {
|
|
41318
41776
|
}
|
|
41319
41777
|
}
|
|
@@ -41350,9 +41808,12 @@ function formatKrakenRadioStatus(cwd, sessionId2, limit = 12) {
|
|
|
41350
41808
|
});
|
|
41351
41809
|
return [`Kraken radio (last ${events.length}) session=${sessionId2}:`, ...lines].join("\n");
|
|
41352
41810
|
}
|
|
41811
|
+
var MAX_CACHED_RADIO_FDS, radioFds;
|
|
41353
41812
|
var init_krakenRadio = __esm({
|
|
41354
41813
|
"src/cli/tools/krakenRadio.ts"() {
|
|
41355
41814
|
"use strict";
|
|
41815
|
+
MAX_CACHED_RADIO_FDS = 32;
|
|
41816
|
+
radioFds = /* @__PURE__ */ new Map();
|
|
41356
41817
|
}
|
|
41357
41818
|
});
|
|
41358
41819
|
|
|
@@ -41366,7 +41827,7 @@ import {
|
|
|
41366
41827
|
realpathSync
|
|
41367
41828
|
} from "node:fs";
|
|
41368
41829
|
import { join as join15, basename } from "node:path";
|
|
41369
|
-
import { createHash as
|
|
41830
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
41370
41831
|
function resolveWorkspaceRoot(projectRoot = process.cwd()) {
|
|
41371
41832
|
const candidates = [
|
|
41372
41833
|
join15(projectRoot, ".zelari"),
|
|
@@ -41382,7 +41843,7 @@ function resolveWorkspaceRoot(projectRoot = process.cwd()) {
|
|
|
41382
41843
|
return candidates[0];
|
|
41383
41844
|
}
|
|
41384
41845
|
function hashProject(projectPath) {
|
|
41385
|
-
return
|
|
41846
|
+
return createHash13("sha1").update(realpathSync(projectPath)).digest("hex").slice(0, 12);
|
|
41386
41847
|
}
|
|
41387
41848
|
function isWritableDir(dir) {
|
|
41388
41849
|
try {
|
|
@@ -42107,12 +42568,12 @@ var init_taskTouchGuard = __esm({
|
|
|
42107
42568
|
});
|
|
42108
42569
|
|
|
42109
42570
|
// src/cli/gitOps.ts
|
|
42110
|
-
import { execFile as
|
|
42111
|
-
import { promisify } from "node:util";
|
|
42571
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
42572
|
+
import { promisify as promisify2 } from "node:util";
|
|
42112
42573
|
import path38 from "node:path";
|
|
42113
42574
|
async function git2(cwd, args) {
|
|
42114
42575
|
try {
|
|
42115
|
-
const { stdout } = await
|
|
42576
|
+
const { stdout } = await execFileAsync2("git", ["-C", cwd, ...args], {
|
|
42116
42577
|
maxBuffer: 16 * 1024 * 1024
|
|
42117
42578
|
});
|
|
42118
42579
|
return stdout;
|
|
@@ -42164,11 +42625,11 @@ async function undoWorkingChanges(opts = {}) {
|
|
|
42164
42625
|
function defaultProjectRoot() {
|
|
42165
42626
|
return path38.resolve(__dirname, "..", "..", "..");
|
|
42166
42627
|
}
|
|
42167
|
-
var
|
|
42628
|
+
var execFileAsync2;
|
|
42168
42629
|
var init_gitOps = __esm({
|
|
42169
42630
|
"src/cli/gitOps.ts"() {
|
|
42170
42631
|
"use strict";
|
|
42171
|
-
|
|
42632
|
+
execFileAsync2 = promisify2(execFile3);
|
|
42172
42633
|
}
|
|
42173
42634
|
});
|
|
42174
42635
|
|
|
@@ -42303,7 +42764,7 @@ var auditLogger_exports = {};
|
|
|
42303
42764
|
__export(auditLogger_exports, {
|
|
42304
42765
|
AuditLogger: () => AuditLogger
|
|
42305
42766
|
});
|
|
42306
|
-
import { promises as
|
|
42767
|
+
import { promises as fs17 } from "node:fs";
|
|
42307
42768
|
import path39 from "node:path";
|
|
42308
42769
|
function defaultAuditPath() {
|
|
42309
42770
|
return auditLogPath();
|
|
@@ -42350,8 +42811,8 @@ var init_auditLogger = __esm({
|
|
|
42350
42811
|
async append(entry) {
|
|
42351
42812
|
const line = JSON.stringify(entry) + "\n";
|
|
42352
42813
|
this.writeQueue = this.writeQueue.then(async () => {
|
|
42353
|
-
await
|
|
42354
|
-
await
|
|
42814
|
+
await fs17.mkdir(path39.dirname(this.logPath), { recursive: true });
|
|
42815
|
+
await fs17.appendFile(this.logPath, line, "utf-8");
|
|
42355
42816
|
});
|
|
42356
42817
|
return this.writeQueue;
|
|
42357
42818
|
}
|
|
@@ -42570,11 +43031,54 @@ var init_engine2 = __esm({
|
|
|
42570
43031
|
}
|
|
42571
43032
|
});
|
|
42572
43033
|
|
|
43034
|
+
// src/cli/kraken/worktreeCleanupBatch.ts
|
|
43035
|
+
function resolveWorktreeCleanupMode(env = process.env) {
|
|
43036
|
+
const v = (env.ZELARI_KRAKEN_WORKTREE_CLEANUP ?? "").trim().toLowerCase();
|
|
43037
|
+
if (v === "eager") return "eager";
|
|
43038
|
+
return "batch";
|
|
43039
|
+
}
|
|
43040
|
+
function isKrakenWorktreeCleanupBatched(env = process.env) {
|
|
43041
|
+
return batchScopes > 0 && resolveWorktreeCleanupMode(env) === "batch";
|
|
43042
|
+
}
|
|
43043
|
+
function beginKrakenWorktreeCleanupBatch(env = process.env) {
|
|
43044
|
+
if (resolveWorktreeCleanupMode(env) !== "batch") return false;
|
|
43045
|
+
batchScopes += 1;
|
|
43046
|
+
return true;
|
|
43047
|
+
}
|
|
43048
|
+
function queueWorktreeCleanup(repoRoot, branch) {
|
|
43049
|
+
pendingPruneRoots.add(repoRoot);
|
|
43050
|
+
if (!branch) return;
|
|
43051
|
+
const queued = pendingBranches.get(repoRoot) ?? /* @__PURE__ */ new Set();
|
|
43052
|
+
queued.add(branch);
|
|
43053
|
+
pendingBranches.set(repoRoot, queued);
|
|
43054
|
+
}
|
|
43055
|
+
function takeQueuedWorktreeCleanup() {
|
|
43056
|
+
if (batchScopes > 0) batchScopes -= 1;
|
|
43057
|
+
const repoRoots = /* @__PURE__ */ new Set([...pendingPruneRoots, ...pendingBranches.keys()]);
|
|
43058
|
+
const branchesByRoot = /* @__PURE__ */ new Map();
|
|
43059
|
+
for (const repoRoot of repoRoots) {
|
|
43060
|
+
const queued = pendingBranches.get(repoRoot);
|
|
43061
|
+
if (queued && queued.size > 0) branchesByRoot.set(repoRoot, [...queued]);
|
|
43062
|
+
pendingPruneRoots.delete(repoRoot);
|
|
43063
|
+
pendingBranches.delete(repoRoot);
|
|
43064
|
+
}
|
|
43065
|
+
return { repoRoots: [...repoRoots], branchesByRoot };
|
|
43066
|
+
}
|
|
43067
|
+
var pendingPruneRoots, pendingBranches, batchScopes;
|
|
43068
|
+
var init_worktreeCleanupBatch = __esm({
|
|
43069
|
+
"src/cli/kraken/worktreeCleanupBatch.ts"() {
|
|
43070
|
+
"use strict";
|
|
43071
|
+
pendingPruneRoots = /* @__PURE__ */ new Set();
|
|
43072
|
+
pendingBranches = /* @__PURE__ */ new Map();
|
|
43073
|
+
batchScopes = 0;
|
|
43074
|
+
}
|
|
43075
|
+
});
|
|
43076
|
+
|
|
42573
43077
|
// src/cli/tools/krakenWorktree.ts
|
|
42574
|
-
import { execFile as
|
|
43078
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
42575
43079
|
import { existsSync as existsSync24, mkdirSync as mkdirSync12, rmSync } from "node:fs";
|
|
42576
43080
|
import path41 from "node:path";
|
|
42577
|
-
import { promisify as
|
|
43081
|
+
import { promisify as promisify3 } from "node:util";
|
|
42578
43082
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
42579
43083
|
function isKrakenWorktreeEnabled(env = process.env) {
|
|
42580
43084
|
const v = (env.ZELARI_KRAKEN_WORKTREE ?? "").trim().toLowerCase();
|
|
@@ -42590,9 +43094,29 @@ function isKrakenWorktreeAutoMergeEnabled(env = process.env) {
|
|
|
42590
43094
|
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
42591
43095
|
return true;
|
|
42592
43096
|
}
|
|
43097
|
+
async function flushKrakenWorktreeCleanupBatch() {
|
|
43098
|
+
const { repoRoots, branchesByRoot } = takeQueuedWorktreeCleanup();
|
|
43099
|
+
const branches = [];
|
|
43100
|
+
const deleted = [];
|
|
43101
|
+
let pruned = 0;
|
|
43102
|
+
for (const repoRoot of repoRoots) {
|
|
43103
|
+
await git3(repoRoot, ["worktree", "prune"]);
|
|
43104
|
+
pruned += 1;
|
|
43105
|
+
const list = branchesByRoot.get(repoRoot);
|
|
43106
|
+
if (list && list.length > 0) {
|
|
43107
|
+
branches.push(...list);
|
|
43108
|
+
const r = await git3(repoRoot, ["branch", "-D", ...list]);
|
|
43109
|
+
for (const line of r.stdout.split("\n")) {
|
|
43110
|
+
const m = /^Deleted branch (\S+)/.exec(line.trim());
|
|
43111
|
+
if (m?.[1]) deleted.push(m[1]);
|
|
43112
|
+
}
|
|
43113
|
+
}
|
|
43114
|
+
}
|
|
43115
|
+
return { pruned, branches, deleted, repoRoots };
|
|
43116
|
+
}
|
|
42593
43117
|
async function git3(cwd, args) {
|
|
42594
43118
|
try {
|
|
42595
|
-
const { stdout, stderr } = await
|
|
43119
|
+
const { stdout, stderr } = await execFileAsync3("git", ["-C", cwd, ...args], {
|
|
42596
43120
|
maxBuffer: 16 * 1024 * 1024,
|
|
42597
43121
|
windowsHide: true
|
|
42598
43122
|
});
|
|
@@ -42608,10 +43132,15 @@ async function git3(cwd, args) {
|
|
|
42608
43132
|
}
|
|
42609
43133
|
}
|
|
42610
43134
|
async function resolveGitRoot(cwd) {
|
|
43135
|
+
const key = path41.resolve(cwd);
|
|
43136
|
+
const memo = gitRootMemo.get(key);
|
|
43137
|
+
if (memo) return memo;
|
|
42611
43138
|
const r = await git3(cwd, ["rev-parse", "--show-toplevel"]);
|
|
42612
43139
|
if (!r.ok) return null;
|
|
42613
43140
|
const root = r.stdout.trim();
|
|
42614
|
-
|
|
43141
|
+
if (!root) return null;
|
|
43142
|
+
gitRootMemo.set(key, root);
|
|
43143
|
+
return root;
|
|
42615
43144
|
}
|
|
42616
43145
|
async function createKrakenWorktree(cwd, label) {
|
|
42617
43146
|
const repoRoot = await resolveGitRoot(cwd);
|
|
@@ -42741,9 +43270,14 @@ async function cleanupKrakenWorktree(handle, env = process.env) {
|
|
|
42741
43270
|
}
|
|
42742
43271
|
} catch {
|
|
42743
43272
|
}
|
|
43273
|
+
const branch = handle.branch.startsWith("kraken/") ? handle.branch : null;
|
|
43274
|
+
if (isKrakenWorktreeCleanupBatched(env)) {
|
|
43275
|
+
queueWorktreeCleanup(handle.repoRoot, branch);
|
|
43276
|
+
return;
|
|
43277
|
+
}
|
|
42744
43278
|
await git3(handle.repoRoot, ["worktree", "prune"]);
|
|
42745
|
-
if (
|
|
42746
|
-
await git3(handle.repoRoot, ["branch", "-D",
|
|
43279
|
+
if (branch) {
|
|
43280
|
+
await git3(handle.repoRoot, ["branch", "-D", branch]);
|
|
42747
43281
|
}
|
|
42748
43282
|
}
|
|
42749
43283
|
function formatWorktreeFooter(handle, opts = {}) {
|
|
@@ -42757,11 +43291,14 @@ function formatWorktreeFooter(handle, opts = {}) {
|
|
|
42757
43291
|
}
|
|
42758
43292
|
return `worktree used: branch=${handle.branch} path=${handle.path}`;
|
|
42759
43293
|
}
|
|
42760
|
-
var
|
|
43294
|
+
var execFileAsync3, gitRootMemo;
|
|
42761
43295
|
var init_krakenWorktree = __esm({
|
|
42762
43296
|
"src/cli/tools/krakenWorktree.ts"() {
|
|
42763
43297
|
"use strict";
|
|
42764
|
-
|
|
43298
|
+
init_worktreeCleanupBatch();
|
|
43299
|
+
init_worktreeCleanupBatch();
|
|
43300
|
+
execFileAsync3 = promisify3(execFile4);
|
|
43301
|
+
gitRootMemo = /* @__PURE__ */ new Map();
|
|
42765
43302
|
}
|
|
42766
43303
|
});
|
|
42767
43304
|
|
|
@@ -43086,6 +43623,43 @@ var init_metrics2 = __esm({
|
|
|
43086
43623
|
}
|
|
43087
43624
|
});
|
|
43088
43625
|
|
|
43626
|
+
// src/cli/tools/tentacleHeartbeat.ts
|
|
43627
|
+
function resolveTentacleHeartbeatMs(env = process.env) {
|
|
43628
|
+
const raw = env.ZELARI_TENTACLE_HEARTBEAT_MS?.trim();
|
|
43629
|
+
if (raw === "0" || raw === "off") return 0;
|
|
43630
|
+
if (!raw) return TENTACLE_HEARTBEAT_DEFAULT_MS;
|
|
43631
|
+
const n = Number.parseInt(raw, 10);
|
|
43632
|
+
return Number.isFinite(n) && n >= 0 ? n : TENTACLE_HEARTBEAT_DEFAULT_MS;
|
|
43633
|
+
}
|
|
43634
|
+
function formatTentacleElapsed(ms) {
|
|
43635
|
+
const totalSec = Math.max(0, Math.floor(ms / 1e3));
|
|
43636
|
+
const m = Math.floor(totalSec / 60);
|
|
43637
|
+
const s = totalSec % 60;
|
|
43638
|
+
return m > 0 ? `${m}m ${s}s` : `${s}s`;
|
|
43639
|
+
}
|
|
43640
|
+
function tentacleHeartbeatCaption(elapsedMs) {
|
|
43641
|
+
return `reasoning \xB7 ${formatTentacleElapsed(elapsedMs)}`;
|
|
43642
|
+
}
|
|
43643
|
+
function startTentacleHeartbeat(onBeat, opts) {
|
|
43644
|
+
const intervalMs = opts?.intervalMs ?? resolveTentacleHeartbeatMs();
|
|
43645
|
+
if (intervalMs <= 0) return () => {
|
|
43646
|
+
};
|
|
43647
|
+
const now = opts?.now ?? Date.now;
|
|
43648
|
+
const started = now();
|
|
43649
|
+
const timer = setInterval(() => {
|
|
43650
|
+
onBeat(tentacleHeartbeatCaption(now() - started));
|
|
43651
|
+
}, intervalMs);
|
|
43652
|
+
timer.unref?.();
|
|
43653
|
+
return () => clearInterval(timer);
|
|
43654
|
+
}
|
|
43655
|
+
var TENTACLE_HEARTBEAT_DEFAULT_MS;
|
|
43656
|
+
var init_tentacleHeartbeat = __esm({
|
|
43657
|
+
"src/cli/tools/tentacleHeartbeat.ts"() {
|
|
43658
|
+
"use strict";
|
|
43659
|
+
TENTACLE_HEARTBEAT_DEFAULT_MS = 15e3;
|
|
43660
|
+
}
|
|
43661
|
+
});
|
|
43662
|
+
|
|
43089
43663
|
// src/cli/kraken/tentacle.ts
|
|
43090
43664
|
var tentacle_exports = {};
|
|
43091
43665
|
__export(tentacle_exports, {
|
|
@@ -43100,15 +43674,46 @@ var init_tentacle = __esm({
|
|
|
43100
43674
|
}
|
|
43101
43675
|
});
|
|
43102
43676
|
|
|
43677
|
+
// src/cli/asyncLimit.ts
|
|
43678
|
+
async function runWithLimit2(items, limit, fn) {
|
|
43679
|
+
const slots = Math.min(
|
|
43680
|
+
items.length,
|
|
43681
|
+
Math.max(1, Number.isFinite(limit) ? Math.floor(limit) : 1)
|
|
43682
|
+
);
|
|
43683
|
+
if (slots <= 0) return;
|
|
43684
|
+
let cursor = 0;
|
|
43685
|
+
let failed = false;
|
|
43686
|
+
const worker = async () => {
|
|
43687
|
+
while (!failed && cursor < items.length) {
|
|
43688
|
+
const index = cursor;
|
|
43689
|
+
cursor += 1;
|
|
43690
|
+
try {
|
|
43691
|
+
await fn(items[index], index);
|
|
43692
|
+
} catch (err) {
|
|
43693
|
+
failed = true;
|
|
43694
|
+
throw err;
|
|
43695
|
+
}
|
|
43696
|
+
}
|
|
43697
|
+
};
|
|
43698
|
+
const workers = [];
|
|
43699
|
+
for (let i = 0; i < slots; i += 1) workers.push(worker());
|
|
43700
|
+
await Promise.all(workers);
|
|
43701
|
+
}
|
|
43702
|
+
var init_asyncLimit = __esm({
|
|
43703
|
+
"src/cli/asyncLimit.ts"() {
|
|
43704
|
+
"use strict";
|
|
43705
|
+
}
|
|
43706
|
+
});
|
|
43707
|
+
|
|
43103
43708
|
// src/cli/checkpoint/checkpointManager.ts
|
|
43104
|
-
import { execFile as
|
|
43105
|
-
import { promisify as
|
|
43709
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
43710
|
+
import { promisify as promisify4 } from "node:util";
|
|
43106
43711
|
import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
|
|
43107
43712
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
43108
43713
|
import path42 from "node:path";
|
|
43109
43714
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
43110
43715
|
async function git4(cwd, args, env) {
|
|
43111
|
-
const { stdout } = await
|
|
43716
|
+
const { stdout } = await execFileAsync4("git", ["-C", cwd, ...args], {
|
|
43112
43717
|
maxBuffer: 64 * 1024 * 1024,
|
|
43113
43718
|
env: env ? { ...process.env, ...env } : process.env
|
|
43114
43719
|
});
|
|
@@ -43230,11 +43835,11 @@ async function restoreCheckpoint(cwd, id3) {
|
|
|
43230
43835
|
async function dropCheckpoint(cwd, id3) {
|
|
43231
43836
|
return await gitSafe(cwd, ["update-ref", "-d", `${REF_PREFIX}${id3}`]) !== null;
|
|
43232
43837
|
}
|
|
43233
|
-
var
|
|
43838
|
+
var execFileAsync4, REF_PREFIX;
|
|
43234
43839
|
var init_checkpointManager = __esm({
|
|
43235
43840
|
"src/cli/checkpoint/checkpointManager.ts"() {
|
|
43236
43841
|
"use strict";
|
|
43237
|
-
|
|
43842
|
+
execFileAsync4 = promisify4(execFile5);
|
|
43238
43843
|
REF_PREFIX = "refs/zelari/checkpoints/";
|
|
43239
43844
|
}
|
|
43240
43845
|
});
|
|
@@ -43296,7 +43901,7 @@ var init_transactional = __esm({
|
|
|
43296
43901
|
});
|
|
43297
43902
|
|
|
43298
43903
|
// src/cli/workspace/worldModel.ts
|
|
43299
|
-
import { promises as
|
|
43904
|
+
import { promises as fs18 } from "node:fs";
|
|
43300
43905
|
import path43 from "node:path";
|
|
43301
43906
|
import { spawn as spawn8 } from "node:child_process";
|
|
43302
43907
|
function worldDir(cwd) {
|
|
@@ -43304,18 +43909,18 @@ function worldDir(cwd) {
|
|
|
43304
43909
|
}
|
|
43305
43910
|
async function ensureWorldDir(cwd) {
|
|
43306
43911
|
const dir = worldDir(cwd);
|
|
43307
|
-
await
|
|
43912
|
+
await fs18.mkdir(dir, { recursive: true });
|
|
43308
43913
|
return dir;
|
|
43309
43914
|
}
|
|
43310
43915
|
async function appendTimeline(cwd, entry) {
|
|
43311
43916
|
const dir = await ensureWorldDir(cwd);
|
|
43312
43917
|
const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
|
|
43313
|
-
await
|
|
43918
|
+
await fs18.appendFile(path43.join(dir, TIMELINE_FILE), line, "utf8");
|
|
43314
43919
|
}
|
|
43315
43920
|
async function readChecks(cwd) {
|
|
43316
43921
|
const p3 = path43.join(worldDir(cwd), CHECKS_FILE);
|
|
43317
43922
|
try {
|
|
43318
|
-
const raw = await
|
|
43923
|
+
const raw = await fs18.readFile(p3, "utf8");
|
|
43319
43924
|
const parsed = JSON.parse(raw);
|
|
43320
43925
|
return Array.isArray(parsed.checks) ? parsed.checks : [];
|
|
43321
43926
|
} catch {
|
|
@@ -43483,11 +44088,11 @@ var init_worldModel = __esm({
|
|
|
43483
44088
|
|
|
43484
44089
|
${args.content}
|
|
43485
44090
|
`;
|
|
43486
|
-
await
|
|
44091
|
+
await fs18.appendFile(file2, block, "utf8");
|
|
43487
44092
|
} else {
|
|
43488
|
-
await
|
|
44093
|
+
await fs18.writeFile(file2, args.content, "utf8");
|
|
43489
44094
|
}
|
|
43490
|
-
const st = await
|
|
44095
|
+
const st = await fs18.stat(file2);
|
|
43491
44096
|
await appendTimeline(ctx.cwd, { kind: "hypothesis_update", bytes: st.size, append: !!args.append });
|
|
43492
44097
|
return typedOk({ path: file2, bytes: st.size });
|
|
43493
44098
|
} catch (err) {
|
|
@@ -43516,7 +44121,7 @@ ${args.content}
|
|
|
43516
44121
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
43517
44122
|
const file2 = path43.join(dir, CHECKS_FILE);
|
|
43518
44123
|
const body = { checks: args.checks };
|
|
43519
|
-
await
|
|
44124
|
+
await fs18.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
|
|
43520
44125
|
await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
|
|
43521
44126
|
return typedOk({ path: file2, count: args.checks.length });
|
|
43522
44127
|
} catch (err) {
|
|
@@ -43601,7 +44206,7 @@ __export(graphMemory_exports, {
|
|
|
43601
44206
|
saveGraphSnapshot: () => saveGraphSnapshot,
|
|
43602
44207
|
toGraphSnapshot: () => toGraphSnapshot
|
|
43603
44208
|
});
|
|
43604
|
-
import { promises as
|
|
44209
|
+
import { promises as fs19 } from "node:fs";
|
|
43605
44210
|
import path44 from "node:path";
|
|
43606
44211
|
function snapshotPath(cwd) {
|
|
43607
44212
|
return path44.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
|
|
@@ -43629,16 +44234,16 @@ function toGraphSnapshot(graph, opts) {
|
|
|
43629
44234
|
}
|
|
43630
44235
|
async function saveGraphSnapshot(cwd, snapshot) {
|
|
43631
44236
|
try {
|
|
43632
|
-
await
|
|
44237
|
+
await fs19.access(cwd);
|
|
43633
44238
|
const file2 = snapshotPath(cwd);
|
|
43634
|
-
await
|
|
43635
|
-
await
|
|
44239
|
+
await fs19.mkdir(path44.dirname(file2), { recursive: true });
|
|
44240
|
+
await fs19.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
43636
44241
|
} catch {
|
|
43637
44242
|
}
|
|
43638
44243
|
}
|
|
43639
44244
|
async function loadGraphSnapshot(cwd) {
|
|
43640
44245
|
try {
|
|
43641
|
-
const raw = await
|
|
44246
|
+
const raw = await fs19.readFile(snapshotPath(cwd), "utf8");
|
|
43642
44247
|
const parsed = JSON.parse(raw);
|
|
43643
44248
|
if (!parsed || !Array.isArray(parsed.nodes)) return null;
|
|
43644
44249
|
return parsed;
|
|
@@ -43705,7 +44310,7 @@ var init_graphMemory = __esm({
|
|
|
43705
44310
|
});
|
|
43706
44311
|
|
|
43707
44312
|
// src/cli/kraken/workbench.ts
|
|
43708
|
-
import { promises as
|
|
44313
|
+
import { promises as fs20 } from "node:fs";
|
|
43709
44314
|
import path45 from "node:path";
|
|
43710
44315
|
function isWorkbenchEnabled(env = process.env) {
|
|
43711
44316
|
const v = (env.ZELARI_KRAKEN_WORKBENCH ?? "1").trim().toLowerCase();
|
|
@@ -43876,11 +44481,11 @@ var init_workbench = __esm({
|
|
|
43876
44481
|
if (!this.enabled) return null;
|
|
43877
44482
|
if (!this.dirty && this.lastWrite) return this.lastWrite;
|
|
43878
44483
|
const out = workbenchPath(this.cwd, this.graphId);
|
|
43879
|
-
await
|
|
44484
|
+
await fs20.mkdir(path45.dirname(out), { recursive: true });
|
|
43880
44485
|
const body = this.render();
|
|
43881
44486
|
const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
|
|
43882
|
-
await
|
|
43883
|
-
await
|
|
44487
|
+
await fs20.writeFile(tmp, body, "utf8");
|
|
44488
|
+
await fs20.rename(tmp, out);
|
|
43884
44489
|
this.dirty = false;
|
|
43885
44490
|
this.lastWrite = Promise.resolve(out);
|
|
43886
44491
|
return out;
|
|
@@ -44460,9 +45065,11 @@ var init_reputationStore = __esm({
|
|
|
44460
45065
|
// src/cli/tools/krakenModel.ts
|
|
44461
45066
|
var krakenModel_exports = {};
|
|
44462
45067
|
__export(krakenModel_exports, {
|
|
45068
|
+
familyCandidatesFromRegistry: () => familyCandidatesFromRegistry,
|
|
44463
45069
|
inferModelFamily: () => inferModelFamily,
|
|
44464
45070
|
isCheapModelId: () => isCheapModelId,
|
|
44465
45071
|
isKrakenAutoModelEnabled: () => isKrakenAutoModelEnabled,
|
|
45072
|
+
isKrakenCrossModelEnabled: () => isKrakenCrossModelEnabled,
|
|
44466
45073
|
isUnknownModelError: () => isUnknownModelError,
|
|
44467
45074
|
parseQualifiedModelRef: () => parseQualifiedModelRef,
|
|
44468
45075
|
pickCheapModel: () => pickCheapModel,
|
|
@@ -44503,6 +45110,10 @@ function isKrakenAutoModelEnabled(env = process.env) {
|
|
|
44503
45110
|
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
44504
45111
|
return true;
|
|
44505
45112
|
}
|
|
45113
|
+
function isKrakenCrossModelEnabled(env = process.env) {
|
|
45114
|
+
const v = (env.ZELARI_KRAKEN_CROSS_MODEL ?? "").trim().toLowerCase();
|
|
45115
|
+
return !(v === "0" || v === "false" || v === "no" || v === "off");
|
|
45116
|
+
}
|
|
44506
45117
|
function parseQualifiedModelRef(ref) {
|
|
44507
45118
|
const s = ref?.trim() ?? "";
|
|
44508
45119
|
const slash = s.indexOf("/");
|
|
@@ -44539,8 +45150,7 @@ function pickDifferentFamily(builder, candidates) {
|
|
|
44539
45150
|
return null;
|
|
44540
45151
|
}
|
|
44541
45152
|
function resolveCrossModelVerifier(builder, candidates, env = process.env) {
|
|
44542
|
-
|
|
44543
|
-
if (cross === "0" || cross === "false" || cross === "off") return null;
|
|
45153
|
+
if (!isKrakenCrossModelEnabled(env)) return null;
|
|
44544
45154
|
const specific = env.ZELARI_KRAKEN_VERIFY_MODEL?.trim();
|
|
44545
45155
|
if (specific) {
|
|
44546
45156
|
const qualified = parseQualifiedModelRef(specific);
|
|
@@ -44562,7 +45172,7 @@ function resolveKrakenSubModel(agent, parentModel, env = process.env, opts = {})
|
|
|
44562
45172
|
}
|
|
44563
45173
|
return shared;
|
|
44564
45174
|
}
|
|
44565
|
-
if (agent === "verify" && opts.familyCandidates && opts.familyCandidates.length > 0) {
|
|
45175
|
+
if (agent === "verify" && opts.familyCandidates && opts.familyCandidates.length > 0 && isKrakenCrossModelEnabled(env)) {
|
|
44566
45176
|
const picked = pickDifferentFamily(
|
|
44567
45177
|
{ provider: opts.provider ?? "", model: parentModel },
|
|
44568
45178
|
opts.familyCandidates
|
|
@@ -44592,20 +45202,40 @@ function resolvePersonaModel(kind2, parentModel, env = process.env, opts = {}) {
|
|
|
44592
45202
|
if (specific) return specific;
|
|
44593
45203
|
return resolveKrakenSubModel("verify", parentModel, env, opts);
|
|
44594
45204
|
}
|
|
45205
|
+
function familyCandidatesFromRegistry(registry4) {
|
|
45206
|
+
if (!registry4 || typeof registry4 !== "object") return [];
|
|
45207
|
+
const out = [];
|
|
45208
|
+
for (const [key, entry] of Object.entries(registry4)) {
|
|
45209
|
+
const provider = key?.trim() ?? "";
|
|
45210
|
+
if (!provider) continue;
|
|
45211
|
+
const models = entry?.models;
|
|
45212
|
+
if (!Array.isArray(models)) continue;
|
|
45213
|
+
for (const raw of models) {
|
|
45214
|
+
const id3 = typeof raw === "string" ? raw : raw && typeof raw.id === "string" ? raw.id : "";
|
|
45215
|
+
const model = id3.trim();
|
|
45216
|
+
if (model) out.push({ provider, model });
|
|
45217
|
+
}
|
|
45218
|
+
}
|
|
45219
|
+
return out;
|
|
45220
|
+
}
|
|
44595
45221
|
async function resolveKrakenSubModelAsync(agent, parentModel, env = process.env, opts = {}) {
|
|
44596
45222
|
let candidates = [];
|
|
44597
|
-
|
|
44598
|
-
|
|
44599
|
-
|
|
45223
|
+
let familyCandidates = [];
|
|
45224
|
+
try {
|
|
45225
|
+
const mod = await Promise.resolve().then(() => (init_modelDiscovery(), modelDiscovery_exports));
|
|
45226
|
+
if (opts.provider) {
|
|
44600
45227
|
const ids = mod.getDiscoveredModelIds(opts.provider);
|
|
44601
45228
|
if (Array.isArray(ids)) candidates = ids;
|
|
44602
|
-
} catch {
|
|
44603
|
-
candidates = [];
|
|
44604
45229
|
}
|
|
45230
|
+
familyCandidates = familyCandidatesFromRegistry(mod.loadModelsRegistry());
|
|
45231
|
+
} catch {
|
|
45232
|
+
candidates = [];
|
|
45233
|
+
familyCandidates = [];
|
|
44605
45234
|
}
|
|
44606
45235
|
return resolveKrakenSubModel(agent, parentModel, env, {
|
|
44607
45236
|
provider: opts.provider,
|
|
44608
|
-
candidates
|
|
45237
|
+
candidates,
|
|
45238
|
+
familyCandidates
|
|
44609
45239
|
});
|
|
44610
45240
|
}
|
|
44611
45241
|
var CHEAP_RE, FLAGSHIP_RE;
|
|
@@ -45068,6 +45698,7 @@ var init_executor = __esm({
|
|
|
45068
45698
|
init_tentacle();
|
|
45069
45699
|
init_krakenWorktree();
|
|
45070
45700
|
init_krakenRadio();
|
|
45701
|
+
init_asyncLimit();
|
|
45071
45702
|
init_transactional();
|
|
45072
45703
|
init_worldModel();
|
|
45073
45704
|
init_graphStatus();
|
|
@@ -45238,11 +45869,13 @@ var init_executor = __esm({
|
|
|
45238
45869
|
}, this.graphTimeoutMs);
|
|
45239
45870
|
graphTimer.unref?.();
|
|
45240
45871
|
}
|
|
45872
|
+
const worktreeCleanupBatched = beginKrakenWorktreeCleanupBatch(process.env);
|
|
45241
45873
|
try {
|
|
45242
45874
|
return await this.schedule(graph);
|
|
45243
45875
|
} finally {
|
|
45244
45876
|
if (graphTimer) clearTimeout(graphTimer);
|
|
45245
45877
|
this.signal?.removeEventListener("abort", onAbort);
|
|
45878
|
+
if (worktreeCleanupBatched) await flushKrakenWorktreeCleanupBatch();
|
|
45246
45879
|
}
|
|
45247
45880
|
}
|
|
45248
45881
|
/** The scheduling loop proper. See {@link execute} for the cancellation wrapper. */
|
|
@@ -46029,6 +46662,7 @@ ${upstream}` : node.prompt,
|
|
|
46029
46662
|
const memory = this.deps.memoryService;
|
|
46030
46663
|
if (!memory || this.deps.memoryAutoWrite === false) return;
|
|
46031
46664
|
try {
|
|
46665
|
+
const edges = [];
|
|
46032
46666
|
for (const node of graph.nodes.values()) {
|
|
46033
46667
|
const nodeMemoryId = this.memoryIds.get(node.id);
|
|
46034
46668
|
if (!nodeMemoryId) continue;
|
|
@@ -46037,22 +46671,21 @@ ${upstream}` : node.prompt,
|
|
|
46037
46671
|
if (!dependencyMemoryId) continue;
|
|
46038
46672
|
if (node.kind === "verify") {
|
|
46039
46673
|
const verdict = parseVerifyVerdict(node.result).verdict;
|
|
46040
|
-
|
|
46674
|
+
edges.push({
|
|
46041
46675
|
from: dependencyMemoryId,
|
|
46042
46676
|
to: nodeMemoryId,
|
|
46043
|
-
relation: verdict === "pass" ? "validated_by" : verdict === "fail" ? "invalidated_by" : "related_to"
|
|
46044
|
-
createdBy: "kraken-orchestrator"
|
|
46677
|
+
relation: verdict === "pass" ? "validated_by" : verdict === "fail" ? "invalidated_by" : "related_to"
|
|
46045
46678
|
});
|
|
46046
46679
|
} else {
|
|
46047
|
-
|
|
46048
|
-
from: nodeMemoryId,
|
|
46049
|
-
to: dependencyMemoryId,
|
|
46050
|
-
relation: "derived_from",
|
|
46051
|
-
createdBy: "kraken-orchestrator"
|
|
46052
|
-
});
|
|
46680
|
+
edges.push({ from: nodeMemoryId, to: dependencyMemoryId, relation: "derived_from" });
|
|
46053
46681
|
}
|
|
46054
46682
|
}
|
|
46055
46683
|
}
|
|
46684
|
+
await runWithLimit2(
|
|
46685
|
+
edges,
|
|
46686
|
+
8,
|
|
46687
|
+
(edge) => memory.connect({ ...edge, createdBy: "kraken-orchestrator" }).catch(() => void 0)
|
|
46688
|
+
);
|
|
46056
46689
|
const counts = countByStatus(graph);
|
|
46057
46690
|
const outcome = await memory.remember({
|
|
46058
46691
|
kind: converged ? "outcome" : "failure",
|
|
@@ -46064,14 +46697,17 @@ ${upstream}` : node.prompt,
|
|
|
46064
46697
|
metadata: { graphId: graph.id, converged, counts, writeClass: "auto" },
|
|
46065
46698
|
writeClass: "auto"
|
|
46066
46699
|
});
|
|
46067
|
-
|
|
46068
|
-
|
|
46069
|
-
|
|
46070
|
-
|
|
46071
|
-
|
|
46072
|
-
|
|
46073
|
-
|
|
46074
|
-
|
|
46700
|
+
const outcomeEdges = [...this.memoryIds.values()].map((memoryId) => ({
|
|
46701
|
+
from: outcome.id,
|
|
46702
|
+
to: memoryId,
|
|
46703
|
+
relation: "derived_from",
|
|
46704
|
+
createdBy: "kraken-orchestrator"
|
|
46705
|
+
}));
|
|
46706
|
+
await runWithLimit2(
|
|
46707
|
+
outcomeEdges,
|
|
46708
|
+
8,
|
|
46709
|
+
(edge) => memory.connect(edge).catch(() => void 0)
|
|
46710
|
+
);
|
|
46075
46711
|
await memory.consolidate({
|
|
46076
46712
|
source: { agent: "kraken-orchestrator", sessionId: this.sessionId },
|
|
46077
46713
|
minOccurrences: 2
|
|
@@ -46875,36 +47511,54 @@ ${taskUserContent}`,
|
|
|
46875
47511
|
emitActivity({ type: "agent_tool", agentId: liveId, toolCallId: ev.toolCallId, tool: startedTools.get(ev.toolCallId) ?? "unknown", status: ev.isError ? "failed" : "completed", durationMs: ev.durationMs, ts: Date.now() });
|
|
46876
47512
|
}
|
|
46877
47513
|
};
|
|
46878
|
-
|
|
46879
|
-
|
|
46880
|
-
|
|
47514
|
+
const stopHeartbeat = startTentacleHeartbeat((caption) => {
|
|
47515
|
+
emitActivity({
|
|
47516
|
+
type: "agent_status",
|
|
47517
|
+
agentId: liveId,
|
|
47518
|
+
status: "running",
|
|
47519
|
+
message: caption,
|
|
47520
|
+
ts: Date.now()
|
|
47521
|
+
});
|
|
46881
47522
|
});
|
|
46882
|
-
|
|
46883
|
-
|
|
46884
|
-
|
|
46885
|
-
|
|
46886
|
-
|
|
46887
|
-
|
|
46888
|
-
|
|
46889
|
-
|
|
46890
|
-
|
|
46891
|
-
|
|
46892
|
-
|
|
46893
|
-
|
|
46894
|
-
|
|
46895
|
-
|
|
46896
|
-
|
|
46897
|
-
|
|
46898
|
-
|
|
46899
|
-
|
|
46900
|
-
|
|
46901
|
-
|
|
46902
|
-
|
|
46903
|
-
|
|
46904
|
-
|
|
46905
|
-
|
|
47523
|
+
let result;
|
|
47524
|
+
let error51;
|
|
47525
|
+
let aborted2;
|
|
47526
|
+
let usage;
|
|
47527
|
+
let toolTrace;
|
|
47528
|
+
try {
|
|
47529
|
+
({ result, error: error51, aborted: aborted2, usage, toolTrace } = await runSubAgent(harness, {
|
|
47530
|
+
...opts.signal ? { signal: opts.signal } : {},
|
|
47531
|
+
onEvent: onHarnessEvent
|
|
47532
|
+
}));
|
|
47533
|
+
if (!aborted2 && !result && sub.fallback && sub.fallback.model !== sub.model) {
|
|
47534
|
+
const { isUnknownModelError: isUnknownModelError2 } = await Promise.resolve().then(() => (init_krakenModel(), krakenModel_exports));
|
|
47535
|
+
if (isUnknownModelError2(error51)) {
|
|
47536
|
+
emitPhase(`model ${sub.model} unavailable \u2014 retrying with ${sub.fallback.model}`);
|
|
47537
|
+
const retryConfig = {
|
|
47538
|
+
...config2,
|
|
47539
|
+
model: sub.fallback.model,
|
|
47540
|
+
provider: sub.fallback.provider,
|
|
47541
|
+
providerStream: sub.fallback.providerStream
|
|
47542
|
+
};
|
|
47543
|
+
try {
|
|
47544
|
+
harness = deps.harnessFactory ? deps.harnessFactory(retryConfig) : new (await Promise.resolve().then(() => (init_harness(), harness_exports))).AgentHarness(retryConfig);
|
|
47545
|
+
const retry = await runSubAgent(harness, {
|
|
47546
|
+
...opts.signal ? { signal: opts.signal } : {},
|
|
47547
|
+
onEvent: onHarnessEvent
|
|
47548
|
+
});
|
|
47549
|
+
result = retry.result;
|
|
47550
|
+
error51 = retry.error;
|
|
47551
|
+
aborted2 = retry.aborted;
|
|
47552
|
+
usage = retry.usage;
|
|
47553
|
+
toolTrace = retry.toolTrace;
|
|
47554
|
+
sub = { ...sub, model: sub.fallback.model, provider: sub.fallback.provider };
|
|
47555
|
+
} catch (err) {
|
|
47556
|
+
error51 = err instanceof Error ? err.message : String(err);
|
|
47557
|
+
}
|
|
46906
47558
|
}
|
|
46907
47559
|
}
|
|
47560
|
+
} finally {
|
|
47561
|
+
stopHeartbeat();
|
|
46908
47562
|
}
|
|
46909
47563
|
const durationMs = Date.now() - started;
|
|
46910
47564
|
if (aborted2) {
|
|
@@ -46914,7 +47568,7 @@ ${taskUserContent}`,
|
|
|
46914
47568
|
agent,
|
|
46915
47569
|
thoroughness,
|
|
46916
47570
|
description: args.description,
|
|
46917
|
-
detail: "cancelled
|
|
47571
|
+
detail: "cancelled by parent",
|
|
46918
47572
|
model: sub.model,
|
|
46919
47573
|
worktree: worktree?.path ?? null,
|
|
46920
47574
|
durationMs,
|
|
@@ -46926,7 +47580,7 @@ ${taskUserContent}`,
|
|
|
46926
47580
|
detail: "cancelled",
|
|
46927
47581
|
durationMs
|
|
46928
47582
|
});
|
|
46929
|
-
return { ok: false, agent, error: "task: sub-agent cancelled
|
|
47583
|
+
return { ok: false, agent, error: "task: sub-agent cancelled by parent", cancelled: true };
|
|
46930
47584
|
}
|
|
46931
47585
|
if (!result) {
|
|
46932
47586
|
if (worktree) await cleanupKrakenWorktree(worktree);
|
|
@@ -47204,6 +47858,7 @@ var init_taskTool = __esm({
|
|
|
47204
47858
|
init_verifyReport();
|
|
47205
47859
|
init_metrics2();
|
|
47206
47860
|
init_dist();
|
|
47861
|
+
init_tentacleHeartbeat();
|
|
47207
47862
|
TASK_TOOL_TIMEOUT_MS = 27e5;
|
|
47208
47863
|
EXPLORE_PROMPT = [
|
|
47209
47864
|
"You are a focused EXPLORE tentacle of Kraken (parent super-agent).",
|
|
@@ -49136,7 +49791,7 @@ var init_planTaskTools = __esm({
|
|
|
49136
49791
|
});
|
|
49137
49792
|
|
|
49138
49793
|
// src/cli/tools/inspectTypecheckSafety.ts
|
|
49139
|
-
import { promises as
|
|
49794
|
+
import { promises as fs21 } from "node:fs";
|
|
49140
49795
|
import path49 from "node:path";
|
|
49141
49796
|
import { spawn as spawn9 } from "node:child_process";
|
|
49142
49797
|
async function scanTsbuildinfo(root) {
|
|
@@ -49146,7 +49801,7 @@ async function scanTsbuildinfo(root) {
|
|
|
49146
49801
|
const dir = stack.pop();
|
|
49147
49802
|
let entries;
|
|
49148
49803
|
try {
|
|
49149
|
-
entries = await
|
|
49804
|
+
entries = await fs21.readdir(dir, { withFileTypes: true });
|
|
49150
49805
|
} catch {
|
|
49151
49806
|
continue;
|
|
49152
49807
|
}
|
|
@@ -49191,7 +49846,7 @@ async function cleanupArtifacts(root, relPaths) {
|
|
|
49191
49846
|
const failed = [];
|
|
49192
49847
|
for (const rel2 of relPaths) {
|
|
49193
49848
|
try {
|
|
49194
|
-
await
|
|
49849
|
+
await fs21.unlink(path49.join(root, rel2));
|
|
49195
49850
|
cleaned.push(rel2);
|
|
49196
49851
|
} catch {
|
|
49197
49852
|
failed.push(rel2);
|
|
@@ -49215,8 +49870,8 @@ var init_inspectTypecheckSafety = __esm({
|
|
|
49215
49870
|
|
|
49216
49871
|
// src/cli/tools/inspectCommand.ts
|
|
49217
49872
|
import { spawn as spawn10 } from "node:child_process";
|
|
49218
|
-
import { createHash as
|
|
49219
|
-
import { existsSync as existsSync28, promises as
|
|
49873
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
49874
|
+
import { existsSync as existsSync28, promises as fs22 } from "node:fs";
|
|
49220
49875
|
import os2 from "node:os";
|
|
49221
49876
|
import path50 from "node:path";
|
|
49222
49877
|
function resolveNodeModuleBin(start, rel2) {
|
|
@@ -49302,7 +49957,7 @@ function buildInspectCommand(op, ctx) {
|
|
|
49302
49957
|
}
|
|
49303
49958
|
case "typecheck": {
|
|
49304
49959
|
const project = path50.resolve(ctx.cwd, op.project ?? "tsconfig.json");
|
|
49305
|
-
const hash3 =
|
|
49960
|
+
const hash3 = createHash14("sha256").update(project).digest("hex").slice(0, 16);
|
|
49306
49961
|
const tsBuildInfoFile = path50.join(os2.tmpdir(), "zelari-inspect", `${hash3}.tsbuildinfo`);
|
|
49307
49962
|
return {
|
|
49308
49963
|
ok: true,
|
|
@@ -49441,7 +50096,7 @@ function createInspectCommandTool(rootOrDeps) {
|
|
|
49441
50096
|
if (op.operation === "typecheck") {
|
|
49442
50097
|
const tsc = built.argv[0];
|
|
49443
50098
|
try {
|
|
49444
|
-
await
|
|
50099
|
+
await fs22.access(tsc);
|
|
49445
50100
|
} catch {
|
|
49446
50101
|
return typedErr(
|
|
49447
50102
|
`TYPESCRIPT_UNAVAILABLE: no TypeScript compiler at ${tsc} \u2014 inspect_command typecheck uses the project toolchain (walk-up to node_modules/typescript/bin/tsc) and refuses to guess. Install dependencies or fall back to read_file/grep_content.`
|
|
@@ -50837,11 +51492,11 @@ var init_store2 = __esm({
|
|
|
50837
51492
|
});
|
|
50838
51493
|
|
|
50839
51494
|
// src/cli/semantic/index.ts
|
|
50840
|
-
import { promises as
|
|
51495
|
+
import { promises as fs23, existsSync as existsSync29, readFileSync as readFileSync21 } from "node:fs";
|
|
50841
51496
|
import path53 from "node:path";
|
|
50842
|
-
import { createHash as
|
|
51497
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
50843
51498
|
function getIndexPath(root) {
|
|
50844
|
-
const hash3 =
|
|
51499
|
+
const hash3 = createHash15("sha1").update(path53.resolve(root)).digest("hex").slice(0, 16);
|
|
50845
51500
|
return process.env.ZELARI_SEMANTIC_FILE ?? path53.join(semanticStateDir(), `${hash3}.json`);
|
|
50846
51501
|
}
|
|
50847
51502
|
async function collectSourceFiles(root, maxFiles = 1500) {
|
|
@@ -50850,7 +51505,7 @@ async function collectSourceFiles(root, maxFiles = 1500) {
|
|
|
50850
51505
|
if (out.length >= maxFiles) return;
|
|
50851
51506
|
let entries;
|
|
50852
51507
|
try {
|
|
50853
|
-
entries = await
|
|
51508
|
+
entries = await fs23.readdir(dir, { withFileTypes: true });
|
|
50854
51509
|
} catch {
|
|
50855
51510
|
return;
|
|
50856
51511
|
}
|
|
@@ -50880,7 +51535,7 @@ async function buildIndex(files, embed, options) {
|
|
|
50880
51535
|
for (const file2 of files) {
|
|
50881
51536
|
let text;
|
|
50882
51537
|
try {
|
|
50883
|
-
text = await
|
|
51538
|
+
text = await fs23.readFile(file2, "utf8");
|
|
50884
51539
|
} catch {
|
|
50885
51540
|
continue;
|
|
50886
51541
|
}
|
|
@@ -50913,10 +51568,10 @@ async function buildIndex(files, embed, options) {
|
|
|
50913
51568
|
}
|
|
50914
51569
|
async function saveIndex(root, data) {
|
|
50915
51570
|
const file2 = getIndexPath(root);
|
|
50916
|
-
await
|
|
51571
|
+
await fs23.mkdir(path53.dirname(file2), { recursive: true });
|
|
50917
51572
|
const tmp = `${file2}.tmp-${process.pid}`;
|
|
50918
|
-
await
|
|
50919
|
-
await
|
|
51573
|
+
await fs23.writeFile(tmp, JSON.stringify(data), "utf8");
|
|
51574
|
+
await fs23.rename(tmp, file2);
|
|
50920
51575
|
}
|
|
50921
51576
|
function loadIndex(root) {
|
|
50922
51577
|
const file2 = getIndexPath(root);
|
|
@@ -52177,13 +52832,13 @@ var init_tools5 = __esm({
|
|
|
52177
52832
|
});
|
|
52178
52833
|
|
|
52179
52834
|
// src/cli/tools/screenshotTool.ts
|
|
52180
|
-
import { execFile as
|
|
52835
|
+
import { execFile as execFile6 } from "node:child_process";
|
|
52181
52836
|
import { mkdir as mkdir3, readFile as readFile8, stat as stat7 } from "node:fs/promises";
|
|
52182
52837
|
import path57 from "node:path";
|
|
52183
|
-
import { promisify as
|
|
52838
|
+
import { promisify as promisify5 } from "node:util";
|
|
52184
52839
|
async function captureWindows(target) {
|
|
52185
52840
|
const script = `Add-Type -AssemblyName System.Windows.Forms,System.Drawing;$b=[System.Windows.Forms.SystemInformation]::VirtualScreen;$bmp=New-Object System.Drawing.Bitmap $b.Width,$b.Height;$g=[System.Drawing.Graphics]::FromImage($bmp);$g.CopyFromScreen($b.Left,$b.Top,0,0,$bmp.Size);$g.Dispose(); $bmp.Save('${target.replace(/'/g, "''")}'); $bmp.Dispose();`;
|
|
52186
|
-
await
|
|
52841
|
+
await execFileAsync5("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
52187
52842
|
timeout: 12e3,
|
|
52188
52843
|
windowsHide: true
|
|
52189
52844
|
});
|
|
@@ -52197,7 +52852,7 @@ async function captureUnixLike(target) {
|
|
|
52197
52852
|
let lastErr = null;
|
|
52198
52853
|
for (const [bin, args] of attempts) {
|
|
52199
52854
|
try {
|
|
52200
|
-
await
|
|
52855
|
+
await execFileAsync5(bin, args, { timeout: 12e3 });
|
|
52201
52856
|
return;
|
|
52202
52857
|
} catch (e) {
|
|
52203
52858
|
lastErr = e;
|
|
@@ -52251,13 +52906,13 @@ function createScreenshotTool(deps = {}) {
|
|
|
52251
52906
|
}
|
|
52252
52907
|
};
|
|
52253
52908
|
}
|
|
52254
|
-
var
|
|
52909
|
+
var execFileAsync5, SCREENSHOT_MAX_BYTES2;
|
|
52255
52910
|
var init_screenshotTool = __esm({
|
|
52256
52911
|
"src/cli/tools/screenshotTool.ts"() {
|
|
52257
52912
|
"use strict";
|
|
52258
52913
|
init_zod();
|
|
52259
52914
|
init_toolTypes();
|
|
52260
|
-
|
|
52915
|
+
execFileAsync5 = promisify5(execFile6);
|
|
52261
52916
|
SCREENSHOT_MAX_BYTES2 = 8 * 1024 * 1024;
|
|
52262
52917
|
}
|
|
52263
52918
|
});
|
|
@@ -53580,6 +54235,163 @@ var init_resolveStream = __esm({
|
|
|
53580
54235
|
}
|
|
53581
54236
|
});
|
|
53582
54237
|
|
|
54238
|
+
// src/cli/providerFailover.ts
|
|
54239
|
+
function providerFailover(options) {
|
|
54240
|
+
const isTransient = options.isTransientFailure ?? DEFAULT_IS_TRANSIENT;
|
|
54241
|
+
const primaryFailedMsg = options.fallbackLabel ? `[failover] primary failed, switching to ${options.fallbackLabel}` : "[failover] primary failed, switching to fallback";
|
|
54242
|
+
const primaryThrewMsg = options.fallbackLabel ? `[failover] primary threw, switching to ${options.fallbackLabel}: ` : "[failover] primary threw: ";
|
|
54243
|
+
const fallbackFailedMsg = options.fallbackLabel ? `[failover] fallback (${options.fallbackLabel}) also failed: ` : "[failover] fallback also failed: ";
|
|
54244
|
+
const notify = (phase2, message) => {
|
|
54245
|
+
if (!options.onFailover) return;
|
|
54246
|
+
try {
|
|
54247
|
+
options.onFailover({
|
|
54248
|
+
phase: phase2,
|
|
54249
|
+
message,
|
|
54250
|
+
...options.fallbackLabel ? { label: options.fallbackLabel } : {}
|
|
54251
|
+
});
|
|
54252
|
+
} catch {
|
|
54253
|
+
}
|
|
54254
|
+
};
|
|
54255
|
+
return async function* (params) {
|
|
54256
|
+
const triedFallback = { value: false };
|
|
54257
|
+
try {
|
|
54258
|
+
for await (const delta of options.primary(params)) {
|
|
54259
|
+
if (isTransient(delta)) {
|
|
54260
|
+
yield delta;
|
|
54261
|
+
triedFallback.value = true;
|
|
54262
|
+
yield {
|
|
54263
|
+
kind: "error",
|
|
54264
|
+
message: primaryFailedMsg
|
|
54265
|
+
};
|
|
54266
|
+
notify("swap-delta", primaryFailedMsg);
|
|
54267
|
+
break;
|
|
54268
|
+
}
|
|
54269
|
+
yield delta;
|
|
54270
|
+
}
|
|
54271
|
+
} catch (err) {
|
|
54272
|
+
triedFallback.value = true;
|
|
54273
|
+
const threwMsg = `${primaryThrewMsg}${err instanceof Error ? err.message : String(err)}`;
|
|
54274
|
+
yield {
|
|
54275
|
+
kind: "error",
|
|
54276
|
+
message: threwMsg
|
|
54277
|
+
};
|
|
54278
|
+
notify("swap-throw", threwMsg);
|
|
54279
|
+
}
|
|
54280
|
+
if (triedFallback.value) {
|
|
54281
|
+
try {
|
|
54282
|
+
for await (const delta of options.fallback(params)) {
|
|
54283
|
+
yield delta;
|
|
54284
|
+
}
|
|
54285
|
+
} catch (err) {
|
|
54286
|
+
const failedMsg = `${fallbackFailedMsg}${err instanceof Error ? err.message : String(err)}`;
|
|
54287
|
+
yield {
|
|
54288
|
+
kind: "error",
|
|
54289
|
+
message: failedMsg
|
|
54290
|
+
};
|
|
54291
|
+
notify("fallback-failed", failedMsg);
|
|
54292
|
+
return;
|
|
54293
|
+
}
|
|
54294
|
+
}
|
|
54295
|
+
};
|
|
54296
|
+
}
|
|
54297
|
+
var DEFAULT_IS_TRANSIENT;
|
|
54298
|
+
var init_providerFailover = __esm({
|
|
54299
|
+
"src/cli/providerFailover.ts"() {
|
|
54300
|
+
"use strict";
|
|
54301
|
+
DEFAULT_IS_TRANSIENT = (delta) => delta.kind === "error";
|
|
54302
|
+
}
|
|
54303
|
+
});
|
|
54304
|
+
|
|
54305
|
+
// src/cli/crossProviderFailover.ts
|
|
54306
|
+
var crossProviderFailover_exports = {};
|
|
54307
|
+
__export(crossProviderFailover_exports, {
|
|
54308
|
+
isHeadlessFailoverEnabled: () => isHeadlessFailoverEnabled,
|
|
54309
|
+
resolveFailoverStream: () => resolveFailoverStream,
|
|
54310
|
+
wrapWithHeadlessFailover: () => wrapWithHeadlessFailover
|
|
54311
|
+
});
|
|
54312
|
+
async function resolveFailoverStream(options) {
|
|
54313
|
+
if (!options.failoverEnabled) {
|
|
54314
|
+
return {
|
|
54315
|
+
fallback: options.primary,
|
|
54316
|
+
fallbackLabel: void 0,
|
|
54317
|
+
warning: "",
|
|
54318
|
+
reason: "disabled"
|
|
54319
|
+
};
|
|
54320
|
+
}
|
|
54321
|
+
const requested = options.envValue?.trim();
|
|
54322
|
+
if (!requested || requested.length === 0) {
|
|
54323
|
+
return {
|
|
54324
|
+
fallback: options.primary,
|
|
54325
|
+
fallbackLabel: void 0,
|
|
54326
|
+
warning: "",
|
|
54327
|
+
reason: "unset"
|
|
54328
|
+
};
|
|
54329
|
+
}
|
|
54330
|
+
const valid = new Set(options.validProviderIds);
|
|
54331
|
+
if (!valid.has(requested)) {
|
|
54332
|
+
return {
|
|
54333
|
+
fallback: options.primary,
|
|
54334
|
+
fallbackLabel: void 0,
|
|
54335
|
+
warning: `[failover] ANATHEMA_FAILOVER_PROVIDER="${requested}" is not a known provider. Falling back to v3-G same-provider behavior. Available: ${options.validProviderIds.join(", ")}.`,
|
|
54336
|
+
reason: "unknown"
|
|
54337
|
+
};
|
|
54338
|
+
}
|
|
54339
|
+
if (requested === options.primaryProviderId) {
|
|
54340
|
+
return {
|
|
54341
|
+
fallback: options.primary,
|
|
54342
|
+
fallbackLabel: void 0,
|
|
54343
|
+
warning: "",
|
|
54344
|
+
reason: "same-as-primary"
|
|
54345
|
+
};
|
|
54346
|
+
}
|
|
54347
|
+
const fallbackConfig = await options.lookupFallbackConfig(requested);
|
|
54348
|
+
if (!fallbackConfig) {
|
|
54349
|
+
return {
|
|
54350
|
+
fallback: options.primary,
|
|
54351
|
+
fallbackLabel: void 0,
|
|
54352
|
+
warning: `[failover] No API key configured for provider "${requested}". Falling back to v3-G same-provider behavior.`,
|
|
54353
|
+
reason: "missing-key"
|
|
54354
|
+
};
|
|
54355
|
+
}
|
|
54356
|
+
return {
|
|
54357
|
+
fallback: options.buildStream(fallbackConfig),
|
|
54358
|
+
fallbackLabel: requested,
|
|
54359
|
+
warning: "",
|
|
54360
|
+
reason: "resolved"
|
|
54361
|
+
};
|
|
54362
|
+
}
|
|
54363
|
+
function isHeadlessFailoverEnabled(env = process.env) {
|
|
54364
|
+
return env.ZELARI_HEADLESS_FAILOVER === "1" && env.ANATHEMA_FAILOVER !== "0";
|
|
54365
|
+
}
|
|
54366
|
+
async function wrapWithHeadlessFailover(options) {
|
|
54367
|
+
const env = options.env ?? process.env;
|
|
54368
|
+
if (!isHeadlessFailoverEnabled(env)) {
|
|
54369
|
+
return options.primary;
|
|
54370
|
+
}
|
|
54371
|
+
const resolved = await resolveFailoverStream({
|
|
54372
|
+
failoverEnabled: true,
|
|
54373
|
+
envValue: env.ANATHEMA_FAILOVER_PROVIDER,
|
|
54374
|
+
primaryProviderId: options.primaryProviderId,
|
|
54375
|
+
primary: options.primary,
|
|
54376
|
+
validProviderIds: options.validProviderIds,
|
|
54377
|
+
lookupFallbackConfig: options.lookupFallbackConfig,
|
|
54378
|
+
buildStream: options.buildStream
|
|
54379
|
+
});
|
|
54380
|
+
if (resolved.warning) options.onWarning?.(resolved.warning);
|
|
54381
|
+
return providerFailover({
|
|
54382
|
+
primary: options.primary,
|
|
54383
|
+
fallback: resolved.fallback,
|
|
54384
|
+
...resolved.fallbackLabel ? { fallbackLabel: resolved.fallbackLabel } : {},
|
|
54385
|
+
...options.onFailover ? { onFailover: options.onFailover } : {}
|
|
54386
|
+
});
|
|
54387
|
+
}
|
|
54388
|
+
var init_crossProviderFailover = __esm({
|
|
54389
|
+
"src/cli/crossProviderFailover.ts"() {
|
|
54390
|
+
"use strict";
|
|
54391
|
+
init_providerFailover();
|
|
54392
|
+
}
|
|
54393
|
+
});
|
|
54394
|
+
|
|
53583
54395
|
// src/cli/safety/toolPermissions.ts
|
|
53584
54396
|
var toolPermissions_exports = {};
|
|
53585
54397
|
__export(toolPermissions_exports, {
|
|
@@ -53766,7 +54578,7 @@ function recordNonUserContent(source2, text, tool) {
|
|
|
53766
54578
|
const excerpt = normalize5(raw).slice(0, MAX_EXCERPT);
|
|
53767
54579
|
if (excerpt.length < PROVENANCE_MIN_MATCH * 2) return;
|
|
53768
54580
|
ring.push({ source: source2, tool, excerpt, at: Date.now() });
|
|
53769
|
-
if (ring.length >
|
|
54581
|
+
if (ring.length > MAX_ENTRIES2) ring.splice(0, ring.length - MAX_ENTRIES2);
|
|
53770
54582
|
} catch {
|
|
53771
54583
|
}
|
|
53772
54584
|
}
|
|
@@ -53822,11 +54634,11 @@ function safeJson2(v) {
|
|
|
53822
54634
|
return "";
|
|
53823
54635
|
}
|
|
53824
54636
|
}
|
|
53825
|
-
var
|
|
54637
|
+
var MAX_ENTRIES2, MAX_EXCERPT, PROVENANCE_MIN_MATCH, SHINGLE_STEP, MAX_SHINGLES, ring;
|
|
53826
54638
|
var init_provenance = __esm({
|
|
53827
54639
|
"src/cli/safety/provenance.ts"() {
|
|
53828
54640
|
"use strict";
|
|
53829
|
-
|
|
54641
|
+
MAX_ENTRIES2 = 40;
|
|
53830
54642
|
MAX_EXCERPT = 8192;
|
|
53831
54643
|
PROVENANCE_MIN_MATCH = 48;
|
|
53832
54644
|
SHINGLE_STEP = 24;
|
|
@@ -54019,7 +54831,7 @@ var init_lifecycleHooks = __esm({
|
|
|
54019
54831
|
});
|
|
54020
54832
|
|
|
54021
54833
|
// src/cli/safety/astGate.ts
|
|
54022
|
-
import { promises as
|
|
54834
|
+
import { promises as fs24 } from "node:fs";
|
|
54023
54835
|
import path59 from "node:path";
|
|
54024
54836
|
function astGateEnabled() {
|
|
54025
54837
|
return process.env.ZELARI_AST_GATE !== "0";
|
|
@@ -54069,7 +54881,7 @@ function wrapWithAstGate(original, opts) {
|
|
|
54069
54881
|
if (astGateEnabled()) gateTarget = containedPathOf(args);
|
|
54070
54882
|
if (gateTarget !== null && isAstSupported(gateTarget)) {
|
|
54071
54883
|
try {
|
|
54072
|
-
preContent = await
|
|
54884
|
+
preContent = await fs24.readFile(gateTarget, "utf8");
|
|
54073
54885
|
} catch (err) {
|
|
54074
54886
|
if (err?.code === "ENOENT") preContent = null;
|
|
54075
54887
|
}
|
|
@@ -54098,16 +54910,16 @@ function wrapWithAstGate(original, opts) {
|
|
|
54098
54910
|
);
|
|
54099
54911
|
return result;
|
|
54100
54912
|
}
|
|
54101
|
-
const post = await
|
|
54913
|
+
const post = await fs24.readFile(absPath, "utf8");
|
|
54102
54914
|
const syntaxError = firstSyntaxError(ts, path59.basename(absPath), post);
|
|
54103
54915
|
if (!syntaxError) return result;
|
|
54104
54916
|
const parseError = `${syntaxError.message} (line ${syntaxError.line}, col ${syntaxError.character})`;
|
|
54105
54917
|
let revertedTo;
|
|
54106
54918
|
if (preContent === null) {
|
|
54107
|
-
await
|
|
54919
|
+
await fs24.unlink(absPath).catch(() => void 0);
|
|
54108
54920
|
revertedTo = "absent";
|
|
54109
54921
|
} else {
|
|
54110
|
-
await
|
|
54922
|
+
await fs24.writeFile(absPath, preContent, "utf8");
|
|
54111
54923
|
revertedTo = snapshotIdOf(preContent);
|
|
54112
54924
|
}
|
|
54113
54925
|
const relLabel = path59.relative(opts.root, absPath) || path59.basename(absPath);
|
|
@@ -54533,8 +55345,8 @@ var init_resourceClaims = __esm({
|
|
|
54533
55345
|
});
|
|
54534
55346
|
|
|
54535
55347
|
// src/cli/toolResultCache.ts
|
|
54536
|
-
import { createHash as
|
|
54537
|
-
import { promises as
|
|
55348
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
55349
|
+
import { promises as fs25 } from "node:fs";
|
|
54538
55350
|
import path60 from "node:path";
|
|
54539
55351
|
function isToolCacheEnabled() {
|
|
54540
55352
|
const raw = process.env.ZELARI_TOOL_CACHE;
|
|
@@ -54546,7 +55358,7 @@ function resolveToolCacheTtlMs() {
|
|
|
54546
55358
|
return Number.isFinite(n) && n >= 0 ? n : TOOL_CACHE_DEFAULT_TTL_MS;
|
|
54547
55359
|
}
|
|
54548
55360
|
function hashKey(parts) {
|
|
54549
|
-
return
|
|
55361
|
+
return createHash16("sha256").update(JSON.stringify(parts), "utf8").digest("hex");
|
|
54550
55362
|
}
|
|
54551
55363
|
function resultBytes(result) {
|
|
54552
55364
|
try {
|
|
@@ -54622,7 +55434,7 @@ async function statKey(toolName, input, ctx) {
|
|
|
54622
55434
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
54623
55435
|
const abs = path60.isAbsolute(rawPath) ? rawPath : path60.join(ctx.cwd, rawPath);
|
|
54624
55436
|
try {
|
|
54625
|
-
const st = await
|
|
55437
|
+
const st = await fs25.stat(abs);
|
|
54626
55438
|
return hashKey({
|
|
54627
55439
|
tool: toolName,
|
|
54628
55440
|
args: input,
|
|
@@ -55047,9 +55859,11 @@ function createKrakenSubAgentContextFactory(opts) {
|
|
|
55047
55859
|
return async ({ agent, cwd: subCwd }) => {
|
|
55048
55860
|
const cfg = providerOverride ? await providerConfigFor(providerOverride) : await providerFromEnv();
|
|
55049
55861
|
if (!cfg) return null;
|
|
55050
|
-
const {
|
|
55862
|
+
const { resolveKrakenSubModelAsync: resolveKrakenSubModelAsync2, parseQualifiedModelRef: parseQualifiedModelRef2 } = await Promise.resolve().then(() => (init_krakenModel(), krakenModel_exports));
|
|
55051
55863
|
const parentModel = modelOverride || cfg.model;
|
|
55052
|
-
const resolvedModel =
|
|
55864
|
+
const resolvedModel = await resolveKrakenSubModelAsync2(agent, parentModel, process.env, {
|
|
55865
|
+
provider: cfg.providerId
|
|
55866
|
+
});
|
|
55053
55867
|
let effCfg = cfg;
|
|
55054
55868
|
let model = resolvedModel;
|
|
55055
55869
|
const ref = parseQualifiedModelRef2(resolvedModel);
|
|
@@ -55082,15 +55896,31 @@ function createKrakenSubAgentContextFactory(opts) {
|
|
|
55082
55896
|
// P0.5: the tentacle's agent identity drives per-agent policy rules.
|
|
55083
55897
|
policyAgent: agent
|
|
55084
55898
|
});
|
|
55899
|
+
const wrapTentacleStream = (primary, primaryProviderId) => wrapWithHeadlessFailover({
|
|
55900
|
+
primary,
|
|
55901
|
+
primaryProviderId,
|
|
55902
|
+
validProviderIds: PROVIDERS.map((p3) => p3.id),
|
|
55903
|
+
lookupFallbackConfig: (id3) => providerConfigFor(id3),
|
|
55904
|
+
buildStream: (config2) => buildProviderStream(config2)
|
|
55905
|
+
});
|
|
55906
|
+
const providerStream = await wrapTentacleStream(
|
|
55907
|
+
buildProviderStream(subCfg),
|
|
55908
|
+
subCfg.providerId
|
|
55909
|
+
);
|
|
55085
55910
|
return {
|
|
55086
|
-
providerStream
|
|
55911
|
+
providerStream,
|
|
55087
55912
|
model,
|
|
55088
55913
|
provider: subCfg.providerId,
|
|
55089
55914
|
...model !== parentModel ? {
|
|
55090
55915
|
fallback: {
|
|
55091
55916
|
model: parentModel,
|
|
55092
55917
|
provider: cfg.providerId,
|
|
55093
|
-
|
|
55918
|
+
// Wrap the 404-parent fallback too so a later model retry still
|
|
55919
|
+
// has transport failover. Orthogonal to isUnknownModelError.
|
|
55920
|
+
providerStream: await wrapTentacleStream(
|
|
55921
|
+
buildProviderStream({ ...cfg, model: parentModel }),
|
|
55922
|
+
cfg.providerId
|
|
55923
|
+
)
|
|
55094
55924
|
}
|
|
55095
55925
|
} : {},
|
|
55096
55926
|
registry: subRegistry,
|
|
@@ -55577,6 +56407,8 @@ var init_toolRegistry = __esm({
|
|
|
55577
56407
|
init_openai_compatible();
|
|
55578
56408
|
init_resolveStream();
|
|
55579
56409
|
init_providerConfig();
|
|
56410
|
+
init_crossProviderFailover();
|
|
56411
|
+
init_keyStore();
|
|
55580
56412
|
init_toolPermissions();
|
|
55581
56413
|
init_destructiveCommands();
|
|
55582
56414
|
init_provenance();
|
|
@@ -55617,12 +56449,12 @@ var init_toolRegistry = __esm({
|
|
|
55617
56449
|
});
|
|
55618
56450
|
|
|
55619
56451
|
// src/cli/metrics.ts
|
|
55620
|
-
import { promises as
|
|
56452
|
+
import { promises as fs26, existsSync as existsSync33, statSync as statSync4, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync15 } from "node:fs";
|
|
55621
56453
|
import path62 from "node:path";
|
|
55622
56454
|
async function readMetrics(file2) {
|
|
55623
56455
|
let raw = "";
|
|
55624
56456
|
try {
|
|
55625
|
-
raw = await
|
|
56457
|
+
raw = await fs26.readFile(file2, "utf-8");
|
|
55626
56458
|
} catch {
|
|
55627
56459
|
return [];
|
|
55628
56460
|
}
|
|
@@ -56000,8 +56832,8 @@ __export(completionProofProbe_exports, {
|
|
|
56000
56832
|
gatherGitAttestation: () => gatherGitAttestation,
|
|
56001
56833
|
harnessManifest: () => harnessManifest
|
|
56002
56834
|
});
|
|
56003
|
-
import { execFile as
|
|
56004
|
-
import { promisify as
|
|
56835
|
+
import { execFile as execFile7 } from "node:child_process";
|
|
56836
|
+
import { promisify as promisify6 } from "node:util";
|
|
56005
56837
|
async function readHarnessVersion() {
|
|
56006
56838
|
if (cachedHarnessVersion !== null) return cachedHarnessVersion;
|
|
56007
56839
|
try {
|
|
@@ -56032,7 +56864,7 @@ async function harnessManifest(env = process.env) {
|
|
|
56032
56864
|
}
|
|
56033
56865
|
async function git5(cwd, args) {
|
|
56034
56866
|
try {
|
|
56035
|
-
const { stdout } = await
|
|
56867
|
+
const { stdout } = await execFileAsync6("git", ["-C", cwd, ...args], {
|
|
56036
56868
|
maxBuffer: 32 * 1024 * 1024,
|
|
56037
56869
|
windowsHide: true
|
|
56038
56870
|
});
|
|
@@ -56074,7 +56906,7 @@ function activeTaskContractSnapshot() {
|
|
|
56074
56906
|
return void 0;
|
|
56075
56907
|
}
|
|
56076
56908
|
}
|
|
56077
|
-
var HARNESS_VERSION_FALLBACK, ADAPTER_IDS, cachedHarnessVersion,
|
|
56909
|
+
var HARNESS_VERSION_FALLBACK, ADAPTER_IDS, cachedHarnessVersion, execFileAsync6;
|
|
56078
56910
|
var init_completionProofProbe = __esm({
|
|
56079
56911
|
"src/cli/kraken/completionProofProbe.ts"() {
|
|
56080
56912
|
"use strict";
|
|
@@ -56082,14 +56914,14 @@ var init_completionProofProbe = __esm({
|
|
|
56082
56914
|
HARNESS_VERSION_FALLBACK = "2.13.0";
|
|
56083
56915
|
ADAPTER_IDS = ["node", "python", "rust", "go", "java", "dotnet"];
|
|
56084
56916
|
cachedHarnessVersion = null;
|
|
56085
|
-
|
|
56917
|
+
execFileAsync6 = promisify6(execFile7);
|
|
56086
56918
|
}
|
|
56087
56919
|
});
|
|
56088
56920
|
|
|
56089
56921
|
// src/cli/kraken/completionProofAttestation.ts
|
|
56090
|
-
import { createHash as
|
|
56922
|
+
import { createHash as createHash17 } from "node:crypto";
|
|
56091
56923
|
function sha256Hex3(data) {
|
|
56092
|
-
return
|
|
56924
|
+
return createHash17("sha256").update(data, "utf8").digest("hex");
|
|
56093
56925
|
}
|
|
56094
56926
|
function canonicalJson(value) {
|
|
56095
56927
|
return JSON.stringify(canonicalValue(value));
|
|
@@ -56549,21 +57381,21 @@ var init_askUserTimeout = __esm({
|
|
|
56549
57381
|
});
|
|
56550
57382
|
|
|
56551
57383
|
// src/cli/state/fileStateStore.ts
|
|
56552
|
-
import { createHash as
|
|
56553
|
-
import { promises as
|
|
57384
|
+
import { createHash as createHash18, randomUUID as randomUUID5 } from "node:crypto";
|
|
57385
|
+
import { promises as fs27 } from "node:fs";
|
|
56554
57386
|
import * as path65 from "node:path";
|
|
56555
57387
|
function shortId() {
|
|
56556
57388
|
return randomUUID5().replace(/-/g, "").slice(0, 12);
|
|
56557
57389
|
}
|
|
56558
57390
|
async function writeJsonAtomic(filePath, data) {
|
|
56559
|
-
await
|
|
57391
|
+
await fs27.mkdir(path65.dirname(filePath), { recursive: true });
|
|
56560
57392
|
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
56561
|
-
await
|
|
56562
|
-
await
|
|
57393
|
+
await fs27.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
57394
|
+
await fs27.rename(tmp, filePath);
|
|
56563
57395
|
}
|
|
56564
57396
|
async function readJsonFile(filePath) {
|
|
56565
57397
|
try {
|
|
56566
|
-
const raw = await
|
|
57398
|
+
const raw = await fs27.readFile(filePath, "utf8");
|
|
56567
57399
|
return JSON.parse(raw);
|
|
56568
57400
|
} catch {
|
|
56569
57401
|
return null;
|
|
@@ -56601,7 +57433,7 @@ async function getStateStore(projectRoot, env = process.env) {
|
|
|
56601
57433
|
}
|
|
56602
57434
|
}
|
|
56603
57435
|
function hashStablePrompt(stable) {
|
|
56604
|
-
return
|
|
57436
|
+
return createHash18("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
|
|
56605
57437
|
}
|
|
56606
57438
|
var DEFAULT_MATERIALIZE_CHARS, FileDurableStateStore, NoopDurableStateStore;
|
|
56607
57439
|
var init_fileStateStore = __esm({
|
|
@@ -56622,8 +57454,8 @@ var init_fileStateStore = __esm({
|
|
|
56622
57454
|
this.artifactsDir = path65.join(this.stateDir, "artifacts");
|
|
56623
57455
|
this.headPath = path65.join(this.stateDir, "HEAD.json");
|
|
56624
57456
|
this.indexPath = path65.join(this.stateDir, "index.jsonl");
|
|
56625
|
-
await
|
|
56626
|
-
await
|
|
57457
|
+
await fs27.mkdir(this.commitsDir, { recursive: true });
|
|
57458
|
+
await fs27.mkdir(this.artifactsDir, { recursive: true });
|
|
56627
57459
|
}
|
|
56628
57460
|
async commit(input) {
|
|
56629
57461
|
if (!input.force && input.verification.ran && !input.verification.ok) {
|
|
@@ -56636,9 +57468,9 @@ var init_fileStateStore = __esm({
|
|
|
56636
57468
|
const id3 = shortId();
|
|
56637
57469
|
const artifactRel = path65.join("artifacts", id3);
|
|
56638
57470
|
const artifactAbs = path65.join(this.artifactsDir, id3);
|
|
56639
|
-
await
|
|
57471
|
+
await fs27.mkdir(artifactAbs, { recursive: true });
|
|
56640
57472
|
const summary = defaultSummary(input, discoveries);
|
|
56641
|
-
await
|
|
57473
|
+
await fs27.writeFile(path65.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
|
|
56642
57474
|
await writeJsonAtomic(path65.join(artifactAbs, "discoveries.json"), discoveries);
|
|
56643
57475
|
await writeJsonAtomic(path65.join(artifactAbs, "verification.json"), input.verification);
|
|
56644
57476
|
const meta3 = {
|
|
@@ -56661,7 +57493,7 @@ var init_fileStateStore = __esm({
|
|
|
56661
57493
|
};
|
|
56662
57494
|
await writeJsonAtomic(path65.join(this.commitsDir, `${id3}.json`), meta3);
|
|
56663
57495
|
await writeJsonAtomic(this.headPath, { id: id3, updatedAt: meta3.createdAt });
|
|
56664
|
-
await
|
|
57496
|
+
await fs27.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
|
|
56665
57497
|
return stripStored(meta3);
|
|
56666
57498
|
}
|
|
56667
57499
|
async head() {
|
|
@@ -56676,7 +57508,7 @@ var init_fileStateStore = __esm({
|
|
|
56676
57508
|
async list(limit = 20) {
|
|
56677
57509
|
let raw;
|
|
56678
57510
|
try {
|
|
56679
|
-
raw = await
|
|
57511
|
+
raw = await fs27.readFile(this.indexPath, "utf8");
|
|
56680
57512
|
} catch {
|
|
56681
57513
|
return [];
|
|
56682
57514
|
}
|
|
@@ -57649,7 +58481,10 @@ async function countVerificationEvidenceInLog(mirror, sessionId2) {
|
|
|
57649
58481
|
if (mirror.status !== "active" && mirror.status !== "closed") return -1;
|
|
57650
58482
|
try {
|
|
57651
58483
|
await mirror.flush().catch(() => void 0);
|
|
57652
|
-
const report = await
|
|
58484
|
+
const report = await readSessionLogCached(
|
|
58485
|
+
path67.join(mirror.sessionsDir, sessionId2, "events.jsonl"),
|
|
58486
|
+
mirror.replayCache
|
|
58487
|
+
);
|
|
57653
58488
|
return report.events.filter((e) => e.kind === "verification.evidence").length;
|
|
57654
58489
|
} catch (err) {
|
|
57655
58490
|
process.stderr.write(
|
|
@@ -57682,7 +58517,7 @@ async function openHeadlessSpine(opts) {
|
|
|
57682
58517
|
if (spine.status === "active") {
|
|
57683
58518
|
const budget = new BudgetRuntime(profileId, { enforcement: resolveResourceEnforcement() });
|
|
57684
58519
|
if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
|
|
57685
|
-
await restoreBudgetRuntimeFromSession(budget, opts.sessionId, opts.baseDir);
|
|
58520
|
+
await restoreBudgetRuntimeFromSession(budget, opts.sessionId, opts.baseDir, spine.replayCache);
|
|
57686
58521
|
}
|
|
57687
58522
|
spine.attachBudgetRuntime(budget);
|
|
57688
58523
|
const manifestSpecs = opts.toolSpecs?.filter((spec) => profileTools.includes(spec.name));
|
|
@@ -58442,11 +59277,11 @@ var init_planDetect = __esm({
|
|
|
58442
59277
|
});
|
|
58443
59278
|
|
|
58444
59279
|
// src/cli/memory/legacyImport.ts
|
|
58445
|
-
import { createHash as
|
|
58446
|
-
import { promises as
|
|
59280
|
+
import { createHash as createHash19 } from "node:crypto";
|
|
59281
|
+
import { promises as fs28 } from "node:fs";
|
|
58447
59282
|
import * as path68 from "node:path";
|
|
58448
59283
|
function sourceId(fact, line) {
|
|
58449
|
-
return `jsonl:${fact.id ??
|
|
59284
|
+
return `jsonl:${fact.id ?? createHash19("sha256").update(line).digest("hex")}`;
|
|
58450
59285
|
}
|
|
58451
59286
|
function kind(metadata2) {
|
|
58452
59287
|
const raw = metadata2.memoryKind;
|
|
@@ -58460,15 +59295,38 @@ function timestamp(value) {
|
|
|
58460
59295
|
const parsed = Date.parse(value);
|
|
58461
59296
|
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : void 0;
|
|
58462
59297
|
}
|
|
59298
|
+
function isPermanentSkip(error51) {
|
|
59299
|
+
return error51 instanceof MemoryPolicyError || error51?.name === "ZodError";
|
|
59300
|
+
}
|
|
59301
|
+
async function isImportComplete(markerPath) {
|
|
59302
|
+
try {
|
|
59303
|
+
const marker = JSON.parse(await fs28.readFile(markerPath, "utf8"));
|
|
59304
|
+
return typeof marker?.found === "number" && typeof marker?.at === "string";
|
|
59305
|
+
} catch {
|
|
59306
|
+
return false;
|
|
59307
|
+
}
|
|
59308
|
+
}
|
|
59309
|
+
async function markImportComplete(markerPath, found) {
|
|
59310
|
+
const temporary = `${markerPath}.tmp`;
|
|
59311
|
+
try {
|
|
59312
|
+
await fs28.writeFile(temporary, `${JSON.stringify({ found, at: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
59313
|
+
`, "utf8");
|
|
59314
|
+
await fs28.rename(temporary, markerPath);
|
|
59315
|
+
} catch {
|
|
59316
|
+
}
|
|
59317
|
+
}
|
|
58463
59318
|
async function importLegacyMemoryLog(backend, service) {
|
|
58464
59319
|
const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
|
|
58465
|
-
const
|
|
59320
|
+
const memoryDir = path68.dirname(backend.databasePath);
|
|
59321
|
+
const markerPath = path68.join(memoryDir, LEGACY_IMPORT_MARKER);
|
|
59322
|
+
if (await isImportComplete(markerPath)) return result;
|
|
58466
59323
|
let raw;
|
|
58467
59324
|
try {
|
|
58468
|
-
raw = await
|
|
59325
|
+
raw = await fs28.readFile(path68.join(memoryDir, "log.jsonl"), "utf8");
|
|
58469
59326
|
} catch {
|
|
58470
59327
|
return result;
|
|
58471
59328
|
}
|
|
59329
|
+
const rows = [];
|
|
58472
59330
|
for (const line of raw.split(/\r?\n/)) {
|
|
58473
59331
|
const trimmed = line.trim();
|
|
58474
59332
|
if (!trimmed) continue;
|
|
@@ -58485,17 +59343,22 @@ async function importLegacyMemoryLog(backend, service) {
|
|
|
58485
59343
|
result.corrupt += 1;
|
|
58486
59344
|
continue;
|
|
58487
59345
|
}
|
|
58488
|
-
|
|
58489
|
-
|
|
59346
|
+
rows.push({ fact, content, importId: sourceId(fact, trimmed) });
|
|
59347
|
+
}
|
|
59348
|
+
const known = rows.length > 0 ? await backend.hasImports([...new Set(rows.map((row) => row.importId))]) : /* @__PURE__ */ new Set();
|
|
59349
|
+
const importedHere = /* @__PURE__ */ new Set();
|
|
59350
|
+
let unresolved = 0;
|
|
59351
|
+
for (const row of rows) {
|
|
59352
|
+
if (known.has(row.importId) || importedHere.has(row.importId)) {
|
|
58490
59353
|
result.skipped += 1;
|
|
58491
59354
|
continue;
|
|
58492
59355
|
}
|
|
58493
|
-
const metadata2 = fact.metadata && typeof fact.metadata === "object" ? fact.metadata : {};
|
|
58494
|
-
const createdAt = timestamp(fact.createdAt);
|
|
59356
|
+
const metadata2 = row.fact.metadata && typeof row.fact.metadata === "object" ? row.fact.metadata : {};
|
|
59357
|
+
const createdAt = timestamp(row.fact.createdAt);
|
|
58495
59358
|
try {
|
|
58496
59359
|
const node = await service.remember({
|
|
58497
59360
|
kind: kind(metadata2),
|
|
58498
|
-
content,
|
|
59361
|
+
content: row.content,
|
|
58499
59362
|
importance: typeof metadata2.importance === "number" ? metadata2.importance : 0.55,
|
|
58500
59363
|
confidence: typeof metadata2.confidence === "number" ? metadata2.confidence : 0.65,
|
|
58501
59364
|
source: {
|
|
@@ -58507,24 +59370,30 @@ async function importLegacyMemoryLog(backend, service) {
|
|
|
58507
59370
|
...createdAt ? { createdAt, recordedAt: createdAt } : {},
|
|
58508
59371
|
metadata: {
|
|
58509
59372
|
...metadata2,
|
|
58510
|
-
legacyId: fact.id,
|
|
58511
|
-
legacyCreatedAt: fact.createdAt,
|
|
58512
|
-
...fact.graph ? { legacyGraph: fact.graph } : {}
|
|
59373
|
+
legacyId: row.fact.id,
|
|
59374
|
+
legacyCreatedAt: row.fact.createdAt,
|
|
59375
|
+
...row.fact.graph ? { legacyGraph: row.fact.graph } : {}
|
|
58513
59376
|
},
|
|
58514
59377
|
writeClass: "auto"
|
|
58515
59378
|
});
|
|
58516
|
-
await backend.recordImport(importId, node.id);
|
|
59379
|
+
await backend.recordImport(row.importId, node.id);
|
|
59380
|
+
importedHere.add(row.importId);
|
|
58517
59381
|
result.imported += 1;
|
|
58518
|
-
} catch {
|
|
59382
|
+
} catch (error51) {
|
|
58519
59383
|
result.skipped += 1;
|
|
59384
|
+
if (!isPermanentSkip(error51)) unresolved += 1;
|
|
58520
59385
|
}
|
|
58521
59386
|
}
|
|
59387
|
+
const everyRowResolved = result.imported + result.skipped + result.corrupt === result.found;
|
|
59388
|
+
if (everyRowResolved && unresolved === 0) await markImportComplete(markerPath, result.found);
|
|
58522
59389
|
return result;
|
|
58523
59390
|
}
|
|
59391
|
+
var LEGACY_IMPORT_MARKER;
|
|
58524
59392
|
var init_legacyImport = __esm({
|
|
58525
59393
|
"src/cli/memory/legacyImport.ts"() {
|
|
58526
59394
|
"use strict";
|
|
58527
59395
|
init_memory();
|
|
59396
|
+
LEGACY_IMPORT_MARKER = "legacy-import-done.json";
|
|
58528
59397
|
}
|
|
58529
59398
|
});
|
|
58530
59399
|
|
|
@@ -58944,8 +59813,8 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
|
|
|
58944
59813
|
});
|
|
58945
59814
|
|
|
58946
59815
|
// src/cli/memory/sqliteBackend.ts
|
|
58947
|
-
import { createHash as
|
|
58948
|
-
import { promises as
|
|
59816
|
+
import { createHash as createHash20, randomUUID as randomUUID6 } from "node:crypto";
|
|
59817
|
+
import { promises as fs29 } from "node:fs";
|
|
58949
59818
|
import * as path70 from "node:path";
|
|
58950
59819
|
function boundedLimit(value, fallback = 50) {
|
|
58951
59820
|
return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
|
|
@@ -58959,9 +59828,9 @@ function withOptional(target, key, value) {
|
|
|
58959
59828
|
return { ...target, [key]: value };
|
|
58960
59829
|
}
|
|
58961
59830
|
function contentHash(content) {
|
|
58962
|
-
return
|
|
59831
|
+
return createHash20("sha256").update(content).digest("hex");
|
|
58963
59832
|
}
|
|
58964
|
-
var NODE_COLUMNS, INSERT_NODE_SQL, SOURCE_COLUMNS, SQLiteMemoryBackend;
|
|
59833
|
+
var NODE_COLUMNS, INSERT_NODE_SQL, IMPORT_ID_CHUNK, SOURCE_COLUMNS, SQLiteMemoryBackend;
|
|
58965
59834
|
var init_sqliteBackend = __esm({
|
|
58966
59835
|
"src/cli/memory/sqliteBackend.ts"() {
|
|
58967
59836
|
"use strict";
|
|
@@ -58975,6 +59844,7 @@ var init_sqliteBackend = __esm({
|
|
|
58975
59844
|
valid_until, recorded_at, retracted_at, embedding_ref, metadata_json`;
|
|
58976
59845
|
INSERT_NODE_SQL = `INSERT INTO memory_nodes (${NODE_COLUMNS})
|
|
58977
59846
|
VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
|
|
59847
|
+
IMPORT_ID_CHUNK = 500;
|
|
58978
59848
|
SOURCE_COLUMNS = {
|
|
58979
59849
|
agent: "agent",
|
|
58980
59850
|
sessionId: "sessionId",
|
|
@@ -59006,7 +59876,7 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
|
|
|
59006
59876
|
async init(projectRoot) {
|
|
59007
59877
|
let resolved;
|
|
59008
59878
|
try {
|
|
59009
|
-
resolved = await
|
|
59879
|
+
resolved = await fs29.realpath(projectRoot);
|
|
59010
59880
|
} catch {
|
|
59011
59881
|
resolved = path70.resolve(projectRoot);
|
|
59012
59882
|
}
|
|
@@ -59021,21 +59891,21 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
|
|
|
59021
59891
|
for (const candidate of [zelariDirectory, directory]) {
|
|
59022
59892
|
let stat8;
|
|
59023
59893
|
try {
|
|
59024
|
-
stat8 = await
|
|
59894
|
+
stat8 = await fs29.lstat(candidate);
|
|
59025
59895
|
} catch (error51) {
|
|
59026
59896
|
if (error51.code !== "ENOENT") throw error51;
|
|
59027
59897
|
try {
|
|
59028
|
-
await
|
|
59898
|
+
await fs29.mkdir(candidate);
|
|
59029
59899
|
} catch (mkdirError) {
|
|
59030
59900
|
if (mkdirError.code !== "EEXIST") throw mkdirError;
|
|
59031
59901
|
}
|
|
59032
|
-
stat8 = await
|
|
59902
|
+
stat8 = await fs29.lstat(candidate);
|
|
59033
59903
|
}
|
|
59034
59904
|
if (stat8.isSymbolicLink() || !stat8.isDirectory()) {
|
|
59035
59905
|
throw new Error(`Memory directory is not a real directory: ${candidate}`);
|
|
59036
59906
|
}
|
|
59037
59907
|
}
|
|
59038
|
-
const canonicalDirectory = await
|
|
59908
|
+
const canonicalDirectory = await fs29.realpath(directory);
|
|
59039
59909
|
const relativeDirectory = path70.relative(resolved, canonicalDirectory);
|
|
59040
59910
|
if (relativeDirectory.startsWith("..") || path70.isAbsolute(relativeDirectory)) {
|
|
59041
59911
|
throw new Error("SQLite memory directory resolves outside the active project.");
|
|
@@ -59538,14 +60408,24 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
|
|
|
59538
60408
|
versions: versionRows.map(decodeVersion).filter((version2) => Boolean(version2))
|
|
59539
60409
|
};
|
|
59540
60410
|
}
|
|
59541
|
-
|
|
60411
|
+
/** Batched `hasImport`: one `IN` query per 500 ids instead of one RPC per row. */
|
|
60412
|
+
async hasImports(ids) {
|
|
59542
60413
|
this.assertReady();
|
|
59543
|
-
const
|
|
59544
|
-
|
|
59545
|
-
|
|
59546
|
-
|
|
59547
|
-
|
|
59548
|
-
|
|
60414
|
+
const found = /* @__PURE__ */ new Set();
|
|
60415
|
+
const unique = [...new Set(ids)];
|
|
60416
|
+
for (let index = 0; index < unique.length; index += IMPORT_ID_CHUNK) {
|
|
60417
|
+
const chunk = unique.slice(index, index + IMPORT_ID_CHUNK);
|
|
60418
|
+
const rows = await this.rpc.statement({
|
|
60419
|
+
sql: `SELECT source_id FROM memory_imports WHERE source_id IN (${chunk.map(() => "?").join(",")})`,
|
|
60420
|
+
params: chunk,
|
|
60421
|
+
mode: "all"
|
|
60422
|
+
});
|
|
60423
|
+
for (const row of rows) found.add(String(row.source_id));
|
|
60424
|
+
}
|
|
60425
|
+
return found;
|
|
60426
|
+
}
|
|
60427
|
+
async hasImport(sourceId2) {
|
|
60428
|
+
return (await this.hasImports([sourceId2])).has(sourceId2);
|
|
59549
60429
|
}
|
|
59550
60430
|
async recordImport(sourceId2, memoryId) {
|
|
59551
60431
|
this.assertReady();
|
|
@@ -59572,8 +60452,8 @@ __export(serviceFactory_exports, {
|
|
|
59572
60452
|
isMemorySemanticEnabled: () => isMemorySemanticEnabled,
|
|
59573
60453
|
isMemoryV2Enabled: () => isMemoryV2Enabled
|
|
59574
60454
|
});
|
|
59575
|
-
import { createHash as
|
|
59576
|
-
import { promises as
|
|
60455
|
+
import { createHash as createHash21 } from "node:crypto";
|
|
60456
|
+
import { promises as fs30 } from "node:fs";
|
|
59577
60457
|
import * as path71 from "node:path";
|
|
59578
60458
|
function isMemoryV2Enabled(env = process.env) {
|
|
59579
60459
|
if (env.ZELARI_MEMORY === "0") return false;
|
|
@@ -59593,13 +60473,13 @@ function semanticMinScore(env) {
|
|
|
59593
60473
|
async function canonicalProjectId(projectRoot) {
|
|
59594
60474
|
let canonical;
|
|
59595
60475
|
try {
|
|
59596
|
-
canonical = await
|
|
60476
|
+
canonical = await fs30.realpath(projectRoot);
|
|
59597
60477
|
} catch {
|
|
59598
60478
|
canonical = path71.resolve(projectRoot);
|
|
59599
60479
|
}
|
|
59600
60480
|
canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
|
|
59601
60481
|
if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
|
|
59602
|
-
return `project_${
|
|
60482
|
+
return `project_${createHash21("sha256").update(canonical).digest("hex").slice(0, 24)}`;
|
|
59603
60483
|
}
|
|
59604
60484
|
async function getMemoryService(projectRoot, env = process.env, options = {}) {
|
|
59605
60485
|
const projectId2 = await canonicalProjectId(projectRoot);
|
|
@@ -60222,32 +61102,32 @@ __export(loadDurableContext_exports, {
|
|
|
60222
61102
|
loadDurableContext: () => loadDurableContext
|
|
60223
61103
|
});
|
|
60224
61104
|
function clearDurableContextCache() {
|
|
60225
|
-
|
|
61105
|
+
cache3 = null;
|
|
60226
61106
|
}
|
|
60227
61107
|
async function loadDurableContext(projectRoot, opts) {
|
|
60228
61108
|
const env = opts?.env ?? process.env;
|
|
60229
61109
|
if (!isStateEnabled(env)) return "";
|
|
60230
61110
|
const cacheMs = opts?.cacheMs ?? DEFAULT_CACHE_MS;
|
|
60231
61111
|
const now = Date.now();
|
|
60232
|
-
if (
|
|
60233
|
-
return
|
|
61112
|
+
if (cache3 && cache3.projectRoot === projectRoot && now - cache3.at < cacheMs) {
|
|
61113
|
+
return cache3.text;
|
|
60234
61114
|
}
|
|
60235
61115
|
try {
|
|
60236
61116
|
const store6 = await getStateStore(projectRoot, env);
|
|
60237
61117
|
const text = await store6.materializeContext(void 0, opts?.maxChars);
|
|
60238
|
-
|
|
60239
|
-
return
|
|
61118
|
+
cache3 = { text: text || "", at: now, projectRoot };
|
|
61119
|
+
return cache3.text;
|
|
60240
61120
|
} catch {
|
|
60241
61121
|
return "";
|
|
60242
61122
|
}
|
|
60243
61123
|
}
|
|
60244
|
-
var DEFAULT_CACHE_MS,
|
|
61124
|
+
var DEFAULT_CACHE_MS, cache3;
|
|
60245
61125
|
var init_loadDurableContext = __esm({
|
|
60246
61126
|
"src/cli/state/loadDurableContext.ts"() {
|
|
60247
61127
|
"use strict";
|
|
60248
61128
|
init_fileStateStore();
|
|
60249
61129
|
DEFAULT_CACHE_MS = 2e3;
|
|
60250
|
-
|
|
61130
|
+
cache3 = null;
|
|
60251
61131
|
}
|
|
60252
61132
|
});
|
|
60253
61133
|
|
|
@@ -62011,7 +62891,7 @@ __export(agentsMd_exports, {
|
|
|
62011
62891
|
updateAgentsMd: () => updateAgentsMd
|
|
62012
62892
|
});
|
|
62013
62893
|
import { existsSync as existsSync44, readFileSync as readFileSync32, writeFileSync as writeFileSync20 } from "node:fs";
|
|
62014
|
-
import { createHash as
|
|
62894
|
+
import { createHash as createHash22 } from "node:crypto";
|
|
62015
62895
|
import { join as join34 } from "node:path";
|
|
62016
62896
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
62017
62897
|
async function readPackageJson3(projectRoot) {
|
|
@@ -62226,7 +63106,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
62226
63106
|
return { changed: true, sections: changedSections };
|
|
62227
63107
|
}
|
|
62228
63108
|
function hash2(s) {
|
|
62229
|
-
return
|
|
63109
|
+
return createHash22("sha256").update(s).digest("hex").slice(0, 16);
|
|
62230
63110
|
}
|
|
62231
63111
|
var AUTO_SECTIONS, MARKER_OPEN, MARKER_CLOSE, GENERATORS;
|
|
62232
63112
|
var init_agentsMd = __esm({
|
|
@@ -62954,7 +63834,7 @@ __export(councilFeedback_exports, {
|
|
|
62954
63834
|
FeedbackStore: () => FeedbackStore
|
|
62955
63835
|
});
|
|
62956
63836
|
import {
|
|
62957
|
-
promises as
|
|
63837
|
+
promises as fs31,
|
|
62958
63838
|
existsSync as existsSync49,
|
|
62959
63839
|
readFileSync as readFileSync37,
|
|
62960
63840
|
writeFileSync as writeFileSync22,
|
|
@@ -63087,7 +63967,7 @@ var init_councilFeedback = __esm({
|
|
|
63087
63967
|
/** Async variant of load for callers that prefer async IO. */
|
|
63088
63968
|
async loadAsync() {
|
|
63089
63969
|
try {
|
|
63090
|
-
const raw = await
|
|
63970
|
+
const raw = await fs31.readFile(this.file, "utf-8");
|
|
63091
63971
|
const parsed = JSON.parse(raw);
|
|
63092
63972
|
if (parsed && Array.isArray(parsed.entries)) {
|
|
63093
63973
|
this.entries = parsed.entries.filter(
|
|
@@ -63407,7 +64287,7 @@ __export(fileBackend_exports, {
|
|
|
63407
64287
|
isMemoryEnabled: () => isMemoryEnabled
|
|
63408
64288
|
});
|
|
63409
64289
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
63410
|
-
import { promises as
|
|
64290
|
+
import { promises as fs32 } from "node:fs";
|
|
63411
64291
|
import * as path75 from "node:path";
|
|
63412
64292
|
function tokenize2(text) {
|
|
63413
64293
|
return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
|
|
@@ -63463,7 +64343,7 @@ var init_fileBackend = __esm({
|
|
|
63463
64343
|
async init(projectRoot) {
|
|
63464
64344
|
this.memoryDir = path75.join(projectRoot, ".zelari", "memory");
|
|
63465
64345
|
this.logPath = path75.join(this.memoryDir, "log.jsonl");
|
|
63466
|
-
await
|
|
64346
|
+
await fs32.mkdir(this.memoryDir, { recursive: true });
|
|
63467
64347
|
}
|
|
63468
64348
|
async add(content, metadata2 = {}, graph) {
|
|
63469
64349
|
const fact = {
|
|
@@ -63473,7 +64353,7 @@ var init_fileBackend = __esm({
|
|
|
63473
64353
|
...graph ? { graph } : {},
|
|
63474
64354
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
63475
64355
|
};
|
|
63476
|
-
await
|
|
64356
|
+
await fs32.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
|
|
63477
64357
|
return fact.id;
|
|
63478
64358
|
}
|
|
63479
64359
|
async search(query, options = {}) {
|
|
@@ -63501,7 +64381,7 @@ var init_fileBackend = __esm({
|
|
|
63501
64381
|
async readAll() {
|
|
63502
64382
|
let raw;
|
|
63503
64383
|
try {
|
|
63504
|
-
raw = await
|
|
64384
|
+
raw = await fs32.readFile(this.logPath, "utf8");
|
|
63505
64385
|
} catch {
|
|
63506
64386
|
return [];
|
|
63507
64387
|
}
|
|
@@ -63534,7 +64414,7 @@ var init_fileBackend = __esm({
|
|
|
63534
64414
|
});
|
|
63535
64415
|
|
|
63536
64416
|
// src/cli/traceStore.ts
|
|
63537
|
-
import { promises as
|
|
64417
|
+
import { promises as fs33 } from "node:fs";
|
|
63538
64418
|
import * as path76 from "node:path";
|
|
63539
64419
|
function traceDir(projectRoot) {
|
|
63540
64420
|
return path76.join(projectRoot, ".zelari", "trace");
|
|
@@ -63544,13 +64424,13 @@ function tracePath(projectRoot, missionId) {
|
|
|
63544
64424
|
}
|
|
63545
64425
|
async function saveTrace(projectRoot, missionId, entries) {
|
|
63546
64426
|
const dir = traceDir(projectRoot);
|
|
63547
|
-
await
|
|
64427
|
+
await fs33.mkdir(dir, { recursive: true });
|
|
63548
64428
|
const payload = {
|
|
63549
64429
|
missionId,
|
|
63550
64430
|
ts: Date.now(),
|
|
63551
64431
|
entries
|
|
63552
64432
|
};
|
|
63553
|
-
await
|
|
64433
|
+
await fs33.writeFile(
|
|
63554
64434
|
tracePath(projectRoot, missionId),
|
|
63555
64435
|
JSON.stringify(payload, null, 2) + "\n",
|
|
63556
64436
|
"utf8"
|
|
@@ -63581,7 +64461,7 @@ __export(zelariMission_exports, {
|
|
|
63581
64461
|
runZelariMission: () => runZelariMission
|
|
63582
64462
|
});
|
|
63583
64463
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
63584
|
-
import { promises as
|
|
64464
|
+
import { promises as fs34 } from "node:fs";
|
|
63585
64465
|
import * as path77 from "node:path";
|
|
63586
64466
|
function resolveMaxIterations(env = process.env) {
|
|
63587
64467
|
const raw = env.ZELARI_MISSION_MAX_ITER;
|
|
@@ -63626,8 +64506,8 @@ function isMissionAutoStart(env = process.env) {
|
|
|
63626
64506
|
}
|
|
63627
64507
|
async function writeMissionState(projectRoot, state3) {
|
|
63628
64508
|
const dir = path77.join(projectRoot, ".zelari");
|
|
63629
|
-
await
|
|
63630
|
-
await
|
|
64509
|
+
await fs34.mkdir(dir, { recursive: true });
|
|
64510
|
+
await fs34.writeFile(
|
|
63631
64511
|
path77.join(dir, "mission-state.json"),
|
|
63632
64512
|
JSON.stringify(state3, null, 2) + "\n",
|
|
63633
64513
|
"utf8"
|
|
@@ -63641,7 +64521,7 @@ async function writeMissionState(projectRoot, state3) {
|
|
|
63641
64521
|
}
|
|
63642
64522
|
async function loadMissionState(projectRoot) {
|
|
63643
64523
|
try {
|
|
63644
|
-
const raw = await
|
|
64524
|
+
const raw = await fs34.readFile(
|
|
63645
64525
|
path77.join(projectRoot, ".zelari", "mission-state.json"),
|
|
63646
64526
|
"utf8"
|
|
63647
64527
|
);
|
|
@@ -66919,11 +67799,11 @@ var init_policy = __esm({
|
|
|
66919
67799
|
});
|
|
66920
67800
|
|
|
66921
67801
|
// src/cli/orchestration/facts.ts
|
|
66922
|
-
import { promises as
|
|
67802
|
+
import { promises as fs44 } from "node:fs";
|
|
66923
67803
|
import path88 from "node:path";
|
|
66924
67804
|
async function collectRepoFileCount(root = process.cwd()) {
|
|
66925
67805
|
try {
|
|
66926
|
-
await
|
|
67806
|
+
await fs44.readdir(root);
|
|
66927
67807
|
} catch {
|
|
66928
67808
|
return void 0;
|
|
66929
67809
|
}
|
|
@@ -66934,7 +67814,7 @@ async function collectRepoFileCount(root = process.cwd()) {
|
|
|
66934
67814
|
const dir = queue.pop();
|
|
66935
67815
|
let entries;
|
|
66936
67816
|
try {
|
|
66937
|
-
entries = await
|
|
67817
|
+
entries = await fs44.readdir(dir, { withFileTypes: true });
|
|
66938
67818
|
} catch {
|
|
66939
67819
|
continue;
|
|
66940
67820
|
}
|
|
@@ -67212,8 +68092,8 @@ function contractFor(t) {
|
|
|
67212
68092
|
blockers
|
|
67213
68093
|
};
|
|
67214
68094
|
}
|
|
67215
|
-
async function readHarnessState(sessionDir) {
|
|
67216
|
-
const report = await
|
|
68095
|
+
async function readHarnessState(sessionDir, cache4) {
|
|
68096
|
+
const report = await readSessionLogCached(path89.join(sessionDir, "events.jsonl"), cache4);
|
|
67217
68097
|
return deriveHarnessState(report.events);
|
|
67218
68098
|
}
|
|
67219
68099
|
var init_harnessState = __esm({
|
|
@@ -67514,7 +68394,7 @@ var init_controlBridge = __esm({
|
|
|
67514
68394
|
function attachHeadlessLiveCancel(opts) {
|
|
67515
68395
|
const abort = new AbortController();
|
|
67516
68396
|
const controlQueue = new RuntimeControlQueue();
|
|
67517
|
-
const cancel = () => {
|
|
68397
|
+
const cancel = (_reason) => {
|
|
67518
68398
|
if (!abort.signal.aborted) abort.abort();
|
|
67519
68399
|
return true;
|
|
67520
68400
|
};
|
|
@@ -67837,7 +68717,7 @@ var init_sandboxedFs = __esm({
|
|
|
67837
68717
|
// src/cli/extensions/loader.ts
|
|
67838
68718
|
import { join as join44 } from "node:path";
|
|
67839
68719
|
import { readdirSync as readdirSync11, readFileSync as readFileSync43 } from "node:fs";
|
|
67840
|
-
import { createHash as
|
|
68720
|
+
import { createHash as createHash23 } from "node:crypto";
|
|
67841
68721
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
67842
68722
|
function globalExtensionsDir() {
|
|
67843
68723
|
return join44(zelariHome(), "extensions");
|
|
@@ -67846,7 +68726,7 @@ function projectExtensionsDir(projectRoot) {
|
|
|
67846
68726
|
return join44(projectRoot, ".zelari", "extensions");
|
|
67847
68727
|
}
|
|
67848
68728
|
function sha256File(file2) {
|
|
67849
|
-
return
|
|
68729
|
+
return createHash23("sha256").update(readFileSync43(file2)).digest("hex");
|
|
67850
68730
|
}
|
|
67851
68731
|
function candidateFiles(dir) {
|
|
67852
68732
|
let names;
|
|
@@ -67877,7 +68757,7 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
|
|
|
67877
68757
|
skipped
|
|
67878
68758
|
};
|
|
67879
68759
|
const fsRoot = options.fsRoot ?? process.cwd();
|
|
67880
|
-
let
|
|
68760
|
+
let fs49 = null;
|
|
67881
68761
|
const pending = [];
|
|
67882
68762
|
for (const dir of dirs) {
|
|
67883
68763
|
const files = candidateFiles(dir.path);
|
|
@@ -67932,9 +68812,9 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
|
|
|
67932
68812
|
skipped.push(`${file2}: missing ZelariExtension export`);
|
|
67933
68813
|
continue;
|
|
67934
68814
|
}
|
|
67935
|
-
if (!
|
|
68815
|
+
if (!fs49) fs49 = bindSandboxedFs(fsRoot);
|
|
67936
68816
|
try {
|
|
67937
|
-
await runtime.registry.registerExtension(ext, { fs:
|
|
68817
|
+
await runtime.registry.registerExtension(ext, { fs: fs49 });
|
|
67938
68818
|
runtime.loaded.push({ id: ext.id, file: file2, scope });
|
|
67939
68819
|
} catch (err) {
|
|
67940
68820
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -67992,7 +68872,7 @@ var init_loader = __esm({
|
|
|
67992
68872
|
});
|
|
67993
68873
|
|
|
67994
68874
|
// src/cli/headless/runOneTurn.ts
|
|
67995
|
-
import { promises as
|
|
68875
|
+
import { promises as fs45 } from "node:fs";
|
|
67996
68876
|
import path92 from "node:path";
|
|
67997
68877
|
function planModeFromOpts(opts) {
|
|
67998
68878
|
return (opts.phase ?? "build") === "plan";
|
|
@@ -68072,10 +68952,10 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
|
|
|
68072
68952
|
})() : void 0;
|
|
68073
68953
|
const unregisterLiveTurnControl = process.env.ZELARI_SERVE_HARNESS === "1" ? registerLiveTurnControl({
|
|
68074
68954
|
queue: controlQueue,
|
|
68075
|
-
cancel: () => {
|
|
68955
|
+
cancel: (reason) => {
|
|
68076
68956
|
const cancelHook = harnessHolder.cancel;
|
|
68077
68957
|
if (!cancelHook) return false;
|
|
68078
|
-
cancelHook();
|
|
68958
|
+
cancelHook(reason);
|
|
68079
68959
|
return true;
|
|
68080
68960
|
}
|
|
68081
68961
|
}) : void 0;
|
|
@@ -68361,7 +69241,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
|
|
|
68361
69241
|
memoryContextChars: 2e3
|
|
68362
69242
|
} : {}
|
|
68363
69243
|
});
|
|
68364
|
-
harnessHolder.cancel = () => harness.cancel();
|
|
69244
|
+
harnessHolder.cancel = (reason) => harness.cancel(reason);
|
|
68365
69245
|
const readBuildProgress = () => {
|
|
68366
69246
|
const getter = harness.getBuildProgress;
|
|
68367
69247
|
return typeof getter === "function" ? getter.call(harness) : { mutationsAttempted: 0, mutationsSucceeded: 0 };
|
|
@@ -68548,11 +69428,11 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
|
|
|
68548
69428
|
process.stdout.write(pass.textBuffer.join(""));
|
|
68549
69429
|
}
|
|
68550
69430
|
process.stdout.write("");
|
|
68551
|
-
if (pass.finalReason !== "error" && opts.output === "json" && wantWrites && pass.successfulWrites === 0) {
|
|
69431
|
+
if (pass.finalReason !== "error" && pass.finalReason !== "cancelled" && opts.output === "json" && wantWrites && pass.successfulWrites === 0) {
|
|
68552
69432
|
emitEvent({ type: "log", message: "[headless] BUILD failed: zero successful mutations after liveness recovery" });
|
|
68553
69433
|
}
|
|
68554
69434
|
try {
|
|
68555
|
-
const closeStatus = pass.finalReason === "error" ? "error" : strictExit !== 0 ? "stopped" : "completed";
|
|
69435
|
+
const closeStatus = pass.finalReason === "error" ? "error" : pass.finalReason === "cancelled" ? "cancelled" : strictExit !== 0 ? "stopped" : "completed";
|
|
68556
69436
|
await spine.close(closeStatus);
|
|
68557
69437
|
} catch {
|
|
68558
69438
|
}
|
|
@@ -68563,8 +69443,8 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
|
|
|
68563
69443
|
if (json3) {
|
|
68564
69444
|
if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
|
|
68565
69445
|
else {
|
|
68566
|
-
await
|
|
68567
|
-
await
|
|
69446
|
+
await fs45.mkdir(path92.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
|
|
69447
|
+
await fs45.writeFile(opts.exportSessionPath, json3, "utf8");
|
|
68568
69448
|
}
|
|
68569
69449
|
}
|
|
68570
69450
|
} catch {
|
|
@@ -69611,7 +70491,7 @@ __export(triggerLock_exports, {
|
|
|
69611
70491
|
lockPath: () => lockPath,
|
|
69612
70492
|
releaseLock: () => releaseLock
|
|
69613
70493
|
});
|
|
69614
|
-
import { promises as
|
|
70494
|
+
import { promises as fs46 } from "node:fs";
|
|
69615
70495
|
import * as path93 from "node:path";
|
|
69616
70496
|
function lockPath(projectRoot) {
|
|
69617
70497
|
return path93.join(projectRoot, ".zelari", "trigger.lock");
|
|
@@ -69628,9 +70508,9 @@ function isPidAlive(pid) {
|
|
|
69628
70508
|
async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
|
|
69629
70509
|
const lp = lockPath(projectRoot);
|
|
69630
70510
|
const dir = path93.dirname(lp);
|
|
69631
|
-
await
|
|
70511
|
+
await fs46.mkdir(dir, { recursive: true });
|
|
69632
70512
|
try {
|
|
69633
|
-
const raw = await
|
|
70513
|
+
const raw = await fs46.readFile(lp, "utf8");
|
|
69634
70514
|
const existing = JSON.parse(raw);
|
|
69635
70515
|
if (existing.pid && isPidAlive(existing.pid)) {
|
|
69636
70516
|
return { acquired: false, heldBy: existing.pid, lockPath: lp };
|
|
@@ -69641,13 +70521,13 @@ async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date())
|
|
|
69641
70521
|
pid: process.pid,
|
|
69642
70522
|
acquiredAt: now().toISOString()
|
|
69643
70523
|
};
|
|
69644
|
-
await
|
|
70524
|
+
await fs46.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
69645
70525
|
return { acquired: true, lockPath: lp };
|
|
69646
70526
|
}
|
|
69647
70527
|
async function releaseLock(projectRoot) {
|
|
69648
70528
|
const lp = lockPath(projectRoot);
|
|
69649
70529
|
try {
|
|
69650
|
-
await
|
|
70530
|
+
await fs46.unlink(lp);
|
|
69651
70531
|
} catch {
|
|
69652
70532
|
}
|
|
69653
70533
|
}
|
|
@@ -69658,7 +70538,7 @@ var init_triggerLock = __esm({
|
|
|
69658
70538
|
});
|
|
69659
70539
|
|
|
69660
70540
|
// src/cli/runHeadless.ts
|
|
69661
|
-
import { promises as
|
|
70541
|
+
import { promises as fs47 } from "node:fs";
|
|
69662
70542
|
import path94 from "node:path";
|
|
69663
70543
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
69664
70544
|
async function runHeadless(opts) {
|
|
@@ -69730,12 +70610,42 @@ ${err.stack}` : "";
|
|
|
69730
70610
|
return 1;
|
|
69731
70611
|
}
|
|
69732
70612
|
const { buildProviderStream: buildProviderStream2 } = await Promise.resolve().then(() => (init_resolveStream(), resolveStream_exports));
|
|
69733
|
-
|
|
70613
|
+
const primaryStream = buildProviderStream2({
|
|
69734
70614
|
providerId: provider,
|
|
69735
70615
|
apiKey: key.apiKey,
|
|
69736
70616
|
baseUrl: key.baseUrl,
|
|
69737
70617
|
model
|
|
69738
70618
|
});
|
|
70619
|
+
const { isHeadlessFailoverEnabled: isHeadlessFailoverEnabled2, wrapWithHeadlessFailover: wrapWithHeadlessFailover2 } = await Promise.resolve().then(() => (init_crossProviderFailover(), crossProviderFailover_exports));
|
|
70620
|
+
if (isHeadlessFailoverEnabled2()) {
|
|
70621
|
+
const { PROVIDERS: PROVIDERS2 } = await Promise.resolve().then(() => (init_keyStore(), keyStore_exports));
|
|
70622
|
+
const { providerConfigFor: providerConfigFor2 } = await Promise.resolve().then(() => (init_openai_compatible(), openai_compatible_exports));
|
|
70623
|
+
providerStream = await wrapWithHeadlessFailover2({
|
|
70624
|
+
primary: primaryStream,
|
|
70625
|
+
primaryProviderId: provider,
|
|
70626
|
+
validProviderIds: PROVIDERS2.map((p3) => p3.id),
|
|
70627
|
+
lookupFallbackConfig: async (id3) => providerConfigFor2(id3),
|
|
70628
|
+
buildStream: (config2) => buildProviderStream2(config2),
|
|
70629
|
+
onWarning: (warning) => {
|
|
70630
|
+
try {
|
|
70631
|
+
process.stderr.write(`[zelari-code --headless] ${warning}
|
|
70632
|
+
`);
|
|
70633
|
+
} catch {
|
|
70634
|
+
}
|
|
70635
|
+
},
|
|
70636
|
+
onFailover: (info) => {
|
|
70637
|
+
try {
|
|
70638
|
+
process.stderr.write(
|
|
70639
|
+
`[zelari-code --headless] [failover] ${info.phase}${info.label ? ` \u2192 ${info.label}` : ""}: ${info.message}
|
|
70640
|
+
`
|
|
70641
|
+
);
|
|
70642
|
+
} catch {
|
|
70643
|
+
}
|
|
70644
|
+
}
|
|
70645
|
+
});
|
|
70646
|
+
} else {
|
|
70647
|
+
providerStream = primaryStream;
|
|
70648
|
+
}
|
|
69739
70649
|
}
|
|
69740
70650
|
return dispatchHeadlessTurn(opts, provider, model, providerStream, {
|
|
69741
70651
|
// H10-fix3: the gate already ran above on the SAME input (no chdir in
|
|
@@ -69907,7 +70817,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
69907
70817
|
log(`loading pre-flight plan: ${planPath}`);
|
|
69908
70818
|
let raw;
|
|
69909
70819
|
try {
|
|
69910
|
-
raw = await
|
|
70820
|
+
raw = await fs47.readFile(planPath, "utf8");
|
|
69911
70821
|
} catch (e) {
|
|
69912
70822
|
log(`plan file not found: ${planPath} (${e.message})`);
|
|
69913
70823
|
exitCode = 1;
|
|
@@ -69948,8 +70858,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
69948
70858
|
const planId = randomUUID10();
|
|
69949
70859
|
const planDir = path94.join(cwd, ".zelari", "radio");
|
|
69950
70860
|
const planPath = path94.join(planDir, `plan-${planId}.json`);
|
|
69951
|
-
await
|
|
69952
|
-
await
|
|
70861
|
+
await fs47.mkdir(planDir, { recursive: true });
|
|
70862
|
+
await fs47.writeFile(
|
|
69953
70863
|
planPath,
|
|
69954
70864
|
JSON.stringify(
|
|
69955
70865
|
{ id: graph.id, nodes: [...graph.nodes.values()] },
|
|
@@ -70338,8 +71248,8 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
|
|
|
70338
71248
|
if (json3) {
|
|
70339
71249
|
if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
|
|
70340
71250
|
else {
|
|
70341
|
-
await
|
|
70342
|
-
await
|
|
71251
|
+
await fs47.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
|
|
71252
|
+
await fs47.writeFile(opts.exportSessionPath, json3, "utf8");
|
|
70343
71253
|
}
|
|
70344
71254
|
}
|
|
70345
71255
|
} catch {
|
|
@@ -70810,8 +71720,8 @@ ${ragContext}` : slicePrompt;
|
|
|
70810
71720
|
if (json3) {
|
|
70811
71721
|
if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
|
|
70812
71722
|
else {
|
|
70813
|
-
await
|
|
70814
|
-
await
|
|
71723
|
+
await fs47.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
|
|
71724
|
+
await fs47.writeFile(opts.exportSessionPath, json3, "utf8");
|
|
70815
71725
|
}
|
|
70816
71726
|
}
|
|
70817
71727
|
} catch {
|
|
@@ -72282,7 +73192,7 @@ import {
|
|
|
72282
73192
|
writeFileSync as writeFileSync26
|
|
72283
73193
|
} from "node:fs";
|
|
72284
73194
|
import { join as join47 } from "node:path";
|
|
72285
|
-
import { createHash as
|
|
73195
|
+
import { createHash as createHash24, randomBytes as randomBytes7, timingSafeEqual } from "node:crypto";
|
|
72286
73196
|
function getZelariHome() {
|
|
72287
73197
|
return zelariHome();
|
|
72288
73198
|
}
|
|
@@ -72350,16 +73260,16 @@ function loadOrCreateToken(explicit) {
|
|
|
72350
73260
|
const token = randomBytes7(24).toString("base64url");
|
|
72351
73261
|
writeFileSync26(path101, token + "\n", "utf8");
|
|
72352
73262
|
try {
|
|
72353
|
-
const
|
|
72354
|
-
|
|
73263
|
+
const fs49 = __require("node:fs");
|
|
73264
|
+
fs49.chmodSync?.(path101, 384);
|
|
72355
73265
|
} catch {
|
|
72356
73266
|
}
|
|
72357
73267
|
return { token, created: true };
|
|
72358
73268
|
}
|
|
72359
73269
|
function tokenMatches(expected, provided) {
|
|
72360
73270
|
if (!provided) return false;
|
|
72361
|
-
const a =
|
|
72362
|
-
const b =
|
|
73271
|
+
const a = createHash24("sha256").update(expected).digest();
|
|
73272
|
+
const b = createHash24("sha256").update(provided).digest();
|
|
72363
73273
|
try {
|
|
72364
73274
|
return timingSafeEqual(a, b);
|
|
72365
73275
|
} catch {
|
|
@@ -72628,7 +73538,7 @@ var init_askUserBridge = __esm({
|
|
|
72628
73538
|
});
|
|
72629
73539
|
|
|
72630
73540
|
// src/cli/serve/spineLockSweep.ts
|
|
72631
|
-
import { promises as
|
|
73541
|
+
import { promises as fs48 } from "node:fs";
|
|
72632
73542
|
import path96 from "node:path";
|
|
72633
73543
|
async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
|
|
72634
73544
|
const dir = sessionsDir2 ?? resolveSessionsDir();
|
|
@@ -72642,14 +73552,14 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
|
|
|
72642
73552
|
const result = { swept: 0, kept: 0, errors: 0 };
|
|
72643
73553
|
let entries;
|
|
72644
73554
|
try {
|
|
72645
|
-
entries = await
|
|
73555
|
+
entries = await fs48.readdir(dir);
|
|
72646
73556
|
} catch {
|
|
72647
73557
|
return result;
|
|
72648
73558
|
}
|
|
72649
73559
|
for (const sessionId2 of entries) {
|
|
72650
73560
|
const lockPath2 = path96.join(dir, sessionId2, "writer.lock");
|
|
72651
73561
|
try {
|
|
72652
|
-
const raw = await
|
|
73562
|
+
const raw = await fs48.readFile(lockPath2, "utf-8");
|
|
72653
73563
|
let lockInfo = {};
|
|
72654
73564
|
try {
|
|
72655
73565
|
lockInfo = JSON.parse(raw);
|
|
@@ -72666,7 +73576,7 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
|
|
|
72666
73576
|
result.kept += 1;
|
|
72667
73577
|
continue;
|
|
72668
73578
|
}
|
|
72669
|
-
await
|
|
73579
|
+
await fs48.rm(lockPath2, { force: true });
|
|
72670
73580
|
result.swept += 1;
|
|
72671
73581
|
onSwept(sessionId2, verdict.reason);
|
|
72672
73582
|
} catch (err) {
|
|
@@ -72886,7 +73796,8 @@ function startHarnessServer(options = {}) {
|
|
|
72886
73796
|
};
|
|
72887
73797
|
}
|
|
72888
73798
|
if (isCancel) {
|
|
72889
|
-
const
|
|
73799
|
+
const reason = typeof params.reason === "string" && params.reason.trim().length > 0 ? params.reason.trim() : void 0;
|
|
73800
|
+
const delivered = live.cancel(reason);
|
|
72890
73801
|
if (delivered) {
|
|
72891
73802
|
write(JSON.stringify(controlAppliedEvent(controlId, "cancel", "cancel")));
|
|
72892
73803
|
}
|
|
@@ -77973,107 +78884,8 @@ init_metrics3();
|
|
|
77973
78884
|
init_modelPricing();
|
|
77974
78885
|
init_openai_compatible();
|
|
77975
78886
|
init_resolveStream();
|
|
77976
|
-
|
|
77977
|
-
|
|
77978
|
-
// src/cli/providerFailover.ts
|
|
77979
|
-
var DEFAULT_IS_TRANSIENT = (delta) => delta.kind === "error";
|
|
77980
|
-
function providerFailover(options) {
|
|
77981
|
-
const isTransient = options.isTransientFailure ?? DEFAULT_IS_TRANSIENT;
|
|
77982
|
-
const primaryFailedMsg = options.fallbackLabel ? `[failover] primary failed, switching to ${options.fallbackLabel}` : "[failover] primary failed, switching to fallback";
|
|
77983
|
-
const primaryThrewMsg = options.fallbackLabel ? `[failover] primary threw, switching to ${options.fallbackLabel}: ` : "[failover] primary threw: ";
|
|
77984
|
-
const fallbackFailedMsg = options.fallbackLabel ? `[failover] fallback (${options.fallbackLabel}) also failed: ` : "[failover] fallback also failed: ";
|
|
77985
|
-
return async function* (params) {
|
|
77986
|
-
const triedFallback = { value: false };
|
|
77987
|
-
try {
|
|
77988
|
-
for await (const delta of options.primary(params)) {
|
|
77989
|
-
if (isTransient(delta)) {
|
|
77990
|
-
yield delta;
|
|
77991
|
-
triedFallback.value = true;
|
|
77992
|
-
yield {
|
|
77993
|
-
kind: "error",
|
|
77994
|
-
message: primaryFailedMsg
|
|
77995
|
-
};
|
|
77996
|
-
break;
|
|
77997
|
-
}
|
|
77998
|
-
yield delta;
|
|
77999
|
-
}
|
|
78000
|
-
} catch (err) {
|
|
78001
|
-
triedFallback.value = true;
|
|
78002
|
-
yield {
|
|
78003
|
-
kind: "error",
|
|
78004
|
-
message: `${primaryThrewMsg}${err instanceof Error ? err.message : String(err)}`
|
|
78005
|
-
};
|
|
78006
|
-
}
|
|
78007
|
-
if (triedFallback.value) {
|
|
78008
|
-
try {
|
|
78009
|
-
for await (const delta of options.fallback(params)) {
|
|
78010
|
-
yield delta;
|
|
78011
|
-
}
|
|
78012
|
-
} catch (err) {
|
|
78013
|
-
yield {
|
|
78014
|
-
kind: "error",
|
|
78015
|
-
message: `${fallbackFailedMsg}${err instanceof Error ? err.message : String(err)}`
|
|
78016
|
-
};
|
|
78017
|
-
return;
|
|
78018
|
-
}
|
|
78019
|
-
}
|
|
78020
|
-
};
|
|
78021
|
-
}
|
|
78022
|
-
|
|
78023
|
-
// src/cli/crossProviderFailover.ts
|
|
78024
|
-
async function resolveFailoverStream(options) {
|
|
78025
|
-
if (!options.failoverEnabled) {
|
|
78026
|
-
return {
|
|
78027
|
-
fallback: options.primary,
|
|
78028
|
-
fallbackLabel: void 0,
|
|
78029
|
-
warning: "",
|
|
78030
|
-
reason: "disabled"
|
|
78031
|
-
};
|
|
78032
|
-
}
|
|
78033
|
-
const requested = options.envValue?.trim();
|
|
78034
|
-
if (!requested || requested.length === 0) {
|
|
78035
|
-
return {
|
|
78036
|
-
fallback: options.primary,
|
|
78037
|
-
fallbackLabel: void 0,
|
|
78038
|
-
warning: "",
|
|
78039
|
-
reason: "unset"
|
|
78040
|
-
};
|
|
78041
|
-
}
|
|
78042
|
-
const valid = new Set(options.validProviderIds);
|
|
78043
|
-
if (!valid.has(requested)) {
|
|
78044
|
-
return {
|
|
78045
|
-
fallback: options.primary,
|
|
78046
|
-
fallbackLabel: void 0,
|
|
78047
|
-
warning: `[failover] ANATHEMA_FAILOVER_PROVIDER="${requested}" is not a known provider. Falling back to v3-G same-provider behavior. Available: ${options.validProviderIds.join(", ")}.`,
|
|
78048
|
-
reason: "unknown"
|
|
78049
|
-
};
|
|
78050
|
-
}
|
|
78051
|
-
if (requested === options.primaryProviderId) {
|
|
78052
|
-
return {
|
|
78053
|
-
fallback: options.primary,
|
|
78054
|
-
fallbackLabel: void 0,
|
|
78055
|
-
warning: "",
|
|
78056
|
-
reason: "same-as-primary"
|
|
78057
|
-
};
|
|
78058
|
-
}
|
|
78059
|
-
const fallbackConfig = await options.lookupFallbackConfig(requested);
|
|
78060
|
-
if (!fallbackConfig) {
|
|
78061
|
-
return {
|
|
78062
|
-
fallback: options.primary,
|
|
78063
|
-
fallbackLabel: void 0,
|
|
78064
|
-
warning: `[failover] No API key configured for provider "${requested}". Falling back to v3-G same-provider behavior.`,
|
|
78065
|
-
reason: "missing-key"
|
|
78066
|
-
};
|
|
78067
|
-
}
|
|
78068
|
-
return {
|
|
78069
|
-
fallback: options.buildStream(fallbackConfig),
|
|
78070
|
-
fallbackLabel: requested,
|
|
78071
|
-
warning: "",
|
|
78072
|
-
reason: "resolved"
|
|
78073
|
-
};
|
|
78074
|
-
}
|
|
78075
|
-
|
|
78076
|
-
// src/cli/hooks/useChatTurn.ts
|
|
78887
|
+
init_providerFailover();
|
|
78888
|
+
init_crossProviderFailover();
|
|
78077
78889
|
init_shellResolver();
|
|
78078
78890
|
init_keyStore();
|
|
78079
78891
|
init_providerConfig();
|
|
@@ -78090,6 +78902,7 @@ init_completionProof();
|
|
|
78090
78902
|
init_verifyStatus();
|
|
78091
78903
|
init_nativeVerification();
|
|
78092
78904
|
init_spineTelemetry();
|
|
78905
|
+
import { useState as useState6, useRef as useRef4, useCallback as useCallback2 } from "react";
|
|
78093
78906
|
|
|
78094
78907
|
// src/cli/hooks/permissionPicker.ts
|
|
78095
78908
|
init_toolPermissions();
|
|
@@ -81335,11 +82148,11 @@ function handleCacheStats(ctx) {
|
|
|
81335
82148
|
// src/cli/slashHandlers/memory.ts
|
|
81336
82149
|
init_messageHelpers();
|
|
81337
82150
|
init_serviceFactory();
|
|
81338
|
-
import { promises as
|
|
82151
|
+
import { promises as fs36 } from "node:fs";
|
|
81339
82152
|
import * as path80 from "node:path";
|
|
81340
82153
|
|
|
81341
82154
|
// src/cli/memory/promotion.ts
|
|
81342
|
-
import { promises as
|
|
82155
|
+
import { promises as fs35 } from "node:fs";
|
|
81343
82156
|
import * as path79 from "node:path";
|
|
81344
82157
|
var START = "<!-- zelari:memory-promotions:start -->";
|
|
81345
82158
|
var END = "<!-- zelari:memory-promotions:end -->";
|
|
@@ -81356,17 +82169,17 @@ async function promoteMemoryToAgentsMd(projectRoot, node) {
|
|
|
81356
82169
|
if (!DURABLE_KINDS.has(node.kind)) {
|
|
81357
82170
|
return { added: false, path: path79.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
|
|
81358
82171
|
}
|
|
81359
|
-
const root = await
|
|
82172
|
+
const root = await fs35.realpath(projectRoot).catch(() => path79.resolve(projectRoot));
|
|
81360
82173
|
const target = path79.join(root, "AGENTS.md");
|
|
81361
82174
|
try {
|
|
81362
|
-
const stat8 = await
|
|
82175
|
+
const stat8 = await fs35.lstat(target);
|
|
81363
82176
|
if (stat8.isSymbolicLink() || !stat8.isFile()) throw new Error("AGENTS.md must be a regular project file.");
|
|
81364
82177
|
} catch (error51) {
|
|
81365
82178
|
if (error51.code !== "ENOENT") throw error51;
|
|
81366
82179
|
}
|
|
81367
82180
|
let current = "";
|
|
81368
82181
|
try {
|
|
81369
|
-
current = await
|
|
82182
|
+
current = await fs35.readFile(target, "utf8");
|
|
81370
82183
|
} catch (error51) {
|
|
81371
82184
|
if (error51.code !== "ENOENT") throw error51;
|
|
81372
82185
|
}
|
|
@@ -81389,11 +82202,11 @@ ${END}
|
|
|
81389
82202
|
`;
|
|
81390
82203
|
}
|
|
81391
82204
|
const temporary = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
81392
|
-
await
|
|
82205
|
+
await fs35.writeFile(temporary, updated, { encoding: "utf8", flag: "wx" });
|
|
81393
82206
|
try {
|
|
81394
|
-
await
|
|
82207
|
+
await fs35.rename(temporary, target);
|
|
81395
82208
|
} catch (error51) {
|
|
81396
|
-
await
|
|
82209
|
+
await fs35.unlink(temporary).catch(() => void 0);
|
|
81397
82210
|
throw error51;
|
|
81398
82211
|
}
|
|
81399
82212
|
return { added: true, path: target };
|
|
@@ -81427,7 +82240,7 @@ function isInside(root, target) {
|
|
|
81427
82240
|
}
|
|
81428
82241
|
async function safeExportPath(cwd, requested) {
|
|
81429
82242
|
const lexicalRoot = path80.resolve(cwd);
|
|
81430
|
-
const root = await
|
|
82243
|
+
const root = await fs36.realpath(lexicalRoot).catch(() => lexicalRoot);
|
|
81431
82244
|
const fallback = path80.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
|
|
81432
82245
|
const target = requested?.trim() ? path80.resolve(root, requested.trim()) : fallback;
|
|
81433
82246
|
if (!isInside(root, target)) {
|
|
@@ -81439,7 +82252,7 @@ async function safeExportPath(cwd, requested) {
|
|
|
81439
82252
|
for (const segment of relativeParent.split(path80.sep).filter(Boolean)) {
|
|
81440
82253
|
cursor = path80.join(cursor, segment);
|
|
81441
82254
|
try {
|
|
81442
|
-
const stat8 = await
|
|
82255
|
+
const stat8 = await fs36.lstat(cursor);
|
|
81443
82256
|
if (stat8.isSymbolicLink()) {
|
|
81444
82257
|
throw new Error("Export path must not traverse a symbolic link.");
|
|
81445
82258
|
}
|
|
@@ -81449,7 +82262,7 @@ async function safeExportPath(cwd, requested) {
|
|
|
81449
82262
|
}
|
|
81450
82263
|
}
|
|
81451
82264
|
try {
|
|
81452
|
-
if ((await
|
|
82265
|
+
if ((await fs36.lstat(target)).isSymbolicLink()) {
|
|
81453
82266
|
throw new Error("Export target must not be a symbolic link.");
|
|
81454
82267
|
}
|
|
81455
82268
|
} catch (error51) {
|
|
@@ -81609,13 +82422,13 @@ ${message}` : message
|
|
|
81609
82422
|
}
|
|
81610
82423
|
case "export": {
|
|
81611
82424
|
const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
|
|
81612
|
-
await
|
|
81613
|
-
const root = await
|
|
81614
|
-
const realParent = await
|
|
82425
|
+
await fs36.mkdir(path80.dirname(target), { recursive: true });
|
|
82426
|
+
const root = await fs36.realpath(ctx.cwd).catch(() => path80.resolve(ctx.cwd));
|
|
82427
|
+
const realParent = await fs36.realpath(path80.dirname(target));
|
|
81615
82428
|
if (!isInside(root, realParent)) {
|
|
81616
82429
|
throw new Error("Export path resolves outside the active project.");
|
|
81617
82430
|
}
|
|
81618
|
-
await
|
|
82431
|
+
await fs36.writeFile(target, JSON.stringify(await memory.export(), null, 2) + "\n", "utf8");
|
|
81619
82432
|
emit(`[memory] export written to ${target}`);
|
|
81620
82433
|
return;
|
|
81621
82434
|
}
|
|
@@ -81820,12 +82633,12 @@ ${digest}
|
|
|
81820
82633
|
init_auditLogger();
|
|
81821
82634
|
init_toolRegistry();
|
|
81822
82635
|
init_messageHelpers();
|
|
81823
|
-
import { promises as
|
|
82636
|
+
import { promises as fs38 } from "node:fs";
|
|
81824
82637
|
|
|
81825
82638
|
// src/cli/tools/krakenCsvFanout.ts
|
|
81826
82639
|
init_zod();
|
|
81827
82640
|
init_taskTool();
|
|
81828
|
-
import { promises as
|
|
82641
|
+
import { promises as fs37 } from "node:fs";
|
|
81829
82642
|
import path81 from "node:path";
|
|
81830
82643
|
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
81831
82644
|
var CsvFanoutArgsSchema = external_exports.object({
|
|
@@ -81847,7 +82660,7 @@ var CsvFanoutArgsSchema = external_exports.object({
|
|
|
81847
82660
|
max_runtime_seconds: external_exports.number().int().positive().optional()
|
|
81848
82661
|
});
|
|
81849
82662
|
async function readCsv(filePath) {
|
|
81850
|
-
const text = await
|
|
82663
|
+
const text = await fs37.readFile(filePath, "utf8");
|
|
81851
82664
|
return parseCsv(text);
|
|
81852
82665
|
}
|
|
81853
82666
|
function parseCsv(text) {
|
|
@@ -81977,7 +82790,7 @@ async function runCsvFanout(args, deps, opts) {
|
|
|
81977
82790
|
errored += 1;
|
|
81978
82791
|
errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
|
|
81979
82792
|
}
|
|
81980
|
-
await
|
|
82793
|
+
await fs37.mkdir(path81.dirname(absOut), { recursive: true });
|
|
81981
82794
|
await queueWrite(serializeCsv(outHeaders, outputRecords));
|
|
81982
82795
|
}
|
|
81983
82796
|
}
|
|
@@ -81999,8 +82812,8 @@ async function runCsvFanout(args, deps, opts) {
|
|
|
81999
82812
|
}
|
|
82000
82813
|
async function atomicWrite(file2, contents) {
|
|
82001
82814
|
const tmp = `${file2}.${process.pid}.${Date.now()}.${randomBytes6(6).toString("hex")}.tmp`;
|
|
82002
|
-
await
|
|
82003
|
-
await
|
|
82815
|
+
await fs37.writeFile(tmp, contents, "utf8");
|
|
82816
|
+
await fs37.rename(tmp, file2);
|
|
82004
82817
|
}
|
|
82005
82818
|
|
|
82006
82819
|
// src/cli/slashHandlers/krakenFanout.ts
|
|
@@ -82098,7 +82911,7 @@ async function handleKrakenFanout(ctx, raw) {
|
|
|
82098
82911
|
}
|
|
82099
82912
|
const absCsv = isAbsolute3(parsed.args.csv_path) ? parsed.args.csv_path : joinPath(ctx.cwd, parsed.args.csv_path);
|
|
82100
82913
|
try {
|
|
82101
|
-
await
|
|
82914
|
+
await fs38.access(absCsv);
|
|
82102
82915
|
} catch {
|
|
82103
82916
|
appendSystem(ctx.setMessages, `[kraken fanout] source CSV not found: ${absCsv}`);
|
|
82104
82917
|
return;
|
|
@@ -82171,7 +82984,7 @@ function splitArgs(s) {
|
|
|
82171
82984
|
|
|
82172
82985
|
// src/cli/slashHandlers/krakenWorkbench.ts
|
|
82173
82986
|
init_messageHelpers();
|
|
82174
|
-
import { promises as
|
|
82987
|
+
import { promises as fs39 } from "node:fs";
|
|
82175
82988
|
import path82 from "node:path";
|
|
82176
82989
|
|
|
82177
82990
|
// src/cli/kraken/workbenchView.ts
|
|
@@ -82293,11 +83106,11 @@ async function handleKrakenWorkbench(ctx) {
|
|
|
82293
83106
|
let latest = null;
|
|
82294
83107
|
let latestMtime = 0;
|
|
82295
83108
|
try {
|
|
82296
|
-
const files = await
|
|
83109
|
+
const files = await fs39.readdir(dir);
|
|
82297
83110
|
for (const f of files) {
|
|
82298
83111
|
if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
|
|
82299
83112
|
const full = path82.join(dir, f);
|
|
82300
|
-
const stat8 = await
|
|
83113
|
+
const stat8 = await fs39.stat(full);
|
|
82301
83114
|
if (stat8.mtimeMs > latestMtime) {
|
|
82302
83115
|
latestMtime = stat8.mtimeMs;
|
|
82303
83116
|
latest = full;
|
|
@@ -82309,7 +83122,7 @@ async function handleKrakenWorkbench(ctx) {
|
|
|
82309
83122
|
appendSystem(ctx.setMessages, "[kraken workbench] no workbench file found (.zelari/radio/workbench-*.md)");
|
|
82310
83123
|
return;
|
|
82311
83124
|
}
|
|
82312
|
-
const content = await
|
|
83125
|
+
const content = await fs39.readFile(latest, "utf8");
|
|
82313
83126
|
const parsed = parseWorkbench(content);
|
|
82314
83127
|
const rendered = formatWorkbenchForTerminal(parsed);
|
|
82315
83128
|
if (!rendered.trim()) {
|
|
@@ -82623,20 +83436,20 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
|
|
|
82623
83436
|
// src/cli/slashHandlers/promoteMember.ts
|
|
82624
83437
|
init_messageHelpers();
|
|
82625
83438
|
init_paths();
|
|
82626
|
-
import { promises as
|
|
83439
|
+
import { promises as fs40 } from "node:fs";
|
|
82627
83440
|
import path85 from "node:path";
|
|
82628
83441
|
async function handlePromoteMember(ctx, memberId) {
|
|
82629
83442
|
try {
|
|
82630
83443
|
const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
82631
83444
|
const { skill, markdown } = promoteMember2(memberId);
|
|
82632
83445
|
const skillDir = skillsDir();
|
|
82633
|
-
await
|
|
83446
|
+
await fs40.mkdir(skillDir, { recursive: true });
|
|
82634
83447
|
const filePath = path85.join(skillDir, `${skill.id}.md`);
|
|
82635
|
-
const previous = await
|
|
82636
|
-
const { createHash:
|
|
82637
|
-
const sha = (s) =>
|
|
83448
|
+
const previous = await fs40.readFile(filePath, "utf8").catch(() => null);
|
|
83449
|
+
const { createHash: createHash25 } = await import("node:crypto");
|
|
83450
|
+
const sha = (s) => createHash25("sha256").update(s, "utf8").digest("hex");
|
|
82638
83451
|
const lineage = `<!-- lineage: genome=sha256:${sha(markdown)} parent=${previous ? `sha256:${sha(previous)}` : "none"} promotedBy=user promotedAt=${(/* @__PURE__ */ new Date()).toISOString()} -->`;
|
|
82639
|
-
await
|
|
83452
|
+
await fs40.writeFile(filePath, `${markdown}
|
|
82640
83453
|
${lineage}
|
|
82641
83454
|
`, "utf8");
|
|
82642
83455
|
appendSystem(
|
|
@@ -82656,7 +83469,7 @@ ${lineage}
|
|
|
82656
83469
|
|
|
82657
83470
|
// src/cli/branchManager.ts
|
|
82658
83471
|
init_paths();
|
|
82659
|
-
import { promises as
|
|
83472
|
+
import { promises as fs41, existsSync as existsSync55, readFileSync as readFileSync41, writeFileSync as writeFileSync24, mkdirSync as mkdirSync21, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
|
|
82660
83473
|
import path86 from "node:path";
|
|
82661
83474
|
var META_FILENAME = "meta.json";
|
|
82662
83475
|
var SESSIONS_SUBDIR = "sessions";
|
|
@@ -82704,7 +83517,7 @@ function writeBranchMeta(name, baseDir, meta3) {
|
|
|
82704
83517
|
async function countSessions(name, baseDir) {
|
|
82705
83518
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
82706
83519
|
try {
|
|
82707
|
-
const entries = await
|
|
83520
|
+
const entries = await fs41.readdir(sessionsPath);
|
|
82708
83521
|
return entries.filter((e) => e.endsWith(".jsonl")).length;
|
|
82709
83522
|
} catch (err) {
|
|
82710
83523
|
if (err.code === "ENOENT") return 0;
|
|
@@ -82757,7 +83570,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
82757
83570
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
82758
83571
|
mkdirSync21(branchSessionsPath, { recursive: true });
|
|
82759
83572
|
const destPath = path86.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
82760
|
-
await
|
|
83573
|
+
await fs41.copyFile(sourcePath, destPath);
|
|
82761
83574
|
const meta3 = {
|
|
82762
83575
|
name,
|
|
82763
83576
|
createdAt: Date.now(),
|
|
@@ -82775,7 +83588,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
82775
83588
|
async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
82776
83589
|
let entries;
|
|
82777
83590
|
try {
|
|
82778
|
-
entries = await
|
|
83591
|
+
entries = await fs41.readdir(baseDir);
|
|
82779
83592
|
} catch (err) {
|
|
82780
83593
|
if (err.code === "ENOENT") return [];
|
|
82781
83594
|
throw err;
|
|
@@ -82859,7 +83672,7 @@ async function handleBranchCheckout(ctx, branchName) {
|
|
|
82859
83672
|
|
|
82860
83673
|
// src/cli/slashHandlers/workspace.ts
|
|
82861
83674
|
init_messageHelpers();
|
|
82862
|
-
import { promises as
|
|
83675
|
+
import { promises as fs42 } from "node:fs";
|
|
82863
83676
|
import path87 from "node:path";
|
|
82864
83677
|
async function handleWorkspaceShow(ctx, what) {
|
|
82865
83678
|
try {
|
|
@@ -82869,7 +83682,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
82869
83682
|
case "plan": {
|
|
82870
83683
|
const planPath = path87.join(zelari, "plan.md");
|
|
82871
83684
|
try {
|
|
82872
|
-
content = await
|
|
83685
|
+
content = await fs42.readFile(planPath, "utf-8");
|
|
82873
83686
|
} catch {
|
|
82874
83687
|
content = "(no plan.md yet \u2014 run a council session first)";
|
|
82875
83688
|
}
|
|
@@ -82878,7 +83691,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
82878
83691
|
case "decisions": {
|
|
82879
83692
|
const decisionsDir = path87.join(zelari, "decisions");
|
|
82880
83693
|
try {
|
|
82881
|
-
const files = (await
|
|
83694
|
+
const files = (await fs42.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
82882
83695
|
if (files.length === 0) {
|
|
82883
83696
|
content = "(no ADRs yet \u2014 invoke /council to generate some)";
|
|
82884
83697
|
} else {
|
|
@@ -82886,7 +83699,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
82886
83699
|
`];
|
|
82887
83700
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
82888
83701
|
for (const f of files) {
|
|
82889
|
-
const raw = await
|
|
83702
|
+
const raw = await fs42.readFile(path87.join(decisionsDir, f), "utf-8");
|
|
82890
83703
|
const { meta: meta3, body } = parseFrontmatter2(raw);
|
|
82891
83704
|
const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
|
|
82892
83705
|
lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
|
|
@@ -82901,7 +83714,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
82901
83714
|
case "risks": {
|
|
82902
83715
|
const risksPath = path87.join(zelari, "risks.md");
|
|
82903
83716
|
try {
|
|
82904
|
-
content = await
|
|
83717
|
+
content = await fs42.readFile(risksPath, "utf-8");
|
|
82905
83718
|
} catch {
|
|
82906
83719
|
content = "(no risks.md yet)";
|
|
82907
83720
|
}
|
|
@@ -82910,7 +83723,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
82910
83723
|
case "agents": {
|
|
82911
83724
|
const agentsPath = path87.join(process.cwd(), "AGENTS.MD");
|
|
82912
83725
|
try {
|
|
82913
|
-
content = await
|
|
83726
|
+
content = await fs42.readFile(agentsPath, "utf-8");
|
|
82914
83727
|
} catch {
|
|
82915
83728
|
content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
|
|
82916
83729
|
}
|
|
@@ -82919,7 +83732,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
82919
83732
|
case "docs": {
|
|
82920
83733
|
const docsDir = path87.join(zelari, "docs");
|
|
82921
83734
|
try {
|
|
82922
|
-
const files = (await
|
|
83735
|
+
const files = (await fs42.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
82923
83736
|
content = files.length ? `# Docs (${files.length})
|
|
82924
83737
|
|
|
82925
83738
|
` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
|
|
@@ -82960,7 +83773,7 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
82960
83773
|
}
|
|
82961
83774
|
try {
|
|
82962
83775
|
const target = path87.join(process.cwd(), ".zelari");
|
|
82963
|
-
await
|
|
83776
|
+
await fs42.rm(target, { recursive: true, force: true });
|
|
82964
83777
|
appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
|
|
82965
83778
|
} catch (err) {
|
|
82966
83779
|
appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -82971,13 +83784,13 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
82971
83784
|
init_provider2();
|
|
82972
83785
|
|
|
82973
83786
|
// src/cli/skillHistory.ts
|
|
82974
|
-
import { promises as
|
|
83787
|
+
import { promises as fs43, existsSync as existsSync56, statSync as statSync8, renameSync as renameSync6, appendFileSync as appendFileSync5, mkdirSync as mkdirSync22 } from "node:fs";
|
|
82975
83788
|
init_paths();
|
|
82976
83789
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
82977
83790
|
async function readSkillHistory(file2) {
|
|
82978
83791
|
let raw = "";
|
|
82979
83792
|
try {
|
|
82980
|
-
raw = await
|
|
83793
|
+
raw = await fs43.readFile(file2, "utf-8");
|
|
82981
83794
|
} catch {
|
|
82982
83795
|
return [];
|
|
82983
83796
|
}
|