zelari-code 2.37.3 → 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.
Files changed (41) hide show
  1. package/dist/cli/asyncLimit.js +53 -0
  2. package/dist/cli/asyncLimit.js.map +1 -0
  3. package/dist/cli/budget/restoreRuntime.js +10 -5
  4. package/dist/cli/budget/restoreRuntime.js.map +1 -1
  5. package/dist/cli/crossProviderFailover.js +32 -0
  6. package/dist/cli/crossProviderFailover.js.map +1 -1
  7. package/dist/cli/harnessState.js +7 -3
  8. package/dist/cli/harnessState.js.map +1 -1
  9. package/dist/cli/headlessSpine.js +7 -3
  10. package/dist/cli/headlessSpine.js.map +1 -1
  11. package/dist/cli/kraken/cachedShell.js +162 -0
  12. package/dist/cli/kraken/cachedShell.js.map +1 -0
  13. package/dist/cli/kraken/contractCompiler.js +6 -1
  14. package/dist/cli/kraken/contractCompiler.js.map +1 -1
  15. package/dist/cli/kraken/executor.js +27 -17
  16. package/dist/cli/kraken/executor.js.map +1 -1
  17. package/dist/cli/kraken/nativeVerification.js +9 -1
  18. package/dist/cli/kraken/nativeVerification.js.map +1 -1
  19. package/dist/cli/kraken/worktreeCleanupBatch.js +110 -0
  20. package/dist/cli/kraken/worktreeCleanupBatch.js.map +1 -0
  21. package/dist/cli/main.bundled.js +1204 -468
  22. package/dist/cli/main.bundled.js.map +4 -4
  23. package/dist/cli/memory/legacyImport.js +66 -14
  24. package/dist/cli/memory/legacyImport.js.map +1 -1
  25. package/dist/cli/memory/sqliteBackend.js +19 -5
  26. package/dist/cli/memory/sqliteBackend.js.map +1 -1
  27. package/dist/cli/providerFailover.js +21 -2
  28. package/dist/cli/providerFailover.js.map +1 -1
  29. package/dist/cli/runHeadless.js +32 -1
  30. package/dist/cli/runHeadless.js.map +1 -1
  31. package/dist/cli/sessionSpine.js +26 -10
  32. package/dist/cli/sessionSpine.js.map +1 -1
  33. package/dist/cli/toolRegistry.js +23 -4
  34. package/dist/cli/toolRegistry.js.map +1 -1
  35. package/dist/cli/tools/krakenModel.js +72 -9
  36. package/dist/cli/tools/krakenModel.js.map +1 -1
  37. package/dist/cli/tools/krakenRadio.js +60 -3
  38. package/dist/cli/tools/krakenRadio.js.map +1 -1
  39. package/dist/cli/tools/krakenWorktree.js +105 -4
  40. package/dist/cli/tools/krakenWorktree.js.map +1 -1
  41. package/package.json +3 -2
@@ -19560,11 +19560,11 @@ var init_listFiles = __esm({
19560
19560
  return 1;
19561
19561
  return a.name.localeCompare(b.name);
19562
19562
  });
