zelari-code 2.16.5 → 2.17.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 (38) hide show
  1. package/dist/cli/app.js +3 -0
  2. package/dist/cli/app.js.map +1 -1
  3. package/dist/cli/companion/serve.js +29 -0
  4. package/dist/cli/companion/serve.js.map +1 -1
  5. package/dist/cli/harnessState.js +240 -0
  6. package/dist/cli/harnessState.js.map +1 -0
  7. package/dist/cli/headless/harnessStateEmit.js +38 -0
  8. package/dist/cli/headless/harnessStateEmit.js.map +1 -0
  9. package/dist/cli/headless/policyGate.js +6 -3
  10. package/dist/cli/headless/policyGate.js.map +1 -1
  11. package/dist/cli/headless/runOneTurn.js +29 -5
  12. package/dist/cli/headless/runOneTurn.js.map +1 -1
  13. package/dist/cli/headless.js +20 -9
  14. package/dist/cli/headless.js.map +1 -1
  15. package/dist/cli/hooks/useChatTurn.js +25 -1
  16. package/dist/cli/hooks/useChatTurn.js.map +1 -1
  17. package/dist/cli/hooks/useSlashDispatch.js +1 -1
  18. package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
  19. package/dist/cli/kraken/verificationBridge.js +27 -4
  20. package/dist/cli/kraken/verificationBridge.js.map +1 -1
  21. package/dist/cli/lsp/manager.js +31 -11
  22. package/dist/cli/lsp/manager.js.map +1 -1
  23. package/dist/cli/main.bundled.js +848 -471
  24. package/dist/cli/main.bundled.js.map +4 -4
  25. package/dist/cli/memory/fileBackend.js +7 -3
  26. package/dist/cli/memory/fileBackend.js.map +1 -1
  27. package/dist/cli/memory/spineTelemetry.js +49 -0
  28. package/dist/cli/memory/spineTelemetry.js.map +1 -0
  29. package/dist/cli/runHeadless.js +118 -30
  30. package/dist/cli/runHeadless.js.map +1 -1
  31. package/dist/cli/safety/jails/win32.js.map +1 -1
  32. package/dist/cli/serve/harnessServer.js +20 -1
  33. package/dist/cli/serve/harnessServer.js.map +1 -1
  34. package/dist/cli/sessionSpine.js +7 -13
  35. package/dist/cli/sessionSpine.js.map +1 -1
  36. package/dist/cli/slashHandlers/krakenGraph.js +11 -0
  37. package/dist/cli/slashHandlers/krakenGraph.js.map +1 -1
  38. package/package.json +2 -2
