zelari-code 2.16.5 → 2.18.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 (42) hide show
  1. package/dist/cli/app.js +3 -0
  2. package/dist/cli/app.js.map +1 -1
  3. package/dist/cli/commands/inspectSession.js +86 -0
  4. package/dist/cli/commands/inspectSession.js.map +1 -0
  5. package/dist/cli/companion/serve.js +29 -0
  6. package/dist/cli/companion/serve.js.map +1 -1
  7. package/dist/cli/harnessState.js +240 -0
  8. package/dist/cli/harnessState.js.map +1 -0
  9. package/dist/cli/headless/harnessStateEmit.js +38 -0
  10. package/dist/cli/headless/harnessStateEmit.js.map +1 -0
  11. package/dist/cli/headless/policyGate.js +6 -3
  12. package/dist/cli/headless/policyGate.js.map +1 -1
  13. package/dist/cli/headless/runOneTurn.js +29 -5
  14. package/dist/cli/headless/runOneTurn.js.map +1 -1
  15. package/dist/cli/headless.js +20 -9
  16. package/dist/cli/headless.js.map +1 -1
  17. package/dist/cli/hooks/useChatTurn.js +25 -1
  18. package/dist/cli/hooks/useChatTurn.js.map +1 -1
  19. package/dist/cli/hooks/useSlashDispatch.js +1 -1
  20. package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
  21. package/dist/cli/kraken/verificationBridge.js +27 -4
  22. package/dist/cli/kraken/verificationBridge.js.map +1 -1
  23. package/dist/cli/lsp/manager.js +31 -11
  24. package/dist/cli/lsp/manager.js.map +1 -1
  25. package/dist/cli/main.bundled.js +1030 -489
  26. package/dist/cli/main.bundled.js.map +4 -4
  27. package/dist/cli/main.js +15 -0
  28. package/dist/cli/main.js.map +1 -1
  29. package/dist/cli/memory/fileBackend.js +7 -3
  30. package/dist/cli/memory/fileBackend.js.map +1 -1
  31. package/dist/cli/memory/spineTelemetry.js +49 -0
  32. package/dist/cli/memory/spineTelemetry.js.map +1 -0
  33. package/dist/cli/runHeadless.js +171 -30
  34. package/dist/cli/runHeadless.js.map +1 -1
  35. package/dist/cli/safety/jails/win32.js.map +1 -1
  36. package/dist/cli/serve/harnessServer.js +20 -1
  37. package/dist/cli/serve/harnessServer.js.map +1 -1
  38. package/dist/cli/sessionSpine.js +22 -13
  39. package/dist/cli/sessionSpine.js.map +1 -1
  40. package/dist/cli/slashHandlers/krakenGraph.js +11 -0
  41. package/dist/cli/slashHandlers/krakenGraph.js.map +1 -1
  42. 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, path91) {
3292
+ if (!path91)
3293
3293
  return obj;
3294
- return path87.reduce((acc, key) => acc?.[key], obj);
3294
+ return path91.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(path91, 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(path91);
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, path91 = []) => {
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 }, [...path91, ...issue2.path]));
3848
3848
  } else if (issue2.code === "invalid_key") {
3849
- processError({ issues: issue2.issues }, [...path87, ...issue2.path]);
3849
+ processError({ issues: issue2.issues }, [...path91, ...issue2.path]);
3850
3850
  } else if (issue2.code === "invalid_element") {
3851
- processError({ issues: issue2.issues }, [...path87, ...issue2.path]);
3851
+ processError({ issues: issue2.issues }, [...path91, ...issue2.path]);
3852
3852
  } else {
3853
- const fullpath = [...path87, ...issue2.path];
3853
+ const fullpath = [...path91, ...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, path91 = []) => {
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 }, [...path91, ...issue2.path]));
3885
3885
  } else if (issue2.code === "invalid_key") {
3886
- processError({ issues: issue2.issues }, [...path87, ...issue2.path]);
3886
+ processError({ issues: issue2.issues }, [...path91, ...issue2.path]);
3887
3887
  } else if (issue2.code === "invalid_element") {
3888
- processError({ issues: issue2.issues }, [...path87, ...issue2.path]);
3888
+ processError({ issues: issue2.issues }, [...path91, ...issue2.path]);
3889
3889
  } else {
3890
- const fullpath = [...path87, ...issue2.path];
3890
+ const fullpath = [...path91, ...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 path91 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
3923
+ for (const seg of path91) {
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 path91 = ref.slice(1).split("/").filter(Boolean);
17427
+ if (path91.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 (path91[0] === defsKey) {
17432
+ const key = path91[1];
17433
17433
  if (!key || !ctx.defs[key]) {
17434
17434
  throw new Error(`Reference not found: ${ref}`);
17435
17435
  }
@@ -18777,11 +18777,18 @@ function filterByInclude(entries, include) {
18777
18777
  if (include.length === 0 || include.length === 1 && include[0] === "*") {
18778
18778
  return entries.filter((e) => e.type === "file");
18779
18779
  }
18780
- const regexes = include.map(globToRegex);
18780
+ const pathRegexes = [];
18781
+ const baseRegexes = [];
18782
+ for (const g of include) {
18783
+ (g.includes("/") || g.includes("**") ? pathRegexes : baseRegexes).push(globToRegex(g));
18784
+ }
18781
18785
  return entries.filter((e) => {
18782
18786
  if (e.type !== "file")
18783
18787
  return false;
18784
- return regexes.some((re) => re.test(e.name));
18788
+ if (pathRegexes.some((re) => re.test(e.name)))
18789
+ return true;
18790
+ const base2 = e.name.slice(e.name.lastIndexOf("/") + 1);
18791
+ return baseRegexes.some((re) => re.test(base2));
18785
18792
  });
18786
18793
  }
18787
18794
  var REGEX_ESCAPE, DEFAULT_EXCLUDES;
@@ -18828,8 +18835,8 @@ function coerceStringList(value, fallback) {
18828
18835
  }
18829
18836
  return fallback;
18830
18837
  }
18831
- function hasRecursiveGlob(include) {
18832
- return include.some((g) => g.includes("**"));
18838
+ function hasPathAnchoredGlob(include) {
18839
+ return include.some((g) => g.includes("/") || g.includes("**"));
18833
18840
  }
18834
18841
  function scopeWarnings(allEntries, include, matched) {
18835
18842
  const warnings = [];
@@ -18837,15 +18844,17 @@ function scopeWarnings(allEntries, include, matched) {
18837
18844
  if (filesWalked === 0)
18838
18845
  return warnings;
18839
18846
  if (matched === 0) {
18840
- warnings.push(`SEARCH_EMPTY_SCOPE: include globs matched 0 of ${filesWalked} files walked \u2014 '*' matches only one path segment; use '**/<glob>' for recursive matching. Do not interpret this result as "pattern not found".`);
18847
+ const cause = hasPathAnchoredGlob(include) ? `path-anchored globs (with '/') match the relative path at exactly that level; use '**/<glob>' for recursive matching` : `flat globs ('*.ts') match the basename at any depth, so no file with these names/extensions exists in the walked tree`;
18848
+ warnings.push(`SEARCH_EMPTY_SCOPE: include globs matched 0 of ${filesWalked} files walked \u2014 ${cause}. Do not interpret this result as "pattern not found".`);
18841
18849
  return warnings;
18842
18850
  }
18843
- if (hasRecursiveGlob(include) || matched >= filesWalked)
18851
+ if (!hasPathAnchoredGlob(include) || matched >= filesWalked)
18844
18852
  return warnings;
18845
- const recursiveRegexes = compileGlobs(include.map((g) => `**/${g}`));
18853
+ const anchored = include.filter((g) => g.includes("/") || g.includes("**"));
18854
+ const recursiveRegexes = compileGlobs(anchored.map((g) => `**/${g}`));
18846
18855
  const wouldMatch = allEntries.filter((e) => e.type === "file" && matchesAnyCompiled(e.name, recursiveRegexes)).length;
18847
18856
  if (wouldMatch > matched) {
18848
- warnings.push(`include globs matched ${matched} of ${filesWalked} files walked \u2014 '*' matches only one path segment; a '**/*.ts'-style recursive glob would have matched ${wouldMatch - matched} more file(s) in subdirectories`);
18857
+ warnings.push(`include globs matched ${matched} of ${filesWalked} files walked \u2014 a path-anchored glob ('${anchored[0]}') matches only that exact level; a '**/${anchored[0]}'-style recursive glob would have matched ${wouldMatch - matched} more file(s) in subdirectories`);
18849
18858
  }
18850
18859
  return warnings;
18851
18860
  }
@@ -18912,7 +18921,10 @@ var init_search = __esm({
18912
18921
  /**
18913
18922
  * Glob pattern(s) to INCLUDE when path is a directory.
18914
18923
  * Accepts a string OR string[] (models often emit a bare string).
18915
- * Default ['*'] = all files. Ignored when path is a file.
18924
+ * A glob without '/' (e.g. '*.ts') matches the file basename at any depth
18925
+ * (grep --include style); a glob with '/' (e.g. 'src/*.ts') matches the
18926
+ * relative path at exactly that level. Default ['*'] = all files.
18927
+ * Ignored when path is a file.
18916
18928
  */
18917
18929
  include: stringOrStringArray.optional().default(["*"]),
18918
18930
  /**
@@ -18925,7 +18937,7 @@ var init_search = __esm({
18925
18937
  });
18926
18938
  grepContentTool = {
18927
18939
  name: "grep_content",
18928
- description: 'Regex search for content in a file OR recursively in a directory. When path is a directory, include/exclude globs filter which files are searched (default: all files, excluding node_modules/dist/.git/etc.). Glob semantics: "*" matches ONE path segment only ("*.ts" does NOT match "sub/file.ts"); use "**" for recursive matching ("**/*.ts" matches at any depth). include/exclude accept a single glob string (e.g. "*.ts") OR an array of globs. Returns matches with line numbers and context, plus filesWalked/filesInTree counts and a warning when the include globs matched suspiciously few files.',
18940
+ description: `Regex search for content in a file OR recursively in a directory. When path is a directory, include/exclude globs filter which files are searched (default: all files, excluding node_modules/dist/.git/etc.). Glob semantics (grep --include style): a glob without '/' (e.g. "*.md") matches the file basename at ANY depth; a glob with '/' (e.g. "src/*.ts") matches the relative path at exactly that level; "**" is explicit recursion ("**/*.ts" matches at any depth, same as the bare form). include/exclude accept a single glob string (e.g. "*.ts") OR an array of globs. Returns matches with line numbers and context, plus filesWalked/filesInTree counts and a warning when the include globs matched suspiciously few files.`,
18929
18941
  permissions: ["read"],
18930
18942
  sideEffect: "none",
18931
18943
  timeoutMs: 3e4,
@@ -19875,11 +19887,11 @@ var init_tools = __esm({
19875
19887
  if (!ctx.addDocument)
19876
19888
  return "Knowledge vault tool not available.";
19877
19889
  const title = args["title"] || "New Document";
19878
- const path87 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
19890
+ const path91 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
19879
19891
  const content = args["content"] || "";
19880
19892
  const tags = args["tags"] || [];
19881
19893
  ctx.addDocument({
19882
- path: path87,
19894
+ path: path91,
19883
19895
  title,
19884
19896
  content,
19885
19897
  format: "markdown",
@@ -19888,7 +19900,7 @@ var init_tools = __esm({
19888
19900
  workspaceId: ctx.workspaceId
19889
19901
  });
19890
19902
  ctx.addActivity("vault", "created document", title);
19891
- return `Document "${title}" created at "${path87}".`;
19903
+ return `Document "${title}" created at "${path91}".`;
19892
19904
  }
19893
19905
  }
19894
19906
  ];
@@ -23328,7 +23340,7 @@ function extractToolObjects(text) {
23328
23340
  }
23329
23341
  return out;
23330
23342
  }
23331
- var BUILD_LIVENESS_RECOVERY_PROMPT, AgentHarness, DOOM_LOOP_THRESHOLD;
23343
+ var TOOL_CALL_TRUNCATED_RECOVERY_MARKER, TOOL_CALL_TRUNCATED_RECOVERY_USER, BUILD_LIVENESS_RECOVERY_PROMPT, AgentHarness, DOOM_LOOP_THRESHOLD;
23332
23344
  var init_AgentHarness = __esm({
23333
23345
  "packages/core/dist/core/AgentHarness.js"() {
23334
23346
  "use strict";
@@ -23340,6 +23352,8 @@ var init_AgentHarness = __esm({
23340
23352
  init_textLoopDetect();
23341
23353
  init_ObserverBus();
23342
23354
  init_textLoopDetect();
23355
+ TOOL_CALL_TRUNCATED_RECOVERY_MARKER = "[harness] Previous tool call was truncated";
23356
+ TOOL_CALL_TRUNCATED_RECOVERY_USER = `${TOOL_CALL_TRUNCATED_RECOVERY_MARKER} by the provider before completion (finish_reason=tool_calls but no complete tool_call arrived). Retry with a shorter payload or split the work into smaller tool calls.`;
23343
23357
  BUILD_LIVENESS_RECOVERY_PROMPT = "[build-liveness] The requested task requires an on-disk implementation, but no successful project mutation has occurred yet. Continue working. Inspect only as needed, then make the required change with an available mutating tool. Do not merely describe a patch or claim completion.";
23344
23358
  AgentHarness = class {
23345
23359
  config;
@@ -23610,10 +23624,10 @@ ${fromRunCache}`,
23610
23624
  }
23611
23625
  const existing = inflight.get(callKey);
23612
23626
  if (existing) {
23613
- const shared2 = await existing;
23627
+ const shared = await existing;
23614
23628
  return {
23615
23629
  content: `[duplicate call \u2014 result repeated; do not call this tool again with the same arguments]
23616
- ${shared2.content}`,
23630
+ ${shared.content}`,
23617
23631
  isError: false,
23618
23632
  durationMs: 0
23619
23633
  };
@@ -24343,7 +24357,8 @@ ${cached2}`
24343
24357
  if (turnToolResults.length > 0) {
24344
24358
  finishRef.value = "tool_calls";
24345
24359
  }
24346
- if (finishRef.value === "tool_calls" && turnToolCalls.length === 0 && turnToolResults.length === 0) {
24360
+ const truncatedToolCall = finishRef.value === "tool_calls" && turnToolCalls.length === 0 && turnToolResults.length === 0;
24361
+ if (truncatedToolCall) {
24347
24362
  const truncErr = createBrainEvent("error", this.sessionId, {
24348
24363
  severity: "recoverable",
24349
24364
  message: "Tool call was truncated (finish_reason=tool_calls but no complete tool_call received). The provider cut the response mid-arguments. Retry with a shorter payload or split the work.",
@@ -24383,6 +24398,15 @@ ${cached2}`
24383
24398
  content: tr.content
24384
24399
  });
24385
24400
  }
24401
+ if (truncatedToolCall) {
24402
+ const last = this.config.messages[this.config.messages.length - 1];
24403
+ if (!(last?.role === "user" && typeof last.content === "string" && last.content.includes(TOOL_CALL_TRUNCATED_RECOVERY_MARKER))) {
24404
+ this.config.messages.push({
24405
+ role: "user",
24406
+ content: TOOL_CALL_TRUNCATED_RECOVERY_USER
24407
+ });
24408
+ }
24409
+ }
24386
24410
  break;
24387
24411
  } else if (delta.kind === "error") {
24388
24412
  finishRef.providerError = true;
@@ -25125,7 +25149,7 @@ var init_appServer = __esm({
25125
25149
  services = factory(root);
25126
25150
  this.workspaceServices.set(root, services);
25127
25151
  }
25128
- const shared2 = services;
25152
+ const shared = services;
25129
25153
  const server = this;
25130
25154
  const count = this.sessionCounts.get(root) ?? 0;
25131
25155
  this.sessionCounts.set(root, count + 1);
@@ -25133,13 +25157,13 @@ var init_appServer = __esm({
25133
25157
  const session = {
25134
25158
  id: id3,
25135
25159
  workspaceRoot: root,
25136
- services: shared2,
25160
+ services: shared,
25137
25161
  runTurn(input) {
25138
25162
  const deps = {
25139
25163
  session: { id: id3, workspaceRoot: root },
25140
25164
  services: {
25141
- ...shared2,
25142
- completionProofWriter: server.trackProofWriter(shared2.completionProofWriter)
25165
+ ...shared,
25166
+ completionProofWriter: server.trackProofWriter(shared.completionProofWriter)
25143
25167
  }
25144
25168
  };
25145
25169
  return runTurn(input, deps);
@@ -25150,10 +25174,10 @@ var init_appServer = __esm({
25150
25174
  server.sessionCounts.set(root, remaining);
25151
25175
  if (remaining <= 0) {
25152
25176
  server.sessionCounts.delete(root);
25153
- const shared3 = server.workspaceServices.get(root);
25177
+ const shared2 = server.workspaceServices.get(root);
25154
25178
  server.workspaceServices.delete(root);
25155
25179
  try {
25156
- shared3?.lspManager?.dispose();
25180
+ shared2?.lspManager?.dispose();
25157
25181
  } catch {
25158
25182
  }
25159
25183
  }
@@ -25317,6 +25341,8 @@ __export(harness_exports, {
25317
25341
  SessionJsonlWriter: () => SessionJsonlWriter,
25318
25342
  TEXT_LOOP_RECOVERY_SYSTEM: () => TEXT_LOOP_RECOVERY_SYSTEM,
25319
25343
  TEXT_LOOP_RECOVERY_USER_PROMPT: () => TEXT_LOOP_RECOVERY_USER_PROMPT,
25344
+ TOOL_CALL_TRUNCATED_RECOVERY_MARKER: () => TOOL_CALL_TRUNCATED_RECOVERY_MARKER,
25345
+ TOOL_CALL_TRUNCATED_RECOVERY_USER: () => TOOL_CALL_TRUNCATED_RECOVERY_USER,
25320
25346
  canonicalTools: () => canonicalTools,
25321
25347
  collapseLoopedAssistantText: () => collapseLoopedAssistantText,
25322
25348
  compareReplayPrefix: () => compareReplayPrefix,
@@ -26138,11 +26164,11 @@ var init_synthesisAudit = __esm({
26138
26164
  import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
26139
26165
  import { join as join4 } from "node:path";
26140
26166
  function loadNfrSpec(zelariRoot) {
26141
- const path87 = join4(zelariRoot, "nfr-spec.json");
26142
- if (!existsSync7(path87))
26167
+ const path91 = join4(zelariRoot, "nfr-spec.json");
26168
+ if (!existsSync7(path91))
26143
26169
  return null;
26144
26170
  try {
26145
- const raw = JSON.parse(readFileSync7(path87, "utf8"));
26171
+ const raw = JSON.parse(readFileSync7(path91, "utf8"));
26146
26172
  if (raw.version !== 1 || !Array.isArray(raw.targets))
26147
26173
  return null;
26148
26174
  return raw;
@@ -28448,9 +28474,9 @@ var init_types5 = __esm({
28448
28474
  import { readFileSync as readFileSync12 } from "node:fs";
28449
28475
  import { join as join10 } from "node:path";
28450
28476
  function readLessonsDeduped(zelariRoot) {
28451
- const path87 = join10(zelariRoot, LESSONS_FILE);
28477
+ const path91 = join10(zelariRoot, LESSONS_FILE);
28452
28478
  try {
28453
- const raw = readFileSync12(path87, "utf8");
28479
+ const raw = readFileSync12(path91, "utf8");
28454
28480
  const byId = /* @__PURE__ */ new Map();
28455
28481
  for (const line of raw.split(/\r?\n/)) {
28456
28482
  if (!line.trim())
@@ -28551,8 +28577,8 @@ function keywordsFrom(check2, signature) {
28551
28577
  return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
28552
28578
  }
28553
28579
  function writeLesson(zelariRoot, lesson) {
28554
- const path87 = join11(zelariRoot, LESSONS_FILE);
28555
- appendFileSync(path87, `${JSON.stringify(lesson)}
28580
+ const path91 = join11(zelariRoot, LESSONS_FILE);
28581
+ appendFileSync(path91, `${JSON.stringify(lesson)}
28556
28582
  `, "utf8");
28557
28583
  }
28558
28584
  function findSimilar(lessons, signature) {
@@ -30515,9 +30541,9 @@ function findCycle(nodes) {
30515
30541
  if (color.get(start) !== WHITE)
30516
30542
  continue;
30517
30543
  const stack = [[start, 0]];
30518
- const path87 = [];
30544
+ const path91 = [];
30519
30545
  color.set(start, GRAY);
30520
- path87.push(start);
30546
+ path91.push(start);
30521
30547
  while (stack.length > 0) {
30522
30548
  const top = stack[stack.length - 1];
30523
30549
  const [id3, idx] = top;
@@ -30530,17 +30556,17 @@ function findCycle(nodes) {
30530
30556
  continue;
30531
30557
  const c = color.get(dep);
30532
30558
  if (c === GRAY) {
30533
- const at = path87.indexOf(dep);
30534
- return [...path87.slice(at), dep];
30559
+ const at = path91.indexOf(dep);
30560
+ return [...path91.slice(at), dep];
30535
30561
  }
30536
30562
  if (c === WHITE) {
30537
30563
  color.set(dep, GRAY);
30538
- path87.push(dep);
30564
+ path91.push(dep);
30539
30565
  stack.push([dep, 0]);
30540
30566
  }
30541
30567
  } else {
30542
30568
  color.set(id3, BLACK);
30543
- path87.pop();
30569
+ path91.pop();
30544
30570
  stack.pop();
30545
30571
  }
30546
30572
  }
@@ -31460,8 +31486,8 @@ var init_runner = __esm({
31460
31486
  failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
31461
31487
  pending: []
31462
31488
  };
31463
- const path87 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
31464
- this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path87}`);
31489
+ const path91 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
31490
+ this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path91}`);
31465
31491
  return snapshot;
31466
31492
  }
31467
31493
  callLog(msg, data) {
@@ -31553,16 +31579,12 @@ var init_types9 = __esm({
31553
31579
  // once at session start / manifest change. State-only (never model-surface):
31554
31580
  // data = {manifest, manifestHash}. Schema review per ADR-0021.
31555
31581
  "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
31582
  "user.message",
31560
31583
  "assistant.message",
31561
31584
  "tool.call",
31562
31585
  "tool.result",
31563
31586
  // 2.x B (crash-safe recovery): dangling call classified. State-only.
31564
31587
  "tool.interrupted",
31565
- "context.injected",
31566
31588
  "session.compacted",
31567
31589
  "task.created",
31568
31590
  "task.updated",
@@ -31571,7 +31593,6 @@ var init_types9 = __esm({
31571
31593
  // State-only: compaction projects it into CompactionStateSnapshot.
31572
31594
  "task.contract",
31573
31595
  "task.contract_updated",
31574
- "kraken.task",
31575
31596
  "council.member",
31576
31597
  "mission.phase",
31577
31598
  "mission.replan",
@@ -31592,6 +31613,15 @@ var init_types9 = __esm({
31592
31613
  "resource.reserve_entered",
31593
31614
  // 2.6.1 (closure plan §9): hard-limit overrun telemetry — state-only.
31594
31615
  "resource.overrun",
31616
+ // ADR-0024 v1.1 (amended 2026-08-30): per-node ENVELOPE for kraken-graph
31617
+ // runs — written by the HOST (the sole spine writer) around the executor's
31618
+ // tentacle-run seam. State-only (never model-surface): data = {nodeId,
31619
+ // agent, graphId?, ok?, cancelled?, durationMs?}; node labels, prompts and
31620
+ // turn output stay on the kraken radio JSONL. One pair per attempt.
31621
+ // ADR-0021 schema review: additive state kinds need no SCHEMA_VERSION bump —
31622
+ // older readers skip them via the tolerant replay (schema-mismatch issues).
31623
+ "graph.node_started",
31624
+ "graph.node_ended",
31595
31625
  "note"
31596
31626
  ];
31597
31627
  SessionEventEnvelopeSchema = external_exports.object({
@@ -33917,16 +33947,16 @@ function runRetentionFromEnv() {
33917
33947
  maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
33918
33948
  };
33919
33949
  }
33920
- async function dirSize(path87) {
33950
+ async function dirSize(path91) {
33921
33951
  let total = 0;
33922
33952
  let entries;
33923
33953
  try {
33924
- entries = await readdir(path87, { withFileTypes: true });
33954
+ entries = await readdir(path91, { withFileTypes: true });
33925
33955
  } catch {
33926
33956
  return 0;
33927
33957
  }
33928
33958
  for (const entry of entries) {
33929
- const child = join13(path87, entry.name);
33959
+ const child = join13(path91, entry.name);
33930
33960
  if (entry.isDirectory())
33931
33961
  total += await dirSize(child);
33932
33962
  else {
@@ -33953,19 +33983,19 @@ async function enforceRunRetention(runsDir, options = {}) {
33953
33983
  for (const entry of entries) {
33954
33984
  if (!entry.isDirectory())
33955
33985
  continue;
33956
- const path87 = join13(runsDir, entry.name);
33986
+ const path91 = join13(runsDir, entry.name);
33957
33987
  let startedAt = 0;
33958
33988
  let endedAt;
33959
33989
  let completed = false;
33960
33990
  try {
33961
- const manifest = JSON.parse(await readFile(join13(path87, "manifest.json"), "utf8"));
33991
+ const manifest = JSON.parse(await readFile(join13(path91, "manifest.json"), "utf8"));
33962
33992
  startedAt = manifest.startedAt ?? 0;
33963
33993
  endedAt = manifest.endedAt;
33964
33994
  completed = Boolean(endedAt) && manifest.status !== "running";
33965
33995
  } catch {
33966
33996
  completed = false;
33967
33997
  }
33968
- infos.push({ name: entry.name, path: path87, startedAt, endedAt, completed, bytes: await dirSize(path87) });
33998
+ infos.push({ name: entry.name, path: path91, startedAt, endedAt, completed, bytes: await dirSize(path91) });
33969
33999
  }
33970
34000
  const remove = async (info) => {
33971
34001
  await rm(info.path, { recursive: true, force: true });
@@ -34737,12 +34767,12 @@ var init_engine = __esm({
34737
34767
  * content digest) and the returned ref carries the event seq when the
34738
34768
  * emitter resolved one.
34739
34769
  */
34740
- async fsEvidence(observation, path87, sha256, content, extra = {}) {
34770
+ async fsEvidence(observation, path91, sha256, content, extra = {}) {
34741
34771
  const digest = sha256 && content !== void 0 ? sha256(content) : void 0;
34742
- const seq = await this.emitEvidence({ observation, path: path87, ...extra, ...digest ? { digest } : {} });
34772
+ const seq = await this.emitEvidence({ observation, path: path91, ...extra, ...digest ? { digest } : {} });
34743
34773
  return {
34744
34774
  tier: "fs-observation",
34745
- ref: path87,
34775
+ ref: path91,
34746
34776
  capturedAt: Date.now(),
34747
34777
  ...digest ? { digest } : {},
34748
34778
  ...seq !== void 0 ? { seq } : {}
@@ -35782,6 +35812,8 @@ __export(dist_exports, {
35782
35812
  TEXT_LOOP_RECOVERY_SYSTEM: () => TEXT_LOOP_RECOVERY_SYSTEM,
35783
35813
  TEXT_LOOP_RECOVERY_USER_PROMPT: () => TEXT_LOOP_RECOVERY_USER_PROMPT,
35784
35814
  TIER_RANK: () => TIER_RANK,
35815
+ TOOL_CALL_TRUNCATED_RECOVERY_MARKER: () => TOOL_CALL_TRUNCATED_RECOVERY_MARKER,
35816
+ TOOL_CALL_TRUNCATED_RECOVERY_USER: () => TOOL_CALL_TRUNCATED_RECOVERY_USER,
35785
35817
  TOOL_DEFINITIONS: () => TOOL_DEFINITIONS,
35786
35818
  TOOL_USE_PROTOCOL_DIRECTIVE: () => TOOL_USE_PROTOCOL_DIRECTIVE,
35787
35819
  TURN_COMPLETION_MODULE: () => TURN_COMPLETION_MODULE,
@@ -37083,6 +37115,15 @@ function mapBrainEventToSpine(ev) {
37083
37115
  ...ev.memberName ? { member: ev.memberName } : {}
37084
37116
  }
37085
37117
  };
37118
+ case "error":
37119
+ if (ev.code === "tool_call_truncated") {
37120
+ return {
37121
+ kind: "user.message",
37122
+ actor: ACTOR_USER,
37123
+ data: { text: TOOL_CALL_TRUNCATED_RECOVERY_USER }
37124
+ };
37125
+ }
37126
+ return null;
37086
37127
  default:
37087
37128
  return null;
37088
37129
  }
@@ -37126,15 +37167,8 @@ async function noteHarnessLifecycle(spine, sessionId2, profileId, budget, baseDi
37126
37167
  resourcePolicy: budget.policy
37127
37168
  });
37128
37169
  if (spine.resumedFromSeq !== void 0 && spine.resumedFromSeq > 0) {
37129
- const original = await lastHarnessManifestHash(sessionId2, baseDir);
37130
- if (original === null) {
37170
+ if (await lastHarnessManifestHash(sessionId2, baseDir) === null) {
37131
37171
  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
37172
  }
37139
37173
  } else {
37140
37174
  spine.harnessManifest(manifest, manifestHash);
@@ -37146,6 +37180,7 @@ var MAX_STREAM_BUFFERS, SessionSpineMirror, SpineMirroringWriter;
37146
37180
  var init_sessionSpine = __esm({
37147
37181
  "src/cli/sessionSpine.ts"() {
37148
37182
  "use strict";
37183
+ init_harness();
37149
37184
  init_session();
37150
37185
  init_session();
37151
37186
  init_verification2();
@@ -37892,9 +37927,9 @@ function spillToolOutput(fullText, meta3) {
37892
37927
  const rnd = randomBytes3(3).toString("hex");
37893
37928
  const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
37894
37929
  const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
37895
- const path87 = join14(dir, file2);
37896
- writeFileSync11(path87, fullText, "utf8");
37897
- return path87;
37930
+ const path91 = join14(dir, file2);
37931
+ writeFileSync11(path91, fullText, "utf8");
37932
+ return path91;
37898
37933
  } catch {
37899
37934
  return null;
37900
37935
  }
@@ -37940,10 +37975,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
37940
37975
  ${tail2}`;
37941
37976
  }
37942
37977
  if (doSpill) {
37943
- const path87 = spillToolOutput(text, { toolName: opts.toolName });
37944
- if (path87) {
37978
+ const path91 = spillToolOutput(text, { toolName: opts.toolName });
37979
+ if (path91) {
37945
37980
  const spillNote = `
37946
- \u2026 [full output spilled to: ${path87} \u2014 re-read with read_file if you need the complete text] \u2026`;
37981
+ \u2026 [full output spilled to: ${path91} \u2014 re-read with read_file if you need the complete text] \u2026`;
37947
37982
  if (preview.includes("] \u2026\n")) {
37948
37983
  preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
37949
37984
  `);
@@ -41056,28 +41091,28 @@ var init_storage = __esm({
41056
41091
  VALID_SCALARS = /^(true|false|null|~)$/i;
41057
41092
  Storage = class {
41058
41093
  /** 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}`);
41094
+ read(path91) {
41095
+ if (!existsSync19(path91)) {
41096
+ throw new Error(`File not found: ${path91}`);
41062
41097
  }
41063
- const md = readFileSync16(path87, "utf8");
41098
+ const md = readFileSync16(path91, "utf8");
41064
41099
  return parseFrontmatter(md);
41065
41100
  }
41066
41101
  /** Read a Markdown file; returns null if not found. */
41067
- readIfExists(path87) {
41068
- if (!existsSync19(path87)) return null;
41069
- return this.read(path87);
41102
+ readIfExists(path91) {
41103
+ if (!existsSync19(path91)) return null;
41104
+ return this.read(path91);
41070
41105
  }
41071
41106
  /**
41072
41107
  * Write a Markdown file atomically (tmp + rename). Creates parent dirs.
41073
41108
  * The meta object is serialized as YAML frontmatter; body as Markdown.
41074
41109
  */
41075
- write(path87, meta3, body) {
41076
- mkdirSync10(dirname2(path87), { recursive: true });
41077
- const tmp = path87 + ".tmp-" + process.pid;
41110
+ write(path91, meta3, body) {
41111
+ mkdirSync10(dirname2(path91), { recursive: true });
41112
+ const tmp = path91 + ".tmp-" + process.pid;
41078
41113
  const md = serializeFrontmatter(meta3, body);
41079
41114
  writeFileSync13(tmp, md, "utf8");
41080
- renameSync(tmp, path87);
41115
+ renameSync(tmp, path91);
41081
41116
  }
41082
41117
  /** List all .md files in a directory (non-recursive). */
41083
41118
  listMarkdown(dir) {
@@ -41139,8 +41174,8 @@ function nextPlanTaskId(store6) {
41139
41174
  return `t${store6.counter}`;
41140
41175
  }
41141
41176
  function writePlanTaskArtifact(rootDir, task) {
41142
- const path87 = join18(rootDir, "plan-tasks", `${task.id}.md`);
41143
- mkdirSync11(dirname3(path87), { recursive: true });
41177
+ const path91 = join18(rootDir, "plan-tasks", `${task.id}.md`);
41178
+ mkdirSync11(dirname3(path91), { recursive: true });
41144
41179
  const meta3 = {
41145
41180
  kind: "task",
41146
41181
  id: task.id,
@@ -41161,7 +41196,7 @@ function writePlanTaskArtifact(rootDir, task) {
41161
41196
  task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
41162
41197
  ""
41163
41198
  ].filter((l) => l !== null).join("\n");
41164
- new Storage().write(path87, meta3, body);
41199
+ new Storage().write(path91, meta3, body);
41165
41200
  }
41166
41201
  function loadHandle(rootDir) {
41167
41202
  const jsonPath = join18(rootDir, "plan.json");
@@ -42960,6 +42995,7 @@ var init_servers = __esm({
42960
42995
  // src/cli/lsp/manager.ts
42961
42996
  import { spawn as spawn10 } from "node:child_process";
42962
42997
  import { readFileSync as readFileSync18 } from "node:fs";
42998
+ import path34 from "node:path";
42963
42999
  function processTransport(child) {
42964
43000
  return {
42965
43001
  send: (data) => {
@@ -42976,12 +43012,22 @@ function processTransport(child) {
42976
43012
  };
42977
43013
  }
42978
43014
  function getSharedLspManager(cwd = process.cwd()) {
42979
- if (shared && shared.cwd === cwd) return shared.manager;
42980
- shared?.manager.dispose();
43015
+ const key = path34.resolve(cwd);
43016
+ const existing = sharedByRoot.get(key);
43017
+ if (existing) return existing;
42981
43018
  const manager = new LspManager({ cwd });
42982
- shared = { cwd, manager };
43019
+ sharedByRoot.set(key, manager);
42983
43020
  return manager;
42984
43021
  }
43022
+ function disposeSharedLspManager() {
43023
+ for (const manager of sharedByRoot.values()) {
43024
+ try {
43025
+ manager.dispose();
43026
+ } catch {
43027
+ }
43028
+ }
43029
+ sharedByRoot.clear();
43030
+ }
42985
43031
  function normalizeLocations(res) {
42986
43032
  if (!res) return [];
42987
43033
  const arr = Array.isArray(res) ? res : [res];
@@ -43048,7 +43094,7 @@ function normalizeRename(res) {
43048
43094
  if (files.length === 0) return null;
43049
43095
  return { files, totalEdits: total };
43050
43096
  }
43051
- var SYMBOL_KINDS, LspManager, shared;
43097
+ var SYMBOL_KINDS, LspManager, sharedByRoot;
43052
43098
  var init_manager = __esm({
43053
43099
  "src/cli/lsp/manager.ts"() {
43054
43100
  "use strict";
@@ -43271,11 +43317,11 @@ var init_manager = __esm({
43271
43317
  this.servers.clear();
43272
43318
  }
43273
43319
  };
43274
- shared = null;
43320
+ sharedByRoot = /* @__PURE__ */ new Map();
43275
43321
  if (typeof process !== "undefined" && typeof process.once === "function") {
43276
43322
  process.once("exit", () => {
43277
43323
  try {
43278
- shared?.manager.dispose();
43324
+ disposeSharedLspManager();
43279
43325
  } catch {
43280
43326
  }
43281
43327
  });
@@ -43285,9 +43331,9 @@ var init_manager = __esm({
43285
43331
 
43286
43332
  // src/cli/ast/engine.ts
43287
43333
  import { readFile as readFile2 } from "node:fs/promises";
43288
- import path34 from "node:path";
43334
+ import path35 from "node:path";
43289
43335
  function isAstSupported(file2) {
43290
- return TS_EXTENSIONS.has(path34.extname(file2).toLowerCase());
43336
+ return TS_EXTENSIONS.has(path35.extname(file2).toLowerCase());
43291
43337
  }
43292
43338
  function loadTs() {
43293
43339
  if (!tsPromise) {
@@ -43299,8 +43345,8 @@ function errMessage(err) {
43299
43345
  return err instanceof Error ? err.message : String(err);
43300
43346
  }
43301
43347
  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();
43348
+ const resolvedPath = path35.isAbsolute(file2) ? file2 : path35.join(cwd ?? process.cwd(), file2);
43349
+ const extension = path35.extname(resolvedPath).toLowerCase();
43304
43350
  if (!TS_EXTENSIONS.has(extension)) {
43305
43351
  return {
43306
43352
  status: "unsupported-extension",
@@ -43342,7 +43388,7 @@ async function parseFileSymbolsDiag(file2, cwd) {
43342
43388
  }
43343
43389
  let source2;
43344
43390
  try {
43345
- source2 = ts.createSourceFile(path34.basename(resolvedPath), text, ts.ScriptTarget.Latest, true);
43391
+ source2 = ts.createSourceFile(path35.basename(resolvedPath), text, ts.ScriptTarget.Latest, true);
43346
43392
  } catch (err) {
43347
43393
  return {
43348
43394
  status: "parse-error",
@@ -43567,11 +43613,11 @@ var init_store2 = __esm({
43567
43613
  // src/cli/semantic/index.ts
43568
43614
  import { promises as fs18, existsSync as existsSync24, readFileSync as readFileSync19 } from "node:fs";
43569
43615
  import { homedir as homedir7 } from "node:os";
43570
- import path35 from "node:path";
43616
+ import path36 from "node:path";
43571
43617
  import { createHash as createHash12 } from "node:crypto";
43572
43618
  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`);
43619
+ const hash3 = createHash12("sha1").update(path36.resolve(root)).digest("hex").slice(0, 16);
43620
+ return process.env.ZELARI_SEMANTIC_FILE ?? path36.join(homedir7(), ".tmp", "zelari-code", "semantic", `${hash3}.json`);
43575
43621
  }
43576
43622
  async function collectSourceFiles(root, maxFiles = 1500) {
43577
43623
  const out = [];
@@ -43589,11 +43635,11 @@ async function collectSourceFiles(root, maxFiles = 1500) {
43589
43635
  if (entry.isDirectory() && IGNORE_DIRS.has(entry.name)) continue;
43590
43636
  if (entry.isDirectory()) continue;
43591
43637
  }
43592
- const full = path35.join(dir, entry.name);
43638
+ const full = path36.join(dir, entry.name);
43593
43639
  if (entry.isDirectory()) {
43594
43640
  if (IGNORE_DIRS.has(entry.name)) continue;
43595
43641
  await walk2(full);
43596
- } else if (SOURCE_EXTENSIONS.has(path35.extname(entry.name).toLowerCase())) {
43642
+ } else if (SOURCE_EXTENSIONS.has(path36.extname(entry.name).toLowerCase())) {
43597
43643
  out.push(full);
43598
43644
  }
43599
43645
  }
@@ -43642,7 +43688,7 @@ async function buildIndex(files, embed, options) {
43642
43688
  }
43643
43689
  async function saveIndex(root, data) {
43644
43690
  const file2 = getIndexPath(root);
43645
- await fs18.mkdir(path35.dirname(file2), { recursive: true });
43691
+ await fs18.mkdir(path36.dirname(file2), { recursive: true });
43646
43692
  const tmp = `${file2}.tmp-${process.pid}`;
43647
43693
  await fs18.writeFile(tmp, JSON.stringify(data), "utf8");
43648
43694
  await fs18.rename(tmp, file2);
@@ -44524,7 +44570,7 @@ var init_provider = __esm({
44524
44570
  });
44525
44571
 
44526
44572
  // src/cli/semantic/tools.ts
44527
- import path36 from "node:path";
44573
+ import path37 from "node:path";
44528
44574
  function createSemanticTool(deps) {
44529
44575
  const buildEmbedFn = deps.buildEmbedFn ?? buildProviderEmbedFn;
44530
44576
  return {
@@ -44551,7 +44597,7 @@ function createSemanticTool(deps) {
44551
44597
  return typedOk({
44552
44598
  count: res.hits.length,
44553
44599
  results: res.hits.map((h) => ({
44554
- location: `${path36.relative(deps.root, h.file) || h.file}:${h.startLine}-${h.endLine}`,
44600
+ location: `${path37.relative(deps.root, h.file) || h.file}:${h.startLine}-${h.endLine}`,
44555
44601
  score: Number(h.score.toFixed(3)),
44556
44602
  preview: h.text.length > 400 ? `${h.text.slice(0, 400)}\u2026` : h.text
44557
44603
  }))
@@ -44571,7 +44617,7 @@ var init_tools4 = __esm({
44571
44617
 
44572
44618
  // src/cli/browser/driver.ts
44573
44619
  import { createRequire as createRequire2 } from "node:module";
44574
- import path37 from "node:path";
44620
+ import path38 from "node:path";
44575
44621
  import { pathToFileURL } from "node:url";
44576
44622
  function asPlaywright(mod) {
44577
44623
  if (!mod || typeof mod !== "object") return null;
@@ -44582,10 +44628,10 @@ function asPlaywright(mod) {
44582
44628
  return null;
44583
44629
  }
44584
44630
  async function loadPlaywright(cwd) {
44585
- const base2 = cwd && cwd.length > 0 ? path37.resolve(cwd) : void 0;
44631
+ const base2 = cwd && cwd.length > 0 ? path38.resolve(cwd) : void 0;
44586
44632
  if (base2) {
44587
44633
  try {
44588
- const req = createRequire2(path37.join(base2, "package.json"));
44634
+ const req = createRequire2(path38.join(base2, "package.json"));
44589
44635
  const resolved = req.resolve("playwright");
44590
44636
  const mod = await import(pathToFileURL(resolved).href);
44591
44637
  const pw = asPlaywright(mod);
@@ -44800,7 +44846,7 @@ var init_driver = __esm({
44800
44846
  });
44801
44847
 
44802
44848
  // src/cli/browser/tools.ts
44803
- import path38 from "node:path";
44849
+ import path39 from "node:path";
44804
44850
  import os8 from "node:os";
44805
44851
  function createBrowserTool(deps = {}) {
44806
44852
  return {
@@ -44819,7 +44865,7 @@ function createBrowserTool(deps = {}) {
44819
44865
  execute: async (args, ctx) => {
44820
44866
  const a = args;
44821
44867
  const dir = deps.screenshotDir ?? os8.tmpdir();
44822
- const screenshotPath = a.screenshot === false ? void 0 : path38.join(dir, `zelari-browser-${Date.now()}.png`);
44868
+ const screenshotPath = a.screenshot === false ? void 0 : path39.join(dir, `zelari-browser-${Date.now()}.png`);
44823
44869
  const result = await runBrowserCheck(
44824
44870
  {
44825
44871
  url: a.url,
@@ -44931,21 +44977,21 @@ function normalizeAuth(auth) {
44931
44977
  return "agent";
44932
44978
  }
44933
44979
  function readSecrets() {
44934
- const path87 = getSshSecretsPath();
44935
- if (!existsSync25(path87)) return {};
44980
+ const path91 = getSshSecretsPath();
44981
+ if (!existsSync25(path91)) return {};
44936
44982
  try {
44937
- return JSON.parse(readFileSync20(path87, "utf8"));
44983
+ return JSON.parse(readFileSync20(path91, "utf8"));
44938
44984
  } catch {
44939
44985
  return {};
44940
44986
  }
44941
44987
  }
44942
44988
  function writeSecrets(data) {
44943
- const path87 = getSshSecretsPath();
44944
- mkdirSync12(dirname4(path87), { recursive: true });
44945
- writeFileSync15(path87, `${JSON.stringify(data, null, 2)}
44989
+ const path91 = getSshSecretsPath();
44990
+ mkdirSync12(dirname4(path91), { recursive: true });
44991
+ writeFileSync15(path91, `${JSON.stringify(data, null, 2)}
44946
44992
  `, "utf8");
44947
44993
  try {
44948
- chmodSync(path87, 384);
44994
+ chmodSync(path91, 384);
44949
44995
  } catch {
44950
44996
  }
44951
44997
  }
@@ -44974,10 +45020,10 @@ function deleteSshPassword(id3) {
44974
45020
  writeSecrets({ passwords });
44975
45021
  }
44976
45022
  function readStore2() {
44977
- const path87 = getSshTargetsPath();
44978
- if (!existsSync25(path87)) return [];
45023
+ const path91 = getSshTargetsPath();
45024
+ if (!existsSync25(path91)) return [];
44979
45025
  try {
44980
- const parsed = JSON.parse(readFileSync20(path87, "utf8"));
45026
+ const parsed = JSON.parse(readFileSync20(path91, "utf8"));
44981
45027
  const list = Array.isArray(parsed.targets) ? parsed.targets : [];
44982
45028
  return list.filter(
44983
45029
  (t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
@@ -44992,11 +45038,11 @@ function readStore2() {
44992
45038
  }
44993
45039
  }
44994
45040
  function writeStore2(targets) {
44995
- const path87 = getSshTargetsPath();
44996
- mkdirSync12(dirname4(path87), { recursive: true });
45041
+ const path91 = getSshTargetsPath();
45042
+ mkdirSync12(dirname4(path91), { recursive: true });
44997
45043
  const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
44998
45044
  writeFileSync15(
44999
- path87,
45045
+ path91,
45000
45046
  `${JSON.stringify({ targets: clean }, null, 2)}
45001
45047
  `,
45002
45048
  "utf8"
@@ -45242,11 +45288,11 @@ function formatSshTargetsForPrompt() {
45242
45288
  ];
45243
45289
  for (const t of targets) {
45244
45290
  const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
45245
- const path87 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
45291
+ const path91 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
45246
45292
  const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
45247
45293
  const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
45248
45294
  lines.push(
45249
- `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path87}${tags}${allow}`
45295
+ `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path91}${tags}${allow}`
45250
45296
  );
45251
45297
  }
45252
45298
  return lines.join("\n");
@@ -45373,10 +45419,10 @@ var init_tools6 = __esm({
45373
45419
 
45374
45420
  // src/cli/workspace/worldModel.ts
45375
45421
  import { promises as fs19 } from "node:fs";
45376
- import path39 from "node:path";
45422
+ import path40 from "node:path";
45377
45423
  import { spawn as spawn12 } from "node:child_process";
45378
45424
  function worldDir(cwd) {
45379
- return path39.join(cwd, WORLD_DIR_NAME);
45425
+ return path40.join(cwd, WORLD_DIR_NAME);
45380
45426
  }
45381
45427
  async function ensureWorldDir(cwd) {
45382
45428
  const dir = worldDir(cwd);
@@ -45386,10 +45432,10 @@ async function ensureWorldDir(cwd) {
45386
45432
  async function appendTimeline(cwd, entry) {
45387
45433
  const dir = await ensureWorldDir(cwd);
45388
45434
  const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
45389
- await fs19.appendFile(path39.join(dir, TIMELINE_FILE), line, "utf8");
45435
+ await fs19.appendFile(path40.join(dir, TIMELINE_FILE), line, "utf8");
45390
45436
  }
45391
45437
  async function readChecks(cwd) {
45392
- const p3 = path39.join(worldDir(cwd), CHECKS_FILE);
45438
+ const p3 = path40.join(worldDir(cwd), CHECKS_FILE);
45393
45439
  try {
45394
45440
  const raw = await fs19.readFile(p3, "utf8");
45395
45441
  const parsed = JSON.parse(raw);
@@ -45464,8 +45510,8 @@ function runShell(command, cwd, timeoutMs2, signal) {
45464
45510
  });
45465
45511
  }
45466
45512
  async function runBacktest(cwd, signal) {
45467
- const checksPath = path39.join(worldDir(cwd), CHECKS_FILE);
45468
- const hypothesisPath = path39.join(worldDir(cwd), HYPOTHESIS_FILE);
45513
+ const checksPath = path40.join(worldDir(cwd), CHECKS_FILE);
45514
+ const hypothesisPath = path40.join(worldDir(cwd), HYPOTHESIS_FILE);
45469
45515
  const checks = await readChecks(cwd);
45470
45516
  if (checks.length === 0) {
45471
45517
  return {
@@ -45534,7 +45580,7 @@ var init_worldModel = __esm({
45534
45580
  "use strict";
45535
45581
  init_zod();
45536
45582
  init_toolTypes();
45537
- WORLD_DIR_NAME = path39.join(".zelari", "world");
45583
+ WORLD_DIR_NAME = path40.join(".zelari", "world");
45538
45584
  HYPOTHESIS_FILE = "hypothesis.md";
45539
45585
  CHECKS_FILE = "checks.json";
45540
45586
  TIMELINE_FILE = "timeline.jsonl";
@@ -45551,7 +45597,7 @@ var init_worldModel = __esm({
45551
45597
  execute: async (args, ctx) => {
45552
45598
  try {
45553
45599
  const dir = await ensureWorldDir(ctx.cwd);
45554
- const file2 = path39.join(dir, HYPOTHESIS_FILE);
45600
+ const file2 = path40.join(dir, HYPOTHESIS_FILE);
45555
45601
  if (args.append) {
45556
45602
  const block = `
45557
45603
 
@@ -45590,7 +45636,7 @@ ${args.content}
45590
45636
  execute: async (args, ctx) => {
45591
45637
  try {
45592
45638
  const dir = await ensureWorldDir(ctx.cwd);
45593
- const file2 = path39.join(dir, CHECKS_FILE);
45639
+ const file2 = path40.join(dir, CHECKS_FILE);
45594
45640
  const body = { checks: args.checks };
45595
45641
  await fs19.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
45596
45642
  await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
@@ -45629,8 +45675,8 @@ ${args.content}
45629
45675
  stdoutPreview: "(dryRun)",
45630
45676
  mismatch: "dryRun"
45631
45677
  })),
45632
- hypothesisPath: path39.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
45633
- checksPath: path39.join(worldDir(ctx.cwd), CHECKS_FILE)
45678
+ hypothesisPath: path40.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
45679
+ checksPath: path40.join(worldDir(ctx.cwd), CHECKS_FILE)
45634
45680
  });
45635
45681
  }
45636
45682
  const result = await runBacktest(ctx.cwd, ctx.signal);
@@ -45654,7 +45700,7 @@ ${args.content}
45654
45700
  execute: async (args, ctx) => {
45655
45701
  try {
45656
45702
  const dir = await ensureWorldDir(ctx.cwd);
45657
- const file2 = path39.join(dir, TIMELINE_FILE);
45703
+ const file2 = path40.join(dir, TIMELINE_FILE);
45658
45704
  await appendTimeline(ctx.cwd, {
45659
45705
  kind: args.kind,
45660
45706
  summary: args.summary,
@@ -46317,12 +46363,12 @@ __export(folderTrust_exports, {
46317
46363
  });
46318
46364
  import { homedir as homedir9 } from "node:os";
46319
46365
  import { existsSync as existsSync26, mkdirSync as mkdirSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
46320
- import path40 from "node:path";
46366
+ import path41 from "node:path";
46321
46367
  function trustStorePath() {
46322
- return _overrideStorePath ?? path40.join(homedir9(), ".zelari-code", "trust.json");
46368
+ return _overrideStorePath ?? path41.join(homedir9(), ".zelari-code", "trust.json");
46323
46369
  }
46324
46370
  function normalize4(p3) {
46325
- const resolved = path40.resolve(p3);
46371
+ const resolved = path41.resolve(p3);
46326
46372
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
46327
46373
  }
46328
46374
  function readStore3() {
@@ -46338,7 +46384,7 @@ function readStore3() {
46338
46384
  function writeStore3(store6) {
46339
46385
  const p3 = trustStorePath();
46340
46386
  try {
46341
- mkdirSync13(path40.dirname(p3), { recursive: true });
46387
+ mkdirSync13(path41.dirname(p3), { recursive: true });
46342
46388
  writeFileSync16(p3, JSON.stringify(store6, null, 2), "utf8");
46343
46389
  } catch (err) {
46344
46390
  throw new Error(
@@ -46364,7 +46410,7 @@ function isFolderTrusted(folderPath) {
46364
46410
  }
46365
46411
  function trustFolder(folderPath) {
46366
46412
  const store6 = readStore3();
46367
- const normalized = path40.resolve(folderPath);
46413
+ const normalized = path41.resolve(folderPath);
46368
46414
  if (!store6.folders.some((f) => normalize4(f.path) === normalize4(normalized))) {
46369
46415
  store6.folders.push({ path: normalized, trustedAt: (/* @__PURE__ */ new Date()).toISOString() });
46370
46416
  writeStore3(store6);
@@ -46548,7 +46594,7 @@ __export(policyEngine_exports, {
46548
46594
  });
46549
46595
  import { readFileSync as readFileSync22 } from "node:fs";
46550
46596
  import { homedir as homedir11 } from "node:os";
46551
- import path41 from "node:path";
46597
+ import path42 from "node:path";
46552
46598
  function emptyPolicySet() {
46553
46599
  return { agents: /* @__PURE__ */ new Map(), warnings: [], precedence: policyPrecedenceFromEnv() };
46554
46600
  }
@@ -46793,9 +46839,9 @@ function loadPolicySet(root, opts = {}) {
46793
46839
  const mode = opts.mode ?? "permissive";
46794
46840
  const warnings = [];
46795
46841
  const precedence = policyPrecedenceFromEnv();
46796
- const project = readPolicyFile(path41.join(root, ".zelari", "policy.json"), warnings, mode);
46842
+ const project = readPolicyFile(path42.join(root, ".zelari", "policy.json"), warnings, mode);
46797
46843
  const global = readPolicyFile(
46798
- path41.join(opts.homeDir ?? homedir11(), ".zelari", "policy.json"),
46844
+ path42.join(opts.homeDir ?? homedir11(), ".zelari", "policy.json"),
46799
46845
  warnings,
46800
46846
  mode
46801
46847
  );
@@ -47232,7 +47278,7 @@ var init_resourceClaims = __esm({
47232
47278
  // src/cli/toolResultCache.ts
47233
47279
  import { createHash as createHash13 } from "node:crypto";
47234
47280
  import { promises as fs20 } from "node:fs";
47235
- import path42 from "node:path";
47281
+ import path43 from "node:path";
47236
47282
  function isToolCacheEnabled() {
47237
47283
  const raw = process.env.ZELARI_TOOL_CACHE;
47238
47284
  return raw !== "0" && raw !== "false" && raw !== "off";
@@ -47317,7 +47363,7 @@ async function statKey(toolName, input, ctx) {
47317
47363
  if (!input || typeof input !== "object") return null;
47318
47364
  const rawPath = input.path;
47319
47365
  if (typeof rawPath !== "string" || rawPath.length === 0) return null;
47320
- const abs = path42.isAbsolute(rawPath) ? rawPath : path42.join(ctx.cwd, rawPath);
47366
+ const abs = path43.isAbsolute(rawPath) ? rawPath : path43.join(ctx.cwd, rawPath);
47321
47367
  try {
47322
47368
  const st = await fs20.stat(abs);
47323
47369
  return hashKey({
@@ -47459,13 +47505,13 @@ function resolveKrakenSubModel(agent, parentModel, env = process.env, opts = {})
47459
47505
  const kindKey = agent === "explore" ? "ZELARI_KRAKEN_EXPLORE_MODEL" : agent === "verify" ? "ZELARI_KRAKEN_VERIFY_MODEL" : "ZELARI_KRAKEN_GENERAL_MODEL";
47460
47506
  const specific = env[kindKey]?.trim();
47461
47507
  if (specific) return specific;
47462
- const shared2 = env.ZELARI_KRAKEN_SUB_MODEL?.trim();
47463
- if (shared2) {
47508
+ const shared = env.ZELARI_KRAKEN_SUB_MODEL?.trim();
47509
+ if (shared) {
47464
47510
  if (agent === "general" && !env.ZELARI_KRAKEN_GENERAL_MODEL) {
47465
- if (env.ZELARI_KRAKEN_GENERAL_USES_SUB === "1") return shared2;
47511
+ if (env.ZELARI_KRAKEN_GENERAL_USES_SUB === "1") return shared;
47466
47512
  return parentModel;
47467
47513
  }
47468
- return shared2;
47514
+ return shared;
47469
47515
  }
47470
47516
  if (agent === "verify" && opts.familyCandidates && opts.familyCandidates.length > 0) {
47471
47517
  const picked = pickDifferentFamily(
@@ -47526,7 +47572,7 @@ __export(toolRegistry_exports, {
47526
47572
  wrapWithSandbox: () => wrapWithSandbox
47527
47573
  });
47528
47574
  import { existsSync as existsSync27 } from "node:fs";
47529
- import path43 from "node:path";
47575
+ import path44 from "node:path";
47530
47576
  function createBuiltinToolRegistry(options = {}) {
47531
47577
  const root = options.root ?? process.cwd();
47532
47578
  const audit = options.audit ?? new AuditLogger();
@@ -48084,14 +48130,14 @@ function wrapWithDiagnostics(original, root, runner) {
48084
48130
  function claimedSourcePath(token, args, root) {
48085
48131
  const cleaned = token.replace(/^["']|["']$/g, "");
48086
48132
  if (!cleaned || cleaned.startsWith("-")) return null;
48087
- if (!DIAG_SOURCE_EXTENSIONS.has(path43.extname(cleaned).toLowerCase())) return null;
48133
+ if (!DIAG_SOURCE_EXTENSIONS.has(path44.extname(cleaned).toLowerCase())) return null;
48088
48134
  const bases = [root];
48089
48135
  const cwd = args["cwd"];
48090
48136
  if (typeof cwd === "string" && cwd.length > 0) {
48091
- bases.unshift(path43.isAbsolute(cwd) ? cwd : path43.resolve(root, cwd));
48137
+ bases.unshift(path44.isAbsolute(cwd) ? cwd : path44.resolve(root, cwd));
48092
48138
  }
48093
48139
  for (const base2 of bases) {
48094
- const candidate = path43.isAbsolute(cleaned) ? path43.normalize(cleaned) : path43.resolve(base2, cleaned);
48140
+ const candidate = path44.isAbsolute(cleaned) ? path44.normalize(cleaned) : path44.resolve(base2, cleaned);
48095
48141
  try {
48096
48142
  const contained = resolveSandboxedPath(candidate, { root });
48097
48143
  if (existsSync27(contained)) return contained;
@@ -48379,7 +48425,7 @@ var init_toolRegistry = __esm({
48379
48425
 
48380
48426
  // src/cli/metrics.ts
48381
48427
  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";
48428
+ import path45 from "node:path";
48383
48429
  import os9 from "node:os";
48384
48430
  async function readMetrics(file2) {
48385
48431
  let raw = "";
@@ -48428,8 +48474,8 @@ var init_metrics3 = __esm({
48428
48474
  file;
48429
48475
  writeQueue = Promise.resolve();
48430
48476
  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 });
48477
+ this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path45.join(os9.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
48478
+ mkdirSync14(path45.dirname(this.file), { recursive: true });
48433
48479
  }
48434
48480
  /** Metrics file path — doctor/summary readers use this. */
48435
48481
  get filePath() {
@@ -48752,7 +48798,7 @@ Current policy: **lead only**.
48752
48798
 
48753
48799
  // src/cli/kraken/verificationAdapters/node.ts
48754
48800
  import { readFile as readFile3, stat as stat2 } from "node:fs/promises";
48755
- import path45 from "node:path";
48801
+ import path46 from "node:path";
48756
48802
  async function fileExists(candidate) {
48757
48803
  try {
48758
48804
  return (await stat2(candidate)).isFile();
@@ -48762,7 +48808,7 @@ async function fileExists(candidate) {
48762
48808
  }
48763
48809
  async function readPackageJson(root) {
48764
48810
  try {
48765
- return JSON.parse(await readFile3(path45.join(root, "package.json"), "utf-8"));
48811
+ return JSON.parse(await readFile3(path46.join(root, "package.json"), "utf-8"));
48766
48812
  } catch {
48767
48813
  return null;
48768
48814
  }
@@ -48776,7 +48822,7 @@ async function resolvePackageManager(root) {
48776
48822
  const fromField = packageManagerFromField(await readPackageJson(root));
48777
48823
  if (fromField) return { pm: fromField, declaredToolchain: true };
48778
48824
  for (const [marker, pm] of PM_LOCKFILES) {
48779
- if (await fileExists(path45.join(root, marker))) return { pm, declaredToolchain: true };
48825
+ if (await fileExists(path46.join(root, marker))) return { pm, declaredToolchain: true };
48780
48826
  }
48781
48827
  return { pm: "npm", declaredToolchain: false };
48782
48828
  }
@@ -48799,7 +48845,7 @@ var init_node = __esm({
48799
48845
  KNOWN_PACKAGE_MANAGERS = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "bun"]);
48800
48846
  nodeAdapter = {
48801
48847
  async detect(root) {
48802
- if (!await fileExists(path45.join(root, "package.json"))) return 0;
48848
+ if (!await fileExists(path46.join(root, "package.json"))) return 0;
48803
48849
  const { declaredToolchain } = await resolvePackageManager(root);
48804
48850
  return declaredToolchain ? 20 : 10;
48805
48851
  },
@@ -48818,7 +48864,7 @@ var init_node = __esm({
48818
48864
 
48819
48865
  // src/cli/kraken/verificationAdapters/python.ts
48820
48866
  import { readFile as readFile4, stat as stat3 } from "node:fs/promises";
48821
- import path46 from "node:path";
48867
+ import path47 from "node:path";
48822
48868
  async function fileExists2(candidate) {
48823
48869
  try {
48824
48870
  return (await stat3(candidate)).isFile();
@@ -48854,7 +48900,7 @@ var init_python = __esm({
48854
48900
  async detect(root) {
48855
48901
  let best = 0;
48856
48902
  for (const [marker, score] of DETECT_MARKERS) {
48857
- if (score > best && await fileExists2(path46.join(root, marker))) best = score;
48903
+ if (score > best && await fileExists2(path47.join(root, marker))) best = score;
48858
48904
  }
48859
48905
  return best;
48860
48906
  },
@@ -48862,12 +48908,12 @@ var init_python = __esm({
48862
48908
  const present = /* @__PURE__ */ new Map();
48863
48909
  for (const name of SCAN_FILES) {
48864
48910
  try {
48865
- present.set(name, await readFile4(path46.join(root, name), "utf-8"));
48911
+ present.set(name, await readFile4(path47.join(root, name), "utf-8"));
48866
48912
  } catch {
48867
48913
  }
48868
48914
  }
48869
48915
  const hasToken = (token) => [...present.values()].some((text) => text.includes(token));
48870
- const pytestEvidenced = hasToken("pytest") || await dirExists(path46.join(root, "tests"));
48916
+ const pytestEvidenced = hasToken("pytest") || await dirExists(path47.join(root, "tests"));
48871
48917
  const mypyReferenced = hasToken("mypy") || present.has("mypy.ini") || present.has(".mypy.ini");
48872
48918
  const pyrightReferenced = hasToken("pyright") || present.has("pyrightconfig.json");
48873
48919
  return {
@@ -48883,7 +48929,7 @@ var init_python = __esm({
48883
48929
 
48884
48930
  // src/cli/kraken/verificationAdapters/rust.ts
48885
48931
  import { stat as stat4 } from "node:fs/promises";
48886
- import path47 from "node:path";
48932
+ import path48 from "node:path";
48887
48933
  async function fileExists3(candidate) {
48888
48934
  try {
48889
48935
  return (await stat4(candidate)).isFile();
@@ -48897,7 +48943,7 @@ var init_rust = __esm({
48897
48943
  "use strict";
48898
48944
  rustAdapter = {
48899
48945
  async detect(root) {
48900
- return await fileExists3(path47.join(root, "Cargo.toml")) ? 10 : 0;
48946
+ return await fileExists3(path48.join(root, "Cargo.toml")) ? 10 : 0;
48901
48947
  },
48902
48948
  async buildPlan(_root) {
48903
48949
  void _root;
@@ -48913,7 +48959,7 @@ var init_rust = __esm({
48913
48959
 
48914
48960
  // src/cli/kraken/verificationAdapters/go.ts
48915
48961
  import { stat as stat5 } from "node:fs/promises";
48916
- import path48 from "node:path";
48962
+ import path49 from "node:path";
48917
48963
  async function fileExists4(candidate) {
48918
48964
  try {
48919
48965
  return (await stat5(candidate)).isFile();
@@ -48927,7 +48973,7 @@ var init_go = __esm({
48927
48973
  "use strict";
48928
48974
  goAdapter = {
48929
48975
  async detect(root) {
48930
- return await fileExists4(path48.join(root, "go.mod")) ? 10 : 0;
48976
+ return await fileExists4(path49.join(root, "go.mod")) ? 10 : 0;
48931
48977
  },
48932
48978
  async buildPlan(_root) {
48933
48979
  return {
@@ -48943,7 +48989,7 @@ var init_go = __esm({
48943
48989
 
48944
48990
  // src/cli/kraken/verificationAdapters/java.ts
48945
48991
  import { stat as stat6 } from "node:fs/promises";
48946
- import path49 from "node:path";
48992
+ import path50 from "node:path";
48947
48993
  async function fileExists5(candidate) {
48948
48994
  try {
48949
48995
  return (await stat6(candidate)).isFile();
@@ -48953,13 +48999,13 @@ async function fileExists5(candidate) {
48953
48999
  }
48954
49000
  async function hasGradleMarker(root) {
48955
49001
  for (const [marker] of GRADLE_MARKERS) {
48956
- if (await fileExists5(path49.join(root, marker))) return true;
49002
+ if (await fileExists5(path50.join(root, marker))) return true;
48957
49003
  }
48958
49004
  return false;
48959
49005
  }
48960
49006
  async function gradleCommand(root, verb, platform = process.platform) {
48961
49007
  const wrapper = platform === "win32" ? "gradlew.bat" : "gradlew";
48962
- if (await fileExists5(path49.join(root, wrapper))) {
49008
+ if (await fileExists5(path50.join(root, wrapper))) {
48963
49009
  return platform === "win32" ? `gradlew.bat ${verb}` : `./gradlew ${verb}`;
48964
49010
  }
48965
49011
  return `gradle ${verb}`;
@@ -48984,7 +49030,7 @@ var init_java = __esm({
48984
49030
  async detect(root) {
48985
49031
  let best = 0;
48986
49032
  for (const [marker, score] of DETECT_MARKERS2) {
48987
- if (score > best && await fileExists5(path49.join(root, marker))) best = score;
49033
+ if (score > best && await fileExists5(path50.join(root, marker))) best = score;
48988
49034
  }
48989
49035
  return best;
48990
49036
  },
@@ -48997,7 +49043,7 @@ var init_java = __esm({
48997
49043
  buildCommand: await gradleCommand(root, "build")
48998
49044
  };
48999
49045
  }
49000
- if (await fileExists5(path49.join(root, "pom.xml"))) {
49046
+ if (await fileExists5(path50.join(root, "pom.xml"))) {
49001
49047
  return {
49002
49048
  typecheckCommand: null,
49003
49049
  // compilation rides the test/package lifecycle
@@ -49106,7 +49152,7 @@ __export(nativeVerification_exports, {
49106
49152
  resolvePackCommandsForRoot: () => resolvePackCommandsForRoot
49107
49153
  });
49108
49154
  import { readFile as readFile5 } from "node:fs/promises";
49109
- import path50 from "node:path";
49155
+ import path51 from "node:path";
49110
49156
  function nativePackEnabled(env = process.env) {
49111
49157
  const v = env.ZELARI_VERIFY_PACK?.toLowerCase();
49112
49158
  if (v === "0" || v === "off" || v === "false") return false;
@@ -49149,7 +49195,7 @@ function packTimeoutMs(env = process.env) {
49149
49195
  }
49150
49196
  async function readPackageScripts(cwd = process.cwd()) {
49151
49197
  try {
49152
- const raw = await readFile5(path50.join(cwd, "package.json"), "utf-8");
49198
+ const raw = await readFile5(path51.join(cwd, "package.json"), "utf-8");
49153
49199
  const parsed = JSON.parse(raw);
49154
49200
  if (parsed && typeof parsed === "object" && typeof parsed.scripts === "object") {
49155
49201
  return parsed.scripts;
@@ -49195,16 +49241,28 @@ var init_nativeVerification = __esm({
49195
49241
 
49196
49242
  // src/cli/kraken/verificationBridge.ts
49197
49243
  import { createHash as createHash14 } from "node:crypto";
49198
- function strictDoneEnabled(surface = "kraken") {
49244
+ function strictDoneEnabled(surface = "kraken", env = process.env) {
49199
49245
  if (surface === "mission") {
49200
- const v2 = process.env.ZELARI_MISSION_STRICT;
49246
+ const v2 = env.ZELARI_MISSION_STRICT;
49201
49247
  if (v2 === "0" || v2 === "false") return false;
49202
49248
  return true;
49203
49249
  }
49204
- const v = process.env.ZELARI_STRICT_DONE;
49250
+ const v = env.ZELARI_STRICT_DONE;
49205
49251
  if (v === "0" || v === "false") return false;
49206
49252
  return true;
49207
49253
  }
49254
+ function strictEnvOverlay(knobs, base2 = process.env) {
49255
+ const overlay = { ...base2 };
49256
+ if (knobs.strictDone !== void 0) {
49257
+ const v = knobs.strictDone ? "1" : "0";
49258
+ overlay.ZELARI_STRICT_DONE = v;
49259
+ overlay.ZELARI_MISSION_STRICT = v;
49260
+ }
49261
+ if (knobs.missionStrict !== void 0) {
49262
+ overlay.ZELARI_MISSION_STRICT = knobs.missionStrict ? "1" : "0";
49263
+ }
49264
+ return overlay;
49265
+ }
49208
49266
  function criterionId(check2, index) {
49209
49267
  const slug = check2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
49210
49268
  return `check-${index + 1}-${slug || "criterion"}`;
@@ -49341,7 +49399,7 @@ async function anchorSelectionEvidence(results, emit, toolTrace) {
49341
49399
  }
49342
49400
  async function evaluateStrictBuildGate(mode, options = {}) {
49343
49401
  const gate = evaluateKrakenCompletionGate(mode);
49344
- const strictOn = strictDoneEnabled(options.surface ?? "kraken");
49402
+ const strictOn = strictDoneEnabled(options.surface ?? "kraken", options.env);
49345
49403
  const nativeOn = nativePackEnabled(options.env ?? process.env);
49346
49404
  const selectionAvailable = gate.selectionUsed && gate.total > 0;
49347
49405
  const scopeContract = options.taskContract ?? activeContractScope()?.contract;
@@ -49670,7 +49728,7 @@ var init_completionProofAttestation = __esm({
49670
49728
  // src/cli/kraken/completionProofPersist.ts
49671
49729
  import { open, rename, rm as rm2 } from "node:fs/promises";
49672
49730
  import { randomBytes as randomBytes5 } from "node:crypto";
49673
- import path51 from "node:path";
49731
+ import path52 from "node:path";
49674
49732
  function isTruthyFlag2(v) {
49675
49733
  const n = v?.trim().toLowerCase();
49676
49734
  return n === "1" || n === "true" || n === "yes" || n === "on";
@@ -49712,8 +49770,8 @@ function isWindowsRenameBlock(err) {
49712
49770
  return code === "EPERM" || code === "ENOTEMPTY" || code === "EEXIST";
49713
49771
  }
49714
49772
  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`);
49773
+ const dir = path52.dirname(target);
49774
+ const tmp = path52.join(dir, `.${path52.basename(target)}.${randomBytes5(6).toString("hex")}.tmp`);
49717
49775
  let fh = null;
49718
49776
  try {
49719
49777
  fh = await open(tmp, "w");
@@ -49759,7 +49817,7 @@ var init_completionProofPersist = __esm({
49759
49817
 
49760
49818
  // src/cli/kraken/completionProof.ts
49761
49819
  import { mkdir as mkdir2 } from "node:fs/promises";
49762
- import path52 from "node:path";
49820
+ import path53 from "node:path";
49763
49821
  function verdictOf(evaluation) {
49764
49822
  return evaluation.evaluation?.verdict ?? (evaluation.blocked ? "BLOCKED" : "PASS");
49765
49823
  }
@@ -49904,7 +49962,7 @@ async function writeCompletionProofDetailed(evaluation, options = {}) {
49904
49962
  const mode = options.persistenceMode ?? activeProofPersistenceMode();
49905
49963
  try {
49906
49964
  const baseDir = options.baseDir ?? process.cwd();
49907
- const dir = path52.join(baseDir, ".zelari");
49965
+ const dir = path53.join(baseDir, ".zelari");
49908
49966
  await mkdir2(dir, { recursive: true });
49909
49967
  const requested = options.attestation ?? {};
49910
49968
  const plan = requested.skipProbes || requested.verificationPlan !== void 0 ? void 0 : await defaultVerificationPlanSnapshot(baseDir);
@@ -49924,8 +49982,8 @@ async function writeCompletionProofDetailed(evaluation, options = {}) {
49924
49982
  baseDir
49925
49983
  );
49926
49984
  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");
49985
+ const markdownPath = path53.join(dir, "completion-proof.md");
49986
+ const jsonPath = path53.join(dir, "completion-proof.json");
49929
49987
  await writeFileAtomic(markdownPath, rendered.markdown);
49930
49988
  await writeFileAtomic(jsonPath, rendered.json);
49931
49989
  return { paths: { markdownPath, jsonPath }, mode, requiredBlockReason: null };
@@ -49951,15 +50009,53 @@ var init_completionProof = __esm({
49951
50009
  }
49952
50010
  });
49953
50011
 
50012
+ // src/cli/memory/spineTelemetry.ts
50013
+ function spineMemoryEventNote(handle, event) {
50014
+ try {
50015
+ if (event.type === "memory_recall_end" && event.reason === "context-built") {
50016
+ handle.note("context.projection", {
50017
+ subject: "context.projection",
50018
+ ...event.contextChars !== void 0 ? { contextChars: event.contextChars } : {},
50019
+ ...event.returnedCount !== void 0 ? { returnedCount: event.returnedCount } : {},
50020
+ ...event.durationMs !== void 0 ? { durationMs: event.durationMs } : {},
50021
+ ...event.backend !== void 0 ? { backend: event.backend } : {}
50022
+ });
50023
+ return;
50024
+ }
50025
+ handle.note(`memory_${event.type}`, {
50026
+ subject: "memory_event",
50027
+ type: event.type,
50028
+ ...event.durationMs !== void 0 ? { durationMs: event.durationMs } : {},
50029
+ ...event.candidateCount !== void 0 ? { candidateCount: event.candidateCount } : {},
50030
+ ...event.returnedCount !== void 0 ? { returnedCount: event.returnedCount } : {},
50031
+ ...event.backend !== void 0 ? { backend: event.backend } : {},
50032
+ ...event.reason !== void 0 ? { reason: event.reason } : {},
50033
+ ...event.memoryId !== void 0 ? { memoryId: event.memoryId } : {}
50034
+ });
50035
+ } catch {
50036
+ }
50037
+ }
50038
+ function memorySinkFor(holder) {
50039
+ return (event) => {
50040
+ const handle = holder.current;
50041
+ if (handle) spineMemoryEventNote(handle, event);
50042
+ };
50043
+ }
50044
+ var init_spineTelemetry = __esm({
50045
+ "src/cli/memory/spineTelemetry.ts"() {
50046
+ "use strict";
50047
+ }
50048
+ });
50049
+
49954
50050
  // src/cli/state/fileStateStore.ts
49955
50051
  import { createHash as createHash16, randomUUID as randomUUID4 } from "node:crypto";
49956
50052
  import { promises as fs22 } from "node:fs";
49957
- import * as path53 from "node:path";
50053
+ import * as path54 from "node:path";
49958
50054
  function shortId() {
49959
50055
  return randomUUID4().replace(/-/g, "").slice(0, 12);
49960
50056
  }
49961
50057
  async function writeJsonAtomic(filePath, data) {
49962
- await fs22.mkdir(path53.dirname(filePath), { recursive: true });
50058
+ await fs22.mkdir(path54.dirname(filePath), { recursive: true });
49963
50059
  const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
49964
50060
  await fs22.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
49965
50061
  await fs22.rename(tmp, filePath);
@@ -50020,11 +50116,11 @@ var init_fileStateStore = __esm({
50020
50116
  indexPath = "";
50021
50117
  async init(projectRoot) {
50022
50118
  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");
50119
+ this.stateDir = path54.join(projectRoot, ".zelari", "state");
50120
+ this.commitsDir = path54.join(this.stateDir, "commits");
50121
+ this.artifactsDir = path54.join(this.stateDir, "artifacts");
50122
+ this.headPath = path54.join(this.stateDir, "HEAD.json");
50123
+ this.indexPath = path54.join(this.stateDir, "index.jsonl");
50028
50124
  await fs22.mkdir(this.commitsDir, { recursive: true });
50029
50125
  await fs22.mkdir(this.artifactsDir, { recursive: true });
50030
50126
  }
@@ -50037,13 +50133,13 @@ var init_fileStateStore = __esm({
50037
50133
  const discoveries = input.discoveries ?? [];
50038
50134
  const parent = await this.head();
50039
50135
  const id3 = shortId();
50040
- const artifactRel = path53.join("artifacts", id3);
50041
- const artifactAbs = path53.join(this.artifactsDir, id3);
50136
+ const artifactRel = path54.join("artifacts", id3);
50137
+ const artifactAbs = path54.join(this.artifactsDir, id3);
50042
50138
  await fs22.mkdir(artifactAbs, { recursive: true });
50043
50139
  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);
50140
+ await fs22.writeFile(path54.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
50141
+ await writeJsonAtomic(path54.join(artifactAbs, "discoveries.json"), discoveries);
50142
+ await writeJsonAtomic(path54.join(artifactAbs, "verification.json"), input.verification);
50047
50143
  const meta3 = {
50048
50144
  id: id3,
50049
50145
  parentId: parent?.id ?? null,
@@ -50055,14 +50151,14 @@ var init_fileStateStore = __esm({
50055
50151
  workspaceCheckpointId: input.workspaceCheckpointId,
50056
50152
  verification: {
50057
50153
  ...input.verification,
50058
- reportPath: input.verification.reportPath ?? path53.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
50154
+ reportPath: input.verification.reportPath ?? path54.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
50059
50155
  },
50060
50156
  changedPaths: input.changedPaths ?? [],
50061
50157
  stablePromptHash: input.stablePromptHash,
50062
50158
  discoveryCount: discoveries.length,
50063
50159
  artifactDir: artifactRel.replace(/\\/g, "/")
50064
50160
  };
50065
- await writeJsonAtomic(path53.join(this.commitsDir, `${id3}.json`), meta3);
50161
+ await writeJsonAtomic(path54.join(this.commitsDir, `${id3}.json`), meta3);
50066
50162
  await writeJsonAtomic(this.headPath, { id: id3, updatedAt: meta3.createdAt });
50067
50163
  await fs22.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
50068
50164
  return stripStored(meta3);
@@ -50073,7 +50169,7 @@ var init_fileStateStore = __esm({
50073
50169
  return this.get(head.id);
50074
50170
  }
50075
50171
  async get(id3) {
50076
- const stored = await readJsonFile(path53.join(this.commitsDir, `${id3}.json`));
50172
+ const stored = await readJsonFile(path54.join(this.commitsDir, `${id3}.json`));
50077
50173
  return stored ? stripStored(stored) : null;
50078
50174
  }
50079
50175
  async list(limit = 20) {
@@ -50112,9 +50208,9 @@ var init_fileStateStore = __esm({
50112
50208
  async loadDiscoveries(id3) {
50113
50209
  const meta3 = id3 ? await this.get(id3) : await this.head();
50114
50210
  if (!meta3) return [];
50115
- const stored = await readJsonFile(path53.join(this.commitsDir, `${meta3.id}.json`));
50211
+ const stored = await readJsonFile(path54.join(this.commitsDir, `${meta3.id}.json`));
50116
50212
  if (!stored?.artifactDir) return [];
50117
- const discPath = path53.join(this.stateDir, stored.artifactDir, "discoveries.json");
50213
+ const discPath = path54.join(this.stateDir, stored.artifactDir, "discoveries.json");
50118
50214
  return await readJsonFile(discPath) ?? [];
50119
50215
  }
50120
50216
  async materializeContext(id3, maxChars = DEFAULT_MATERIALIZE_CHARS) {
@@ -51367,10 +51463,10 @@ var init_mode = __esm({
51367
51463
 
51368
51464
  // src/cli/headless.ts
51369
51465
  import { readFileSync as readFileSync23 } from "node:fs";
51370
- import path54 from "node:path";
51466
+ import path55 from "node:path";
51371
51467
  function resolveHeadlessCwd(opts) {
51372
51468
  const raw = typeof opts.cwd === "string" ? opts.cwd.trim() : "";
51373
- return path54.resolve(raw.length > 0 ? raw : process.cwd());
51469
+ return path55.resolve(raw.length > 0 ? raw : process.cwd());
51374
51470
  }
51375
51471
  function defaultProfileForMode(mode) {
51376
51472
  switch (mode) {
@@ -51401,7 +51497,8 @@ function parseHeadlessFlags(argv) {
51401
51497
  let profile;
51402
51498
  let resumeSessionId;
51403
51499
  let exportSessionPath;
51404
- let strictDone = false;
51500
+ let strictDone;
51501
+ let missionStrict;
51405
51502
  let krakenGraph;
51406
51503
  let planOnly = process.env.ZELARI_KRAKEN_PLAN_ONLY === "1" || process.env.ZELARI_KRAKEN_PLAN_ONLY === "true";
51407
51504
  let runPlan = process.env.ZELARI_KRAKEN_RUN_PLAN;
@@ -51563,7 +51660,10 @@ function parseHeadlessFlags(argv) {
51563
51660
  strictDone = true;
51564
51661
  } else if (arg === "--no-strict-done") {
51565
51662
  strictDone = false;
51566
- process.env.ZELARI_MISSION_STRICT = "0";
51663
+ } else if (arg === "--mission-strict") {
51664
+ missionStrict = true;
51665
+ } else if (arg === "--no-mission-strict") {
51666
+ missionStrict = false;
51567
51667
  } else if (arg === "--kraken-graph") {
51568
51668
  krakenGraph = argv[i + 1];
51569
51669
  i++;
@@ -51618,7 +51718,8 @@ function parseHeadlessFlags(argv) {
51618
51718
  ...profile ? { profile } : {},
51619
51719
  ...resumeSessionId ? { resumeSessionId } : {},
51620
51720
  ...exportSessionPath ? { exportSessionPath } : {},
51621
- ...strictDone ? { strictDone: true } : {},
51721
+ ...strictDone !== void 0 ? { strictDone } : {},
51722
+ ...missionStrict !== void 0 ? { missionStrict } : {},
51622
51723
  ...krakenGraph ? { krakenGraph } : {},
51623
51724
  ...planOnly ? { planOnly: true } : {},
51624
51725
  ...runPlan ? { runPlan } : {},
@@ -52305,7 +52406,7 @@ var init_claudeProvider = __esm({
52305
52406
  // src/cli/memory/legacyImport.ts
52306
52407
  import { createHash as createHash17 } from "node:crypto";
52307
52408
  import { promises as fs23 } from "node:fs";
52308
- import * as path55 from "node:path";
52409
+ import * as path56 from "node:path";
52309
52410
  function sourceId(fact, line) {
52310
52411
  return `jsonl:${fact.id ?? createHash17("sha256").update(line).digest("hex")}`;
52311
52412
  }
@@ -52323,7 +52424,7 @@ function timestamp(value) {
52323
52424
  }
52324
52425
  async function importLegacyMemoryLog(backend, service) {
52325
52426
  const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
52326
- const logPath = path55.join(path55.dirname(backend.databasePath), "log.jsonl");
52427
+ const logPath = path56.join(path56.dirname(backend.databasePath), "log.jsonl");
52327
52428
  let raw;
52328
52429
  try {
52329
52430
  raw = await fs23.readFile(logPath, "utf8");
@@ -52506,7 +52607,7 @@ var init_sqliteCodec = __esm({
52506
52607
  // src/cli/memory/sqliteRpc.ts
52507
52608
  import { existsSync as existsSync30 } from "node:fs";
52508
52609
  import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
52509
- import * as path56 from "node:path";
52610
+ import * as path57 from "node:path";
52510
52611
  import { Worker } from "node:worker_threads";
52511
52612
  function isBusy(error51) {
52512
52613
  const candidate = error51;
@@ -52515,10 +52616,10 @@ function isBusy(error51) {
52515
52616
  );
52516
52617
  }
52517
52618
  function resolveWorkerUrl() {
52518
- const here = path56.dirname(fileURLToPath2(import.meta.url));
52519
- const direct = path56.join(here, "sqliteWorker.mjs");
52619
+ const here = path57.dirname(fileURLToPath2(import.meta.url));
52620
+ const direct = path57.join(here, "sqliteWorker.mjs");
52520
52621
  if (existsSync30(direct)) return pathToFileURL2(direct);
52521
- return pathToFileURL2(path56.join(here, "memory", "sqliteWorker.mjs"));
52622
+ return pathToFileURL2(path57.join(here, "memory", "sqliteWorker.mjs"));
52522
52623
  }
52523
52624
  var SqliteWorkerRpc;
52524
52625
  var init_sqliteRpc = __esm({
@@ -52807,7 +52908,7 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
52807
52908
  // src/cli/memory/sqliteBackend.ts
52808
52909
  import { createHash as createHash18, randomUUID as randomUUID5 } from "node:crypto";
52809
52910
  import { promises as fs24 } from "node:fs";
52810
- import * as path57 from "node:path";
52911
+ import * as path58 from "node:path";
52811
52912
  function boundedLimit(value, fallback = 50) {
52812
52913
  return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
52813
52914
  }
@@ -52869,16 +52970,16 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
52869
52970
  try {
52870
52971
  resolved = await fs24.realpath(projectRoot);
52871
52972
  } catch {
52872
- resolved = path57.resolve(projectRoot);
52973
+ resolved = path58.resolve(projectRoot);
52873
52974
  }
52874
52975
  if (this.initialized && resolved === this.projectRoot) return;
52875
52976
  if (this.initialized) await this.close();
52876
52977
  const filename = this.options.filename ?? "memory.db";
52877
- if (path57.basename(filename) !== filename || filename === "." || filename === "..") {
52978
+ if (path58.basename(filename) !== filename || filename === "." || filename === "..") {
52878
52979
  throw new Error("SQLite memory filename must not contain a path.");
52879
52980
  }
52880
- const zelariDirectory = path57.join(resolved, ".zelari");
52881
- const directory = path57.join(zelariDirectory, "memory");
52981
+ const zelariDirectory = path58.join(resolved, ".zelari");
52982
+ const directory = path58.join(zelariDirectory, "memory");
52882
52983
  for (const candidate of [zelariDirectory, directory]) {
52883
52984
  let stat7;
52884
52985
  try {
@@ -52897,12 +52998,12 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
52897
52998
  }
52898
52999
  }
52899
53000
  const canonicalDirectory = await fs24.realpath(directory);
52900
- const relativeDirectory = path57.relative(resolved, canonicalDirectory);
52901
- if (relativeDirectory.startsWith("..") || path57.isAbsolute(relativeDirectory)) {
53001
+ const relativeDirectory = path58.relative(resolved, canonicalDirectory);
53002
+ if (relativeDirectory.startsWith("..") || path58.isAbsolute(relativeDirectory)) {
52902
53003
  throw new Error("SQLite memory directory resolves outside the active project.");
52903
53004
  }
52904
53005
  this.projectRoot = resolved;
52905
- this.databasePath = path57.join(canonicalDirectory, filename);
53006
+ this.databasePath = path58.join(canonicalDirectory, filename);
52906
53007
  const opened = await this.rpc.open({
52907
53008
  dbPath: this.databasePath,
52908
53009
  schemaSql: SQLITE_MEMORY_BASE_SCHEMA,
@@ -53435,7 +53536,7 @@ __export(serviceFactory_exports, {
53435
53536
  });
53436
53537
  import { createHash as createHash19 } from "node:crypto";
53437
53538
  import { promises as fs25 } from "node:fs";
53438
- import * as path58 from "node:path";
53539
+ import * as path59 from "node:path";
53439
53540
  function isMemoryV2Enabled(env = process.env) {
53440
53541
  if (env.ZELARI_MEMORY === "0") return false;
53441
53542
  if (env.ZELARI_MEMORY_BACKEND === "file" || env.ZELARI_MEMORY_BACKEND === "jsonl") return false;
@@ -53456,7 +53557,7 @@ async function canonicalProjectId(projectRoot) {
53456
53557
  try {
53457
53558
  canonical = await fs25.realpath(projectRoot);
53458
53559
  } catch {
53459
- canonical = path58.resolve(projectRoot);
53560
+ canonical = path59.resolve(projectRoot);
53460
53561
  }
53461
53562
  canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
53462
53563
  if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
@@ -54182,8 +54283,8 @@ function readPlan(ctx) {
54182
54283
  } catch {
54183
54284
  }
54184
54285
  }
54185
- const path87 = workspaceFile(ctx.rootDir, "plan");
54186
- const doc = ctx.storage.readIfExists(path87);
54286
+ const path91 = workspaceFile(ctx.rootDir, "plan");
54287
+ const doc = ctx.storage.readIfExists(path91);
54187
54288
  if (!doc) return { phases: [], tasks: [], milestones: [] };
54188
54289
  const meta3 = doc.meta;
54189
54290
  return {
@@ -54361,7 +54462,7 @@ function addMilestoneRecord(ctx, summary, input) {
54361
54462
  dueDate: input.dueDate,
54362
54463
  targetVersion: version2
54363
54464
  });
54364
- const path87 = join31(ctx.rootDir, "milestones", `${id3}.md`);
54465
+ const path91 = join31(ctx.rootDir, "milestones", `${id3}.md`);
54365
54466
  const meta3 = {
54366
54467
  kind: "milestone",
54367
54468
  id: id3,
@@ -54378,7 +54479,7 @@ function addMilestoneRecord(ctx, summary, input) {
54378
54479
  `Target version: ${version2}`,
54379
54480
  ""
54380
54481
  ].join("\n");
54381
- ctx.storage.write(path87, meta3, body);
54482
+ ctx.storage.write(path91, meta3, body);
54382
54483
  return { id: id3, created: true };
54383
54484
  }
54384
54485
  function readPlanSummary(ctx) {
@@ -54582,7 +54683,7 @@ function addIdeaStub(ctx) {
54582
54683
  const tags = args["tags"] ?? [];
54583
54684
  const category = args["category"] ?? "General";
54584
54685
  const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
54585
- const path87 = workspaceArtifact(ctx.rootDir, "decisions", id3);
54686
+ const path91 = workspaceArtifact(ctx.rootDir, "decisions", id3);
54586
54687
  const meta3 = {
54587
54688
  kind: "adr",
54588
54689
  status: "proposed",
@@ -54608,7 +54709,7 @@ function addIdeaStub(ctx) {
54608
54709
  ...consequences.map((c) => `- ${c}`),
54609
54710
  ""
54610
54711
  ].join("\n");
54611
- ctx.storage.write(path87, meta3, body);
54712
+ ctx.storage.write(path91, meta3, body);
54612
54713
  return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
54613
54714
  });
54614
54715
  }
@@ -54690,14 +54791,14 @@ function createDocumentStub(ctx) {
54690
54791
  ctx.storage.write(risksPath, riskMeta, content);
54691
54792
  return `Document "${title}" created at risks.md (workspace root).`;
54692
54793
  }
54693
- const path87 = workspaceArtifact(ctx.rootDir, "docs", slug);
54794
+ const path91 = workspaceArtifact(ctx.rootDir, "docs", slug);
54694
54795
  const meta3 = {
54695
54796
  kind: "doc",
54696
54797
  id: slug,
54697
54798
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
54698
54799
  tags
54699
54800
  };
54700
- ctx.storage.write(path87, meta3, content);
54801
+ ctx.storage.write(path91, meta3, content);
54701
54802
  return `Document "${title}" created at docs/${slug}.md.`;
54702
54803
  });
54703
54804
  }
@@ -55084,10 +55185,10 @@ function getUserMcpPath() {
55084
55185
  function getProjectMcpPath(projectRoot) {
55085
55186
  return join32(projectRoot, ".zelari", "mcp.json");
55086
55187
  }
55087
- function readFile6(path87) {
55088
- if (!existsSync37(path87)) return {};
55188
+ function readFile6(path91) {
55189
+ if (!existsSync37(path91)) return {};
55089
55190
  try {
55090
- const parsed = JSON.parse(readFileSync29(path87, "utf8"));
55191
+ const parsed = JSON.parse(readFileSync29(path91, "utf8"));
55091
55192
  const out = {};
55092
55193
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
55093
55194
  if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
@@ -55103,10 +55204,10 @@ function readFile6(path87) {
55103
55204
  return {};
55104
55205
  }
55105
55206
  }
55106
- function writeFile2(path87, servers) {
55107
- mkdirSync16(dirname9(path87), { recursive: true });
55207
+ function writeFile2(path91, servers) {
55208
+ mkdirSync16(dirname9(path91), { recursive: true });
55108
55209
  const body = { mcpServers: servers };
55109
- writeFileSync18(path87, `${JSON.stringify(body, null, 2)}
55210
+ writeFileSync18(path91, `${JSON.stringify(body, null, 2)}
55110
55211
  `, "utf8");
55111
55212
  }
55112
55213
  function listMcpServers(projectRoot) {
@@ -55139,9 +55240,9 @@ function upsertMcpServer(opts) {
55139
55240
  if (!opts.config.command?.trim()) {
55140
55241
  return { ok: false, error: "command is required" };
55141
55242
  }
55142
- let path87;
55243
+ let path91;
55143
55244
  if (opts.scope === "user") {
55144
- path87 = getUserMcpPath();
55245
+ path91 = getUserMcpPath();
55145
55246
  } else {
55146
55247
  const root = opts.projectRoot?.trim();
55147
55248
  if (!root) {
@@ -55150,30 +55251,30 @@ function upsertMcpServer(opts) {
55150
55251
  error: "projectRoot required for project scope (Open Folder first)"
55151
55252
  };
55152
55253
  }
55153
- path87 = getProjectMcpPath(root);
55254
+ path91 = getProjectMcpPath(root);
55154
55255
  }
55155
- const current = readFile6(path87);
55256
+ const current = readFile6(path91);
55156
55257
  current[name] = {
55157
55258
  command: opts.config.command.trim(),
55158
55259
  args: opts.config.args,
55159
55260
  env: opts.config.env,
55160
55261
  enabled: opts.config.enabled !== false
55161
55262
  };
55162
- writeFile2(path87, current);
55163
- return { ok: true, path: path87 };
55263
+ writeFile2(path91, current);
55264
+ return { ok: true, path: path91 };
55164
55265
  }
55165
55266
  function removeMcpServer(opts) {
55166
- const path87 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
55167
- if (!path87) {
55267
+ const path91 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
55268
+ if (!path91) {
55168
55269
  return { ok: false, error: "projectRoot required for project scope" };
55169
55270
  }
55170
- const current = readFile6(path87);
55271
+ const current = readFile6(path91);
55171
55272
  if (!(opts.name in current)) {
55172
- return { ok: false, error: `Server "${opts.name}" not found in ${path87}` };
55273
+ return { ok: false, error: `Server "${opts.name}" not found in ${path91}` };
55173
55274
  }
55174
55275
  delete current[opts.name];
55175
- writeFile2(path87, current);
55176
- return { ok: true, path: path87 };
55276
+ writeFile2(path91, current);
55277
+ return { ok: true, path: path91 };
55177
55278
  }
55178
55279
  var init_mcpConfigIo = __esm({
55179
55280
  "src/cli/mcp/mcpConfigIo.ts"() {
@@ -55574,10 +55675,10 @@ import { createHash as createHash20 } from "node:crypto";
55574
55675
  import { join as join34 } from "node:path";
55575
55676
  import { readFile as readFile7 } from "node:fs/promises";
55576
55677
  async function readPackageJson3(projectRoot) {
55577
- const path87 = join34(projectRoot, "package.json");
55578
- if (!existsSync39(path87)) return null;
55678
+ const path91 = join34(projectRoot, "package.json");
55679
+ if (!existsSync39(path91)) return null;
55579
55680
  try {
55580
- return JSON.parse(await readFile7(path87, "utf8"));
55681
+ return JSON.parse(await readFile7(path91, "utf8"));
55581
55682
  } catch {
55582
55683
  return null;
55583
55684
  }
@@ -55659,9 +55760,9 @@ async function genBuild(ctx) {
55659
55760
  ].join("\n");
55660
55761
  }
55661
55762
  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");
55763
+ const path91 = join34(ctx.rootDir, "risks.md");
55764
+ if (!existsSync39(path91)) return "_No open questions._";
55765
+ const content = readFileSync31(path91, "utf8");
55665
55766
  const lines = content.split("\n");
55666
55767
  const questions = [];
55667
55768
  let currentTitle = "";
@@ -55935,9 +56036,9 @@ function versionKey(value) {
55935
56036
  function firstString2(v) {
55936
56037
  return typeof v === "string" && v.trim().length > 0 ? v : null;
55937
56038
  }
55938
- function readFileSyncSafe(path87) {
56039
+ function readFileSyncSafe(path91) {
55939
56040
  try {
55940
- return readFileSync32(path87, "utf8");
56041
+ return readFileSync32(path91, "utf8");
55941
56042
  } catch {
55942
56043
  return null;
55943
56044
  }
@@ -56400,8 +56501,8 @@ async function runPostCouncilHook(ctx, options) {
56400
56501
  sources: scope.sources
56401
56502
  } : void 0
56402
56503
  });
56403
- const path87 = writeCouncilCompletion(ctx.rootDir, completion);
56404
- completionHook = { ran: true, path: path87, completion };
56504
+ const path91 = writeCouncilCompletion(ctx.rootDir, completion);
56505
+ completionHook = { ran: true, path: path91, completion };
56405
56506
  } catch (err) {
56406
56507
  completionHook = {
56407
56508
  ran: true,
@@ -56446,7 +56547,7 @@ import {
56446
56547
  writeFileSync as writeFileSync21,
56447
56548
  mkdirSync as mkdirSync17
56448
56549
  } from "node:fs";
56449
- import path59 from "node:path";
56550
+ import path60 from "node:path";
56450
56551
  import os10 from "node:os";
56451
56552
  var FeedbackStore;
56452
56553
  var init_councilFeedback = __esm({
@@ -56457,7 +56558,7 @@ var init_councilFeedback = __esm({
56457
56558
  now;
56458
56559
  entries = [];
56459
56560
  constructor(options = {}) {
56460
- this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path59.join(os10.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
56561
+ this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path60.join(os10.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
56461
56562
  this.now = options.now ?? Date.now;
56462
56563
  this.load();
56463
56564
  }
@@ -56563,7 +56664,7 @@ var init_councilFeedback = __esm({
56563
56664
  }
56564
56665
  }
56565
56666
  save() {
56566
- mkdirSync17(path59.dirname(this.file), { recursive: true });
56667
+ mkdirSync17(path60.dirname(this.file), { recursive: true });
56567
56668
  writeFileSync21(
56568
56669
  this.file,
56569
56670
  JSON.stringify({ entries: this.entries }, null, 2),
@@ -56631,7 +56732,7 @@ import { execFile as execFile4 } from "node:child_process";
56631
56732
  import { promisify as promisify3 } from "node:util";
56632
56733
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
56633
56734
  import { tmpdir as tmpdir3 } from "node:os";
56634
- import path60 from "node:path";
56735
+ import path61 from "node:path";
56635
56736
  import { randomUUID as randomUUID6 } from "node:crypto";
56636
56737
  async function git4(cwd, args, env) {
56637
56738
  const { stdout } = await execFileAsync3("git", ["-C", cwd, ...args], {
@@ -56651,8 +56752,8 @@ async function isGitRepo(cwd) {
56651
56752
  return await gitSafe(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true";
56652
56753
  }
56653
56754
  async function withTempIndex(fn) {
56654
- const dir = mkdtempSync(path60.join(tmpdir3(), "zelari-ckpt-"));
56655
- const indexFile = path60.join(dir, "index");
56755
+ const dir = mkdtempSync(path61.join(tmpdir3(), "zelari-ckpt-"));
56756
+ const indexFile = path61.join(dir, "index");
56656
56757
  try {
56657
56758
  return await fn(indexFile);
56658
56759
  } finally {
@@ -56743,7 +56844,7 @@ async function restoreCheckpoint(cwd, id3) {
56743
56844
  const deleted = [];
56744
56845
  for (const rel2 of added) {
56745
56846
  try {
56746
- rmSync2(path60.join(cwd, rel2), { force: true });
56847
+ rmSync2(path61.join(cwd, rel2), { force: true });
56747
56848
  deleted.push(rel2);
56748
56849
  } catch {
56749
56850
  }
@@ -56847,7 +56948,7 @@ __export(fileBackend_exports, {
56847
56948
  });
56848
56949
  import { randomUUID as randomUUID7 } from "node:crypto";
56849
56950
  import { promises as fs27 } from "node:fs";
56850
- import * as path61 from "node:path";
56951
+ import * as path62 from "node:path";
56851
56952
  function tokenize2(text) {
56852
56953
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
56853
56954
  }
@@ -56861,10 +56962,12 @@ function matchesFilter(metadata2, filter) {
56861
56962
  function isMemoryEnabled(env = process.env) {
56862
56963
  return env.ZELARI_MEMORY !== "0";
56863
56964
  }
56864
- async function getMemoryBackend(projectRoot, env = process.env) {
56965
+ async function getMemoryBackend(projectRoot, env = process.env, onEvent) {
56865
56966
  if (!isMemoryEnabled(env)) return new NoopMemoryBackend();
56866
56967
  if (isMemoryV2Enabled(env)) {
56867
- const service = await getMemoryService(projectRoot, env);
56968
+ const service = await getMemoryService(projectRoot, env, {
56969
+ ...onEvent ? { onEvent } : {}
56970
+ });
56868
56971
  if (service instanceof NoopMemoryService) return new NoopMemoryBackend();
56869
56972
  return new LegacyMemoryBackendAdapter(service);
56870
56973
  }
@@ -56898,8 +57001,8 @@ var init_fileBackend = __esm({
56898
57001
  logPath = "";
56899
57002
  memoryDir = "";
56900
57003
  async init(projectRoot) {
56901
- this.memoryDir = path61.join(projectRoot, ".zelari", "memory");
56902
- this.logPath = path61.join(this.memoryDir, "log.jsonl");
57004
+ this.memoryDir = path62.join(projectRoot, ".zelari", "memory");
57005
+ this.logPath = path62.join(this.memoryDir, "log.jsonl");
56903
57006
  await fs27.mkdir(this.memoryDir, { recursive: true });
56904
57007
  }
56905
57008
  async add(content, metadata2 = {}, graph) {
@@ -56972,12 +57075,12 @@ var init_fileBackend = __esm({
56972
57075
 
56973
57076
  // src/cli/traceStore.ts
56974
57077
  import { promises as fs28 } from "node:fs";
56975
- import * as path62 from "node:path";
57078
+ import * as path63 from "node:path";
56976
57079
  function traceDir(projectRoot) {
56977
- return path62.join(projectRoot, ".zelari", "trace");
57080
+ return path63.join(projectRoot, ".zelari", "trace");
56978
57081
  }
56979
57082
  function tracePath(projectRoot, missionId) {
56980
- return path62.join(traceDir(projectRoot), `${missionId}.json`);
57083
+ return path63.join(traceDir(projectRoot), `${missionId}.json`);
56981
57084
  }
56982
57085
  async function saveTrace(projectRoot, missionId, entries) {
56983
57086
  const dir = traceDir(projectRoot);
@@ -57014,7 +57117,7 @@ __export(zelariMission_exports, {
57014
57117
  });
57015
57118
  import { randomUUID as randomUUID8 } from "node:crypto";
57016
57119
  import { promises as fs29 } from "node:fs";
57017
- import * as path63 from "node:path";
57120
+ import * as path64 from "node:path";
57018
57121
  function resolveMaxIterations(env = process.env) {
57019
57122
  const raw = env.ZELARI_MISSION_MAX_ITER;
57020
57123
  const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
@@ -57057,10 +57160,10 @@ function isMissionAutoStart(env = process.env) {
57057
57160
  return env.ZELARI_MISSION_AUTO === "1";
57058
57161
  }
57059
57162
  async function writeMissionState(projectRoot, state3) {
57060
- const dir = path63.join(projectRoot, ".zelari");
57163
+ const dir = path64.join(projectRoot, ".zelari");
57061
57164
  await fs29.mkdir(dir, { recursive: true });
57062
57165
  await fs29.writeFile(
57063
- path63.join(dir, "mission-state.json"),
57166
+ path64.join(dir, "mission-state.json"),
57064
57167
  JSON.stringify(state3, null, 2) + "\n",
57065
57168
  "utf8"
57066
57169
  );
@@ -57735,7 +57838,7 @@ function safeSocketPath(socketPath) {
57735
57838
  return socketPath.trim();
57736
57839
  }
57737
57840
  function startPermissionBroker(socketPath, handlers, opts) {
57738
- const path87 = safeSocketPath(socketPath);
57841
+ const path91 = safeSocketPath(socketPath);
57739
57842
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
57740
57843
  const sockets = /* @__PURE__ */ new Set();
57741
57844
  const server = createServer2((socket) => {
@@ -57835,10 +57938,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
57835
57938
  return new Promise((resolve9, reject) => {
57836
57939
  const onError = (err) => reject(err);
57837
57940
  server.once("error", onError);
57838
- server.listen(path87, () => {
57941
+ server.listen(path91, () => {
57839
57942
  server.removeListener("error", onError);
57840
57943
  resolve9({
57841
- socketPath: path87,
57944
+ socketPath: path91,
57842
57945
  stop: () => new Promise((res) => {
57843
57946
  for (const s of sockets) s.destroy();
57844
57947
  sockets.clear();
@@ -57849,7 +57952,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
57849
57952
  if (done) return;
57850
57953
  done = true;
57851
57954
  if (process.platform !== "win32") {
57852
- unlink(path87, () => res());
57955
+ unlink(path91, () => res());
57853
57956
  } else {
57854
57957
  res();
57855
57958
  }
@@ -57862,11 +57965,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
57862
57965
  });
57863
57966
  }
57864
57967
  function requestBrokerAsk(socketPath, ask, opts) {
57865
- const path87 = safeSocketPath(socketPath);
57968
+ const path91 = safeSocketPath(socketPath);
57866
57969
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
57867
57970
  const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
57868
57971
  return new Promise((resolve9, reject) => {
57869
- const socket = connect(path87);
57972
+ const socket = connect(path91);
57870
57973
  let buffer = "";
57871
57974
  let settled = false;
57872
57975
  const settle = (fn) => {
@@ -57881,7 +57984,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
57881
57984
  settle(
57882
57985
  () => reject(
57883
57986
  new Error(
57884
- `permission broker unavailable at "${path87}" (connect timed out after ${connectTimeoutMs}ms)`
57987
+ `permission broker unavailable at "${path91}" (connect timed out after ${connectTimeoutMs}ms)`
57885
57988
  )
57886
57989
  )
57887
57990
  );
@@ -58021,7 +58124,7 @@ var init_brokerHandlers = __esm({
58021
58124
  // src/cli/gitOps.ts
58022
58125
  import { execFile as execFile5 } from "node:child_process";
58023
58126
  import { promisify as promisify4 } from "node:util";
58024
- import path64 from "node:path";
58127
+ import path65 from "node:path";
58025
58128
  async function git5(cwd, args) {
58026
58129
  try {
58027
58130
  const { stdout } = await execFileAsync4("git", ["-C", cwd, ...args], {
@@ -58066,7 +58169,7 @@ async function undoWorkingChanges(opts = {}) {
58066
58169
  };
58067
58170
  }
58068
58171
  function defaultProjectRoot() {
58069
- return path64.resolve(__dirname, "..", "..", "..");
58172
+ return path65.resolve(__dirname, "..", "..", "..");
58070
58173
  }
58071
58174
  var execFileAsync4;
58072
58175
  var init_gitOps = __esm({
@@ -58684,9 +58787,9 @@ __export(graphMemory_exports, {
58684
58787
  toGraphSnapshot: () => toGraphSnapshot
58685
58788
  });
58686
58789
  import { promises as fs32 } from "node:fs";
58687
- import path67 from "node:path";
58790
+ import path68 from "node:path";
58688
58791
  function snapshotPath(cwd) {
58689
- return path67.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
58792
+ return path68.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
58690
58793
  }
58691
58794
  function toGraphSnapshot(graph, opts) {
58692
58795
  const unresolved = (opts.unresolvedFindings ?? []).map((u) => ({
@@ -58713,7 +58816,7 @@ async function saveGraphSnapshot(cwd, snapshot) {
58713
58816
  try {
58714
58817
  await fs32.access(cwd);
58715
58818
  const file2 = snapshotPath(cwd);
58716
- await fs32.mkdir(path67.dirname(file2), { recursive: true });
58819
+ await fs32.mkdir(path68.dirname(file2), { recursive: true });
58717
58820
  await fs32.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
58718
58821
  } catch {
58719
58822
  }
@@ -58780,13 +58883,19 @@ var SNAPSHOT_DIR, SNAPSHOT_FILE, MAX_SNAPSHOT_FINDINGS_CHARS;
58780
58883
  var init_graphMemory = __esm({
58781
58884
  "src/cli/kraken/graphMemory.ts"() {
58782
58885
  "use strict";
58783
- SNAPSHOT_DIR = path67.join(".zelari", "kraken");
58886
+ SNAPSHOT_DIR = path68.join(".zelari", "kraken");
58784
58887
  SNAPSHOT_FILE = "last-graph.json";
58785
58888
  MAX_SNAPSHOT_FINDINGS_CHARS = 400;
58786
58889
  }
58787
58890
  });
58788
58891
 
58789
58892
  // src/cli/kraken/tentacle.ts
58893
+ var tentacle_exports = {};
58894
+ __export(tentacle_exports, {
58895
+ TASK_TOOL_TIMEOUT_MS: () => TASK_TOOL_TIMEOUT_MS,
58896
+ runSubAgent: () => runSubAgent,
58897
+ runTentacle: () => runTentacle
58898
+ });
58790
58899
  var init_tentacle = __esm({
58791
58900
  "src/cli/kraken/tentacle.ts"() {
58792
58901
  "use strict";
@@ -58852,14 +58961,14 @@ var init_transactional = __esm({
58852
58961
 
58853
58962
  // src/cli/kraken/workbench.ts
58854
58963
  import { promises as fs33 } from "node:fs";
58855
- import path68 from "node:path";
58964
+ import path69 from "node:path";
58856
58965
  function isWorkbenchEnabled(env = process.env) {
58857
58966
  const v = (env.ZELARI_KRAKEN_WORKBENCH ?? "1").trim().toLowerCase();
58858
58967
  if (v === "0" || v === "false" || v === "no" || v === "off") return false;
58859
58968
  return true;
58860
58969
  }
58861
58970
  function workbenchPath(cwd, graphId) {
58862
- return path68.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
58971
+ return path69.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
58863
58972
  }
58864
58973
  function countByStatus2(nodes) {
58865
58974
  const out = { pending: 0, running: 0, done: 0, error: 0, skipped: 0 };
@@ -59022,7 +59131,7 @@ var init_workbench = __esm({
59022
59131
  if (!this.enabled) return null;
59023
59132
  if (!this.dirty && this.lastWrite) return this.lastWrite;
59024
59133
  const out = workbenchPath(this.cwd, this.graphId);
59025
- await fs33.mkdir(path68.dirname(out), { recursive: true });
59134
+ await fs33.mkdir(path69.dirname(out), { recursive: true });
59026
59135
  const body = this.render();
59027
59136
  const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
59028
59137
  await fs33.writeFile(tmp, body, "utf8");
@@ -59395,14 +59504,14 @@ var init_spawnRoi = __esm({
59395
59504
 
59396
59505
  // src/cli/kraken/reputationStore.ts
59397
59506
  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";
59507
+ import path70 from "node:path";
59399
59508
  function resolveReputationStorePath(cwd = process.cwd(), env = process.env) {
59400
59509
  const override = env[REPUTATION_STORE_ENV]?.trim();
59401
59510
  if (override) return override;
59402
- return path69.join(cwd, ".zelari", "reputation.jsonl");
59511
+ return path70.join(cwd, ".zelari", "reputation.jsonl");
59403
59512
  }
59404
59513
  async function appendRecord(storePath, record2) {
59405
- await mkdir3(path69.dirname(storePath), { recursive: true });
59514
+ await mkdir3(path70.dirname(storePath), { recursive: true });
59406
59515
  await appendFile2(storePath, `${JSON.stringify(record2)}
59407
59516
  `, "utf8");
59408
59517
  }
@@ -59802,7 +59911,7 @@ __export(executor_exports, {
59802
59911
  thoroughnessForKind: () => thoroughnessForKind
59803
59912
  });
59804
59913
  import { existsSync as existsSync44 } from "node:fs";
59805
- import path70 from "node:path";
59914
+ import path71 from "node:path";
59806
59915
  async function defaultSymbolExtractor(file2) {
59807
59916
  if (!isAstSupported(file2)) return null;
59808
59917
  const r = await parseFileSymbolsDiag(file2);
@@ -59868,7 +59977,7 @@ function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultC
59868
59977
  }
59869
59978
  function defaultChecksExists(cwd) {
59870
59979
  try {
59871
- return existsSync44(path70.join(cwd, ".zelari", "world", "checks.json"));
59980
+ return existsSync44(path71.join(cwd, ".zelari", "world", "checks.json"));
59872
59981
  } catch {
59873
59982
  return false;
59874
59983
  }
@@ -60376,7 +60485,7 @@ var init_executor = __esm({
60376
60485
  try {
60377
60486
  const summary = aggregate(
60378
60487
  records,
60379
- { repo: path70.basename(this.parentCwd), role: agentForNode(node) },
60488
+ { repo: path71.basename(this.parentCwd), role: agentForNode(node) },
60380
60489
  now
60381
60490
  );
60382
60491
  sample = summary.sample;
@@ -60853,7 +60962,7 @@ ${upstream}` : node.prompt,
60853
60962
  const model = res.ok && res.model && res.model !== "n/a" ? res.model : null;
60854
60963
  const reviewerVerdict = res.ok && this.isReviewerKind(node.kind) && typeof node.result === "string" && node.result.length > 0 ? parseVerifyVerdict(node.result).verdict : null;
60855
60964
  const record2 = reputationRecordFromNodeRun({
60856
- repo: path70.basename(this.parentCwd),
60965
+ repo: path71.basename(this.parentCwd),
60857
60966
  role: agentForNode(node),
60858
60967
  kind: node.kind,
60859
60968
  ok: res.ok,
@@ -61624,10 +61733,10 @@ var init_prereqChecks = __esm({
61624
61733
 
61625
61734
  // src/cli/plugins/prefs.ts
61626
61735
  import { existsSync as existsSync46, readFileSync as readFileSync36, writeFileSync as writeFileSync22, mkdirSync as mkdirSync18 } from "node:fs";
61627
- import path73 from "node:path";
61736
+ import path74 from "node:path";
61628
61737
  import os11 from "node:os";
61629
61738
  function getPluginPrefsPath() {
61630
- return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path73.join(os11.homedir(), ".tmp", "zelari-code", "plugins.json");
61739
+ return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path74.join(os11.homedir(), ".tmp", "zelari-code", "plugins.json");
61631
61740
  }
61632
61741
  function getPluginPrefs() {
61633
61742
  const file2 = getPluginPrefsPath();
@@ -61648,7 +61757,7 @@ function getPluginPrefs() {
61648
61757
  }
61649
61758
  function writePluginPrefs(prefs) {
61650
61759
  const file2 = getPluginPrefsPath();
61651
- mkdirSync18(path73.dirname(file2), { recursive: true });
61760
+ mkdirSync18(path74.dirname(file2), { recursive: true });
61652
61761
  writeFileSync22(file2, JSON.stringify(prefs, null, 2), {
61653
61762
  encoding: "utf-8",
61654
61763
  mode: 384
@@ -61685,7 +61794,7 @@ __export(registry_exports, {
61685
61794
  isBinaryOnPath: () => isBinaryOnPath
61686
61795
  });
61687
61796
  import { existsSync as existsSync47 } from "node:fs";
61688
- import path74 from "node:path";
61797
+ import path75 from "node:path";
61689
61798
  function detectLocalBin(bin) {
61690
61799
  return (cwd) => {
61691
61800
  try {
@@ -61703,7 +61812,7 @@ function isBinaryOnPath(bin, opts = {}) {
61703
61812
  const platform = opts.platform ?? process.platform;
61704
61813
  const exists = opts.exists ?? existsSync47;
61705
61814
  const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
61706
- const pathMod = platform === "win32" ? path74.win32 : path74.posix;
61815
+ const pathMod = platform === "win32" ? path75.win32 : path75.posix;
61707
61816
  const sep4 = platform === "win32" ? ";" : ":";
61708
61817
  const dirs = pathEnv.split(sep4).filter((d) => d.length > 0);
61709
61818
  const candidates = [bin];
@@ -62798,7 +62907,7 @@ var init_policy = __esm({
62798
62907
 
62799
62908
  // src/cli/orchestration/facts.ts
62800
62909
  import { promises as fs41 } from "node:fs";
62801
- import path79 from "node:path";
62910
+ import path80 from "node:path";
62802
62911
  async function collectRepoFileCount(root = process.cwd()) {
62803
62912
  try {
62804
62913
  await fs41.readdir(root);
@@ -62818,7 +62927,7 @@ async function collectRepoFileCount(root = process.cwd()) {
62818
62927
  }
62819
62928
  for (const e of entries) {
62820
62929
  if (e.isDirectory()) {
62821
- if (!SKIP_DIRS.has(e.name)) queue.push(path79.join(dir, e.name));
62930
+ if (!SKIP_DIRS.has(e.name)) queue.push(path80.join(dir, e.name));
62822
62931
  } else if (e.isFile()) {
62823
62932
  count++;
62824
62933
  if (count > MAX_WALK_FILES) return count;
@@ -62914,6 +63023,206 @@ var init_streamScrub = __esm({
62914
63023
  }
62915
63024
  });
62916
63025
 
63026
+ // src/cli/harnessState.ts
63027
+ import path81 from "node:path";
63028
+ function asString3(v) {
63029
+ return typeof v === "string" ? v : "";
63030
+ }
63031
+ function asNumber2(v) {
63032
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
63033
+ }
63034
+ function asCallId(v, seq) {
63035
+ return typeof v === "string" && v.length > 0 ? v : `seq:${seq}`;
63036
+ }
63037
+ function newTurn(index, userText) {
63038
+ return {
63039
+ index,
63040
+ userText: userText.length > 0 ? userText : void 0,
63041
+ toolCalls: 0,
63042
+ toolKinds: [],
63043
+ outcome: "pending",
63044
+ unsettledCallIds: /* @__PURE__ */ new Set(),
63045
+ settledCallIds: /* @__PURE__ */ new Set(),
63046
+ interrupted: 0,
63047
+ assistantMessages: 0
63048
+ };
63049
+ }
63050
+ function deriveHarnessState(events) {
63051
+ const session = {
63052
+ sessionId: events[events.length - 1]?.sessionId ?? "",
63053
+ status: "pending",
63054
+ lastSeq: 0
63055
+ };
63056
+ const support = { contextProjections: [], memoryEvents: 0, compactions: 0 };
63057
+ let tokensSaved;
63058
+ const acc = [];
63059
+ let current = null;
63060
+ for (const e of events) {
63061
+ session.lastSeq = e.seq;
63062
+ switch (e.kind) {
63063
+ case "session.started":
63064
+ session.startedAt ??= e.ts;
63065
+ break;
63066
+ case "session.ended": {
63067
+ session.endedAt = e.ts;
63068
+ const reason = asString3(e.data.reason);
63069
+ session.status = reason.length > 0 ? reason : "ended";
63070
+ if (current) {
63071
+ current.closedBy = "session-ended";
63072
+ current.endReason = reason;
63073
+ current = null;
63074
+ }
63075
+ break;
63076
+ }
63077
+ case "user.message": {
63078
+ if (current) current.closedBy = "next-turn";
63079
+ current = newTurn(acc.length + 1, asString3(e.data.text));
63080
+ acc.push(current);
63081
+ break;
63082
+ }
63083
+ case "assistant.message": {
63084
+ if (!current) break;
63085
+ current.assistantMessages += 1;
63086
+ const text = asString3(e.data.text);
63087
+ current.assistantChars = (current.assistantChars ?? 0) + text.length;
63088
+ current.assistantText = text;
63089
+ break;
63090
+ }
63091
+ case "tool.call": {
63092
+ if (!current) break;
63093
+ current.toolCalls += 1;
63094
+ const tool = asString3(e.data.tool);
63095
+ if (tool.length > 0 && !current.toolKinds.includes(tool)) current.toolKinds.push(tool);
63096
+ current.unsettledCallIds.add(asCallId(e.data.callId, e.seq));
63097
+ break;
63098
+ }
63099
+ case "tool.result": {
63100
+ if (!current) break;
63101
+ current.settledCallIds.add(asCallId(e.data.callId, e.seq));
63102
+ break;
63103
+ }
63104
+ case "tool.interrupted": {
63105
+ if (current) current.interrupted += 1;
63106
+ break;
63107
+ }
63108
+ case "verification.run": {
63109
+ if (!current) break;
63110
+ current.verification = {
63111
+ strict: e.data.strict === true,
63112
+ verdict: asString3(e.data.verdict) || "unknown"
63113
+ };
63114
+ break;
63115
+ }
63116
+ case "session.compacted": {
63117
+ support.compactions += 1;
63118
+ const saved = asNumber2(e.data.tokensSaved);
63119
+ if (saved !== void 0) tokensSaved = (tokensSaved ?? 0) + saved;
63120
+ break;
63121
+ }
63122
+ case "note": {
63123
+ const subject = asString3(e.data.subject);
63124
+ if (subject === "context.projection") {
63125
+ support.contextProjections.push({
63126
+ contextChars: asNumber2(e.data.contextChars) ?? 0,
63127
+ returnedCount: asNumber2(e.data.returnedCount) ?? 0
63128
+ });
63129
+ } else if (subject === "memory_event") {
63130
+ support.memoryEvents += 1;
63131
+ }
63132
+ break;
63133
+ }
63134
+ default:
63135
+ break;
63136
+ }
63137
+ }
63138
+ const turns = acc.map((t) => finalizeTurn(t));
63139
+ return {
63140
+ session,
63141
+ turns,
63142
+ execution: { turnsTotal: turns.length, contracts: acc.map((t) => contractFor(t)) },
63143
+ support: tokensSaved === void 0 ? support : { ...support, tokensSavedByCompaction: tokensSaved }
63144
+ };
63145
+ }
63146
+ function finalizeTurn(t) {
63147
+ let outcome;
63148
+ if (t.closedBy === void 0) outcome = "pending";
63149
+ else if (t.closedBy === "session-ended" && t.endReason !== "completed") outcome = "error";
63150
+ else outcome = "completed";
63151
+ return {
63152
+ index: t.index,
63153
+ userText: t.userText,
63154
+ assistantChars: t.assistantMessages > 0 ? t.assistantChars ?? 0 : void 0,
63155
+ assistantText: t.assistantMessages > 0 ? t.assistantText : void 0,
63156
+ toolCalls: t.toolCalls,
63157
+ toolKinds: t.toolKinds,
63158
+ verification: t.verification,
63159
+ outcome
63160
+ };
63161
+ }
63162
+ function contractFor(t) {
63163
+ const userMessage = true;
63164
+ const assistantReply = t.assistantMessages > 0;
63165
+ const allSettled = [...t.unsettledCallIds].every((id3) => t.settledCallIds.has(id3));
63166
+ const toolsSettled = allSettled && t.interrupted === 0;
63167
+ const blockers = [];
63168
+ if (!assistantReply) blockers.push("assistant-reply-missing");
63169
+ if (!toolsSettled) blockers.push("tools-unsettled");
63170
+ if (t.verification) {
63171
+ if (!t.verification.strict) blockers.push("verification-not-strict");
63172
+ else if (t.verification.verdict !== "PASS") blockers.push(`verification-verdict-${t.verification.verdict}`);
63173
+ } else if (t.closedBy === void 0) {
63174
+ blockers.push("turn-pending");
63175
+ } else if (t.closedBy === "session-ended" && t.endReason !== "completed") {
63176
+ blockers.push(`turn-error-${t.endReason}`);
63177
+ }
63178
+ return {
63179
+ turn: t.index,
63180
+ complete: userMessage && assistantReply && toolsSettled && blockers.length === 0,
63181
+ signals: {
63182
+ userMessage,
63183
+ assistantReply,
63184
+ toolsSettled,
63185
+ verification: t.verification
63186
+ },
63187
+ blockers
63188
+ };
63189
+ }
63190
+ async function readHarnessState(sessionDir) {
63191
+ const report = await readSessionLog(path81.join(sessionDir, "events.jsonl"));
63192
+ return deriveHarnessState(report.events);
63193
+ }
63194
+ var init_harnessState = __esm({
63195
+ "src/cli/harnessState.ts"() {
63196
+ "use strict";
63197
+ init_session();
63198
+ }
63199
+ });
63200
+
63201
+ // src/cli/headless/harnessStateEmit.ts
63202
+ import path82 from "node:path";
63203
+ async function emitHarnessStateEvent(opts) {
63204
+ if (opts.output !== "json") return;
63205
+ try {
63206
+ const sessionsDir = resolveSessionsDir({ workspaceRoot: opts.workspaceRoot });
63207
+ const state3 = await readHarnessState(path82.join(sessionsDir, opts.spine.sessionId));
63208
+ opts.emitEvent({ type: "harness_state", ...state3 });
63209
+ } catch (err) {
63210
+ const msg = err instanceof Error ? err.message : String(err);
63211
+ try {
63212
+ process.stderr.write(`[zelari-code --headless] harness_state unavailable: ${msg}
63213
+ `);
63214
+ } catch {
63215
+ }
63216
+ }
63217
+ }
63218
+ var init_harnessStateEmit = __esm({
63219
+ "src/cli/headless/harnessStateEmit.ts"() {
63220
+ "use strict";
63221
+ init_session();
63222
+ init_harnessState();
63223
+ }
63224
+ });
63225
+
62917
63226
  // src/cli/headless/policyGate.ts
62918
63227
  import { isAbsolute as isAbsolute5, resolve as resolve7 } from "node:path";
62919
63228
  import { randomUUID as randomUUID9 } from "node:crypto";
@@ -62959,7 +63268,7 @@ async function recordPolicyLoadBlockedOnSpine(block, opts = {}) {
62959
63268
  sessionId: sessionId2,
62960
63269
  ...opts.mode ? { mode: opts.mode } : {},
62961
63270
  ...opts.profile ? { profile: opts.profile } : {},
62962
- workspace: process.cwd()
63271
+ workspace: opts.workspace ?? process.cwd()
62963
63272
  });
62964
63273
  if (opts.mode === "zelari") {
62965
63274
  spine.missionPhase("dispatch", block.reason);
@@ -63390,13 +63699,13 @@ var init_sessionControl = __esm({
63390
63699
 
63391
63700
  // src/cli/extensions/sandboxedFs.ts
63392
63701
  import { promises as fsp } from "node:fs";
63393
- import path80 from "node:path";
63702
+ import path83 from "node:path";
63394
63703
  function errText(prefix, p3, err) {
63395
63704
  const msg = err instanceof Error ? err.message : String(err);
63396
63705
  return `[extension-fs] ${prefix} "${p3}": ${msg}`;
63397
63706
  }
63398
63707
  function bindSandboxedFs(root) {
63399
- const resolvedRoot = path80.resolve(root);
63708
+ const resolvedRoot = path83.resolve(root);
63400
63709
  return {
63401
63710
  root: resolvedRoot,
63402
63711
  async readFile(relativePath) {
@@ -63412,7 +63721,7 @@ function bindSandboxedFs(root) {
63412
63721
  try {
63413
63722
  const target = resolveSandboxedPath(relativePath, { root: resolvedRoot });
63414
63723
  verifyContainment(target, { root: resolvedRoot });
63415
- await fsp.mkdir(path80.dirname(target), { recursive: true });
63724
+ await fsp.mkdir(path83.dirname(target), { recursive: true });
63416
63725
  await fsp.writeFile(target, data, "utf8");
63417
63726
  return typedOk({ path: target });
63418
63727
  } catch (err) {
@@ -63597,7 +63906,7 @@ var init_loader = __esm({
63597
63906
 
63598
63907
  // src/cli/headless/runOneTurn.ts
63599
63908
  import { promises as fs42 } from "node:fs";
63600
- import path81 from "node:path";
63909
+ import path84 from "node:path";
63601
63910
  function planModeFromOpts(opts) {
63602
63911
  return (opts.phase ?? "build") === "plan";
63603
63912
  }
@@ -63651,11 +63960,14 @@ async function writeProofSafe(gate, meta3, baseDir = process.cwd()) {
63651
63960
  );
63652
63961
  }
63653
63962
  }
63654
- async function runOneTurn(opts, provider, model, providerStream) {
63963
+ async function runOneTurn(opts, provider, model, providerStream, extras) {
63655
63964
  const sessionId2 = crypto.randomUUID();
63656
63965
  const cwd = resolveHeadlessCwd(opts);
63657
63966
  const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
63658
- const nativeMemory = memoryFactory.isMemoryV2Enabled() ? await memoryFactory.getMemoryService(cwd, process.env) : void 0;
63967
+ const spineHolder = {};
63968
+ const nativeMemory = memoryFactory.isMemoryV2Enabled() ? await memoryFactory.getMemoryService(cwd, process.env, {
63969
+ onEvent: memorySinkFor(spineHolder)
63970
+ }) : void 0;
63659
63971
  const memoryAutoWrite = memoryFactory.isMemoryAutoWriteEnabled();
63660
63972
  const controlQueue = new RuntimeControlQueue();
63661
63973
  const harnessHolder = {};
@@ -63748,7 +64060,11 @@ async function runOneTurn(opts, provider, model, providerStream) {
63748
64060
  },
63749
64061
  ...nativeMemory ? { memoryService: nativeMemory } : {},
63750
64062
  memoryAutoWrite,
63751
- ...extensionRuntime ? { extensions: extensionRuntime } : {}
64063
+ ...extensionRuntime ? { extensions: extensionRuntime } : {},
64064
+ // t37: serve-harness threads the kernel-owned workspace LspManager here
64065
+ // (TurnExtras). undefined keeps the shared per-root fallback — which is
64066
+ // itself one-manager-per-root since t37, so no cross-workspace thrash.
64067
+ ...extras?.lspProvider ? { lspProvider: extras.lspProvider } : {}
63752
64068
  });
63753
64069
  await registerHeadlessMcp(toolRegistry, opts);
63754
64070
  const spine = await openHeadlessSpine({
@@ -63759,6 +64075,7 @@ async function runOneTurn(opts, provider, model, providerStream) {
63759
64075
  // 2.6.1 (plan §7): deep specs from THIS run’s registry.
63760
64076
  toolSpecs: typeof toolRegistry.fingerprints === "function" ? toolRegistry.fingerprints() : void 0
63761
64077
  });
64078
+ spineHolder.current = spine;
63762
64079
  const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
63763
64080
  emitEvent(sessionStartedEvent(spine));
63764
64081
  if (opts.orchestrationDecision) {
@@ -64067,8 +64384,9 @@ async function runOneTurn(opts, provider, model, providerStream) {
64067
64384
  },
64068
64385
  emit: (input) => spine.appendEvent(input)
64069
64386
  };
64387
+ const strictEnv = strictEnvOverlay(opts);
64070
64388
  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 });
64389
+ const strictGate = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd, env: strictEnv });
64072
64390
  await runAdvisoryVerifierReview(strictGate, verifierReviewDeps).catch(() => void 0);
64073
64391
  const gate = strictGate.gate;
64074
64392
  const verificationPayload = strictGateEventPayload(strictGate);
@@ -64103,7 +64421,7 @@ async function runOneTurn(opts, provider, model, providerStream) {
64103
64421
  successfulWrites: pass.successfulWrites + repair.successfulWrites,
64104
64422
  emittedWrites: pass.emittedWrites + repair.emittedWrites
64105
64423
  };
64106
- const after = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd });
64424
+ const after = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd, env: strictEnv });
64107
64425
  await runAdvisoryVerifierReview(after, verifierReviewDeps).catch(() => void 0);
64108
64426
  const afterPayload = strictGateEventPayload(after);
64109
64427
  spine.verificationRun(afterPayload);
@@ -64138,13 +64456,14 @@ async function runOneTurn(opts, provider, model, providerStream) {
64138
64456
  await spine.close(closeStatus);
64139
64457
  } catch {
64140
64458
  }
64459
+ await emitHarnessStateEvent({ spine, workspaceRoot: cwd, output: opts.output, emitEvent });
64141
64460
  if (opts.exportSessionPath) {
64142
64461
  try {
64143
64462
  const json3 = await spine.exportJson();
64144
64463
  if (json3) {
64145
64464
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
64146
64465
  else {
64147
- await fs42.mkdir(path81.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
64466
+ await fs42.mkdir(path84.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
64148
64467
  await fs42.writeFile(opts.exportSessionPath, json3, "utf8");
64149
64468
  }
64150
64469
  }
@@ -64200,6 +64519,7 @@ var init_runOneTurn = __esm({
64200
64519
  init_selectionPlaybook();
64201
64520
  init_delegationPolicy();
64202
64521
  init_facts();
64522
+ init_spineTelemetry();
64203
64523
  init_headless();
64204
64524
  init_mode();
64205
64525
  init_skills2();
@@ -64213,6 +64533,7 @@ var init_runOneTurn = __esm({
64213
64533
  init_modelContextBuilder();
64214
64534
  init_metrics3();
64215
64535
  init_headlessSpine();
64536
+ init_harnessStateEmit();
64216
64537
  init_runtime2();
64217
64538
  init_controlBridge();
64218
64539
  init_protocol2();
@@ -65118,9 +65439,9 @@ __export(triggerLock_exports, {
65118
65439
  releaseLock: () => releaseLock
65119
65440
  });
65120
65441
  import { promises as fs43 } from "node:fs";
65121
- import * as path82 from "node:path";
65442
+ import * as path85 from "node:path";
65122
65443
  function lockPath(projectRoot) {
65123
- return path82.join(projectRoot, ".zelari", "trigger.lock");
65444
+ return path85.join(projectRoot, ".zelari", "trigger.lock");
65124
65445
  }
65125
65446
  function isPidAlive(pid) {
65126
65447
  try {
@@ -65133,7 +65454,7 @@ function isPidAlive(pid) {
65133
65454
  }
65134
65455
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
65135
65456
  const lp = lockPath(projectRoot);
65136
- const dir = path82.dirname(lp);
65457
+ const dir = path85.dirname(lp);
65137
65458
  await fs43.mkdir(dir, { recursive: true });
65138
65459
  try {
65139
65460
  const raw = await fs43.readFile(lp, "utf8");
@@ -65165,13 +65486,10 @@ var init_triggerLock = __esm({
65165
65486
 
65166
65487
  // src/cli/runHeadless.ts
65167
65488
  import { promises as fs44 } from "node:fs";
65168
- import path83 from "node:path";
65489
+ import path86 from "node:path";
65169
65490
  import { randomUUID as randomUUID10 } from "node:crypto";
65170
65491
  async function runHeadless(opts) {
65171
65492
  resetTaskSpawnCount();
65172
- if (opts.strictDone) {
65173
- process.env.ZELARI_STRICT_DONE = "1";
65174
- }
65175
65493
  let crashed = false;
65176
65494
  const handleFatal = (label, err) => {
65177
65495
  if (crashed) return;
@@ -65245,7 +65563,13 @@ ${err.stack}` : "";
65245
65563
  model
65246
65564
  });
65247
65565
  }
65248
- return dispatchHeadlessTurn(opts, provider, model, providerStream);
65566
+ return dispatchHeadlessTurn(opts, provider, model, providerStream, {
65567
+ // H10-fix3: the gate already ran above on the SAME input (no chdir in
65568
+ // between) — the one-shot marker keeps dispatchHeadlessTurn from
65569
+ // re-running it (duplicate `[policy]` stderr warning + double policy
65570
+ // load). Per-invocation flag only; never process-global.
65571
+ policyGateDone: true
65572
+ });
65249
65573
  }
65250
65574
  async function applyHeadlessPolicyGate(opts) {
65251
65575
  const cwd = resolveHeadlessCwd(opts);
@@ -65257,6 +65581,9 @@ async function applyHeadlessPolicyGate(opts) {
65257
65581
  reportPolicyLoadBlocked(policyLoad.block, opts.output);
65258
65582
  await recordPolicyLoadBlockedOnSpine(policyLoad.block, {
65259
65583
  mode: opts.mode,
65584
+ // H10-fix2: the spine must land in the RESOLVED workspace, not the
65585
+ // process cwd — a sidecar hosts N workspaces without `chdir`.
65586
+ workspace: cwd,
65260
65587
  ...opts.profile ? { profile: opts.profile } : {},
65261
65588
  ...opts.resumeSessionId ? { resumeSessionId: opts.resumeSessionId } : {}
65262
65589
  });
@@ -65276,7 +65603,7 @@ function applyKrakenTurnEnv(opts) {
65276
65603
  }
65277
65604
  }
65278
65605
  }
65279
- async function dispatchHeadlessTurn(opts, provider, model, providerStream) {
65606
+ async function dispatchHeadlessTurn(opts, provider, model, providerStream, oneShot, extras) {
65280
65607
  const cwd = resolveHeadlessCwd(opts);
65281
65608
  if (typeof opts.mode === "string") {
65282
65609
  const parsed = parseMode(opts.mode);
@@ -65304,8 +65631,10 @@ async function dispatchHeadlessTurn(opts, provider, model, providerStream) {
65304
65631
  }
65305
65632
  } catch {
65306
65633
  }
65307
- const policyBlock = await applyHeadlessPolicyGate(opts);
65308
- if (policyBlock !== void 0) return policyBlock;
65634
+ if (!oneShot?.policyGateDone) {
65635
+ const policyBlock = await applyHeadlessPolicyGate(opts);
65636
+ if (policyBlock !== void 0) return policyBlock;
65637
+ }
65309
65638
  if (opts.orchestrationAuto) {
65310
65639
  const facts = await collectOrchestrationFacts(cwd);
65311
65640
  const verdict = chooseOrchestration(opts.task ?? "", facts);
@@ -65347,12 +65676,12 @@ async function dispatchHeadlessTurn(opts, provider, model, providerStream) {
65347
65676
  `);
65348
65677
  }
65349
65678
  if (mode === "zelari") {
65350
- return runHeadlessZelari(opts, provider, model, providerStream);
65679
+ return runHeadlessZelari(opts, provider, model, providerStream, extras);
65351
65680
  }
65352
65681
  if (mode === "council" || opts.useCouncil) {
65353
- return runHeadlessCouncil(opts, provider, model, providerStream);
65682
+ return runHeadlessCouncil(opts, provider, model, providerStream, extras);
65354
65683
  }
65355
- return runOneTurn(opts, provider, model, providerStream);
65684
+ return runOneTurn(opts, provider, model, providerStream, extras);
65356
65685
  }
65357
65686
  async function runHeadlessKrakenGraph(opts, provider, model) {
65358
65687
  const { isKrakenGraphEnabled: isKrakenGraphEnabled2, KrakenGraphExecutor: KrakenGraphExecutor2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
@@ -65372,8 +65701,15 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
65372
65701
  const { createKrakenSubAgentContextFactory: createKrakenSubAgentContextFactory2 } = await Promise.resolve().then(() => (init_toolRegistry(), toolRegistry_exports));
65373
65702
  const cwd = resolveHeadlessCwd(opts);
65374
65703
  const sessionId2 = crypto.randomUUID();
65704
+ const spine = await openHeadlessSpine({ sessionId: sessionId2, mode: "kraken", workspace: cwd });
65705
+ if (opts.output === "json") emitEvent(sessionStartedEvent(spine));
65706
+ spine.userMessage(prompt);
65375
65707
  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;
65708
+ const graphMemory = isMemoryV2Enabled2() ? await getMemoryService2(cwd, process.env, {
65709
+ // W2: the spine is already open here — memory events are noted
65710
+ // directly (context.projection / memory_event state-only payloads).
65711
+ onEvent: (event) => spineMemoryEventNote(spine, event)
65712
+ }) : void 0;
65377
65713
  const log = (message) => {
65378
65714
  if (opts.output === "json") {
65379
65715
  emitEvent({ type: "log", message });
@@ -65388,28 +65724,32 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
65388
65724
  abort.abort();
65389
65725
  };
65390
65726
  process.once("SIGINT", onSigint);
65727
+ let exitCode = 0;
65391
65728
  try {
65392
65729
  let preflightGraph;
65393
65730
  if (opts.runPlan && opts.runPlan.trim() !== "") {
65394
- const planPath = path83.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
65731
+ const planPath = path86.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
65395
65732
  log(`loading pre-flight plan: ${planPath}`);
65396
65733
  let raw;
65397
65734
  try {
65398
65735
  raw = await fs44.readFile(planPath, "utf8");
65399
65736
  } catch (e) {
65400
65737
  log(`plan file not found: ${planPath} (${e.message})`);
65401
- return 1;
65738
+ exitCode = 1;
65739
+ return exitCode;
65402
65740
  }
65403
65741
  let planJson;
65404
65742
  try {
65405
65743
  planJson = JSON.parse(raw);
65406
65744
  } catch (e) {
65407
65745
  log(`plan file is malformed JSON: ${e.message}`);
65408
- return 1;
65746
+ exitCode = 1;
65747
+ return exitCode;
65409
65748
  }
65410
65749
  if (!planJson || !Array.isArray(planJson.nodes)) {
65411
65750
  log(`plan file is malformed: missing "nodes" array`);
65412
- return 1;
65751
+ exitCode = 1;
65752
+ return exitCode;
65413
65753
  }
65414
65754
  const { createGraph: createGraph2, validateGraph: validateGraph2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
65415
65755
  const validated = createGraph2(planJson.graphId ?? opts.runPlan, planJson.nodes);
@@ -65431,8 +65771,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
65431
65771
  log(formatKrakenGraphAscii2(graph));
65432
65772
  if (opts.planOnly) {
65433
65773
  const planId = randomUUID10();
65434
- const planDir = path83.join(cwd, ".zelari", "radio");
65435
- const planPath = path83.join(planDir, `plan-${planId}.json`);
65774
+ const planDir = path86.join(cwd, ".zelari", "radio");
65775
+ const planPath = path86.join(planDir, `plan-${planId}.json`);
65436
65776
  await fs44.mkdir(planDir, { recursive: true });
65437
65777
  await fs44.writeFile(
65438
65778
  planPath,
@@ -65451,9 +65791,11 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
65451
65791
  emitEvent({ type: "log", message: `plan_only_id=${planId}` });
65452
65792
  emitEvent({ type: "log", message: `plan_only_path=${planPath}` });
65453
65793
  }
65454
- return 0;
65794
+ exitCode = 0;
65795
+ return exitCode;
65455
65796
  }
65456
65797
  const audit = new AuditLogger2();
65798
+ const { runTentacle: runTentacle2 } = await Promise.resolve().then(() => (init_tentacle(), tentacle_exports));
65457
65799
  const executor = new KrakenGraphExecutor2({
65458
65800
  taskToolDeps: {
65459
65801
  createSubAgentContext: createKrakenSubAgentContextFactory2({
@@ -65486,7 +65828,11 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
65486
65828
  parentCwd: cwd,
65487
65829
  sessionId: sessionId2,
65488
65830
  goal: prompt,
65489
- signal: abort.signal
65831
+ signal: abort.signal,
65832
+ // ADR-0024 v1.1: same delegate (`runTentacle`), wrapped so each node
65833
+ // turn leaves a graph.node_started / graph.node_ended envelope pair on
65834
+ // the spine. The executor owns scheduling; the HOST owns the spine.
65835
+ runTentacleFn: (runOpts) => nodeSpineEnvelopeRun(spine, runOpts, () => runTentacle2(runOpts))
65490
65836
  });
65491
65837
  const summary = await executor.execute(graph);
65492
65838
  if (summary.cancelled) log("graph cancelled \u2014 partial results below");
@@ -65508,7 +65854,8 @@ ${formatKrakenGraphDigest2(
65508
65854
  process.stdout.write(`${finalAscii}
65509
65855
  `);
65510
65856
  }
65511
- return summary.converged ? 0 : 3;
65857
+ exitCode = summary.converged ? 0 : 3;
65858
+ return exitCode;
65512
65859
  } catch (err) {
65513
65860
  const message = err instanceof Error ? err.message : String(err);
65514
65861
  if (opts.output === "json") {
@@ -65517,17 +65864,56 @@ ${formatKrakenGraphDigest2(
65517
65864
  process.stderr.write(`[zelari-code --headless] kraken graph failed: ${message}
65518
65865
  `);
65519
65866
  }
65520
- return 2;
65867
+ exitCode = 2;
65868
+ return exitCode;
65521
65869
  } finally {
65522
65870
  process.off("SIGINT", onSigint);
65523
65871
  await graphMemory?.close().catch(() => void 0);
65872
+ try {
65873
+ const closeReason = abort.signal.aborted ? "cancelled" : exitCode === 0 ? "completed" : "error";
65874
+ await spine.close(closeReason);
65875
+ } catch {
65876
+ }
65877
+ await emitHarnessStateEvent({ spine, workspaceRoot: cwd, output: opts.output, emitEvent });
65524
65878
  }
65525
65879
  }
65526
- async function buildCouncilToolRegistry(planMode, opts, memoryService, memoryAutoWrite = false) {
65880
+ function nodeSpineEnvelopeRun(spine, runOpts, run) {
65881
+ const startedAt = Date.now();
65882
+ const noteNode = (kind2, extra) => {
65883
+ if (!runOpts.nodeId) return;
65884
+ void spine.appendEvent({
65885
+ kind: kind2,
65886
+ actor: { type: "system" },
65887
+ data: {
65888
+ nodeId: runOpts.nodeId,
65889
+ agent: runOpts.agent,
65890
+ ...runOpts.graphId ? { graphId: runOpts.graphId } : {},
65891
+ ...extra
65892
+ }
65893
+ });
65894
+ };
65895
+ noteNode("graph.node_started");
65896
+ return run().then(
65897
+ (res) => {
65898
+ noteNode("graph.node_ended", {
65899
+ ok: res.ok,
65900
+ ...!res.ok && res.cancelled ? { cancelled: true } : {},
65901
+ durationMs: Date.now() - startedAt
65902
+ });
65903
+ return res;
65904
+ },
65905
+ (err) => {
65906
+ noteNode("graph.node_ended", { ok: false, durationMs: Date.now() - startedAt });
65907
+ throw err;
65908
+ }
65909
+ );
65910
+ }
65911
+ async function buildCouncilToolRegistry(planMode, opts, memoryService, memoryAutoWrite = false, extras) {
65527
65912
  const cwd = opts ? resolveHeadlessCwd(opts) : process.cwd();
65528
65913
  const { registry: toolRegistry } = createBuiltinToolRegistry({
65529
65914
  root: cwd,
65530
65915
  planMode,
65916
+ ...extras?.lspProvider ? { lspProvider: extras.lspProvider } : {},
65531
65917
  permissionPolicy: {
65532
65918
  read: "allow",
65533
65919
  write: "allow",
@@ -65554,12 +65940,15 @@ async function buildCouncilToolRegistry(planMode, opts, memoryService, memoryAut
65554
65940
  }
65555
65941
  return { toolRegistry, workspaceCtx: realCtx };
65556
65942
  }
65557
- async function runHeadlessCouncil(opts, provider, model, providerStream) {
65943
+ async function runHeadlessCouncil(opts, provider, model, providerStream, extras) {
65558
65944
  const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
65559
65945
  const sessionId2 = crypto.randomUUID();
65560
65946
  const cwd = resolveHeadlessCwd(opts);
65561
65947
  const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
65562
- const nativeMemory = memoryFactory.isMemoryV2Enabled() ? await memoryFactory.getMemoryService(cwd, process.env) : void 0;
65948
+ const spineHolder = {};
65949
+ const nativeMemory = memoryFactory.isMemoryV2Enabled() ? await memoryFactory.getMemoryService(cwd, process.env, {
65950
+ onEvent: memorySinkFor(spineHolder)
65951
+ }) : void 0;
65563
65952
  const memoryAutoWrite = memoryFactory.isMemoryAutoWriteEnabled();
65564
65953
  const spine = await openHeadlessSpine({
65565
65954
  sessionId: opts.resumeSessionId ?? sessionId2,
@@ -65567,6 +65956,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
65567
65956
  profile: opts.profile,
65568
65957
  workspace: cwd
65569
65958
  });
65959
+ spineHolder.current = spine;
65570
65960
  const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
65571
65961
  emitEvent(sessionStartedEvent(spine));
65572
65962
  if (opts.orchestrationDecision) {
@@ -65586,7 +65976,8 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
65586
65976
  planModeFromOpts(opts) || softGated,
65587
65977
  opts,
65588
65978
  nativeMemory,
65589
- memoryAutoWrite
65979
+ memoryAutoWrite,
65980
+ extras
65590
65981
  );
65591
65982
  const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
65592
65983
  const feedbackStore = new FeedbackStore2();
@@ -65715,13 +66106,14 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
65715
66106
  await spine.close(exitCode === 0 ? "completed" : "error");
65716
66107
  } catch {
65717
66108
  }
66109
+ await emitHarnessStateEvent({ spine, workspaceRoot: cwd, output: opts.output, emitEvent });
65718
66110
  if (opts.exportSessionPath) {
65719
66111
  try {
65720
66112
  const json3 = await spine.exportJson();
65721
66113
  if (json3) {
65722
66114
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
65723
66115
  else {
65724
- await fs44.mkdir(path83.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
66116
+ await fs44.mkdir(path86.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
65725
66117
  await fs44.writeFile(opts.exportSessionPath, json3, "utf8");
65726
66118
  }
65727
66119
  }
@@ -65754,7 +66146,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
65754
66146
  await nativeMemory?.close().catch(() => void 0);
65755
66147
  return exitCode;
65756
66148
  }
65757
- async function runHeadlessZelari(opts, provider, model, providerStream) {
66149
+ async function runHeadlessZelari(opts, provider, model, providerStream, extras) {
65758
66150
  const projectRoot = resolveHeadlessCwd(opts);
65759
66151
  const sessionId2 = opts.resumeSessionId ?? crypto.randomUUID();
65760
66152
  const spine = await openHeadlessSpine({
@@ -65777,13 +66169,18 @@ async function runHeadlessZelari(opts, provider, model, providerStream) {
65777
66169
  userMessage: opts.task,
65778
66170
  hasPlan: hasWorkspacePlan2(projectRoot)
65779
66171
  });
65780
- const memory = await getMemoryBackend2(projectRoot);
66172
+ const memory = await getMemoryBackend2(
66173
+ projectRoot,
66174
+ process.env,
66175
+ (event) => spineMemoryEventNote(spine, event)
66176
+ );
65781
66177
  const nativeMissionMemory = memory.service;
65782
66178
  const { toolRegistry, workspaceCtx } = await buildCouncilToolRegistry(
65783
66179
  planModeFromOpts(opts),
65784
66180
  opts,
65785
66181
  nativeMissionMemory,
65786
- Boolean(nativeMissionMemory) && process.env.ZELARI_MEMORY_AUTO_WRITE !== "0"
66182
+ Boolean(nativeMissionMemory) && process.env.ZELARI_MEMORY_AUTO_WRITE !== "0",
66183
+ extras
65787
66184
  );
65788
66185
  const feedbackStore = new FeedbackStore2();
65789
66186
  const chairmanBudget = envNumber(process.env.ZELARI_MODE_MAX_TOOLS_LUCIFER, {
@@ -66096,6 +66493,8 @@ ${ragContext}` : slicePrompt;
66096
66493
  const missionGate = await evaluateStrictBuildGate("build", {
66097
66494
  emit: (input) => spine.appendEvent(input),
66098
66495
  surface: "mission",
66496
+ // H10-fix1: per-invocation env overlay — never process.env.
66497
+ env: strictEnvOverlay(opts),
66099
66498
  cwd: projectRoot
66100
66499
  });
66101
66500
  const missionVerificationPayload = strictGateEventPayload(missionGate);
@@ -66132,13 +66531,14 @@ ${ragContext}` : slicePrompt;
66132
66531
  else await spine.close(exitCode === 2 ? "error" : "stopped");
66133
66532
  } catch {
66134
66533
  }
66534
+ await emitHarnessStateEvent({ spine, workspaceRoot: projectRoot, output: opts.output, emitEvent });
66135
66535
  if (opts.exportSessionPath) {
66136
66536
  try {
66137
66537
  const json3 = await spine.exportJson();
66138
66538
  if (json3) {
66139
66539
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
66140
66540
  else {
66141
- await fs44.mkdir(path83.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
66541
+ await fs44.mkdir(path86.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
66142
66542
  await fs44.writeFile(opts.exportSessionPath, json3, "utf8");
66143
66543
  }
66144
66544
  }
@@ -66157,6 +66557,7 @@ var init_runHeadless = __esm({
66157
66557
  init_toolRegistry();
66158
66558
  init_policy();
66159
66559
  init_facts();
66560
+ init_spineTelemetry();
66160
66561
  init_councilConfig();
66161
66562
  init_headless();
66162
66563
  init_claudeProvider();
@@ -66172,6 +66573,7 @@ var init_runHeadless = __esm({
66172
66573
  init_modelContextBuilder();
66173
66574
  init_metrics3();
66174
66575
  init_headlessSpine();
66576
+ init_harnessStateEmit();
66175
66577
  init_policyGate();
66176
66578
  init_policyLoadMode();
66177
66579
  init_runOneTurn();
@@ -66749,7 +67151,7 @@ function upsertSkill(opts) {
66749
67151
  }
66750
67152
  dir = getProjectSkillsDir(root);
66751
67153
  }
66752
- const path87 = skillFilePath(dir, name);
67154
+ const path91 = skillFilePath(dir, name);
66753
67155
  const content = serializeSkillMd({
66754
67156
  name,
66755
67157
  description,
@@ -66758,13 +67160,13 @@ function upsertSkill(opts) {
66758
67160
  tools: opts.tools,
66759
67161
  cost: opts.cost
66760
67162
  });
66761
- const parsed = parseSkillMd(content, path87);
67163
+ const parsed = parseSkillMd(content, path91);
66762
67164
  if (!parsed) {
66763
67165
  return { ok: false, error: "Generated SKILL.md failed validation" };
66764
67166
  }
66765
- mkdirSync21(dirname13(path87), { recursive: true });
66766
- writeFileSync24(path87, content, "utf8");
66767
- return { ok: true, path: path87 };
67167
+ mkdirSync21(dirname13(path91), { recursive: true });
67168
+ writeFileSync24(path91, content, "utf8");
67169
+ return { ok: true, path: path91 };
66768
67170
  }
66769
67171
  function removeSkill(opts) {
66770
67172
  const name = opts.name.trim().toLowerCase();
@@ -66782,8 +67184,8 @@ function removeSkill(opts) {
66782
67184
  dir = getProjectSkillsDir(root);
66783
67185
  }
66784
67186
  const skillDir = join46(dir, name);
66785
- const path87 = skillFilePath(dir, name);
66786
- if (!existsSync52(path87) && !existsSync52(skillDir)) {
67187
+ const path91 = skillFilePath(dir, name);
67188
+ if (!existsSync52(path91) && !existsSync52(skillDir)) {
66787
67189
  return { ok: false, error: `Skill "${name}" not found in ${dir}` };
66788
67190
  }
66789
67191
  try {
@@ -66794,7 +67196,7 @@ function removeSkill(opts) {
66794
67196
  error: err instanceof Error ? err.message : String(err)
66795
67197
  };
66796
67198
  }
66797
- return { ok: true, path: path87 };
67199
+ return { ok: true, path: path91 };
66798
67200
  }
66799
67201
  var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
66800
67202
  var init_skillConfigIo = __esm({
@@ -66913,7 +67315,7 @@ var init_jsonApi = __esm({
66913
67315
  });
66914
67316
 
66915
67317
  // src/cli/memory/mcpAdapter.ts
66916
- import * as path84 from "node:path";
67318
+ import * as path87 from "node:path";
66917
67319
  var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
66918
67320
  var init_mcpAdapter = __esm({
66919
67321
  "src/cli/memory/mcpAdapter.ts"() {
@@ -67083,8 +67485,8 @@ var init_mcpAdapter = __esm({
67083
67485
  this.takeWrite();
67084
67486
  const externalFile = args.source?.file;
67085
67487
  if (externalFile) {
67086
- const normalized = path84.normalize(externalFile);
67087
- if (path84.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path84.sep}`)) {
67488
+ const normalized = path87.normalize(externalFile);
67489
+ if (path87.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path87.sep}`)) {
67088
67490
  throw new Error("source.file must be project-relative and cannot escape the project");
67089
67491
  }
67090
67492
  }
@@ -67612,12 +68014,12 @@ function ensureHome() {
67612
68014
  }
67613
68015
  }
67614
68016
  function loadCompanionConfig() {
67615
- const path87 = getCompanionConfigPath();
67616
- if (!existsSync53(path87)) {
68017
+ const path91 = getCompanionConfigPath();
68018
+ if (!existsSync53(path91)) {
67617
68019
  return { projects: [] };
67618
68020
  }
67619
68021
  try {
67620
- const raw = JSON.parse(readFileSync41(path87, "utf8"));
68022
+ const raw = JSON.parse(readFileSync41(path91, "utf8"));
67621
68023
  const projects = Array.isArray(raw.projects) ? raw.projects.filter(
67622
68024
  (p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
67623
68025
  ).map((p3) => ({
@@ -67655,16 +68057,16 @@ function loadOrCreateToken(explicit) {
67655
68057
  return { token: explicit.trim(), created: false };
67656
68058
  }
67657
68059
  ensureHome();
67658
- const path87 = getCompanionTokenPath();
67659
- if (existsSync53(path87)) {
67660
- const t = readFileSync41(path87, "utf8").trim();
68060
+ const path91 = getCompanionTokenPath();
68061
+ if (existsSync53(path91)) {
68062
+ const t = readFileSync41(path91, "utf8").trim();
67661
68063
  if (t) return { token: t, created: false };
67662
68064
  }
67663
68065
  const token = randomBytes7(24).toString("base64url");
67664
- writeFileSync25(path87, token + "\n", "utf8");
68066
+ writeFileSync25(path91, token + "\n", "utf8");
67665
68067
  try {
67666
68068
  const fs45 = __require("node:fs");
67667
- fs45.chmodSync?.(path87, 384);
68069
+ fs45.chmodSync?.(path91, 384);
67668
68070
  } catch {
67669
68071
  }
67670
68072
  return { token, created: true };
@@ -67689,17 +68091,17 @@ function mergeProjects(cfg, extraPaths) {
67689
68091
  byId.set(p3.id, p3);
67690
68092
  }
67691
68093
  for (const raw of extraPaths) {
67692
- const path87 = raw.trim();
67693
- if (!path87) continue;
67694
- let id3 = slugFromPath(path87);
68094
+ const path91 = raw.trim();
68095
+ if (!path91) continue;
68096
+ let id3 = slugFromPath(path91);
67695
68097
  let n = 2;
67696
- while (byId.has(id3) && byId.get(id3).path !== path87) {
67697
- id3 = `${slugFromPath(path87)}-${n++}`;
68098
+ while (byId.has(id3) && byId.get(id3).path !== path91) {
68099
+ id3 = `${slugFromPath(path91)}-${n++}`;
67698
68100
  }
67699
68101
  byId.set(id3, {
67700
68102
  id: id3,
67701
- name: slugFromPath(path87),
67702
- path: path87
68103
+ name: slugFromPath(path91),
68104
+ path: path91
67703
68105
  });
67704
68106
  }
67705
68107
  return [...byId.values()];
@@ -67752,6 +68154,7 @@ __export(harnessServer_exports, {
67752
68154
  bindHarnessTurnOptions: () => bindHarnessTurnOptions,
67753
68155
  createCliRunTurn: () => createCliRunTurn,
67754
68156
  createCliWorkspaceServices: () => createCliWorkspaceServices,
68157
+ resolveTurnLspProvider: () => resolveTurnLspProvider,
67755
68158
  runHarnessServer: () => runHarnessServer,
67756
68159
  startHarnessServer: () => startHarnessServer
67757
68160
  });
@@ -67797,6 +68200,10 @@ function bindHarnessTurnOptions(input, workspaceRoot) {
67797
68200
  useCouncil: turnInput.useCouncil === true || mode === "council"
67798
68201
  };
67799
68202
  }
68203
+ function resolveTurnLspProvider(services) {
68204
+ const candidate = services?.lspManager;
68205
+ return candidate instanceof LspManager ? candidate : void 0;
68206
+ }
67800
68207
  function createCliRunTurn() {
67801
68208
  let streamPromise = null;
67802
68209
  const ensureStream = () => {
@@ -67823,11 +68230,14 @@ function createCliRunTurn() {
67823
68230
  return async (input, deps) => {
67824
68231
  const { provider, model, stream } = await ensureStream();
67825
68232
  const opts = bindHarnessTurnOptions(input, deps.session.workspaceRoot);
68233
+ const lspProvider = resolveTurnLspProvider(deps.services);
67826
68234
  const exitCode = await dispatchHeadlessTurn(
67827
68235
  opts,
67828
68236
  provider,
67829
68237
  model,
67830
- stream
68238
+ stream,
68239
+ void 0,
68240
+ lspProvider ? { lspProvider } : void 0
67831
68241
  );
67832
68242
  return { exitCode };
67833
68243
  };
@@ -68666,9 +69076,9 @@ async function runCompanionServe(opts = {}) {
68666
69076
  return;
68667
69077
  }
68668
69078
  const url2 = parseUrl(req);
68669
- const path87 = url2.pathname.replace(/\/+$/, "") || "/";
69079
+ const path91 = url2.pathname.replace(/\/+$/, "") || "/";
68670
69080
  try {
68671
- if (req.method === "GET" && (path87 === "/health" || path87 === "/v1/health")) {
69081
+ if (req.method === "GET" && (path91 === "/health" || path91 === "/v1/health")) {
68672
69082
  sendJson2(res, 200, {
68673
69083
  ok: true,
68674
69084
  service: "zelari-companion",
@@ -68680,18 +69090,18 @@ async function runCompanionServe(opts = {}) {
68680
69090
  });
68681
69091
  return;
68682
69092
  }
68683
- if (path87.startsWith("/v1")) {
69093
+ if (path91.startsWith("/v1")) {
68684
69094
  if (!tokenMatches(token, getBearer(req))) {
68685
69095
  sendJson2(res, 401, { ok: false, error: "unauthorized" });
68686
69096
  return;
68687
69097
  }
68688
69098
  }
68689
- if (req.method === "GET" && path87 === "/v1/config") {
69099
+ if (req.method === "GET" && path91 === "/v1/config") {
68690
69100
  const snap = buildDesktopConfigSnapshot();
68691
69101
  sendJson2(res, 200, { ok: true, ...snap });
68692
69102
  return;
68693
69103
  }
68694
- if (req.method === "GET" && path87 === "/v1/projects") {
69104
+ if (req.method === "GET" && path91 === "/v1/projects") {
68695
69105
  sendJson2(res, 200, {
68696
69106
  ok: true,
68697
69107
  projects: projects.map((p3) => ({
@@ -68702,7 +69112,7 @@ async function runCompanionServe(opts = {}) {
68702
69112
  });
68703
69113
  return;
68704
69114
  }
68705
- if (req.method === "GET" && path87 === "/v1/runs") {
69115
+ if (req.method === "GET" && path91 === "/v1/runs") {
68706
69116
  sendJson2(res, 200, {
68707
69117
  ok: true,
68708
69118
  active: runs.getActive(),
@@ -68720,7 +69130,7 @@ async function runCompanionServe(opts = {}) {
68720
69130
  });
68721
69131
  return;
68722
69132
  }
68723
- if (req.method === "POST" && path87 === "/v1/runs") {
69133
+ if (req.method === "POST" && path91 === "/v1/runs") {
68724
69134
  const raw = await readBody(req);
68725
69135
  let body = {};
68726
69136
  try {
@@ -68763,11 +69173,12 @@ async function runCompanionServe(opts = {}) {
68763
69173
  createdAt: result.run.createdAt
68764
69174
  },
68765
69175
  eventsUrl: `/v1/runs/${result.run.id}/events`,
68766
- cancelUrl: `/v1/runs/${result.run.id}/cancel`
69176
+ cancelUrl: `/v1/runs/${result.run.id}/cancel`,
69177
+ steerUrl: `/v1/runs/${result.run.id}/steer`
68767
69178
  });
68768
69179
  return;
68769
69180
  }
68770
- const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path87);
69181
+ const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path91);
68771
69182
  if (req.method === "GET" && eventsMatch) {
68772
69183
  const runId = eventsMatch[1];
68773
69184
  const run = runs.getRun(runId);
@@ -68832,7 +69243,7 @@ async function runCompanionServe(opts = {}) {
68832
69243
  }, 500);
68833
69244
  return;
68834
69245
  }
68835
- const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path87);
69246
+ const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path91);
68836
69247
  if (req.method === "POST" && cancelMatch) {
68837
69248
  const runId = cancelMatch[1];
68838
69249
  const result = runs.cancel(runId);
@@ -68843,6 +69254,30 @@ async function runCompanionServe(opts = {}) {
68843
69254
  sendJson2(res, 200, { ok: true, cancelled: runId });
68844
69255
  return;
68845
69256
  }
69257
+ const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path91);
69258
+ if (req.method === "POST" && steerMatch) {
69259
+ const runId = steerMatch[1];
69260
+ const raw = await readBody(req);
69261
+ let body = {};
69262
+ try {
69263
+ body = raw ? JSON.parse(raw) : {};
69264
+ } catch {
69265
+ sendJson2(res, 400, { ok: false, error: "invalid JSON body" });
69266
+ return;
69267
+ }
69268
+ const text = typeof body.text === "string" ? body.text.trim() : "";
69269
+ if (!text) {
69270
+ sendJson2(res, 400, { ok: false, error: "text is required" });
69271
+ return;
69272
+ }
69273
+ const result = await runs.steer(runId, text);
69274
+ if (!result.ok) {
69275
+ sendJson2(res, 404, { ok: false, error: result.error });
69276
+ return;
69277
+ }
69278
+ sendJson2(res, 200, { ok: true, steered: runId, result: result.result });
69279
+ return;
69280
+ }
68846
69281
  sendJson2(res, 404, { ok: false, error: "not found" });
68847
69282
  } catch (err) {
68848
69283
  sendJson2(res, 500, {
@@ -68986,11 +69421,11 @@ import { execSync as execSync2 } from "node:child_process";
68986
69421
  import { existsSync as existsSync55, readFileSync as readFileSync42, readlinkSync, statSync as statSync10 } from "node:fs";
68987
69422
  import { createRequire as createRequire3 } from "node:module";
68988
69423
  import { fileURLToPath as fileURLToPath3 } from "node:url";
68989
- import path85 from "node:path";
69424
+ import path88 from "node:path";
68990
69425
  function findPackageRoot(start) {
68991
69426
  let dir = start;
68992
69427
  for (let i = 0; i < 6; i += 1) {
68993
- const candidate = path85.join(dir, "package.json");
69428
+ const candidate = path88.join(dir, "package.json");
68994
69429
  if (existsSync55(candidate)) {
68995
69430
  try {
68996
69431
  const pkg = JSON.parse(readFileSync42(candidate, "utf8"));
@@ -68998,11 +69433,11 @@ function findPackageRoot(start) {
68998
69433
  } catch {
68999
69434
  }
69000
69435
  }
69001
- const parent = path85.dirname(dir);
69436
+ const parent = path88.dirname(dir);
69002
69437
  if (parent === dir) break;
69003
69438
  dir = parent;
69004
69439
  }
69005
- return path85.resolve(__dirname3, "..", "..", "..");
69440
+ return path88.resolve(__dirname3, "..", "..", "..");
69006
69441
  }
69007
69442
  function tryExec(cmd) {
69008
69443
  try {
@@ -69016,7 +69451,7 @@ function tryExec(cmd) {
69016
69451
  }
69017
69452
  function readPackageJson4() {
69018
69453
  try {
69019
- const pkgPath = path85.join(packageRoot, "package.json");
69454
+ const pkgPath = path88.join(packageRoot, "package.json");
69020
69455
  return JSON.parse(readFileSync42(pkgPath, "utf8"));
69021
69456
  } catch {
69022
69457
  return null;
@@ -69032,7 +69467,7 @@ function checkShim(pkgName) {
69032
69467
  }
69033
69468
  const isWin = process.platform === "win32";
69034
69469
  const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
69035
- const shimPath = path85.join(prefix, shimName);
69470
+ const shimPath = path88.join(prefix, shimName);
69036
69471
  if (!existsSync55(shimPath)) {
69037
69472
  return FAIL(
69038
69473
  `shim not found at ${shimPath}
@@ -69060,8 +69495,8 @@ function checkShim(pkgName) {
69060
69495
  fix: npm install -g ${pkgName}@latest --force`
69061
69496
  );
69062
69497
  }
69063
- const resolved = path85.resolve(path85.dirname(shimPath), target);
69064
- const expected = path85.join(
69498
+ const resolved = path88.resolve(path88.dirname(shimPath), target);
69499
+ const expected = path88.join(
69065
69500
  prefix,
69066
69501
  "node_modules",
69067
69502
  pkgName,
@@ -69100,7 +69535,7 @@ function checkNode(pkg) {
69100
69535
  return OK(`node ${raw}`);
69101
69536
  }
69102
69537
  function checkBundle() {
69103
- const bundle = path85.join(packageRoot, "dist", "cli", "main.bundled.js");
69538
+ const bundle = path88.join(packageRoot, "dist", "cli", "main.bundled.js");
69104
69539
  if (!existsSync55(bundle)) {
69105
69540
  return FAIL(
69106
69541
  `dist/cli/main.bundled.js missing at ${bundle}
@@ -69121,7 +69556,7 @@ function checkRuntimeDeps() {
69121
69556
  const missing = [];
69122
69557
  for (const dep of required2) {
69123
69558
  try {
69124
- const localReq = createRequire3(path85.join(packageRoot, "package.json"));
69559
+ const localReq = createRequire3(path88.join(packageRoot, "package.json"));
69125
69560
  localReq.resolve(dep);
69126
69561
  } catch {
69127
69562
  missing.push(dep);
@@ -69321,7 +69756,7 @@ var init_doctor = __esm({
69321
69756
  init_metrics3();
69322
69757
  init_contextGrowthSummary();
69323
69758
  require3 = createRequire3(import.meta.url);
69324
- __dirname3 = path85.dirname(fileURLToPath3(import.meta.url));
69759
+ __dirname3 = path88.dirname(fileURLToPath3(import.meta.url));
69325
69760
  packageRoot = findPackageRoot(__dirname3);
69326
69761
  OK = (message) => ({
69327
69762
  ok: true,
@@ -69499,21 +69934,88 @@ var init_fixBudget = __esm({
69499
69934
  }
69500
69935
  });
69501
69936
 
69937
+ // src/cli/commands/inspectSession.ts
69938
+ var inspectSession_exports = {};
69939
+ __export(inspectSession_exports, {
69940
+ renderInspectReport: () => renderInspectReport,
69941
+ runInspectSession: () => runInspectSession
69942
+ });
69943
+ import path89 from "node:path";
69944
+ import { existsSync as existsSync56 } from "node:fs";
69945
+ function renderInspectReport(state3) {
69946
+ const lines = [
69947
+ `session ${state3.session.sessionId} status=${state3.session.status} turns=${state3.execution.turnsTotal}`
69948
+ ];
69949
+ const contractByTurn = new Map(state3.execution.contracts.map((c) => [c.turn, c]));
69950
+ for (const turn of state3.turns) {
69951
+ const contract = contractByTurn.get(turn.index);
69952
+ const verification = turn.verification ? `${turn.verification.verdict}${turn.verification.strict ? "" : " (non-strict)"}` : "unknown";
69953
+ const blockers = contract?.blockers ?? [];
69954
+ const completion = contract?.complete ? "complete" : blockers.length > 0 ? `incomplete \u2014 ${blockers.length} blockers: ${blockers.join(", ")}` : "incomplete";
69955
+ lines.push(
69956
+ ` turn ${turn.index} [${turn.outcome}] verification: ${verification} contract: ${completion}`
69957
+ );
69958
+ }
69959
+ lines.push("");
69960
+ lines.push("support lens:");
69961
+ const projections = state3.support.contextProjections;
69962
+ const last = projections[projections.length - 1];
69963
+ lines.push(
69964
+ ` context projections: ${projections.length}` + (last ? ` (last: ${last.contextChars} chars \u2192 ${last.returnedCount} items)` : "")
69965
+ );
69966
+ lines.push(` memory events: ${state3.support.memoryEvents}`);
69967
+ const saved = state3.support.tokensSavedByCompaction;
69968
+ lines.push(
69969
+ ` compactions: ${state3.support.compactions}${saved !== void 0 ? ` (${saved} tokens saved)` : ""}`
69970
+ );
69971
+ return lines.join("\n");
69972
+ }
69973
+ async function runInspectSession(opts) {
69974
+ const sessionsDir = resolveSessionsDir({ workspaceRoot: opts.cwd ?? process.cwd() });
69975
+ const sessionDir = path89.join(sessionsDir, opts.sessionId);
69976
+ const eventsPath = path89.join(sessionDir, "events.jsonl");
69977
+ if (!existsSync56(sessionDir)) {
69978
+ console.error(`zelari-code inspect: no session directory at ${sessionDir}`);
69979
+ return 1;
69980
+ }
69981
+ if (!existsSync56(eventsPath)) {
69982
+ console.error(`zelari-code inspect: session directory has no events.jsonl at ${eventsPath}`);
69983
+ return 1;
69984
+ }
69985
+ let state3;
69986
+ try {
69987
+ state3 = await readHarnessState(sessionDir);
69988
+ } catch (err) {
69989
+ const msg = err instanceof Error ? err.message : String(err);
69990
+ console.error(`zelari-code inspect: cannot read session at ${sessionDir}: ${msg}`);
69991
+ return 1;
69992
+ }
69993
+ console.log(opts.json ? JSON.stringify(state3, null, 2) : renderInspectReport(state3));
69994
+ return 0;
69995
+ }
69996
+ var init_inspectSession = __esm({
69997
+ "src/cli/commands/inspectSession.ts"() {
69998
+ "use strict";
69999
+ init_session();
70000
+ init_harnessState();
70001
+ }
70002
+ });
70003
+
69502
70004
  // src/cli/commands/inspect.ts
69503
70005
  var inspect_exports = {};
69504
70006
  __export(inspect_exports, {
69505
70007
  collectInspectReport: () => collectInspectReport,
69506
70008
  runInspect: () => runInspect
69507
70009
  });
69508
- import path86 from "node:path";
69509
- import { existsSync as existsSync56, readFileSync as readFileSync43, readdirSync as readdirSync12 } from "node:fs";
70010
+ import path90 from "node:path";
70011
+ import { existsSync as existsSync57, readFileSync as readFileSync43, readdirSync as readdirSync12 } from "node:fs";
69510
70012
  import { homedir as homedir17 } from "node:os";
69511
70013
  async function collectInspectReport(cwd = process.cwd()) {
69512
70014
  ensureBuiltinSkillsLoadedSync();
69513
70015
  const snap = listSkillsSnapshot(cwd);
69514
70016
  const mcp = listMcpServers(cwd);
69515
- const userMcpPath = path86.join(homedir17(), ".zelari-code", "mcp.json");
69516
- const projectMcpPath = path86.join(cwd, ".zelari", "mcp.json");
70017
+ const userMcpPath = path90.join(homedir17(), ".zelari-code", "mcp.json");
70018
+ const projectMcpPath = path90.join(cwd, ".zelari", "mcp.json");
69517
70019
  const globalHooks = globalHooksDir();
69518
70020
  const projectHooks = projectHooksDir(cwd);
69519
70021
  const projectTrusted = isFolderTrusted(cwd);
@@ -69539,11 +70041,11 @@ async function collectInspectReport(cwd = process.cwd()) {
69539
70041
  folders: listTrustedFolders()
69540
70042
  },
69541
70043
  configSources: [
69542
- { path: userMcpPath, exists: existsSync56(userMcpPath) },
69543
- { 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")) }
70044
+ { path: userMcpPath, exists: existsSync57(userMcpPath) },
70045
+ { path: projectMcpPath, exists: existsSync57(projectMcpPath) },
70046
+ { path: path90.join(homedir17(), ".zelari-code", "provider.json"), exists: existsSync57(path90.join(homedir17(), ".zelari-code", "provider.json")) },
70047
+ { path: path90.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync57(path90.join(cwd, ".zelari", "AGENTS.md")) },
70048
+ { path: path90.join(cwd, "AGENTS.md"), exists: existsSync57(path90.join(cwd, "AGENTS.md")) }
69547
70049
  ],
69548
70050
  skills: {
69549
70051
  total: snap.skills.length,
@@ -69556,7 +70058,7 @@ async function collectInspectReport(cwd = process.cwd()) {
69556
70058
  user: mcp.servers.filter((s) => s.scope === "user").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
69557
70059
  project: mcp.servers.filter((s) => s.scope === "project").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
69558
70060
  projectTrusted,
69559
- projectConfigExists: existsSync56(projectMcpPath)
70061
+ projectConfigExists: existsSync57(projectMcpPath)
69560
70062
  },
69561
70063
  hooks: {
69562
70064
  global: {
@@ -69583,12 +70085,12 @@ function listJsonFiles(dir) {
69583
70085
  }
69584
70086
  function findAgentsMd(cwd) {
69585
70087
  const candidates = [
69586
- path86.join(cwd, "AGENTS.md"),
69587
- path86.join(cwd, ".zelari", "AGENTS.md")
70088
+ path90.join(cwd, "AGENTS.md"),
70089
+ path90.join(cwd, ".zelari", "AGENTS.md")
69588
70090
  ];
69589
70091
  const found = [];
69590
70092
  for (const c of candidates) {
69591
- if (existsSync56(c)) {
70093
+ if (existsSync57(c)) {
69592
70094
  try {
69593
70095
  const text = readFileSync43(c, "utf8");
69594
70096
  found.push(`${c} (${text.length} bytes)`);
@@ -72709,6 +73211,7 @@ init_completionGate();
72709
73211
  init_verificationBridge();
72710
73212
  init_completionProof();
72711
73213
  init_nativeVerification();
73214
+ init_spineTelemetry();
72712
73215
 
72713
73216
  // src/cli/hooks/permissionPicker.ts
72714
73217
  init_toolPermissions();
@@ -72912,8 +73415,14 @@ function useChatTurn(params) {
72912
73415
  try {
72913
73416
  const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
72914
73417
  if (memoryFactory.isMemoryV2Enabled()) {
73418
+ const tuiSpineHolder = {
73419
+ get current() {
73420
+ return writerRef.current?.spine;
73421
+ }
73422
+ };
72915
73423
  memoryService = await memoryFactory.getMemoryService(process.cwd(), process.env, {
72916
- onWarning: (warning) => appendSystem(setMessages, warning, Date.now())
73424
+ onWarning: (warning) => appendSystem(setMessages, warning, Date.now()),
73425
+ onEvent: memorySinkFor(tuiSpineHolder)
72917
73426
  });
72918
73427
  memoryAutoWrite = memoryFactory.isMemoryAutoWriteEnabled();
72919
73428
  }
@@ -73880,8 +74389,14 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
73880
74389
  try {
73881
74390
  const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
73882
74391
  if (memoryFactory.isMemoryV2Enabled()) {
74392
+ const councilSpineHolder = {
74393
+ get current() {
74394
+ return writerRef.current?.spine;
74395
+ }
74396
+ };
73883
74397
  councilMemory = await memoryFactory.getMemoryService(process.cwd(), process.env, {
73884
- onWarning: (warning) => appendSystem(setMessages, warning, Date.now())
74398
+ onWarning: (warning) => appendSystem(setMessages, warning, Date.now()),
74399
+ onEvent: memorySinkFor(councilSpineHolder)
73885
74400
  });
73886
74401
  councilMemoryAutoWrite = memoryFactory.isMemoryAutoWriteEnabled();
73887
74402
  if (!overrides.ragContext) {
@@ -74490,7 +75005,12 @@ async function runZelariMissionInTui(userMessage, deps, emit) {
74490
75005
  userMessage,
74491
75006
  hasPlan: hasWorkspacePlan2(projectRoot)
74492
75007
  });
74493
- const memory = await getMemoryBackend2(projectRoot);
75008
+ const missionSpineHolder = {
75009
+ get current() {
75010
+ return deps.writerRef.current?.spine;
75011
+ }
75012
+ };
75013
+ const memory = await getMemoryBackend2(projectRoot, process.env, memorySinkFor(missionSpineHolder));
74494
75014
  const chairmanBudget = envNumber(process.env.ZELARI_MODE_MAX_TOOLS_LUCIFER, {
74495
75015
  default: 30,
74496
75016
  min: 1
@@ -75735,11 +76255,11 @@ function handleCacheStats(ctx) {
75735
76255
  init_messageHelpers();
75736
76256
  init_serviceFactory();
75737
76257
  import { promises as fs31 } from "node:fs";
75738
- import * as path66 from "node:path";
76258
+ import * as path67 from "node:path";
75739
76259
 
75740
76260
  // src/cli/memory/promotion.ts
75741
76261
  import { promises as fs30 } from "node:fs";
75742
- import * as path65 from "node:path";
76262
+ import * as path66 from "node:path";
75743
76263
  var START = "<!-- zelari:memory-promotions:start -->";
75744
76264
  var END = "<!-- zelari:memory-promotions:end -->";
75745
76265
  var DURABLE_KINDS = /* @__PURE__ */ new Set(["fact", "decision", "constraint", "preference", "procedure"]);
@@ -75750,13 +76270,13 @@ function lineFor(node) {
75750
76270
  }
75751
76271
  async function promoteMemoryToAgentsMd(projectRoot, node) {
75752
76272
  if (node.status !== "active") {
75753
- return { added: false, path: path65.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
76273
+ return { added: false, path: path66.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
75754
76274
  }
75755
76275
  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` };
76276
+ return { added: false, path: path66.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
75757
76277
  }
75758
- const root = await fs30.realpath(projectRoot).catch(() => path65.resolve(projectRoot));
75759
- const target = path65.join(root, "AGENTS.md");
76278
+ const root = await fs30.realpath(projectRoot).catch(() => path66.resolve(projectRoot));
76279
+ const target = path66.join(root, "AGENTS.md");
75760
76280
  try {
75761
76281
  const stat7 = await fs30.lstat(target);
75762
76282
  if (stat7.isSymbolicLink() || !stat7.isFile()) throw new Error("AGENTS.md must be a regular project file.");
@@ -75821,22 +76341,22 @@ function sourceLine(source2) {
75821
76341
  return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
75822
76342
  }
75823
76343
  function isInside(root, target) {
75824
- const relative6 = path66.relative(root, target);
75825
- return relative6 === "" || !relative6.startsWith("..") && !path66.isAbsolute(relative6);
76344
+ const relative6 = path67.relative(root, target);
76345
+ return relative6 === "" || !relative6.startsWith("..") && !path67.isAbsolute(relative6);
75826
76346
  }
75827
76347
  async function safeExportPath(cwd, requested) {
75828
- const lexicalRoot = path66.resolve(cwd);
76348
+ const lexicalRoot = path67.resolve(cwd);
75829
76349
  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;
76350
+ const fallback = path67.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
76351
+ const target = requested?.trim() ? path67.resolve(root, requested.trim()) : fallback;
75832
76352
  if (!isInside(root, target)) {
75833
76353
  throw new Error("Export path must stay inside the active project.");
75834
76354
  }
75835
- const parent = path66.dirname(target);
75836
- const relativeParent = path66.relative(root, parent);
76355
+ const parent = path67.dirname(target);
76356
+ const relativeParent = path67.relative(root, parent);
75837
76357
  let cursor = root;
75838
- for (const segment of relativeParent.split(path66.sep).filter(Boolean)) {
75839
- cursor = path66.join(cursor, segment);
76358
+ for (const segment of relativeParent.split(path67.sep).filter(Boolean)) {
76359
+ cursor = path67.join(cursor, segment);
75840
76360
  try {
75841
76361
  const stat7 = await fs31.lstat(cursor);
75842
76362
  if (stat7.isSymbolicLink()) {
@@ -76008,9 +76528,9 @@ ${message}` : message
76008
76528
  }
76009
76529
  case "export": {
76010
76530
  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));
76531
+ await fs31.mkdir(path67.dirname(target), { recursive: true });
76532
+ const root = await fs31.realpath(ctx.cwd).catch(() => path67.resolve(ctx.cwd));
76533
+ const realParent = await fs31.realpath(path67.dirname(target));
76014
76534
  if (!isInside(root, realParent)) {
76015
76535
  throw new Error("Export path resolves outside the active project.");
76016
76536
  }
@@ -76128,6 +76648,7 @@ init_graphMemory();
76128
76648
  init_executor();
76129
76649
  init_graphStatus();
76130
76650
  init_serviceFactory();
76651
+ init_spineTelemetry();
76131
76652
  async function handleKrakenGraph(ctx, prompt) {
76132
76653
  if (!isKrakenGraphEnabled()) {
76133
76654
  appendSystem(
@@ -76141,8 +76662,14 @@ async function handleKrakenGraph(ctx, prompt) {
76141
76662
  return;
76142
76663
  }
76143
76664
  appendSystem(ctx.setMessages, `[kraken] planning graph for: ${prompt.trim()}`);
76665
+ const tuiSpineHolder = {
76666
+ get current() {
76667
+ return ctx.writerRef?.current?.spine ?? void 0;
76668
+ }
76669
+ };
76144
76670
  const memory = isMemoryV2Enabled() ? await getMemoryService(ctx.cwd, process.env, {
76145
- onWarning: (warning) => appendSystem(ctx.setMessages, warning)
76671
+ onWarning: (warning) => appendSystem(ctx.setMessages, warning),
76672
+ onEvent: memorySinkFor(tuiSpineHolder)
76146
76673
  }) : void 0;
76147
76674
  const audit = new AuditLogger();
76148
76675
  const taskToolDeps = {
@@ -76206,7 +76733,7 @@ import { promises as fs35 } from "node:fs";
76206
76733
  init_zod();
76207
76734
  init_taskTool();
76208
76735
  import { promises as fs34 } from "node:fs";
76209
- import path71 from "node:path";
76736
+ import path72 from "node:path";
76210
76737
  import { randomBytes as randomBytes6 } from "node:crypto";
76211
76738
  var CsvFanoutArgsSchema = external_exports.object({
76212
76739
  csv_path: external_exports.string().min(1),
@@ -76300,8 +76827,8 @@ function resolveMaxConcurrency(env = process.env) {
76300
76827
  }
76301
76828
  async function runCsvFanout(args, deps, opts) {
76302
76829
  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);
76830
+ const absCsv = path72.isAbsolute(args.csv_path) ? args.csv_path : path72.join(opts.parentCwd, args.csv_path);
76831
+ const absOut = path72.isAbsolute(args.output_csv_path) ? args.output_csv_path : path72.join(opts.parentCwd, args.output_csv_path);
76305
76832
  const { headers: headers2, rows } = await readCsv(absCsv);
76306
76833
  if (headers2.length === 0) {
76307
76834
  throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
@@ -76357,7 +76884,7 @@ async function runCsvFanout(args, deps, opts) {
76357
76884
  errored += 1;
76358
76885
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
76359
76886
  }
76360
- await fs34.mkdir(path71.dirname(absOut), { recursive: true });
76887
+ await fs34.mkdir(path72.dirname(absOut), { recursive: true });
76361
76888
  await queueWrite(serializeCsv(outHeaders, outputRecords));
76362
76889
  }
76363
76890
  }
@@ -76552,7 +77079,7 @@ function splitArgs(s) {
76552
77079
  // src/cli/slashHandlers/krakenWorkbench.ts
76553
77080
  init_messageHelpers();
76554
77081
  import { promises as fs36 } from "node:fs";
76555
- import path72 from "node:path";
77082
+ import path73 from "node:path";
76556
77083
 
76557
77084
  // src/cli/kraken/workbenchView.ts
76558
77085
  var EMPTY = {
@@ -76669,14 +77196,14 @@ function formatWorkbenchForTerminal(p3) {
76669
77196
 
76670
77197
  // src/cli/slashHandlers/krakenWorkbench.ts
76671
77198
  async function handleKrakenWorkbench(ctx) {
76672
- const dir = path72.join(ctx.cwd, ".zelari", "radio");
77199
+ const dir = path73.join(ctx.cwd, ".zelari", "radio");
76673
77200
  let latest = null;
76674
77201
  let latestMtime = 0;
76675
77202
  try {
76676
77203
  const files = await fs36.readdir(dir);
76677
77204
  for (const f of files) {
76678
77205
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
76679
- const full = path72.join(dir, f);
77206
+ const full = path73.join(dir, f);
76680
77207
  const stat7 = await fs36.stat(full);
76681
77208
  if (stat7.mtimeMs > latestMtime) {
76682
77209
  latestMtime = stat7.mtimeMs;
@@ -76693,10 +77220,10 @@ async function handleKrakenWorkbench(ctx) {
76693
77220
  const parsed = parseWorkbench(content);
76694
77221
  const rendered = formatWorkbenchForTerminal(parsed);
76695
77222
  if (!rendered.trim()) {
76696
- appendSystem(ctx.setMessages, `[kraken workbench] ${path72.basename(latest)}: (no nodes / no events yet)`);
77223
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path73.basename(latest)}: (no nodes / no events yet)`);
76697
77224
  return;
76698
77225
  }
76699
- appendSystem(ctx.setMessages, `[kraken workbench] ${path72.basename(latest)}:
77226
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path73.basename(latest)}:
76700
77227
  ${rendered}`);
76701
77228
  }
76702
77229
 
@@ -77003,15 +77530,15 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
77003
77530
  // src/cli/slashHandlers/promoteMember.ts
77004
77531
  init_messageHelpers();
77005
77532
  import { promises as fs37 } from "node:fs";
77006
- import path75 from "node:path";
77533
+ import path76 from "node:path";
77007
77534
  import os12 from "node:os";
77008
77535
  async function handlePromoteMember(ctx, memberId) {
77009
77536
  try {
77010
77537
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
77011
77538
  const { skill, markdown } = promoteMember2(memberId);
77012
- const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path75.join(os12.homedir(), ".tmp", "zelari-code", "skills");
77539
+ const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path76.join(os12.homedir(), ".tmp", "zelari-code", "skills");
77013
77540
  await fs37.mkdir(skillDir, { recursive: true });
77014
- const filePath = path75.join(skillDir, `${skill.id}.md`);
77541
+ const filePath = path76.join(skillDir, `${skill.id}.md`);
77015
77542
  await fs37.writeFile(filePath, markdown, "utf8");
77016
77543
  appendSystem(
77017
77544
  ctx.setMessages,
@@ -77029,24 +77556,24 @@ async function handlePromoteMember(ctx, memberId) {
77029
77556
 
77030
77557
  // src/cli/branchManager.ts
77031
77558
  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";
77559
+ import path77 from "node:path";
77033
77560
  import os13 from "node:os";
77034
77561
  var META_FILENAME = "meta.json";
77035
77562
  var SESSIONS_SUBDIR = "sessions";
77036
77563
  function getBranchesBaseDir() {
77037
- return process.env.ANATHEMA_BRANCHES_DIR ?? path76.join(os13.homedir(), ".tmp", "zelari-code", "branches");
77564
+ return process.env.ANATHEMA_BRANCHES_DIR ?? path77.join(os13.homedir(), ".tmp", "zelari-code", "branches");
77038
77565
  }
77039
77566
  function getSessionsBaseDir() {
77040
- return process.env.ANATHEMA_SESSIONS_DIR ?? path76.join(os13.homedir(), ".tmp", "zelari-code", "sessions");
77567
+ return process.env.ANATHEMA_SESSIONS_DIR ?? path77.join(os13.homedir(), ".tmp", "zelari-code", "sessions");
77041
77568
  }
77042
77569
  function branchPathFor(name, baseDir) {
77043
- return path76.join(baseDir, name);
77570
+ return path77.join(baseDir, name);
77044
77571
  }
77045
77572
  function metaPathFor(name, baseDir) {
77046
- return path76.join(baseDir, name, META_FILENAME);
77573
+ return path77.join(baseDir, name, META_FILENAME);
77047
77574
  }
77048
77575
  function sessionsPathFor(name, baseDir) {
77049
- return path76.join(baseDir, name, SESSIONS_SUBDIR);
77576
+ return path77.join(baseDir, name, SESSIONS_SUBDIR);
77050
77577
  }
77051
77578
  function readBranchMeta(name, baseDir) {
77052
77579
  const metaPath = metaPathFor(name, baseDir);
@@ -77071,7 +77598,7 @@ function readBranchMeta(name, baseDir) {
77071
77598
  }
77072
77599
  function writeBranchMeta(name, baseDir, meta3) {
77073
77600
  const metaPath = metaPathFor(name, baseDir);
77074
- mkdirSync19(path76.dirname(metaPath), { recursive: true });
77601
+ mkdirSync19(path77.dirname(metaPath), { recursive: true });
77075
77602
  writeFileSync23(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
77076
77603
  }
77077
77604
  async function countSessions(name, baseDir) {
@@ -77122,14 +77649,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
77122
77649
  if (branchExists(name, baseDir)) {
77123
77650
  throw new BranchAlreadyExistsError(name);
77124
77651
  }
77125
- const sourcePath = path76.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
77652
+ const sourcePath = path77.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
77126
77653
  if (!existsSync48(sourcePath)) {
77127
77654
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
77128
77655
  }
77129
77656
  const branchPath = branchPathFor(name, baseDir);
77130
77657
  const branchSessionsPath = sessionsPathFor(name, baseDir);
77131
77658
  mkdirSync19(branchSessionsPath, { recursive: true });
77132
- const destPath = path76.join(branchSessionsPath, `${fromSessionId}.jsonl`);
77659
+ const destPath = path77.join(branchSessionsPath, `${fromSessionId}.jsonl`);
77133
77660
  await fs38.copyFile(sourcePath, destPath);
77134
77661
  const meta3 = {
77135
77662
  name,
@@ -77233,14 +77760,14 @@ async function handleBranchCheckout(ctx, branchName) {
77233
77760
  // src/cli/slashHandlers/workspace.ts
77234
77761
  init_messageHelpers();
77235
77762
  import { promises as fs39 } from "node:fs";
77236
- import path77 from "node:path";
77763
+ import path78 from "node:path";
77237
77764
  async function handleWorkspaceShow(ctx, what) {
77238
77765
  try {
77239
- const zelari = path77.join(process.cwd(), ".zelari");
77766
+ const zelari = path78.join(process.cwd(), ".zelari");
77240
77767
  let content;
77241
77768
  switch (what) {
77242
77769
  case "plan": {
77243
- const planPath = path77.join(zelari, "plan.md");
77770
+ const planPath = path78.join(zelari, "plan.md");
77244
77771
  try {
77245
77772
  content = await fs39.readFile(planPath, "utf-8");
77246
77773
  } catch {
@@ -77249,7 +77776,7 @@ async function handleWorkspaceShow(ctx, what) {
77249
77776
  break;
77250
77777
  }
77251
77778
  case "decisions": {
77252
- const decisionsDir = path77.join(zelari, "decisions");
77779
+ const decisionsDir = path78.join(zelari, "decisions");
77253
77780
  try {
77254
77781
  const files = (await fs39.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
77255
77782
  if (files.length === 0) {
@@ -77259,7 +77786,7 @@ async function handleWorkspaceShow(ctx, what) {
77259
77786
  `];
77260
77787
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
77261
77788
  for (const f of files) {
77262
- const raw = await fs39.readFile(path77.join(decisionsDir, f), "utf-8");
77789
+ const raw = await fs39.readFile(path78.join(decisionsDir, f), "utf-8");
77263
77790
  const { meta: meta3, body } = parseFrontmatter2(raw);
77264
77791
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
77265
77792
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -77272,7 +77799,7 @@ async function handleWorkspaceShow(ctx, what) {
77272
77799
  break;
77273
77800
  }
77274
77801
  case "risks": {
77275
- const risksPath = path77.join(zelari, "risks.md");
77802
+ const risksPath = path78.join(zelari, "risks.md");
77276
77803
  try {
77277
77804
  content = await fs39.readFile(risksPath, "utf-8");
77278
77805
  } catch {
@@ -77281,7 +77808,7 @@ async function handleWorkspaceShow(ctx, what) {
77281
77808
  break;
77282
77809
  }
77283
77810
  case "agents": {
77284
- const agentsPath = path77.join(process.cwd(), "AGENTS.MD");
77811
+ const agentsPath = path78.join(process.cwd(), "AGENTS.MD");
77285
77812
  try {
77286
77813
  content = await fs39.readFile(agentsPath, "utf-8");
77287
77814
  } catch {
@@ -77290,7 +77817,7 @@ async function handleWorkspaceShow(ctx, what) {
77290
77817
  break;
77291
77818
  }
77292
77819
  case "docs": {
77293
- const docsDir = path77.join(zelari, "docs");
77820
+ const docsDir = path78.join(zelari, "docs");
77294
77821
  try {
77295
77822
  const files = (await fs39.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
77296
77823
  content = files.length ? `# Docs (${files.length})
@@ -77332,7 +77859,7 @@ async function handleWorkspaceReset(ctx, force) {
77332
77859
  return;
77333
77860
  }
77334
77861
  try {
77335
- const target = path77.join(process.cwd(), ".zelari");
77862
+ const target = path78.join(process.cwd(), ".zelari");
77336
77863
  await fs39.rm(target, { recursive: true, force: true });
77337
77864
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
77338
77865
  } catch (err) {
@@ -77344,7 +77871,7 @@ async function handleWorkspaceReset(ctx, force) {
77344
77871
  init_provider2();
77345
77872
 
77346
77873
  // src/cli/slashHandlers/skills.ts
77347
- import path78 from "node:path";
77874
+ import path79 from "node:path";
77348
77875
  import os14 from "node:os";
77349
77876
 
77350
77877
  // src/cli/skillHistory.ts
@@ -77473,7 +78000,7 @@ function handleSkillPicker(ctx, skills, openPicker, fallbackMessage) {
77473
78000
  });
77474
78001
  }
77475
78002
  async function handleSkillStats(ctx, skillId) {
77476
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path78.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
78003
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path79.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
77477
78004
  try {
77478
78005
  const records = await readSkillHistory(historyFile);
77479
78006
  const stats = getSkillStats(records, skillId);
@@ -77489,7 +78016,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
77489
78016
  appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
77490
78017
  return;
77491
78018
  }
77492
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path78.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
78019
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path79.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
77493
78020
  try {
77494
78021
  const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
77495
78022
  appendSystem(ctx.setMessages, formatted);
@@ -77945,7 +78472,10 @@ function useSlashDispatch(params) {
77945
78472
  }
77946
78473
  if (result.kind === "kraken_graph") {
77947
78474
  const sid = (sessionId2 || "default").trim();
77948
- await handleKrakenGraph({ setMessages, cwd: process.cwd(), sessionId: sid }, result.graphPrompt ?? "");
78475
+ await handleKrakenGraph(
78476
+ { setMessages, cwd: process.cwd(), sessionId: sid, writerRef: params.writerRef },
78477
+ result.graphPrompt ?? ""
78478
+ );
77949
78479
  return;
77950
78480
  }
77951
78481
  if (result.kind === "kraken_fanout") {
@@ -78282,6 +78812,9 @@ function App() {
78282
78812
  sessionId: session.sessionId,
78283
78813
  messages: session.messages,
78284
78814
  setMessages: session.setMessages,
78815
+ // W2: same writer ref passed to useChatTurn — lets /kraken graph project
78816
+ // memory events onto the session spine mirror.
78817
+ writerRef: session.writerRef,
78285
78818
  setInput,
78286
78819
  setBusy,
78287
78820
  setSessionId: session.setSessionId,
@@ -79184,8 +79717,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
79184
79717
  let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
79185
79718
  if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
79186
79719
  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";
79720
+ const path91 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
79721
+ name = path91 && /^[a-z0-9]/.test(path91) ? path91 : "imported-skill";
79189
79722
  } catch {
79190
79723
  name = "imported-skill";
79191
79724
  }
@@ -79520,6 +80053,14 @@ function pickRootComponent() {
79520
80053
  process.exit(1);
79521
80054
  }
79522
80055
  if (argv.includes("--inspect") || argv.includes("inspect")) {
80056
+ const inspectAt = argv.findIndex((a) => a === "inspect" || a === "--inspect");
80057
+ const sessionId2 = inspectAt >= 0 ? argv.slice(inspectAt + 1).find((a) => !a.startsWith("-")) : void 0;
80058
+ if (sessionId2) {
80059
+ const { runInspectSession: runInspectSession2 } = (init_inspectSession(), __toCommonJS(inspectSession_exports));
80060
+ const json4 = argv.includes("--json");
80061
+ void runInspectSession2({ sessionId: sessionId2, json: json4 }).then((code) => process.exit(code));
80062
+ return { kind: "done" };
80063
+ }
79523
80064
  const { runInspect: runInspect2 } = (init_inspect(), __toCommonJS(inspect_exports));
79524
80065
  const json3 = argv.includes("--json");
79525
80066
  void runInspect2({ json: json3 }).then((code) => process.exit(code));