19563
- const MAX_ENTRIES2 = 500;
19564
- const truncated = entries.length > MAX_ENTRIES2;
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, MAX_ENTRIES2) : entries, truncated }, {
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 cloneMessages(messages) {
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 systemMessages = cloneMessages(params.messages.slice(0, split));
22482
- const conversation = cloneMessages(params.messages.slice(split));
22483
- const tools = canonicalTools(params.tools).map((t) => structuredClone(t));
22484
- const header = stableStringify({
22485
- provider: params.provider,
22486
- model: params.model,
22487
- systemMessages,
22488
- tools
22489
- });
22490
- const request = stableStringify({
22491
- provider: params.provider,
22492
- model: params.model,
22493
- systemMessages,
22494
- tools,
22495
- conversation
22496
- });
22497
- return {
22498
- provider: params.provider,
22499
- model: params.model,
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
- headerFingerprint: sha256Hex(header),
22504
- requestFingerprint: sha256Hex(request),
22505
- createdAt: Date.now()
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
- let expected = 1;
23526
- const lines = content.split("\n");
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 { path: filePath, events, issues, ok: issues.length === 0 };
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 fs48 = options.fs ?? new NodeFsProvider(workspace);
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: fs48,
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
- for (const criterion of criteria) {
25616
- results.push(await this.evaluateOne(criterion, context.scope));
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 sha256 = this.options.sha256 ?? defaultSha256;
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 = sha256(result.stdout);
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 done({ status: "unknown", evidence, detail: `command timed out (${check2.timeoutMs ?? "default"}ms)` });
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 done({
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 done({
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 done({ status: "pass", evidence });
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, sha256, content, extra = {}) {
25758
- const digest = sha256 && content !== void 0 ? sha256(content) : void 0;
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 sha256 = this.options.sha256 ?? defaultSha256;
25770
- const fs48 = this.services.fs;
25771
- if (!fs48)
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 fs48.exists(check2.path);
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 fs48.readFile(check2.path).catch(() => "");
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, sha256, content, { exists: true })]
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 fs48 = this.services.fs;
25786
- if (!fs48)
25924
+ const fs49 = this.services.fs;
25925
+ if (!fs49)
25787
25926
  return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
25788
- const exists = await fs48.exists(check2.path);
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 sha256 = this.options.sha256 ?? defaultSha256;
25800
- const fs48 = this.services.fs;
25801
- if (!fs48)
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 fs48.readFile(check2.path);
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, sha256, content)];
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 createHash9 } from "node:crypto";
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 createHash9("sha256").update(input).digest("hex");
27562
+ return createHash10("sha256").update(input).digest("hex");
27322
27563
  }
27323
27564
  function matchNoteToToolTrace(note, trace) {
27324
27565
  const n = normalize3(note);
@@ -29729,6 +29970,8 @@ ${shared.content}`,
29729
29970
  emitSnapshot(tools, generation, messages = this.messagesForProvider()) {
29730
29971
  if (!this.config.onRequestSnapshot)
29731
29972
  return;
29973
+ if (resolveRequestSnapshotMode() === "off")
29974
+ return;
29732
29975
  try {
29733
29976
  this.config.onRequestSnapshot(createRoutedRequestSnapshot({
29734
29977
  messages,
@@ -31022,6 +31265,7 @@ __export(harness_exports, {
31022
31265
  TEXT_TOOLS_PARTIAL_USER: () => TEXT_TOOLS_PARTIAL_USER,
31023
31266
  TOOL_CALL_TRUNCATED_RECOVERY_MARKER: () => TOOL_CALL_TRUNCATED_RECOVERY_MARKER,
31024
31267
  TOOL_CALL_TRUNCATED_RECOVERY_USER: () => TOOL_CALL_TRUNCATED_RECOVERY_USER,
31268
+ __resetRequestSnapshotMemoForTests: () => __resetRequestSnapshotMemoForTests,
31025
31269
  canonicalTools: () => canonicalTools,
31026
31270
  collapseLoopedAssistantText: () => collapseLoopedAssistantText,
31027
31271
  compareReplayPrefix: () => compareReplayPrefix,
@@ -31044,6 +31288,7 @@ __export(harness_exports, {
31044
31288
  recordRequest: () => recordRequest,
31045
31289
  recordToolResult: () => recordToolResult,
31046
31290
  recordUsage: () => recordUsage,
31291
+ resolveRequestSnapshotMode: () => resolveRequestSnapshotMode,
31047
31292
  runExtensionPreToolUse: () => runExtensionPreToolUse,
31048
31293
  sha256Hex: () => sha256Hex,
31049
31294
  splitHookCommandLine: () => splitHookCommandLine,
@@ -37380,6 +37625,146 @@ var init_agentAdapter = __esm({
37380
37625
  }
37381
37626
  });
37382
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
+
37383
37768
  // packages/core/dist/session/lineage.js
37384
37769
  async function forkSession(store6, parentSessionId, options = {}) {
37385
37770
  const parent = await store6.read(parentSessionId);
@@ -37943,6 +38328,7 @@ var init_session = __esm({
37943
38328
  init_agentAdapter();
37944
38329
  init_writer();
37945
38330
  init_replay();
38331
+ init_replayCache();
37946
38332
  init_store();
37947
38333
  init_lineage();
37948
38334
  init_exportSession();
@@ -38436,12 +38822,12 @@ var CORE_VERSION;
38436
38822
  var init_version = __esm({
38437
38823
  "packages/core/dist/version.js"() {
38438
38824
  "use strict";
38439
- CORE_VERSION = "2.37.3";
38825
+ CORE_VERSION = "2.38.0";
38440
38826
  }
38441
38827
  });
38442
38828
 
38443
38829
  // packages/core/dist/runtime/fingerprints.js
38444
- import { createHash as createHash10 } from "node:crypto";
38830
+ import { createHash as createHash11 } from "node:crypto";
38445
38831
  function toolFingerprintHash(tools) {
38446
38832
  const canonical = [...tools].map((t) => ({
38447
38833
  name: t.name,
@@ -38450,7 +38836,7 @@ function toolFingerprintHash(tools) {
38450
38836
  ...t.outputContractVersion !== void 0 ? { outputContractVersion: t.outputContractVersion } : {},
38451
38837
  ...t.capabilityFlags !== void 0 ? { capabilityFlags: [...t.capabilityFlags].sort() } : {}
38452
38838
  })).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
38453
- return createHash10("sha256").update(stableStringify(canonical)).digest("hex");
38839
+ return createHash11("sha256").update(stableStringify(canonical)).digest("hex");
38454
38840
  }
38455
38841
  function skillFingerprintHash(skills) {
38456
38842
  const canonical = [...skills].map((s) => ({
@@ -38458,7 +38844,7 @@ function skillFingerprintHash(skills) {
38458
38844
  ...s.version !== void 0 ? { version: s.version } : {},
38459
38845
  ...s.contentDigest !== void 0 ? { contentDigest: s.contentDigest } : {}
38460
38846
  })).sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
38461
- return createHash10("sha256").update(stableStringify(canonical)).digest("hex");
38847
+ return createHash11("sha256").update(stableStringify(canonical)).digest("hex");
38462
38848
  }
38463
38849
  var init_fingerprints = __esm({
38464
38850
  "packages/core/dist/runtime/fingerprints.js"() {
@@ -38496,6 +38882,7 @@ __export(dist_exports, {
38496
38882
  CommandCheckSchema: () => CommandCheckSchema,
38497
38883
  CriterionSchema: () => CriterionSchema,
38498
38884
  CriterionSourceSchema: () => CriterionSourceSchema,
38885
+ DEFAULT_COMMAND_CONCURRENCY: () => DEFAULT_COMMAND_CONCURRENCY,
38499
38886
  DEFAULT_CONTEXT_POLICY: () => DEFAULT_CONTEXT_POLICY,
38500
38887
  DEFAULT_HEARTBEAT_STALE_MS: () => DEFAULT_HEARTBEAT_STALE_MS,
38501
38888
  DEFAULT_MAX_NODES: () => DEFAULT_MAX_NODES,
@@ -38622,6 +39009,7 @@ __export(dist_exports, {
38622
39009
  SessionActorSchema: () => SessionActorSchema,
38623
39010
  SessionEventEnvelopeSchema: () => SessionEventEnvelopeSchema,
38624
39011
  SessionJsonlWriter: () => SessionJsonlWriter,
39012
+ SessionLogCache: () => SessionLogCache,
38625
39013
  SessionLogLockedError: () => SessionLogLockedError,
38626
39014
  SessionLogWriter: () => SessionLogWriter,
38627
39015
  SessionStore: () => SessionStore,
@@ -38660,6 +39048,7 @@ __export(dist_exports, {
38660
39048
  WorkspacePathEscapeError: () => WorkspacePathEscapeError,
38661
39049
  WorktreeWorkspace: () => WorktreeWorkspace,
38662
39050
  ZELARI_CODING_PACK_ID: () => ZELARI_CODING_PACK_ID,
39051
+ __resetRequestSnapshotMemoForTests: () => __resetRequestSnapshotMemoForTests,
38663
39052
  analyzeScope: () => analyzeScope,
38664
39053
  applyCompletionRetry: () => applyCompletionRetry,
38665
39054
  applyDeterministicAutofix: () => applyDeterministicAutofix,
@@ -38821,6 +39210,7 @@ __export(dist_exports, {
38821
39210
  isFollowUpControlEvent: () => isFollowUpControlEvent,
38822
39211
  isGeneratedPath: () => isGeneratedPath,
38823
39212
  isModelSurfaceEvent: () => isModelSurfaceEvent,
39213
+ isReplayCacheEnabled: () => isReplayCacheEnabled,
38824
39214
  isReviewerKind: () => isReviewerKind,
38825
39215
  isSearchTool: () => isSearchTool,
38826
39216
  isSeqShadowed: () => isSeqShadowed,
@@ -38829,6 +39219,7 @@ __export(dist_exports, {
38829
39219
  isSteerControlEvent: () => isSteerControlEvent,
38830
39220
  isValidTool: () => isValidTool,
38831
39221
  isVerificationReserveProtected: () => isVerificationReserveProtected,
39222
+ isVerifyParallelEnabled: () => isVerifyParallelEnabled,
38832
39223
  isVerifyToolCheckSkipped: () => isVerifyToolCheckSkipped,
38833
39224
  jaccardSimilarity: () => jaccardSimilarity,
38834
39225
  jsonBytes: () => jsonBytes,
@@ -38867,6 +39258,8 @@ __export(dist_exports, {
38867
39258
  parseNameOnlyDiff: () => parseNameOnlyDiff,
38868
39259
  parsePersonaVerdict: () => parsePersonaVerdict,
38869
39260
  parseProjectRootFromWorkspaceContext: () => parseProjectRootFromWorkspaceContext,
39261
+ parseSessionLogLines: () => parseSessionLogLines,
39262
+ parseSessionLogText: () => parseSessionLogText,
38870
39263
  parseTextToolCalls: () => parseTextToolCalls,
38871
39264
  parseTextToolCallsDetailed: () => parseTextToolCallsDetailed,
38872
39265
  parseThinking: () => parseThinking,
@@ -38884,6 +39277,7 @@ __export(dist_exports, {
38884
39277
  readLessonsDeduped: () => readLessonsDeduped,
38885
39278
  readSession: () => readSession,
38886
39279
  readSessionLog: () => readSessionLog,
39280
+ readSessionLogCached: () => readSessionLogCached,
38887
39281
  recallLessons: () => recallLessons,
38888
39282
  recencyScore: () => recencyScore,
38889
39283
  recordRequest: () => recordRequest,
@@ -38900,6 +39294,7 @@ __export(dist_exports, {
38900
39294
  renderSteers: () => renderSteers,
38901
39295
  replayChairmanTextTools: () => replayChairmanTextTools,
38902
39296
  resolveAgentSkills: () => resolveAgentSkills,
39297
+ resolveCommandConcurrency: () => resolveCommandConcurrency,
38903
39298
  resolveCouncilRunMode: () => resolveCouncilRunMode,
38904
39299
  resolveHeartbeatStaleMs: () => resolveHeartbeatStaleMs,
38905
39300
  resolveInterventions: () => resolveInterventions,
@@ -38907,6 +39302,7 @@ __export(dist_exports, {
38907
39302
  resolveMaxTentacles: () => resolveMaxTentacles,
38908
39303
  resolvePlanTimeoutMs: () => resolvePlanTimeoutMs,
38909
39304
  resolveProfile: () => resolveProfile,
39305
+ resolveRequestSnapshotMode: () => resolveRequestSnapshotMode,
38910
39306
  resolveResponseLanguage: () => resolveResponseLanguage,
38911
39307
  resolveRoleSystemPrompt: () => resolveRoleSystemPrompt,
38912
39308
  resolveSessionsDir: () => resolveSessionsDir,
@@ -39141,7 +39537,7 @@ var init_graphStatus = __esm({
39141
39537
  });
39142
39538
 
39143
39539
  // src/cli/sessionManager.ts
39144
- import { promises as fs14, existsSync as existsSync13, readFileSync as readFileSync15, writeFileSync as writeFileSync11, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, statSync } from "node:fs";
39540
+ import { promises as fs15, existsSync as existsSync13, readFileSync as readFileSync15, writeFileSync as writeFileSync11, mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, statSync } from "node:fs";
39145
39541
  import path30 from "node:path";
39146
39542
  import { randomUUID as randomUUID2 } from "node:crypto";
39147
39543
  function getSessionBaseDir() {
@@ -39151,7 +39547,7 @@ function getCurrentSessionFile() {
39151
39547
  return currentSessionPath();
39152
39548
  }
39153
39549
  async function ensureSessionDir() {
39154
- await fs14.mkdir(getSessionBaseDir(), { recursive: true });
39550
+ await fs15.mkdir(getSessionBaseDir(), { recursive: true });
39155
39551
  }
39156
39552
  function getCurrentSessionId() {
39157
39553
  const file2 = getCurrentSessionFile();
@@ -39201,7 +39597,7 @@ async function listSessions() {
39201
39597
  const baseDir = getSessionBaseDir();
39202
39598
  let entries;
39203
39599
  try {
39204
- entries = await fs14.readdir(baseDir);
39600
+ entries = await fs15.readdir(baseDir);
39205
39601
  } catch (err) {
39206
39602
  if (err.code === "ENOENT") return [];
39207
39603
  throw err;
@@ -39591,16 +39987,16 @@ var init_budgetRuntime = __esm({
39591
39987
 
39592
39988
  // src/cli/budget/restoreRuntime.ts
39593
39989
  import path31 from "node:path";
39594
- async function restoreBudgetRuntimeFromSession(budget, sessionId2, baseDir) {
39990
+ async function restoreBudgetRuntimeFromSession(budget, sessionId2, baseDir, cache4) {
39595
39991
  const eventsPath = path31.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
39596
- const report = await readSessionLog(eventsPath).catch(() => null);
39992
+ const report = await readSessionLogCached(eventsPath, cache4).catch(() => null);
39597
39993
  if (!report || report.events.length === 0) return false;
39598
39994
  budget.adoptLedgerFromEvents(report.events);
39599
39995
  return true;
39600
39996
  }
39601
- async function lastHarnessManifestHash(sessionId2, baseDir) {
39997
+ async function lastHarnessManifestHash(sessionId2, baseDir, cache4) {
39602
39998
  const eventsPath = path31.join(resolveSessionsDir({ baseDir }), sessionId2, "events.jsonl");
39603
- const report = await readSessionLog(eventsPath).catch(() => null);
39999
+ const report = await readSessionLogCached(eventsPath, cache4).catch(() => null);
39604
40000
  if (!report) return null;
39605
40001
  for (let i = report.events.length - 1; i >= 0; i--) {
39606
40002
  const e = report.events[i];
@@ -40066,7 +40462,7 @@ async function wrapSessionWriter(inner, sessionId2, options = {}) {
40066
40462
  enforcement: resolveResourceEnforcement()
40067
40463
  });
40068
40464
  if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
40069
- await restoreBudgetRuntimeFromSession(budget, sessionId2, options.baseDir);
40465
+ await restoreBudgetRuntimeFromSession(budget, sessionId2, options.baseDir, spine.replayCache);
40070
40466
  }
40071
40467
  spine.attachBudgetRuntime(budget);
40072
40468
  await noteHarnessLifecycle(
@@ -40097,7 +40493,7 @@ async function noteHarnessLifecycle(spine, sessionId2, profileId, budget, baseDi
40097
40493
  resourcePolicy: budget.policy
40098
40494
  });
40099
40495
  if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
40100
- if (await lastHarnessManifestHash(sessionId2, baseDir) === null) {
40496
+ if (await lastHarnessManifestHash(sessionId2, baseDir, spine.replayCache) === null) {
40101
40497
  spine.harnessManifest(manifest, manifestHash);
40102
40498
  }
40103
40499
  } else {
@@ -40147,6 +40543,13 @@ var init_sessionSpine = __esm({
40147
40543
  /** Seq the log continued from when adopting an existing session. */
40148
40544
  resumedFromSeq;
40149
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();
40150
40553
  /**
40151
40554
  * Adopt a 1.x sessionId into the spine: continue the seq when the log
40152
40555
  * already exists (resume), otherwise start fresh with `session.started`.
@@ -40157,7 +40560,10 @@ var init_sessionSpine = __esm({
40157
40560
  if (!spineEnabled()) return mirror;
40158
40561
  try {
40159
40562
  const sessionDir = path33.join(mirror.sessionsDir, sessionId2);
40160
- const report = await readSessionLog(path33.join(sessionDir, "events.jsonl"));
40563
+ const report = await readSessionLogCached(
40564
+ path33.join(sessionDir, "events.jsonl"),
40565
+ mirror.replayCache
40566
+ );
40161
40567
  const existed = report.events.length > 0 || report.issues.length > 0;
40162
40568
  if (report.events.some((e) => e.kind === "task.contract" || e.kind === "user.message")) {
40163
40569
  mirror.contractSeeded = true;
@@ -40332,8 +40738,9 @@ var init_sessionSpine = __esm({
40332
40738
  */
40333
40739
  async derivedPriorTurns() {
40334
40740
  if (this.status !== "active" && this.status !== "closed") return null;
40335
- const report = await readSessionLog(
40336
- 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
40337
40744
  ).catch(() => null);
40338
40745
  if (!report || report.events.length === 0) return null;
40339
40746
  return deriveMessages(report.events);
@@ -40342,8 +40749,9 @@ var init_sessionSpine = __esm({
40342
40749
  async compactionStateSnapshot(toSeq) {
40343
40750
  if (this.status !== "active" && this.status !== "closed") return null;
40344
40751
  await this.flush();
40345
- const report = await readSessionLog(
40346
- 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
40347
40755
  ).catch(() => null);
40348
40756
  if (!report || report.events.length === 0) return null;
40349
40757
  return buildCompactionStateSnapshot(report.events, toSeq);
@@ -40355,8 +40763,9 @@ var init_sessionSpine = __esm({
40355
40763
  */
40356
40764
  async lastVerificationRun() {
40357
40765
  if (this.status !== "active" && this.status !== "closed") return null;
40358
- const report = await readSessionLog(
40359
- 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
40360
40769
  ).catch(() => null);
40361
40770
  if (!report) return null;
40362
40771
  return lastVerificationRun(report.events);
@@ -40492,7 +40901,7 @@ var init_sessionSpine = __esm({
40492
40901
  seq = seq.then(async (s) => {
40493
40902
  try {
40494
40903
  const eventsPath = path33.join(this.sessionsDir, this.sessionId, "events.jsonl");
40495
- const report = await readSessionLog(eventsPath).catch(() => null);
40904
+ const report = await readSessionLogCached(eventsPath, this.replayCache).catch(() => null);
40496
40905
  if (!report || typeof s !== "number") return s;
40497
40906
  const current = latestTaskContract(report.events);
40498
40907
  if (!current) return s;
@@ -40760,7 +41169,7 @@ async function loadObservationIndex(sessionId2, baseDir) {
40760
41169
  mtimeMs = 0;
40761
41170
  }
40762
41171
  }
40763
- const hit = cache.get(sessionId2);
41172
+ const hit = cache2.get(sessionId2);
40764
41173
  if (hit && !exists) return hit;
40765
41174
  if (hit && hit.filePath === filePath && hit.mtimeMs === mtimeMs) return hit;
40766
41175
  const events = existsSync15(filePath) ? await readSession(filePath) : [];
@@ -40789,12 +41198,12 @@ async function loadObservationIndex(sessionId2, baseDir) {
40789
41198
  if (e.toolCallId) byToolCallId.set(e.toolCallId, seq);
40790
41199
  }
40791
41200
  const index = { filePath, mtimeMs, bySeq, byToolCallId, names };
40792
- cache.set(sessionId2, index);
41201
+ cache2.set(sessionId2, index);
40793
41202
  return index;
40794
41203
  }
40795
41204
  function invalidateObservationIndex(sessionId2) {
40796
- if (sessionId2) cache.delete(sessionId2);
40797
- else cache.clear();
41205
+ if (sessionId2) cache2.delete(sessionId2);
41206
+ else cache2.clear();
40798
41207
  }
40799
41208
  async function getObservationBySeq(sessionId2, seq, baseDir) {
40800
41209
  const index = await loadObservationIndex(sessionId2, baseDir);
@@ -40802,7 +41211,7 @@ async function getObservationBySeq(sessionId2, seq, baseDir) {
40802
41211
  }
40803
41212
  function lookupSeqSync(sessionId2, toolCallId, baseDir) {
40804
41213
  const filePath = sessionFilePath(sessionId2, baseDir);
40805
- const hit = cache.get(sessionId2);
41214
+ const hit = cache2.get(sessionId2);
40806
41215
  if (hit && hit.filePath === filePath) return hit.byToolCallId.get(toolCallId);
40807
41216
  return void 0;
40808
41217
  }
@@ -40817,10 +41226,10 @@ function emptyIndex(sessionId2, baseDir) {
40817
41226
  }
40818
41227
  function ingestLiveEvent(sessionId2, event, baseDir) {
40819
41228
  if (!sessionId2) return;
40820
- let index = cache.get(sessionId2);
41229
+ let index = cache2.get(sessionId2);
40821
41230
  if (!index) {
40822
41231
  index = emptyIndex(sessionId2, baseDir);
40823
- cache.set(sessionId2, index);
41232
+ cache2.set(sessionId2, index);
40824
41233
  }
40825
41234
  if (isToolStart(event)) {
40826
41235
  index.names.set(event.toolCallId, event.toolName);
@@ -40848,19 +41257,19 @@ function applySessionSurface(messages) {
40848
41257
  const lookup = sid ? (id3) => lookupSeqSync(sid, id3) : void 0;
40849
41258
  return projectSessionSurface(messages, void 0, lookup).messages;
40850
41259
  }
40851
- var cache;
41260
+ var cache2;
40852
41261
  var init_observationStore = __esm({
40853
41262
  "src/cli/hooks/observationStore.ts"() {
40854
41263
  "use strict";
40855
41264
  init_harness();
40856
41265
  init_sessionManager();
40857
41266
  init_sessionSurface();
40858
- cache = /* @__PURE__ */ new Map();
41267
+ cache2 = /* @__PURE__ */ new Map();
40859
41268
  }
40860
41269
  });
40861
41270
 
40862
41271
  // packages/core/dist/core/tools/toolOutputSpill.js
40863
- import { createHash as createHash11, randomBytes as randomBytes3 } from "node:crypto";
41272
+ import { createHash as createHash12, randomBytes as randomBytes3 } from "node:crypto";
40864
41273
  import { existsSync as existsSync16, mkdirSync as mkdirSync7, writeFileSync as writeFileSync12 } from "node:fs";
40865
41274
  import { homedir as homedir5, tmpdir as tmpdir2 } from "node:os";
40866
41275
  import { join as join14 } from "node:path";
@@ -40890,7 +41299,7 @@ function spillToolOutput(fullText, meta3) {
40890
41299
  if (!existsSync16(dir)) {
40891
41300
  mkdirSync7(dir, { recursive: true });
40892
41301
  }
40893
- const hash3 = createHash11("sha256").update(fullText).digest("hex").slice(0, 12);
41302
+ const hash3 = createHash12("sha256").update(fullText).digest("hex").slice(0, 12);
40894
41303
  const stamp = Date.now().toString(36);
40895
41304
  const rnd = randomBytes3(3).toString("hex");
40896
41305
  const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
@@ -41193,7 +41602,7 @@ var init_registry2 = __esm({
41193
41602
 
41194
41603
  // src/cli/safety/sandboxPath.ts
41195
41604
  import path35 from "node:path";
41196
- import fs15 from "node:fs";
41605
+ import fs16 from "node:fs";
41197
41606
  function normalizedCase(p3) {
41198
41607
  return IS_CASE_FOLDING ? p3.toLowerCase() : p3;
41199
41608
  }
@@ -41227,7 +41636,7 @@ function assertRealAncestorContained(resolvedLexical, realRoot, userPath) {
41227
41636
  for (; ; ) {
41228
41637
  if (probe === path35.dirname(probe)) break;
41229
41638
  try {
41230
- realProbe = fs15.realpathSync(probe);
41639
+ realProbe = fs16.realpathSync(probe);
41231
41640
  break;
41232
41641
  } catch (err) {
41233
41642
  if (err?.code === "ENOENT") {
@@ -41255,7 +41664,7 @@ function resolveSandboxedCore(userPath, options = {}) {
41255
41664
  assertLexicalContainment(resolved, root, userPath);
41256
41665
  let realRoot = null;
41257
41666
  try {
41258
- realRoot = fs15.realpathSync(root);
41667
+ realRoot = fs16.realpathSync(root);
41259
41668
  } catch {
41260
41669
  return resolved;
41261
41670
  }
@@ -41274,7 +41683,7 @@ function verifyContainment(resolvedAbsolute, options = {}) {
41274
41683
  assertLexicalContainment(resolved, root, resolvedAbsolute);
41275
41684
  let realRoot = null;
41276
41685
  try {
41277
- realRoot = fs15.realpathSync(root);
41686
+ realRoot = fs16.realpathSync(root);
41278
41687
  } catch {
41279
41688
  return;
41280
41689
  }
@@ -41298,7 +41707,7 @@ var init_sandboxPath = __esm({
41298
41707
  });
41299
41708
 
41300
41709
  // src/cli/tools/krakenRadio.ts
41301
- 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";
41302
41711
  import path36 from "node:path";
41303
41712
  function radioDir(cwd) {
41304
41713
  return path36.join(cwd, ".zelari", "radio");
@@ -41307,6 +41716,35 @@ function radioPath(cwd, sessionId2) {
41307
41716
  const safe = (sessionId2 || "default").replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
41308
41717
  return path36.join(radioDir(cwd), `${safe}.jsonl`);
41309
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
+ }
41310
41748
  function appendKrakenRadio(cwd, sessionId2, event) {
41311
41749
  try {
41312
41750
  const dir = radioDir(cwd);
@@ -41332,8 +41770,8 @@ function appendKrakenRadio(cwd, sessionId2, event) {
41332
41770
  ...event.symbolsA !== void 0 ? { symbolsA: event.symbolsA } : {},
41333
41771
  ...event.symbolsB !== void 0 ? { symbolsB: event.symbolsB } : {}
41334
41772
  };
41335
- appendFileSync2(radioPath(cwd, sessionId2), `${JSON.stringify(row)}
41336
- `, "utf8");
41773
+ appendRadioLine(radioPath(cwd, sessionId2), `${JSON.stringify(row)}
41774
+ `);
41337
41775
  } catch {
41338
41776
  }
41339
41777
  }
@@ -41370,9 +41808,12 @@ function formatKrakenRadioStatus(cwd, sessionId2, limit = 12) {
41370
41808
  });
41371
41809
  return [`Kraken radio (last ${events.length}) session=${sessionId2}:`, ...lines].join("\n");
41372
41810
  }
41811
+ var MAX_CACHED_RADIO_FDS, radioFds;
41373
41812
  var init_krakenRadio = __esm({
41374
41813
  "src/cli/tools/krakenRadio.ts"() {
41375
41814
  "use strict";
41815
+ MAX_CACHED_RADIO_FDS = 32;
41816
+ radioFds = /* @__PURE__ */ new Map();
41376
41817
  }
41377
41818
  });
41378
41819
 
@@ -41386,7 +41827,7 @@ import {
41386
41827
  realpathSync
41387
41828
  } from "node:fs";
41388
41829
  import { join as join15, basename } from "node:path";
41389
- import { createHash as createHash12 } from "node:crypto";
41830
+ import { createHash as createHash13 } from "node:crypto";
41390
41831
  function resolveWorkspaceRoot(projectRoot = process.cwd()) {
41391
41832
  const candidates = [
41392
41833
  join15(projectRoot, ".zelari"),
@@ -41402,7 +41843,7 @@ function resolveWorkspaceRoot(projectRoot = process.cwd()) {
41402
41843
  return candidates[0];
41403
41844
  }
41404
41845
  function hashProject(projectPath) {
41405
- return createHash12("sha1").update(realpathSync(projectPath)).digest("hex").slice(0, 12);
41846
+ return createHash13("sha1").update(realpathSync(projectPath)).digest("hex").slice(0, 12);
41406
41847
  }
41407
41848
  function isWritableDir(dir) {
41408
41849
  try {
@@ -42127,12 +42568,12 @@ var init_taskTouchGuard = __esm({
42127
42568
  });
42128
42569
 
42129
42570
  // src/cli/gitOps.ts
42130
- import { execFile as execFile2 } from "node:child_process";
42131
- import { promisify } from "node:util";
42571
+ import { execFile as execFile3 } from "node:child_process";
42572
+ import { promisify as promisify2 } from "node:util";
42132
42573
  import path38 from "node:path";
42133
42574
  async function git2(cwd, args) {
42134
42575
  try {
42135
- const { stdout } = await execFileAsync("git", ["-C", cwd, ...args], {
42576
+ const { stdout } = await execFileAsync2("git", ["-C", cwd, ...args], {
42136
42577
  maxBuffer: 16 * 1024 * 1024
42137
42578
  });
42138
42579
  return stdout;
@@ -42184,11 +42625,11 @@ async function undoWorkingChanges(opts = {}) {
42184
42625
  function defaultProjectRoot() {
42185
42626
  return path38.resolve(__dirname, "..", "..", "..");
42186
42627
  }
42187
- var execFileAsync;
42628
+ var execFileAsync2;
42188
42629
  var init_gitOps = __esm({
42189
42630
  "src/cli/gitOps.ts"() {
42190
42631
  "use strict";
42191
- execFileAsync = promisify(execFile2);
42632
+ execFileAsync2 = promisify2(execFile3);
42192
42633
  }
42193
42634
  });
42194
42635
 
@@ -42323,7 +42764,7 @@ var auditLogger_exports = {};
42323
42764
  __export(auditLogger_exports, {
42324
42765
  AuditLogger: () => AuditLogger
42325
42766
  });
42326
- import { promises as fs16 } from "node:fs";
42767
+ import { promises as fs17 } from "node:fs";
42327
42768
  import path39 from "node:path";
42328
42769
  function defaultAuditPath() {
42329
42770
  return auditLogPath();
@@ -42370,8 +42811,8 @@ var init_auditLogger = __esm({
42370
42811
  async append(entry) {
42371
42812
  const line = JSON.stringify(entry) + "\n";
42372
42813
  this.writeQueue = this.writeQueue.then(async () => {
42373
- await fs16.mkdir(path39.dirname(this.logPath), { recursive: true });
42374
- await fs16.appendFile(this.logPath, line, "utf-8");
42814
+ await fs17.mkdir(path39.dirname(this.logPath), { recursive: true });
42815
+ await fs17.appendFile(this.logPath, line, "utf-8");
42375
42816
  });
42376
42817
  return this.writeQueue;
42377
42818
  }
@@ -42590,11 +43031,54 @@ var init_engine2 = __esm({
42590
43031
  }
42591
43032
  });
42592
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
+
42593
43077
  // src/cli/tools/krakenWorktree.ts
42594
- import { execFile as execFile3 } from "node:child_process";
43078
+ import { execFile as execFile4 } from "node:child_process";
42595
43079
  import { existsSync as existsSync24, mkdirSync as mkdirSync12, rmSync } from "node:fs";
42596
43080
  import path41 from "node:path";
42597
- import { promisify as promisify2 } from "node:util";
43081
+ import { promisify as promisify3 } from "node:util";
42598
43082
  import { randomBytes as randomBytes4 } from "node:crypto";
42599
43083
  function isKrakenWorktreeEnabled(env = process.env) {
42600
43084
  const v = (env.ZELARI_KRAKEN_WORKTREE ?? "").trim().toLowerCase();
@@ -42610,9 +43094,29 @@ function isKrakenWorktreeAutoMergeEnabled(env = process.env) {
42610
43094
  if (v === "0" || v === "false" || v === "no" || v === "off") return false;
42611
43095
  return true;
42612
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
+ }
42613
43117
  async function git3(cwd, args) {
42614
43118
  try {
42615
- const { stdout, stderr } = await execFileAsync2("git", ["-C", cwd, ...args], {
43119
+ const { stdout, stderr } = await execFileAsync3("git", ["-C", cwd, ...args], {
42616
43120
  maxBuffer: 16 * 1024 * 1024,
42617
43121
  windowsHide: true
42618
43122
  });
@@ -42628,10 +43132,15 @@ async function git3(cwd, args) {
42628
43132
  }
42629
43133
  }
42630
43134
  async function resolveGitRoot(cwd) {
43135
+ const key = path41.resolve(cwd);
43136
+ const memo = gitRootMemo.get(key);
43137
+ if (memo) return memo;
42631
43138
  const r = await git3(cwd, ["rev-parse", "--show-toplevel"]);
42632
43139
  if (!r.ok) return null;
42633
43140
  const root = r.stdout.trim();
42634
- return root || null;
43141
+ if (!root) return null;
43142
+ gitRootMemo.set(key, root);
43143
+ return root;
42635
43144
  }
42636
43145
  async function createKrakenWorktree(cwd, label) {
42637
43146
  const repoRoot = await resolveGitRoot(cwd);
@@ -42761,9 +43270,14 @@ async function cleanupKrakenWorktree(handle, env = process.env) {
42761
43270
  }
42762
43271
  } catch {
42763
43272
  }
43273
+ const branch = handle.branch.startsWith("kraken/") ? handle.branch : null;
43274
+ if (isKrakenWorktreeCleanupBatched(env)) {
43275
+ queueWorktreeCleanup(handle.repoRoot, branch);
43276
+ return;
43277
+ }
42764
43278
  await git3(handle.repoRoot, ["worktree", "prune"]);
42765
- if (handle.branch.startsWith("kraken/")) {
42766
- await git3(handle.repoRoot, ["branch", "-D", handle.branch]);
43279
+ if (branch) {
43280
+ await git3(handle.repoRoot, ["branch", "-D", branch]);
42767
43281
  }
42768
43282
  }
42769
43283
  function formatWorktreeFooter(handle, opts = {}) {
@@ -42777,11 +43291,14 @@ function formatWorktreeFooter(handle, opts = {}) {
42777
43291
  }
42778
43292
  return `worktree used: branch=${handle.branch} path=${handle.path}`;
42779
43293
  }
42780
- var execFileAsync2;
43294
+ var execFileAsync3, gitRootMemo;
42781
43295
  var init_krakenWorktree = __esm({
42782
43296
  "src/cli/tools/krakenWorktree.ts"() {
42783
43297
  "use strict";
42784
- execFileAsync2 = promisify2(execFile3);
43298
+ init_worktreeCleanupBatch();
43299
+ init_worktreeCleanupBatch();
43300
+ execFileAsync3 = promisify3(execFile4);
43301
+ gitRootMemo = /* @__PURE__ */ new Map();
42785
43302
  }
42786
43303
  });
42787
43304
 
@@ -43157,15 +43674,46 @@ var init_tentacle = __esm({
43157
43674
  }
43158
43675
  });
43159
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
+
43160
43708
  // src/cli/checkpoint/checkpointManager.ts
43161
- import { execFile as execFile4 } from "node:child_process";
43162
- import { promisify as promisify3 } from "node:util";
43709
+ import { execFile as execFile5 } from "node:child_process";
43710
+ import { promisify as promisify4 } from "node:util";
43163
43711
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
43164
43712
  import { tmpdir as tmpdir3 } from "node:os";
43165
43713
  import path42 from "node:path";
43166
43714
  import { randomUUID as randomUUID3 } from "node:crypto";
43167
43715
  async function git4(cwd, args, env) {
43168
- const { stdout } = await execFileAsync3("git", ["-C", cwd, ...args], {
43716
+ const { stdout } = await execFileAsync4("git", ["-C", cwd, ...args], {
43169
43717
  maxBuffer: 64 * 1024 * 1024,
43170
43718
  env: env ? { ...process.env, ...env } : process.env
43171
43719
  });
@@ -43287,11 +43835,11 @@ async function restoreCheckpoint(cwd, id3) {
43287
43835
  async function dropCheckpoint(cwd, id3) {
43288
43836
  return await gitSafe(cwd, ["update-ref", "-d", `${REF_PREFIX}${id3}`]) !== null;
43289
43837
  }
43290
- var execFileAsync3, REF_PREFIX;
43838
+ var execFileAsync4, REF_PREFIX;
43291
43839
  var init_checkpointManager = __esm({
43292
43840
  "src/cli/checkpoint/checkpointManager.ts"() {
43293
43841
  "use strict";
43294
- execFileAsync3 = promisify3(execFile4);
43842
+ execFileAsync4 = promisify4(execFile5);
43295
43843
  REF_PREFIX = "refs/zelari/checkpoints/";
43296
43844
  }
43297
43845
  });
@@ -43353,7 +43901,7 @@ var init_transactional = __esm({
43353
43901
  });
43354
43902
 
43355
43903
  // src/cli/workspace/worldModel.ts
43356
- import { promises as fs17 } from "node:fs";
43904
+ import { promises as fs18 } from "node:fs";
43357
43905
  import path43 from "node:path";
43358
43906
  import { spawn as spawn8 } from "node:child_process";
43359
43907
  function worldDir(cwd) {
@@ -43361,18 +43909,18 @@ function worldDir(cwd) {
43361
43909
  }
43362
43910
  async function ensureWorldDir(cwd) {
43363
43911
  const dir = worldDir(cwd);
43364
- await fs17.mkdir(dir, { recursive: true });
43912
+ await fs18.mkdir(dir, { recursive: true });
43365
43913
  return dir;
43366
43914
  }
43367
43915
  async function appendTimeline(cwd, entry) {
43368
43916
  const dir = await ensureWorldDir(cwd);
43369
43917
  const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
43370
- await fs17.appendFile(path43.join(dir, TIMELINE_FILE), line, "utf8");
43918
+ await fs18.appendFile(path43.join(dir, TIMELINE_FILE), line, "utf8");
43371
43919
  }
43372
43920
  async function readChecks(cwd) {
43373
43921
  const p3 = path43.join(worldDir(cwd), CHECKS_FILE);
43374
43922
  try {
43375
- const raw = await fs17.readFile(p3, "utf8");
43923
+ const raw = await fs18.readFile(p3, "utf8");
43376
43924
  const parsed = JSON.parse(raw);
43377
43925
  return Array.isArray(parsed.checks) ? parsed.checks : [];
43378
43926
  } catch {
@@ -43540,11 +44088,11 @@ var init_worldModel = __esm({
43540
44088
 
43541
44089
  ${args.content}
43542
44090
  `;
43543
- await fs17.appendFile(file2, block, "utf8");
44091
+ await fs18.appendFile(file2, block, "utf8");
43544
44092
  } else {
43545
- await fs17.writeFile(file2, args.content, "utf8");
44093
+ await fs18.writeFile(file2, args.content, "utf8");
43546
44094
  }
43547
- const st = await fs17.stat(file2);
44095
+ const st = await fs18.stat(file2);
43548
44096
  await appendTimeline(ctx.cwd, { kind: "hypothesis_update", bytes: st.size, append: !!args.append });
43549
44097
  return typedOk({ path: file2, bytes: st.size });
43550
44098
  } catch (err) {
@@ -43573,7 +44121,7 @@ ${args.content}
43573
44121
  const dir = await ensureWorldDir(ctx.cwd);
43574
44122
  const file2 = path43.join(dir, CHECKS_FILE);
43575
44123
  const body = { checks: args.checks };
43576
- await fs17.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
44124
+ await fs18.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
43577
44125
  await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
43578
44126
  return typedOk({ path: file2, count: args.checks.length });
43579
44127
  } catch (err) {
@@ -43658,7 +44206,7 @@ __export(graphMemory_exports, {
43658
44206
  saveGraphSnapshot: () => saveGraphSnapshot,
43659
44207
  toGraphSnapshot: () => toGraphSnapshot
43660
44208
  });
43661
- import { promises as fs18 } from "node:fs";
44209
+ import { promises as fs19 } from "node:fs";
43662
44210
  import path44 from "node:path";
43663
44211
  function snapshotPath(cwd) {
43664
44212
  return path44.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
@@ -43686,16 +44234,16 @@ function toGraphSnapshot(graph, opts) {
43686
44234
  }
43687
44235
  async function saveGraphSnapshot(cwd, snapshot) {
43688
44236
  try {
43689
- await fs18.access(cwd);
44237
+ await fs19.access(cwd);
43690
44238
  const file2 = snapshotPath(cwd);
43691
- await fs18.mkdir(path44.dirname(file2), { recursive: true });
43692
- await fs18.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
44239
+ await fs19.mkdir(path44.dirname(file2), { recursive: true });
44240
+ await fs19.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
43693
44241
  } catch {
43694
44242
  }
43695
44243
  }
43696
44244
  async function loadGraphSnapshot(cwd) {
43697
44245
  try {
43698
- const raw = await fs18.readFile(snapshotPath(cwd), "utf8");
44246
+ const raw = await fs19.readFile(snapshotPath(cwd), "utf8");
43699
44247
  const parsed = JSON.parse(raw);
43700
44248
  if (!parsed || !Array.isArray(parsed.nodes)) return null;
43701
44249
  return parsed;
@@ -43762,7 +44310,7 @@ var init_graphMemory = __esm({
43762
44310
  });
43763
44311
 
43764
44312
  // src/cli/kraken/workbench.ts
43765
- import { promises as fs19 } from "node:fs";
44313
+ import { promises as fs20 } from "node:fs";
43766
44314
  import path45 from "node:path";
43767
44315
  function isWorkbenchEnabled(env = process.env) {
43768
44316
  const v = (env.ZELARI_KRAKEN_WORKBENCH ?? "1").trim().toLowerCase();
@@ -43933,11 +44481,11 @@ var init_workbench = __esm({
43933
44481
  if (!this.enabled) return null;
43934
44482
  if (!this.dirty && this.lastWrite) return this.lastWrite;
43935
44483
  const out = workbenchPath(this.cwd, this.graphId);
43936
- await fs19.mkdir(path45.dirname(out), { recursive: true });
44484
+ await fs20.mkdir(path45.dirname(out), { recursive: true });
43937
44485
  const body = this.render();
43938
44486
  const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
43939
- await fs19.writeFile(tmp, body, "utf8");
43940
- await fs19.rename(tmp, out);
44487
+ await fs20.writeFile(tmp, body, "utf8");
44488
+ await fs20.rename(tmp, out);
43941
44489
  this.dirty = false;
43942
44490
  this.lastWrite = Promise.resolve(out);
43943
44491
  return out;
@@ -44517,9 +45065,11 @@ var init_reputationStore = __esm({
44517
45065
  // src/cli/tools/krakenModel.ts
44518
45066
  var krakenModel_exports = {};
44519
45067
  __export(krakenModel_exports, {
45068
+ familyCandidatesFromRegistry: () => familyCandidatesFromRegistry,
44520
45069
  inferModelFamily: () => inferModelFamily,
44521
45070
  isCheapModelId: () => isCheapModelId,
44522
45071
  isKrakenAutoModelEnabled: () => isKrakenAutoModelEnabled,
45072
+ isKrakenCrossModelEnabled: () => isKrakenCrossModelEnabled,
44523
45073
  isUnknownModelError: () => isUnknownModelError,
44524
45074
  parseQualifiedModelRef: () => parseQualifiedModelRef,
44525
45075
  pickCheapModel: () => pickCheapModel,
@@ -44560,6 +45110,10 @@ function isKrakenAutoModelEnabled(env = process.env) {
44560
45110
  if (v === "0" || v === "false" || v === "no" || v === "off") return false;
44561
45111
  return true;
44562
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
+ }
44563
45117
  function parseQualifiedModelRef(ref) {
44564
45118
  const s = ref?.trim() ?? "";
44565
45119
  const slash = s.indexOf("/");
@@ -44596,8 +45150,7 @@ function pickDifferentFamily(builder, candidates) {
44596
45150
  return null;
44597
45151
  }
44598
45152
  function resolveCrossModelVerifier(builder, candidates, env = process.env) {
44599
- const cross = (env.ZELARI_KRAKEN_CROSS_MODEL ?? "").trim().toLowerCase();
44600
- if (cross === "0" || cross === "false" || cross === "off") return null;
45153
+ if (!isKrakenCrossModelEnabled(env)) return null;
44601
45154
  const specific = env.ZELARI_KRAKEN_VERIFY_MODEL?.trim();
44602
45155
  if (specific) {
44603
45156
  const qualified = parseQualifiedModelRef(specific);
@@ -44619,7 +45172,7 @@ function resolveKrakenSubModel(agent, parentModel, env = process.env, opts = {})
44619
45172
  }
44620
45173
  return shared;
44621
45174
  }
44622
- if (agent === "verify" && opts.familyCandidates && opts.familyCandidates.length > 0) {
45175
+ if (agent === "verify" && opts.familyCandidates && opts.familyCandidates.length > 0 && isKrakenCrossModelEnabled(env)) {
44623
45176
  const picked = pickDifferentFamily(
44624
45177
  { provider: opts.provider ?? "", model: parentModel },
44625
45178
  opts.familyCandidates
@@ -44649,20 +45202,40 @@ function resolvePersonaModel(kind2, parentModel, env = process.env, opts = {}) {
44649
45202
  if (specific) return specific;
44650
45203
  return resolveKrakenSubModel("verify", parentModel, env, opts);
44651
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
+ }
44652
45221
  async function resolveKrakenSubModelAsync(agent, parentModel, env = process.env, opts = {}) {
44653
45222
  let candidates = [];
44654
- if (opts.provider) {
44655
- try {
44656
- const mod = await Promise.resolve().then(() => (init_modelDiscovery(), modelDiscovery_exports));
45223
+ let familyCandidates = [];
45224
+ try {
45225
+ const mod = await Promise.resolve().then(() => (init_modelDiscovery(), modelDiscovery_exports));
45226
+ if (opts.provider) {
44657
45227
  const ids = mod.getDiscoveredModelIds(opts.provider);
44658
45228
  if (Array.isArray(ids)) candidates = ids;
44659
- } catch {
44660
- candidates = [];
44661
45229
  }
45230
+ familyCandidates = familyCandidatesFromRegistry(mod.loadModelsRegistry());
45231
+ } catch {
45232
+ candidates = [];
45233
+ familyCandidates = [];
44662
45234
  }
44663
45235
  return resolveKrakenSubModel(agent, parentModel, env, {
44664
45236
  provider: opts.provider,
44665
- candidates
45237
+ candidates,
45238
+ familyCandidates
44666
45239
  });
44667
45240
  }
44668
45241
  var CHEAP_RE, FLAGSHIP_RE;
@@ -45125,6 +45698,7 @@ var init_executor = __esm({
45125
45698
  init_tentacle();
45126
45699
  init_krakenWorktree();
45127
45700
  init_krakenRadio();
45701
+ init_asyncLimit();
45128
45702
  init_transactional();
45129
45703
  init_worldModel();
45130
45704
  init_graphStatus();
@@ -45295,11 +45869,13 @@ var init_executor = __esm({
45295
45869
  }, this.graphTimeoutMs);
45296
45870
  graphTimer.unref?.();
45297
45871
  }
45872
+ const worktreeCleanupBatched = beginKrakenWorktreeCleanupBatch(process.env);
45298
45873
  try {
45299
45874
  return await this.schedule(graph);
45300
45875
  } finally {
45301
45876
  if (graphTimer) clearTimeout(graphTimer);
45302
45877
  this.signal?.removeEventListener("abort", onAbort);
45878
+ if (worktreeCleanupBatched) await flushKrakenWorktreeCleanupBatch();
45303
45879
  }
45304
45880
  }
45305
45881
  /** The scheduling loop proper. See {@link execute} for the cancellation wrapper. */
@@ -46086,6 +46662,7 @@ ${upstream}` : node.prompt,
46086
46662
  const memory = this.deps.memoryService;
46087
46663
  if (!memory || this.deps.memoryAutoWrite === false) return;
46088
46664
  try {
46665
+ const edges = [];
46089
46666
  for (const node of graph.nodes.values()) {
46090
46667
  const nodeMemoryId = this.memoryIds.get(node.id);
46091
46668
  if (!nodeMemoryId) continue;
@@ -46094,22 +46671,21 @@ ${upstream}` : node.prompt,
46094
46671
  if (!dependencyMemoryId) continue;
46095
46672
  if (node.kind === "verify") {
46096
46673
  const verdict = parseVerifyVerdict(node.result).verdict;
46097
- await memory.connect({
46674
+ edges.push({
46098
46675
  from: dependencyMemoryId,
46099
46676
  to: nodeMemoryId,
46100
- relation: verdict === "pass" ? "validated_by" : verdict === "fail" ? "invalidated_by" : "related_to",
46101
- createdBy: "kraken-orchestrator"
46677
+ relation: verdict === "pass" ? "validated_by" : verdict === "fail" ? "invalidated_by" : "related_to"
46102
46678
  });
46103
46679
  } else {
46104
- await memory.connect({
46105
- from: nodeMemoryId,
46106
- to: dependencyMemoryId,
46107
- relation: "derived_from",
46108
- createdBy: "kraken-orchestrator"
46109
- });
46680
+ edges.push({ from: nodeMemoryId, to: dependencyMemoryId, relation: "derived_from" });
46110
46681
  }
46111
46682
  }
46112
46683
  }
46684
+ await runWithLimit2(
46685
+ edges,
46686
+ 8,
46687
+ (edge) => memory.connect({ ...edge, createdBy: "kraken-orchestrator" }).catch(() => void 0)
46688
+ );
46113
46689
  const counts = countByStatus(graph);
46114
46690
  const outcome = await memory.remember({
46115
46691
  kind: converged ? "outcome" : "failure",
@@ -46121,14 +46697,17 @@ ${upstream}` : node.prompt,
46121
46697
  metadata: { graphId: graph.id, converged, counts, writeClass: "auto" },
46122
46698
  writeClass: "auto"
46123
46699
  });
46124
- for (const memoryId of this.memoryIds.values()) {
46125
- await memory.connect({
46126
- from: outcome.id,
46127
- to: memoryId,
46128
- relation: "derived_from",
46129
- createdBy: "kraken-orchestrator"
46130
- });
46131
- }
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
+ );
46132
46711
  await memory.consolidate({
46133
46712
  source: { agent: "kraken-orchestrator", sessionId: this.sessionId },
46134
46713
  minOccurrences: 2
@@ -49212,7 +49791,7 @@ var init_planTaskTools = __esm({
49212
49791
  });
49213
49792
 
49214
49793
  // src/cli/tools/inspectTypecheckSafety.ts
49215
- import { promises as fs20 } from "node:fs";
49794
+ import { promises as fs21 } from "node:fs";
49216
49795
  import path49 from "node:path";
49217
49796
  import { spawn as spawn9 } from "node:child_process";
49218
49797
  async function scanTsbuildinfo(root) {
@@ -49222,7 +49801,7 @@ async function scanTsbuildinfo(root) {
49222
49801
  const dir = stack.pop();
49223
49802
  let entries;
49224
49803
  try {
49225
- entries = await fs20.readdir(dir, { withFileTypes: true });
49804
+ entries = await fs21.readdir(dir, { withFileTypes: true });
49226
49805
  } catch {
49227
49806
  continue;
49228
49807
  }
@@ -49267,7 +49846,7 @@ async function cleanupArtifacts(root, relPaths) {
49267
49846
  const failed = [];
49268
49847
  for (const rel2 of relPaths) {
49269
49848
  try {
49270
- await fs20.unlink(path49.join(root, rel2));
49849
+ await fs21.unlink(path49.join(root, rel2));
49271
49850
  cleaned.push(rel2);
49272
49851
  } catch {
49273
49852
  failed.push(rel2);
@@ -49291,8 +49870,8 @@ var init_inspectTypecheckSafety = __esm({
49291
49870
 
49292
49871
  // src/cli/tools/inspectCommand.ts
49293
49872
  import { spawn as spawn10 } from "node:child_process";
49294
- import { createHash as createHash13 } from "node:crypto";
49295
- import { existsSync as existsSync28, promises as fs21 } from "node:fs";
49873
+ import { createHash as createHash14 } from "node:crypto";
49874
+ import { existsSync as existsSync28, promises as fs22 } from "node:fs";
49296
49875
  import os2 from "node:os";
49297
49876
  import path50 from "node:path";
49298
49877
  function resolveNodeModuleBin(start, rel2) {
@@ -49378,7 +49957,7 @@ function buildInspectCommand(op, ctx) {
49378
49957
  }
49379
49958
  case "typecheck": {
49380
49959
  const project = path50.resolve(ctx.cwd, op.project ?? "tsconfig.json");
49381
- const hash3 = createHash13("sha256").update(project).digest("hex").slice(0, 16);
49960
+ const hash3 = createHash14("sha256").update(project).digest("hex").slice(0, 16);
49382
49961
  const tsBuildInfoFile = path50.join(os2.tmpdir(), "zelari-inspect", `${hash3}.tsbuildinfo`);
49383
49962
  return {
49384
49963
  ok: true,
@@ -49517,7 +50096,7 @@ function createInspectCommandTool(rootOrDeps) {
49517
50096
  if (op.operation === "typecheck") {
49518
50097
  const tsc = built.argv[0];
49519
50098
  try {
49520
- await fs21.access(tsc);
50099
+ await fs22.access(tsc);
49521
50100
  } catch {
49522
50101
  return typedErr(
49523
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.`
@@ -50913,11 +51492,11 @@ var init_store2 = __esm({
50913
51492
  });
50914
51493
 
50915
51494
  // src/cli/semantic/index.ts
50916
- import { promises as fs22, existsSync as existsSync29, readFileSync as readFileSync21 } from "node:fs";
51495
+ import { promises as fs23, existsSync as existsSync29, readFileSync as readFileSync21 } from "node:fs";
50917
51496
  import path53 from "node:path";
50918
- import { createHash as createHash14 } from "node:crypto";
51497
+ import { createHash as createHash15 } from "node:crypto";
50919
51498
  function getIndexPath(root) {
50920
- const hash3 = createHash14("sha1").update(path53.resolve(root)).digest("hex").slice(0, 16);
51499
+ const hash3 = createHash15("sha1").update(path53.resolve(root)).digest("hex").slice(0, 16);
50921
51500
  return process.env.ZELARI_SEMANTIC_FILE ?? path53.join(semanticStateDir(), `${hash3}.json`);
50922
51501
  }
50923
51502
  async function collectSourceFiles(root, maxFiles = 1500) {
@@ -50926,7 +51505,7 @@ async function collectSourceFiles(root, maxFiles = 1500) {
50926
51505
  if (out.length >= maxFiles) return;
50927
51506
  let entries;
50928
51507
  try {
50929
- entries = await fs22.readdir(dir, { withFileTypes: true });
51508
+ entries = await fs23.readdir(dir, { withFileTypes: true });
50930
51509
  } catch {
50931
51510
  return;
50932
51511
  }
@@ -50956,7 +51535,7 @@ async function buildIndex(files, embed, options) {
50956
51535
  for (const file2 of files) {
50957
51536
  let text;
50958
51537
  try {
50959
- text = await fs22.readFile(file2, "utf8");
51538
+ text = await fs23.readFile(file2, "utf8");
50960
51539
  } catch {
50961
51540
  continue;
50962
51541
  }
@@ -50989,10 +51568,10 @@ async function buildIndex(files, embed, options) {
50989
51568
  }
50990
51569
  async function saveIndex(root, data) {
50991
51570
  const file2 = getIndexPath(root);
50992
- await fs22.mkdir(path53.dirname(file2), { recursive: true });
51571
+ await fs23.mkdir(path53.dirname(file2), { recursive: true });
50993
51572
  const tmp = `${file2}.tmp-${process.pid}`;
50994
- await fs22.writeFile(tmp, JSON.stringify(data), "utf8");
50995
- await fs22.rename(tmp, file2);
51573
+ await fs23.writeFile(tmp, JSON.stringify(data), "utf8");
51574
+ await fs23.rename(tmp, file2);
50996
51575
  }
50997
51576
  function loadIndex(root) {
50998
51577
  const file2 = getIndexPath(root);
@@ -52253,13 +52832,13 @@ var init_tools5 = __esm({
52253
52832
  });
52254
52833
 
52255
52834
  // src/cli/tools/screenshotTool.ts
52256
- import { execFile as execFile5 } from "node:child_process";
52835
+ import { execFile as execFile6 } from "node:child_process";
52257
52836
  import { mkdir as mkdir3, readFile as readFile8, stat as stat7 } from "node:fs/promises";
52258
52837
  import path57 from "node:path";
52259
- import { promisify as promisify4 } from "node:util";
52838
+ import { promisify as promisify5 } from "node:util";
52260
52839
  async function captureWindows(target) {
52261
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();`;
52262
- await execFileAsync4("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
52841
+ await execFileAsync5("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
52263
52842
  timeout: 12e3,
52264
52843
  windowsHide: true
52265
52844
  });
@@ -52273,7 +52852,7 @@ async function captureUnixLike(target) {
52273
52852
  let lastErr = null;
52274
52853
  for (const [bin, args] of attempts) {
52275
52854
  try {
52276
- await execFileAsync4(bin, args, { timeout: 12e3 });
52855
+ await execFileAsync5(bin, args, { timeout: 12e3 });
52277
52856
  return;
52278
52857
  } catch (e) {
52279
52858
  lastErr = e;
@@ -52327,13 +52906,13 @@ function createScreenshotTool(deps = {}) {
52327
52906
  }
52328
52907
  };
52329
52908
  }
52330
- var execFileAsync4, SCREENSHOT_MAX_BYTES2;
52909
+ var execFileAsync5, SCREENSHOT_MAX_BYTES2;
52331
52910
  var init_screenshotTool = __esm({
52332
52911
  "src/cli/tools/screenshotTool.ts"() {
52333
52912
  "use strict";
52334
52913
  init_zod();
52335
52914
  init_toolTypes();
52336
- execFileAsync4 = promisify4(execFile5);
52915
+ execFileAsync5 = promisify5(execFile6);
52337
52916
  SCREENSHOT_MAX_BYTES2 = 8 * 1024 * 1024;
52338
52917
  }
52339
52918
  });
@@ -53656,6 +54235,163 @@ var init_resolveStream = __esm({
53656
54235
  }
53657
54236
  });
53658
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
+
53659
54395
  // src/cli/safety/toolPermissions.ts
53660
54396
  var toolPermissions_exports = {};
53661
54397
  __export(toolPermissions_exports, {
@@ -53842,7 +54578,7 @@ function recordNonUserContent(source2, text, tool) {
53842
54578
  const excerpt = normalize5(raw).slice(0, MAX_EXCERPT);
53843
54579
  if (excerpt.length < PROVENANCE_MIN_MATCH * 2) return;
53844
54580
  ring.push({ source: source2, tool, excerpt, at: Date.now() });
53845
- if (ring.length > MAX_ENTRIES) ring.splice(0, ring.length - MAX_ENTRIES);
54581
+ if (ring.length > MAX_ENTRIES2) ring.splice(0, ring.length - MAX_ENTRIES2);
53846
54582
  } catch {
53847
54583
  }
53848
54584
  }
@@ -53898,11 +54634,11 @@ function safeJson2(v) {
53898
54634
  return "";
53899
54635
  }
53900
54636
  }
53901
- var MAX_ENTRIES, MAX_EXCERPT, PROVENANCE_MIN_MATCH, SHINGLE_STEP, MAX_SHINGLES, ring;
54637
+ var MAX_ENTRIES2, MAX_EXCERPT, PROVENANCE_MIN_MATCH, SHINGLE_STEP, MAX_SHINGLES, ring;
53902
54638
  var init_provenance = __esm({
53903
54639
  "src/cli/safety/provenance.ts"() {
53904
54640
  "use strict";
53905
- MAX_ENTRIES = 40;
54641
+ MAX_ENTRIES2 = 40;
53906
54642
  MAX_EXCERPT = 8192;
53907
54643
  PROVENANCE_MIN_MATCH = 48;
53908
54644
  SHINGLE_STEP = 24;
@@ -54095,7 +54831,7 @@ var init_lifecycleHooks = __esm({
54095
54831
  });
54096
54832
 
54097
54833
  // src/cli/safety/astGate.ts
54098
- import { promises as fs23 } from "node:fs";
54834
+ import { promises as fs24 } from "node:fs";
54099
54835
  import path59 from "node:path";
54100
54836
  function astGateEnabled() {
54101
54837
  return process.env.ZELARI_AST_GATE !== "0";
@@ -54145,7 +54881,7 @@ function wrapWithAstGate(original, opts) {
54145
54881
  if (astGateEnabled()) gateTarget = containedPathOf(args);
54146
54882
  if (gateTarget !== null && isAstSupported(gateTarget)) {
54147
54883
  try {
54148
- preContent = await fs23.readFile(gateTarget, "utf8");
54884
+ preContent = await fs24.readFile(gateTarget, "utf8");
54149
54885
  } catch (err) {
54150
54886
  if (err?.code === "ENOENT") preContent = null;
54151
54887
  }
@@ -54174,16 +54910,16 @@ function wrapWithAstGate(original, opts) {
54174
54910
  );
54175
54911
  return result;
54176
54912
  }
54177
- const post = await fs23.readFile(absPath, "utf8");
54913
+ const post = await fs24.readFile(absPath, "utf8");
54178
54914
  const syntaxError = firstSyntaxError(ts, path59.basename(absPath), post);
54179
54915
  if (!syntaxError) return result;
54180
54916
  const parseError = `${syntaxError.message} (line ${syntaxError.line}, col ${syntaxError.character})`;
54181
54917
  let revertedTo;
54182
54918
  if (preContent === null) {
54183
- await fs23.unlink(absPath).catch(() => void 0);
54919
+ await fs24.unlink(absPath).catch(() => void 0);
54184
54920
  revertedTo = "absent";
54185
54921
  } else {
54186
- await fs23.writeFile(absPath, preContent, "utf8");
54922
+ await fs24.writeFile(absPath, preContent, "utf8");
54187
54923
  revertedTo = snapshotIdOf(preContent);
54188
54924
  }
54189
54925
  const relLabel = path59.relative(opts.root, absPath) || path59.basename(absPath);
@@ -54609,8 +55345,8 @@ var init_resourceClaims = __esm({
54609
55345
  });
54610
55346
 
54611
55347
  // src/cli/toolResultCache.ts
54612
- import { createHash as createHash15 } from "node:crypto";
54613
- import { promises as fs24 } from "node:fs";
55348
+ import { createHash as createHash16 } from "node:crypto";
55349
+ import { promises as fs25 } from "node:fs";
54614
55350
  import path60 from "node:path";
54615
55351
  function isToolCacheEnabled() {
54616
55352
  const raw = process.env.ZELARI_TOOL_CACHE;
@@ -54622,7 +55358,7 @@ function resolveToolCacheTtlMs() {
54622
55358
  return Number.isFinite(n) && n >= 0 ? n : TOOL_CACHE_DEFAULT_TTL_MS;
54623
55359
  }
54624
55360
  function hashKey(parts) {
54625
- return createHash15("sha256").update(JSON.stringify(parts), "utf8").digest("hex");
55361
+ return createHash16("sha256").update(JSON.stringify(parts), "utf8").digest("hex");
54626
55362
  }
54627
55363
  function resultBytes(result) {
54628
55364
  try {
@@ -54698,7 +55434,7 @@ async function statKey(toolName, input, ctx) {
54698
55434
  if (typeof rawPath !== "string" || rawPath.length === 0) return null;
54699
55435
  const abs = path60.isAbsolute(rawPath) ? rawPath : path60.join(ctx.cwd, rawPath);
54700
55436
  try {
54701
- const st = await fs24.stat(abs);
55437
+ const st = await fs25.stat(abs);
54702
55438
  return hashKey({
54703
55439
  tool: toolName,
54704
55440
  args: input,
@@ -55123,9 +55859,11 @@ function createKrakenSubAgentContextFactory(opts) {
55123
55859
  return async ({ agent, cwd: subCwd }) => {
55124
55860
  const cfg = providerOverride ? await providerConfigFor(providerOverride) : await providerFromEnv();
55125
55861
  if (!cfg) return null;
55126
- const { resolveKrakenSubModel: resolveKrakenSubModel2, parseQualifiedModelRef: parseQualifiedModelRef2 } = await Promise.resolve().then(() => (init_krakenModel(), krakenModel_exports));
55862
+ const { resolveKrakenSubModelAsync: resolveKrakenSubModelAsync2, parseQualifiedModelRef: parseQualifiedModelRef2 } = await Promise.resolve().then(() => (init_krakenModel(), krakenModel_exports));
55127
55863
  const parentModel = modelOverride || cfg.model;
55128
- const resolvedModel = resolveKrakenSubModel2(agent, parentModel);
55864
+ const resolvedModel = await resolveKrakenSubModelAsync2(agent, parentModel, process.env, {
55865
+ provider: cfg.providerId
55866
+ });
55129
55867
  let effCfg = cfg;
55130
55868
  let model = resolvedModel;
55131
55869
  const ref = parseQualifiedModelRef2(resolvedModel);
@@ -55158,15 +55896,31 @@ function createKrakenSubAgentContextFactory(opts) {
55158
55896
  // P0.5: the tentacle's agent identity drives per-agent policy rules.
55159
55897
  policyAgent: agent
55160
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
+ );
55161
55910
  return {
55162
- providerStream: buildProviderStream(subCfg),
55911
+ providerStream,
55163
55912
  model,
55164
55913
  provider: subCfg.providerId,
55165
55914
  ...model !== parentModel ? {
55166
55915
  fallback: {
55167
55916
  model: parentModel,
55168
55917
  provider: cfg.providerId,
55169
- providerStream: buildProviderStream({ ...cfg, model: parentModel })
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
+ )
55170
55924
  }
55171
55925
  } : {},
55172
55926
  registry: subRegistry,
@@ -55653,6 +56407,8 @@ var init_toolRegistry = __esm({
55653
56407
  init_openai_compatible();
55654
56408
  init_resolveStream();
55655
56409
  init_providerConfig();
56410
+ init_crossProviderFailover();
56411
+ init_keyStore();
55656
56412
  init_toolPermissions();
55657
56413
  init_destructiveCommands();
55658
56414
  init_provenance();
@@ -55693,12 +56449,12 @@ var init_toolRegistry = __esm({
55693
56449
  });
55694
56450
 
55695
56451
  // src/cli/metrics.ts
55696
- import { promises as fs25, existsSync as existsSync33, statSync as statSync4, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync15 } from "node:fs";
56452
+ import { promises as fs26, existsSync as existsSync33, statSync as statSync4, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync15 } from "node:fs";
55697
56453
  import path62 from "node:path";
55698
56454
  async function readMetrics(file2) {
55699
56455
  let raw = "";
55700
56456
  try {
55701
- raw = await fs25.readFile(file2, "utf-8");
56457
+ raw = await fs26.readFile(file2, "utf-8");
55702
56458
  } catch {
55703
56459
  return [];
55704
56460
  }
@@ -56076,8 +56832,8 @@ __export(completionProofProbe_exports, {
56076
56832
  gatherGitAttestation: () => gatherGitAttestation,
56077
56833
  harnessManifest: () => harnessManifest
56078
56834
  });
56079
- import { execFile as execFile6 } from "node:child_process";
56080
- import { promisify as promisify5 } from "node:util";
56835
+ import { execFile as execFile7 } from "node:child_process";
56836
+ import { promisify as promisify6 } from "node:util";
56081
56837
  async function readHarnessVersion() {
56082
56838
  if (cachedHarnessVersion !== null) return cachedHarnessVersion;
56083
56839
  try {
@@ -56108,7 +56864,7 @@ async function harnessManifest(env = process.env) {
56108
56864
  }
56109
56865
  async function git5(cwd, args) {
56110
56866
  try {
56111
- const { stdout } = await execFileAsync5("git", ["-C", cwd, ...args], {
56867
+ const { stdout } = await execFileAsync6("git", ["-C", cwd, ...args], {
56112
56868
  maxBuffer: 32 * 1024 * 1024,
56113
56869
  windowsHide: true
56114
56870
  });
@@ -56150,7 +56906,7 @@ function activeTaskContractSnapshot() {
56150
56906
  return void 0;
56151
56907
  }
56152
56908
  }
56153
- var HARNESS_VERSION_FALLBACK, ADAPTER_IDS, cachedHarnessVersion, execFileAsync5;
56909
+ var HARNESS_VERSION_FALLBACK, ADAPTER_IDS, cachedHarnessVersion, execFileAsync6;
56154
56910
  var init_completionProofProbe = __esm({
56155
56911
  "src/cli/kraken/completionProofProbe.ts"() {
56156
56912
  "use strict";
@@ -56158,14 +56914,14 @@ var init_completionProofProbe = __esm({
56158
56914
  HARNESS_VERSION_FALLBACK = "2.13.0";
56159
56915
  ADAPTER_IDS = ["node", "python", "rust", "go", "java", "dotnet"];
56160
56916
  cachedHarnessVersion = null;
56161
- execFileAsync5 = promisify5(execFile6);
56917
+ execFileAsync6 = promisify6(execFile7);
56162
56918
  }
56163
56919
  });
56164
56920
 
56165
56921
  // src/cli/kraken/completionProofAttestation.ts
56166
- import { createHash as createHash16 } from "node:crypto";
56922
+ import { createHash as createHash17 } from "node:crypto";
56167
56923
  function sha256Hex3(data) {
56168
- return createHash16("sha256").update(data, "utf8").digest("hex");
56924
+ return createHash17("sha256").update(data, "utf8").digest("hex");
56169
56925
  }
56170
56926
  function canonicalJson(value) {
56171
56927
  return JSON.stringify(canonicalValue(value));
@@ -56625,21 +57381,21 @@ var init_askUserTimeout = __esm({
56625
57381
  });
56626
57382
 
56627
57383
  // src/cli/state/fileStateStore.ts
56628
- import { createHash as createHash17, randomUUID as randomUUID5 } from "node:crypto";
56629
- import { promises as fs26 } from "node:fs";
57384
+ import { createHash as createHash18, randomUUID as randomUUID5 } from "node:crypto";
57385
+ import { promises as fs27 } from "node:fs";
56630
57386
  import * as path65 from "node:path";
56631
57387
  function shortId() {
56632
57388
  return randomUUID5().replace(/-/g, "").slice(0, 12);
56633
57389
  }
56634
57390
  async function writeJsonAtomic(filePath, data) {
56635
- await fs26.mkdir(path65.dirname(filePath), { recursive: true });
57391
+ await fs27.mkdir(path65.dirname(filePath), { recursive: true });
56636
57392
  const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
56637
- await fs26.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
56638
- await fs26.rename(tmp, filePath);
57393
+ await fs27.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
57394
+ await fs27.rename(tmp, filePath);
56639
57395
  }
56640
57396
  async function readJsonFile(filePath) {
56641
57397
  try {
56642
- const raw = await fs26.readFile(filePath, "utf8");
57398
+ const raw = await fs27.readFile(filePath, "utf8");
56643
57399
  return JSON.parse(raw);
56644
57400
  } catch {
56645
57401
  return null;
@@ -56677,7 +57433,7 @@ async function getStateStore(projectRoot, env = process.env) {
56677
57433
  }
56678
57434
  }
56679
57435
  function hashStablePrompt(stable) {
56680
- return createHash17("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
57436
+ return createHash18("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
56681
57437
  }
56682
57438
  var DEFAULT_MATERIALIZE_CHARS, FileDurableStateStore, NoopDurableStateStore;
56683
57439
  var init_fileStateStore = __esm({
@@ -56698,8 +57454,8 @@ var init_fileStateStore = __esm({
56698
57454
  this.artifactsDir = path65.join(this.stateDir, "artifacts");
56699
57455
  this.headPath = path65.join(this.stateDir, "HEAD.json");
56700
57456
  this.indexPath = path65.join(this.stateDir, "index.jsonl");
56701
- await fs26.mkdir(this.commitsDir, { recursive: true });
56702
- await fs26.mkdir(this.artifactsDir, { recursive: true });
57457
+ await fs27.mkdir(this.commitsDir, { recursive: true });
57458
+ await fs27.mkdir(this.artifactsDir, { recursive: true });
56703
57459
  }
56704
57460
  async commit(input) {
56705
57461
  if (!input.force && input.verification.ran && !input.verification.ok) {
@@ -56712,9 +57468,9 @@ var init_fileStateStore = __esm({
56712
57468
  const id3 = shortId();
56713
57469
  const artifactRel = path65.join("artifacts", id3);
56714
57470
  const artifactAbs = path65.join(this.artifactsDir, id3);
56715
- await fs26.mkdir(artifactAbs, { recursive: true });
57471
+ await fs27.mkdir(artifactAbs, { recursive: true });
56716
57472
  const summary = defaultSummary(input, discoveries);
56717
- await fs26.writeFile(path65.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
57473
+ await fs27.writeFile(path65.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
56718
57474
  await writeJsonAtomic(path65.join(artifactAbs, "discoveries.json"), discoveries);
56719
57475
  await writeJsonAtomic(path65.join(artifactAbs, "verification.json"), input.verification);
56720
57476
  const meta3 = {
@@ -56737,7 +57493,7 @@ var init_fileStateStore = __esm({
56737
57493
  };
56738
57494
  await writeJsonAtomic(path65.join(this.commitsDir, `${id3}.json`), meta3);
56739
57495
  await writeJsonAtomic(this.headPath, { id: id3, updatedAt: meta3.createdAt });
56740
- await fs26.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
57496
+ await fs27.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
56741
57497
  return stripStored(meta3);
56742
57498
  }
56743
57499
  async head() {
@@ -56752,7 +57508,7 @@ var init_fileStateStore = __esm({
56752
57508
  async list(limit = 20) {
56753
57509
  let raw;
56754
57510
  try {
56755
- raw = await fs26.readFile(this.indexPath, "utf8");
57511
+ raw = await fs27.readFile(this.indexPath, "utf8");
56756
57512
  } catch {
56757
57513
  return [];
56758
57514
  }
@@ -57725,7 +58481,10 @@ async function countVerificationEvidenceInLog(mirror, sessionId2) {
57725
58481
  if (mirror.status !== "active" && mirror.status !== "closed") return -1;
57726
58482
  try {
57727
58483
  await mirror.flush().catch(() => void 0);
57728
- const report = await readSessionLog(path67.join(mirror.sessionsDir, sessionId2, "events.jsonl"));
58484
+ const report = await readSessionLogCached(
58485
+ path67.join(mirror.sessionsDir, sessionId2, "events.jsonl"),
58486
+ mirror.replayCache
58487
+ );
57729
58488
  return report.events.filter((e) => e.kind === "verification.evidence").length;
57730
58489
  } catch (err) {
57731
58490
  process.stderr.write(
@@ -57758,7 +58517,7 @@ async function openHeadlessSpine(opts) {
57758
58517
  if (spine.status === "active") {
57759
58518
  const budget = new BudgetRuntime(profileId, { enforcement: resolveResourceEnforcement() });
57760
58519
  if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
57761
- await restoreBudgetRuntimeFromSession(budget, opts.sessionId, opts.baseDir);
58520
+ await restoreBudgetRuntimeFromSession(budget, opts.sessionId, opts.baseDir, spine.replayCache);
57762
58521
  }
57763
58522
  spine.attachBudgetRuntime(budget);
57764
58523
  const manifestSpecs = opts.toolSpecs?.filter((spec) => profileTools.includes(spec.name));
@@ -58518,11 +59277,11 @@ var init_planDetect = __esm({
58518
59277
  });
58519
59278
 
58520
59279
  // src/cli/memory/legacyImport.ts
58521
- import { createHash as createHash18 } from "node:crypto";
58522
- import { promises as fs27 } from "node:fs";
59280
+ import { createHash as createHash19 } from "node:crypto";
59281
+ import { promises as fs28 } from "node:fs";
58523
59282
  import * as path68 from "node:path";
58524
59283
  function sourceId(fact, line) {
58525
- return `jsonl:${fact.id ?? createHash18("sha256").update(line).digest("hex")}`;
59284
+ return `jsonl:${fact.id ?? createHash19("sha256").update(line).digest("hex")}`;
58526
59285
  }
58527
59286
  function kind(metadata2) {
58528
59287
  const raw = metadata2.memoryKind;
@@ -58536,15 +59295,38 @@ function timestamp(value) {
58536
59295
  const parsed = Date.parse(value);
58537
59296
  return Number.isFinite(parsed) ? new Date(parsed).toISOString() : void 0;
58538
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
+ }
58539
59318
  async function importLegacyMemoryLog(backend, service) {
58540
59319
  const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
58541
- const logPath = path68.join(path68.dirname(backend.databasePath), "log.jsonl");
59320
+ const memoryDir = path68.dirname(backend.databasePath);
59321
+ const markerPath = path68.join(memoryDir, LEGACY_IMPORT_MARKER);
59322
+ if (await isImportComplete(markerPath)) return result;
58542
59323
  let raw;
58543
59324
  try {
58544
- raw = await fs27.readFile(logPath, "utf8");
59325
+ raw = await fs28.readFile(path68.join(memoryDir, "log.jsonl"), "utf8");
58545
59326
  } catch {
58546
59327
  return result;
58547
59328
  }
59329
+ const rows = [];
58548
59330
  for (const line of raw.split(/\r?\n/)) {
58549
59331
  const trimmed = line.trim();
58550
59332
  if (!trimmed) continue;
@@ -58561,17 +59343,22 @@ async function importLegacyMemoryLog(backend, service) {
58561
59343
  result.corrupt += 1;
58562
59344
  continue;
58563
59345
  }
58564
- const importId = sourceId(fact, trimmed);
58565
- if (await backend.hasImport(importId)) {
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)) {
58566
59353
  result.skipped += 1;
58567
59354
  continue;
58568
59355
  }
58569
- const metadata2 = fact.metadata && typeof fact.metadata === "object" ? fact.metadata : {};
58570
- 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);
58571
59358
  try {
58572
59359
  const node = await service.remember({
58573
59360
  kind: kind(metadata2),
58574
- content,
59361
+ content: row.content,
58575
59362
  importance: typeof metadata2.importance === "number" ? metadata2.importance : 0.55,
58576
59363
  confidence: typeof metadata2.confidence === "number" ? metadata2.confidence : 0.65,
58577
59364
  source: {
@@ -58583,24 +59370,30 @@ async function importLegacyMemoryLog(backend, service) {
58583
59370
  ...createdAt ? { createdAt, recordedAt: createdAt } : {},
58584
59371
  metadata: {
58585
59372
  ...metadata2,
58586
- legacyId: fact.id,
58587
- legacyCreatedAt: fact.createdAt,
58588
- ...fact.graph ? { legacyGraph: fact.graph } : {}
59373
+ legacyId: row.fact.id,
59374
+ legacyCreatedAt: row.fact.createdAt,
59375
+ ...row.fact.graph ? { legacyGraph: row.fact.graph } : {}
58589
59376
  },
58590
59377
  writeClass: "auto"
58591
59378
  });
58592
- await backend.recordImport(importId, node.id);
59379
+ await backend.recordImport(row.importId, node.id);
59380
+ importedHere.add(row.importId);
58593
59381
  result.imported += 1;
58594
- } catch {
59382
+ } catch (error51) {
58595
59383
  result.skipped += 1;
59384
+ if (!isPermanentSkip(error51)) unresolved += 1;
58596
59385
  }
58597
59386
  }
59387
+ const everyRowResolved = result.imported + result.skipped + result.corrupt === result.found;
59388
+ if (everyRowResolved && unresolved === 0) await markImportComplete(markerPath, result.found);
58598
59389
  return result;
58599
59390
  }
59391
+ var LEGACY_IMPORT_MARKER;
58600
59392
  var init_legacyImport = __esm({
58601
59393
  "src/cli/memory/legacyImport.ts"() {
58602
59394
  "use strict";
58603
59395
  init_memory();
59396
+ LEGACY_IMPORT_MARKER = "legacy-import-done.json";
58604
59397
  }
58605
59398
  });
58606
59399
 
@@ -59020,8 +59813,8 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
59020
59813
  });
59021
59814
 
59022
59815
  // src/cli/memory/sqliteBackend.ts
59023
- import { createHash as createHash19, randomUUID as randomUUID6 } from "node:crypto";
59024
- import { promises as fs28 } from "node:fs";
59816
+ import { createHash as createHash20, randomUUID as randomUUID6 } from "node:crypto";
59817
+ import { promises as fs29 } from "node:fs";
59025
59818
  import * as path70 from "node:path";
59026
59819
  function boundedLimit(value, fallback = 50) {
59027
59820
  return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
@@ -59035,9 +59828,9 @@ function withOptional(target, key, value) {
59035
59828
  return { ...target, [key]: value };
59036
59829
  }
59037
59830
  function contentHash(content) {
59038
- return createHash19("sha256").update(content).digest("hex");
59831
+ return createHash20("sha256").update(content).digest("hex");
59039
59832
  }
59040
- var NODE_COLUMNS, INSERT_NODE_SQL, SOURCE_COLUMNS, SQLiteMemoryBackend;
59833
+ var NODE_COLUMNS, INSERT_NODE_SQL, IMPORT_ID_CHUNK, SOURCE_COLUMNS, SQLiteMemoryBackend;
59041
59834
  var init_sqliteBackend = __esm({
59042
59835
  "src/cli/memory/sqliteBackend.ts"() {
59043
59836
  "use strict";
@@ -59051,6 +59844,7 @@ var init_sqliteBackend = __esm({
59051
59844
  valid_until, recorded_at, retracted_at, embedding_ref, metadata_json`;
59052
59845
  INSERT_NODE_SQL = `INSERT INTO memory_nodes (${NODE_COLUMNS})
59053
59846
  VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
59847
+ IMPORT_ID_CHUNK = 500;
59054
59848
  SOURCE_COLUMNS = {
59055
59849
  agent: "agent",
59056
59850
  sessionId: "sessionId",
@@ -59082,7 +59876,7 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
59082
59876
  async init(projectRoot) {
59083
59877
  let resolved;
59084
59878
  try {
59085
- resolved = await fs28.realpath(projectRoot);
59879
+ resolved = await fs29.realpath(projectRoot);
59086
59880
  } catch {
59087
59881
  resolved = path70.resolve(projectRoot);
59088
59882
  }
@@ -59097,21 +59891,21 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
59097
59891
  for (const candidate of [zelariDirectory, directory]) {
59098
59892
  let stat8;
59099
59893
  try {
59100
- stat8 = await fs28.lstat(candidate);
59894
+ stat8 = await fs29.lstat(candidate);
59101
59895
  } catch (error51) {
59102
59896
  if (error51.code !== "ENOENT") throw error51;
59103
59897
  try {
59104
- await fs28.mkdir(candidate);
59898
+ await fs29.mkdir(candidate);
59105
59899
  } catch (mkdirError) {
59106
59900
  if (mkdirError.code !== "EEXIST") throw mkdirError;
59107
59901
  }
59108
- stat8 = await fs28.lstat(candidate);
59902
+ stat8 = await fs29.lstat(candidate);
59109
59903
  }
59110
59904
  if (stat8.isSymbolicLink() || !stat8.isDirectory()) {
59111
59905
  throw new Error(`Memory directory is not a real directory: ${candidate}`);
59112
59906
  }
59113
59907
  }
59114
- const canonicalDirectory = await fs28.realpath(directory);
59908
+ const canonicalDirectory = await fs29.realpath(directory);
59115
59909
  const relativeDirectory = path70.relative(resolved, canonicalDirectory);
59116
59910
  if (relativeDirectory.startsWith("..") || path70.isAbsolute(relativeDirectory)) {
59117
59911
  throw new Error("SQLite memory directory resolves outside the active project.");
@@ -59614,14 +60408,24 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
59614
60408
  versions: versionRows.map(decodeVersion).filter((version2) => Boolean(version2))
59615
60409
  };
59616
60410
  }
59617
- async hasImport(sourceId2) {
60411
+ /** Batched `hasImport`: one `IN` query per 500 ids instead of one RPC per row. */
60412
+ async hasImports(ids) {
59618
60413
  this.assertReady();
59619
- const row = await this.rpc.statement({
59620
- sql: "SELECT source_id FROM memory_imports WHERE source_id=?",
59621
- params: [sourceId2],
59622
- mode: "get"
59623
- });
59624
- return Boolean(row);
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);
59625
60429
  }
59626
60430
  async recordImport(sourceId2, memoryId) {
59627
60431
  this.assertReady();
@@ -59648,8 +60452,8 @@ __export(serviceFactory_exports, {
59648
60452
  isMemorySemanticEnabled: () => isMemorySemanticEnabled,
59649
60453
  isMemoryV2Enabled: () => isMemoryV2Enabled
59650
60454
  });
59651
- import { createHash as createHash20 } from "node:crypto";
59652
- import { promises as fs29 } from "node:fs";
60455
+ import { createHash as createHash21 } from "node:crypto";
60456
+ import { promises as fs30 } from "node:fs";
59653
60457
  import * as path71 from "node:path";
59654
60458
  function isMemoryV2Enabled(env = process.env) {
59655
60459
  if (env.ZELARI_MEMORY === "0") return false;
@@ -59669,13 +60473,13 @@ function semanticMinScore(env) {
59669
60473
  async function canonicalProjectId(projectRoot) {
59670
60474
  let canonical;
59671
60475
  try {
59672
- canonical = await fs29.realpath(projectRoot);
60476
+ canonical = await fs30.realpath(projectRoot);
59673
60477
  } catch {
59674
60478
  canonical = path71.resolve(projectRoot);
59675
60479
  }
59676
60480
  canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
59677
60481
  if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
59678
- return `project_${createHash20("sha256").update(canonical).digest("hex").slice(0, 24)}`;
60482
+ return `project_${createHash21("sha256").update(canonical).digest("hex").slice(0, 24)}`;
59679
60483
  }
59680
60484
  async function getMemoryService(projectRoot, env = process.env, options = {}) {
59681
60485
  const projectId2 = await canonicalProjectId(projectRoot);
@@ -60298,32 +61102,32 @@ __export(loadDurableContext_exports, {
60298
61102
  loadDurableContext: () => loadDurableContext
60299
61103
  });
60300
61104
  function clearDurableContextCache() {
60301
- cache2 = null;
61105
+ cache3 = null;
60302
61106
  }
60303
61107
  async function loadDurableContext(projectRoot, opts) {
60304
61108
  const env = opts?.env ?? process.env;
60305
61109
  if (!isStateEnabled(env)) return "";
60306
61110
  const cacheMs = opts?.cacheMs ?? DEFAULT_CACHE_MS;
60307
61111
  const now = Date.now();
60308
- if (cache2 && cache2.projectRoot === projectRoot && now - cache2.at < cacheMs) {
60309
- return cache2.text;
61112
+ if (cache3 && cache3.projectRoot === projectRoot && now - cache3.at < cacheMs) {
61113
+ return cache3.text;
60310
61114
  }
60311
61115
  try {
60312
61116
  const store6 = await getStateStore(projectRoot, env);
60313
61117
  const text = await store6.materializeContext(void 0, opts?.maxChars);
60314
- cache2 = { text: text || "", at: now, projectRoot };
60315
- return cache2.text;
61118
+ cache3 = { text: text || "", at: now, projectRoot };
61119
+ return cache3.text;
60316
61120
  } catch {
60317
61121
  return "";
60318
61122
  }
60319
61123
  }
60320
- var DEFAULT_CACHE_MS, cache2;
61124
+ var DEFAULT_CACHE_MS, cache3;
60321
61125
  var init_loadDurableContext = __esm({
60322
61126
  "src/cli/state/loadDurableContext.ts"() {
60323
61127
  "use strict";
60324
61128
  init_fileStateStore();
60325
61129
  DEFAULT_CACHE_MS = 2e3;
60326
- cache2 = null;
61130
+ cache3 = null;
60327
61131
  }
60328
61132
  });
60329
61133
 
@@ -62087,7 +62891,7 @@ __export(agentsMd_exports, {
62087
62891
  updateAgentsMd: () => updateAgentsMd
62088
62892
  });
62089
62893
  import { existsSync as existsSync44, readFileSync as readFileSync32, writeFileSync as writeFileSync20 } from "node:fs";
62090
- import { createHash as createHash21 } from "node:crypto";
62894
+ import { createHash as createHash22 } from "node:crypto";
62091
62895
  import { join as join34 } from "node:path";
62092
62896
  import { readFile as readFile10 } from "node:fs/promises";
62093
62897
  async function readPackageJson3(projectRoot) {
@@ -62302,7 +63106,7 @@ async function updateAgentsMd(ctx, projectRoot) {
62302
63106
  return { changed: true, sections: changedSections };
62303
63107
  }
62304
63108
  function hash2(s) {
62305
- return createHash21("sha256").update(s).digest("hex").slice(0, 16);
63109
+ return createHash22("sha256").update(s).digest("hex").slice(0, 16);
62306
63110
  }
62307
63111
  var AUTO_SECTIONS, MARKER_OPEN, MARKER_CLOSE, GENERATORS;
62308
63112
  var init_agentsMd = __esm({
@@ -63030,7 +63834,7 @@ __export(councilFeedback_exports, {
63030
63834
  FeedbackStore: () => FeedbackStore
63031
63835
  });
63032
63836
  import {
63033
- promises as fs30,
63837
+ promises as fs31,
63034
63838
  existsSync as existsSync49,
63035
63839
  readFileSync as readFileSync37,
63036
63840
  writeFileSync as writeFileSync22,
@@ -63163,7 +63967,7 @@ var init_councilFeedback = __esm({
63163
63967
  /** Async variant of load for callers that prefer async IO. */
63164
63968
  async loadAsync() {
63165
63969
  try {
63166
- const raw = await fs30.readFile(this.file, "utf-8");
63970
+ const raw = await fs31.readFile(this.file, "utf-8");
63167
63971
  const parsed = JSON.parse(raw);
63168
63972
  if (parsed && Array.isArray(parsed.entries)) {
63169
63973
  this.entries = parsed.entries.filter(
@@ -63483,7 +64287,7 @@ __export(fileBackend_exports, {
63483
64287
  isMemoryEnabled: () => isMemoryEnabled
63484
64288
  });
63485
64289
  import { randomUUID as randomUUID7 } from "node:crypto";
63486
- import { promises as fs31 } from "node:fs";
64290
+ import { promises as fs32 } from "node:fs";
63487
64291
  import * as path75 from "node:path";
63488
64292
  function tokenize2(text) {
63489
64293
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
@@ -63539,7 +64343,7 @@ var init_fileBackend = __esm({
63539
64343
  async init(projectRoot) {
63540
64344
  this.memoryDir = path75.join(projectRoot, ".zelari", "memory");
63541
64345
  this.logPath = path75.join(this.memoryDir, "log.jsonl");
63542
- await fs31.mkdir(this.memoryDir, { recursive: true });
64346
+ await fs32.mkdir(this.memoryDir, { recursive: true });
63543
64347
  }
63544
64348
  async add(content, metadata2 = {}, graph) {
63545
64349
  const fact = {
@@ -63549,7 +64353,7 @@ var init_fileBackend = __esm({
63549
64353
  ...graph ? { graph } : {},
63550
64354
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
63551
64355
  };
63552
- await fs31.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
64356
+ await fs32.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
63553
64357
  return fact.id;
63554
64358
  }
63555
64359
  async search(query, options = {}) {
@@ -63577,7 +64381,7 @@ var init_fileBackend = __esm({
63577
64381
  async readAll() {
63578
64382
  let raw;
63579
64383
  try {
63580
- raw = await fs31.readFile(this.logPath, "utf8");
64384
+ raw = await fs32.readFile(this.logPath, "utf8");
63581
64385
  } catch {
63582
64386
  return [];
63583
64387
  }
@@ -63610,7 +64414,7 @@ var init_fileBackend = __esm({
63610
64414
  });
63611
64415
 
63612
64416
  // src/cli/traceStore.ts
63613
- import { promises as fs32 } from "node:fs";
64417
+ import { promises as fs33 } from "node:fs";
63614
64418
  import * as path76 from "node:path";
63615
64419
  function traceDir(projectRoot) {
63616
64420
  return path76.join(projectRoot, ".zelari", "trace");
@@ -63620,13 +64424,13 @@ function tracePath(projectRoot, missionId) {
63620
64424
  }
63621
64425
  async function saveTrace(projectRoot, missionId, entries) {
63622
64426
  const dir = traceDir(projectRoot);
63623
- await fs32.mkdir(dir, { recursive: true });
64427
+ await fs33.mkdir(dir, { recursive: true });
63624
64428
  const payload = {
63625
64429
  missionId,
63626
64430
  ts: Date.now(),
63627
64431
  entries
63628
64432
  };
63629
- await fs32.writeFile(
64433
+ await fs33.writeFile(
63630
64434
  tracePath(projectRoot, missionId),
63631
64435
  JSON.stringify(payload, null, 2) + "\n",
63632
64436
  "utf8"
@@ -63657,7 +64461,7 @@ __export(zelariMission_exports, {
63657
64461
  runZelariMission: () => runZelariMission
63658
64462
  });
63659
64463
  import { randomUUID as randomUUID8 } from "node:crypto";
63660
- import { promises as fs33 } from "node:fs";
64464
+ import { promises as fs34 } from "node:fs";
63661
64465
  import * as path77 from "node:path";
63662
64466
  function resolveMaxIterations(env = process.env) {
63663
64467
  const raw = env.ZELARI_MISSION_MAX_ITER;
@@ -63702,8 +64506,8 @@ function isMissionAutoStart(env = process.env) {
63702
64506
  }
63703
64507
  async function writeMissionState(projectRoot, state3) {
63704
64508
  const dir = path77.join(projectRoot, ".zelari");
63705
- await fs33.mkdir(dir, { recursive: true });
63706
- await fs33.writeFile(
64509
+ await fs34.mkdir(dir, { recursive: true });
64510
+ await fs34.writeFile(
63707
64511
  path77.join(dir, "mission-state.json"),
63708
64512
  JSON.stringify(state3, null, 2) + "\n",
63709
64513
  "utf8"
@@ -63717,7 +64521,7 @@ async function writeMissionState(projectRoot, state3) {
63717
64521
  }
63718
64522
  async function loadMissionState(projectRoot) {
63719
64523
  try {
63720
- const raw = await fs33.readFile(
64524
+ const raw = await fs34.readFile(
63721
64525
  path77.join(projectRoot, ".zelari", "mission-state.json"),
63722
64526
  "utf8"
63723
64527
  );
@@ -66995,11 +67799,11 @@ var init_policy = __esm({
66995
67799
  });
66996
67800
 
66997
67801
  // src/cli/orchestration/facts.ts
66998
- import { promises as fs43 } from "node:fs";
67802
+ import { promises as fs44 } from "node:fs";
66999
67803
  import path88 from "node:path";
67000
67804
  async function collectRepoFileCount(root = process.cwd()) {
67001
67805
  try {
67002
- await fs43.readdir(root);
67806
+ await fs44.readdir(root);
67003
67807
  } catch {
67004
67808
  return void 0;
67005
67809
  }
@@ -67010,7 +67814,7 @@ async function collectRepoFileCount(root = process.cwd()) {
67010
67814
  const dir = queue.pop();
67011
67815
  let entries;
67012
67816
  try {
67013
- entries = await fs43.readdir(dir, { withFileTypes: true });
67817
+ entries = await fs44.readdir(dir, { withFileTypes: true });
67014
67818
  } catch {
67015
67819
  continue;
67016
67820
  }
@@ -67288,8 +68092,8 @@ function contractFor(t) {
67288
68092
  blockers
67289
68093
  };
67290
68094
  }
67291
- async function readHarnessState(sessionDir) {
67292
- const report = await readSessionLog(path89.join(sessionDir, "events.jsonl"));
68095
+ async function readHarnessState(sessionDir, cache4) {
68096
+ const report = await readSessionLogCached(path89.join(sessionDir, "events.jsonl"), cache4);
67293
68097
  return deriveHarnessState(report.events);
67294
68098
  }
67295
68099
  var init_harnessState = __esm({
@@ -67913,7 +68717,7 @@ var init_sandboxedFs = __esm({
67913
68717
  // src/cli/extensions/loader.ts
67914
68718
  import { join as join44 } from "node:path";
67915
68719
  import { readdirSync as readdirSync11, readFileSync as readFileSync43 } from "node:fs";
67916
- import { createHash as createHash22 } from "node:crypto";
68720
+ import { createHash as createHash23 } from "node:crypto";
67917
68721
  import { pathToFileURL as pathToFileURL3 } from "node:url";
67918
68722
  function globalExtensionsDir() {
67919
68723
  return join44(zelariHome(), "extensions");
@@ -67922,7 +68726,7 @@ function projectExtensionsDir(projectRoot) {
67922
68726
  return join44(projectRoot, ".zelari", "extensions");
67923
68727
  }
67924
68728
  function sha256File(file2) {
67925
- return createHash22("sha256").update(readFileSync43(file2)).digest("hex");
68729
+ return createHash23("sha256").update(readFileSync43(file2)).digest("hex");
67926
68730
  }
67927
68731
  function candidateFiles(dir) {
67928
68732
  let names;
@@ -67953,7 +68757,7 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
67953
68757
  skipped
67954
68758
  };
67955
68759
  const fsRoot = options.fsRoot ?? process.cwd();
67956
- let fs48 = null;
68760
+ let fs49 = null;
67957
68761
  const pending = [];
67958
68762
  for (const dir of dirs) {
67959
68763
  const files = candidateFiles(dir.path);
@@ -68008,9 +68812,9 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
68008
68812
  skipped.push(`${file2}: missing ZelariExtension export`);
68009
68813
  continue;
68010
68814
  }
68011
- if (!fs48) fs48 = bindSandboxedFs(fsRoot);
68815
+ if (!fs49) fs49 = bindSandboxedFs(fsRoot);
68012
68816
  try {
68013
- await runtime.registry.registerExtension(ext, { fs: fs48 });
68817
+ await runtime.registry.registerExtension(ext, { fs: fs49 });
68014
68818
  runtime.loaded.push({ id: ext.id, file: file2, scope });
68015
68819
  } catch (err) {
68016
68820
  const msg = err instanceof Error ? err.message : String(err);
@@ -68068,7 +68872,7 @@ var init_loader = __esm({
68068
68872
  });
68069
68873
 
68070
68874
  // src/cli/headless/runOneTurn.ts
68071
- import { promises as fs44 } from "node:fs";
68875
+ import { promises as fs45 } from "node:fs";
68072
68876
  import path92 from "node:path";
68073
68877
  function planModeFromOpts(opts) {
68074
68878
  return (opts.phase ?? "build") === "plan";
@@ -68639,8 +69443,8 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68639
69443
  if (json3) {
68640
69444
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
68641
69445
  else {
68642
- await fs44.mkdir(path92.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
68643
- await fs44.writeFile(opts.exportSessionPath, json3, "utf8");
69446
+ await fs45.mkdir(path92.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
69447
+ await fs45.writeFile(opts.exportSessionPath, json3, "utf8");
68644
69448
  }
68645
69449
  }
68646
69450
  } catch {
@@ -69687,7 +70491,7 @@ __export(triggerLock_exports, {
69687
70491
  lockPath: () => lockPath,
69688
70492
  releaseLock: () => releaseLock
69689
70493
  });
69690
- import { promises as fs45 } from "node:fs";
70494
+ import { promises as fs46 } from "node:fs";
69691
70495
  import * as path93 from "node:path";
69692
70496
  function lockPath(projectRoot) {
69693
70497
  return path93.join(projectRoot, ".zelari", "trigger.lock");
@@ -69704,9 +70508,9 @@ function isPidAlive(pid) {
69704
70508
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
69705
70509
  const lp = lockPath(projectRoot);
69706
70510
  const dir = path93.dirname(lp);
69707
- await fs45.mkdir(dir, { recursive: true });
70511
+ await fs46.mkdir(dir, { recursive: true });
69708
70512
  try {
69709
- const raw = await fs45.readFile(lp, "utf8");
70513
+ const raw = await fs46.readFile(lp, "utf8");
69710
70514
  const existing = JSON.parse(raw);
69711
70515
  if (existing.pid && isPidAlive(existing.pid)) {
69712
70516
  return { acquired: false, heldBy: existing.pid, lockPath: lp };
@@ -69717,13 +70521,13 @@ async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date())
69717
70521
  pid: process.pid,
69718
70522
  acquiredAt: now().toISOString()
69719
70523
  };
69720
- await fs45.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
70524
+ await fs46.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
69721
70525
  return { acquired: true, lockPath: lp };
69722
70526
  }
69723
70527
  async function releaseLock(projectRoot) {
69724
70528
  const lp = lockPath(projectRoot);
69725
70529
  try {
69726
- await fs45.unlink(lp);
70530
+ await fs46.unlink(lp);
69727
70531
  } catch {
69728
70532
  }
69729
70533
  }
@@ -69734,7 +70538,7 @@ var init_triggerLock = __esm({
69734
70538
  });
69735
70539
 
69736
70540
  // src/cli/runHeadless.ts
69737
- import { promises as fs46 } from "node:fs";
70541
+ import { promises as fs47 } from "node:fs";
69738
70542
  import path94 from "node:path";
69739
70543
  import { randomUUID as randomUUID10 } from "node:crypto";
69740
70544
  async function runHeadless(opts) {
@@ -69806,12 +70610,42 @@ ${err.stack}` : "";
69806
70610
  return 1;
69807
70611
  }
69808
70612
  const { buildProviderStream: buildProviderStream2 } = await Promise.resolve().then(() => (init_resolveStream(), resolveStream_exports));
69809
- providerStream = buildProviderStream2({
70613
+ const primaryStream = buildProviderStream2({
69810
70614
  providerId: provider,
69811
70615
  apiKey: key.apiKey,
69812
70616
  baseUrl: key.baseUrl,
69813
70617
  model
69814
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
+ }
69815
70649
  }
69816
70650
  return dispatchHeadlessTurn(opts, provider, model, providerStream, {
69817
70651
  // H10-fix3: the gate already ran above on the SAME input (no chdir in
@@ -69983,7 +70817,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
69983
70817
  log(`loading pre-flight plan: ${planPath}`);
69984
70818
  let raw;
69985
70819
  try {
69986
- raw = await fs46.readFile(planPath, "utf8");
70820
+ raw = await fs47.readFile(planPath, "utf8");
69987
70821
  } catch (e) {
69988
70822
  log(`plan file not found: ${planPath} (${e.message})`);
69989
70823
  exitCode = 1;
@@ -70024,8 +70858,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
70024
70858
  const planId = randomUUID10();
70025
70859
  const planDir = path94.join(cwd, ".zelari", "radio");
70026
70860
  const planPath = path94.join(planDir, `plan-${planId}.json`);
70027
- await fs46.mkdir(planDir, { recursive: true });
70028
- await fs46.writeFile(
70861
+ await fs47.mkdir(planDir, { recursive: true });
70862
+ await fs47.writeFile(
70029
70863
  planPath,
70030
70864
  JSON.stringify(
70031
70865
  { id: graph.id, nodes: [...graph.nodes.values()] },
@@ -70414,8 +71248,8 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
70414
71248
  if (json3) {
70415
71249
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
70416
71250
  else {
70417
- await fs46.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70418
- await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
71251
+ await fs47.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
71252
+ await fs47.writeFile(opts.exportSessionPath, json3, "utf8");
70419
71253
  }
70420
71254
  }
70421
71255
  } catch {
@@ -70886,8 +71720,8 @@ ${ragContext}` : slicePrompt;
70886
71720
  if (json3) {
70887
71721
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
70888
71722
  else {
70889
- await fs46.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70890
- await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
71723
+ await fs47.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
71724
+ await fs47.writeFile(opts.exportSessionPath, json3, "utf8");
70891
71725
  }
70892
71726
  }
70893
71727
  } catch {
@@ -72358,7 +73192,7 @@ import {
72358
73192
  writeFileSync as writeFileSync26
72359
73193
  } from "node:fs";
72360
73194
  import { join as join47 } from "node:path";
72361
- import { createHash as createHash23, randomBytes as randomBytes7, timingSafeEqual } from "node:crypto";
73195
+ import { createHash as createHash24, randomBytes as randomBytes7, timingSafeEqual } from "node:crypto";
72362
73196
  function getZelariHome() {
72363
73197
  return zelariHome();
72364
73198
  }
@@ -72426,16 +73260,16 @@ function loadOrCreateToken(explicit) {
72426
73260
  const token = randomBytes7(24).toString("base64url");
72427
73261
  writeFileSync26(path101, token + "\n", "utf8");
72428
73262
  try {
72429
- const fs48 = __require("node:fs");
72430
- fs48.chmodSync?.(path101, 384);
73263
+ const fs49 = __require("node:fs");
73264
+ fs49.chmodSync?.(path101, 384);
72431
73265
  } catch {
72432
73266
  }
72433
73267
  return { token, created: true };
72434
73268
  }
72435
73269
  function tokenMatches(expected, provided) {
72436
73270
  if (!provided) return false;
72437
- const a = createHash23("sha256").update(expected).digest();
72438
- const b = createHash23("sha256").update(provided).digest();
73271
+ const a = createHash24("sha256").update(expected).digest();
73272
+ const b = createHash24("sha256").update(provided).digest();
72439
73273
  try {
72440
73274
  return timingSafeEqual(a, b);
72441
73275
  } catch {
@@ -72704,7 +73538,7 @@ var init_askUserBridge = __esm({
72704
73538
  });
72705
73539
 
72706
73540
  // src/cli/serve/spineLockSweep.ts
72707
- import { promises as fs47 } from "node:fs";
73541
+ import { promises as fs48 } from "node:fs";
72708
73542
  import path96 from "node:path";
72709
73543
  async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
72710
73544
  const dir = sessionsDir2 ?? resolveSessionsDir();
@@ -72718,14 +73552,14 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
72718
73552
  const result = { swept: 0, kept: 0, errors: 0 };
72719
73553
  let entries;
72720
73554
  try {
72721
- entries = await fs47.readdir(dir);
73555
+ entries = await fs48.readdir(dir);
72722
73556
  } catch {
72723
73557
  return result;
72724
73558
  }
72725
73559
  for (const sessionId2 of entries) {
72726
73560
  const lockPath2 = path96.join(dir, sessionId2, "writer.lock");
72727
73561
  try {
72728
- const raw = await fs47.readFile(lockPath2, "utf-8");
73562
+ const raw = await fs48.readFile(lockPath2, "utf-8");
72729
73563
  let lockInfo = {};
72730
73564
  try {
72731
73565
  lockInfo = JSON.parse(raw);
@@ -72742,7 +73576,7 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
72742
73576
  result.kept += 1;
72743
73577
  continue;
72744
73578
  }
72745
- await fs47.rm(lockPath2, { force: true });
73579
+ await fs48.rm(lockPath2, { force: true });
72746
73580
  result.swept += 1;
72747
73581
  onSwept(sessionId2, verdict.reason);
72748
73582
  } catch (err) {
@@ -78050,107 +78884,8 @@ init_metrics3();
78050
78884
  init_modelPricing();
78051
78885
  init_openai_compatible();
78052
78886
  init_resolveStream();
78053
- import { useState as useState6, useRef as useRef4, useCallback as useCallback2 } from "react";
78054
-
78055
- // src/cli/providerFailover.ts
78056
- var DEFAULT_IS_TRANSIENT = (delta) => delta.kind === "error";
78057
- function providerFailover(options) {
78058
- const isTransient = options.isTransientFailure ?? DEFAULT_IS_TRANSIENT;
78059
- const primaryFailedMsg = options.fallbackLabel ? `[failover] primary failed, switching to ${options.fallbackLabel}` : "[failover] primary failed, switching to fallback";
78060
- const primaryThrewMsg = options.fallbackLabel ? `[failover] primary threw, switching to ${options.fallbackLabel}: ` : "[failover] primary threw: ";
78061
- const fallbackFailedMsg = options.fallbackLabel ? `[failover] fallback (${options.fallbackLabel}) also failed: ` : "[failover] fallback also failed: ";
78062
- return async function* (params) {
78063
- const triedFallback = { value: false };
78064
- try {
78065
- for await (const delta of options.primary(params)) {
78066
- if (isTransient(delta)) {
78067
- yield delta;
78068
- triedFallback.value = true;
78069
- yield {
78070
- kind: "error",
78071
- message: primaryFailedMsg
78072
- };
78073
- break;
78074
- }
78075
- yield delta;
78076
- }
78077
- } catch (err) {
78078
- triedFallback.value = true;
78079
- yield {
78080
- kind: "error",
78081
- message: `${primaryThrewMsg}${err instanceof Error ? err.message : String(err)}`
78082
- };
78083
- }
78084
- if (triedFallback.value) {
78085
- try {
78086
- for await (const delta of options.fallback(params)) {
78087
- yield delta;
78088
- }
78089
- } catch (err) {
78090
- yield {
78091
- kind: "error",
78092
- message: `${fallbackFailedMsg}${err instanceof Error ? err.message : String(err)}`
78093
- };
78094
- return;
78095
- }
78096
- }
78097
- };
78098
- }
78099
-
78100
- // src/cli/crossProviderFailover.ts
78101
- async function resolveFailoverStream(options) {
78102
- if (!options.failoverEnabled) {
78103
- return {
78104
- fallback: options.primary,
78105
- fallbackLabel: void 0,
78106
- warning: "",
78107
- reason: "disabled"
78108
- };
78109
- }
78110
- const requested = options.envValue?.trim();
78111
- if (!requested || requested.length === 0) {
78112
- return {
78113
- fallback: options.primary,
78114
- fallbackLabel: void 0,
78115
- warning: "",
78116
- reason: "unset"
78117
- };
78118
- }
78119
- const valid = new Set(options.validProviderIds);
78120
- if (!valid.has(requested)) {
78121
- return {
78122
- fallback: options.primary,
78123
- fallbackLabel: void 0,
78124
- warning: `[failover] ANATHEMA_FAILOVER_PROVIDER="${requested}" is not a known provider. Falling back to v3-G same-provider behavior. Available: ${options.validProviderIds.join(", ")}.`,
78125
- reason: "unknown"
78126
- };
78127
- }
78128
- if (requested === options.primaryProviderId) {
78129
- return {
78130
- fallback: options.primary,
78131
- fallbackLabel: void 0,
78132
- warning: "",
78133
- reason: "same-as-primary"
78134
- };
78135
- }
78136
- const fallbackConfig = await options.lookupFallbackConfig(requested);
78137
- if (!fallbackConfig) {
78138
- return {
78139
- fallback: options.primary,
78140
- fallbackLabel: void 0,
78141
- warning: `[failover] No API key configured for provider "${requested}". Falling back to v3-G same-provider behavior.`,
78142
- reason: "missing-key"
78143
- };
78144
- }
78145
- return {
78146
- fallback: options.buildStream(fallbackConfig),
78147
- fallbackLabel: requested,
78148
- warning: "",
78149
- reason: "resolved"
78150
- };
78151
- }
78152
-
78153
- // src/cli/hooks/useChatTurn.ts
78887
+ init_providerFailover();
78888
+ init_crossProviderFailover();
78154
78889
  init_shellResolver();
78155
78890
  init_keyStore();
78156
78891
  init_providerConfig();
@@ -78167,6 +78902,7 @@ init_completionProof();
78167
78902
  init_verifyStatus();
78168
78903
  init_nativeVerification();
78169
78904
  init_spineTelemetry();
78905
+ import { useState as useState6, useRef as useRef4, useCallback as useCallback2 } from "react";
78170
78906
 
78171
78907
  // src/cli/hooks/permissionPicker.ts
78172
78908
  init_toolPermissions();
@@ -81412,11 +82148,11 @@ function handleCacheStats(ctx) {
81412
82148
  // src/cli/slashHandlers/memory.ts
81413
82149
  init_messageHelpers();
81414
82150
  init_serviceFactory();
81415
- import { promises as fs35 } from "node:fs";
82151
+ import { promises as fs36 } from "node:fs";
81416
82152
  import * as path80 from "node:path";
81417
82153
 
81418
82154
  // src/cli/memory/promotion.ts
81419
- import { promises as fs34 } from "node:fs";
82155
+ import { promises as fs35 } from "node:fs";
81420
82156
  import * as path79 from "node:path";
81421
82157
  var START = "<!-- zelari:memory-promotions:start -->";
81422
82158
  var END = "<!-- zelari:memory-promotions:end -->";
@@ -81433,17 +82169,17 @@ async function promoteMemoryToAgentsMd(projectRoot, node) {
81433
82169
  if (!DURABLE_KINDS.has(node.kind)) {
81434
82170
  return { added: false, path: path79.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
81435
82171
  }
81436
- const root = await fs34.realpath(projectRoot).catch(() => path79.resolve(projectRoot));
82172
+ const root = await fs35.realpath(projectRoot).catch(() => path79.resolve(projectRoot));
81437
82173
  const target = path79.join(root, "AGENTS.md");
81438
82174
  try {
81439
- const stat8 = await fs34.lstat(target);
82175
+ const stat8 = await fs35.lstat(target);
81440
82176
  if (stat8.isSymbolicLink() || !stat8.isFile()) throw new Error("AGENTS.md must be a regular project file.");
81441
82177
  } catch (error51) {
81442
82178
  if (error51.code !== "ENOENT") throw error51;
81443
82179
  }
81444
82180
  let current = "";
81445
82181
  try {
81446
- current = await fs34.readFile(target, "utf8");
82182
+ current = await fs35.readFile(target, "utf8");
81447
82183
  } catch (error51) {
81448
82184
  if (error51.code !== "ENOENT") throw error51;
81449
82185
  }
@@ -81466,11 +82202,11 @@ ${END}
81466
82202
  `;
81467
82203
  }
81468
82204
  const temporary = `${target}.tmp-${process.pid}-${Date.now()}`;
81469
- await fs34.writeFile(temporary, updated, { encoding: "utf8", flag: "wx" });
82205
+ await fs35.writeFile(temporary, updated, { encoding: "utf8", flag: "wx" });
81470
82206
  try {
81471
- await fs34.rename(temporary, target);
82207
+ await fs35.rename(temporary, target);
81472
82208
  } catch (error51) {
81473
- await fs34.unlink(temporary).catch(() => void 0);
82209
+ await fs35.unlink(temporary).catch(() => void 0);
81474
82210
  throw error51;
81475
82211
  }
81476
82212
  return { added: true, path: target };
@@ -81504,7 +82240,7 @@ function isInside(root, target) {
81504
82240
  }
81505
82241
  async function safeExportPath(cwd, requested) {
81506
82242
  const lexicalRoot = path80.resolve(cwd);
81507
- const root = await fs35.realpath(lexicalRoot).catch(() => lexicalRoot);
82243
+ const root = await fs36.realpath(lexicalRoot).catch(() => lexicalRoot);
81508
82244
  const fallback = path80.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
81509
82245
  const target = requested?.trim() ? path80.resolve(root, requested.trim()) : fallback;
81510
82246
  if (!isInside(root, target)) {
@@ -81516,7 +82252,7 @@ async function safeExportPath(cwd, requested) {
81516
82252
  for (const segment of relativeParent.split(path80.sep).filter(Boolean)) {
81517
82253
  cursor = path80.join(cursor, segment);
81518
82254
  try {
81519
- const stat8 = await fs35.lstat(cursor);
82255
+ const stat8 = await fs36.lstat(cursor);
81520
82256
  if (stat8.isSymbolicLink()) {
81521
82257
  throw new Error("Export path must not traverse a symbolic link.");
81522
82258
  }
@@ -81526,7 +82262,7 @@ async function safeExportPath(cwd, requested) {
81526
82262
  }
81527
82263
  }
81528
82264
  try {
81529
- if ((await fs35.lstat(target)).isSymbolicLink()) {
82265
+ if ((await fs36.lstat(target)).isSymbolicLink()) {
81530
82266
  throw new Error("Export target must not be a symbolic link.");
81531
82267
  }
81532
82268
  } catch (error51) {
@@ -81686,13 +82422,13 @@ ${message}` : message
81686
82422
  }
81687
82423
  case "export": {
81688
82424
  const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
81689
- await fs35.mkdir(path80.dirname(target), { recursive: true });
81690
- const root = await fs35.realpath(ctx.cwd).catch(() => path80.resolve(ctx.cwd));
81691
- const realParent = await fs35.realpath(path80.dirname(target));
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));
81692
82428
  if (!isInside(root, realParent)) {
81693
82429
  throw new Error("Export path resolves outside the active project.");
81694
82430
  }
81695
- await fs35.writeFile(target, JSON.stringify(await memory.export(), null, 2) + "\n", "utf8");
82431
+ await fs36.writeFile(target, JSON.stringify(await memory.export(), null, 2) + "\n", "utf8");
81696
82432
  emit(`[memory] export written to ${target}`);
81697
82433
  return;
81698
82434
  }
@@ -81897,12 +82633,12 @@ ${digest}
81897
82633
  init_auditLogger();
81898
82634
  init_toolRegistry();
81899
82635
  init_messageHelpers();
81900
- import { promises as fs37 } from "node:fs";
82636
+ import { promises as fs38 } from "node:fs";
81901
82637
 
81902
82638
  // src/cli/tools/krakenCsvFanout.ts
81903
82639
  init_zod();
81904
82640
  init_taskTool();
81905
- import { promises as fs36 } from "node:fs";
82641
+ import { promises as fs37 } from "node:fs";
81906
82642
  import path81 from "node:path";
81907
82643
  import { randomBytes as randomBytes6 } from "node:crypto";
81908
82644
  var CsvFanoutArgsSchema = external_exports.object({
@@ -81924,7 +82660,7 @@ var CsvFanoutArgsSchema = external_exports.object({
81924
82660
  max_runtime_seconds: external_exports.number().int().positive().optional()
81925
82661
  });
81926
82662
  async function readCsv(filePath) {
81927
- const text = await fs36.readFile(filePath, "utf8");
82663
+ const text = await fs37.readFile(filePath, "utf8");
81928
82664
  return parseCsv(text);
81929
82665
  }
81930
82666
  function parseCsv(text) {
@@ -82054,7 +82790,7 @@ async function runCsvFanout(args, deps, opts) {
82054
82790
  errored += 1;
82055
82791
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
82056
82792
  }
82057
- await fs36.mkdir(path81.dirname(absOut), { recursive: true });
82793
+ await fs37.mkdir(path81.dirname(absOut), { recursive: true });
82058
82794
  await queueWrite(serializeCsv(outHeaders, outputRecords));
82059
82795
  }
82060
82796
  }
@@ -82076,8 +82812,8 @@ async function runCsvFanout(args, deps, opts) {
82076
82812
  }
82077
82813
  async function atomicWrite(file2, contents) {
82078
82814
  const tmp = `${file2}.${process.pid}.${Date.now()}.${randomBytes6(6).toString("hex")}.tmp`;
82079
- await fs36.writeFile(tmp, contents, "utf8");
82080
- await fs36.rename(tmp, file2);
82815
+ await fs37.writeFile(tmp, contents, "utf8");
82816
+ await fs37.rename(tmp, file2);
82081
82817
  }
82082
82818
 
82083
82819
  // src/cli/slashHandlers/krakenFanout.ts
@@ -82175,7 +82911,7 @@ async function handleKrakenFanout(ctx, raw) {
82175
82911
  }
82176
82912
  const absCsv = isAbsolute3(parsed.args.csv_path) ? parsed.args.csv_path : joinPath(ctx.cwd, parsed.args.csv_path);
82177
82913
  try {
82178
- await fs37.access(absCsv);
82914
+ await fs38.access(absCsv);
82179
82915
  } catch {
82180
82916
  appendSystem(ctx.setMessages, `[kraken fanout] source CSV not found: ${absCsv}`);
82181
82917
  return;
@@ -82248,7 +82984,7 @@ function splitArgs(s) {
82248
82984
 
82249
82985
  // src/cli/slashHandlers/krakenWorkbench.ts
82250
82986
  init_messageHelpers();
82251
- import { promises as fs38 } from "node:fs";
82987
+ import { promises as fs39 } from "node:fs";
82252
82988
  import path82 from "node:path";
82253
82989
 
82254
82990
  // src/cli/kraken/workbenchView.ts
@@ -82370,11 +83106,11 @@ async function handleKrakenWorkbench(ctx) {
82370
83106
  let latest = null;
82371
83107
  let latestMtime = 0;
82372
83108
  try {
82373
- const files = await fs38.readdir(dir);
83109
+ const files = await fs39.readdir(dir);
82374
83110
  for (const f of files) {
82375
83111
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
82376
83112
  const full = path82.join(dir, f);
82377
- const stat8 = await fs38.stat(full);
83113
+ const stat8 = await fs39.stat(full);
82378
83114
  if (stat8.mtimeMs > latestMtime) {
82379
83115
  latestMtime = stat8.mtimeMs;
82380
83116
  latest = full;
@@ -82386,7 +83122,7 @@ async function handleKrakenWorkbench(ctx) {
82386
83122
  appendSystem(ctx.setMessages, "[kraken workbench] no workbench file found (.zelari/radio/workbench-*.md)");
82387
83123
  return;
82388
83124
  }
82389
- const content = await fs38.readFile(latest, "utf8");
83125
+ const content = await fs39.readFile(latest, "utf8");
82390
83126
  const parsed = parseWorkbench(content);
82391
83127
  const rendered = formatWorkbenchForTerminal(parsed);
82392
83128
  if (!rendered.trim()) {
@@ -82700,20 +83436,20 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
82700
83436
  // src/cli/slashHandlers/promoteMember.ts
82701
83437
  init_messageHelpers();
82702
83438
  init_paths();
82703
- import { promises as fs39 } from "node:fs";
83439
+ import { promises as fs40 } from "node:fs";
82704
83440
  import path85 from "node:path";
82705
83441
  async function handlePromoteMember(ctx, memberId) {
82706
83442
  try {
82707
83443
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
82708
83444
  const { skill, markdown } = promoteMember2(memberId);
82709
83445
  const skillDir = skillsDir();
82710
- await fs39.mkdir(skillDir, { recursive: true });
83446
+ await fs40.mkdir(skillDir, { recursive: true });
82711
83447
  const filePath = path85.join(skillDir, `${skill.id}.md`);
82712
- const previous = await fs39.readFile(filePath, "utf8").catch(() => null);
82713
- const { createHash: createHash24 } = await import("node:crypto");
82714
- const sha = (s) => createHash24("sha256").update(s, "utf8").digest("hex");
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");
82715
83451
  const lineage = `<!-- lineage: genome=sha256:${sha(markdown)} parent=${previous ? `sha256:${sha(previous)}` : "none"} promotedBy=user promotedAt=${(/* @__PURE__ */ new Date()).toISOString()} -->`;
82716
- await fs39.writeFile(filePath, `${markdown}
83452
+ await fs40.writeFile(filePath, `${markdown}
82717
83453
  ${lineage}
82718
83454
  `, "utf8");
82719
83455
  appendSystem(
@@ -82733,7 +83469,7 @@ ${lineage}
82733
83469
 
82734
83470
  // src/cli/branchManager.ts
82735
83471
  init_paths();
82736
- import { promises as fs40, existsSync as existsSync55, readFileSync as readFileSync41, writeFileSync as writeFileSync24, mkdirSync as mkdirSync21, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
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";
82737
83473
  import path86 from "node:path";
82738
83474
  var META_FILENAME = "meta.json";
82739
83475
  var SESSIONS_SUBDIR = "sessions";
@@ -82781,7 +83517,7 @@ function writeBranchMeta(name, baseDir, meta3) {
82781
83517
  async function countSessions(name, baseDir) {
82782
83518
  const sessionsPath = sessionsPathFor(name, baseDir);
82783
83519
  try {
82784
- const entries = await fs40.readdir(sessionsPath);
83520
+ const entries = await fs41.readdir(sessionsPath);
82785
83521
  return entries.filter((e) => e.endsWith(".jsonl")).length;
82786
83522
  } catch (err) {
82787
83523
  if (err.code === "ENOENT") return 0;
@@ -82834,7 +83570,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
82834
83570
  const branchSessionsPath = sessionsPathFor(name, baseDir);
82835
83571
  mkdirSync21(branchSessionsPath, { recursive: true });
82836
83572
  const destPath = path86.join(branchSessionsPath, `${fromSessionId}.jsonl`);
82837
- await fs40.copyFile(sourcePath, destPath);
83573
+ await fs41.copyFile(sourcePath, destPath);
82838
83574
  const meta3 = {
82839
83575
  name,
82840
83576
  createdAt: Date.now(),
@@ -82852,7 +83588,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
82852
83588
  async function listBranches(baseDir = getBranchesBaseDir()) {
82853
83589
  let entries;
82854
83590
  try {
82855
- entries = await fs40.readdir(baseDir);
83591
+ entries = await fs41.readdir(baseDir);
82856
83592
  } catch (err) {
82857
83593
  if (err.code === "ENOENT") return [];
82858
83594
  throw err;
@@ -82936,7 +83672,7 @@ async function handleBranchCheckout(ctx, branchName) {
82936
83672
 
82937
83673
  // src/cli/slashHandlers/workspace.ts
82938
83674
  init_messageHelpers();
82939
- import { promises as fs41 } from "node:fs";
83675
+ import { promises as fs42 } from "node:fs";
82940
83676
  import path87 from "node:path";
82941
83677
  async function handleWorkspaceShow(ctx, what) {
82942
83678
  try {
@@ -82946,7 +83682,7 @@ async function handleWorkspaceShow(ctx, what) {
82946
83682
  case "plan": {
82947
83683
  const planPath = path87.join(zelari, "plan.md");
82948
83684
  try {
82949
- content = await fs41.readFile(planPath, "utf-8");
83685
+ content = await fs42.readFile(planPath, "utf-8");
82950
83686
  } catch {
82951
83687
  content = "(no plan.md yet \u2014 run a council session first)";
82952
83688
  }
@@ -82955,7 +83691,7 @@ async function handleWorkspaceShow(ctx, what) {
82955
83691
  case "decisions": {
82956
83692
  const decisionsDir = path87.join(zelari, "decisions");
82957
83693
  try {
82958
- const files = (await fs41.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
83694
+ const files = (await fs42.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
82959
83695
  if (files.length === 0) {
82960
83696
  content = "(no ADRs yet \u2014 invoke /council to generate some)";
82961
83697
  } else {
@@ -82963,7 +83699,7 @@ async function handleWorkspaceShow(ctx, what) {
82963
83699
  `];
82964
83700
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
82965
83701
  for (const f of files) {
82966
- const raw = await fs41.readFile(path87.join(decisionsDir, f), "utf-8");
83702
+ const raw = await fs42.readFile(path87.join(decisionsDir, f), "utf-8");
82967
83703
  const { meta: meta3, body } = parseFrontmatter2(raw);
82968
83704
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
82969
83705
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -82978,7 +83714,7 @@ async function handleWorkspaceShow(ctx, what) {
82978
83714
  case "risks": {
82979
83715
  const risksPath = path87.join(zelari, "risks.md");
82980
83716
  try {
82981
- content = await fs41.readFile(risksPath, "utf-8");
83717
+ content = await fs42.readFile(risksPath, "utf-8");
82982
83718
  } catch {
82983
83719
  content = "(no risks.md yet)";
82984
83720
  }
@@ -82987,7 +83723,7 @@ async function handleWorkspaceShow(ctx, what) {
82987
83723
  case "agents": {
82988
83724
  const agentsPath = path87.join(process.cwd(), "AGENTS.MD");
82989
83725
  try {
82990
- content = await fs41.readFile(agentsPath, "utf-8");
83726
+ content = await fs42.readFile(agentsPath, "utf-8");
82991
83727
  } catch {
82992
83728
  content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
82993
83729
  }
@@ -82996,7 +83732,7 @@ async function handleWorkspaceShow(ctx, what) {
82996
83732
  case "docs": {
82997
83733
  const docsDir = path87.join(zelari, "docs");
82998
83734
  try {
82999
- const files = (await fs41.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
83735
+ const files = (await fs42.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
83000
83736
  content = files.length ? `# Docs (${files.length})
83001
83737
 
83002
83738
  ` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
@@ -83037,7 +83773,7 @@ async function handleWorkspaceReset(ctx, force) {
83037
83773
  }
83038
83774
  try {
83039
83775
  const target = path87.join(process.cwd(), ".zelari");
83040
- await fs41.rm(target, { recursive: true, force: true });
83776
+ await fs42.rm(target, { recursive: true, force: true });
83041
83777
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
83042
83778
  } catch (err) {
83043
83779
  appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
@@ -83048,13 +83784,13 @@ async function handleWorkspaceReset(ctx, force) {
83048
83784
  init_provider2();
83049
83785
 
83050
83786
  // src/cli/skillHistory.ts
83051
- import { promises as fs42, existsSync as existsSync56, statSync as statSync8, renameSync as renameSync6, appendFileSync as appendFileSync5, mkdirSync as mkdirSync22 } from "node:fs";
83787
+ import { promises as fs43, existsSync as existsSync56, statSync as statSync8, renameSync as renameSync6, appendFileSync as appendFileSync5, mkdirSync as mkdirSync22 } from "node:fs";
83052
83788
  init_paths();
83053
83789
  var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
83054
83790
  async function readSkillHistory(file2) {
83055
83791
  let raw = "";
83056
83792
  try {
83057
- raw = await fs42.readFile(file2, "utf-8");
83793
+ raw = await fs43.readFile(file2, "utf-8");
83058
83794
  } catch {
83059
83795
  return [];
83060
83796
  }