@@ -3288,10 +3288,10 @@ function mergeDefs(...defs) {
3288
3288
  function cloneDef(schema) {
3289
3289
  return mergeDefs(schema._zod.def);
3290
3290
  }
3291
- function getElementAtPath(obj, path87) {
3292
- if (!path87)
3291
+ function getElementAtPath(obj, path90) {
3292
+ if (!path90)
3293
3293
  return obj;
3294
- return path87.reduce((acc, key) => acc?.[key], obj);
3294
+ return path90.reduce((acc, key) => acc?.[key], obj);
3295
3295
  }
3296
3296
  function promiseAllObject(promisesObj) {
3297
3297
  const keys = Object.keys(promisesObj);
@@ -3619,11 +3619,11 @@ function explicitlyAborted(x, startIndex = 0) {
3619
3619
  }
3620
3620
  return false;
3621
3621
  }
3622
- function prefixIssues(path87, issues) {
3622
+ function prefixIssues(path90, issues) {
3623
3623
  return issues.map((iss) => {
3624
3624
  var _a3;
3625
3625
  (_a3 = iss).path ?? (_a3.path = []);
3626
- iss.path.unshift(path87);
3626
+ iss.path.unshift(path90);
3627
3627
  return iss;
3628
3628
  });
3629
3629
  }
@@ -3841,16 +3841,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
3841
3841
  }
3842
3842
  function formatError(error51, mapper = (issue2) => issue2.message) {
3843
3843
  const fieldErrors = { _errors: [] };
3844
- const processError = (error52, path87 = []) => {
3844
+ const processError = (error52, path90 = []) => {
3845
3845
  for (const issue2 of error52.issues) {
3846
3846
  if (issue2.code === "invalid_union" && issue2.errors.length) {
3847
- issue2.errors.map((issues) => processError({ issues }, [...path87, ...issue2.path]));
3847
+ issue2.errors.map((issues) => processError({ issues }, [...path90, ...issue2.path]));
3848
3848
  } else if (issue2.code === "invalid_key") {
3849
- processError({ issues: issue2.issues }, [...path87, ...issue2.path]);
3849
+ processError({ issues: issue2.issues }, [...path90, ...issue2.path]);
3850
3850
  } else if (issue2.code === "invalid_element") {
3851
- processError({ issues: issue2.issues }, [...path87, ...issue2.path]);
3851
+ processError({ issues: issue2.issues }, [...path90, ...issue2.path]);
3852
3852
  } else {
3853
- const fullpath = [...path87, ...issue2.path];
3853
+ const fullpath = [...path90, ...issue2.path];
3854
3854
  if (fullpath.length === 0) {
3855
3855
  fieldErrors._errors.push(mapper(issue2));
3856
3856
  } else {
@@ -3877,17 +3877,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
3877
3877
  }
3878
3878
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
3879
3879
  const result = { errors: [] };
3880
- const processError = (error52, path87 = []) => {
3880
+ const processError = (error52, path90 = []) => {
3881
3881
  var _a3, _b;
3882
3882
  for (const issue2 of error52.issues) {
3883
3883
  if (issue2.code === "invalid_union" && issue2.errors.length) {
3884
- issue2.errors.map((issues) => processError({ issues }, [...path87, ...issue2.path]));
3884
+ issue2.errors.map((issues) => processError({ issues }, [...path90, ...issue2.path]));
3885
3885
  } else if (issue2.code === "invalid_key") {
3886
- processError({ issues: issue2.issues }, [...path87, ...issue2.path]);
3886
+ processError({ issues: issue2.issues }, [...path90, ...issue2.path]);
3887
3887
  } else if (issue2.code === "invalid_element") {
3888
- processError({ issues: issue2.issues }, [...path87, ...issue2.path]);
3888
+ processError({ issues: issue2.issues }, [...path90, ...issue2.path]);
3889
3889
  } else {
3890
- const fullpath = [...path87, ...issue2.path];
3890
+ const fullpath = [...path90, ...issue2.path];
3891
3891
  if (fullpath.length === 0) {
3892
3892
  result.errors.push(mapper(issue2));
3893
3893
  continue;
@@ -3919,8 +3919,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
3919
3919
  }
3920
3920
  function toDotPath(_path) {
3921
3921
  const segs = [];
3922
- const path87 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
3923
- for (const seg of path87) {
3922
+ const path90 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
3923
+ for (const seg of path90) {
3924
3924
  if (typeof seg === "number")
3925
3925
  segs.push(`[${seg}]`);
3926
3926
  else if (typeof seg === "symbol")
@@ -17423,13 +17423,13 @@ function resolveRef(ref, ctx) {
17423
17423
  if (!ref.startsWith("#")) {
17424
17424
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
17425
17425
  }
17426
- const path87 = ref.slice(1).split("/").filter(Boolean);
17427
- if (path87.length === 0) {
17426
+ const path90 = ref.slice(1).split("/").filter(Boolean);
17427
+ if (path90.length === 0) {
17428
17428
  return ctx.rootSchema;
17429
17429
  }
17430
17430
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
17431
- if (path87[0] === defsKey) {
17432
- const key = path87[1];
17431
+ if (path90[0] === defsKey) {
17432
+ const key = path90[1];
17433
17433
  if (!key || !ctx.defs[key]) {
17434
17434
  throw new Error(`Reference not found: ${ref}`);
17435
17435
  }
@@ -19875,11 +19875,11 @@ var init_tools = __esm({
19875
19875
  if (!ctx.addDocument)
19876
19876
  return "Knowledge vault tool not available.";
19877
19877
  const title = args["title"] || "New Document";
19878
- const path87 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
19878
+ const path90 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
19879
19879
  const content = args["content"] || "";
19880
19880
  const tags = args["tags"] || [];
19881
19881
  ctx.addDocument({
19882
- path: path87,
19882
+ path: path90,
19883
19883
  title,
19884
19884
  content,
19885
19885
  format: "markdown",
@@ -19888,7 +19888,7 @@ var init_tools = __esm({
19888
19888
  workspaceId: ctx.workspaceId
19889
19889
  });
19890
19890
  ctx.addActivity("vault", "created document", title);
19891
- return `Document "${title}" created at "${path87}".`;
19891
+ return `Document "${title}" created at "${path90}".`;
19892
19892
  }
19893
19893
  }
19894
19894
  ];
@@ -23610,10 +23610,10 @@ ${fromRunCache}`,
23610
23610
  }
23611
23611
  const existing = inflight.get(callKey);
23612
23612
  if (existing) {
23613
- const shared2 = await existing;
23613
+ const shared = await existing;
23614
23614
  return {
23615
23615
  content: `[duplicate call \u2014 result repeated; do not call this tool again with the same arguments]
23616
- ${shared2.content}`,
23616
+ ${shared.content}`,
23617
23617
  isError: false,
23618
23618
  durationMs: 0
23619
23619
  };
@@ -25125,7 +25125,7 @@ var init_appServer = __esm({
25125
25125
  services = factory(root);
25126
25126
  this.workspaceServices.set(root, services);
25127
25127
  }
25128
- const shared2 = services;
25128
+ const shared = services;
25129
25129
  const server = this;
25130
25130
  const count = this.sessionCounts.get(root) ?? 0;
25131
25131
  this.sessionCounts.set(root, count + 1);
@@ -25133,13 +25133,13 @@ var init_appServer = __esm({
25133
25133
  const session = {
25134
25134
  id: id3,
25135
25135
  workspaceRoot: root,
25136
- services: shared2,
25136
+ services: shared,
25137
25137
  runTurn(input) {
25138
25138
  const deps = {
25139
25139
  session: { id: id3, workspaceRoot: root },
25140
25140
  services: {
25141
- ...shared2,
25142
- completionProofWriter: server.trackProofWriter(shared2.completionProofWriter)
25141
+ ...shared,
25142
+ completionProofWriter: server.trackProofWriter(shared.completionProofWriter)
25143
25143
  }
25144
25144
  };
25145
25145
  return runTurn(input, deps);
@@ -25150,10 +25150,10 @@ var init_appServer = __esm({
25150
25150
  server.sessionCounts.set(root, remaining);
25151
25151
  if (remaining <= 0) {
25152
25152
  server.sessionCounts.delete(root);
25153
- const shared3 = server.workspaceServices.get(root);
25153
+ const shared2 = server.workspaceServices.get(root);
25154
25154
  server.workspaceServices.delete(root);
25155
25155
  try {
25156
- shared3?.lspManager?.dispose();
25156
+ shared2?.lspManager?.dispose();
25157
25157
  } catch {
25158
25158
  }
25159
25159
  }
@@ -26138,11 +26138,11 @@ var init_synthesisAudit = __esm({
26138
26138
  import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
26139
26139
  import { join as join4 } from "node:path";
26140
26140
  function loadNfrSpec(zelariRoot) {
26141
- const path87 = join4(zelariRoot, "nfr-spec.json");
26142
- if (!existsSync7(path87))
26141
+ const path90 = join4(zelariRoot, "nfr-spec.json");
26142
+ if (!existsSync7(path90))
26143
26143
  return null;
26144
26144
  try {
26145
- const raw = JSON.parse(readFileSync7(path87, "utf8"));
26145
+ const raw = JSON.parse(readFileSync7(path90, "utf8"));
26146
26146
  if (raw.version !== 1 || !Array.isArray(raw.targets))
26147
26147
  return null;
26148
26148
  return raw;
@@ -28448,9 +28448,9 @@ var init_types5 = __esm({
28448
28448
  import { readFileSync as readFileSync12 } from "node:fs";
28449
28449
  import { join as join10 } from "node:path";
28450
28450
  function readLessonsDeduped(zelariRoot) {
28451
- const path87 = join10(zelariRoot, LESSONS_FILE);
28451
+ const path90 = join10(zelariRoot, LESSONS_FILE);
28452
28452
  try {
28453
- const raw = readFileSync12(path87, "utf8");
28453
+ const raw = readFileSync12(path90, "utf8");
28454
28454
  const byId = /* @__PURE__ */ new Map();
28455
28455
  for (const line of raw.split(/\r?\n/)) {
28456
28456
  if (!line.trim())
@@ -28551,8 +28551,8 @@ function keywordsFrom(check2, signature) {
28551
28551
  return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
28552
28552
  }
28553
28553
  function writeLesson(zelariRoot, lesson) {
28554
- const path87 = join11(zelariRoot, LESSONS_FILE);
28555
- appendFileSync(path87, `${JSON.stringify(lesson)}
28554
+ const path90 = join11(zelariRoot, LESSONS_FILE);
28555
+ appendFileSync(path90, `${JSON.stringify(lesson)}
28556
28556
  `, "utf8");
28557
28557
  }
28558
28558
  function findSimilar(lessons, signature) {
@@ -30515,9 +30515,9 @@ function findCycle(nodes) {
30515
30515
  if (color.get(start) !== WHITE)
30516
30516
  continue;
30517
30517
  const stack = [[start, 0]];
30518
- const path87 = [];
30518
+ const path90 = [];
30519
30519
  color.set(start, GRAY);
30520
- path87.push(start);
30520
+ path90.push(start);
30521
30521
  while (stack.length > 0) {
30522
30522
  const top = stack[stack.length - 1];
30523
30523
  const [id3, idx] = top;
@@ -30530,17 +30530,17 @@ function findCycle(nodes) {
30530
30530
  continue;
30531
30531
  const c = color.get(dep);
30532
30532
  if (c === GRAY) {
30533
- const at = path87.indexOf(dep);
30534
- return [...path87.slice(at), dep];
30533
+ const at = path90.indexOf(dep);
30534
+ return [...path90.slice(at), dep];
30535
30535
  }
30536
30536
  if (c === WHITE) {
30537
30537
  color.set(dep, GRAY);
30538
- path87.push(dep);
30538
+ path90.push(dep);
30539
30539
  stack.push([dep, 0]);
30540
30540
  }
30541
30541
  } else {
30542
30542
  color.set(id3, BLACK);
30543
- path87.pop();
30543
+ path90.pop();
30544
30544
  stack.pop();
30545
30545
  }
30546
30546
  }
@@ -31460,8 +31460,8 @@ var init_runner = __esm({
31460
31460
  failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
31461
31461
  pending: []
31462
31462
  };
31463
- const path87 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
31464
- this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path87}`);
31463
+ const path90 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
31464
+ this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path90}`);
31465
31465
  return snapshot;
31466
31466
  }
31467
31467
  callLog(msg, data) {
@@ -31553,16 +31553,12 @@ var init_types9 = __esm({
31553
31553
  // once at session start / manifest change. State-only (never model-surface):
31554
31554
  // data = {manifest, manifestHash}. Schema review per ADR-0021.
31555
31555
  "session.harness_manifest",
31556
- // 2.6.1 (closure plan §6): resume-time harness drift record. State-only:
31557
- // data = {originalManifestHash, currentManifestHash}. Non-blocking signal.
31558
- "session.harness_drift",
31559
31556
  "user.message",
31560
31557
  "assistant.message",
31561
31558
  "tool.call",
31562
31559
  "tool.result",
31563
31560
  // 2.x B (crash-safe recovery): dangling call classified. State-only.
31564
31561
  "tool.interrupted",
31565
- "context.injected",
31566
31562
  "session.compacted",
31567
31563
  "task.created",
31568
31564
  "task.updated",
@@ -31571,7 +31567,6 @@ var init_types9 = __esm({
31571
31567
  // State-only: compaction projects it into CompactionStateSnapshot.
31572
31568
  "task.contract",
31573
31569
  "task.contract_updated",
31574
- "kraken.task",
31575
31570
  "council.member",
31576
31571
  "mission.phase",
31577
31572
  "mission.replan",
@@ -33917,16 +33912,16 @@ function runRetentionFromEnv() {
33917
33912
  maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
33918
33913
  };
33919
33914
  }
33920
- async function dirSize(path87) {
33915
+ async function dirSize(path90) {
33921
33916
  let total = 0;
33922
33917
  let entries;
33923
33918
  try {
33924
- entries = await readdir(path87, { withFileTypes: true });
33919
+ entries = await readdir(path90, { withFileTypes: true });
33925
33920
  } catch {
33926
33921
  return 0;
33927
33922
  }
33928
33923
  for (const entry of entries) {
33929
- const child = join13(path87, entry.name);
33924
+ const child = join13(path90, entry.name);
33930
33925
  if (entry.isDirectory())
33931
33926
  total += await dirSize(child);
33932
33927
  else {
@@ -33953,19 +33948,19 @@ async function enforceRunRetention(runsDir, options = {}) {
33953
33948
  for (const entry of entries) {
33954
33949
  if (!entry.isDirectory())
33955
33950
  continue;
33956
- const path87 = join13(runsDir, entry.name);
33951
+ const path90 = join13(runsDir, entry.name);
33957
33952
  let startedAt = 0;
33958
33953
  let endedAt;
33959
33954
  let completed = false;
33960
33955
  try {
33961
- const manifest = JSON.parse(await readFile(join13(path87, "manifest.json"), "utf8"));
33956
+ const manifest = JSON.parse(await readFile(join13(path90, "manifest.json"), "utf8"));
33962
33957
  startedAt = manifest.startedAt ?? 0;
33963
33958
  endedAt = manifest.endedAt;
33964
33959
  completed = Boolean(endedAt) && manifest.status !== "running";
33965
33960
  } catch {
33966
33961
  completed = false;
33967
33962
  }
33968
- infos.push({ name: entry.name, path: path87, startedAt, endedAt, completed, bytes: await dirSize(path87) });
33963
+ infos.push({ name: entry.name, path: path90, startedAt, endedAt, completed, bytes: await dirSize(path90) });
33969
33964
  }
33970
33965
  const remove = async (info) => {
33971
33966
  await rm(info.path, { recursive: true, force: true });
@@ -34737,12 +34732,12 @@ var init_engine = __esm({
34737
34732
  * content digest) and the returned ref carries the event seq when the
34738
34733
  * emitter resolved one.
34739
34734
  */
34740
- async fsEvidence(observation, path87, sha256, content, extra = {}) {
34735
+ async fsEvidence(observation, path90, sha256, content, extra = {}) {
34741
34736
  const digest = sha256 && content !== void 0 ? sha256(content) : void 0;
34742
- const seq = await this.emitEvidence({ observation, path: path87, ...extra, ...digest ? { digest } : {} });
34737
+ const seq = await this.emitEvidence({ observation, path: path90, ...extra, ...digest ? { digest } : {} });
34743
34738
  return {
34744
34739
  tier: "fs-observation",
34745
- ref: path87,
34740
+ ref: path90,
34746
34741
  capturedAt: Date.now(),
34747
34742
  ...digest ? { digest } : {},
34748
34743
  ...seq !== void 0 ? { seq } : {}
@@ -37126,15 +37121,8 @@ async function noteHarnessLifecycle(spine, sessionId2, profileId, budget, baseDi
37126
37121
  resourcePolicy: budget.policy
37127
37122
  });
37128
37123
  if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
37129
- const original = await lastHarnessManifestHash(sessionId2, baseDir);
37130
- if (original === null) {
37124
+ if (await lastHarnessManifestHash(sessionId2, baseDir) === null) {
37131
37125
  spine.harnessManifest(manifest, manifestHash);
37132
- } else if (original !== manifestHash) {
37133
- await spine.appendEvent({
37134
- kind: "session.harness_drift",
37135
- actor: ACTOR_SYSTEM,
37136
- data: { originalManifestHash: original, currentManifestHash: manifestHash }
37137
- });
37138
37126
  }
37139
37127
  } else {
37140
37128
  spine.harnessManifest(manifest, manifestHash);
@@ -37892,9 +37880,9 @@ function spillToolOutput(fullText, meta3) {
37892
37880
  const rnd = randomBytes3(3).toString("hex");
37893
37881
  const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
37894
37882
  const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
37895
- const path87 = join14(dir, file2);
37896
- writeFileSync11(path87, fullText, "utf8");
37897
- return path87;
37883
+ const path90 = join14(dir, file2);
37884
+ writeFileSync11(path90, fullText, "utf8");
37885
+ return path90;
37898
37886
  } catch {
37899
37887
  return null;
37900
37888
  }
@@ -37940,10 +37928,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
37940
37928
  ${tail2}`;
37941
37929
  }
37942
37930
  if (doSpill) {
37943
- const path87 = spillToolOutput(text, { toolName: opts.toolName });
37944
- if (path87) {
37931
+ const path90 = spillToolOutput(text, { toolName: opts.toolName });
37932
+ if (path90) {
37945
37933
  const spillNote = `
37946
- \u2026 [full output spilled to: ${path87} \u2014 re-read with read_file if you need the complete text] \u2026`;
37934
+ \u2026 [full output spilled to: ${path90} \u2014 re-read with read_file if you need the complete text] \u2026`;
37947
37935
  if (preview.includes("] \u2026\n")) {
37948
37936
  preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
37949
37937
  `);
@@ -41056,28 +41044,28 @@ var init_storage = __esm({
41056
41044
  VALID_SCALARS = /^(true|false|null|~)$/i;
41057
41045
  Storage = class {
41058
41046
  /** Read a Markdown file with frontmatter. Throws if not found. */
41059
- read(path87) {
41060
- if (!existsSync19(path87)) {
41061
- throw new Error(`File not found: ${path87}`);
41047
+ read(path90) {
41048
+ if (!existsSync19(path90)) {
41049
+ throw new Error(`File not found: ${path90}`);
41062
41050
  }
41063
- const md = readFileSync16(path87, "utf8");
41051
+ const md = readFileSync16(path90, "utf8");
41064
41052
  return parseFrontmatter(md);
41065
41053
  }
41066
41054
  /** Read a Markdown file; returns null if not found. */
41067
- readIfExists(path87) {
41068
- if (!existsSync19(path87)) return null;
41069
- return this.read(path87);
41055
+ readIfExists(path90) {
41056
+ if (!existsSync19(path90)) return null;
41057
+ return this.read(path90);
41070
41058
  }
41071
41059
  /**
41072
41060
  * Write a Markdown file atomically (tmp + rename). Creates parent dirs.
41073
41061
  * The meta object is serialized as YAML frontmatter; body as Markdown.
41074
41062
  */
41075
- write(path87, meta3, body) {
41076
- mkdirSync10(dirname2(path87), { recursive: true });
41077
- const tmp = path87 + ".tmp-" + process.pid;
41063
+ write(path90, meta3, body) {
41064
+ mkdirSync10(dirname2(path90), { recursive: true });
41065
+ const tmp = path90 + ".tmp-" + process.pid;
41078
41066
  const md = serializeFrontmatter(meta3, body);
41079
41067
  writeFileSync13(tmp, md, "utf8");
41080
- renameSync(tmp, path87);
41068
+ renameSync(tmp, path90);
41081
41069
  }
41082
41070
  /** List all .md files in a directory (non-recursive). */
41083
41071
  listMarkdown(dir) {
@@ -41139,8 +41127,8 @@ function nextPlanTaskId(store6) {
41139
41127
  return `t${store6.counter}`;
41140
41128
  }
41141
41129
  function writePlanTaskArtifact(rootDir, task) {
41142
- const path87 = join18(rootDir, "plan-tasks", `${task.id}.md`);
41143
- mkdirSync11(dirname3(path87), { recursive: true });
41130
+ const path90 = join18(rootDir, "plan-tasks", `${task.id}.md`);
41131
+ mkdirSync11(dirname3(path90), { recursive: true });
41144
41132
  const meta3 = {
41145
41133
  kind: "task",
41146
41134
  id: task.id,
@@ -41161,7 +41149,7 @@ function writePlanTaskArtifact(rootDir, task) {
41161
41149
  task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
41162
41150
  ""
41163
41151
  ].filter((l) => l !== null).join("\n");
41164
- new Storage().write(path87, meta3, body);
41152
+ new Storage().write(path90, meta3, body);
41165
41153
  }
41166
41154
  function loadHandle(rootDir) {
41167
41155
  const jsonPath = join18(rootDir, "plan.json");
@@ -42960,6 +42948,7 @@ var init_servers = __esm({
42960
42948
  // src/cli/lsp/manager.ts
42961
42949
  import { spawn as spawn10 } from "node:child_process";
42962
42950
  import { readFileSync as readFileSync18 } from "node:fs";
42951
+ import path34 from "node:path";
42963
42952
  function processTransport(child) {
42964
42953
  return {
42965
42954
  send: (data) => {
@@ -42976,12 +42965,22 @@ function processTransport(child) {
42976
42965
  };
42977
42966
  }
42978
42967
  function getSharedLspManager(cwd = process.cwd()) {
42979
- if (shared && shared.cwd === cwd) return shared.manager;
42980
- shared?.manager.dispose();
42968
+ const key = path34.resolve(cwd);
42969
+ const existing = sharedByRoot.get(key);
42970
+ if (existing) return existing;
42981
42971
  const manager = new LspManager({ cwd });
42982
- shared = { cwd, manager };
42972
+ sharedByRoot.set(key, manager);
42983
42973
  return manager;
42984
42974
  }
42975
+ function disposeSharedLspManager() {
42976
+ for (const manager of sharedByRoot.values()) {
42977
+ try {
42978
+ manager.dispose();
42979
+ } catch {
42980
+ }
42981
+ }
42982
+ sharedByRoot.clear();
42983
+ }
42985
42984
  function normalizeLocations(res) {
42986
42985
  if (!res) return [];
42987
42986
  const arr = Array.isArray(res) ? res : [res];
@@ -43048,7 +43047,7 @@ function normalizeRename(res) {
43048
43047
  if (files.length === 0) return null;
43049
43048
  return { files, totalEdits: total };
43050
43049
  }
43051
- var SYMBOL_KINDS, LspManager, shared;
43050
+ var SYMBOL_KINDS, LspManager, sharedByRoot;
43052
43051
  var init_manager = __esm({
43053
43052
  "src/cli/lsp/manager.ts"() {
43054
43053
  "use strict";
@@ -43271,11 +43270,11 @@ var init_manager = __esm({
43271
43270
  this.servers.clear();
43272
43271
  }
43273
43272
  };
43274
- shared = null;
43273
+ sharedByRoot = /* @__PURE__ */ new Map();
43275
43274
  if (typeof process !== "undefined" && typeof process.once === "function") {
43276
43275
  process.once("exit", () => {
43277
43276
  try {
43278
- shared?.manager.dispose();
43277
+ disposeSharedLspManager();
43279
43278
  } catch {
43280
43279
  }
43281
43280
  });
@@ -43285,9 +43284,9 @@ var init_manager = __esm({
43285
43284
 
43286
43285
  // src/cli/ast/engine.ts
43287
43286
  import { readFile as readFile2 } from "node:fs/promises";
43288
- import path34 from "node:path";
43287
+ import path35 from "node:path";
43289
43288
  function isAstSupported(file2) {
43290
- return TS_EXTENSIONS.has(path34.extname(file2).toLowerCase());
43289
+ return TS_EXTENSIONS.has(path35.extname(file2).toLowerCase());
43291
43290
  }
43292
43291
  function loadTs() {
43293
43292
  if (!tsPromise) {
@@ -43299,8 +43298,8 @@ function errMessage(err) {
43299
43298
  return err instanceof Error ? err.message : String(err);
43300
43299
  }
43301
43300
  async function parseFileSymbolsDiag(file2, cwd) {
43302
- const resolvedPath = path34.isAbsolute(file2) ? file2 : path34.join(cwd ?? process.cwd(), file2);
43303
- const extension = path34.extname(resolvedPath).toLowerCase();
43301
+ const resolvedPath = path35.isAbsolute(file2) ? file2 : path35.join(cwd ?? process.cwd(), file2);
43302
+ const extension = path35.extname(resolvedPath).toLowerCase();
43304
43303
  if (!TS_EXTENSIONS.has(extension)) {
43305
43304
  return {
43306
43305
  status: "unsupported-extension",
@@ -43342,7 +43341,7 @@ async function parseFileSymbolsDiag(file2, cwd) {
43342
43341
  }
43343
43342
  let source2;
43344
43343
  try {
43345
- source2 = ts.createSourceFile(path34.basename(resolvedPath), text, ts.ScriptTarget.Latest, true);
43344
+ source2 = ts.createSourceFile(path35.basename(resolvedPath), text, ts.ScriptTarget.Latest, true);
43346
43345
  } catch (err) {
43347
43346
  return {
43348
43347
  status: "parse-error",
@@ -43567,11 +43566,11 @@ var init_store2 = __esm({
43567
43566
  // src/cli/semantic/index.ts
43568
43567
  import { promises as fs18, existsSync as existsSync24, readFileSync as readFileSync19 } from "node:fs";
43569
43568
  import { homedir as homedir7 } from "node:os";
43570
- import path35 from "node:path";
43569
+ import path36 from "node:path";
43571
43570
  import { createHash as createHash12 } from "node:crypto";
43572
43571
  function getIndexPath(root) {
43573
- const hash3 = createHash12("sha1").update(path35.resolve(root)).digest("hex").slice(0, 16);
43574
- return process.env.ZELARI_SEMANTIC_FILE ?? path35.join(homedir7(), ".tmp", "zelari-code", "semantic", `${hash3}.json`);
43572
+ const hash3 = createHash12("sha1").update(path36.resolve(root)).digest("hex").slice(0, 16);
43573
+ return process.env.ZELARI_SEMANTIC_FILE ?? path36.join(homedir7(), ".tmp", "zelari-code", "semantic", `${hash3}.json`);
43575
43574
  }
43576
43575
  async function collectSourceFiles(root, maxFiles = 1500) {
43577
43576
  const out = [];
@@ -43589,11 +43588,11 @@ async function collectSourceFiles(root, maxFiles = 1500) {
43589
43588
  if (entry.isDirectory() && IGNORE_DIRS.has(entry.name)) continue;
43590
43589
  if (entry.isDirectory()) continue;
43591
43590
  }
43592
- const full = path35.join(dir, entry.name);
43591
+ const full = path36.join(dir, entry.name);
43593
43592
  if (entry.isDirectory()) {
43594
43593
  if (IGNORE_DIRS.has(entry.name)) continue;
43595
43594
  await walk2(full);
43596
- } else if (SOURCE_EXTENSIONS.has(path35.extname(entry.name).toLowerCase())) {
43595
+ } else if (SOURCE_EXTENSIONS.has(path36.extname(entry.name).toLowerCase())) {
43597
43596
  out.push(full);
43598
43597
  }
43599
43598
  }
@@ -43642,7 +43641,7 @@ async function buildIndex(files, embed, options) {
43642
43641
  }
43643
43642
  async function saveIndex(root, data) {
43644
43643
  const file2 = getIndexPath(root);
43645
- await fs18.mkdir(path35.dirname(file2), { recursive: true });
43644
+ await fs18.mkdir(path36.dirname(file2), { recursive: true });
43646
43645
  const tmp = `${file2}.tmp-${process.pid}`;
43647
43646
  await fs18.writeFile(tmp, JSON.stringify(data), "utf8");
43648
43647
  await fs18.rename(tmp, file2);
@@ -44524,7 +44523,7 @@ var init_provider = __esm({
44524
44523
  });
44525
44524
 
44526
44525
  // src/cli/semantic/tools.ts
44527
- import path36 from "node:path";
44526
+ import path37 from "node:path";
44528
44527
  function createSemanticTool(deps) {
44529
44528
  const buildEmbedFn = deps.buildEmbedFn ?? buildProviderEmbedFn;
44530
44529
  return {
@@ -44551,7 +44550,7 @@ function createSemanticTool(deps) {
44551
44550
  return typedOk({
44552
44551
  count: res.hits.length,
44553
44552
  results: res.hits.map((h) => ({
44554
- location: `${path36.relative(deps.root, h.file) || h.file}:${h.startLine}-${h.endLine}`,
44553
+ location: `${path37.relative(deps.root, h.file) || h.file}:${h.startLine}-${h.endLine}`,
44555
44554
  score: Number(h.score.toFixed(3)),
44556
44555
  preview: h.text.length > 400 ? `${h.text.slice(0, 400)}\u2026` : h.text
44557
44556
  }))
@@ -44571,7 +44570,7 @@ var init_tools4 = __esm({
44571
44570
 
44572
44571
  // src/cli/browser/driver.ts
44573
44572
  import { createRequire as createRequire2 } from "node:module";
44574
- import path37 from "node:path";
44573
+ import path38 from "node:path";
44575
44574
  import { pathToFileURL } from "node:url";
44576
44575
  function asPlaywright(mod) {
44577
44576
  if (!mod || typeof mod !== "object") return null;
@@ -44582,10 +44581,10 @@ function asPlaywright(mod) {
44582
44581
  return null;
44583
44582
  }
44584
44583
  async function loadPlaywright(cwd) {
44585
- const base2 = cwd && cwd.length > 0 ? path37.resolve(cwd) : void 0;
44584
+ const base2 = cwd && cwd.length > 0 ? path38.resolve(cwd) : void 0;
44586
44585
  if (base2) {
44587
44586
  try {
44588
- const req = createRequire2(path37.join(base2, "package.json"));
44587
+ const req = createRequire2(path38.join(base2, "package.json"));
44589
44588
  const resolved = req.resolve("playwright");
44590
44589
  const mod = await import(pathToFileURL(resolved).href);
44591
44590
  const pw = asPlaywright(mod);
@@ -44800,7 +44799,7 @@ var init_driver = __esm({
44800
44799
  });
44801
44800
 
44802
44801
  // src/cli/browser/tools.ts
44803
- import path38 from "node:path";
44802
+ import path39 from "node:path";
44804
44803
  import os8 from "node:os";
44805
44804
  function createBrowserTool(deps = {}) {
44806
44805
  return {
@@ -44819,7 +44818,7 @@ function createBrowserTool(deps = {}) {
44819
44818
  execute: async (args, ctx) => {
44820
44819
  const a = args;
44821
44820
  const dir = deps.screenshotDir ?? os8.tmpdir();
44822
- const screenshotPath = a.screenshot === false ? void 0 : path38.join(dir, `zelari-browser-${Date.now()}.png`);
44821
+ const screenshotPath = a.screenshot === false ? void 0 : path39.join(dir, `zelari-browser-${Date.now()}.png`);
44823
44822
  const result = await runBrowserCheck(
44824
44823
  {
44825
44824
  url: a.url,
@@ -44931,21 +44930,21 @@ function normalizeAuth(auth) {
44931
44930
  return "agent";
44932
44931
  }
44933
44932
  function readSecrets() {
44934
- const path87 = getSshSecretsPath();
44935
- if (!existsSync25(path87)) return {};
44933
+ const path90 = getSshSecretsPath();
44934
+ if (!existsSync25(path90)) return {};
44936
44935
  try {
44937
- return JSON.parse(readFileSync20(path87, "utf8"));
44936
+ return JSON.parse(readFileSync20(path90, "utf8"));
44938
44937
  } catch {
44939
44938
  return {};
44940
44939
  }
44941
44940
  }
44942
44941
  function writeSecrets(data) {
44943
- const path87 = getSshSecretsPath();
44944
- mkdirSync12(dirname4(path87), { recursive: true });
44945
- writeFileSync15(path87, `${JSON.stringify(data, null, 2)}
44942
+ const path90 = getSshSecretsPath();
44943
+ mkdirSync12(dirname4(path90), { recursive: true });
44944
+ writeFileSync15(path90, `${JSON.stringify(data, null, 2)}
44946
44945
  `, "utf8");
44947
44946
  try {
44948
- chmodSync(path87, 384);
44947
+ chmodSync(path90, 384);
44949
44948
  } catch {
44950
44949
  }
44951
44950
  }
@@ -44974,10 +44973,10 @@ function deleteSshPassword(id3) {
44974
44973
  writeSecrets({ passwords });
44975
44974
  }
44976
44975
  function readStore2() {
44977
- const path87 = getSshTargetsPath();
44978
- if (!existsSync25(path87)) return [];
44976
+ const path90 = getSshTargetsPath();
44977
+ if (!existsSync25(path90)) return [];
44979
44978
  try {
44980
- const parsed = JSON.parse(readFileSync20(path87, "utf8"));
44979
+ const parsed = JSON.parse(readFileSync20(path90, "utf8"));
44981
44980
  const list = Array.isArray(parsed.targets) ? parsed.targets : [];
44982
44981
  return list.filter(
44983
44982
  (t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
@@ -44992,11 +44991,11 @@ function readStore2() {
44992
44991
  }
44993
44992
  }
44994
44993
  function writeStore2(targets) {
44995
- const path87 = getSshTargetsPath();
44996
- mkdirSync12(dirname4(path87), { recursive: true });
44994
+ const path90 = getSshTargetsPath();
44995
+ mkdirSync12(dirname4(path90), { recursive: true });
44997
44996
  const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
44998
44997
  writeFileSync15(
44999
- path87,
44998
+ path90,
45000
44999
  `${JSON.stringify({ targets: clean }, null, 2)}
45001
45000
  `,
45002
45001
  "utf8"
@@ -45242,11 +45241,11 @@ function formatSshTargetsForPrompt() {
45242
45241
  ];
45243
45242
  for (const t of targets) {
45244
45243
  const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
45245
- const path87 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
45244
+ const path90 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
45246
45245
  const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
45247
45246
  const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
45248
45247
  lines.push(
45249
- `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path87}${tags}${allow}`
45248
+ `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path90}${tags}${allow}`
45250
45249
  );
45251
45250
  }
45252
45251
  return lines.join("\n");
@@ -45373,10 +45372,10 @@ var init_tools6 = __esm({
45373
45372
 
45374
45373
  // src/cli/workspace/worldModel.ts
45375
45374
  import { promises as fs19 } from "node:fs";
45376
- import path39 from "node:path";
45375
+ import path40 from "node:path";
45377
45376
  import { spawn as spawn12 } from "node:child_process";
45378
45377
  function worldDir(cwd) {
45379
- return path39.join(cwd, WORLD_DIR_NAME);
45378
+ return path40.join(cwd, WORLD_DIR_NAME);
45380
45379
  }
45381
45380
  async function ensureWorldDir(cwd) {
45382
45381
  const dir = worldDir(cwd);
@@ -45386,10 +45385,10 @@ async function ensureWorldDir(cwd) {
45386
45385
  async function appendTimeline(cwd, entry) {
45387
45386
  const dir = await ensureWorldDir(cwd);
45388
45387
  const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
45389
- await fs19.appendFile(path39.join(dir, TIMELINE_FILE), line, "utf8");
45388
+ await fs19.appendFile(path40.join(dir, TIMELINE_FILE), line, "utf8");
45390
45389
  }
45391
45390
  async function readChecks(cwd) {
45392
- const p3 = path39.join(worldDir(cwd), CHECKS_FILE);
45391
+ const p3 = path40.join(worldDir(cwd), CHECKS_FILE);
45393
45392
  try {
45394
45393
  const raw = await fs19.readFile(p3, "utf8");
45395
45394
  const parsed = JSON.parse(raw);
@@ -45464,8 +45463,8 @@ function runShell(command, cwd, timeoutMs2, signal) {
45464
45463
  });
45465
45464
  }
45466
45465
  async function runBacktest(cwd, signal) {
45467
- const checksPath = path39.join(worldDir(cwd), CHECKS_FILE);
45468
- const hypothesisPath = path39.join(worldDir(cwd), HYPOTHESIS_FILE);
45466
+ const checksPath = path40.join(worldDir(cwd), CHECKS_FILE);
45467
+ const hypothesisPath = path40.join(worldDir(cwd), HYPOTHESIS_FILE);
45469
45468
  const checks = await readChecks(cwd);
45470
45469
  if (checks.length === 0) {
45471
45470
  return {
@@ -45534,7 +45533,7 @@ var init_worldModel = __esm({
45534
45533
  "use strict";
45535
45534
  init_zod();
45536
45535
  init_toolTypes();
45537
- WORLD_DIR_NAME = path39.join(".zelari", "world");
45536
+ WORLD_DIR_NAME = path40.join(".zelari", "world");
45538
45537
  HYPOTHESIS_FILE = "hypothesis.md";
45539
45538
  CHECKS_FILE = "checks.json";
45540
45539
  TIMELINE_FILE = "timeline.jsonl";
@@ -45551,7 +45550,7 @@ var init_worldModel = __esm({
45551
45550
  execute: async (args, ctx) => {
45552
45551
  try {
45553
45552
  const dir = await ensureWorldDir(ctx.cwd);
45554
- const file2 = path39.join(dir, HYPOTHESIS_FILE);
45553
+ const file2 = path40.join(dir, HYPOTHESIS_FILE);
45555
45554
  if (args.append) {
45556
45555
  const block = `
45557
45556
 
@@ -45590,7 +45589,7 @@ ${args.content}
45590
45589
  execute: async (args, ctx) => {
45591
45590
  try {
45592
45591
  const dir = await ensureWorldDir(ctx.cwd);
45593
- const file2 = path39.join(dir, CHECKS_FILE);
45592
+ const file2 = path40.join(dir, CHECKS_FILE);
45594
45593
  const body = { checks: args.checks };
45595
45594
  await fs19.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
45596
45595
  await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
@@ -45629,8 +45628,8 @@ ${args.content}
45629
45628
  stdoutPreview: "(dryRun)",
45630
45629
  mismatch: "dryRun"
45631
45630
  })),
45632
- hypothesisPath: path39.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
45633
- checksPath: path39.join(worldDir(ctx.cwd), CHECKS_FILE)
45631
+ hypothesisPath: path40.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
45632
+ checksPath: path40.join(worldDir(ctx.cwd), CHECKS_FILE)
45634
45633
  });
45635
45634
  }
45636
45635
  const result = await runBacktest(ctx.cwd, ctx.signal);
@@ -45654,7 +45653,7 @@ ${args.content}
45654
45653
  execute: async (args, ctx) => {
45655
45654
  try {
45656
45655
  const dir = await ensureWorldDir(ctx.cwd);
45657
- const file2 = path39.join(dir, TIMELINE_FILE);
45656
+ const file2 = path40.join(dir, TIMELINE_FILE);
45658
45657
  await appendTimeline(ctx.cwd, {
45659
45658
  kind: args.kind,
45660
45659
  summary: args.summary,
@@ -46317,12 +46316,12 @@ __export(folderTrust_exports, {
46317
46316
  });
46318
46317
  import { homedir as homedir9 } from "node:os";
46319
46318
  import { existsSync as existsSync26, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
46320
- import path40 from "node:path";
46319
+ import path41 from "node:path";
46321
46320
  function trustStorePath() {
46322
- return _overrideStorePath ?? path40.join(homedir9(), ".zelari-code", "trust.json");
46321
+ return _overrideStorePath ?? path41.join(homedir9(), ".zelari-code", "trust.json");
46323
46322
  }
46324
46323
  function normalize4(p3) {
46325
- const resolved = path40.resolve(p3);
46324
+ const resolved = path41.resolve(p3);
46326
46325
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
46327
46326
  }
46328
46327
  function readStore3() {
@@ -46338,7 +46337,7 @@ function readStore3() {
46338
46337
  function writeStore3(store6) {
46339
46338
  const p3 = trustStorePath();
46340
46339
  try {
46341
- mkdirSync13(path40.dirname(p3), { recursive: true });
46340
+ mkdirSync13(path41.dirname(p3), { recursive: true });
46342
46341
  writeFileSync16(p3, JSON.stringify(store6, null, 2), "utf8");
46343
46342
  } catch (err) {
46344
46343
  throw new Error(
@@ -46364,7 +46363,7 @@ function isFolderTrusted(folderPath) {
46364
46363
  }
46365
46364
  function trustFolder(folderPath) {
46366
46365
  const store6 = readStore3();
46367
- const normalized = path40.resolve(folderPath);
46366
+ const normalized = path41.resolve(folderPath);
46368
46367
  if (!store6.folders.some((f) => normalize4(f.path) === normalize4(normalized))) {
46369
46368
  store6.folders.push({ path: normalized, trustedAt: (/* @__PURE__ */ new Date()).toISOString() });
46370
46369
  writeStore3(store6);
@@ -46548,7 +46547,7 @@ __export(policyEngine_exports, {
46548
46547
  });
46549
46548
  import { readFileSync as readFileSync22 } from "node:fs";
46550
46549
  import { homedir as homedir11 } from "node:os";
46551
- import path41 from "node:path";
46550
+ import path42 from "node:path";
46552
46551
  function emptyPolicySet() {
46553
46552
  return { agents: /* @__PURE__ */ new Map(), warnings: [], precedence: policyPrecedenceFromEnv() };
46554
46553
  }
@@ -46793,9 +46792,9 @@ function loadPolicySet(root, opts = {}) {
46793
46792
  const mode = opts.mode ?? "permissive";
46794
46793
  const warnings = [];
46795
46794
  const precedence = policyPrecedenceFromEnv();
46796
- const project = readPolicyFile(path41.join(root, ".zelari", "policy.json"), warnings, mode);
46795
+ const project = readPolicyFile(path42.join(root, ".zelari", "policy.json"), warnings, mode);
46797
46796
  const global = readPolicyFile(
46798
- path41.join(opts.homeDir ?? homedir11(), ".zelari", "policy.json"),
46797
+ path42.join(opts.homeDir ?? homedir11(), ".zelari", "policy.json"),
46799
46798
  warnings,
46800
46799
  mode
46801
46800
  );
@@ -47232,7 +47231,7 @@ var init_resourceClaims = __esm({
47232
47231
  // src/cli/toolResultCache.ts
47233
47232
  import { createHash as createHash13 } from "node:crypto";
47234
47233
  import { promises as fs20 } from "node:fs";
47235
- import path42 from "node:path";
47234
+ import path43 from "node:path";
47236
47235
  function isToolCacheEnabled() {
47237
47236
  const raw = process.env.ZELARI_TOOL_CACHE;
47238
47237
  return raw !== "0" && raw !== "false" && raw !== "off";
@@ -47317,7 +47316,7 @@ async function statKey(toolName, input, ctx) {
47317
47316
  if (!input || typeof input !== "object") return null;
47318
47317
  const rawPath = input.path;
47319
47318
  if (typeof rawPath !== "string" || rawPath.length === 0) return null;
47320
- const abs = path42.isAbsolute(rawPath) ? rawPath : path42.join(ctx.cwd, rawPath);
47319
+ const abs = path43.isAbsolute(rawPath) ? rawPath : path43.join(ctx.cwd, rawPath);
47321
47320
  try {
47322
47321
  const st = await fs20.stat(abs);
47323
47322
  return hashKey({
@@ -47459,13 +47458,13 @@ function resolveKrakenSubModel(agent, parentModel, env = process.env, opts = {})
47459
47458
  const kindKey = agent === "explore" ? "ZELARI_KRAKEN_EXPLORE_MODEL" : agent === "verify" ? "ZELARI_KRAKEN_VERIFY_MODEL" : "ZELARI_KRAKEN_GENERAL_MODEL";
47460
47459
  const specific = env[kindKey]?.trim();
47461
47460
  if (specific) return specific;
47462
- const shared2 = env.ZELARI_KRAKEN_SUB_MODEL?.trim();
47463
- if (shared2) {
47461
+ const shared = env.ZELARI_KRAKEN_SUB_MODEL?.trim();
47462
+ if (shared) {
47464
47463
  if (agent === "general" && !env.ZELARI_KRAKEN_GENERAL_MODEL) {
47465
- if (env.ZELARI_KRAKEN_GENERAL_USES_SUB === "1") return shared2;
47464
+ if (env.ZELARI_KRAKEN_GENERAL_USES_SUB === "1") return shared;
47466
47465
  return parentModel;
47467
47466
  }
47468
- return shared2;
47467
+ return shared;
47469
47468
  }
47470
47469
  if (agent === "verify" && opts.familyCandidates && opts.familyCandidates.length > 0) {
47471
47470
  const picked = pickDifferentFamily(
@@ -47526,7 +47525,7 @@ __export(toolRegistry_exports, {
47526
47525
  wrapWithSandbox: () => wrapWithSandbox
47527
47526
  });
47528
47527
  import { existsSync as existsSync27 } from "node:fs";
47529
- import path43 from "node:path";
47528
+ import path44 from "node:path";
47530
47529
  function createBuiltinToolRegistry(options = {}) {
47531
47530
  const root = options.root ?? process.cwd();
47532
47531
  const audit = options.audit ?? new AuditLogger();
@@ -48084,14 +48083,14 @@ function wrapWithDiagnostics(original, root, runner) {
48084
48083
  function claimedSourcePath(token, args, root) {
48085
48084
  const cleaned = token.replace(/^["']|["']$/g, "");
48086
48085
  if (!cleaned || cleaned.startsWith("-")) return null;
48087
- if (!DIAG_SOURCE_EXTENSIONS.has(path43.extname(cleaned).toLowerCase())) return null;
48086
+ if (!DIAG_SOURCE_EXTENSIONS.has(path44.extname(cleaned).toLowerCase())) return null;
48088
48087
  const bases = [root];
48089
48088
  const cwd = args["cwd"];
48090
48089
  if (typeof cwd === "string" && cwd.length > 0) {
48091
- bases.unshift(path43.isAbsolute(cwd) ? cwd : path43.resolve(root, cwd));
48090
+ bases.unshift(path44.isAbsolute(cwd) ? cwd : path44.resolve(root, cwd));
48092
48091
  }
48093
48092
  for (const base2 of bases) {
48094
- const candidate = path43.isAbsolute(cleaned) ? path43.normalize(cleaned) : path43.resolve(base2, cleaned);
48093
+ const candidate = path44.isAbsolute(cleaned) ? path44.normalize(cleaned) : path44.resolve(base2, cleaned);
48095
48094
  try {
48096
48095
  const contained = resolveSandboxedPath(candidate, { root });
48097
48096
  if (existsSync27(contained)) return contained;
@@ -48379,7 +48378,7 @@ var init_toolRegistry = __esm({
48379
48378
 
48380
48379
  // src/cli/metrics.ts
48381
48380
  import { promises as fs21, existsSync as existsSync28, statSync as statSync4, renameSync as renameSync3, appendFileSync as appendFileSync3, mkdirSync as mkdirSync14 } from "node:fs";
48382
- import path44 from "node:path";
48381
+ import path45 from "node:path";
48383
48382
  import os9 from "node:os";
48384
48383
  async function readMetrics(file2) {
48385
48384
  let raw = "";
@@ -48428,8 +48427,8 @@ var init_metrics3 = __esm({
48428
48427
  file;
48429
48428
  writeQueue = Promise.resolve();
48430
48429
  constructor(file2) {
48431
- this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path44.join(os9.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
48432
- mkdirSync14(path44.dirname(this.file), { recursive: true });
48430
+ this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path45.join(os9.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
48431
+ mkdirSync14(path45.dirname(this.file), { recursive: true });
48433
48432
  }
48434
48433
  /** Metrics file path — doctor/summary readers use this. */
48435
48434
  get filePath() {
@@ -48752,7 +48751,7 @@ Current policy: **lead only**.
48752
48751
 
48753
48752
  // src/cli/kraken/verificationAdapters/node.ts
48754
48753
  import { readFile as readFile3, stat as stat2 } from "node:fs/promises";
48755
- import path45 from "node:path";
48754
+ import path46 from "node:path";
48756
48755
  async function fileExists(candidate) {
48757
48756
  try {
48758
48757
  return (await stat2(candidate)).isFile();
@@ -48762,7 +48761,7 @@ async function fileExists(candidate) {
48762
48761
  }
48763
48762
  async function readPackageJson(root) {
48764
48763
  try {
48765
- return JSON.parse(await readFile3(path45.join(root, "package.json"), "utf-8"));
48764
+ return JSON.parse(await readFile3(path46.join(root, "package.json"), "utf-8"));
48766
48765
  } catch {
48767
48766
  return null;
48768
48767
  }
@@ -48776,7 +48775,7 @@ async function resolvePackageManager(root) {
48776
48775
  const fromField = packageManagerFromField(await readPackageJson(root));
48777
48776
  if (fromField) return { pm: fromField, declaredToolchain: true };
48778
48777
  for (const [marker, pm] of PM_LOCKFILES) {
48779
- if (await fileExists(path45.join(root, marker))) return { pm, declaredToolchain: true };
48778
+ if (await fileExists(path46.join(root, marker))) return { pm, declaredToolchain: true };
48780
48779
  }
48781
48780
  return { pm: "npm", declaredToolchain: false };
48782
48781
  }
@@ -48799,7 +48798,7 @@ var init_node = __esm({
48799
48798
  KNOWN_PACKAGE_MANAGERS = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "bun"]);
48800
48799
  nodeAdapter = {
48801
48800
  async detect(root) {
48802
- if (!await fileExists(path45.join(root, "package.json"))) return 0;
48801
+ if (!await fileExists(path46.join(root, "package.json"))) return 0;
48803
48802
  const { declaredToolchain } = await resolvePackageManager(root);
48804
48803
  return declaredToolchain ? 20 : 10;
48805
48804
  },
@@ -48818,7 +48817,7 @@ var init_node = __esm({
48818
48817
 
48819
48818
  // src/cli/kraken/verificationAdapters/python.ts
48820
48819
  import { readFile as readFile4, stat as stat3 } from "node:fs/promises";
48821
- import path46 from "node:path";
48820
+ import path47 from "node:path";
48822
48821
  async function fileExists2(candidate) {
48823
48822
  try {
48824
48823
  return (await stat3(candidate)).isFile();
@@ -48854,7 +48853,7 @@ var init_python = __esm({
48854
48853
  async detect(root) {
48855
48854
  let best = 0;
48856
48855
  for (const [marker, score] of DETECT_MARKERS) {
48857
- if (score > best && await fileExists2(path46.join(root, marker))) best = score;
48856
+ if (score > best && await fileExists2(path47.join(root, marker))) best = score;
48858
48857
  }
48859
48858
  return best;
48860
48859
  },
@@ -48862,12 +48861,12 @@ var init_python = __esm({
48862
48861
  const present = /* @__PURE__ */ new Map();
48863
48862
  for (const name of SCAN_FILES) {
48864
48863
  try {
48865
- present.set(name, await readFile4(path46.join(root, name), "utf-8"));
48864
+ present.set(name, await readFile4(path47.join(root, name), "utf-8"));
48866
48865
  } catch {
48867
48866
  }
48868
48867
  }
48869
48868
  const hasToken = (token) => [...present.values()].some((text) => text.includes(token));
48870
- const pytestEvidenced = hasToken("pytest") || await dirExists(path46.join(root, "tests"));
48869
+ const pytestEvidenced = hasToken("pytest") || await dirExists(path47.join(root, "tests"));
48871
48870
  const mypyReferenced = hasToken("mypy") || present.has("mypy.ini") || present.has(".mypy.ini");
48872
48871
  const pyrightReferenced = hasToken("pyright") || present.has("pyrightconfig.json");
48873
48872
  return {
@@ -48883,7 +48882,7 @@ var init_python = __esm({
48883
48882
 
48884
48883
  // src/cli/kraken/verificationAdapters/rust.ts
48885
48884
  import { stat as stat4 } from "node:fs/promises";
48886
- import path47 from "node:path";
48885
+ import path48 from "node:path";
48887
48886
  async function fileExists3(candidate) {
48888
48887
  try {
48889
48888
  return (await stat4(candidate)).isFile();
@@ -48897,7 +48896,7 @@ var init_rust = __esm({
48897
48896
  "use strict";
48898
48897
  rustAdapter = {
48899
48898
  async detect(root) {
48900
- return await fileExists3(path47.join(root, "Cargo.toml")) ? 10 : 0;
48899
+ return await fileExists3(path48.join(root, "Cargo.toml")) ? 10 : 0;
48901
48900
  },
48902
48901
  async buildPlan(_root) {
48903
48902
  void _root;
@@ -48913,7 +48912,7 @@ var init_rust = __esm({
48913
48912
 
48914
48913
  // src/cli/kraken/verificationAdapters/go.ts
48915
48914
  import { stat as stat5 } from "node:fs/promises";
48916
- import path48 from "node:path";
48915
+ import path49 from "node:path";
48917
48916
  async function fileExists4(candidate) {
48918
48917
  try {
48919
48918
  return (await stat5(candidate)).isFile();
@@ -48927,7 +48926,7 @@ var init_go = __esm({
48927
48926
  "use strict";
48928
48927
  goAdapter = {
48929
48928
  async detect(root) {
48930
- return await fileExists4(path48.join(root, "go.mod")) ? 10 : 0;
48929
+ return await fileExists4(path49.join(root, "go.mod")) ? 10 : 0;
48931
48930
  },
48932
48931
  async buildPlan(_root) {
48933
48932
  return {
@@ -48943,7 +48942,7 @@ var init_go = __esm({
48943
48942
 
48944
48943
  // src/cli/kraken/verificationAdapters/java.ts
48945
48944
  import { stat as stat6 } from "node:fs/promises";
48946
- import path49 from "node:path";
48945
+ import path50 from "node:path";
48947
48946
  async function fileExists5(candidate) {
48948
48947
  try {
48949
48948
  return (await stat6(candidate)).isFile();
@@ -48953,13 +48952,13 @@ async function fileExists5(candidate) {
48953
48952
  }
48954
48953
  async function hasGradleMarker(root) {
48955
48954
  for (const [marker] of GRADLE_MARKERS) {
48956
- if (await fileExists5(path49.join(root, marker))) return true;
48955
+ if (await fileExists5(path50.join(root, marker))) return true;
48957
48956
  }
48958
48957
  return false;
48959
48958
  }
48960
48959
  async function gradleCommand(root, verb, platform = process.platform) {
48961
48960
  const wrapper = platform === "win32" ? "gradlew.bat" : "gradlew";
48962
- if (await fileExists5(path49.join(root, wrapper))) {
48961
+ if (await fileExists5(path50.join(root, wrapper))) {
48963
48962
  return platform === "win32" ? `gradlew.bat ${verb}` : `./gradlew ${verb}`;
48964
48963
  }
48965
48964
  return `gradle ${verb}`;
@@ -48984,7 +48983,7 @@ var init_java = __esm({
48984
48983
  async detect(root) {
48985
48984
  let best = 0;
48986
48985
  for (const [marker, score] of DETECT_MARKERS2) {
48987
- if (score > best && await fileExists5(path49.join(root, marker))) best = score;
48986
+ if (score > best && await fileExists5(path50.join(root, marker))) best = score;
48988
48987
  }
48989
48988
  return best;
48990
48989
  },
@@ -48997,7 +48996,7 @@ var init_java = __esm({
48997
48996
  buildCommand: await gradleCommand(root, "build")
48998
48997
  };
48999
48998
  }
49000
- if (await fileExists5(path49.join(root, "pom.xml"))) {
48999
+ if (await fileExists5(path50.join(root, "pom.xml"))) {
49001
49000
  return {
49002
49001
  typecheckCommand: null,
49003
49002
  // compilation rides the test/package lifecycle
@@ -49106,7 +49105,7 @@ __export(nativeVerification_exports, {
49106
49105
  resolvePackCommandsForRoot: () => resolvePackCommandsForRoot
49107
49106
  });
49108
49107
  import { readFile as readFile5 } from "node:fs/promises";
49109
- import path50 from "node:path";
49108
+ import path51 from "node:path";
49110
49109
  function nativePackEnabled(env = process.env) {
49111
49110
  const v = env.ZELARI_VERIFY_PACK?.toLowerCase();
49112
49111
  if (v === "0" || v === "off" || v === "false") return false;
@@ -49149,7 +49148,7 @@ function packTimeoutMs(env = process.env) {
49149
49148
  }
49150
49149
  async function readPackageScripts(cwd = process.cwd()) {
49151
49150
  try {
49152
- const raw = await readFile5(path50.join(cwd, "package.json"), "utf-8");
49151
+ const raw = await readFile5(path51.join(cwd, "package.json"), "utf-8");
49153
49152
  const parsed = JSON.parse(raw);
49154
49153
  if (parsed && typeof parsed === "object" && typeof parsed.scripts === "object") {
49155
49154
  return parsed.scripts;
@@ -49195,16 +49194,28 @@ var init_nativeVerification = __esm({
49195
49194
 
49196
49195
  // src/cli/kraken/verificationBridge.ts
49197
49196
  import { createHash as createHash14 } from "node:crypto";
49198
- function strictDoneEnabled(surface = "kraken") {
49197
+ function strictDoneEnabled(surface = "kraken", env = process.env) {
49199
49198
  if (surface === "mission") {
49200
- const v2 = process.env.ZELARI_MISSION_STRICT;
49199
+ const v2 = env.ZELARI_MISSION_STRICT;
49201
49200
  if (v2 === "0" || v2 === "false") return false;
49202
49201
  return true;
49203
49202
  }
49204
- const v = process.env.ZELARI_STRICT_DONE;
49203
+ const v = env.ZELARI_STRICT_DONE;
49205
49204
  if (v === "0" || v === "false") return false;
49206
49205
  return true;
49207
49206
  }
49207
+ function strictEnvOverlay(knobs, base2 = process.env) {
49208
+ const overlay = { ...base2 };
49209
+ if (knobs.strictDone !== void 0) {
49210
+ const v = knobs.strictDone ? "1" : "0";
49211
+ overlay.ZELARI_STRICT_DONE = v;
49212
+ overlay.ZELARI_MISSION_STRICT = v;
49213
+ }
49214
+ if (knobs.missionStrict !== void 0) {
49215
+ overlay.ZELARI_MISSION_STRICT = knobs.missionStrict ? "1" : "0";
49216
+ }
49217
+ return overlay;
49218
+ }
49208
49219
  function criterionId(check2, index) {
49209
49220
  const slug = check2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
49210
49221
  return `check-${index + 1}-${slug || "criterion"}`;
@@ -49341,7 +49352,7 @@ async function anchorSelectionEvidence(results, emit, toolTrace) {
49341
49352
  }
49342
49353
  async function evaluateStrictBuildGate(mode, options = {}) {
49343
49354
  const gate = evaluateKrakenCompletionGate(mode);
49344
- const strictOn = strictDoneEnabled(options.surface ?? "kraken");
49355
+ const strictOn = strictDoneEnabled(options.surface ?? "kraken", options.env);
49345
49356
  const nativeOn = nativePackEnabled(options.env ?? process.env);
49346
49357
  const selectionAvailable = gate.selectionUsed && gate.total > 0;
49347
49358
  const scopeContract = options.taskContract ?? activeContractScope()?.contract;
@@ -49670,7 +49681,7 @@ var init_completionProofAttestation = __esm({
49670
49681
  // src/cli/kraken/completionProofPersist.ts
49671
49682
  import { open, rename, rm as rm2 } from "node:fs/promises";
49672
49683
  import { randomBytes as randomBytes5 } from "node:crypto";
49673
- import path51 from "node:path";
49684
+ import path52 from "node:path";
49674
49685
  function isTruthyFlag2(v) {
49675
49686
  const n = v?.trim().toLowerCase();
49676
49687
  return n === "1" || n === "true" || n === "yes" || n === "on";
@@ -49712,8 +49723,8 @@ function isWindowsRenameBlock(err) {
49712
49723
  return code === "EPERM" || code === "ENOTEMPTY" || code === "EEXIST";
49713
49724
  }
49714
49725
  async function writeFileAtomic(target, data) {
49715
- const dir = path51.dirname(target);
49716
- const tmp = path51.join(dir, `.${path51.basename(target)}.${randomBytes5(6).toString("hex")}.tmp`);
49726
+ const dir = path52.dirname(target);
49727
+ const tmp = path52.join(dir, `.${path52.basename(target)}.${randomBytes5(6).toString("hex")}.tmp`);
49717
49728
  let fh = null;
49718
49729
  try {
49719
49730
  fh = await open(tmp, "w");
@@ -49759,7 +49770,7 @@ var init_completionProofPersist = __esm({
49759
49770
 
49760
49771
  // src/cli/kraken/completionProof.ts
49761
49772
  import { mkdir as mkdir2 } from "node:fs/promises";
49762
- import path52 from "node:path";
49773
+ import path53 from "node:path";
49763
49774
  function verdictOf(evaluation) {
49764
49775
  return evaluation.evaluation?.verdict ?? (evaluation.blocked ? "BLOCKED" : "PASS");
49765
49776
  }
@@ -49904,7 +49915,7 @@ async function writeCompletionProofDetailed(evaluation, options = {}) {
49904
49915
  const mode = options.persistenceMode ?? activeProofPersistenceMode();
49905
49916
  try {
49906
49917
  const baseDir = options.baseDir ?? process.cwd();
49907
- const dir = path52.join(baseDir, ".zelari");
49918
+ const dir = path53.join(baseDir, ".zelari");
49908
49919
  await mkdir2(dir, { recursive: true });
49909
49920
  const requested = options.attestation ?? {};
49910
49921
  const plan = requested.skipProbes || requested.verificationPlan !== void 0 ? void 0 : await defaultVerificationPlanSnapshot(baseDir);
@@ -49924,8 +49935,8 @@ async function writeCompletionProofDetailed(evaluation, options = {}) {
49924
49935
  baseDir
49925
49936
  );
49926
49937
  const rendered = renderCompletionProof(evaluation, options.meta ?? {}, wrapper.attestation);
49927
- const markdownPath = path52.join(dir, "completion-proof.md");
49928
- const jsonPath = path52.join(dir, "completion-proof.json");
49938
+ const markdownPath = path53.join(dir, "completion-proof.md");
49939
+ const jsonPath = path53.join(dir, "completion-proof.json");
49929
49940
  await writeFileAtomic(markdownPath, rendered.markdown);
49930
49941
  await writeFileAtomic(jsonPath, rendered.json);
49931
49942
  return { paths: { markdownPath, jsonPath }, mode, requiredBlockReason: null };
@@ -49951,15 +49962,53 @@ var init_completionProof = __esm({
49951
49962
  }
49952
49963
  });
49953
49964
 
49965
+ // src/cli/memory/spineTelemetry.ts
49966
+ function spineMemoryEventNote(handle, event) {
49967
+ try {
49968
+ if (event.type === "memory_recall_end" && event.reason === "context-built") {
49969
+ handle.note("context.projection", {
49970
+ subject: "context.projection",
49971
+ ...event.contextChars !== void 0 ? { contextChars: event.contextChars } : {},
49972
+ ...event.returnedCount !== void 0 ? { returnedCount: event.returnedCount } : {},
49973
+ ...event.durationMs !== void 0 ? { durationMs: event.durationMs } : {},
49974
+ ...event.backend !== void 0 ? { backend: event.backend } : {}
49975
+ });
49976
+ return;
49977
+ }
49978
+ handle.note(`memory_${event.type}`, {
49979
+ subject: "memory_event",
49980
+ type: event.type,
49981
+ ...event.durationMs !== void 0 ? { durationMs: event.durationMs } : {},
49982
+ ...event.candidateCount !== void 0 ? { candidateCount: event.candidateCount } : {},
49983
+ ...event.returnedCount !== void 0 ? { returnedCount: event.returnedCount } : {},
49984
+ ...event.backend !== void 0 ? { backend: event.backend } : {},
49985
+ ...event.reason !== void 0 ? { reason: event.reason } : {},
49986
+ ...event.memoryId !== void 0 ? { memoryId: event.memoryId } : {}
49987
+ });
49988
+ } catch {
49989
+ }
49990
+ }
49991
+ function memorySinkFor(holder) {
49992
+ return (event) => {
49993
+ const handle = holder.current;
49994
+ if (handle) spineMemoryEventNote(handle, event);
49995
+ };
49996
+ }
49997
+ var init_spineTelemetry = __esm({
49998
+ "src/cli/memory/spineTelemetry.ts"() {
49999
+ "use strict";
50000
+ }
50001
+ });
50002
+
49954
50003
  // src/cli/state/fileStateStore.ts
49955
50004
  import { createHash as createHash16, randomUUID as randomUUID4 } from "node:crypto";
49956
50005
  import { promises as fs22 } from "node:fs";
49957
- import * as path53 from "node:path";
50006
+ import * as path54 from "node:path";
49958
50007
  function shortId() {
49959
50008
  return randomUUID4().replace(/-/g, "").slice(0, 12);
49960
50009
  }
49961
50010
  async function writeJsonAtomic(filePath, data) {
49962
- await fs22.mkdir(path53.dirname(filePath), { recursive: true });
50011
+ await fs22.mkdir(path54.dirname(filePath), { recursive: true });
49963
50012
  const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
49964
50013
  await fs22.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
49965
50014
  await fs22.rename(tmp, filePath);
@@ -50020,11 +50069,11 @@ var init_fileStateStore = __esm({
50020
50069
  indexPath = "";
50021
50070
  async init(projectRoot) {
50022
50071
  this.root = projectRoot;
50023
- this.stateDir = path53.join(projectRoot, ".zelari", "state");
50024
- this.commitsDir = path53.join(this.stateDir, "commits");
50025
- this.artifactsDir = path53.join(this.stateDir, "artifacts");
50026
- this.headPath = path53.join(this.stateDir, "HEAD.json");
50027
- this.indexPath = path53.join(this.stateDir, "index.jsonl");
50072
+ this.stateDir = path54.join(projectRoot, ".zelari", "state");
50073
+ this.commitsDir = path54.join(this.stateDir, "commits");
50074
+ this.artifactsDir = path54.join(this.stateDir, "artifacts");
50075
+ this.headPath = path54.join(this.stateDir, "HEAD.json");
50076
+ this.indexPath = path54.join(this.stateDir, "index.jsonl");
50028
50077
  await fs22.mkdir(this.commitsDir, { recursive: true });
50029
50078
  await fs22.mkdir(this.artifactsDir, { recursive: true });
50030
50079
  }
@@ -50037,13 +50086,13 @@ var init_fileStateStore = __esm({
50037
50086
  const discoveries = input.discoveries ?? [];
50038
50087
  const parent = await this.head();
50039
50088
  const id3 = shortId();
50040
- const artifactRel = path53.join("artifacts", id3);
50041
- const artifactAbs = path53.join(this.artifactsDir, id3);
50089
+ const artifactRel = path54.join("artifacts", id3);
50090
+ const artifactAbs = path54.join(this.artifactsDir, id3);
50042
50091
  await fs22.mkdir(artifactAbs, { recursive: true });
50043
50092
  const summary = defaultSummary(input, discoveries);
50044
- await fs22.writeFile(path53.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
50045
- await writeJsonAtomic(path53.join(artifactAbs, "discoveries.json"), discoveries);
50046
- await writeJsonAtomic(path53.join(artifactAbs, "verification.json"), input.verification);
50093
+ await fs22.writeFile(path54.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
50094
+ await writeJsonAtomic(path54.join(artifactAbs, "discoveries.json"), discoveries);
50095
+ await writeJsonAtomic(path54.join(artifactAbs, "verification.json"), input.verification);
50047
50096
  const meta3 = {
50048
50097
  id: id3,
50049
50098
  parentId: parent?.id ?? null,
@@ -50055,14 +50104,14 @@ var init_fileStateStore = __esm({
50055
50104
  workspaceCheckpointId: input.workspaceCheckpointId,
50056
50105
  verification: {
50057
50106
  ...input.verification,
50058
- reportPath: input.verification.reportPath ?? path53.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
50107
+ reportPath: input.verification.reportPath ?? path54.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
50059
50108
  },
50060
50109
  changedPaths: input.changedPaths ?? [],
50061
50110
  stablePromptHash: input.stablePromptHash,
50062
50111
  discoveryCount: discoveries.length,
50063
50112
  artifactDir: artifactRel.replace(/\\/g, "/")
50064
50113
  };
50065
- await writeJsonAtomic(path53.join(this.commitsDir, `${id3}.json`), meta3);
50114
+ await writeJsonAtomic(path54.join(this.commitsDir, `${id3}.json`), meta3);
50066
50115
  await writeJsonAtomic(this.headPath, { id: id3, updatedAt: meta3.createdAt });
50067
50116
  await fs22.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
50068
50117
  return stripStored(meta3);
@@ -50073,7 +50122,7 @@ var init_fileStateStore = __esm({
50073
50122
  return this.get(head.id);
50074
50123
  }
50075
50124
  async get(id3) {
50076
- const stored = await readJsonFile(path53.join(this.commitsDir, `${id3}.json`));
50125
+ const stored = await readJsonFile(path54.join(this.commitsDir, `${id3}.json`));
50077
50126
  return stored ? stripStored(stored) : null;
50078
50127
  }
50079
50128
  async list(limit = 20) {
@@ -50112,9 +50161,9 @@ var init_fileStateStore = __esm({
50112
50161
  async loadDiscoveries(id3) {
50113
50162
  const meta3 = id3 ? await this.get(id3) : await this.head();
50114
50163
  if (!meta3) return [];
50115
- const stored = await readJsonFile(path53.join(this.commitsDir, `${meta3.id}.json`));
50164
+ const stored = await readJsonFile(path54.join(this.commitsDir, `${meta3.id}.json`));
50116
50165
  if (!stored?.artifactDir) return [];
50117
- const discPath = path53.join(this.stateDir, stored.artifactDir, "discoveries.json");
50166
+ const discPath = path54.join(this.stateDir, stored.artifactDir, "discoveries.json");
50118
50167
  return await readJsonFile(discPath) ?? [];
50119
50168
  }
50120
50169
  async materializeContext(id3, maxChars = DEFAULT_MATERIALIZE_CHARS) {
@@ -51367,10 +51416,10 @@ var init_mode = __esm({
51367
51416
 
51368
51417
  // src/cli/headless.ts
51369
51418
  import { readFileSync as readFileSync23 } from "node:fs";
51370
- import path54 from "node:path";
51419
+ import path55 from "node:path";
51371
51420
  function resolveHeadlessCwd(opts) {
51372
51421
  const raw = typeof opts.cwd === "string" ? opts.cwd.trim() : "";
51373
- return path54.resolve(raw.length > 0 ? raw : process.cwd());
51422
+ return path55.resolve(raw.length > 0 ? raw : process.cwd());
51374
51423
  }
51375
51424
  function defaultProfileForMode(mode) {
51376
51425
  switch (mode) {
@@ -51401,7 +51450,8 @@ function parseHeadlessFlags(argv) {
51401
51450
  let profile;
51402
51451
  let resumeSessionId;
51403
51452
  let exportSessionPath;
51404
- let strictDone = false;
51453
+ let strictDone;
51454
+ let missionStrict;
51405
51455
  let krakenGraph;
51406
51456
  let planOnly = process.env.ZELARI_KRAKEN_PLAN_ONLY === "1" || process.env.ZELARI_KRAKEN_PLAN_ONLY === "true";
51407
51457
  let runPlan = process.env.ZELARI_KRAKEN_RUN_PLAN;
@@ -51563,7 +51613,10 @@ function parseHeadlessFlags(argv) {
51563
51613
  strictDone = true;
51564
51614
  } else if (arg === "--no-strict-done") {
51565
51615
  strictDone = false;
51566
- process.env.ZELARI_MISSION_STRICT = "0";
51616
+ } else if (arg === "--mission-strict") {
51617
+ missionStrict = true;
51618
+ } else if (arg === "--no-mission-strict") {
51619
+ missionStrict = false;
51567
51620
  } else if (arg === "--kraken-graph") {
51568
51621
  krakenGraph = argv[i + 1];
51569
51622
  i++;
@@ -51618,7 +51671,8 @@ function parseHeadlessFlags(argv) {
51618
51671
  ...profile ? { profile } : {},
51619
51672
  ...resumeSessionId ? { resumeSessionId } : {},
51620
51673
  ...exportSessionPath ? { exportSessionPath } : {},
51621
- ...strictDone ? { strictDone: true } : {},
51674
+ ...strictDone !== void 0 ? { strictDone } : {},
51675
+ ...missionStrict !== void 0 ? { missionStrict } : {},
51622
51676
  ...krakenGraph ? { krakenGraph } : {},
51623
51677
  ...planOnly ? { planOnly: true } : {},
51624
51678
  ...runPlan ? { runPlan } : {},
@@ -52305,7 +52359,7 @@ var init_claudeProvider = __esm({
52305
52359
  // src/cli/memory/legacyImport.ts
52306
52360
  import { createHash as createHash17 } from "node:crypto";
52307
52361
  import { promises as fs23 } from "node:fs";
52308
- import * as path55 from "node:path";
52362
+ import * as path56 from "node:path";
52309
52363
  function sourceId(fact, line) {
52310
52364
  return `jsonl:${fact.id ?? createHash17("sha256").update(line).digest("hex")}`;
52311
52365
  }
@@ -52323,7 +52377,7 @@ function timestamp(value) {
52323
52377
  }
52324
52378
  async function importLegacyMemoryLog(backend, service) {
52325
52379
  const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
52326
- const logPath = path55.join(path55.dirname(backend.databasePath), "log.jsonl");
52380
+ const logPath = path56.join(path56.dirname(backend.databasePath), "log.jsonl");
52327
52381
  let raw;
52328
52382
  try {
52329
52383
  raw = await fs23.readFile(logPath, "utf8");
@@ -52506,7 +52560,7 @@ var init_sqliteCodec = __esm({
52506
52560
  // src/cli/memory/sqliteRpc.ts
52507
52561
  import { existsSync as existsSync30 } from "node:fs";
52508
52562
  import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
52509
- import * as path56 from "node:path";
52563
+ import * as path57 from "node:path";
52510
52564
  import { Worker } from "node:worker_threads";
52511
52565
  function isBusy(error51) {
52512
52566
  const candidate = error51;
@@ -52515,10 +52569,10 @@ function isBusy(error51) {
52515
52569
  );
52516
52570
  }
52517
52571
  function resolveWorkerUrl() {
52518
- const here = path56.dirname(fileURLToPath2(import.meta.url));
52519
- const direct = path56.join(here, "sqliteWorker.mjs");
52572
+ const here = path57.dirname(fileURLToPath2(import.meta.url));
52573
+ const direct = path57.join(here, "sqliteWorker.mjs");
52520
52574
  if (existsSync30(direct)) return pathToFileURL2(direct);
52521
- return pathToFileURL2(path56.join(here, "memory", "sqliteWorker.mjs"));
52575
+ return pathToFileURL2(path57.join(here, "memory", "sqliteWorker.mjs"));
52522
52576
  }
52523
52577
  var SqliteWorkerRpc;
52524
52578
  var init_sqliteRpc = __esm({
@@ -52807,7 +52861,7 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
52807
52861
  // src/cli/memory/sqliteBackend.ts
52808
52862
  import { createHash as createHash18, randomUUID as randomUUID5 } from "node:crypto";
52809
52863
  import { promises as fs24 } from "node:fs";
52810
- import * as path57 from "node:path";
52864
+ import * as path58 from "node:path";
52811
52865
  function boundedLimit(value, fallback = 50) {
52812
52866
  return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
52813
52867
  }
@@ -52869,16 +52923,16 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
52869
52923
  try {
52870
52924
  resolved = await fs24.realpath(projectRoot);
52871
52925
  } catch {
52872
- resolved = path57.resolve(projectRoot);
52926
+ resolved = path58.resolve(projectRoot);
52873
52927
  }
52874
52928
  if (this.initialized && resolved === this.projectRoot) return;
52875
52929
  if (this.initialized) await this.close();
52876
52930
  const filename = this.options.filename ?? "memory.db";
52877
- if (path57.basename(filename) !== filename || filename === "." || filename === "..") {
52931
+ if (path58.basename(filename) !== filename || filename === "." || filename === "..") {
52878
52932
  throw new Error("SQLite memory filename must not contain a path.");
52879
52933
  }
52880
- const zelariDirectory = path57.join(resolved, ".zelari");
52881
- const directory = path57.join(zelariDirectory, "memory");
52934
+ const zelariDirectory = path58.join(resolved, ".zelari");
52935
+ const directory = path58.join(zelariDirectory, "memory");
52882
52936
  for (const candidate of [zelariDirectory, directory]) {
52883
52937
  let stat7;
52884
52938
  try {
@@ -52897,12 +52951,12 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
52897
52951
  }
52898
52952
  }
52899
52953
  const canonicalDirectory = await fs24.realpath(directory);
52900
- const relativeDirectory = path57.relative(resolved, canonicalDirectory);
52901
- if (relativeDirectory.startsWith("..") || path57.isAbsolute(relativeDirectory)) {
52954
+ const relativeDirectory = path58.relative(resolved, canonicalDirectory);
52955
+ if (relativeDirectory.startsWith("..") || path58.isAbsolute(relativeDirectory)) {
52902
52956
  throw new Error("SQLite memory directory resolves outside the active project.");
52903
52957
  }
52904
52958
  this.projectRoot = resolved;
52905
- this.databasePath = path57.join(canonicalDirectory, filename);
52959
+ this.databasePath = path58.join(canonicalDirectory, filename);
52906
52960
  const opened = await this.rpc.open({
52907
52961
  dbPath: this.databasePath,
52908
52962
  schemaSql: SQLITE_MEMORY_BASE_SCHEMA,
@@ -53435,7 +53489,7 @@ __export(serviceFactory_exports, {
53435
53489
  });
53436
53490
  import { createHash as createHash19 } from "node:crypto";
53437
53491
  import { promises as fs25 } from "node:fs";
53438
- import * as path58 from "node:path";
53492
+ import * as path59 from "node:path";
53439
53493
  function isMemoryV2Enabled(env = process.env) {
53440
53494
  if (env.ZELARI_MEMORY === "0") return false;
53441
53495
  if (env.ZELARI_MEMORY_BACKEND === "file" || env.ZELARI_MEMORY_BACKEND === "jsonl") return false;
@@ -53456,7 +53510,7 @@ async function canonicalProjectId(projectRoot) {
53456
53510
  try {
53457
53511
  canonical = await fs25.realpath(projectRoot);
53458
53512
  } catch {
53459
- canonical = path58.resolve(projectRoot);
53513
+ canonical = path59.resolve(projectRoot);
53460
53514
  }
53461
53515
  canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
53462
53516
  if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
@@ -54182,8 +54236,8 @@ function readPlan(ctx) {
54182
54236
  } catch {
54183
54237
  }
54184
54238
  }
54185
- const path87 = workspaceFile(ctx.rootDir, "plan");
54186
- const doc = ctx.storage.readIfExists(path87);
54239
+ const path90 = workspaceFile(ctx.rootDir, "plan");
54240
+ const doc = ctx.storage.readIfExists(path90);
54187
54241
  if (!doc) return { phases: [], tasks: [], milestones: [] };
54188
54242
  const meta3 = doc.meta;
54189
54243
  return {
@@ -54361,7 +54415,7 @@ function addMilestoneRecord(ctx, summary, input) {
54361
54415
  dueDate: input.dueDate,
54362
54416
  targetVersion: version2
54363
54417
  });
54364
- const path87 = join31(ctx.rootDir, "milestones", `${id3}.md`);
54418
+ const path90 = join31(ctx.rootDir, "milestones", `${id3}.md`);
54365
54419
  const meta3 = {
54366
54420
  kind: "milestone",
54367
54421
  id: id3,
@@ -54378,7 +54432,7 @@ function addMilestoneRecord(ctx, summary, input) {
54378
54432
  `Target version: ${version2}`,
54379
54433
  ""
54380
54434
  ].join("\n");
54381
- ctx.storage.write(path87, meta3, body);
54435
+ ctx.storage.write(path90, meta3, body);
54382
54436
  return { id: id3, created: true };
54383
54437
  }
54384
54438
  function readPlanSummary(ctx) {
@@ -54582,7 +54636,7 @@ function addIdeaStub(ctx) {
54582
54636
  const tags = args["tags"] ?? [];
54583
54637
  const category = args["category"] ?? "General";
54584
54638
  const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
54585
- const path87 = workspaceArtifact(ctx.rootDir, "decisions", id3);
54639
+ const path90 = workspaceArtifact(ctx.rootDir, "decisions", id3);
54586
54640
  const meta3 = {
54587
54641
  kind: "adr",
54588
54642
  status: "proposed",
@@ -54608,7 +54662,7 @@ function addIdeaStub(ctx) {
54608
54662
  ...consequences.map((c) => `- ${c}`),
54609
54663
  ""
54610
54664
  ].join("\n");
54611
- ctx.storage.write(path87, meta3, body);
54665
+ ctx.storage.write(path90, meta3, body);
54612
54666
  return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
54613
54667
  });
54614
54668
  }
@@ -54690,14 +54744,14 @@ function createDocumentStub(ctx) {
54690
54744
  ctx.storage.write(risksPath, riskMeta, content);
54691
54745
  return `Document "${title}" created at risks.md (workspace root).`;
54692
54746
  }
54693
- const path87 = workspaceArtifact(ctx.rootDir, "docs", slug);
54747
+ const path90 = workspaceArtifact(ctx.rootDir, "docs", slug);
54694
54748
  const meta3 = {
54695
54749
  kind: "doc",
54696
54750
  id: slug,
54697
54751
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
54698
54752
  tags
54699
54753
  };
54700
- ctx.storage.write(path87, meta3, content);
54754
+ ctx.storage.write(path90, meta3, content);
54701
54755
  return `Document "${title}" created at docs/${slug}.md.`;
54702
54756
  });
54703
54757
  }
@@ -55084,10 +55138,10 @@ function getUserMcpPath() {
55084
55138
  function getProjectMcpPath(projectRoot) {
55085
55139
  return join32(projectRoot, ".zelari", "mcp.json");
55086
55140
  }
55087
- function readFile6(path87) {
55088
- if (!existsSync37(path87)) return {};
55141
+ function readFile6(path90) {
55142
+ if (!existsSync37(path90)) return {};
55089
55143
  try {
55090
- const parsed = JSON.parse(readFileSync29(path87, "utf8"));
55144
+ const parsed = JSON.parse(readFileSync29(path90, "utf8"));
55091
55145
  const out = {};
55092
55146
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
55093
55147
  if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
@@ -55103,10 +55157,10 @@ function readFile6(path87) {
55103
55157
  return {};
55104
55158
  }
55105
55159
  }
55106
- function writeFile2(path87, servers) {
55107
- mkdirSync16(dirname9(path87), { recursive: true });
55160
+ function writeFile2(path90, servers) {
55161
+ mkdirSync16(dirname9(path90), { recursive: true });
55108
55162
  const body = { mcpServers: servers };
55109
- writeFileSync18(path87, `${JSON.stringify(body, null, 2)}
55163
+ writeFileSync18(path90, `${JSON.stringify(body, null, 2)}
55110
55164
  `, "utf8");
55111
55165
  }
55112
55166
  function listMcpServers(projectRoot) {
@@ -55139,9 +55193,9 @@ function upsertMcpServer(opts) {
55139
55193
  if (!opts.config.command?.trim()) {
55140
55194
  return { ok: false, error: "command is required" };
55141
55195
  }
55142
- let path87;
55196
+ let path90;
55143
55197
  if (opts.scope === "user") {
55144
- path87 = getUserMcpPath();
55198
+ path90 = getUserMcpPath();
55145
55199
  } else {
55146
55200
  const root = opts.projectRoot?.trim();
55147
55201
  if (!root) {
@@ -55150,30 +55204,30 @@ function upsertMcpServer(opts) {
55150
55204
  error: "projectRoot required for project scope (Open Folder first)"
55151
55205
  };
55152
55206
  }
55153
- path87 = getProjectMcpPath(root);
55207
+ path90 = getProjectMcpPath(root);
55154
55208
  }
55155
- const current = readFile6(path87);
55209
+ const current = readFile6(path90);
55156
55210
  current[name] = {
55157
55211
  command: opts.config.command.trim(),
55158
55212
  args: opts.config.args,
55159
55213
  env: opts.config.env,
55160
55214
  enabled: opts.config.enabled !== false
55161
55215
  };
55162
- writeFile2(path87, current);
55163
- return { ok: true, path: path87 };
55216
+ writeFile2(path90, current);
55217
+ return { ok: true, path: path90 };
55164
55218
  }
55165
55219
  function removeMcpServer(opts) {
55166
- const path87 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
55167
- if (!path87) {
55220
+ const path90 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
55221
+ if (!path90) {
55168
55222
  return { ok: false, error: "projectRoot required for project scope" };
55169
55223
  }
55170
- const current = readFile6(path87);
55224
+ const current = readFile6(path90);
55171
55225
  if (!(opts.name in current)) {
55172
- return { ok: false, error: `Server "${opts.name}" not found in ${path87}` };
55226
+ return { ok: false, error: `Server "${opts.name}" not found in ${path90}` };
55173
55227
  }
55174
55228
  delete current[opts.name];
55175
- writeFile2(path87, current);
55176
- return { ok: true, path: path87 };
55229
+ writeFile2(path90, current);
55230
+ return { ok: true, path: path90 };
55177
55231
  }
55178
55232
  var init_mcpConfigIo = __esm({
55179
55233
  "src/cli/mcp/mcpConfigIo.ts"() {
@@ -55574,10 +55628,10 @@ import { createHash as createHash20 } from "node:crypto";
55574
55628
  import { join as join34 } from "node:path";
55575
55629
  import { readFile as readFile7 } from "node:fs/promises";
55576
55630
  async function readPackageJson3(projectRoot) {
55577
- const path87 = join34(projectRoot, "package.json");
55578
- if (!existsSync39(path87)) return null;
55631
+ const path90 = join34(projectRoot, "package.json");
55632
+ if (!existsSync39(path90)) return null;
55579
55633
  try {
55580
- return JSON.parse(await readFile7(path87, "utf8"));
55634
+ return JSON.parse(await readFile7(path90, "utf8"));
55581
55635
  } catch {
55582
55636
  return null;
55583
55637
  }
@@ -55659,9 +55713,9 @@ async function genBuild(ctx) {
55659
55713
  ].join("\n");
55660
55714
  }
55661
55715
  async function genOpenQuestions(ctx) {
55662
- const path87 = join34(ctx.rootDir, "risks.md");
55663
- if (!existsSync39(path87)) return "_No open questions._";
55664
- const content = readFileSync31(path87, "utf8");
55716
+ const path90 = join34(ctx.rootDir, "risks.md");
55717
+ if (!existsSync39(path90)) return "_No open questions._";
55718
+ const content = readFileSync31(path90, "utf8");
55665
55719
  const lines = content.split("\n");
55666
55720
  const questions = [];
55667
55721
  let currentTitle = "";
@@ -55935,9 +55989,9 @@ function versionKey(value) {
55935
55989
  function firstString2(v) {
55936
55990
  return typeof v === "string" && v.trim().length > 0 ? v : null;
55937
55991
  }
55938
- function readFileSyncSafe(path87) {
55992
+ function readFileSyncSafe(path90) {
55939
55993
  try {
55940
- return readFileSync32(path87, "utf8");
55994
+ return readFileSync32(path90, "utf8");
55941
55995
  } catch {
55942
55996
  return null;
55943
55997
  }
@@ -56400,8 +56454,8 @@ async function runPostCouncilHook(ctx, options) {
56400
56454
  sources: scope.sources
56401
56455
  } : void 0
56402
56456
  });
56403
- const path87 = writeCouncilCompletion(ctx.rootDir, completion);
56404
- completionHook = { ran: true, path: path87, completion };
56457
+ const path90 = writeCouncilCompletion(ctx.rootDir, completion);
56458
+ completionHook = { ran: true, path: path90, completion };
56405
56459
  } catch (err) {
56406
56460
  completionHook = {
56407
56461
  ran: true,
@@ -56446,7 +56500,7 @@ import {
56446
56500
  writeFileSync as writeFileSync21,
56447
56501
  mkdirSync as mkdirSync17
56448
56502
  } from "node:fs";
56449
- import path59 from "node:path";
56503
+ import path60 from "node:path";
56450
56504
  import os10 from "node:os";
56451
56505
  var FeedbackStore;
56452
56506
  var init_councilFeedback = __esm({
@@ -56457,7 +56511,7 @@ var init_councilFeedback = __esm({
56457
56511
  now;
56458
56512
  entries = [];
56459
56513
  constructor(options = {}) {
56460
- this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path59.join(os10.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
56514
+ this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path60.join(os10.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
56461
56515
  this.now = options.now ?? Date.now;
56462
56516
  this.load();
56463
56517
  }
@@ -56563,7 +56617,7 @@ var init_councilFeedback = __esm({
56563
56617
  }
56564
56618
  }
56565
56619
  save() {
56566
- mkdirSync17(path59.dirname(this.file), { recursive: true });
56620
+ mkdirSync17(path60.dirname(this.file), { recursive: true });
56567
56621
  writeFileSync21(
56568
56622
  this.file,
56569
56623
  JSON.stringify({ entries: this.entries }, null, 2),
@@ -56631,7 +56685,7 @@ import { execFile as execFile4 } from "node:child_process";
56631
56685
  import { promisify as promisify3 } from "node:util";
56632
56686
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
56633
56687
  import { tmpdir as tmpdir3 } from "node:os";
56634
- import path60 from "node:path";
56688
+ import path61 from "node:path";
56635
56689
  import { randomUUID as randomUUID6 } from "node:crypto";
56636
56690
  async function git4(cwd, args, env) {
56637
56691
  const { stdout } = await execFileAsync3("git", ["-C", cwd, ...args], {
@@ -56651,8 +56705,8 @@ async function isGitRepo(cwd) {
56651
56705
  return await gitSafe(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true";
56652
56706
  }
56653
56707
  async function withTempIndex(fn) {
56654
- const dir = mkdtempSync(path60.join(tmpdir3(), "zelari-ckpt-"));
56655
- const indexFile = path60.join(dir, "index");
56708
+ const dir = mkdtempSync(path61.join(tmpdir3(), "zelari-ckpt-"));
56709
+ const indexFile = path61.join(dir, "index");
56656
56710
  try {
56657
56711
  return await fn(indexFile);
56658
56712
  } finally {
@@ -56743,7 +56797,7 @@ async function restoreCheckpoint(cwd, id3) {
56743
56797
  const deleted = [];
56744
56798
  for (const rel2 of added) {
56745
56799
  try {
56746
- rmSync2(path60.join(cwd, rel2), { force: true });
56800
+ rmSync2(path61.join(cwd, rel2), { force: true });
56747
56801
  deleted.push(rel2);
56748
56802
  } catch {
56749
56803
  }
@@ -56847,7 +56901,7 @@ __export(fileBackend_exports, {
56847
56901
  });
56848
56902
  import { randomUUID as randomUUID7 } from "node:crypto";
56849
56903
  import { promises as fs27 } from "node:fs";
56850
- import * as path61 from "node:path";
56904
+ import * as path62 from "node:path";
56851
56905
  function tokenize2(text) {
56852
56906
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
56853
56907
  }
@@ -56861,10 +56915,12 @@ function matchesFilter(metadata2, filter) {
56861
56915
  function isMemoryEnabled(env = process.env) {
56862
56916
  return env.ZELARI_MEMORY !== "0";
56863
56917
  }
56864
- async function getMemoryBackend(projectRoot, env = process.env) {
56918
+ async function getMemoryBackend(projectRoot, env = process.env, onEvent) {
56865
56919
  if (!isMemoryEnabled(env)) return new NoopMemoryBackend();
56866
56920
  if (isMemoryV2Enabled(env)) {
56867
- const service = await getMemoryService(projectRoot, env);
56921
+ const service = await getMemoryService(projectRoot, env, {
56922
+ ...onEvent ? { onEvent } : {}
56923
+ });
56868
56924
  if (service instanceof NoopMemoryService) return new NoopMemoryBackend();
56869
56925
  return new LegacyMemoryBackendAdapter(service);
56870
56926
  }
@@ -56898,8 +56954,8 @@ var init_fileBackend = __esm({
56898
56954
  logPath = "";
56899
56955
  memoryDir = "";
56900
56956
  async init(projectRoot) {
56901
- this.memoryDir = path61.join(projectRoot, ".zelari", "memory");
56902
- this.logPath = path61.join(this.memoryDir, "log.jsonl");
56957
+ this.memoryDir = path62.join(projectRoot, ".zelari", "memory");
56958
+ this.logPath = path62.join(this.memoryDir, "log.jsonl");
56903
56959
  await fs27.mkdir(this.memoryDir, { recursive: true });
56904
56960
  }
56905
56961
  async add(content, metadata2 = {}, graph) {
@@ -56972,12 +57028,12 @@ var init_fileBackend = __esm({
56972
57028
 
56973
57029
  // src/cli/traceStore.ts
56974
57030
  import { promises as fs28 } from "node:fs";
56975
- import * as path62 from "node:path";
57031
+ import * as path63 from "node:path";
56976
57032
  function traceDir(projectRoot) {
56977
- return path62.join(projectRoot, ".zelari", "trace");
57033
+ return path63.join(projectRoot, ".zelari", "trace");
56978
57034
  }
56979
57035
  function tracePath(projectRoot, missionId) {
56980
- return path62.join(traceDir(projectRoot), `${missionId}.json`);
57036
+ return path63.join(traceDir(projectRoot), `${missionId}.json`);
56981
57037
  }
56982
57038
  async function saveTrace(projectRoot, missionId, entries) {
56983
57039
  const dir = traceDir(projectRoot);
@@ -57014,7 +57070,7 @@ __export(zelariMission_exports, {
57014
57070
  });
57015
57071
  import { randomUUID as randomUUID8 } from "node:crypto";
57016
57072
  import { promises as fs29 } from "node:fs";
57017
- import * as path63 from "node:path";
57073
+ import * as path64 from "node:path";
57018
57074
  function resolveMaxIterations(env = process.env) {
57019
57075
  const raw = env.ZELARI_MISSION_MAX_ITER;
57020
57076
  const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
@@ -57057,10 +57113,10 @@ function isMissionAutoStart(env = process.env) {
57057
57113
  return env.ZELARI_MISSION_AUTO === "1";
57058
57114
  }
57059
57115
  async function writeMissionState(projectRoot, state3) {
57060
- const dir = path63.join(projectRoot, ".zelari");
57116
+ const dir = path64.join(projectRoot, ".zelari");
57061
57117
  await fs29.mkdir(dir, { recursive: true });
57062
57118
  await fs29.writeFile(
57063
- path63.join(dir, "mission-state.json"),
57119
+ path64.join(dir, "mission-state.json"),
57064
57120
  JSON.stringify(state3, null, 2) + "\n",
57065
57121
  "utf8"
57066
57122
  );
@@ -57735,7 +57791,7 @@ function safeSocketPath(socketPath) {
57735
57791
  return socketPath.trim();
57736
57792
  }
57737
57793
  function startPermissionBroker(socketPath, handlers, opts) {
57738
- const path87 = safeSocketPath(socketPath);
57794
+ const path90 = safeSocketPath(socketPath);
57739
57795
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
57740
57796
  const sockets = /* @__PURE__ */ new Set();
57741
57797
  const server = createServer2((socket) => {
@@ -57835,10 +57891,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
57835
57891
  return new Promise((resolve9, reject) => {
57836
57892
  const onError = (err) => reject(err);
57837
57893
  server.once("error", onError);
57838
- server.listen(path87, () => {
57894
+ server.listen(path90, () => {
57839
57895
  server.removeListener("error", onError);
57840
57896
  resolve9({
57841
- socketPath: path87,
57897
+ socketPath: path90,
57842
57898
  stop: () => new Promise((res) => {
57843
57899
  for (const s of sockets) s.destroy();
57844
57900
  sockets.clear();
@@ -57849,7 +57905,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
57849
57905
  if (done) return;
57850
57906
  done = true;
57851
57907
  if (process.platform !== "win32") {
57852
- unlink(path87, () => res());
57908
+ unlink(path90, () => res());
57853
57909
  } else {
57854
57910
  res();
57855
57911
  }
@@ -57862,11 +57918,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
57862
57918
  });
57863
57919
  }
57864
57920
  function requestBrokerAsk(socketPath, ask, opts) {
57865
- const path87 = safeSocketPath(socketPath);
57921
+ const path90 = safeSocketPath(socketPath);
57866
57922
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
57867
57923
  const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
57868
57924
  return new Promise((resolve9, reject) => {
57869
- const socket = connect(path87);
57925
+ const socket = connect(path90);
57870
57926
  let buffer = "";
57871
57927
  let settled = false;
57872
57928
  const settle = (fn) => {
@@ -57881,7 +57937,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
57881
57937
  settle(
57882
57938
  () => reject(
57883
57939
  new Error(
57884
- `permission broker unavailable at "${path87}" (connect timed out after ${connectTimeoutMs}ms)`
57940
+ `permission broker unavailable at "${path90}" (connect timed out after ${connectTimeoutMs}ms)`
57885
57941
  )
57886
57942
  )
57887
57943
  );
@@ -58021,7 +58077,7 @@ var init_brokerHandlers = __esm({
58021
58077
  // src/cli/gitOps.ts
58022
58078
  import { execFile as execFile5 } from "node:child_process";
58023
58079
  import { promisify as promisify4 } from "node:util";
58024
- import path64 from "node:path";
58080
+ import path65 from "node:path";
58025
58081
  async function git5(cwd, args) {
58026
58082
  try {
58027
58083
  const { stdout } = await execFileAsync4("git", ["-C", cwd, ...args], {
@@ -58066,7 +58122,7 @@ async function undoWorkingChanges(opts = {}) {
58066
58122
  };
58067
58123
  }
58068
58124
  function defaultProjectRoot() {
58069
- return path64.resolve(__dirname, "..", "..", "..");
58125
+ return path65.resolve(__dirname, "..", "..", "..");
58070
58126
  }
58071
58127
  var execFileAsync4;
58072
58128
  var init_gitOps = __esm({
@@ -58684,9 +58740,9 @@ __export(graphMemory_exports, {
58684
58740
  toGraphSnapshot: () => toGraphSnapshot
58685
58741
  });
58686
58742
  import { promises as fs32 } from "node:fs";
58687
- import path67 from "node:path";
58743
+ import path68 from "node:path";
58688
58744
  function snapshotPath(cwd) {
58689
- return path67.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
58745
+ return path68.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
58690
58746
  }
58691
58747
  function toGraphSnapshot(graph, opts) {
58692
58748
  const unresolved = (opts.unresolvedFindings ?? []).map((u) => ({
@@ -58713,7 +58769,7 @@ async function saveGraphSnapshot(cwd, snapshot) {
58713
58769
  try {
58714
58770
  await fs32.access(cwd);
58715
58771
  const file2 = snapshotPath(cwd);
58716
- await fs32.mkdir(path67.dirname(file2), { recursive: true });
58772
+ await fs32.mkdir(path68.dirname(file2), { recursive: true });
58717
58773
  await fs32.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
58718
58774
  } catch {
58719
58775
  }
@@ -58780,7 +58836,7 @@ var SNAPSHOT_DIR, SNAPSHOT_FILE, MAX_SNAPSHOT_FINDINGS_CHARS;
58780
58836
  var init_graphMemory = __esm({
58781
58837
  "src/cli/kraken/graphMemory.ts"() {
58782
58838
  "use strict";
58783
- SNAPSHOT_DIR = path67.join(".zelari", "kraken");
58839
+ SNAPSHOT_DIR = path68.join(".zelari", "kraken");
58784
58840
  SNAPSHOT_FILE = "last-graph.json";
58785
58841
  MAX_SNAPSHOT_FINDINGS_CHARS = 400;
58786
58842
  }
@@ -58852,14 +58908,14 @@ var init_transactional = __esm({
58852
58908
 
58853
58909
  // src/cli/kraken/workbench.ts
58854
58910
  import { promises as fs33 } from "node:fs";
58855
- import path68 from "node:path";
58911
+ import path69 from "node:path";
58856
58912
  function isWorkbenchEnabled(env = process.env) {
58857
58913
  const v = (env.ZELARI_KRAKEN_WORKBENCH ?? "1").trim().toLowerCase();
58858
58914
  if (v === "0" || v === "false" || v === "no" || v === "off") return false;
58859
58915
  return true;
58860
58916
  }
58861
58917
  function workbenchPath(cwd, graphId) {
58862
- return path68.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
58918
+ return path69.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
58863
58919
  }
58864
58920
  function countByStatus2(nodes) {
58865
58921
  const out = { pending: 0, running: 0, done: 0, error: 0, skipped: 0 };
@@ -59022,7 +59078,7 @@ var init_workbench = __esm({
59022
59078
  if (!this.enabled) return null;
59023
59079
  if (!this.dirty && this.lastWrite) return this.lastWrite;
59024
59080
  const out = workbenchPath(this.cwd, this.graphId);
59025
- await fs33.mkdir(path68.dirname(out), { recursive: true });
59081
+ await fs33.mkdir(path69.dirname(out), { recursive: true });
59026
59082
  const body = this.render();
59027
59083
  const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
59028
59084
  await fs33.writeFile(tmp, body, "utf8");
@@ -59395,14 +59451,14 @@ var init_spawnRoi = __esm({
59395
59451
 
59396
59452
  // src/cli/kraken/reputationStore.ts
59397
59453
  import { appendFile as appendFile2, mkdir as mkdir3, readFile as readFile8, rename as rename2, writeFile as writeFile3 } from "node:fs/promises";
59398
- import path69 from "node:path";
59454
+ import path70 from "node:path";
59399
59455
  function resolveReputationStorePath(cwd = process.cwd(), env = process.env) {
59400
59456
  const override = env[REPUTATION_STORE_ENV]?.trim();
59401
59457
  if (override) return override;
59402
- return path69.join(cwd, ".zelari", "reputation.jsonl");
59458
+ return path70.join(cwd, ".zelari", "reputation.jsonl");
59403
59459
  }
59404
59460
  async function appendRecord(storePath, record2) {
59405
- await mkdir3(path69.dirname(storePath), { recursive: true });
59461
+ await mkdir3(path70.dirname(storePath), { recursive: true });
59406
59462
  await appendFile2(storePath, `${JSON.stringify(record2)}
59407
59463
  `, "utf8");
59408
59464
  }
@@ -59802,7 +59858,7 @@ __export(executor_exports, {
59802
59858
  thoroughnessForKind: () => thoroughnessForKind
59803
59859
  });
59804
59860
  import { existsSync as existsSync44 } from "node:fs";
59805
- import path70 from "node:path";
59861
+ import path71 from "node:path";
59806
59862
  async function defaultSymbolExtractor(file2) {
59807
59863
  if (!isAstSupported(file2)) return null;
59808
59864
  const r = await parseFileSymbolsDiag(file2);
@@ -59868,7 +59924,7 @@ function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultC
59868
59924
  }
59869
59925
  function defaultChecksExists(cwd) {
59870
59926
  try {
59871
- return existsSync44(path70.join(cwd, ".zelari", "world", "checks.json"));
59927
+ return existsSync44(path71.join(cwd, ".zelari", "world", "checks.json"));
59872
59928
  } catch {
59873
59929
  return false;
59874
59930
  }
@@ -60376,7 +60432,7 @@ var init_executor = __esm({
60376
60432
  try {
60377
60433
  const summary = aggregate(
60378
60434
  records,
60379
- { repo: path70.basename(this.parentCwd), role: agentForNode(node) },
60435
+ { repo: path71.basename(this.parentCwd), role: agentForNode(node) },
60380
60436
  now
60381
60437
  );
60382
60438
  sample = summary.sample;
@@ -60853,7 +60909,7 @@ ${upstream}` : node.prompt,
60853
60909
  const model = res.ok && res.model && res.model !== "n/a" ? res.model : null;
60854
60910
  const reviewerVerdict = res.ok && this.isReviewerKind(node.kind) && typeof node.result === "string" && node.result.length > 0 ? parseVerifyVerdict(node.result).verdict : null;
60855
60911
  const record2 = reputationRecordFromNodeRun({
60856
- repo: path70.basename(this.parentCwd),
60912
+ repo: path71.basename(this.parentCwd),
60857
60913
  role: agentForNode(node),
60858
60914
  kind: node.kind,
60859
60915
  ok: res.ok,
@@ -61624,10 +61680,10 @@ var init_prereqChecks = __esm({
61624
61680
 
61625
61681
  // src/cli/plugins/prefs.ts
61626
61682
  import { existsSync as existsSync46, readFileSync as readFileSync36, writeFileSync as writeFileSync22, mkdirSync as mkdirSync18 } from "node:fs";
61627
- import path73 from "node:path";
61683
+ import path74 from "node:path";
61628
61684
  import os11 from "node:os";
61629
61685
  function getPluginPrefsPath() {
61630
- return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path73.join(os11.homedir(), ".tmp", "zelari-code", "plugins.json");
61686
+ return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path74.join(os11.homedir(), ".tmp", "zelari-code", "plugins.json");
61631
61687
  }
61632
61688
  function getPluginPrefs() {
61633
61689
  const file2 = getPluginPrefsPath();
@@ -61648,7 +61704,7 @@ function getPluginPrefs() {
61648
61704
  }
61649
61705
  function writePluginPrefs(prefs) {
61650
61706
  const file2 = getPluginPrefsPath();
61651
- mkdirSync18(path73.dirname(file2), { recursive: true });
61707
+ mkdirSync18(path74.dirname(file2), { recursive: true });
61652
61708
  writeFileSync22(file2, JSON.stringify(prefs, null, 2), {
61653
61709
  encoding: "utf-8",
61654
61710
  mode: 384
@@ -61685,7 +61741,7 @@ __export(registry_exports, {
61685
61741
  isBinaryOnPath: () => isBinaryOnPath
61686
61742
  });
61687
61743
  import { existsSync as existsSync47 } from "node:fs";
61688
- import path74 from "node:path";
61744
+ import path75 from "node:path";
61689
61745
  function detectLocalBin(bin) {
61690
61746
  return (cwd) => {
61691
61747
  try {
@@ -61703,7 +61759,7 @@ function isBinaryOnPath(bin, opts = {}) {
61703
61759
  const platform = opts.platform ?? process.platform;
61704
61760
  const exists = opts.exists ?? existsSync47;
61705
61761
  const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
61706
- const pathMod = platform === "win32" ? path74.win32 : path74.posix;
61762
+ const pathMod = platform === "win32" ? path75.win32 : path75.posix;
61707
61763
  const sep4 = platform === "win32" ? ";" : ":";
61708
61764
  const dirs = pathEnv.split(sep4).filter((d) => d.length > 0);
61709
61765
  const candidates = [bin];
@@ -62798,7 +62854,7 @@ var init_policy = __esm({
62798
62854
 
62799
62855
  // src/cli/orchestration/facts.ts
62800
62856
  import { promises as fs41 } from "node:fs";
62801
- import path79 from "node:path";
62857
+ import path80 from "node:path";
62802
62858
  async function collectRepoFileCount(root = process.cwd()) {
62803
62859
  try {
62804
62860
  await fs41.readdir(root);
@@ -62818,7 +62874,7 @@ async function collectRepoFileCount(root = process.cwd()) {
62818
62874
  }
62819
62875
  for (const e of entries) {
62820
62876
  if (e.isDirectory()) {
62821
- if (!SKIP_DIRS.has(e.name)) queue.push(path79.join(dir, e.name));
62877
+ if (!SKIP_DIRS.has(e.name)) queue.push(path80.join(dir, e.name));
62822
62878
  } else if (e.isFile()) {
62823
62879
  count++;
62824
62880
  if (count > MAX_WALK_FILES) return count;
@@ -62914,6 +62970,206 @@ var init_streamScrub = __esm({
62914
62970
  }
62915
62971
  });
62916
62972
 
62973
+ // src/cli/harnessState.ts
62974
+ import path81 from "node:path";
62975
+ function asString3(v) {
62976
+ return typeof v === "string" ? v : "";
62977
+ }
62978
+ function asNumber2(v) {
62979
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
62980
+ }
62981
+ function asCallId(v, seq) {
62982
+ return typeof v === "string" && v.length > 0 ? v : `seq:${seq}`;
62983
+ }
62984
+ function newTurn(index, userText) {
62985
+ return {
62986
+ index,
62987
+ userText: userText.length > 0 ? userText : void 0,
62988
+ toolCalls: 0,
62989
+ toolKinds: [],
62990
+ outcome: "pending",
62991
+ unsettledCallIds: /* @__PURE__ */ new Set(),
62992
+ settledCallIds: /* @__PURE__ */ new Set(),
62993
+ interrupted: 0,
62994
+ assistantMessages: 0
62995
+ };
62996
+ }
62997
+ function deriveHarnessState(events) {
62998
+ const session = {
62999
+ sessionId: events[events.length - 1]?.sessionId ?? "",
63000
+ status: "pending",
63001
+ lastSeq: 0
63002
+ };
63003
+ const support = { contextProjections: [], memoryEvents: 0, compactions: 0 };
63004
+ let tokensSaved;
63005
+ const acc = [];
63006
+ let current = null;
63007
+ for (const e of events) {
63008
+ session.lastSeq = e.seq;
63009
+ switch (e.kind) {
63010
+ case "session.started":
63011
+ session.startedAt ??= e.ts;
63012
+ break;
63013
+ case "session.ended": {
63014
+ session.endedAt = e.ts;
63015
+ const reason = asString3(e.data.reason);
63016
+ session.status = reason.length > 0 ? reason : "ended";
63017
+ if (current) {
63018
+ current.closedBy = "session-ended";
63019
+ current.endReason = reason;
63020
+ current = null;
63021
+ }
63022
+ break;
63023
+ }
63024
+ case "user.message": {
63025
+ if (current) current.closedBy = "next-turn";
63026
+ current = newTurn(acc.length + 1, asString3(e.data.text));
63027
+ acc.push(current);
63028
+ break;
63029
+ }
63030
+ case "assistant.message": {
63031
+ if (!current) break;
63032
+ current.assistantMessages += 1;
63033
+ const text = asString3(e.data.text);
63034
+ current.assistantChars = (current.assistantChars ?? 0) + text.length;
63035
+ current.assistantText = text;
63036
+ break;
63037
+ }
63038
+ case "tool.call": {
63039
+ if (!current) break;
63040
+ current.toolCalls += 1;
63041
+ const tool = asString3(e.data.tool);
63042
+ if (tool.length > 0 && !current.toolKinds.includes(tool)) current.toolKinds.push(tool);
63043
+ current.unsettledCallIds.add(asCallId(e.data.callId, e.seq));
63044
+ break;
63045
+ }
63046
+ case "tool.result": {
63047
+ if (!current) break;
63048
+ current.settledCallIds.add(asCallId(e.data.callId, e.seq));
63049
+ break;
63050
+ }
63051
+ case "tool.interrupted": {
63052
+ if (current) current.interrupted += 1;
63053
+ break;
63054
+ }
63055
+ case "verification.run": {
63056
+ if (!current) break;
63057
+ current.verification = {
63058
+ strict: e.data.strict === true,
63059
+ verdict: asString3(e.data.verdict) || "unknown"
63060
+ };
63061
+ break;
63062
+ }
63063
+ case "session.compacted": {
63064
+ support.compactions += 1;
63065
+ const saved = asNumber2(e.data.tokensSaved);
63066
+ if (saved !== void 0) tokensSaved = (tokensSaved ?? 0) + saved;
63067
+ break;
63068
+ }
63069
+ case "note": {
63070
+ const subject = asString3(e.data.subject);
63071
+ if (subject === "context.projection") {
63072
+ support.contextProjections.push({
63073
+ contextChars: asNumber2(e.data.contextChars) ?? 0,
63074
+ returnedCount: asNumber2(e.data.returnedCount) ?? 0
63075
+ });
63076
+ } else if (subject === "memory_event") {
63077
+ support.memoryEvents += 1;
63078
+ }
63079
+ break;
63080
+ }
63081
+ default:
63082
+ break;
63083
+ }
63084
+ }
63085
+ const turns = acc.map((t) => finalizeTurn(t));
63086
+ return {
63087
+ session,
63088
+ turns,
63089
+ execution: { turnsTotal: turns.length, contracts: acc.map((t) => contractFor(t)) },
63090
+ support: tokensSaved === void 0 ? support : { ...support, tokensSavedByCompaction: tokensSaved }
63091
+ };
63092
+ }
63093
+ function finalizeTurn(t) {
63094
+ let outcome;
63095
+ if (t.closedBy === void 0) outcome = "pending";
63096
+ else if (t.closedBy === "session-ended" && t.endReason !== "completed") outcome = "error";
63097
+ else outcome = "completed";
63098
+ return {
63099
+ index: t.index,
63100
+ userText: t.userText,
63101
+ assistantChars: t.assistantMessages > 0 ? t.assistantChars ?? 0 : void 0,
63102
+ assistantText: t.assistantMessages > 0 ? t.assistantText : void 0,
63103
+ toolCalls: t.toolCalls,
63104
+ toolKinds: t.toolKinds,
63105
+ verification: t.verification,
63106
+ outcome
63107
+ };
63108
+ }
63109
+ function contractFor(t) {
63110
+ const userMessage = true;
63111
+ const assistantReply = t.assistantMessages > 0;
63112
+ const allSettled = [...t.unsettledCallIds].every((id3) => t.settledCallIds.has(id3));
63113
+ const toolsSettled = allSettled && t.interrupted === 0;
63114
+ const blockers = [];
63115
+ if (!assistantReply) blockers.push("assistant-reply-missing");
63116
+ if (!toolsSettled) blockers.push("tools-unsettled");
63117
+ if (t.verification) {
63118
+ if (!t.verification.strict) blockers.push("verification-not-strict");
63119
+ else if (t.verification.verdict !== "PASS") blockers.push(`verification-verdict-${t.verification.verdict}`);
63120
+ } else if (t.closedBy === void 0) {
63121
+ blockers.push("turn-pending");
63122
+ } else if (t.closedBy === "session-ended" && t.endReason !== "completed") {
63123
+ blockers.push(`turn-error-${t.endReason}`);
63124
+ }
63125
+ return {
63126
+ turn: t.index,
63127
+ complete: userMessage && assistantReply && toolsSettled && blockers.length === 0,
63128
+ signals: {
63129
+ userMessage,
63130
+ assistantReply,
63131
+ toolsSettled,
63132
+ verification: t.verification
63133
+ },
63134
+ blockers
63135
+ };
63136
+ }
63137
+ async function readHarnessState(sessionDir) {
63138
+ const report = await readSessionLog(path81.join(sessionDir, "events.jsonl"));
63139
+ return deriveHarnessState(report.events);
63140
+ }
63141
+ var init_harnessState = __esm({
63142
+ "src/cli/harnessState.ts"() {
63143
+ "use strict";
63144
+ init_session();
63145
+ }
63146
+ });
63147
+
63148
+ // src/cli/headless/harnessStateEmit.ts
63149
+ import path82 from "node:path";
63150
+ async function emitHarnessStateEvent(opts) {
63151
+ if (opts.output !== "json") return;
63152
+ try {
63153
+ const sessionsDir = resolveSessionsDir({ workspaceRoot: opts.workspaceRoot });
63154
+ const state3 = await readHarnessState(path82.join(sessionsDir, opts.spine.sessionId));
63155
+ opts.emitEvent({ type: "harness_state", ...state3 });
63156
+ } catch (err) {
63157
+ const msg = err instanceof Error ? err.message : String(err);
63158
+ try {
63159
+ process.stderr.write(`[zelari-code --headless] harness_state unavailable: ${msg}
63160
+ `);
63161
+ } catch {
63162
+ }
63163
+ }
63164
+ }
63165
+ var init_harnessStateEmit = __esm({
63166
+ "src/cli/headless/harnessStateEmit.ts"() {
63167
+ "use strict";
63168
+ init_session();
63169
+ init_harnessState();
63170
+ }
63171
+ });
63172
+
62917
63173
  // src/cli/headless/policyGate.ts
62918
63174
  import { isAbsolute as isAbsolute5, resolve as resolve7 } from "node:path";
62919
63175
  import { randomUUID as randomUUID9 } from "node:crypto";
@@ -62959,7 +63215,7 @@ async function recordPolicyLoadBlockedOnSpine(block, opts = {}) {
62959
63215
  sessionId: sessionId2,
62960
63216
  ...opts.mode ? { mode: opts.mode } : {},
62961
63217
  ...opts.profile ? { profile: opts.profile } : {},
62962
- workspace: process.cwd()
63218
+ workspace: opts.workspace ?? process.cwd()
62963
63219
  });
62964
63220
  if (opts.mode === "zelari") {
62965
63221
  spine.missionPhase("dispatch", block.reason);
@@ -63390,13 +63646,13 @@ var init_sessionControl = __esm({
63390
63646
 
63391
63647
  // src/cli/extensions/sandboxedFs.ts
63392
63648
  import { promises as fsp } from "node:fs";
63393
- import path80 from "node:path";
63649
+ import path83 from "node:path";
63394
63650
  function errText(prefix, p3, err) {
63395
63651
  const msg = err instanceof Error ? err.message : String(err);
63396
63652
  return `[extension-fs] ${prefix} "${p3}": ${msg}`;
63397
63653
  }
63398
63654
  function bindSandboxedFs(root) {
63399
- const resolvedRoot = path80.resolve(root);
63655
+ const resolvedRoot = path83.resolve(root);
63400
63656
  return {
63401
63657
  root: resolvedRoot,
63402
63658
  async readFile(relativePath) {
@@ -63412,7 +63668,7 @@ function bindSandboxedFs(root) {
63412
63668
  try {
63413
63669
  const target = resolveSandboxedPath(relativePath, { root: resolvedRoot });
63414
63670
  verifyContainment(target, { root: resolvedRoot });
63415
- await fsp.mkdir(path80.dirname(target), { recursive: true });
63671
+ await fsp.mkdir(path83.dirname(target), { recursive: true });
63416
63672
  await fsp.writeFile(target, data, "utf8");
63417
63673
  return typedOk({ path: target });
63418
63674
  } catch (err) {
@@ -63597,7 +63853,7 @@ var init_loader = __esm({
63597
63853
 
63598
63854
  // src/cli/headless/runOneTurn.ts
63599
63855
  import { promises as fs42 } from "node:fs";
63600
- import path81 from "node:path";
63856
+ import path84 from "node:path";
63601
63857
  function planModeFromOpts(opts) {
63602
63858
  return (opts.phase ?? "build") === "plan";
63603
63859
  }
@@ -63651,11 +63907,14 @@ async function writeProofSafe(gate, meta3, baseDir = process.cwd()) {
63651
63907
  );
63652
63908
  }
63653
63909
  }
63654
- async function runOneTurn(opts, provider, model, providerStream) {
63910
+ async function runOneTurn(opts, provider, model, providerStream, extras) {
63655
63911
  const sessionId2 = crypto.randomUUID();
63656
63912
  const cwd = resolveHeadlessCwd(opts);
63657
63913
  const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
63658
- const nativeMemory = memoryFactory.isMemoryV2Enabled() ? await memoryFactory.getMemoryService(cwd, process.env) : void 0;
63914
+ const spineHolder = {};
63915
+ const nativeMemory = memoryFactory.isMemoryV2Enabled() ? await memoryFactory.getMemoryService(cwd, process.env, {
63916
+ onEvent: memorySinkFor(spineHolder)
63917
+ }) : void 0;
63659
63918
  const memoryAutoWrite = memoryFactory.isMemoryAutoWriteEnabled();
63660
63919
  const controlQueue = new RuntimeControlQueue();
63661
63920
  const harnessHolder = {};
@@ -63748,7 +64007,11 @@ async function runOneTurn(opts, provider, model, providerStream) {
63748
64007
  },
63749
64008
  ...nativeMemory ? { memoryService: nativeMemory } : {},
63750
64009
  memoryAutoWrite,
63751
- ...extensionRuntime ? { extensions: extensionRuntime } : {}
64010
+ ...extensionRuntime ? { extensions: extensionRuntime } : {},
64011
+ // t37: serve-harness threads the kernel-owned workspace LspManager here
64012
+ // (TurnExtras). undefined keeps the shared per-root fallback — which is
64013
+ // itself one-manager-per-root since t37, so no cross-workspace thrash.
64014
+ ...extras?.lspProvider ? { lspProvider: extras.lspProvider } : {}
63752
64015
  });
63753
64016
  await registerHeadlessMcp(toolRegistry, opts);
63754
64017
  const spine = await openHeadlessSpine({
@@ -63759,6 +64022,7 @@ async function runOneTurn(opts, provider, model, providerStream) {
63759
64022
  // 2.6.1 (plan §7): deep specs from THIS run’s registry.
63760
64023
  toolSpecs: typeof toolRegistry.fingerprints === "function" ? toolRegistry.fingerprints() : void 0
63761
64024
  });
64025
+ spineHolder.current = spine;
63762
64026
  const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
63763
64027
  emitEvent(sessionStartedEvent(spine));
63764
64028
  if (opts.orchestrationDecision) {
@@ -64067,8 +64331,9 @@ async function runOneTurn(opts, provider, model, providerStream) {
64067
64331
  },
64068
64332
  emit: (input) => spine.appendEvent(input)
64069
64333
  };
64334
+ const strictEnv = strictEnvOverlay(opts);
64070
64335
  if (pass.finalReason === "completed" && pass.exitCode === 0 && isKrakenMode(opts.mode) && (isKrakenSelectionEnabled() || nativePackEnabled()) && !planModeFromOpts(opts)) {
64071
- const strictGate = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd });
64336
+ const strictGate = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd, env: strictEnv });
64072
64337
  await runAdvisoryVerifierReview(strictGate, verifierReviewDeps).catch(() => void 0);
64073
64338
  const gate = strictGate.gate;
64074
64339
  const verificationPayload = strictGateEventPayload(strictGate);
@@ -64103,7 +64368,7 @@ async function runOneTurn(opts, provider, model, providerStream) {
64103
64368
  successfulWrites: pass.successfulWrites + repair.successfulWrites,
64104
64369
  emittedWrites: pass.emittedWrites + repair.emittedWrites
64105
64370
  };
64106
- const after = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd });
64371
+ const after = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd, env: strictEnv });
64107
64372
  await runAdvisoryVerifierReview(after, verifierReviewDeps).catch(() => void 0);
64108
64373
  const afterPayload = strictGateEventPayload(after);
64109
64374
  spine.verificationRun(afterPayload);
@@ -64138,13 +64403,14 @@ async function runOneTurn(opts, provider, model, providerStream) {
64138
64403
  await spine.close(closeStatus);
64139
64404
  } catch {
64140
64405
  }
64406
+ await emitHarnessStateEvent({ spine, workspaceRoot: cwd, output: opts.output, emitEvent });
64141
64407
  if (opts.exportSessionPath) {
64142
64408
  try {
64143
64409
  const json3 = await spine.exportJson();
64144
64410
  if (json3) {
64145
64411
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
64146
64412
  else {
64147
- await fs42.mkdir(path81.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
64413
+ await fs42.mkdir(path84.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
64148
64414
  await fs42.writeFile(opts.exportSessionPath, json3, "utf8");
64149
64415
  }
64150
64416
  }
@@ -64200,6 +64466,7 @@ var init_runOneTurn = __esm({
64200
64466
  init_selectionPlaybook();
64201
64467
  init_delegationPolicy();
64202
64468
  init_facts();
64469
+ init_spineTelemetry();
64203
64470
  init_headless();
64204
64471
  init_mode();
64205
64472
  init_skills2();
@@ -64213,6 +64480,7 @@ var init_runOneTurn = __esm({
64213
64480
  init_modelContextBuilder();
64214
64481
  init_metrics3();
64215
64482
  init_headlessSpine();
64483
+ init_harnessStateEmit();
64216
64484
  init_runtime2();
64217
64485
  init_controlBridge();
64218
64486
  init_protocol2();
@@ -65118,9 +65386,9 @@ __export(triggerLock_exports, {
65118
65386
  releaseLock: () => releaseLock
65119
65387
  });
65120
65388
  import { promises as fs43 } from "node:fs";
65121
- import * as path82 from "node:path";
65389
+ import * as path85 from "node:path";
65122
65390
  function lockPath(projectRoot) {
65123
- return path82.join(projectRoot, ".zelari", "trigger.lock");
65391
+ return path85.join(projectRoot, ".zelari", "trigger.lock");
65124
65392
  }
65125
65393
  function isPidAlive(pid) {
65126
65394
  try {
@@ -65133,7 +65401,7 @@ function isPidAlive(pid) {
65133
65401
  }
65134
65402
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
65135
65403
  const lp = lockPath(projectRoot);
65136
- const dir = path82.dirname(lp);
65404
+ const dir = path85.dirname(lp);
65137
65405
  await fs43.mkdir(dir, { recursive: true });
65138
65406
  try {
65139
65407
  const raw = await fs43.readFile(lp, "utf8");
@@ -65165,13 +65433,10 @@ var init_triggerLock = __esm({
65165
65433
 
65166
65434
  // src/cli/runHeadless.ts
65167
65435
  import { promises as fs44 } from "node:fs";
65168
- import path83 from "node:path";
65436
+ import path86 from "node:path";
65169
65437
  import { randomUUID as randomUUID10 } from "node:crypto";
65170
65438
  async function runHeadless(opts) {
65171
65439
  resetTaskSpawnCount();
65172
- if (opts.strictDone) {
65173
- process.env.ZELARI_STRICT_DONE = "1";
65174
- }
65175
65440
  let crashed = false;
65176
65441
  const handleFatal = (label, err) => {
65177
65442
  if (crashed) return;
@@ -65245,7 +65510,13 @@ ${err.stack}` : "";
65245
65510
  model
65246
65511
  });
65247
65512
  }
65248
- return dispatchHeadlessTurn(opts, provider, model, providerStream);
65513
+ return dispatchHeadlessTurn(opts, provider, model, providerStream, {
65514
+ // H10-fix3: the gate already ran above on the SAME input (no chdir in
65515
+ // between) — the one-shot marker keeps dispatchHeadlessTurn from
65516
+ // re-running it (duplicate `[policy]` stderr warning + double policy
65517
+ // load). Per-invocation flag only; never process-global.
65518
+ policyGateDone: true
65519
+ });
65249
65520
  }
65250
65521
  async function applyHeadlessPolicyGate(opts) {
65251
65522
  const cwd = resolveHeadlessCwd(opts);
@@ -65257,6 +65528,9 @@ async function applyHeadlessPolicyGate(opts) {
65257
65528
  reportPolicyLoadBlocked(policyLoad.block, opts.output);
65258
65529
  await recordPolicyLoadBlockedOnSpine(policyLoad.block, {
65259
65530
  mode: opts.mode,
65531
+ // H10-fix2: the spine must land in the RESOLVED workspace, not the
65532
+ // process cwd — a sidecar hosts N workspaces without `chdir`.
65533
+ workspace: cwd,
65260
65534
  ...opts.profile ? { profile: opts.profile } : {},
65261
65535
  ...opts.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {}
65262
65536
  });
@@ -65276,7 +65550,7 @@ function applyKrakenTurnEnv(opts) {
65276
65550
  }
65277
65551
  }
65278
65552
  }
65279
- async function dispatchHeadlessTurn(opts, provider, model, providerStream) {
65553
+ async function dispatchHeadlessTurn(opts, provider, model, providerStream, oneShot, extras) {
65280
65554
  const cwd = resolveHeadlessCwd(opts);
65281
65555
  if (typeof opts.mode === "string") {
65282
65556
  const parsed = parseMode(opts.mode);
@@ -65304,8 +65578,10 @@ async function dispatchHeadlessTurn(opts, provider, model, providerStream) {
65304
65578
  }
65305
65579
  } catch {
65306
65580
  }
65307
- const policyBlock = await applyHeadlessPolicyGate(opts);
65308
- if (policyBlock !== void 0) return policyBlock;
65581
+ if (!oneShot?.policyGateDone) {
65582
+ const policyBlock = await applyHeadlessPolicyGate(opts);
65583
+ if (policyBlock !== void 0) return policyBlock;
65584
+ }
65309
65585
  if (opts.orchestrationAuto) {
65310
65586
  const facts = await collectOrchestrationFacts(cwd);
65311
65587
  const verdict = chooseOrchestration(opts.task ?? "", facts);
@@ -65347,12 +65623,12 @@ async function dispatchHeadlessTurn(opts, provider, model, providerStream) {
65347
65623
  `);
65348
65624
  }
65349
65625
  if (mode === "zelari") {
65350
- return runHeadlessZelari(opts, provider, model, providerStream);
65626
+ return runHeadlessZelari(opts, provider, model, providerStream, extras);
65351
65627
  }
65352
65628
  if (mode === "council" || opts.useCouncil) {
65353
- return runHeadlessCouncil(opts, provider, model, providerStream);
65629
+ return runHeadlessCouncil(opts, provider, model, providerStream, extras);
65354
65630
  }
65355
- return runOneTurn(opts, provider, model, providerStream);
65631
+ return runOneTurn(opts, provider, model, providerStream, extras);
65356
65632
  }
65357
65633
  async function runHeadlessKrakenGraph(opts, provider, model) {
65358
65634
  const { isKrakenGraphEnabled: isKrakenGraphEnabled2, KrakenGraphExecutor: KrakenGraphExecutor2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
@@ -65372,8 +65648,15 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
65372
65648
  const { createKrakenSubAgentContextFactory: createKrakenSubAgentContextFactory2 } = await Promise.resolve().then(() => (init_toolRegistry(), toolRegistry_exports));
65373
65649
  const cwd = resolveHeadlessCwd(opts);
65374
65650
  const sessionId2 = crypto.randomUUID();
65651
+ const spine = await openHeadlessSpine({ sessionId: sessionId2, mode: "kraken", workspace: cwd });
65652
+ if (opts.output === "json") emitEvent(sessionStartedEvent(spine));
65653
+ spine.userMessage(prompt);
65375
65654
  const { getMemoryService: getMemoryService2, isMemoryAutoWriteEnabled: isMemoryAutoWriteEnabled2, isMemoryV2Enabled: isMemoryV2Enabled2 } = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
65376
- const graphMemory = isMemoryV2Enabled2() ? await getMemoryService2(cwd, process.env) : void 0;
65655
+ const graphMemory = isMemoryV2Enabled2() ? await getMemoryService2(cwd, process.env, {
65656
+ // W2: the spine is already open here — memory events are noted
65657
+ // directly (context.projection / memory_event state-only payloads).
65658
+ onEvent: (event) => spineMemoryEventNote(spine, event)
65659
+ }) : void 0;
65377
65660
  const log = (message) => {
65378
65661
  if (opts.output === "json") {
65379
65662
  emitEvent({ type: "log", message });
@@ -65388,28 +65671,32 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
65388
65671
  abort.abort();
65389
65672
  };
65390
65673
  process.once("SIGINT", onSigint);
65674
+ let exitCode = 0;
65391
65675
  try {
65392
65676
  let preflightGraph;
65393
65677
  if (opts.runPlan && opts.runPlan.trim() !== "") {
65394
- const planPath = path83.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
65678
+ const planPath = path86.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
65395
65679
  log(`loading pre-flight plan: ${planPath}`);
65396
65680
  let raw;
65397
65681
  try {
65398
65682
  raw = await fs44.readFile(planPath, "utf8");
65399
65683
  } catch (e) {
65400
65684
  log(`plan file not found: ${planPath} (${e.message})`);
65401
- return 1;
65685
+ exitCode = 1;
65686
+ return exitCode;
65402
65687
  }
65403
65688
  let planJson;
65404
65689
  try {
65405
65690
  planJson = JSON.parse(raw);
65406
65691
  } catch (e) {
65407
65692
  log(`plan file is malformed JSON: ${e.message}`);
65408
- return 1;
65693
+ exitCode = 1;
65694
+ return exitCode;
65409
65695
  }
65410
65696
  if (!planJson || !Array.isArray(planJson.nodes)) {
65411
65697
  log(`plan file is malformed: missing "nodes" array`);
65412
- return 1;
65698
+ exitCode = 1;
65699
+ return exitCode;
65413
65700
  }
65414
65701
  const { createGraph: createGraph2, validateGraph: validateGraph2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
65415
65702
  const validated = createGraph2(planJson.graphId ?? opts.runPlan, planJson.nodes);
@@ -65431,8 +65718,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
65431
65718
  log(formatKrakenGraphAscii2(graph));
65432
65719
  if (opts.planOnly) {
65433
65720
  const planId = randomUUID10();
65434
- const planDir = path83.join(cwd, ".zelari", "radio");
65435
- const planPath = path83.join(planDir, `plan-${planId}.json`);
65721
+ const planDir = path86.join(cwd, ".zelari", "radio");
65722
+ const planPath = path86.join(planDir, `plan-${planId}.json`);
65436
65723
  await fs44.mkdir(planDir, { recursive: true });
65437
65724
  await fs44.writeFile(
65438
65725
  planPath,
@@ -65451,7 +65738,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
65451
65738
  emitEvent({ type: "log", message: `plan_only_id=${planId}` });
65452
65739
  emitEvent({ type: "log", message: `plan_only_path=${planPath}` });
65453
65740
  }
65454
- return 0;
65741
+ exitCode = 0;
65742
+ return exitCode;
65455
65743
  }
65456
65744
  const audit = new AuditLogger2();
65457
65745
  const executor = new KrakenGraphExecutor2({
@@ -65508,7 +65796,8 @@ ${formatKrakenGraphDigest2(
65508
65796
  process.stdout.write(`${finalAscii}
65509
65797
  `);
65510
65798
  }
65511
- return summary.converged ? 0 : 3;
65799
+ exitCode = summary.converged ? 0 : 3;
65800
+ return exitCode;
65512
65801
  } catch (err) {
65513
65802
  const message = err instanceof Error ? err.message : String(err);
65514
65803
  if (opts.output === "json") {
@@ -65517,17 +65806,25 @@ ${formatKrakenGraphDigest2(
65517
65806
  process.stderr.write(`[zelari-code --headless] kraken graph failed: ${message}
65518
65807
  `);
65519
65808
  }
65520
- return 2;
65809
+ exitCode = 2;
65810
+ return exitCode;
65521
65811
  } finally {
65522
65812
  process.off("SIGINT", onSigint);
65523
65813
  await graphMemory?.close().catch(() => void 0);
65814
+ try {
65815
+ const closeReason = abort.signal.aborted ? "cancelled" : exitCode === 0 ? "completed" : "error";
65816
+ await spine.close(closeReason);
65817
+ } catch {
65818
+ }
65819
+ await emitHarnessStateEvent({ spine, workspaceRoot: cwd, output: opts.output, emitEvent });
65524
65820
  }
65525
65821
  }
65526
- async function buildCouncilToolRegistry(planMode, opts, memoryService, memoryAutoWrite = false) {
65822
+ async function buildCouncilToolRegistry(planMode, opts, memoryService, memoryAutoWrite = false, extras) {
65527
65823
  const cwd = opts ? resolveHeadlessCwd(opts) : process.cwd();
65528
65824
  const { registry: toolRegistry } = createBuiltinToolRegistry({
65529
65825
  root: cwd,
65530
65826
  planMode,
65827
+ ...extras?.lspProvider ? { lspProvider: extras.lspProvider } : {},
65531
65828
  permissionPolicy: {
65532
65829
  read: "allow",
65533
65830
  write: "allow",
@@ -65554,12 +65851,15 @@ async function buildCouncilToolRegistry(planMode, opts, memoryService, memoryAut
65554
65851
  }
65555
65852
  return { toolRegistry, workspaceCtx: realCtx };
65556
65853
  }
65557
- async function runHeadlessCouncil(opts, provider, model, providerStream) {
65854
+ async function runHeadlessCouncil(opts, provider, model, providerStream, extras) {
65558
65855
  const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
65559
65856
  const sessionId2 = crypto.randomUUID();
65560
65857
  const cwd = resolveHeadlessCwd(opts);
65561
65858
  const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
65562
- const nativeMemory = memoryFactory.isMemoryV2Enabled() ? await memoryFactory.getMemoryService(cwd, process.env) : void 0;
65859
+ const spineHolder = {};
65860
+ const nativeMemory = memoryFactory.isMemoryV2Enabled() ? await memoryFactory.getMemoryService(cwd, process.env, {
65861
+ onEvent: memorySinkFor(spineHolder)
65862
+ }) : void 0;
65563
65863
  const memoryAutoWrite = memoryFactory.isMemoryAutoWriteEnabled();
65564
65864
  const spine = await openHeadlessSpine({
65565
65865
  sessionId: opts.resumeSessionId ?? sessionId2,
@@ -65567,6 +65867,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
65567
65867
  profile: opts.profile,
65568
65868
  workspace: cwd
65569
65869
  });
65870
+ spineHolder.current = spine;
65570
65871
  const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
65571
65872
  emitEvent(sessionStartedEvent(spine));
65572
65873
  if (opts.orchestrationDecision) {
@@ -65586,7 +65887,8 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
65586
65887
  planModeFromOpts(opts) || softGated,
65587
65888
  opts,
65588
65889
  nativeMemory,
65589
- memoryAutoWrite
65890
+ memoryAutoWrite,
65891
+ extras
65590
65892
  );
65591
65893
  const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
65592
65894
  const feedbackStore = new FeedbackStore2();
@@ -65715,13 +66017,14 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
65715
66017
  await spine.close(exitCode === 0 ? "completed" : "error");
65716
66018
  } catch {
65717
66019
  }
66020
+ await emitHarnessStateEvent({ spine, workspaceRoot: cwd, output: opts.output, emitEvent });
65718
66021
  if (opts.exportSessionPath) {
65719
66022
  try {
65720
66023
  const json3 = await spine.exportJson();
65721
66024
  if (json3) {
65722
66025
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
65723
66026
  else {
65724
- await fs44.mkdir(path83.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
66027
+ await fs44.mkdir(path86.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
65725
66028
  await fs44.writeFile(opts.exportSessionPath, json3, "utf8");
65726
66029
  }
65727
66030
  }
@@ -65754,7 +66057,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
65754
66057
  await nativeMemory?.close().catch(() => void 0);
65755
66058
  return exitCode;
65756
66059
  }
65757
- async function runHeadlessZelari(opts, provider, model, providerStream) {
66060
+ async function runHeadlessZelari(opts, provider, model, providerStream, extras) {
65758
66061
  const projectRoot = resolveHeadlessCwd(opts);
65759
66062
  const sessionId2 = opts.resumeSessionId ?? crypto.randomUUID();
65760
66063
  const spine = await openHeadlessSpine({
@@ -65777,13 +66080,18 @@ async function runHeadlessZelari(opts, provider, model, providerStream) {
65777
66080
  userMessage: opts.task,
65778
66081
  hasPlan: hasWorkspacePlan2(projectRoot)
65779
66082
  });
65780
- const memory = await getMemoryBackend2(projectRoot);
66083
+ const memory = await getMemoryBackend2(
66084
+ projectRoot,
66085
+ process.env,
66086
+ (event) => spineMemoryEventNote(spine, event)
66087
+ );
65781
66088
  const nativeMissionMemory = memory.service;
65782
66089
  const { toolRegistry, workspaceCtx } = await buildCouncilToolRegistry(
65783
66090
  planModeFromOpts(opts),
65784
66091
  opts,
65785
66092
  nativeMissionMemory,
65786
- Boolean(nativeMissionMemory) && process.env.ZELARI_MEMORY_AUTO_WRITE !== "0"
66093
+ Boolean(nativeMissionMemory) && process.env.ZELARI_MEMORY_AUTO_WRITE !== "0",
66094
+ extras
65787
66095
  );
65788
66096
  const feedbackStore = new FeedbackStore2();
65789
66097
  const chairmanBudget = envNumber(process.env.ZELARI_MODE_MAX_TOOLS_LUCIFER, {
@@ -66096,6 +66404,8 @@ ${ragContext}` : slicePrompt;
66096
66404
  const missionGate = await evaluateStrictBuildGate("build", {
66097
66405
  emit: (input) => spine.appendEvent(input),
66098
66406
  surface: "mission",
66407
+ // H10-fix1: per-invocation env overlay — never process.env.
66408
+ env: strictEnvOverlay(opts),
66099
66409
  cwd: projectRoot
66100
66410
  });
66101
66411
  const missionVerificationPayload = strictGateEventPayload(missionGate);
@@ -66132,13 +66442,14 @@ ${ragContext}` : slicePrompt;
66132
66442
  else await spine.close(exitCode === 2 ? "error" : "stopped");
66133
66443
  } catch {
66134
66444
  }
66445
+ await emitHarnessStateEvent({ spine, workspaceRoot: projectRoot, output: opts.output, emitEvent });
66135
66446
  if (opts.exportSessionPath) {
66136
66447
  try {
66137
66448
  const json3 = await spine.exportJson();
66138
66449
  if (json3) {
66139
66450
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
66140
66451
  else {
66141
- await fs44.mkdir(path83.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
66452
+ await fs44.mkdir(path86.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
66142
66453
  await fs44.writeFile(opts.exportSessionPath, json3, "utf8");
66143
66454
  }
66144
66455
  }
@@ -66157,6 +66468,7 @@ var init_runHeadless = __esm({
66157
66468
  init_toolRegistry();
66158
66469
  init_policy();
66159
66470
  init_facts();
66471
+ init_spineTelemetry();
66160
66472
  init_councilConfig();
66161
66473
  init_headless();
66162
66474
  init_claudeProvider();
@@ -66172,6 +66484,7 @@ var init_runHeadless = __esm({
66172
66484
  init_modelContextBuilder();
66173
66485
  init_metrics3();
66174
66486
  init_headlessSpine();
66487
+ init_harnessStateEmit();
66175
66488
  init_policyGate();
66176
66489
  init_policyLoadMode();
66177
66490
  init_runOneTurn();
@@ -66749,7 +67062,7 @@ function upsertSkill(opts) {
66749
67062
  }
66750
67063
  dir = getProjectSkillsDir(root);
66751
67064
  }
66752
- const path87 = skillFilePath(dir, name);
67065
+ const path90 = skillFilePath(dir, name);
66753
67066
  const content = serializeSkillMd({
66754
67067
  name,
66755
67068
  description,
@@ -66758,13 +67071,13 @@ function upsertSkill(opts) {
66758
67071
  tools: opts.tools,
66759
67072
  cost: opts.cost
66760
67073
  });
66761
- const parsed = parseSkillMd(content, path87);
67074
+ const parsed = parseSkillMd(content, path90);
66762
67075
  if (!parsed) {
66763
67076
  return { ok: false, error: "Generated SKILL.md failed validation" };
66764
67077
  }
66765
- mkdirSync21(dirname13(path87), { recursive: true });
66766
- writeFileSync24(path87, content, "utf8");
66767
- return { ok: true, path: path87 };
67078
+ mkdirSync21(dirname13(path90), { recursive: true });
67079
+ writeFileSync24(path90, content, "utf8");
67080
+ return { ok: true, path: path90 };
66768
67081
  }
66769
67082
  function removeSkill(opts) {
66770
67083
  const name = opts.name.trim().toLowerCase();
@@ -66782,8 +67095,8 @@ function removeSkill(opts) {
66782
67095
  dir = getProjectSkillsDir(root);
66783
67096
  }
66784
67097
  const skillDir = join46(dir, name);
66785
- const path87 = skillFilePath(dir, name);
66786
- if (!existsSync52(path87) && !existsSync52(skillDir)) {
67098
+ const path90 = skillFilePath(dir, name);
67099
+ if (!existsSync52(path90) && !existsSync52(skillDir)) {
66787
67100
  return { ok: false, error: `Skill "${name}" not found in ${dir}` };
66788
67101
  }
66789
67102
  try {
@@ -66794,7 +67107,7 @@ function removeSkill(opts) {
66794
67107
  error: err instanceof Error ? err.message : String(err)
66795
67108
  };
66796
67109
  }
66797
- return { ok: true, path: path87 };
67110
+ return { ok: true, path: path90 };
66798
67111
  }
66799
67112
  var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
66800
67113
  var init_skillConfigIo = __esm({
@@ -66913,7 +67226,7 @@ var init_jsonApi = __esm({
66913
67226
  });
66914
67227
 
66915
67228
  // src/cli/memory/mcpAdapter.ts
66916
- import * as path84 from "node:path";
67229
+ import * as path87 from "node:path";
66917
67230
  var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
66918
67231
  var init_mcpAdapter = __esm({
66919
67232
  "src/cli/memory/mcpAdapter.ts"() {
@@ -67083,8 +67396,8 @@ var init_mcpAdapter = __esm({
67083
67396
  this.takeWrite();
67084
67397
  const externalFile = args.source?.file;
67085
67398
  if (externalFile) {
67086
- const normalized = path84.normalize(externalFile);
67087
- if (path84.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path84.sep}`)) {
67399
+ const normalized = path87.normalize(externalFile);
67400
+ if (path87.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path87.sep}`)) {
67088
67401
  throw new Error("source.file must be project-relative and cannot escape the project");
67089
67402
  }
67090
67403
  }
@@ -67612,12 +67925,12 @@ function ensureHome() {
67612
67925
  }
67613
67926
  }
67614
67927
  function loadCompanionConfig() {
67615
- const path87 = getCompanionConfigPath();
67616
- if (!existsSync53(path87)) {
67928
+ const path90 = getCompanionConfigPath();
67929
+ if (!existsSync53(path90)) {
67617
67930
  return { projects: [] };
67618
67931
  }
67619
67932
  try {
67620
- const raw = JSON.parse(readFileSync41(path87, "utf8"));
67933
+ const raw = JSON.parse(readFileSync41(path90, "utf8"));
67621
67934
  const projects = Array.isArray(raw.projects) ? raw.projects.filter(
67622
67935
  (p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
67623
67936
  ).map((p3) => ({
@@ -67655,16 +67968,16 @@ function loadOrCreateToken(explicit) {
67655
67968
  return { token: explicit.trim(), created: false };
67656
67969
  }
67657
67970
  ensureHome();
67658
- const path87 = getCompanionTokenPath();
67659
- if (existsSync53(path87)) {
67660
- const t = readFileSync41(path87, "utf8").trim();
67971
+ const path90 = getCompanionTokenPath();
67972
+ if (existsSync53(path90)) {
67973
+ const t = readFileSync41(path90, "utf8").trim();
67661
67974
  if (t) return { token: t, created: false };
67662
67975
  }
67663
67976
  const token = randomBytes7(24).toString("base64url");
67664
- writeFileSync25(path87, token + "\n", "utf8");
67977
+ writeFileSync25(path90, token + "\n", "utf8");
67665
67978
  try {
67666
67979
  const fs45 = __require("node:fs");
67667
- fs45.chmodSync?.(path87, 384);
67980
+ fs45.chmodSync?.(path90, 384);
67668
67981
  } catch {
67669
67982
  }
67670
67983
  return { token, created: true };
@@ -67689,17 +68002,17 @@ function mergeProjects(cfg, extraPaths) {
67689
68002
  byId.set(p3.id, p3);
67690
68003
  }
67691
68004
  for (const raw of extraPaths) {
67692
- const path87 = raw.trim();
67693
- if (!path87) continue;
67694
- let id3 = slugFromPath(path87);
68005
+ const path90 = raw.trim();
68006
+ if (!path90) continue;
68007
+ let id3 = slugFromPath(path90);
67695
68008
  let n = 2;
67696
- while (byId.has(id3) && byId.get(id3).path !== path87) {
67697
- id3 = `${slugFromPath(path87)}-${n++}`;
68009
+ while (byId.has(id3) && byId.get(id3).path !== path90) {
68010
+ id3 = `${slugFromPath(path90)}-${n++}`;
67698
68011
  }
67699
68012
  byId.set(id3, {
67700
68013
  id: id3,
67701
- name: slugFromPath(path87),
67702
- path: path87
68014
+ name: slugFromPath(path90),
68015
+ path: path90
67703
68016
  });
67704
68017
  }
67705
68018
  return [...byId.values()];
@@ -67752,6 +68065,7 @@ __export(harnessServer_exports, {
67752
68065
  bindHarnessTurnOptions: () => bindHarnessTurnOptions,
67753
68066
  createCliRunTurn: () => createCliRunTurn,
67754
68067
  createCliWorkspaceServices: () => createCliWorkspaceServices,
68068
+ resolveTurnLspProvider: () => resolveTurnLspProvider,
67755
68069
  runHarnessServer: () => runHarnessServer,
67756
68070
  startHarnessServer: () => startHarnessServer
67757
68071
  });
@@ -67797,6 +68111,10 @@ function bindHarnessTurnOptions(input, workspaceRoot) {
67797
68111
  useCouncil: turnInput.useCouncil === true || mode === "council"
67798
68112
  };
67799
68113
  }
68114
+ function resolveTurnLspProvider(services) {
68115
+ const candidate = services?.lspManager;
68116
+ return candidate instanceof LspManager ? candidate : void 0;
68117
+ }
67800
68118
  function createCliRunTurn() {
67801
68119
  let streamPromise = null;
67802
68120
  const ensureStream = () => {
@@ -67823,11 +68141,14 @@ function createCliRunTurn() {
67823
68141
  return async (input, deps) => {
67824
68142
  const { provider, model, stream } = await ensureStream();
67825
68143
  const opts = bindHarnessTurnOptions(input, deps.session.workspaceRoot);
68144
+ const lspProvider = resolveTurnLspProvider(deps.services);
67826
68145
  const exitCode = await dispatchHeadlessTurn(
67827
68146
  opts,
67828
68147
  provider,
67829
68148
  model,
67830
- stream
68149
+ stream,
68150
+ void 0,
68151
+ lspProvider ? { lspProvider } : void 0
67831
68152
  );
67832
68153
  return { exitCode };
67833
68154
  };
@@ -68666,9 +68987,9 @@ async function runCompanionServe(opts = {}) {
68666
68987
  return;
68667
68988
  }
68668
68989
  const url2 = parseUrl(req);
68669
- const path87 = url2.pathname.replace(/\/+$/, "") || "/";
68990
+ const path90 = url2.pathname.replace(/\/+$/, "") || "/";
68670
68991
  try {
68671
- if (req.method === "GET" && (path87 === "/health" || path87 === "/v1/health")) {
68992
+ if (req.method === "GET" && (path90 === "/health" || path90 === "/v1/health")) {
68672
68993
  sendJson2(res, 200, {
68673
68994
  ok: true,
68674
68995
  service: "zelari-companion",
@@ -68680,18 +69001,18 @@ async function runCompanionServe(opts = {}) {
68680
69001
  });
68681
69002
  return;
68682
69003
  }
68683
- if (path87.startsWith("/v1")) {
69004
+ if (path90.startsWith("/v1")) {
68684
69005
  if (!tokenMatches(token, getBearer(req))) {
68685
69006
  sendJson2(res, 401, { ok: false, error: "unauthorized" });
68686
69007
  return;
68687
69008
  }
68688
69009
  }
68689
- if (req.method === "GET" && path87 === "/v1/config") {
69010
+ if (req.method === "GET" && path90 === "/v1/config") {
68690
69011
  const snap = buildDesktopConfigSnapshot();
68691
69012
  sendJson2(res, 200, { ok: true, ...snap });
68692
69013
  return;
68693
69014
  }
68694
- if (req.method === "GET" && path87 === "/v1/projects") {
69015
+ if (req.method === "GET" && path90 === "/v1/projects") {
68695
69016
  sendJson2(res, 200, {
68696
69017
  ok: true,
68697
69018
  projects: projects.map((p3) => ({
@@ -68702,7 +69023,7 @@ async function runCompanionServe(opts = {}) {
68702
69023
  });
68703
69024
  return;
68704
69025
  }
68705
- if (req.method === "GET" && path87 === "/v1/runs") {
69026
+ if (req.method === "GET" && path90 === "/v1/runs") {
68706
69027
  sendJson2(res, 200, {
68707
69028
  ok: true,
68708
69029
  active: runs.getActive(),
@@ -68720,7 +69041,7 @@ async function runCompanionServe(opts = {}) {
68720
69041
  });
68721
69042
  return;
68722
69043
  }
68723
- if (req.method === "POST" && path87 === "/v1/runs") {
69044
+ if (req.method === "POST" && path90 === "/v1/runs") {
68724
69045
  const raw = await readBody(req);
68725
69046
  let body = {};
68726
69047
  try {
@@ -68763,11 +69084,12 @@ async function runCompanionServe(opts = {}) {
68763
69084
  createdAt: result.run.createdAt
68764
69085
  },
68765
69086
  eventsUrl: `/v1/runs/${result.run.id}/events`,
68766
- cancelUrl: `/v1/runs/${result.run.id}/cancel`
69087
+ cancelUrl: `/v1/runs/${result.run.id}/cancel`,
69088
+ steerUrl: `/v1/runs/${result.run.id}/steer`
68767
69089
  });
68768
69090
  return;
68769
69091
  }
68770
- const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path87);
69092
+ const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path90);
68771
69093
  if (req.method === "GET" && eventsMatch) {
68772
69094
  const runId = eventsMatch[1];
68773
69095
  const run = runs.getRun(runId);
@@ -68832,7 +69154,7 @@ async function runCompanionServe(opts = {}) {
68832
69154
  }, 500);
68833
69155
  return;
68834
69156
  }
68835
- const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path87);
69157
+ const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path90);
68836
69158
  if (req.method === "POST" && cancelMatch) {
68837
69159
  const runId = cancelMatch[1];
68838
69160
  const result = runs.cancel(runId);
@@ -68843,6 +69165,30 @@ async function runCompanionServe(opts = {}) {
68843
69165
  sendJson2(res, 200, { ok: true, cancelled: runId });
68844
69166
  return;
68845
69167
  }
69168
+ const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path90);
69169
+ if (req.method === "POST" && steerMatch) {
69170
+ const runId = steerMatch[1];
69171
+ const raw = await readBody(req);
69172
+ let body = {};
69173
+ try {
69174
+ body = raw ? JSON.parse(raw) : {};
69175
+ } catch {
69176
+ sendJson2(res, 400, { ok: false, error: "invalid JSON body" });
69177
+ return;
69178
+ }
69179
+ const text = typeof body.text === "string" ? body.text.trim() : "";
69180
+ if (!text) {
69181
+ sendJson2(res, 400, { ok: false, error: "text is required" });
69182
+ return;
69183
+ }
69184
+ const result = await runs.steer(runId, text);
69185
+ if (!result.ok) {
69186
+ sendJson2(res, 404, { ok: false, error: result.error });
69187
+ return;
69188
+ }
69189
+ sendJson2(res, 200, { ok: true, steered: runId, result: result.result });
69190
+ return;
69191
+ }
68846
69192
  sendJson2(res, 404, { ok: false, error: "not found" });
68847
69193
  } catch (err) {
68848
69194
  sendJson2(res, 500, {
@@ -68986,11 +69332,11 @@ import { execSync as execSync2 } from "node:child_process";
68986
69332
  import { existsSync as existsSync55, readFileSync as readFileSync42, readlinkSync, statSync as statSync10 } from "node:fs";
68987
69333
  import { createRequire as createRequire3 } from "node:module";
68988
69334
  import { fileURLToPath as fileURLToPath3 } from "node:url";
68989
- import path85 from "node:path";
69335
+ import path88 from "node:path";
68990
69336
  function findPackageRoot(start) {
68991
69337
  let dir = start;
68992
69338
  for (let i = 0; i < 6; i += 1) {
68993
- const candidate = path85.join(dir, "package.json");
69339
+ const candidate = path88.join(dir, "package.json");
68994
69340
  if (existsSync55(candidate)) {
68995
69341
  try {
68996
69342
  const pkg = JSON.parse(readFileSync42(candidate, "utf8"));
@@ -68998,11 +69344,11 @@ function findPackageRoot(start) {
68998
69344
  } catch {
68999
69345
  }
69000
69346
  }
69001
- const parent = path85.dirname(dir);
69347
+ const parent = path88.dirname(dir);
69002
69348
  if (parent === dir) break;
69003
69349
  dir = parent;
69004
69350
  }
69005
- return path85.resolve(__dirname3, "..", "..", "..");
69351
+ return path88.resolve(__dirname3, "..", "..", "..");
69006
69352
  }
69007
69353
  function tryExec(cmd) {
69008
69354
  try {
@@ -69016,7 +69362,7 @@ function tryExec(cmd) {
69016
69362
  }
69017
69363
  function readPackageJson4() {
69018
69364
  try {
69019
- const pkgPath = path85.join(packageRoot, "package.json");
69365
+ const pkgPath = path88.join(packageRoot, "package.json");
69020
69366
  return JSON.parse(readFileSync42(pkgPath, "utf8"));
69021
69367
  } catch {
69022
69368
  return null;
@@ -69032,7 +69378,7 @@ function checkShim(pkgName) {
69032
69378
  }
69033
69379
  const isWin = process.platform === "win32";
69034
69380
  const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
69035
- const shimPath = path85.join(prefix, shimName);
69381
+ const shimPath = path88.join(prefix, shimName);
69036
69382
  if (!existsSync55(shimPath)) {
69037
69383
  return FAIL(
69038
69384
  `shim not found at ${shimPath}
@@ -69060,8 +69406,8 @@ function checkShim(pkgName) {
69060
69406
  fix: npm install -g ${pkgName}@latest --force`
69061
69407
  );
69062
69408
  }
69063
- const resolved = path85.resolve(path85.dirname(shimPath), target);
69064
- const expected = path85.join(
69409
+ const resolved = path88.resolve(path88.dirname(shimPath), target);
69410
+ const expected = path88.join(
69065
69411
  prefix,
69066
69412
  "node_modules",
69067
69413
  pkgName,
@@ -69100,7 +69446,7 @@ function checkNode(pkg) {
69100
69446
  return OK(`node ${raw}`);
69101
69447
  }
69102
69448
  function checkBundle() {
69103
- const bundle = path85.join(packageRoot, "dist", "cli", "main.bundled.js");
69449
+ const bundle = path88.join(packageRoot, "dist", "cli", "main.bundled.js");
69104
69450
  if (!existsSync55(bundle)) {
69105
69451
  return FAIL(
69106
69452
  `dist/cli/main.bundled.js missing at ${bundle}
@@ -69121,7 +69467,7 @@ function checkRuntimeDeps() {
69121
69467
  const missing = [];
69122
69468
  for (const dep of required2) {
69123
69469
  try {
69124
- const localReq = createRequire3(path85.join(packageRoot, "package.json"));
69470
+ const localReq = createRequire3(path88.join(packageRoot, "package.json"));
69125
69471
  localReq.resolve(dep);
69126
69472
  } catch {
69127
69473
  missing.push(dep);
@@ -69321,7 +69667,7 @@ var init_doctor = __esm({
69321
69667
  init_metrics3();
69322
69668
  init_contextGrowthSummary();
69323
69669
  require3 = createRequire3(import.meta.url);
69324
- __dirname3 = path85.dirname(fileURLToPath3(import.meta.url));
69670
+ __dirname3 = path88.dirname(fileURLToPath3(import.meta.url));
69325
69671
  packageRoot = findPackageRoot(__dirname3);
69326
69672
  OK = (message) => ({
69327
69673
  ok: true,
@@ -69505,15 +69851,15 @@ __export(inspect_exports, {
69505
69851
  collectInspectReport: () => collectInspectReport,
69506
69852
  runInspect: () => runInspect
69507
69853
  });
69508
- import path86 from "node:path";
69854
+ import path89 from "node:path";
69509
69855
  import { existsSync as existsSync56, readFileSync as readFileSync43, readdirSync as readdirSync12 } from "node:fs";
69510
69856
  import { homedir as homedir17 } from "node:os";
69511
69857
  async function collectInspectReport(cwd = process.cwd()) {
69512
69858
  ensureBuiltinSkillsLoadedSync();
69513
69859
  const snap = listSkillsSnapshot(cwd);
69514
69860
  const mcp = listMcpServers(cwd);
69515
- const userMcpPath = path86.join(homedir17(), ".zelari-code", "mcp.json");
69516
- const projectMcpPath = path86.join(cwd, ".zelari", "mcp.json");
69861
+ const userMcpPath = path89.join(homedir17(), ".zelari-code", "mcp.json");
69862
+ const projectMcpPath = path89.join(cwd, ".zelari", "mcp.json");
69517
69863
  const globalHooks = globalHooksDir();
69518
69864
  const projectHooks = projectHooksDir(cwd);
69519
69865
  const projectTrusted = isFolderTrusted(cwd);
@@ -69541,9 +69887,9 @@ async function collectInspectReport(cwd = process.cwd()) {
69541
69887
  configSources: [
69542
69888
  { path: userMcpPath, exists: existsSync56(userMcpPath) },
69543
69889
  { path: projectMcpPath, exists: existsSync56(projectMcpPath) },
69544
- { path: path86.join(homedir17(), ".zelari-code", "provider.json"), exists: existsSync56(path86.join(homedir17(), ".zelari-code", "provider.json")) },
69545
- { path: path86.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync56(path86.join(cwd, ".zelari", "AGENTS.md")) },
69546
- { path: path86.join(cwd, "AGENTS.md"), exists: existsSync56(path86.join(cwd, "AGENTS.md")) }
69890
+ { path: path89.join(homedir17(), ".zelari-code", "provider.json"), exists: existsSync56(path89.join(homedir17(), ".zelari-code", "provider.json")) },
69891
+ { path: path89.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync56(path89.join(cwd, ".zelari", "AGENTS.md")) },
69892
+ { path: path89.join(cwd, "AGENTS.md"), exists: existsSync56(path89.join(cwd, "AGENTS.md")) }
69547
69893
  ],
69548
69894
  skills: {
69549
69895
  total: snap.skills.length,
@@ -69583,8 +69929,8 @@ function listJsonFiles(dir) {
69583
69929
  }
69584
69930
  function findAgentsMd(cwd) {
69585
69931
  const candidates = [
69586
- path86.join(cwd, "AGENTS.md"),
69587
- path86.join(cwd, ".zelari", "AGENTS.md")
69932
+ path89.join(cwd, "AGENTS.md"),
69933
+ path89.join(cwd, ".zelari", "AGENTS.md")
69588
69934
  ];
69589
69935
  const found = [];
69590
69936
  for (const c of candidates) {
@@ -72709,6 +73055,7 @@ init_completionGate();
72709
73055
  init_verificationBridge();
72710
73056
  init_completionProof();
72711
73057
  init_nativeVerification();
73058
+ init_spineTelemetry();
72712
73059
 
72713
73060
  // src/cli/hooks/permissionPicker.ts
72714
73061
  init_toolPermissions();
@@ -72912,8 +73259,14 @@ function useChatTurn(params) {
72912
73259
  try {
72913
73260
  const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
72914
73261
  if (memoryFactory.isMemoryV2Enabled()) {
73262
+ const tuiSpineHolder = {
73263
+ get current() {
73264
+ return writerRef.current?.spine;
73265
+ }
73266
+ };
72915
73267
  memoryService = await memoryFactory.getMemoryService(process.cwd(), process.env, {
72916
- onWarning: (warning) => appendSystem(setMessages, warning, Date.now())
73268
+ onWarning: (warning) => appendSystem(setMessages, warning, Date.now()),
73269
+ onEvent: memorySinkFor(tuiSpineHolder)
72917
73270
  });
72918
73271
  memoryAutoWrite = memoryFactory.isMemoryAutoWriteEnabled();
72919
73272
  }
@@ -73880,8 +74233,14 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
73880
74233
  try {
73881
74234
  const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
73882
74235
  if (memoryFactory.isMemoryV2Enabled()) {
74236
+ const councilSpineHolder = {
74237
+ get current() {
74238
+ return writerRef.current?.spine;
74239
+ }
74240
+ };
73883
74241
  councilMemory = await memoryFactory.getMemoryService(process.cwd(), process.env, {
73884
- onWarning: (warning) => appendSystem(setMessages, warning, Date.now())
74242
+ onWarning: (warning) => appendSystem(setMessages, warning, Date.now()),
74243
+ onEvent: memorySinkFor(councilSpineHolder)
73885
74244
  });
73886
74245
  councilMemoryAutoWrite = memoryFactory.isMemoryAutoWriteEnabled();
73887
74246
  if (!overrides.ragContext) {
@@ -74490,7 +74849,12 @@ async function runZelariMissionInTui(userMessage, deps, emit) {
74490
74849
  userMessage,
74491
74850
  hasPlan: hasWorkspacePlan2(projectRoot)
74492
74851
  });
74493
- const memory = await getMemoryBackend2(projectRoot);
74852
+ const missionSpineHolder = {
74853
+ get current() {
74854
+ return deps.writerRef.current?.spine;
74855
+ }
74856
+ };
74857
+ const memory = await getMemoryBackend2(projectRoot, process.env, memorySinkFor(missionSpineHolder));
74494
74858
  const chairmanBudget = envNumber(process.env.ZELARI_MODE_MAX_TOOLS_LUCIFER, {
74495
74859
  default: 30,
74496
74860
  min: 1
@@ -75735,11 +76099,11 @@ function handleCacheStats(ctx) {
75735
76099
  init_messageHelpers();
75736
76100
  init_serviceFactory();
75737
76101
  import { promises as fs31 } from "node:fs";
75738
- import * as path66 from "node:path";
76102
+ import * as path67 from "node:path";
75739
76103
 
75740
76104
  // src/cli/memory/promotion.ts
75741
76105
  import { promises as fs30 } from "node:fs";
75742
- import * as path65 from "node:path";
76106
+ import * as path66 from "node:path";
75743
76107
  var START = "<!-- zelari:memory-promotions:start -->";
75744
76108
  var END = "<!-- zelari:memory-promotions:end -->";
75745
76109
  var DURABLE_KINDS = /* @__PURE__ */ new Set(["fact", "decision", "constraint", "preference", "procedure"]);
@@ -75750,13 +76114,13 @@ function lineFor(node) {
75750
76114
  }
75751
76115
  async function promoteMemoryToAgentsMd(projectRoot, node) {
75752
76116
  if (node.status !== "active") {
75753
- return { added: false, path: path65.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
76117
+ return { added: false, path: path66.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
75754
76118
  }
75755
76119
  if (!DURABLE_KINDS.has(node.kind)) {
75756
- return { added: false, path: path65.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
76120
+ return { added: false, path: path66.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
75757
76121
  }
75758
- const root = await fs30.realpath(projectRoot).catch(() => path65.resolve(projectRoot));
75759
- const target = path65.join(root, "AGENTS.md");
76122
+ const root = await fs30.realpath(projectRoot).catch(() => path66.resolve(projectRoot));
76123
+ const target = path66.join(root, "AGENTS.md");
75760
76124
  try {
75761
76125
  const stat7 = await fs30.lstat(target);
75762
76126
  if (stat7.isSymbolicLink() || !stat7.isFile()) throw new Error("AGENTS.md must be a regular project file.");
@@ -75821,22 +76185,22 @@ function sourceLine(source2) {
75821
76185
  return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
75822
76186
  }
75823
76187
  function isInside(root, target) {
75824
- const relative6 = path66.relative(root, target);
75825
- return relative6 === "" || !relative6.startsWith("..") && !path66.isAbsolute(relative6);
76188
+ const relative6 = path67.relative(root, target);
76189
+ return relative6 === "" || !relative6.startsWith("..") && !path67.isAbsolute(relative6);
75826
76190
  }
75827
76191
  async function safeExportPath(cwd, requested) {
75828
- const lexicalRoot = path66.resolve(cwd);
76192
+ const lexicalRoot = path67.resolve(cwd);
75829
76193
  const root = await fs31.realpath(lexicalRoot).catch(() => lexicalRoot);
75830
- const fallback = path66.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
75831
- const target = requested?.trim() ? path66.resolve(root, requested.trim()) : fallback;
76194
+ const fallback = path67.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
76195
+ const target = requested?.trim() ? path67.resolve(root, requested.trim()) : fallback;
75832
76196
  if (!isInside(root, target)) {
75833
76197
  throw new Error("Export path must stay inside the active project.");
75834
76198
  }
75835
- const parent = path66.dirname(target);
75836
- const relativeParent = path66.relative(root, parent);
76199
+ const parent = path67.dirname(target);
76200
+ const relativeParent = path67.relative(root, parent);
75837
76201
  let cursor = root;
75838
- for (const segment of relativeParent.split(path66.sep).filter(Boolean)) {
75839
- cursor = path66.join(cursor, segment);
76202
+ for (const segment of relativeParent.split(path67.sep).filter(Boolean)) {
76203
+ cursor = path67.join(cursor, segment);
75840
76204
  try {
75841
76205
  const stat7 = await fs31.lstat(cursor);
75842
76206
  if (stat7.isSymbolicLink()) {
@@ -76008,9 +76372,9 @@ ${message}` : message
76008
76372
  }
76009
76373
  case "export": {
76010
76374
  const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
76011
- await fs31.mkdir(path66.dirname(target), { recursive: true });
76012
- const root = await fs31.realpath(ctx.cwd).catch(() => path66.resolve(ctx.cwd));
76013
- const realParent = await fs31.realpath(path66.dirname(target));
76375
+ await fs31.mkdir(path67.dirname(target), { recursive: true });
76376
+ const root = await fs31.realpath(ctx.cwd).catch(() => path67.resolve(ctx.cwd));
76377
+ const realParent = await fs31.realpath(path67.dirname(target));
76014
76378
  if (!isInside(root, realParent)) {
76015
76379
  throw new Error("Export path resolves outside the active project.");
76016
76380
  }
@@ -76128,6 +76492,7 @@ init_graphMemory();
76128
76492
  init_executor();
76129
76493
  init_graphStatus();
76130
76494
  init_serviceFactory();
76495
+ init_spineTelemetry();
76131
76496
  async function handleKrakenGraph(ctx, prompt) {
76132
76497
  if (!isKrakenGraphEnabled()) {
76133
76498
  appendSystem(
@@ -76141,8 +76506,14 @@ async function handleKrakenGraph(ctx, prompt) {
76141
76506
  return;
76142
76507
  }
76143
76508
  appendSystem(ctx.setMessages, `[kraken] planning graph for: ${prompt.trim()}`);
76509
+ const tuiSpineHolder = {
76510
+ get current() {
76511
+ return ctx.writerRef?.current?.spine ?? void 0;
76512
+ }
76513
+ };
76144
76514
  const memory = isMemoryV2Enabled() ? await getMemoryService(ctx.cwd, process.env, {
76145
- onWarning: (warning) => appendSystem(ctx.setMessages, warning)
76515
+ onWarning: (warning) => appendSystem(ctx.setMessages, warning),
76516
+ onEvent: memorySinkFor(tuiSpineHolder)
76146
76517
  }) : void 0;
76147
76518
  const audit = new AuditLogger();
76148
76519
  const taskToolDeps = {
@@ -76206,7 +76577,7 @@ import { promises as fs35 } from "node:fs";
76206
76577
  init_zod();
76207
76578
  init_taskTool();
76208
76579
  import { promises as fs34 } from "node:fs";
76209
- import path71 from "node:path";
76580
+ import path72 from "node:path";
76210
76581
  import { randomBytes as randomBytes6 } from "node:crypto";
76211
76582
  var CsvFanoutArgsSchema = external_exports.object({
76212
76583
  csv_path: external_exports.string().min(1),
@@ -76300,8 +76671,8 @@ function resolveMaxConcurrency(env = process.env) {
76300
76671
  }
76301
76672
  async function runCsvFanout(args, deps, opts) {
76302
76673
  const start = Date.now();
76303
- const absCsv = path71.isAbsolute(args.csv_path) ? args.csv_path : path71.join(opts.parentCwd, args.csv_path);
76304
- const absOut = path71.isAbsolute(args.output_csv_path) ? args.output_csv_path : path71.join(opts.parentCwd, args.output_csv_path);
76674
+ const absCsv = path72.isAbsolute(args.csv_path) ? args.csv_path : path72.join(opts.parentCwd, args.csv_path);
76675
+ const absOut = path72.isAbsolute(args.output_csv_path) ? args.output_csv_path : path72.join(opts.parentCwd, args.output_csv_path);
76305
76676
  const { headers: headers2, rows } = await readCsv(absCsv);
76306
76677
  if (headers2.length === 0) {
76307
76678
  throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
@@ -76357,7 +76728,7 @@ async function runCsvFanout(args, deps, opts) {
76357
76728
  errored += 1;
76358
76729
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
76359
76730
  }
76360
- await fs34.mkdir(path71.dirname(absOut), { recursive: true });
76731
+ await fs34.mkdir(path72.dirname(absOut), { recursive: true });
76361
76732
  await queueWrite(serializeCsv(outHeaders, outputRecords));
76362
76733
  }
76363
76734
  }
@@ -76552,7 +76923,7 @@ function splitArgs(s) {
76552
76923
  // src/cli/slashHandlers/krakenWorkbench.ts
76553
76924
  init_messageHelpers();
76554
76925
  import { promises as fs36 } from "node:fs";
76555
- import path72 from "node:path";
76926
+ import path73 from "node:path";
76556
76927
 
76557
76928
  // src/cli/kraken/workbenchView.ts
76558
76929
  var EMPTY = {
@@ -76669,14 +77040,14 @@ function formatWorkbenchForTerminal(p3) {
76669
77040
 
76670
77041
  // src/cli/slashHandlers/krakenWorkbench.ts
76671
77042
  async function handleKrakenWorkbench(ctx) {
76672
- const dir = path72.join(ctx.cwd, ".zelari", "radio");
77043
+ const dir = path73.join(ctx.cwd, ".zelari", "radio");
76673
77044
  let latest = null;
76674
77045
  let latestMtime = 0;
76675
77046
  try {
76676
77047
  const files = await fs36.readdir(dir);
76677
77048
  for (const f of files) {
76678
77049
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
76679
- const full = path72.join(dir, f);
77050
+ const full = path73.join(dir, f);
76680
77051
  const stat7 = await fs36.stat(full);
76681
77052
  if (stat7.mtimeMs > latestMtime) {
76682
77053
  latestMtime = stat7.mtimeMs;
@@ -76693,10 +77064,10 @@ async function handleKrakenWorkbench(ctx) {
76693
77064
  const parsed = parseWorkbench(content);
76694
77065
  const rendered = formatWorkbenchForTerminal(parsed);
76695
77066
  if (!rendered.trim()) {
76696
- appendSystem(ctx.setMessages, `[kraken workbench] ${path72.basename(latest)}: (no nodes / no events yet)`);
77067
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path73.basename(latest)}: (no nodes / no events yet)`);
76697
77068
  return;
76698
77069
  }
76699
- appendSystem(ctx.setMessages, `[kraken workbench] ${path72.basename(latest)}:
77070
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path73.basename(latest)}:
76700
77071
  ${rendered}`);
76701
77072
  }
76702
77073
 
@@ -77003,15 +77374,15 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
77003
77374
  // src/cli/slashHandlers/promoteMember.ts
77004
77375
  init_messageHelpers();
77005
77376
  import { promises as fs37 } from "node:fs";
77006
- import path75 from "node:path";
77377
+ import path76 from "node:path";
77007
77378
  import os12 from "node:os";
77008
77379
  async function handlePromoteMember(ctx, memberId) {
77009
77380
  try {
77010
77381
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
77011
77382
  const { skill, markdown } = promoteMember2(memberId);
77012
- const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path75.join(os12.homedir(), ".tmp", "zelari-code", "skills");
77383
+ const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path76.join(os12.homedir(), ".tmp", "zelari-code", "skills");
77013
77384
  await fs37.mkdir(skillDir, { recursive: true });
77014
- const filePath = path75.join(skillDir, `${skill.id}.md`);
77385
+ const filePath = path76.join(skillDir, `${skill.id}.md`);
77015
77386
  await fs37.writeFile(filePath, markdown, "utf8");
77016
77387
  appendSystem(
77017
77388
  ctx.setMessages,
@@ -77029,24 +77400,24 @@ async function handlePromoteMember(ctx, memberId) {
77029
77400
 
77030
77401
  // src/cli/branchManager.ts
77031
77402
  import { promises as fs38, existsSync as existsSync48, readFileSync as readFileSync37, writeFileSync as writeFileSync23, mkdirSync as mkdirSync19, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
77032
- import path76 from "node:path";
77403
+ import path77 from "node:path";
77033
77404
  import os13 from "node:os";
77034
77405
  var META_FILENAME = "meta.json";
77035
77406
  var SESSIONS_SUBDIR = "sessions";
77036
77407
  function getBranchesBaseDir() {
77037
- return process.env.ANATHEMA_BRANCHES_DIR ?? path76.join(os13.homedir(), ".tmp", "zelari-code", "branches");
77408
+ return process.env.ANATHEMA_BRANCHES_DIR ?? path77.join(os13.homedir(), ".tmp", "zelari-code", "branches");
77038
77409
  }
77039
77410
  function getSessionsBaseDir() {
77040
- return process.env.ANATHEMA_SESSIONS_DIR ?? path76.join(os13.homedir(), ".tmp", "zelari-code", "sessions");
77411
+ return process.env.ANATHEMA_SESSIONS_DIR ?? path77.join(os13.homedir(), ".tmp", "zelari-code", "sessions");
77041
77412
  }
77042
77413
  function branchPathFor(name, baseDir) {
77043
- return path76.join(baseDir, name);
77414
+ return path77.join(baseDir, name);
77044
77415
  }
77045
77416
  function metaPathFor(name, baseDir) {
77046
- return path76.join(baseDir, name, META_FILENAME);
77417
+ return path77.join(baseDir, name, META_FILENAME);
77047
77418
  }
77048
77419
  function sessionsPathFor(name, baseDir) {
77049
- return path76.join(baseDir, name, SESSIONS_SUBDIR);
77420
+ return path77.join(baseDir, name, SESSIONS_SUBDIR);
77050
77421
  }
77051
77422
  function readBranchMeta(name, baseDir) {
77052
77423
  const metaPath = metaPathFor(name, baseDir);
@@ -77071,7 +77442,7 @@ function readBranchMeta(name, baseDir) {
77071
77442
  }
77072
77443
  function writeBranchMeta(name, baseDir, meta3) {
77073
77444
  const metaPath = metaPathFor(name, baseDir);
77074
- mkdirSync19(path76.dirname(metaPath), { recursive: true });
77445
+ mkdirSync19(path77.dirname(metaPath), { recursive: true });
77075
77446
  writeFileSync23(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
77076
77447
  }
77077
77448
  async function countSessions(name, baseDir) {
@@ -77122,14 +77493,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
77122
77493
  if (branchExists(name, baseDir)) {
77123
77494
  throw new BranchAlreadyExistsError(name);
77124
77495
  }
77125
- const sourcePath = path76.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
77496
+ const sourcePath = path77.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
77126
77497
  if (!existsSync48(sourcePath)) {
77127
77498
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
77128
77499
  }
77129
77500
  const branchPath = branchPathFor(name, baseDir);
77130
77501
  const branchSessionsPath = sessionsPathFor(name, baseDir);
77131
77502
  mkdirSync19(branchSessionsPath, { recursive: true });
77132
- const destPath = path76.join(branchSessionsPath, `${fromSessionId}.jsonl`);
77503
+ const destPath = path77.join(branchSessionsPath, `${fromSessionId}.jsonl`);
77133
77504
  await fs38.copyFile(sourcePath, destPath);
77134
77505
  const meta3 = {
77135
77506
  name,
@@ -77233,14 +77604,14 @@ async function handleBranchCheckout(ctx, branchName) {
77233
77604
  // src/cli/slashHandlers/workspace.ts
77234
77605
  init_messageHelpers();
77235
77606
  import { promises as fs39 } from "node:fs";
77236
- import path77 from "node:path";
77607
+ import path78 from "node:path";
77237
77608
  async function handleWorkspaceShow(ctx, what) {
77238
77609
  try {
77239
- const zelari = path77.join(process.cwd(), ".zelari");
77610
+ const zelari = path78.join(process.cwd(), ".zelari");
77240
77611
  let content;
77241
77612
  switch (what) {
77242
77613
  case "plan": {
77243
- const planPath = path77.join(zelari, "plan.md");
77614
+ const planPath = path78.join(zelari, "plan.md");
77244
77615
  try {
77245
77616
  content = await fs39.readFile(planPath, "utf-8");
77246
77617
  } catch {
@@ -77249,7 +77620,7 @@ async function handleWorkspaceShow(ctx, what) {
77249
77620
  break;
77250
77621
  }
77251
77622
  case "decisions": {
77252
- const decisionsDir = path77.join(zelari, "decisions");
77623
+ const decisionsDir = path78.join(zelari, "decisions");
77253
77624
  try {
77254
77625
  const files = (await fs39.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
77255
77626
  if (files.length === 0) {
@@ -77259,7 +77630,7 @@ async function handleWorkspaceShow(ctx, what) {
77259
77630
  `];
77260
77631
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
77261
77632
  for (const f of files) {
77262
- const raw = await fs39.readFile(path77.join(decisionsDir, f), "utf-8");
77633
+ const raw = await fs39.readFile(path78.join(decisionsDir, f), "utf-8");
77263
77634
  const { meta: meta3, body } = parseFrontmatter2(raw);
77264
77635
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
77265
77636
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -77272,7 +77643,7 @@ async function handleWorkspaceShow(ctx, what) {
77272
77643
  break;
77273
77644
  }
77274
77645
  case "risks": {
77275
- const risksPath = path77.join(zelari, "risks.md");
77646
+ const risksPath = path78.join(zelari, "risks.md");
77276
77647
  try {
77277
77648
  content = await fs39.readFile(risksPath, "utf-8");
77278
77649
  } catch {
@@ -77281,7 +77652,7 @@ async function handleWorkspaceShow(ctx, what) {
77281
77652
  break;
77282
77653
  }
77283
77654
  case "agents": {
77284
- const agentsPath = path77.join(process.cwd(), "AGENTS.MD");
77655
+ const agentsPath = path78.join(process.cwd(), "AGENTS.MD");
77285
77656
  try {
77286
77657
  content = await fs39.readFile(agentsPath, "utf-8");
77287
77658
  } catch {
@@ -77290,7 +77661,7 @@ async function handleWorkspaceShow(ctx, what) {
77290
77661
  break;
77291
77662
  }
77292
77663
  case "docs": {
77293
- const docsDir = path77.join(zelari, "docs");
77664
+ const docsDir = path78.join(zelari, "docs");
77294
77665
  try {
77295
77666
  const files = (await fs39.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
77296
77667
  content = files.length ? `# Docs (${files.length})
@@ -77332,7 +77703,7 @@ async function handleWorkspaceReset(ctx, force) {
77332
77703
  return;
77333
77704
  }
77334
77705
  try {
77335
- const target = path77.join(process.cwd(), ".zelari");
77706
+ const target = path78.join(process.cwd(), ".zelari");
77336
77707
  await fs39.rm(target, { recursive: true, force: true });
77337
77708
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
77338
77709
  } catch (err) {
@@ -77344,7 +77715,7 @@ async function handleWorkspaceReset(ctx, force) {
77344
77715
  init_provider2();
77345
77716
 
77346
77717
  // src/cli/slashHandlers/skills.ts
77347
- import path78 from "node:path";
77718
+ import path79 from "node:path";
77348
77719
  import os14 from "node:os";
77349
77720
 
77350
77721
  // src/cli/skillHistory.ts
@@ -77473,7 +77844,7 @@ function handleSkillPicker(ctx, skills, openPicker, fallbackMessage) {
77473
77844
  });
77474
77845
  }
77475
77846
  async function handleSkillStats(ctx, skillId) {
77476
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path78.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
77847
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path79.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
77477
77848
  try {
77478
77849
  const records = await readSkillHistory(historyFile);
77479
77850
  const stats = getSkillStats(records, skillId);
@@ -77489,7 +77860,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
77489
77860
  appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
77490
77861
  return;
77491
77862
  }
77492
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path78.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
77863
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path79.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
77493
77864
  try {
77494
77865
  const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
77495
77866
  appendSystem(ctx.setMessages, formatted);
@@ -77945,7 +78316,10 @@ function useSlashDispatch(params) {
77945
78316
  }
77946
78317
  if (result.kind === "kraken_graph") {
77947
78318
  const sid = (sessionId2 || "default").trim();
77948
- await handleKrakenGraph({ setMessages, cwd: process.cwd(), sessionId: sid }, result.graphPrompt ?? "");
78319
+ await handleKrakenGraph(
78320
+ { setMessages, cwd: process.cwd(), sessionId: sid, writerRef: params.writerRef },
78321
+ result.graphPrompt ?? ""
78322
+ );
77949
78323
  return;
77950
78324
  }
77951
78325
  if (result.kind === "kraken_fanout") {
@@ -78282,6 +78656,9 @@ function App() {
78282
78656
  sessionId: session.sessionId,
78283
78657
  messages: session.messages,
78284
78658
  setMessages: session.setMessages,
78659
+ // W2: same writer ref passed to useChatTurn — lets /kraken graph project
78660
+ // memory events onto the session spine mirror.
78661
+ writerRef: session.writerRef,
78285
78662
  setInput,
78286
78663
  setBusy,
78287
78664
  setSessionId: session.setSessionId,
@@ -79184,8 +79561,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
79184
79561
  let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
79185
79562
  if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
79186
79563
  try {
79187
- const path87 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
79188
- name = path87 && /^[a-z0-9]/.test(path87) ? path87 : "imported-skill";
79564
+ const path90 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
79565
+ name = path90 && /^[a-z0-9]/.test(path90) ? path90 : "imported-skill";
79189
79566
  } catch {
79190
79567
  name = "imported-skill";
79191
79568
  }