zelari-code 2.56.0 → 2.57.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 (32) hide show
  1. package/dist/cli/budget/modelContextBuilder.js +4 -1
  2. package/dist/cli/budget/modelContextBuilder.js.map +1 -1
  3. package/dist/cli/evolution/ledger.js +85 -0
  4. package/dist/cli/evolution/ledger.js.map +1 -1
  5. package/dist/cli/evolution/patternLedger.js +165 -0
  6. package/dist/cli/evolution/patternLedger.js.map +1 -0
  7. package/dist/cli/headless/runOneTurn.js +13 -1
  8. package/dist/cli/headless/runOneTurn.js.map +1 -1
  9. package/dist/cli/hooks/useChatTurn.js +21 -1
  10. package/dist/cli/hooks/useChatTurn.js.map +1 -1
  11. package/dist/cli/main.bundled.js +1246 -662
  12. package/dist/cli/main.bundled.js.map +4 -4
  13. package/dist/cli/memory/mcpAdapter.js +3 -1
  14. package/dist/cli/memory/mcpAdapter.js.map +1 -1
  15. package/dist/cli/memory/onePager.js +93 -0
  16. package/dist/cli/memory/onePager.js.map +1 -0
  17. package/dist/cli/memory/serviceFactory.js +5 -0
  18. package/dist/cli/memory/serviceFactory.js.map +1 -1
  19. package/dist/cli/memory/sqliteBackend.js +40 -3
  20. package/dist/cli/memory/sqliteBackend.js.map +1 -1
  21. package/dist/cli/memory/sqliteCodec.js +2 -0
  22. package/dist/cli/memory/sqliteCodec.js.map +1 -1
  23. package/dist/cli/memory/sqliteSchema.js +11 -1
  24. package/dist/cli/memory/sqliteSchema.js.map +1 -1
  25. package/dist/cli/runHeadless.js +62 -12
  26. package/dist/cli/runHeadless.js.map +1 -1
  27. package/dist/cli/slashCommands.js +1 -1
  28. package/dist/cli/slashHandlers/memory.js +21 -0
  29. package/dist/cli/slashHandlers/memory.js.map +1 -1
  30. package/dist/cli/toolResultCache.js +4 -22
  31. package/dist/cli/toolResultCache.js.map +1 -1
  32. package/package.json +3 -2
@@ -3876,10 +3876,10 @@ function mergeDefs(...defs) {
3876
3876
  function cloneDef(schema) {
3877
3877
  return mergeDefs(schema._zod.def);
3878
3878
  }
3879
- function getElementAtPath(obj, path126) {
3880
- if (!path126)
3879
+ function getElementAtPath(obj, path128) {
3880
+ if (!path128)
3881
3881
  return obj;
3882
- return path126.reduce((acc, key) => acc?.[key], obj);
3882
+ return path128.reduce((acc, key) => acc?.[key], obj);
3883
3883
  }
3884
3884
  function promiseAllObject(promisesObj) {
3885
3885
  const keys = Object.keys(promisesObj);
@@ -4207,11 +4207,11 @@ function explicitlyAborted(x, startIndex = 0) {
4207
4207
  }
4208
4208
  return false;
4209
4209
  }
4210
- function prefixIssues(path126, issues) {
4210
+ function prefixIssues(path128, issues) {
4211
4211
  return issues.map((iss) => {
4212
4212
  var _a3;
4213
4213
  (_a3 = iss).path ?? (_a3.path = []);
4214
- iss.path.unshift(path126);
4214
+ iss.path.unshift(path128);
4215
4215
  return iss;
4216
4216
  });
4217
4217
  }
@@ -4429,16 +4429,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
4429
4429
  }
4430
4430
  function formatError(error51, mapper = (issue2) => issue2.message) {
4431
4431
  const fieldErrors = { _errors: [] };
4432
- const processError = (error52, path126 = []) => {
4432
+ const processError = (error52, path128 = []) => {
4433
4433
  for (const issue2 of error52.issues) {
4434
4434
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4435
- issue2.errors.map((issues) => processError({ issues }, [...path126, ...issue2.path]));
4435
+ issue2.errors.map((issues) => processError({ issues }, [...path128, ...issue2.path]));
4436
4436
  } else if (issue2.code === "invalid_key") {
4437
- processError({ issues: issue2.issues }, [...path126, ...issue2.path]);
4437
+ processError({ issues: issue2.issues }, [...path128, ...issue2.path]);
4438
4438
  } else if (issue2.code === "invalid_element") {
4439
- processError({ issues: issue2.issues }, [...path126, ...issue2.path]);
4439
+ processError({ issues: issue2.issues }, [...path128, ...issue2.path]);
4440
4440
  } else {
4441
- const fullpath = [...path126, ...issue2.path];
4441
+ const fullpath = [...path128, ...issue2.path];
4442
4442
  if (fullpath.length === 0) {
4443
4443
  fieldErrors._errors.push(mapper(issue2));
4444
4444
  } else {
@@ -4465,17 +4465,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
4465
4465
  }
4466
4466
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
4467
4467
  const result = { errors: [] };
4468
- const processError = (error52, path126 = []) => {
4468
+ const processError = (error52, path128 = []) => {
4469
4469
  var _a3, _b;
4470
4470
  for (const issue2 of error52.issues) {
4471
4471
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4472
- issue2.errors.map((issues) => processError({ issues }, [...path126, ...issue2.path]));
4472
+ issue2.errors.map((issues) => processError({ issues }, [...path128, ...issue2.path]));
4473
4473
  } else if (issue2.code === "invalid_key") {
4474
- processError({ issues: issue2.issues }, [...path126, ...issue2.path]);
4474
+ processError({ issues: issue2.issues }, [...path128, ...issue2.path]);
4475
4475
  } else if (issue2.code === "invalid_element") {
4476
- processError({ issues: issue2.issues }, [...path126, ...issue2.path]);
4476
+ processError({ issues: issue2.issues }, [...path128, ...issue2.path]);
4477
4477
  } else {
4478
- const fullpath = [...path126, ...issue2.path];
4478
+ const fullpath = [...path128, ...issue2.path];
4479
4479
  if (fullpath.length === 0) {
4480
4480
  result.errors.push(mapper(issue2));
4481
4481
  continue;
@@ -4507,8 +4507,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
4507
4507
  }
4508
4508
  function toDotPath(_path) {
4509
4509
  const segs = [];
4510
- const path126 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4511
- for (const seg of path126) {
4510
+ const path128 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4511
+ for (const seg of path128) {
4512
4512
  if (typeof seg === "number")
4513
4513
  segs.push(`[${seg}]`);
4514
4514
  else if (typeof seg === "symbol")
@@ -18011,13 +18011,13 @@ function resolveRef(ref, ctx) {
18011
18011
  if (!ref.startsWith("#")) {
18012
18012
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
18013
18013
  }
18014
- const path126 = ref.slice(1).split("/").filter(Boolean);
18015
- if (path126.length === 0) {
18014
+ const path128 = ref.slice(1).split("/").filter(Boolean);
18015
+ if (path128.length === 0) {
18016
18016
  return ctx.rootSchema;
18017
18017
  }
18018
18018
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
18019
- if (path126[0] === defsKey) {
18020
- const key = path126[1];
18019
+ if (path128[0] === defsKey) {
18020
+ const key = path128[1];
18021
18021
  if (!key || !ctx.defs[key]) {
18022
18022
  throw new Error(`Reference not found: ${ref}`);
18023
18023
  }
@@ -18851,17 +18851,17 @@ var init_newlines = __esm({
18851
18851
  });
18852
18852
 
18853
18853
  // packages/core/dist/core/tools/builtin/fileEvents.js
18854
- function fileReadEvent(path126, snapshotId) {
18855
- return { kind: "file.read", actor: { type: "tool" }, data: { path: path126, snapshotId } };
18854
+ function fileReadEvent(path128, snapshotId) {
18855
+ return { kind: "file.read", actor: { type: "tool" }, data: { path: path128, snapshotId } };
18856
18856
  }
18857
- function fileAppliedEvent(path126, snapshotId, bytes) {
18858
- return { kind: "file.applied", actor: { type: "tool" }, data: { path: path126, snapshotId, bytes } };
18857
+ function fileAppliedEvent(path128, snapshotId, bytes) {
18858
+ return { kind: "file.applied", actor: { type: "tool" }, data: { path: path128, snapshotId, bytes } };
18859
18859
  }
18860
- function fileRejectedEvent(path126, reason, hint) {
18860
+ function fileRejectedEvent(path128, reason, hint) {
18861
18861
  return {
18862
18862
  kind: "file.rejected",
18863
18863
  actor: { type: "tool" },
18864
- data: hint === void 0 ? { path: path126, reason } : { path: path126, reason, hint }
18864
+ data: hint === void 0 ? { path: path128, reason } : { path: path128, reason, hint }
18865
18865
  };
18866
18866
  }
18867
18867
  function reReadHint(reject) {
@@ -20817,11 +20817,11 @@ var init_tools = __esm({
20817
20817
  if (!ctx.addDocument)
20818
20818
  return "Knowledge vault tool not available.";
20819
20819
  const title = args["title"] || "New Document";
20820
- const path126 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20820
+ const path128 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20821
20821
  const content = args["content"] || "";
20822
20822
  const tags = args["tags"] || [];
20823
20823
  ctx.addDocument({
20824
- path: path126,
20824
+ path: path128,
20825
20825
  title,
20826
20826
  content,
20827
20827
  format: "markdown",
@@ -20830,7 +20830,7 @@ var init_tools = __esm({
20830
20830
  workspaceId: ctx.workspaceId
20831
20831
  });
20832
20832
  ctx.addActivity("vault", "created document", title);
20833
- return `Document "${title}" created at "${path126}".`;
20833
+ return `Document "${title}" created at "${path128}".`;
20834
20834
  }
20835
20835
  }
20836
20836
  ];
@@ -24666,7 +24666,7 @@ async function createExecutionContext(options = {}) {
24666
24666
  workspaceKind: workspace.kind
24667
24667
  }
24668
24668
  });
24669
- const fs51 = options.fs ?? new NodeFsProvider(workspace);
24669
+ const fs52 = options.fs ?? new NodeFsProvider(workspace);
24670
24670
  const shell = options.shell ?? new NodeShellProvider(workspace);
24671
24671
  const subagent = options.subagent ?? NOOP_SUBAGENT_PROVIDER;
24672
24672
  const env = options.env ?? process.env;
@@ -24674,7 +24674,7 @@ async function createExecutionContext(options = {}) {
24674
24674
  sessionId: sessionId2,
24675
24675
  profile,
24676
24676
  workspace,
24677
- fs: fs51,
24677
+ fs: fs52,
24678
24678
  shell,
24679
24679
  subagent,
24680
24680
  appendSessionEvent: (input) => writer.append(input),
@@ -26075,16 +26075,16 @@ function runRetentionFromEnv() {
26075
26075
  maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
26076
26076
  };
26077
26077
  }
26078
- async function dirSize(path126) {
26078
+ async function dirSize(path128) {
26079
26079
  let total = 0;
26080
26080
  let entries;
26081
26081
  try {
26082
- entries = await readdir(path126, { withFileTypes: true });
26082
+ entries = await readdir(path128, { withFileTypes: true });
26083
26083
  } catch {
26084
26084
  return 0;
26085
26085
  }
26086
26086
  for (const entry of entries) {
26087
- const child = join3(path126, entry.name);
26087
+ const child = join3(path128, entry.name);
26088
26088
  if (entry.isDirectory())
26089
26089
  total += await dirSize(child);
26090
26090
  else {
@@ -26111,19 +26111,19 @@ async function enforceRunRetention(runsDir, options = {}) {
26111
26111
  for (const entry of entries) {
26112
26112
  if (!entry.isDirectory())
26113
26113
  continue;
26114
- const path126 = join3(runsDir, entry.name);
26114
+ const path128 = join3(runsDir, entry.name);
26115
26115
  let startedAt = 0;
26116
26116
  let endedAt;
26117
26117
  let completed = false;
26118
26118
  try {
26119
- const manifest = JSON.parse(await readFile(join3(path126, "manifest.json"), "utf8"));
26119
+ const manifest = JSON.parse(await readFile(join3(path128, "manifest.json"), "utf8"));
26120
26120
  startedAt = manifest.startedAt ?? 0;
26121
26121
  endedAt = manifest.endedAt;
26122
26122
  completed = Boolean(endedAt) && manifest.status !== "running";
26123
26123
  } catch {
26124
26124
  completed = false;
26125
26125
  }
26126
- infos.push({ name: entry.name, path: path126, startedAt, endedAt, completed, bytes: await dirSize(path126) });
26126
+ infos.push({ name: entry.name, path: path128, startedAt, endedAt, completed, bytes: await dirSize(path128) });
26127
26127
  }
26128
26128
  const remove = async (info) => {
26129
26129
  await rm(info.path, { recursive: true, force: true });
@@ -26681,12 +26681,12 @@ var init_engine = __esm({
26681
26681
  * content digest) and the returned ref carries the event seq when the
26682
26682
  * emitter resolved one.
26683
26683
  */
26684
- async fsEvidence(observation, path126, sha2562, content, extra = {}) {
26684
+ async fsEvidence(observation, path128, sha2562, content, extra = {}) {
26685
26685
  const digest = sha2562 && content !== void 0 ? sha2562(content) : void 0;
26686
- const seq = await this.emitEvidence({ observation, path: path126, ...extra, ...digest ? { digest } : {} });
26686
+ const seq = await this.emitEvidence({ observation, path: path128, ...extra, ...digest ? { digest } : {} });
26687
26687
  return {
26688
26688
  tier: "fs-observation",
26689
- ref: path126,
26689
+ ref: path128,
26690
26690
  capturedAt: Date.now(),
26691
26691
  ...digest ? { digest } : {},
26692
26692
  ...seq !== void 0 ? { seq } : {}
@@ -26694,25 +26694,25 @@ var init_engine = __esm({
26694
26694
  }
26695
26695
  async evalFileExists(check2, done) {
26696
26696
  const sha2562 = this.options.sha256 ?? defaultSha256;
26697
- const fs51 = this.services.fs;
26698
- if (!fs51)
26697
+ const fs52 = this.services.fs;
26698
+ if (!fs52)
26699
26699
  return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
26700
- const exists = await fs51.exists(check2.path);
26700
+ const exists = await fs52.exists(check2.path);
26701
26701
  if (!exists) {
26702
26702
  await this.emitEvidence({ observation: "file-exists", path: check2.path, exists: false });
26703
26703
  return done({ status: "fail", evidence: [], detail: `file not found: ${check2.path}` });
26704
26704
  }
26705
- const content = await fs51.readFile(check2.path).catch(() => "");
26705
+ const content = await fs52.readFile(check2.path).catch(() => "");
26706
26706
  return done({
26707
26707
  status: "pass",
26708
26708
  evidence: [await this.fsEvidence("file-exists", check2.path, sha2562, content, { exists: true })]
26709
26709
  });
26710
26710
  }
26711
26711
  async evalFileAbsent(check2, done) {
26712
- const fs51 = this.services.fs;
26713
- if (!fs51)
26712
+ const fs52 = this.services.fs;
26713
+ if (!fs52)
26714
26714
  return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
26715
- const exists = await fs51.exists(check2.path);
26715
+ const exists = await fs52.exists(check2.path);
26716
26716
  if (exists) {
26717
26717
  await this.emitEvidence({ observation: "file-absent", path: check2.path, exists: true });
26718
26718
  return done({ status: "fail", evidence: [], detail: `file still present: ${check2.path}` });
@@ -26724,12 +26724,12 @@ var init_engine = __esm({
26724
26724
  }
26725
26725
  async evalFileContains(check2, done) {
26726
26726
  const sha2562 = this.options.sha256 ?? defaultSha256;
26727
- const fs51 = this.services.fs;
26728
- if (!fs51)
26727
+ const fs52 = this.services.fs;
26728
+ if (!fs52)
26729
26729
  return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
26730
26730
  let content;
26731
26731
  try {
26732
- content = await fs51.readFile(check2.path);
26732
+ content = await fs52.readFile(check2.path);
26733
26733
  } catch {
26734
26734
  await this.emitEvidence({ observation: "file-contains", path: check2.path, readable: false });
26735
26735
  return done({ status: "fail", evidence: [], detail: `file not readable: ${check2.path}` });
@@ -28463,8 +28463,8 @@ function strictEnvOverlay(knobs, base2 = process.env) {
28463
28463
  return overlay;
28464
28464
  }
28465
28465
  function criterionId(check2, index) {
28466
- const slug = check2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
28467
- return `check-${index + 1}-${slug || "criterion"}`;
28466
+ const slug2 = check2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
28467
+ return `check-${index + 1}-${slug2 || "criterion"}`;
28468
28468
  }
28469
28469
  function normalize3(text) {
28470
28470
  return text.toLowerCase().replace(/\s+/g, " ").trim();
@@ -34430,11 +34430,11 @@ var init_synthesisAudit = __esm({
34430
34430
  import { existsSync as existsSync16, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
34431
34431
  import { join as join5 } from "node:path";
34432
34432
  function loadNfrSpec(zelariRoot) {
34433
- const path126 = join5(zelariRoot, "nfr-spec.json");
34434
- if (!existsSync16(path126))
34433
+ const path128 = join5(zelariRoot, "nfr-spec.json");
34434
+ if (!existsSync16(path128))
34435
34435
  return null;
34436
34436
  try {
34437
- const raw = JSON.parse(readFileSync15(path126, "utf8"));
34437
+ const raw = JSON.parse(readFileSync15(path128, "utf8"));
34438
34438
  if (raw.version !== 1 || !Array.isArray(raw.targets))
34439
34439
  return null;
34440
34440
  return raw;
@@ -36835,9 +36835,9 @@ var init_types9 = __esm({
36835
36835
  import { readFileSync as readFileSync20 } from "node:fs";
36836
36836
  import { join as join11 } from "node:path";
36837
36837
  function readLessonsDeduped(zelariRoot) {
36838
- const path126 = join11(zelariRoot, LESSONS_FILE);
36838
+ const path128 = join11(zelariRoot, LESSONS_FILE);
36839
36839
  try {
36840
- const raw = readFileSync20(path126, "utf8");
36840
+ const raw = readFileSync20(path128, "utf8");
36841
36841
  const byId = /* @__PURE__ */ new Map();
36842
36842
  for (const line of raw.split(/\r?\n/)) {
36843
36843
  if (!line.trim())
@@ -36938,8 +36938,8 @@ function keywordsFrom(check2, signature) {
36938
36938
  return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
36939
36939
  }
36940
36940
  function writeLesson(zelariRoot, lesson) {
36941
- const path126 = join12(zelariRoot, LESSONS_FILE);
36942
- appendFileSync(path126, `${JSON.stringify(lesson)}
36941
+ const path128 = join12(zelariRoot, LESSONS_FILE);
36942
+ appendFileSync(path128, `${JSON.stringify(lesson)}
36943
36943
  `, "utf8");
36944
36944
  }
36945
36945
  function findSimilar(lessons, signature) {
@@ -37550,7 +37550,7 @@ var init_types11 = __esm({
37550
37550
  });
37551
37551
 
37552
37552
  // packages/core/dist/memory/schemas.js
37553
- var isoDate, unit, metadata, MemoryKindSchema, MemoryStatusSchema, MemoryRelationSchema, MemoryVisibilitySchema, MemorySourceSchema, MemoryNodeInputSchema, MemoryNodeSchema, MemoryEdgeInputSchema, MemoryEdgeSchema;
37553
+ var isoDate, unit, metadata, relevantWhen, MemoryKindSchema, MemoryStatusSchema, MemoryRelationSchema, MemoryVisibilitySchema, MemorySourceSchema, MemoryNodeInputSchema, MemoryNodeSchema, MemoryEdgeInputSchema, MemoryEdgeSchema;
37554
37554
  var init_schemas3 = __esm({
37555
37555
  "packages/core/dist/memory/schemas.js"() {
37556
37556
  "use strict";
@@ -37565,6 +37565,7 @@ var init_schemas3 = __esm({
37565
37565
  return false;
37566
37566
  }
37567
37567
  }, "Memory metadata must be JSON-serializable and no larger than 128 KB.");
37568
+ relevantWhen = external_exports.array(external_exports.string().min(1).max(120)).max(8).optional();
37568
37569
  MemoryKindSchema = external_exports.enum(MEMORY_KINDS);
37569
37570
  MemoryStatusSchema = external_exports.enum(MEMORY_STATUSES);
37570
37571
  MemoryRelationSchema = external_exports.enum(MEMORY_RELATIONS);
@@ -37596,6 +37597,7 @@ var init_schemas3 = __esm({
37596
37597
  status: MemoryStatusSchema.optional(),
37597
37598
  visibility: MemoryVisibilitySchema.optional(),
37598
37599
  tags: external_exports.array(external_exports.string().min(1).max(120)).max(64).optional(),
37600
+ relevantWhen,
37599
37601
  source: MemorySourceSchema.optional(),
37600
37602
  createdAt: isoDate.optional(),
37601
37603
  recordedAt: isoDate.optional(),
@@ -37678,11 +37680,13 @@ function scoreMemoryCandidate(candidate, query, options = {}) {
37678
37680
  confidence: node.confidence,
37679
37681
  recency: recencyScore(node.updatedAt, options.now, options.recencyHalfLifeDays),
37680
37682
  graphProximity: Math.max(0, Math.min(1, candidate.graphProximity ?? 0)),
37681
- verificationBonus: verified(node)
37683
+ verificationBonus: verified(node),
37684
+ triggerMatch: Math.max(0, Math.min(1, candidate.triggerMatch ?? 0))
37682
37685
  };
37683
37686
  const weights = { ...DEFAULT_MEMORY_SCORING_WEIGHTS, ...options.weights };
37684
37687
  const semanticAvailable = candidate.semanticRelevance !== void 0;
37685
- const activeEntries = Object.entries(weights).filter(([key]) => semanticAvailable || key !== "semanticRelevance");
37688
+ const triggerAvailable = candidate.triggerMatch !== void 0;
37689
+ const activeEntries = Object.entries(weights).filter(([key]) => (semanticAvailable || key !== "semanticRelevance") && (triggerAvailable || key !== "triggerMatch"));
37686
37690
  const totalWeight = activeEntries.reduce((sum, [, weight]) => sum + Math.max(0, weight), 0);
37687
37691
  const weighted = activeEntries.reduce((sum, [key, weight]) => sum + signals[key] * Math.max(0, weight), 0);
37688
37692
  const score = totalWeight > 0 ? weighted / totalWeight : 0;
@@ -37702,11 +37706,117 @@ var init_scoring = __esm({
37702
37706
  confidence: 0.1,
37703
37707
  recency: 0.1,
37704
37708
  graphProximity: 0.1,
37705
- verificationBonus: 0.05
37709
+ verificationBonus: 0.05,
37710
+ // A trigger hit is a strong "this memory is useful now" signal; weight it
37711
+ // above lexical overlap so an associative match beats a loose keyword match.
37712
+ triggerMatch: 0.4
37706
37713
  };
37707
37714
  }
37708
37715
  });
37709
37716
 
37717
+ // packages/core/dist/memory/relevantWhen.js
37718
+ function keyTokens(value) {
37719
+ const seen = /* @__PURE__ */ new Set();
37720
+ const out = [];
37721
+ for (const token of memoryTokens(value)) {
37722
+ if (token.length < 3 || token.length > MAX_TOKEN_LENGTH)
37723
+ continue;
37724
+ if (STOPWORDS.has(token) || seen.has(token))
37725
+ continue;
37726
+ seen.add(token);
37727
+ out.push(token);
37728
+ }
37729
+ return out;
37730
+ }
37731
+ function clip(phrase) {
37732
+ const trimmed = phrase.replace(/\s+/g, " ").trim();
37733
+ return trimmed.length <= MAX_PHRASE_LENGTH ? trimmed : `${trimmed.slice(0, MAX_PHRASE_LENGTH - 1).trimEnd()}\u2026`;
37734
+ }
37735
+ function deriveRelevantWhen(content, kind2, tags = []) {
37736
+ const tokens = keyTokens(content);
37737
+ for (const tag of tags) {
37738
+ for (const token of keyTokens(tag)) {
37739
+ if (!tokens.includes(token))
37740
+ tokens.push(token);
37741
+ }
37742
+ }
37743
+ if (tokens.length === 0)
37744
+ return [];
37745
+ if (kind2 === "failure") {
37746
+ const errorClass = tokens.find((token) => ERRORISH.test(token));
37747
+ const tool = tokens.find((token) => TOOLISH.test(token) && token !== errorClass) ?? tokens[0];
37748
+ return [clip(errorClass ? `when ${tool} fails with ${errorClass}` : `when ${tool} fails`)];
37749
+ }
37750
+ if (kind2 === "procedure") {
37751
+ const command = tokens.find((token) => TOOLISH.test(token)) ?? tokens[0];
37752
+ return [clip(`when running ${command}`)];
37753
+ }
37754
+ const phrases = [];
37755
+ for (const token of tokens) {
37756
+ if (phrases.length >= RELEVANT_WHEN_CAP)
37757
+ break;
37758
+ phrases.push(clip(`when ${token}`));
37759
+ }
37760
+ return [...new Set(phrases)];
37761
+ }
37762
+ var RELEVANT_WHEN_CAP, MAX_PHRASE_LENGTH, MAX_TOKEN_LENGTH, STOPWORDS, TOOLISH, ERRORISH;
37763
+ var init_relevantWhen = __esm({
37764
+ "packages/core/dist/memory/relevantWhen.js"() {
37765
+ "use strict";
37766
+ init_scoring();
37767
+ RELEVANT_WHEN_CAP = 3;
37768
+ MAX_PHRASE_LENGTH = 120;
37769
+ MAX_TOKEN_LENGTH = 24;
37770
+ STOPWORDS = /* @__PURE__ */ new Set([
37771
+ "the",
37772
+ "and",
37773
+ "for",
37774
+ "with",
37775
+ "that",
37776
+ "this",
37777
+ "from",
37778
+ "when",
37779
+ "into",
37780
+ "your",
37781
+ "you",
37782
+ "are",
37783
+ "was",
37784
+ "were",
37785
+ "has",
37786
+ "have",
37787
+ "had",
37788
+ "not",
37789
+ "but",
37790
+ "its",
37791
+ "also",
37792
+ "will",
37793
+ "can",
37794
+ "should",
37795
+ "must",
37796
+ "them",
37797
+ "they",
37798
+ "our",
37799
+ "out",
37800
+ "any",
37801
+ "all",
37802
+ "each",
37803
+ "per",
37804
+ "via",
37805
+ "use",
37806
+ "using",
37807
+ "get",
37808
+ "set",
37809
+ "new",
37810
+ "old",
37811
+ "one",
37812
+ "two",
37813
+ "may"
37814
+ ]);
37815
+ TOOLISH = /(?:npm|pnpm|yarn|node|tsc|vitest|jest|eslint|prettier|docker|git|cargo|rustc|python|pip|go|mvn|gradle|make|curl|http|fetch|sqlite|postgres|redis|deploy|build|test|lint|install|migrate|migration)/i;
37816
+ ERRORISH = /(?:timeout|timedout|etimedout|econn|eaddrinuse|enoent|eacces|enospc|eexist|lock|locked|denied|refused|crash|signal|exhaust|oom|heap|exception|error|traceback|segfault|panic)/i;
37817
+ }
37818
+ });
37819
+
37710
37820
  // packages/core/dist/memory/policies.js
37711
37821
  function shannonEntropy(value) {
37712
37822
  const counts = /* @__PURE__ */ new Map();
@@ -38148,6 +38258,7 @@ var init_service = __esm({
38148
38258
  init_context2();
38149
38259
  init_policies();
38150
38260
  init_scoring();
38261
+ init_relevantWhen();
38151
38262
  init_semantic();
38152
38263
  MemoryPolicyError = class extends Error {
38153
38264
  constructor(message) {
@@ -38162,6 +38273,7 @@ var init_service = __esm({
38162
38273
  onEvent;
38163
38274
  now;
38164
38275
  defaultContextChars;
38276
+ relevantWhenEnabled;
38165
38277
  semantic;
38166
38278
  constructor(projectId2, backend, options = {}) {
38167
38279
  this.backend = backend;
@@ -38172,6 +38284,7 @@ var init_service = __esm({
38172
38284
  this.onEvent = options.onEvent;
38173
38285
  this.now = options.now ?? (() => /* @__PURE__ */ new Date());
38174
38286
  this.defaultContextChars = options.defaultContextChars ?? 2e3;
38287
+ this.relevantWhenEnabled = options.relevantWhen ?? true;
38175
38288
  if (options.embeddingProvider) {
38176
38289
  this.semantic = new SemanticMemoryController(projectId2, backend, options.embeddingProvider, {
38177
38290
  now: this.now,
@@ -38181,6 +38294,31 @@ var init_service = __esm({
38181
38294
  });
38182
38295
  }
38183
38296
  }
38297
+ /** Sanitize, dedupe, and cap associative triggers before persistence. */
38298
+ cleanRelevantWhen(proposed) {
38299
+ const out = [];
38300
+ for (const phrase of proposed) {
38301
+ if (typeof phrase !== "string")
38302
+ continue;
38303
+ const cleaned = this.sanitizer.sanitize(phrase);
38304
+ if (cleaned.rejected)
38305
+ continue;
38306
+ const value = cleaned.content.trim().slice(0, 120).trim();
38307
+ if (!value || out.includes(value))
38308
+ continue;
38309
+ out.push(value);
38310
+ if (out.length >= RELEVANT_WHEN_CAP)
38311
+ break;
38312
+ }
38313
+ return out;
38314
+ }
38315
+ /** Use host-supplied triggers, else derive them purely from the content. */
38316
+ buildRelevantWhen(input, content, kind2, tags) {
38317
+ if (!this.relevantWhenEnabled)
38318
+ return [];
38319
+ const proposed = input && input.length > 0 ? input : deriveRelevantWhen(content, kind2, tags);
38320
+ return this.cleanRelevantWhen(proposed);
38321
+ }
38184
38322
  emit(event) {
38185
38323
  if (!this.onEvent)
38186
38324
  return;
@@ -38213,6 +38351,7 @@ var init_service = __esm({
38213
38351
  ...sanitized.redactions.length > 0 ? { secretRedactions: sanitized.redactions } : {}
38214
38352
  };
38215
38353
  const tags = normalizeTags(parsed.tags);
38354
+ const relevantWhen2 = this.buildRelevantWhen(parsed.relevantWhen, sanitized.content, parsed.kind, tags);
38216
38355
  const exactKey = normalizedMemoryKey(sanitized.content);
38217
38356
  const possible = await this.backend.search({
38218
38357
  text: sanitized.content,
@@ -38225,13 +38364,18 @@ var init_service = __esm({
38225
38364
  const duplicate = possible.find(({ node: node2 }) => normalizedMemoryKey(node2.content) === exactKey && (visibility === "project" || node2.source.client === source2.client))?.node;
38226
38365
  if (duplicate) {
38227
38366
  const mergedTags = normalizeTags([...duplicate.tags, ...tags]);
38228
- const shouldUpdate = confidence > duplicate.confidence || clampUnit(parsed.importance, 0.5) > duplicate.importance || mergedTags.length !== duplicate.tags.length || sanitized.redactions.length > 0;
38367
+ const mergedRelevantWhen = this.cleanRelevantWhen([
38368
+ ...duplicate.relevantWhen ?? [],
38369
+ ...relevantWhen2
38370
+ ]);
38371
+ const shouldUpdate = confidence > duplicate.confidence || clampUnit(parsed.importance, 0.5) > duplicate.importance || mergedTags.length !== duplicate.tags.length || mergedRelevantWhen.length !== (duplicate.relevantWhen?.length ?? 0) || sanitized.redactions.length > 0;
38229
38372
  if (!shouldUpdate)
38230
38373
  return duplicate;
38231
38374
  const updated = await this.backend.update(duplicate.id, {
38232
38375
  confidence: Math.max(duplicate.confidence, confidence),
38233
38376
  importance: Math.max(duplicate.importance, clampUnit(parsed.importance, 0.5)),
38234
38377
  tags: mergedTags,
38378
+ ...mergedRelevantWhen.length ? { relevantWhen: mergedRelevantWhen } : {},
38235
38379
  source: source2,
38236
38380
  metadata: { ...duplicate.metadata, ...metadata2 },
38237
38381
  actor: source2.agent,
@@ -38250,6 +38394,7 @@ var init_service = __esm({
38250
38394
  status: parsed.status ?? "active",
38251
38395
  visibility,
38252
38396
  tags,
38397
+ ...relevantWhen2.length ? { relevantWhen: relevantWhen2 } : {},
38253
38398
  source: source2,
38254
38399
  ...parsed.createdAt ? { createdAt: parsed.createdAt } : {},
38255
38400
  ...parsed.recordedAt ? { recordedAt: parsed.recordedAt } : {},
@@ -38283,6 +38428,21 @@ var init_service = __esm({
38283
38428
  if (candidate.node.projectId === this.projectId && (!raw.externalClient || candidate.node.visibility === "project" || candidate.node.source.client === raw.externalClient))
38284
38429
  byId.set(candidate.node.id, candidate);
38285
38430
  }
38431
+ if (this.relevantWhenEnabled && !raw.asOf && text && this.backend.searchRelevantWhen) {
38432
+ const triggers = await this.backend.searchRelevantWhen({
38433
+ ...recallQuery,
38434
+ text,
38435
+ projectId: this.projectId,
38436
+ statuses: raw.statuses ?? (raw.includeHistorical ? void 0 : ["active"]),
38437
+ limit: Math.max(limit, Math.min(200, limit * 5))
38438
+ });
38439
+ for (const hit of triggers) {
38440
+ if (hit.node.projectId !== this.projectId || raw.externalClient && hit.node.visibility === "private" && hit.node.source.client !== raw.externalClient)
38441
+ continue;
38442
+ const prior = byId.get(hit.node.id);
38443
+ byId.set(hit.node.id, prior ? { ...prior, triggerMatch: 1 } : { ...hit, lexicalRelevance: 1, triggerMatch: 1 });
38444
+ }
38445
+ }
38286
38446
  if (this.semantic) {
38287
38447
  const semantic = await this.semantic.search({
38288
38448
  ...raw,
@@ -38850,6 +39010,7 @@ var init_memory = __esm({
38850
39010
  init_types11();
38851
39011
  init_schemas3();
38852
39012
  init_scoring();
39013
+ init_relevantWhen();
38853
39014
  init_policies();
38854
39015
  init_context2();
38855
39016
  init_service();
@@ -38917,9 +39078,9 @@ function findCycle(nodes) {
38917
39078
  if (color.get(start) !== WHITE)
38918
39079
  continue;
38919
39080
  const stack = [[start, 0]];
38920
- const path126 = [];
39081
+ const path128 = [];
38921
39082
  color.set(start, GRAY);
38922
- path126.push(start);
39083
+ path128.push(start);
38923
39084
  while (stack.length > 0) {
38924
39085
  const top = stack[stack.length - 1];
38925
39086
  const [id3, idx] = top;
@@ -38932,17 +39093,17 @@ function findCycle(nodes) {
38932
39093
  continue;
38933
39094
  const c = color.get(dep);
38934
39095
  if (c === GRAY) {
38935
- const at = path126.indexOf(dep);
38936
- return [...path126.slice(at), dep];
39096
+ const at = path128.indexOf(dep);
39097
+ return [...path128.slice(at), dep];
38937
39098
  }
38938
39099
  if (c === WHITE) {
38939
39100
  color.set(dep, GRAY);
38940
- path126.push(dep);
39101
+ path128.push(dep);
38941
39102
  stack.push([dep, 0]);
38942
39103
  }
38943
39104
  } else {
38944
39105
  color.set(id3, BLACK);
38945
- path126.pop();
39106
+ path128.pop();
38946
39107
  stack.pop();
38947
39108
  }
38948
39109
  }
@@ -39862,8 +40023,8 @@ var init_runner = __esm({
39862
40023
  failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
39863
40024
  pending: []
39864
40025
  };
39865
- const path126 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
39866
- this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path126}`);
40026
+ const path128 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
40027
+ this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path128}`);
39867
40028
  return snapshot;
39868
40029
  }
39869
40030
  callLog(msg, data) {
@@ -40421,7 +40582,7 @@ var CORE_VERSION;
40421
40582
  var init_version = __esm({
40422
40583
  "packages/core/dist/version.js"() {
40423
40584
  "use strict";
40424
- CORE_VERSION = "2.56.0";
40585
+ CORE_VERSION = "2.57.0";
40425
40586
  }
40426
40587
  });
40427
40588
 
@@ -40596,6 +40757,7 @@ __export(dist_exports, {
40596
40757
  PressureThresholdsSchema: () => PressureThresholdsSchema,
40597
40758
  ProfileSchema: () => ProfileSchema,
40598
40759
  REDACTED: () => REDACTED,
40760
+ RELEVANT_WHEN_CAP: () => RELEVANT_WHEN_CAP,
40599
40761
  ReasoningWatchdog: () => ReasoningWatchdog,
40600
40762
  RepetitionGuard: () => RepetitionGuard,
40601
40763
  ResourcePolicySchema: () => ResourcePolicySchema,
@@ -40737,6 +40899,7 @@ __export(dist_exports, {
40737
40899
  deriveInitialContract: () => deriveInitialContract,
40738
40900
  deriveMessages: () => deriveMessages,
40739
40901
  deriveMissionState: () => deriveMissionState,
40902
+ deriveRelevantWhen: () => deriveRelevantWhen,
40740
40903
  derivedToAgentMessages: () => derivedToAgentMessages,
40741
40904
  detectAssistantTextLoop: () => detectAssistantTextLoop,
40742
40905
  detectAssistantTextLoopWindow: () => detectAssistantTextLoopWindow,
@@ -43145,9 +43308,9 @@ function spillToolOutput(fullText, meta3) {
43145
43308
  const rnd = randomBytes3(3).toString("hex");
43146
43309
  const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
43147
43310
  const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
43148
- const path126 = join14(dir, file2);
43149
- writeFileSync13(path126, fullText, "utf8");
43150
- return path126;
43311
+ const path128 = join14(dir, file2);
43312
+ writeFileSync13(path128, fullText, "utf8");
43313
+ return path128;
43151
43314
  } catch {
43152
43315
  return null;
43153
43316
  }
@@ -43158,7 +43321,7 @@ var init_toolOutputSpill = __esm({
43158
43321
  }
43159
43322
  });
43160
43323
 
43161
- // packages/core/dist/core/tools/registry.js
43324
+ // packages/core/dist/core/tools/observationCompactor.js
43162
43325
  function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
43163
43326
  if (text.length === 0)
43164
43327
  return text;
@@ -43193,10 +43356,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
43193
43356
  ${tail2}`;
43194
43357
  }
43195
43358
  if (doSpill) {
43196
- const path126 = spillToolOutput(text, { toolName: opts.toolName });
43197
- if (path126) {
43359
+ const path128 = spillToolOutput(text, { toolName: opts.toolName });
43360
+ if (path128) {
43198
43361
  const spillNote = `
43199
- \u2026 [full output spilled to: ${path126} \u2014 re-read with read_file if you need the complete text] \u2026`;
43362
+ \u2026 [full output spilled to: ${path128} \u2014 re-read with read_file if you need the complete text] \u2026`;
43200
43363
  if (preview.includes("] \u2026\n")) {
43201
43364
  preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
43202
43365
  `);
@@ -43207,14 +43370,47 @@ ${tail2}`;
43207
43370
  }
43208
43371
  return preview;
43209
43372
  }
43210
- var TOOL_NAME_ALIASES, TOOL_RESULT_LINE_CAP, ToolRegistry;
43373
+ function compactToolResult(result, opts = {}) {
43374
+ if (!result.ok)
43375
+ return result;
43376
+ const truncOpts = { toolName: opts.toolName };
43377
+ if (opts.cap !== void 0)
43378
+ truncOpts.cap = opts.cap;
43379
+ if (opts.spill !== void 0)
43380
+ truncOpts.spill = opts.spill;
43381
+ if (typeof result.value === "string") {
43382
+ result.value = truncateToolResult(result.value, truncOpts);
43383
+ } else if (result.value && typeof result.value === "object") {
43384
+ const v = result.value;
43385
+ if (typeof v.content === "string") {
43386
+ v.content = truncateToolResult(v.content, truncOpts);
43387
+ }
43388
+ }
43389
+ return result;
43390
+ }
43391
+ var TOOL_RESULT_LINE_CAP;
43392
+ var init_observationCompactor = __esm({
43393
+ "packages/core/dist/core/tools/observationCompactor.js"() {
43394
+ "use strict";
43395
+ init_toolOutputSpill();
43396
+ TOOL_RESULT_LINE_CAP = (() => {
43397
+ const raw = process.env.ZELARI_TOOL_RESULT_LINES;
43398
+ const n = raw ? Number.parseInt(raw, 10) : 200;
43399
+ return Number.isFinite(n) && n >= 10 ? n : 200;
43400
+ })();
43401
+ }
43402
+ });
43403
+
43404
+ // packages/core/dist/core/tools/registry.js
43405
+ var TOOL_NAME_ALIASES, ToolRegistry;
43211
43406
  var init_registry2 = __esm({
43212
43407
  "packages/core/dist/core/tools/registry.js"() {
43213
43408
  "use strict";
43214
43409
  init_zodBridge();
43215
- init_toolOutputSpill();
43410
+ init_observationCompactor();
43216
43411
  init_toolTypes();
43217
43412
  init_toolOutputSpill();
43413
+ init_observationCompactor();
43218
43414
  TOOL_NAME_ALIASES = {
43219
43415
  read: "read_file",
43220
43416
  readfile: "read_file",
@@ -43239,11 +43435,6 @@ var init_registry2 = __esm({
43239
43435
  run: "bash",
43240
43436
  exec: "bash"
43241
43437
  };
43242
- TOOL_RESULT_LINE_CAP = (() => {
43243
- const raw = process.env.ZELARI_TOOL_RESULT_LINES;
43244
- const n = raw ? Number.parseInt(raw, 10) : 200;
43245
- return Number.isFinite(n) && n >= 10 ? n : 200;
43246
- })();
43247
43438
  ToolRegistry = class {
43248
43439
  tools = /* @__PURE__ */ new Map();
43249
43440
  /** v0.10.0: lifecycle hooks (PreToolUse/PostToolUse). Null = no hooks. */
@@ -43373,17 +43564,7 @@ var init_registry2 = __esm({
43373
43564
  })
43374
43565
  ]);
43375
43566
  if (result.ok) {
43376
- const tName = options.toolName ?? name;
43377
- if (typeof result.value === "string") {
43378
- result.value = truncateToolResult(result.value, {
43379
- toolName: tName
43380
- });
43381
- } else if (result.value && typeof result.value === "object") {
43382
- const v = result.value;
43383
- if (typeof v.content === "string") {
43384
- v.content = truncateToolResult(v.content, { toolName: tName });
43385
- }
43386
- }
43567
+ compactToolResult(result, { toolName: options.toolName ?? name });
43387
43568
  }
43388
43569
  if (this.lifecycleHooks) {
43389
43570
  try {
@@ -43756,8 +43937,8 @@ function workspaceFile(rootDir, kind2) {
43756
43937
  return join15(rootDir, "workspace.json");
43757
43938
  }
43758
43939
  }
43759
- function workspaceArtifact(rootDir, subdir, slug) {
43760
- return join15(rootDir, subdir, `${slug}.md`);
43940
+ function workspaceArtifact(rootDir, subdir, slug2) {
43941
+ return join15(rootDir, subdir, `${slug2}.md`);
43761
43942
  }
43762
43943
  function projectName(projectRoot = process.cwd()) {
43763
43944
  return basename(realpathSync(projectRoot));
@@ -44041,28 +44222,28 @@ var init_storage = __esm({
44041
44222
  VALID_SCALARS = /^(true|false|null|~)$/i;
44042
44223
  Storage = class {
44043
44224
  /** Read a Markdown file with frontmatter. Throws if not found. */
44044
- read(path126) {
44045
- if (!existsSync25(path126)) {
44046
- throw new Error(`File not found: ${path126}`);
44225
+ read(path128) {
44226
+ if (!existsSync25(path128)) {
44227
+ throw new Error(`File not found: ${path128}`);
44047
44228
  }
44048
- const md = readFileSync24(path126, "utf8");
44229
+ const md = readFileSync24(path128, "utf8");
44049
44230
  return parseFrontmatter(md);
44050
44231
  }
44051
44232
  /** Read a Markdown file; returns null if not found. */
44052
- readIfExists(path126) {
44053
- if (!existsSync25(path126)) return null;
44054
- return this.read(path126);
44233
+ readIfExists(path128) {
44234
+ if (!existsSync25(path128)) return null;
44235
+ return this.read(path128);
44055
44236
  }
44056
44237
  /**
44057
44238
  * Write a Markdown file atomically (tmp + rename). Creates parent dirs.
44058
44239
  * The meta object is serialized as YAML frontmatter; body as Markdown.
44059
44240
  */
44060
- write(path126, meta3, body) {
44061
- mkdirSync11(dirname2(path126), { recursive: true });
44062
- const tmp = path126 + ".tmp-" + process.pid;
44241
+ write(path128, meta3, body) {
44242
+ mkdirSync11(dirname2(path128), { recursive: true });
44243
+ const tmp = path128 + ".tmp-" + process.pid;
44063
44244
  const md = serializeFrontmatter(meta3, body);
44064
44245
  writeFileSync15(tmp, md, "utf8");
44065
- renameSync2(tmp, path126);
44246
+ renameSync2(tmp, path128);
44066
44247
  }
44067
44248
  /** List all .md files in a directory (non-recursive). */
44068
44249
  listMarkdown(dir) {
@@ -44173,8 +44354,8 @@ function nextPlanTaskId(store6) {
44173
44354
  return `t${store6.counter}`;
44174
44355
  }
44175
44356
  function writePlanTaskArtifact(rootDir, task) {
44176
- const path126 = join17(rootDir, "plan-tasks", `${task.id}.md`);
44177
- mkdirSync12(dirname3(path126), { recursive: true });
44357
+ const path128 = join17(rootDir, "plan-tasks", `${task.id}.md`);
44358
+ mkdirSync12(dirname3(path128), { recursive: true });
44178
44359
  const meta3 = {
44179
44360
  kind: "task",
44180
44361
  id: task.id,
@@ -44195,7 +44376,7 @@ function writePlanTaskArtifact(rootDir, task) {
44195
44376
  task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
44196
44377
  ""
44197
44378
  ].filter((l) => l !== null).join("\n");
44198
- new Storage().write(path126, meta3, body);
44379
+ new Storage().write(path128, meta3, body);
44199
44380
  }
44200
44381
  function loadHandle(rootDir) {
44201
44382
  const jsonPath = join17(rootDir, "plan.json");
@@ -45352,8 +45533,8 @@ async function createKrakenWorktreeDetailed(cwd, label) {
45352
45533
  const head = await git3(repoRoot, ["rev-parse", "HEAD"]);
45353
45534
  const baseSha = head.ok ? head.stdout.trim() : void 0;
45354
45535
  const id3 = `${Date.now().toString(36)}-${randomBytes4(3).toString("hex")}`;
45355
- const slug = (label ?? "task").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "task";
45356
- const branch = `kraken/${slug}-${id3}`;
45536
+ const slug2 = (label ?? "task").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "task";
45537
+ const branch = `kraken/${slug2}-${id3}`;
45357
45538
  const wtRoot = path50.join(repoRoot, ".zelari", "worktrees");
45358
45539
  const wtPath = path50.join(wtRoot, `kraken-${id3}`);
45359
45540
  const longPaths = isLongPath(repoRoot, wtPath);
@@ -53056,7 +53237,7 @@ function upsertSkill(opts) {
53056
53237
  }
53057
53238
  dir = getProjectSkillsDir(root);
53058
53239
  }
53059
- const path126 = skillFilePath(dir, name);
53240
+ const path128 = skillFilePath(dir, name);
53060
53241
  const content = serializeSkillMd({
53061
53242
  name,
53062
53243
  description,
@@ -53065,13 +53246,13 @@ function upsertSkill(opts) {
53065
53246
  tools: opts.tools,
53066
53247
  cost: opts.cost
53067
53248
  });
53068
- const parsed = parseSkillMd(content, path126);
53249
+ const parsed = parseSkillMd(content, path128);
53069
53250
  if (!parsed) {
53070
53251
  return { ok: false, error: "Generated SKILL.md failed validation" };
53071
53252
  }
53072
- mkdirSync15(dirname4(path126), { recursive: true });
53073
- writeFileSync18(path126, content, "utf8");
53074
- return { ok: true, path: path126 };
53253
+ mkdirSync15(dirname4(path128), { recursive: true });
53254
+ writeFileSync18(path128, content, "utf8");
53255
+ return { ok: true, path: path128 };
53075
53256
  }
53076
53257
  function removeSkill(opts) {
53077
53258
  const name = opts.name.trim().toLowerCase();
@@ -53089,8 +53270,8 @@ function removeSkill(opts) {
53089
53270
  dir = getProjectSkillsDir(root);
53090
53271
  }
53091
53272
  const skillDir = join20(dir, name);
53092
- const path126 = skillFilePath(dir, name);
53093
- if (!existsSync35(path126) && !existsSync35(skillDir)) {
53273
+ const path128 = skillFilePath(dir, name);
53274
+ if (!existsSync35(path128) && !existsSync35(skillDir)) {
53094
53275
  return { ok: false, error: `Skill "${name}" not found in ${dir}` };
53095
53276
  }
53096
53277
  try {
@@ -53101,7 +53282,7 @@ function removeSkill(opts) {
53101
53282
  error: err instanceof Error ? err.message : String(err)
53102
53283
  };
53103
53284
  }
53104
- return { ok: true, path: path126 };
53285
+ return { ok: true, path: path128 };
53105
53286
  }
53106
53287
  var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
53107
53288
  var init_skillConfigIo = __esm({
@@ -53161,16 +53342,16 @@ function createCreateSkillTool(opts) {
53161
53342
  const overwrite = args?.overwrite === true;
53162
53343
  const dir = scope === "user" ? getUserSkillsDir() : getProjectSkillsDir(root);
53163
53344
  const skillDir = resolve3(dir, name);
53164
- const path126 = resolve3(skillDir, "SKILL.md");
53165
- if (!path126.startsWith(resolve3(dir) + sep)) {
53345
+ const path128 = resolve3(skillDir, "SKILL.md");
53346
+ if (!path128.startsWith(resolve3(dir) + sep)) {
53166
53347
  return typedErr(
53167
53348
  `Refused: "${name}" would resolve outside the ${scope} skills directory (${resolve3(dir)}).`
53168
53349
  );
53169
53350
  }
53170
- const existed = existsSync36(path126);
53351
+ const existed = existsSync36(path128);
53171
53352
  if (existed && !overwrite) {
53172
53353
  return typedErr(
53173
- `Skill "${name}" already exists at ${path126} \u2014 nothing was written. Call create_skill again with overwrite: true to replace it, or pick another name.`
53354
+ `Skill "${name}" already exists at ${path128} \u2014 nothing was written. Call create_skill again with overwrite: true to replace it, or pick another name.`
53174
53355
  );
53175
53356
  }
53176
53357
  const written = upsertSkill({
@@ -56785,21 +56966,21 @@ function normalizeAuth(auth) {
56785
56966
  return "agent";
56786
56967
  }
56787
56968
  function readSecrets() {
56788
- const path126 = getSshSecretsPath();
56789
- if (!existsSync39(path126)) return {};
56969
+ const path128 = getSshSecretsPath();
56970
+ if (!existsSync39(path128)) return {};
56790
56971
  try {
56791
- return JSON.parse(readFileSync31(path126, "utf8"));
56972
+ return JSON.parse(readFileSync31(path128, "utf8"));
56792
56973
  } catch {
56793
56974
  return {};
56794
56975
  }
56795
56976
  }
56796
56977
  function writeSecrets(data) {
56797
- const path126 = getSshSecretsPath();
56798
- mkdirSync16(dirname5(path126), { recursive: true });
56799
- writeFileSync19(path126, `${JSON.stringify(data, null, 2)}
56978
+ const path128 = getSshSecretsPath();
56979
+ mkdirSync16(dirname5(path128), { recursive: true });
56980
+ writeFileSync19(path128, `${JSON.stringify(data, null, 2)}
56800
56981
  `, "utf8");
56801
56982
  try {
56802
- chmodSync(path126, 384);
56983
+ chmodSync(path128, 384);
56803
56984
  } catch {
56804
56985
  }
56805
56986
  }
@@ -56828,10 +57009,10 @@ function deleteSshPassword(id3) {
56828
57009
  writeSecrets({ passwords });
56829
57010
  }
56830
57011
  function readStore2() {
56831
- const path126 = getSshTargetsPath();
56832
- if (!existsSync39(path126)) return [];
57012
+ const path128 = getSshTargetsPath();
57013
+ if (!existsSync39(path128)) return [];
56833
57014
  try {
56834
- const parsed = JSON.parse(readFileSync31(path126, "utf8"));
57015
+ const parsed = JSON.parse(readFileSync31(path128, "utf8"));
56835
57016
  const list = Array.isArray(parsed.targets) ? parsed.targets : [];
56836
57017
  return list.filter(
56837
57018
  (t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
@@ -56846,11 +57027,11 @@ function readStore2() {
56846
57027
  }
56847
57028
  }
56848
57029
  function writeStore2(targets) {
56849
- const path126 = getSshTargetsPath();
56850
- mkdirSync16(dirname5(path126), { recursive: true });
57030
+ const path128 = getSshTargetsPath();
57031
+ mkdirSync16(dirname5(path128), { recursive: true });
56851
57032
  const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
56852
57033
  writeFileSync19(
56853
- path126,
57034
+ path128,
56854
57035
  `${JSON.stringify({ targets: clean }, null, 2)}
56855
57036
  `,
56856
57037
  "utf8"
@@ -57096,11 +57277,11 @@ function formatSshTargetsForPrompt() {
57096
57277
  ];
57097
57278
  for (const t of targets) {
57098
57279
  const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
57099
- const path126 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
57280
+ const path128 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
57100
57281
  const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
57101
57282
  const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
57102
57283
  lines.push(
57103
- `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path126}${tags}${allow}`
57284
+ `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path128}${tags}${allow}`
57104
57285
  );
57105
57286
  }
57106
57287
  return lines.join("\n");
@@ -59888,26 +60069,7 @@ function cloneResult(result) {
59888
60069
  }
59889
60070
  }
59890
60071
  function applyTruncation(result, toolName2) {
59891
- if (!result.ok) return result;
59892
- if (typeof result.value === "string") {
59893
- return {
59894
- ok: true,
59895
- value: truncateToolResult(result.value, { toolName: toolName2, spill: false })
59896
- };
59897
- }
59898
- if (result.value && typeof result.value === "object") {
59899
- const v = result.value;
59900
- if (typeof v.content === "string") {
59901
- return {
59902
- ok: true,
59903
- value: {
59904
- ...v,
59905
- content: truncateToolResult(v.content, { toolName: toolName2, spill: false })
59906
- }
59907
- };
59908
- }
59909
- }
59910
- return result;
60072
+ return compactToolResult(result, { toolName: toolName2, spill: false });
59911
60073
  }
59912
60074
  function evictOldest() {
59913
60075
  let oldestKey = null;
@@ -62479,6 +62641,7 @@ function decodeNode(row) {
62479
62641
  status: row.status,
62480
62642
  visibility: row.visibility ?? "project",
62481
62643
  tags: json2(row.tags_json, []),
62644
+ relevantWhen: json2(row.relevant_when_json, []),
62482
62645
  source: json2(row.source_json, {}),
62483
62646
  createdAt: row.created_at,
62484
62647
  updatedAt: row.updated_at,
@@ -62503,6 +62666,7 @@ function nodeSqlValues(node) {
62503
62666
  node.status,
62504
62667
  node.visibility ?? "project",
62505
62668
  JSON.stringify(node.tags),
62669
+ JSON.stringify(node.relevantWhen ?? []),
62506
62670
  JSON.stringify(node.source),
62507
62671
  node.createdAt,
62508
62672
  node.updatedAt,
@@ -62687,7 +62851,7 @@ var SQLITE_MEMORY_SCHEMA_VERSION, SQLITE_MEMORY_BASE_SCHEMA, SQLITE_MEMORY_MIGRA
62687
62851
  var init_sqliteSchema = __esm({
62688
62852
  "src/cli/memory/sqliteSchema.ts"() {
62689
62853
  "use strict";
62690
- SQLITE_MEMORY_SCHEMA_VERSION = 2;
62854
+ SQLITE_MEMORY_SCHEMA_VERSION = 3;
62691
62855
  SQLITE_MEMORY_BASE_SCHEMA = `
62692
62856
  PRAGMA foreign_keys = ON;
62693
62857
  PRAGMA journal_mode = WAL;
@@ -62705,6 +62869,7 @@ CREATE TABLE IF NOT EXISTS memory_nodes (
62705
62869
  status TEXT NOT NULL CHECK (status IN ('active','superseded','retracted','archived')),
62706
62870
  visibility TEXT NOT NULL DEFAULT 'project' CHECK (visibility IN ('project','private')),
62707
62871
  tags_json TEXT NOT NULL DEFAULT '[]',
62872
+ relevant_when_json TEXT NOT NULL DEFAULT '[]',
62708
62873
  source_json TEXT NOT NULL DEFAULT '{}',
62709
62874
  created_at TEXT NOT NULL,
62710
62875
  updated_at TEXT NOT NULL,
@@ -62834,6 +62999,15 @@ SELECT id, visibility, json_extract(source_json, '$.client'), updated_at FROM me
62834
62999
  END;
62835
63000
  INSERT INTO memory_access(memory_id, visibility, owner_client, updated_at)
62836
63001
  SELECT id, visibility, json_extract(source_json, '$.client'), updated_at FROM memory_nodes;
63002
+ `
63003
+ },
63004
+ {
63005
+ // S3 (T-Mem lite): additive associative-trigger column. Legacy rows default
63006
+ // to '[]'; the FTS triggers are untouched (triggers are matched via
63007
+ // json_each, and json_each('[]') yields zero rows, so '[]' never explodes).
63008
+ version: 3,
63009
+ sql: `
63010
+ ALTER TABLE memory_nodes ADD COLUMN relevant_when_json TEXT NOT NULL DEFAULT '[]';
62837
63011
  `
62838
63012
  }
62839
63013
  ];
@@ -62897,10 +63071,10 @@ var init_sqliteBackend = __esm({
62897
63071
  init_sqliteSchema();
62898
63072
  NODE_COLUMNS = `
62899
63073
  id, schema_version, project_id, kind, content, importance, confidence,
62900
- status, visibility, tags_json, source_json, created_at, updated_at, valid_from,
63074
+ status, visibility, tags_json, relevant_when_json, source_json, created_at, updated_at, valid_from,
62901
63075
  valid_until, recorded_at, retracted_at, embedding_ref, metadata_json`;
62902
63076
  INSERT_NODE_SQL = `INSERT INTO memory_nodes (${NODE_COLUMNS})
62903
- VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
63077
+ VALUES (${Array.from({ length: 20 }, () => "?").join(",")})`;
62904
63078
  IMPORT_ID_CHUNK = 500;
62905
63079
  SOURCE_COLUMNS = {
62906
63080
  agent: "agent",
@@ -63004,6 +63178,7 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
63004
63178
  status: input.status ?? "active",
63005
63179
  visibility: input.visibility ?? "project",
63006
63180
  tags: input.tags ?? [],
63181
+ relevantWhen: input.relevantWhen ?? [],
63007
63182
  source: input.source ?? {},
63008
63183
  createdAt,
63009
63184
  updatedAt: now,
@@ -63053,6 +63228,7 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
63053
63228
  ...patch.status ? { status: patch.status } : {},
63054
63229
  ...patch.visibility ? { visibility: patch.visibility } : {},
63055
63230
  ...patch.tags ? { tags: patch.tags } : {},
63231
+ ...patch.relevantWhen ? { relevantWhen: patch.relevantWhen } : {},
63056
63232
  ...patch.source ? { source: patch.source } : {},
63057
63233
  ...patch.metadata ? { metadata: patch.metadata } : {},
63058
63234
  updatedAt: now,
@@ -63071,7 +63247,7 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
63071
63247
  {
63072
63248
  sql: `UPDATE memory_nodes SET
63073
63249
  schema_version=?, project_id=?, kind=?, content=?, importance=?, confidence=?,
63074
- status=?, visibility=?, tags_json=?, source_json=?, created_at=?, updated_at=?, valid_from=?,
63250
+ status=?, visibility=?, tags_json=?, relevant_when_json=?, source_json=?, created_at=?, updated_at=?, valid_from=?,
63075
63251
  valid_until=?, recorded_at=?, retracted_at=?, embedding_ref=?, metadata_json=?
63076
63252
  WHERE id=?`,
63077
63253
  params: [...nodeSqlValues(updated).slice(1), updated.id]
@@ -63107,6 +63283,36 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
63107
63283
  return this.searchCurrent(query, text, expression, false);
63108
63284
  }
63109
63285
  }
63286
+ /**
63287
+ * T-Mem lite: retrieve nodes whose `relevantWhen` triggers overlap the query
63288
+ * tokens. Runs as a separate query so the lexical similarity prefilter in
63289
+ * `search` can never drop an associative hit. `json_each('[]')` yields zero
63290
+ * rows, so empty/legacy triggers are harmless.
63291
+ */
63292
+ async searchRelevantWhen(query) {
63293
+ this.assertReady();
63294
+ const text = query.text?.trim() ?? "";
63295
+ if (!text) return [];
63296
+ const tokens = [
63297
+ ...new Set(text.toLocaleLowerCase().match(/[\p{L}\p{N}_-]{3,}/gu) ?? [])
63298
+ ].slice(0, 24);
63299
+ if (tokens.length === 0) return [];
63300
+ const params = [];
63301
+ const where = [];
63302
+ const clauses = tokens.map(
63303
+ () => `EXISTS (SELECT 1 FROM json_each(n.relevant_when_json) je WHERE instr(' ' || lower(je.value) || ' ', ' ' || ? || ' ') > 0)`
63304
+ );
63305
+ where.push(`(${clauses.join(" OR ")})`);
63306
+ params.push(...tokens);
63307
+ this.addFilters(query, where, params, "n");
63308
+ params.push(boundedLimit(query.limit));
63309
+ const rows = await this.rpc.statement({
63310
+ sql: `SELECT n.* FROM memory_nodes n WHERE ${where.join(" AND ")} ORDER BY n.importance DESC, n.updated_at DESC LIMIT ?`,
63311
+ params,
63312
+ mode: "all"
63313
+ });
63314
+ return rows.map(decodeNode).filter((node) => Boolean(node)).map((node) => ({ node, lexicalRelevance: 1, triggerMatch: 1 }));
63315
+ }
63110
63316
  async searchCurrent(query, text, expression, useFts) {
63111
63317
  const params = [];
63112
63318
  const where = [];
@@ -63507,6 +63713,7 @@ __export(serviceFactory_exports, {
63507
63713
  getMemoryService: () => getMemoryService,
63508
63714
  isMemoryAutoWriteEnabled: () => isMemoryAutoWriteEnabled,
63509
63715
  isMemorySemanticEnabled: () => isMemorySemanticEnabled,
63716
+ isMemoryTriggersEnabled: () => isMemoryTriggersEnabled,
63510
63717
  isMemoryV2Enabled: () => isMemoryV2Enabled
63511
63718
  });
63512
63719
  import { createHash as createHash22 } from "node:crypto";
@@ -63523,6 +63730,9 @@ function isMemoryAutoWriteEnabled(env = process.env) {
63523
63730
  function isMemorySemanticEnabled(env = process.env) {
63524
63731
  return isMemoryV2Enabled(env) && env.ZELARI_MEMORY_SEMANTIC === "1";
63525
63732
  }
63733
+ function isMemoryTriggersEnabled(env = process.env) {
63734
+ return isMemoryV2Enabled(env) && env.ZELARI_MEMORY_TRIGGERS !== "0";
63735
+ }
63526
63736
  function semanticMinScore(env) {
63527
63737
  const value = Number(env.ZELARI_MEMORY_SEMANTIC_MIN_SCORE);
63528
63738
  return Number.isFinite(value) ? Math.max(0, Math.min(value, 1)) : void 0;
@@ -63560,7 +63770,8 @@ async function getMemoryService(projectRoot, env = process.env, options = {}) {
63560
63770
  const service = new DefaultMemoryService(projectId2, backend, {
63561
63771
  ...options.onEvent ? { onEvent: options.onEvent } : {},
63562
63772
  ...embeddingProvider ? { embeddingProvider } : {},
63563
- ...semanticMinScore(env) !== void 0 ? { minSemanticRelevance: semanticMinScore(env) } : {}
63773
+ ...semanticMinScore(env) !== void 0 ? { minSemanticRelevance: semanticMinScore(env) } : {},
63774
+ relevantWhen: isMemoryTriggersEnabled(env)
63564
63775
  });
63565
63776
  if (backend.lastMigration) {
63566
63777
  const migration = backend.lastMigration;
@@ -63842,6 +64053,75 @@ var init_opsKnowledge = __esm({
63842
64053
  }
63843
64054
  });
63844
64055
 
64056
+ // src/cli/memory/onePager.ts
64057
+ import { promises as fs33 } from "node:fs";
64058
+ import * as path84 from "node:path";
64059
+ function isOnePagerEnabled(env = process.env) {
64060
+ return env.ZELARI_ONE_PAGER !== "0";
64061
+ }
64062
+ function slug(text, max = 48) {
64063
+ const line = text.split(/\r?\n/, 1)[0].trim();
64064
+ return line.length <= max ? line : `${line.slice(0, max - 1)}\u2026`;
64065
+ }
64066
+ async function howWeTestIndex(cwd) {
64067
+ try {
64068
+ const stat9 = await fs33.stat(path84.join(cwd, HOW_WE_TEST_RELATIVE));
64069
+ return `${HOW_WE_TEST_RELATIVE} \xB7 ${new Date(stat9.mtimeMs).toISOString()}`;
64070
+ } catch {
64071
+ return null;
64072
+ }
64073
+ }
64074
+ async function procedureAliases(memory) {
64075
+ if (!memory) return null;
64076
+ const nodes = await listVerifiedProcedureNodes(memory);
64077
+ if (!nodes || nodes.length === 0) return null;
64078
+ return nodes.slice(0, MAX_PROCEDURES).map((node) => `- ${slug(node.tags[0] ?? node.content)}`).join("\n");
64079
+ }
64080
+ function truncate(text, cap3) {
64081
+ if (text.length <= cap3) return text;
64082
+ return `${text.slice(0, cap3 - TRUNCATION_MARKER2.length).trimEnd()}${TRUNCATION_MARKER2}`;
64083
+ }
64084
+ async function buildOnePager(opts = {}) {
64085
+ if (!isOnePagerEnabled(opts.env)) return [];
64086
+ try {
64087
+ const cwd = opts.cwd ?? process.cwd();
64088
+ const sections = [];
64089
+ const todos2 = formatTodosForModel(listSessionTodos());
64090
+ if (todos2 && todos2 !== "(no todos)") sections.push(`## Open loops
64091
+ ${todos2}`);
64092
+ const index = await howWeTestIndex(cwd);
64093
+ if (index) sections.push(`## How we test
64094
+ ${index}`);
64095
+ const procedures = await procedureAliases(opts.memory);
64096
+ if (procedures) sections.push(`## Procedures
64097
+ ${procedures}`);
64098
+ if (!opts.skipCompactRecap) {
64099
+ const recap = opts.compactSummary?.trim();
64100
+ if (recap) sections.push(`## Compact recap
64101
+ ${recap.slice(0, SECTION_RECAP_CAP)}`);
64102
+ }
64103
+ if (sections.length === 0) return [];
64104
+ const body = `${ONE_PAGER_PREFIX}
64105
+ ${sections.join("\n\n")}`;
64106
+ return [{ role: "system", content: truncate(body, ONE_PAGER_CHAR_CAP) }];
64107
+ } catch {
64108
+ return [];
64109
+ }
64110
+ }
64111
+ var ONE_PAGER_CHAR_CAP, ONE_PAGER_PREFIX, SECTION_RECAP_CAP, MAX_PROCEDURES, TRUNCATION_MARKER2;
64112
+ var init_onePager = __esm({
64113
+ "src/cli/memory/onePager.ts"() {
64114
+ "use strict";
64115
+ init_sessionTodos();
64116
+ init_howWeTest();
64117
+ ONE_PAGER_CHAR_CAP = 1500;
64118
+ ONE_PAGER_PREFIX = "WORKING SET";
64119
+ SECTION_RECAP_CAP = 400;
64120
+ MAX_PROCEDURES = 8;
64121
+ TRUNCATION_MARKER2 = "\n\u2026(working set truncated)";
64122
+ }
64123
+ });
64124
+
63845
64125
  // src/cli/memory/spineTelemetry.ts
63846
64126
  function spineMemoryEventNote(handle, event) {
63847
64127
  try {
@@ -63925,20 +64205,20 @@ var init_askUserTimeout = __esm({
63925
64205
 
63926
64206
  // src/cli/state/fileStateStore.ts
63927
64207
  import { createHash as createHash24, randomUUID as randomUUID6 } from "node:crypto";
63928
- import { promises as fs33 } from "node:fs";
63929
- import * as path84 from "node:path";
64208
+ import { promises as fs34 } from "node:fs";
64209
+ import * as path85 from "node:path";
63930
64210
  function shortId() {
63931
64211
  return randomUUID6().replace(/-/g, "").slice(0, 12);
63932
64212
  }
63933
64213
  async function writeJsonAtomic(filePath, data) {
63934
- await fs33.mkdir(path84.dirname(filePath), { recursive: true });
64214
+ await fs34.mkdir(path85.dirname(filePath), { recursive: true });
63935
64215
  const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
63936
- await fs33.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
63937
- await fs33.rename(tmp, filePath);
64216
+ await fs34.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
64217
+ await fs34.rename(tmp, filePath);
63938
64218
  }
63939
64219
  async function readJsonFile(filePath) {
63940
64220
  try {
63941
- const raw = await fs33.readFile(filePath, "utf8");
64221
+ const raw = await fs34.readFile(filePath, "utf8");
63942
64222
  return JSON.parse(raw);
63943
64223
  } catch {
63944
64224
  return null;
@@ -63992,13 +64272,13 @@ var init_fileStateStore = __esm({
63992
64272
  indexPath = "";
63993
64273
  async init(projectRoot) {
63994
64274
  this.root = projectRoot;
63995
- this.stateDir = path84.join(projectRoot, ".zelari", "state");
63996
- this.commitsDir = path84.join(this.stateDir, "commits");
63997
- this.artifactsDir = path84.join(this.stateDir, "artifacts");
63998
- this.headPath = path84.join(this.stateDir, "HEAD.json");
63999
- this.indexPath = path84.join(this.stateDir, "index.jsonl");
64000
- await fs33.mkdir(this.commitsDir, { recursive: true });
64001
- await fs33.mkdir(this.artifactsDir, { recursive: true });
64275
+ this.stateDir = path85.join(projectRoot, ".zelari", "state");
64276
+ this.commitsDir = path85.join(this.stateDir, "commits");
64277
+ this.artifactsDir = path85.join(this.stateDir, "artifacts");
64278
+ this.headPath = path85.join(this.stateDir, "HEAD.json");
64279
+ this.indexPath = path85.join(this.stateDir, "index.jsonl");
64280
+ await fs34.mkdir(this.commitsDir, { recursive: true });
64281
+ await fs34.mkdir(this.artifactsDir, { recursive: true });
64002
64282
  }
64003
64283
  async commit(input) {
64004
64284
  if (!input.force && input.verification.ran && !input.verification.ok) {
@@ -64009,13 +64289,13 @@ var init_fileStateStore = __esm({
64009
64289
  const discoveries = input.discoveries ?? [];
64010
64290
  const parent = await this.head();
64011
64291
  const id3 = shortId();
64012
- const artifactRel = path84.join("artifacts", id3);
64013
- const artifactAbs = path84.join(this.artifactsDir, id3);
64014
- await fs33.mkdir(artifactAbs, { recursive: true });
64292
+ const artifactRel = path85.join("artifacts", id3);
64293
+ const artifactAbs = path85.join(this.artifactsDir, id3);
64294
+ await fs34.mkdir(artifactAbs, { recursive: true });
64015
64295
  const summary = defaultSummary(input, discoveries);
64016
- await fs33.writeFile(path84.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
64017
- await writeJsonAtomic(path84.join(artifactAbs, "discoveries.json"), discoveries);
64018
- await writeJsonAtomic(path84.join(artifactAbs, "verification.json"), input.verification);
64296
+ await fs34.writeFile(path85.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
64297
+ await writeJsonAtomic(path85.join(artifactAbs, "discoveries.json"), discoveries);
64298
+ await writeJsonAtomic(path85.join(artifactAbs, "verification.json"), input.verification);
64019
64299
  const meta3 = {
64020
64300
  id: id3,
64021
64301
  parentId: parent?.id ?? null,
@@ -64027,16 +64307,16 @@ var init_fileStateStore = __esm({
64027
64307
  workspaceCheckpointId: input.workspaceCheckpointId,
64028
64308
  verification: {
64029
64309
  ...input.verification,
64030
- reportPath: input.verification.reportPath ?? path84.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
64310
+ reportPath: input.verification.reportPath ?? path85.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
64031
64311
  },
64032
64312
  changedPaths: input.changedPaths ?? [],
64033
64313
  stablePromptHash: input.stablePromptHash,
64034
64314
  discoveryCount: discoveries.length,
64035
64315
  artifactDir: artifactRel.replace(/\\/g, "/")
64036
64316
  };
64037
- await writeJsonAtomic(path84.join(this.commitsDir, `${id3}.json`), meta3);
64317
+ await writeJsonAtomic(path85.join(this.commitsDir, `${id3}.json`), meta3);
64038
64318
  await writeJsonAtomic(this.headPath, { id: id3, updatedAt: meta3.createdAt });
64039
- await fs33.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
64319
+ await fs34.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
64040
64320
  return stripStored(meta3);
64041
64321
  }
64042
64322
  async head() {
@@ -64045,13 +64325,13 @@ var init_fileStateStore = __esm({
64045
64325
  return this.get(head.id);
64046
64326
  }
64047
64327
  async get(id3) {
64048
- const stored = await readJsonFile(path84.join(this.commitsDir, `${id3}.json`));
64328
+ const stored = await readJsonFile(path85.join(this.commitsDir, `${id3}.json`));
64049
64329
  return stored ? stripStored(stored) : null;
64050
64330
  }
64051
64331
  async list(limit = 20) {
64052
64332
  let raw;
64053
64333
  try {
64054
- raw = await fs33.readFile(this.indexPath, "utf8");
64334
+ raw = await fs34.readFile(this.indexPath, "utf8");
64055
64335
  } catch {
64056
64336
  return [];
64057
64337
  }
@@ -64084,9 +64364,9 @@ var init_fileStateStore = __esm({
64084
64364
  async loadDiscoveries(id3) {
64085
64365
  const meta3 = id3 ? await this.get(id3) : await this.head();
64086
64366
  if (!meta3) return [];
64087
- const stored = await readJsonFile(path84.join(this.commitsDir, `${meta3.id}.json`));
64367
+ const stored = await readJsonFile(path85.join(this.commitsDir, `${meta3.id}.json`));
64088
64368
  if (!stored?.artifactDir) return [];
64089
- const discPath = path84.join(this.stateDir, stored.artifactDir, "discoveries.json");
64369
+ const discPath = path85.join(this.stateDir, stored.artifactDir, "discoveries.json");
64090
64370
  return await readJsonFile(discPath) ?? [];
64091
64371
  }
64092
64372
  async materializeContext(id3, maxChars = DEFAULT_MATERIALIZE_CHARS) {
@@ -64297,7 +64577,7 @@ __export(conversationContext_exports, {
64297
64577
  setLastClarification: () => setLastClarification
64298
64578
  });
64299
64579
  import { existsSync as existsSync44 } from "node:fs";
64300
- import { join as join28 } from "node:path";
64580
+ import { join as join29 } from "node:path";
64301
64581
  function getHistory() {
64302
64582
  return history;
64303
64583
  }
@@ -64306,7 +64586,7 @@ function setHistory(messages) {
64306
64586
  history = projected === messages ? [...messages] : projected;
64307
64587
  }
64308
64588
  function compactInPlace(cwd = process.cwd()) {
64309
- const durableStatePresent = existsSync44(join28(cwd, ".zelari", "state", "HEAD.json"));
64589
+ const durableStatePresent = existsSync44(join29(cwd, ".zelari", "state", "HEAD.json"));
64310
64590
  history = applySessionSurface(compactHistory(history, { durableStatePresent }));
64311
64591
  }
64312
64592
  function appendMessages(msgs) {
@@ -64365,10 +64645,10 @@ function formatHistoryMessages(messages, maxTurns = 6, maxTotalChars = 12e3) {
64365
64645
  for (let i = messages.length - 1; i >= 0 && turns < maxTurns; i--) {
64366
64646
  const m = messages[i];
64367
64647
  if (m.role === "user") {
64368
- chunk.push(`User: ${truncate(m.content, 800)}`);
64648
+ chunk.push(`User: ${truncate2(m.content, 800)}`);
64369
64649
  turns += 1;
64370
64650
  } else if (m.role === "assistant" && m.content.trim()) {
64371
- chunk.push(`Assistant: ${truncate(m.content, 2e3)}`);
64651
+ chunk.push(`Assistant: ${truncate2(m.content, 2e3)}`);
64372
64652
  }
64373
64653
  }
64374
64654
  if (chunk.length === 0) return "";
@@ -64407,7 +64687,7 @@ The user CONFIRMED the plan and wants you to IMPLEMENT it ON DISK NOW.
64407
64687
  - Do NOT restart from zero or re-ask for the overall goal.
64408
64688
 
64409
64689
  ## Prior assistant output (plan to implement \u2014 authoritative)
64410
- ${truncate(lastAsst.content, max)}
64690
+ ${truncate2(lastAsst.content, max)}
64411
64691
 
64412
64692
  ## Instruction
64413
64693
  Implement the plan on disk now with mutating tools, then briefly list the files you wrote/edited.`;
@@ -64458,7 +64738,7 @@ function buildAgentUserWithHistory(task, prior) {
64458
64738
  if (anchored) return anchored;
64459
64739
  return buildContinueUserMessage(task, messages, { maxPriorChars: 8e3 }) ?? task;
64460
64740
  }
64461
- function truncate(s, max) {
64741
+ function truncate2(s, max) {
64462
64742
  const t = s.replace(/\s+/g, " ").trim();
64463
64743
  if (t.length <= max) return t;
64464
64744
  return `${t.slice(0, max - 1)}\u2026`;
@@ -64700,10 +64980,10 @@ __export(headless_exports, {
64700
64980
  resolveHeadlessProvider: () => resolveHeadlessProvider
64701
64981
  });
64702
64982
  import { readFileSync as readFileSync34 } from "node:fs";
64703
- import path85 from "node:path";
64983
+ import path86 from "node:path";
64704
64984
  function resolveHeadlessCwd(opts) {
64705
64985
  const raw = typeof opts.cwd === "string" ? opts.cwd.trim() : "";
64706
- return path85.resolve(raw.length > 0 ? raw : process.cwd());
64986
+ return path86.resolve(raw.length > 0 ? raw : process.cwd());
64707
64987
  }
64708
64988
  function defaultProfileForMode(mode) {
64709
64989
  switch (mode) {
@@ -65069,7 +65349,7 @@ __export(headlessSpine_exports, {
65069
65349
  seedHeadlessModelHistory: () => seedHeadlessModelHistory,
65070
65350
  sessionStartedEvent: () => sessionStartedEvent
65071
65351
  });
65072
- import path86 from "node:path";
65352
+ import path87 from "node:path";
65073
65353
  function sessionStartedEvent(handle) {
65074
65354
  return {
65075
65355
  type: "session_started",
@@ -65086,7 +65366,7 @@ async function countVerificationEvidenceInLog(mirror, sessionId2) {
65086
65366
  try {
65087
65367
  await mirror.flush().catch(() => void 0);
65088
65368
  const report = await readSessionLogCached(
65089
- path86.join(mirror.sessionsDir, sessionId2, "events.jsonl"),
65369
+ path87.join(mirror.sessionsDir, sessionId2, "events.jsonl"),
65090
65370
  mirror.replayCache
65091
65371
  );
65092
65372
  return report.events.filter((e) => e.kind === "verification.evidence").length;
@@ -65396,7 +65676,10 @@ async function buildModelContext(input) {
65396
65676
  const sourceHistory = (derived ?? [...input.fallbackHistory]).filter(
65397
65677
  (message) => !isLegacyResourceStatus(message)
65398
65678
  );
65399
- const requestTail = resourceStatusTail(input.resourceSnapshot);
65679
+ const requestTail = [
65680
+ ...resourceStatusTail(input.resourceSnapshot),
65681
+ ...input.volatileOnePager ?? []
65682
+ ];
65400
65683
  const inputTokens = estimateHistoryTokens(sourceHistory);
65401
65684
  const requestSurface = input.systemMessages || input.tools ? {
65402
65685
  provider: input.provider ?? "local",
@@ -65862,9 +66145,9 @@ __export(planDetect_exports, {
65862
66145
  hasWorkspacePlan: () => hasWorkspacePlan
65863
66146
  });
65864
66147
  import { existsSync as existsSync45, readFileSync as readFileSync35 } from "node:fs";
65865
- import { join as join29 } from "node:path";
66148
+ import { join as join30 } from "node:path";
65866
66149
  function hasWorkspacePlan(projectRoot = process.cwd()) {
65867
- const planPath = join29(resolveWorkspaceRoot(projectRoot), "plan.json");
66150
+ const planPath = join30(resolveWorkspaceRoot(projectRoot), "plan.json");
65868
66151
  if (!existsSync45(planPath)) return false;
65869
66152
  try {
65870
66153
  const parsed = JSON.parse(readFileSync35(planPath, "utf8"));
@@ -65882,10 +66165,10 @@ var init_planDetect = __esm({
65882
66165
 
65883
66166
  // src/cli/workspace/projectInstructions.ts
65884
66167
  import { existsSync as existsSync46, readFileSync as readFileSync36 } from "node:fs";
65885
- import { join as join30 } from "node:path";
66168
+ import { join as join31 } from "node:path";
65886
66169
  function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
65887
66170
  for (const name of CANDIDATES) {
65888
- const full = join30(projectRoot, name);
66171
+ const full = join31(projectRoot, name);
65889
66172
  if (!existsSync46(full)) continue;
65890
66173
  try {
65891
66174
  let raw = readFileSync36(full, "utf8");
@@ -65933,7 +66216,7 @@ __export(workspaceSummary_exports, {
65933
66216
  buildZelariReadHint: () => buildZelariReadHint
65934
66217
  });
65935
66218
  import { existsSync as existsSync47, readFileSync as readFileSync37, readdirSync as readdirSync9, statSync as statSync8 } from "node:fs";
65936
- import { join as join31, relative as relative2 } from "node:path";
66219
+ import { join as join32, relative as relative2 } from "node:path";
65937
66220
  function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
65938
66221
  const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
65939
66222
  const name = safeProjectName(projectRoot);
@@ -65966,7 +66249,7 @@ function formatTaskLine(t) {
65966
66249
  }
65967
66250
  function buildPlanSummary(projectRoot = process.cwd(), options) {
65968
66251
  const zelariRoot = resolveWorkspaceRoot(projectRoot);
65969
- const planPath = join31(zelariRoot, "plan.json");
66252
+ const planPath = join32(zelariRoot, "plan.json");
65970
66253
  if (!existsSync47(planPath)) return null;
65971
66254
  let plan;
65972
66255
  try {
@@ -66109,7 +66392,7 @@ function pickNextTask(open2) {
66109
66392
  )[0];
66110
66393
  }
66111
66394
  function buildZelariReadHint(projectRoot = process.cwd()) {
66112
- const planPath = join31(resolveWorkspaceRoot(projectRoot), "plan.json");
66395
+ const planPath = join32(resolveWorkspaceRoot(projectRoot), "plan.json");
66113
66396
  if (!existsSync47(planPath)) return "";
66114
66397
  return [
66115
66398
  "# Council workspace detected (.zelari/) \u2014 DRAFT vault",
@@ -66125,7 +66408,7 @@ function safeProjectName(root) {
66125
66408
  }
66126
66409
  }
66127
66410
  function readPackageJson2(projectRoot) {
66128
- const p3 = join31(projectRoot, "package.json");
66411
+ const p3 = join32(projectRoot, "package.json");
66129
66412
  if (!existsSync47(p3)) return null;
66130
66413
  try {
66131
66414
  return JSON.parse(readFileSync37(p3, "utf8"));
@@ -66178,11 +66461,11 @@ function listShallow(projectRoot, maxEntries) {
66178
66461
  out.push(`\u2026 (+${top.length - count} more)`);
66179
66462
  break;
66180
66463
  }
66181
- const rel2 = relative2(projectRoot, join31(projectRoot, entry.name));
66464
+ const rel2 = relative2(projectRoot, join32(projectRoot, entry.name));
66182
66465
  if (entry.isDirectory()) {
66183
66466
  let inner = "";
66184
66467
  try {
66185
- const sub = readdirSync9(join31(projectRoot, entry.name), {
66468
+ const sub = readdirSync9(join32(projectRoot, entry.name), {
66186
66469
  withFileTypes: true
66187
66470
  }).filter((e) => !e.name.startsWith(".")).slice(0, 4).map((e) => e.name);
66188
66471
  if (sub.length > 0)
@@ -66231,11 +66514,11 @@ var init_workspaceSummary = __esm({
66231
66514
 
66232
66515
  // src/cli/workspace/buildLessonsSummary.ts
66233
66516
  import { existsSync as existsSync48 } from "node:fs";
66234
- import { join as join32 } from "node:path";
66517
+ import { join as join33 } from "node:path";
66235
66518
  function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
66236
66519
  if (process.env["ZELARI_LESSONS"] === "0") return null;
66237
66520
  const zelariRoot = resolveWorkspaceRoot(projectRoot);
66238
- if (!existsSync48(join32(zelariRoot, "lessons.jsonl"))) return null;
66521
+ if (!existsSync48(join33(zelariRoot, "lessons.jsonl"))) return null;
66239
66522
  const lessons = recallLessons(zelariRoot, {
66240
66523
  maxLessons: 5,
66241
66524
  maxBytes: 2048,
@@ -66257,7 +66540,7 @@ __export(composeContext_exports, {
66257
66540
  composeProjectContext: () => composeProjectContext
66258
66541
  });
66259
66542
  import { existsSync as existsSync49, readdirSync as readdirSync10, readFileSync as readFileSync38 } from "node:fs";
66260
- import { join as join33 } from "node:path";
66543
+ import { join as join34 } from "node:path";
66261
66544
  function cap2(text, max, label) {
66262
66545
  if (!text || text.length <= max) return { text: text || "", truncated: false };
66263
66546
  return {
@@ -66274,7 +66557,7 @@ function buildDesignIndex(projectRoot, maxChars) {
66274
66557
  "# Design vault index (.zelari/) \u2014 HYPOTHESES only",
66275
66558
  "Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
66276
66559
  ];
66277
- const docsDir = join33(root, "docs");
66560
+ const docsDir = join34(root, "docs");
66278
66561
  if (existsSync49(docsDir)) {
66279
66562
  try {
66280
66563
  const docs = readdirSync10(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
@@ -66289,11 +66572,11 @@ function buildDesignIndex(projectRoot, maxChars) {
66289
66572
  }
66290
66573
  }
66291
66574
  for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
66292
- if (existsSync49(join33(root, name))) {
66575
+ if (existsSync49(join34(root, name))) {
66293
66576
  lines.push(`- .zelari/${name} present`);
66294
66577
  }
66295
66578
  }
66296
- const decisionsDir = join33(root, "decisions");
66579
+ const decisionsDir = join34(root, "decisions");
66297
66580
  if (existsSync49(decisionsDir)) {
66298
66581
  try {
66299
66582
  const n = readdirSync10(decisionsDir).filter((f) => f.endsWith(".md")).length;
@@ -66395,14 +66678,14 @@ function composeProjectContext(input) {
66395
66678
  }
66396
66679
  function readDurableHeadSync(projectRoot) {
66397
66680
  try {
66398
- const headPath = join33(projectRoot, ".zelari", "state", "HEAD.json");
66681
+ const headPath = join34(projectRoot, ".zelari", "state", "HEAD.json");
66399
66682
  if (!existsSync49(headPath)) return "";
66400
66683
  const head = JSON.parse(readFileSync38(headPath, "utf8"));
66401
66684
  if (!head?.id) return "";
66402
- const metaPath = join33(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
66685
+ const metaPath = join34(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
66403
66686
  if (!existsSync49(metaPath)) return "";
66404
66687
  const meta3 = JSON.parse(readFileSync38(metaPath, "utf8"));
66405
- const discPath = meta3.artifactDir ? join33(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join33(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
66688
+ const discPath = meta3.artifactDir ? join34(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join34(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
66406
66689
  let discoveries = [];
66407
66690
  if (existsSync49(discPath)) {
66408
66691
  discoveries = JSON.parse(readFileSync38(discPath, "utf8"));
@@ -66486,7 +66769,7 @@ import {
66486
66769
  mkdirSync as mkdirSync19,
66487
66770
  renameSync as renameSync5
66488
66771
  } from "node:fs";
66489
- import { join as join34, basename as basename4, dirname as dirname10, relative as relative3 } from "node:path";
66772
+ import { join as join35, basename as basename4, dirname as dirname10, relative as relative3 } from "node:path";
66490
66773
  function createWorkspaceContext(projectRoot = process.cwd()) {
66491
66774
  const rootDir = resolveWorkspaceRoot(projectRoot);
66492
66775
  return {
@@ -66496,7 +66779,7 @@ function createWorkspaceContext(projectRoot = process.cwd()) {
66496
66779
  };
66497
66780
  }
66498
66781
  function planJsonPath(ctx) {
66499
- return join34(ctx.rootDir, "plan.json");
66782
+ return join35(ctx.rootDir, "plan.json");
66500
66783
  }
66501
66784
  function readPlan(ctx) {
66502
66785
  const jsonPath = planJsonPath(ctx);
@@ -66515,8 +66798,8 @@ function readPlan(ctx) {
66515
66798
  } catch {
66516
66799
  }
66517
66800
  }
66518
- const path126 = workspaceFile(ctx.rootDir, "plan");
66519
- const doc = ctx.storage.readIfExists(path126);
66801
+ const path128 = workspaceFile(ctx.rootDir, "plan");
66802
+ const doc = ctx.storage.readIfExists(path128);
66520
66803
  if (!doc) return { phases: [], tasks: [], milestones: [] };
66521
66804
  const meta3 = doc.meta;
66522
66805
  return {
@@ -66609,7 +66892,7 @@ function renderPlanBody(summary) {
66609
66892
  return lines.join("\n");
66610
66893
  }
66611
66894
  function nextAdrId(ctx) {
66612
- const decisionsDir = join34(ctx.rootDir, "decisions");
66895
+ const decisionsDir = join35(ctx.rootDir, "decisions");
66613
66896
  if (!existsSync50(decisionsDir)) return "001";
66614
66897
  const existing = readdirSync11(decisionsDir).filter((f) => f.endsWith(".md")).map((f) => f.match(/^(\d+)-/)).filter((m) => !!m).map((m) => parseInt(m[1], 10));
66615
66898
  const max = existing.length === 0 ? 0 : Math.max(...existing);
@@ -66634,14 +66917,14 @@ function addPhaseRecord(summary, input) {
66634
66917
  return { id: id3, created: true };
66635
66918
  }
66636
66919
  function addTaskRecord(ctx, summary, phaseId, t, options) {
66637
- const slug = slugify3(t.title);
66920
+ const slug2 = slugify3(t.title);
66638
66921
  if (options.dedupe) {
66639
66922
  const existing = summary.tasks.find(
66640
- (k) => k.phaseId === phaseId && k.id.replace(/-\d+$/, "") === `${phaseId}-${slug}`
66923
+ (k) => k.phaseId === phaseId && k.id.replace(/-\d+$/, "") === `${phaseId}-${slug2}`
66641
66924
  );
66642
66925
  if (existing) return { id: existing.id, created: false };
66643
66926
  }
66644
- const id3 = `${phaseId}-${slug}-${summary.tasks.filter((k) => k.phaseId === phaseId).length + 1}`;
66927
+ const id3 = `${phaseId}-${slug2}-${summary.tasks.filter((k) => k.phaseId === phaseId).length + 1}`;
66645
66928
  summary.tasks.push({
66646
66929
  kind: "task",
66647
66930
  id: id3,
@@ -66655,7 +66938,7 @@ function addTaskRecord(ctx, summary, phaseId, t, options) {
66655
66938
  // plan.json record (they already live in tags + the artifact body md).
66656
66939
  files: t.fileRefs
66657
66940
  });
66658
- const taskPath = join34(ctx.rootDir, "plan-tasks", `${id3}.md`);
66941
+ const taskPath = join35(ctx.rootDir, "plan-tasks", `${id3}.md`);
66659
66942
  const meta3 = {
66660
66943
  kind: "task",
66661
66944
  id: id3,
@@ -66697,7 +66980,7 @@ function addMilestoneRecord(ctx, summary, input) {
66697
66980
  dueDate: input.dueDate,
66698
66981
  targetVersion: version2
66699
66982
  });
66700
- const path126 = join34(ctx.rootDir, "milestones", `${id3}.md`);
66983
+ const path128 = join35(ctx.rootDir, "milestones", `${id3}.md`);
66701
66984
  const meta3 = {
66702
66985
  kind: "milestone",
66703
66986
  id: id3,
@@ -66714,7 +66997,7 @@ function addMilestoneRecord(ctx, summary, input) {
66714
66997
  `Target version: ${version2}`,
66715
66998
  ""
66716
66999
  ].join("\n");
66717
- ctx.storage.write(path126, meta3, body);
67000
+ ctx.storage.write(path128, meta3, body);
66718
67001
  return { id: id3, created: true };
66719
67002
  }
66720
67003
  function readPlanSummary(ctx) {
@@ -66918,7 +67201,7 @@ function addIdeaStub(ctx) {
66918
67201
  const tags = args["tags"] ?? [];
66919
67202
  const category = args["category"] ?? "General";
66920
67203
  const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
66921
- const path126 = workspaceArtifact(ctx.rootDir, "decisions", id3);
67204
+ const path128 = workspaceArtifact(ctx.rootDir, "decisions", id3);
66922
67205
  const meta3 = {
66923
67206
  kind: "adr",
66924
67207
  status: "proposed",
@@ -66944,7 +67227,7 @@ function addIdeaStub(ctx) {
66944
67227
  ...consequences.map((c) => `- ${c}`),
66945
67228
  ""
66946
67229
  ].join("\n");
66947
- ctx.storage.write(path126, meta3, body);
67230
+ ctx.storage.write(path128, meta3, body);
66948
67231
  return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
66949
67232
  });
66950
67233
  }
@@ -66995,7 +67278,7 @@ function createNfrSpecStub(ctx) {
66995
67278
  },
66996
67279
  planFeatureKeywords: Array.isArray(args["planFeatureKeywords"]) ? args["planFeatureKeywords"] : void 0
66997
67280
  };
66998
- const outPath = join34(ctx.rootDir, "nfr-spec.json");
67281
+ const outPath = join35(ctx.rootDir, "nfr-spec.json");
66999
67282
  writeFileSync21(outPath, JSON.stringify(spec, null, 2), "utf8");
67000
67283
  return `NFR spec written to nfr-spec.json (${targets.length} target(s)).`;
67001
67284
  });
@@ -67014,8 +67297,8 @@ function createDocumentStub(ctx) {
67014
67297
  const content = args["content"] ?? "";
67015
67298
  const tags = args["tags"] ?? [];
67016
67299
  const normalizedTitle = title.replace(/\.(md|markdown)\s*$/i, "");
67017
- const slug = slugify3(normalizedTitle) || `doc-${Date.now()}`;
67018
- if (slug === "risks") {
67300
+ const slug2 = slugify3(normalizedTitle) || `doc-${Date.now()}`;
67301
+ if (slug2 === "risks") {
67019
67302
  const risksPath = workspaceFile(ctx.rootDir, "risks");
67020
67303
  const riskMeta = {
67021
67304
  kind: "risk",
@@ -67026,15 +67309,15 @@ function createDocumentStub(ctx) {
67026
67309
  ctx.storage.write(risksPath, riskMeta, content);
67027
67310
  return `Document "${title}" created at risks.md (workspace root).`;
67028
67311
  }
67029
- const path126 = workspaceArtifact(ctx.rootDir, "docs", slug);
67312
+ const path128 = workspaceArtifact(ctx.rootDir, "docs", slug2);
67030
67313
  const meta3 = {
67031
67314
  kind: "doc",
67032
- id: slug,
67315
+ id: slug2,
67033
67316
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
67034
67317
  tags
67035
67318
  };
67036
- ctx.storage.write(path126, meta3, content);
67037
- return `Document "${title}" created at docs/${slug}.md.`;
67319
+ ctx.storage.write(path128, meta3, content);
67320
+ return `Document "${title}" created at docs/${slug2}.md.`;
67038
67321
  });
67039
67322
  }
67040
67323
  };
@@ -67059,11 +67342,11 @@ function searchDocumentsStub(ctx) {
67059
67342
  (w) => w.length >= 3 && w !== "or" && w !== "and" && w !== "the"
67060
67343
  );
67061
67344
  const files = [
67062
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "decisions")),
67063
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "docs")),
67064
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "reviews")),
67065
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "plan-tasks")),
67066
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "milestones")),
67345
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "decisions")),
67346
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "docs")),
67347
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "reviews")),
67348
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "plan-tasks")),
67349
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "milestones")),
67067
67350
  workspaceFile(ctx.rootDir, "plan"),
67068
67351
  workspaceFile(ctx.rootDir, "risks")
67069
67352
  ];
@@ -67121,9 +67404,9 @@ function linkDocumentsStub(ctx) {
67121
67404
  const toId = args["toId"] ?? args["targetId"] ?? args["targetPathOrTitle"];
67122
67405
  if (!fromId || !toId) return "linkDocuments requires fromId and toId.";
67123
67406
  const allFiles = [
67124
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "decisions")),
67125
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "docs")),
67126
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "reviews"))
67407
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "decisions")),
67408
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "docs")),
67409
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "reviews"))
67127
67410
  ];
67128
67411
  const source2 = allFiles.find((f) => {
67129
67412
  try {
@@ -67154,9 +67437,9 @@ function getDocumentBacklinksStub(ctx) {
67154
67437
  const targetId = args["targetId"] ?? args["id"];
67155
67438
  if (!targetId) return "getDocumentBacklinks requires targetId.";
67156
67439
  const allFiles = [
67157
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "decisions")),
67158
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "docs")),
67159
- ...ctx.storage.listMarkdown(join34(ctx.rootDir, "reviews"))
67440
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "decisions")),
67441
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "docs")),
67442
+ ...ctx.storage.listMarkdown(join35(ctx.rootDir, "reviews"))
67160
67443
  ];
67161
67444
  const backlinks = [];
67162
67445
  for (const file2 of allFiles) {
@@ -67656,17 +67939,17 @@ import {
67656
67939
  readFileSync as readFileSync40,
67657
67940
  writeFileSync as writeFileSync22
67658
67941
  } from "node:fs";
67659
- import { dirname as dirname11, join as join35 } from "node:path";
67942
+ import { dirname as dirname11, join as join36 } from "node:path";
67660
67943
  function getUserMcpPath() {
67661
- return join35(zelariHome(), "mcp.json");
67944
+ return join36(zelariHome(), "mcp.json");
67662
67945
  }
67663
67946
  function getProjectMcpPath(projectRoot) {
67664
- return join35(projectRoot, ".zelari", "mcp.json");
67947
+ return join36(projectRoot, ".zelari", "mcp.json");
67665
67948
  }
67666
- function readFile10(path126) {
67667
- if (!existsSync51(path126)) return {};
67949
+ function readFile10(path128) {
67950
+ if (!existsSync51(path128)) return {};
67668
67951
  try {
67669
- const parsed = JSON.parse(readFileSync40(path126, "utf8"));
67952
+ const parsed = JSON.parse(readFileSync40(path128, "utf8"));
67670
67953
  const out = {};
67671
67954
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
67672
67955
  const hasCommand = !!cfg && typeof cfg.command === "string" && !!cfg.command.trim();
@@ -67688,10 +67971,10 @@ function readFile10(path126) {
67688
67971
  return {};
67689
67972
  }
67690
67973
  }
67691
- function writeFile4(path126, servers) {
67692
- mkdirSync20(dirname11(path126), { recursive: true });
67974
+ function writeFile4(path128, servers) {
67975
+ mkdirSync20(dirname11(path128), { recursive: true });
67693
67976
  const body = { mcpServers: servers };
67694
- writeFileSync22(path126, `${JSON.stringify(body, null, 2)}
67977
+ writeFileSync22(path128, `${JSON.stringify(body, null, 2)}
67695
67978
  `, "utf8");
67696
67979
  }
67697
67980
  function listMcpServers(projectRoot) {
@@ -67769,9 +68052,9 @@ function upsertMcpServer(opts) {
67769
68052
  error: "either command (stdio) or url (http) is required"
67770
68053
  };
67771
68054
  }
67772
- let path126;
68055
+ let path128;
67773
68056
  if (opts.scope === "user") {
67774
- path126 = getUserMcpPath();
68057
+ path128 = getUserMcpPath();
67775
68058
  } else {
67776
68059
  const root = opts.projectRoot?.trim();
67777
68060
  if (!root) {
@@ -67780,9 +68063,9 @@ function upsertMcpServer(opts) {
67780
68063
  error: "projectRoot required for project scope (Open Folder first)"
67781
68064
  };
67782
68065
  }
67783
- path126 = getProjectMcpPath(root);
68066
+ path128 = getProjectMcpPath(root);
67784
68067
  }
67785
- const current = readFile10(path126);
68068
+ const current = readFile10(path128);
67786
68069
  const previous = current[name];
67787
68070
  current[name] = {
67788
68071
  command: hasCommand ? opts.config.command.trim() : void 0,
@@ -67798,21 +68081,21 @@ function upsertMcpServer(opts) {
67798
68081
  serial: opts.config.serial,
67799
68082
  enabled: opts.config.enabled !== false
67800
68083
  };
67801
- writeFile4(path126, current);
67802
- return { ok: true, path: path126 };
68084
+ writeFile4(path128, current);
68085
+ return { ok: true, path: path128 };
67803
68086
  }
67804
68087
  function removeMcpServer(opts) {
67805
- const path126 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
67806
- if (!path126) {
68088
+ const path128 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
68089
+ if (!path128) {
67807
68090
  return { ok: false, error: "projectRoot required for project scope" };
67808
68091
  }
67809
- const current = readFile10(path126);
68092
+ const current = readFile10(path128);
67810
68093
  if (!(opts.name in current)) {
67811
- return { ok: false, error: `Server "${opts.name}" not found in ${path126}` };
68094
+ return { ok: false, error: `Server "${opts.name}" not found in ${path128}` };
67812
68095
  }
67813
68096
  delete current[opts.name];
67814
- writeFile4(path126, current);
67815
- return { ok: true, path: path126 };
68097
+ writeFile4(path128, current);
68098
+ return { ok: true, path: path128 };
67816
68099
  }
67817
68100
  var ENV_KEY_RE;
67818
68101
  var init_mcpConfigIo = __esm({
@@ -67987,15 +68270,15 @@ __export(mcpManager_exports, {
67987
68270
  registerMcpTools: () => registerMcpTools
67988
68271
  });
67989
68272
  import { existsSync as existsSync52, readFileSync as readFileSync41 } from "node:fs";
67990
- import { join as join36 } from "node:path";
68273
+ import { join as join37 } from "node:path";
67991
68274
  function readMcpConfig(projectRoot = process.cwd(), opts) {
67992
68275
  const merged = {};
67993
68276
  const paths = [];
67994
68277
  if (process.env["ZELARI_MCP_USER"] !== "0") {
67995
- paths.push(join36(zelariHome(), "mcp.json"));
68278
+ paths.push(join37(zelariHome(), "mcp.json"));
67996
68279
  }
67997
68280
  if (!opts?.skipProjectMcp) {
67998
- paths.push(join36(projectRoot, ".zelari", "mcp.json"));
68281
+ paths.push(join37(projectRoot, ".zelari", "mcp.json"));
67999
68282
  }
68000
68283
  for (const p3 of paths) {
68001
68284
  if (!existsSync52(p3)) continue;
@@ -68016,7 +68299,7 @@ async function ensureLoaded(projectRoot) {
68016
68299
  if (state2.loaded) return;
68017
68300
  state2.loaded = true;
68018
68301
  const trusted = isFolderTrusted(projectRoot);
68019
- if (!trusted && existsSync52(join36(projectRoot, ".zelari", "mcp.json"))) {
68302
+ if (!trusted && existsSync52(join37(projectRoot, ".zelari", "mcp.json"))) {
68020
68303
  state2.warnings.push(
68021
68304
  "[mcp] project .zelari/mcp.json ignored \u2014 folder not trusted (run /trust or `zelari-code --trust` to enable project MCP)"
68022
68305
  );
@@ -68286,13 +68569,13 @@ __export(agentsMd_exports, {
68286
68569
  });
68287
68570
  import { existsSync as existsSync53, readFileSync as readFileSync42, writeFileSync as writeFileSync23 } from "node:fs";
68288
68571
  import { createHash as createHash25 } from "node:crypto";
68289
- import { join as join37 } from "node:path";
68572
+ import { join as join38 } from "node:path";
68290
68573
  import { readFile as readFile11 } from "node:fs/promises";
68291
68574
  async function readPackageJson3(projectRoot) {
68292
- const path126 = join37(projectRoot, "package.json");
68293
- if (!existsSync53(path126)) return null;
68575
+ const path128 = join38(projectRoot, "package.json");
68576
+ if (!existsSync53(path128)) return null;
68294
68577
  try {
68295
- return JSON.parse(await readFile11(path126, "utf8"));
68578
+ return JSON.parse(await readFile11(path128, "utf8"));
68296
68579
  } catch {
68297
68580
  return null;
68298
68581
  }
@@ -68314,7 +68597,7 @@ async function genTechStack(ctx) {
68314
68597
  ].join("\n");
68315
68598
  }
68316
68599
  async function genDecisions(ctx) {
68317
- const decisionsDir = join37(ctx.rootDir, "decisions");
68600
+ const decisionsDir = join38(ctx.rootDir, "decisions");
68318
68601
  if (!existsSync53(decisionsDir)) return "_No ADRs yet._";
68319
68602
  const files = ctx.storage.listMarkdown(decisionsDir).sort();
68320
68603
  const accepted = [];
@@ -68340,7 +68623,7 @@ async function genDecisions(ctx) {
68340
68623
  }
68341
68624
  async function genConventions(ctx) {
68342
68625
  const lines = [];
68343
- const claudeMd = join37(ctx.projectRoot, "CLAUDE.MD");
68626
+ const claudeMd = join38(ctx.projectRoot, "CLAUDE.MD");
68344
68627
  if (existsSync53(claudeMd)) {
68345
68628
  const content = readFileSync42(claudeMd, "utf8");
68346
68629
  const match = content.match(/## Architecture rules[\s\S]+?(?=\n## |\n*$)/);
@@ -68374,9 +68657,9 @@ async function genBuild(ctx) {
68374
68657
  ].join("\n");
68375
68658
  }
68376
68659
  async function genOpenQuestions(ctx) {
68377
- const path126 = join37(ctx.rootDir, "risks.md");
68378
- if (!existsSync53(path126)) return "_No open questions._";
68379
- const content = readFileSync42(path126, "utf8");
68660
+ const path128 = join38(ctx.rootDir, "risks.md");
68661
+ if (!existsSync53(path128)) return "_No open questions._";
68662
+ const content = readFileSync42(path128, "utf8");
68380
68663
  const lines = content.split("\n");
68381
68664
  const questions = [];
68382
68665
  let currentTitle = "";
@@ -68450,7 +68733,7 @@ function titleCase(id3) {
68450
68733
  return id3.split("-").map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
68451
68734
  }
68452
68735
  async function updateAgentsMd(ctx, projectRoot) {
68453
- const agentsPath = join37(projectRoot, "AGENTS.MD");
68736
+ const agentsPath = join38(projectRoot, "AGENTS.MD");
68454
68737
  if (existsSync53(agentsPath)) {
68455
68738
  const content = readFileSync42(agentsPath, "utf8");
68456
68739
  const hasAnyMarker = AUTO_SECTIONS.some((id3) => content.includes(MARKER_OPEN(id3)));
@@ -68622,11 +68905,11 @@ var init_completeDesign = __esm({
68622
68905
 
68623
68906
  // src/cli/workspace/planDriftCheck.ts
68624
68907
  import { existsSync as existsSync54, readFileSync as readFileSync43, readdirSync as readdirSync12, statSync as statSync9, writeFileSync as writeFileSync24 } from "node:fs";
68625
- import { join as join38 } from "node:path";
68908
+ import { join as join39 } from "node:path";
68626
68909
  function findCanonicalDoc(rootDir) {
68627
- const docsDir = join38(rootDir, "docs");
68910
+ const docsDir = join39(rootDir, "docs");
68628
68911
  if (!existsSync54(docsDir)) return null;
68629
- const candidates = readdirSync12(docsDir).filter((f) => /^plan-canonical.*\.md$/i.test(f)).map((f) => ({ f, mtime: statSync9(join38(docsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
68912
+ const candidates = readdirSync12(docsDir).filter((f) => /^plan-canonical.*\.md$/i.test(f)).map((f) => ({ f, mtime: statSync9(join39(docsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
68630
68913
  return candidates.length > 0 ? candidates[0].f : null;
68631
68914
  }
68632
68915
  function parseCanonicalDoc(text) {
@@ -68650,9 +68933,9 @@ function versionKey(value) {
68650
68933
  function firstString2(v) {
68651
68934
  return typeof v === "string" && v.trim().length > 0 ? v : null;
68652
68935
  }
68653
- function readFileSyncSafe(path126) {
68936
+ function readFileSyncSafe(path128) {
68654
68937
  try {
68655
- return readFileSync43(path126, "utf8");
68938
+ return readFileSync43(path128, "utf8");
68656
68939
  } catch {
68657
68940
  return null;
68658
68941
  }
@@ -68661,7 +68944,7 @@ async function runPlanDriftCheck(rootDir) {
68661
68944
  if (process.env["ZELARI_DRIFT_CHECK"] === "0") {
68662
68945
  return { ran: false, reason: "ZELARI_DRIFT_CHECK=0 (disabled)" };
68663
68946
  }
68664
- const planPath = join38(rootDir, "plan.json");
68947
+ const planPath = join39(rootDir, "plan.json");
68665
68948
  if (!existsSync54(planPath)) {
68666
68949
  return { ran: false, reason: ".zelari/plan.json missing (not design-phase)" };
68667
68950
  }
@@ -68677,7 +68960,7 @@ async function runPlanDriftCheck(rootDir) {
68677
68960
  const milestones = Array.isArray(plan.milestones) ? plan.milestones : [];
68678
68961
  const phaseIds = new Set(phases.map((p3) => typeof p3.id === "string" ? p3.id : "").filter(Boolean));
68679
68962
  const canonicalName = findCanonicalDoc(rootDir);
68680
- const canonicalText = canonicalName ? readFileSyncSafe(join38(rootDir, "docs", canonicalName)) : null;
68963
+ const canonicalText = canonicalName ? readFileSyncSafe(join39(rootDir, "docs", canonicalName)) : null;
68681
68964
  if (canonicalText !== null) {
68682
68965
  const { activePhases, blockedPrefixes } = parseCanonicalDoc(canonicalText);
68683
68966
  for (const id3 of activePhases) {
@@ -68756,7 +69039,7 @@ async function runPlanDriftCheck(rootDir) {
68756
69039
  const canonicalParsed = canonicalName !== null && canonicalText !== null;
68757
69040
  let reportPath;
68758
69041
  try {
68759
- reportPath = join38(rootDir, "drift-report.json");
69042
+ reportPath = join39(rootDir, "drift-report.json");
68760
69043
  writeFileSync24(
68761
69044
  reportPath,
68762
69045
  JSON.stringify(
@@ -68794,7 +69077,7 @@ var init_planDriftCheck = __esm({
68794
69077
  // src/cli/workspace/projectSmoke.ts
68795
69078
  import { spawn as spawn15 } from "node:child_process";
68796
69079
  import { existsSync as existsSync55, readFileSync as readFileSync44 } from "node:fs";
68797
- import { join as join39 } from "node:path";
69080
+ import { join as join40 } from "node:path";
68798
69081
  function pickSmokeScript(scripts) {
68799
69082
  if (!scripts) return null;
68800
69083
  for (const name of SMOKE_SCRIPT_PRIORITY) {
@@ -68806,7 +69089,7 @@ async function runProjectSmoke(projectRoot, timeoutMs2 = DEFAULT_TIMEOUT_MS3) {
68806
69089
  if (process.env["ZELARI_SMOKE"] === "0") {
68807
69090
  return { ran: false, reason: "ZELARI_SMOKE=0 (disabled)" };
68808
69091
  }
68809
- const pkgPath = join39(projectRoot, "package.json");
69092
+ const pkgPath = join40(projectRoot, "package.json");
68810
69093
  if (!existsSync55(pkgPath)) {
68811
69094
  return { ran: false, reason: "no package.json (skipped)" };
68812
69095
  }
@@ -68900,7 +69183,7 @@ __export(evidenceFromSpine_exports, {
68900
69183
  evidenceRefsFromEventLines: () => evidenceRefsFromEventLines
68901
69184
  });
68902
69185
  import { existsSync as existsSync56, readFileSync as readFileSync45 } from "node:fs";
68903
- import path87 from "node:path";
69186
+ import path88 from "node:path";
68904
69187
  function asRecord5(v) {
68905
69188
  return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
68906
69189
  }
@@ -68938,7 +69221,7 @@ function evidenceRefsFromEventLines(lines) {
68938
69221
  }
68939
69222
  function collectSessionEvidenceRefs(sessionId2) {
68940
69223
  try {
68941
- const file2 = path87.join(sessionsDir(), sessionId2, "events.jsonl");
69224
+ const file2 = path88.join(sessionsDir(), sessionId2, "events.jsonl");
68942
69225
  if (!existsSync56(file2)) return [];
68943
69226
  return evidenceRefsFromEventLines(readFileSync45(file2, "utf8").split("\n"));
68944
69227
  } catch {
@@ -68964,7 +69247,7 @@ __export(postCouncilHook_exports, {
68964
69247
  });
68965
69248
  import { spawn as spawn16 } from "node:child_process";
68966
69249
  import { existsSync as existsSync57, readFileSync as readFileSync46 } from "node:fs";
68967
- import { join as join40 } from "node:path";
69250
+ import { join as join41 } from "node:path";
68968
69251
  async function runCompleteDesignPostProcessor(ctx, options) {
68969
69252
  if (options?.runMode === "implementation") {
68970
69253
  return {
@@ -68975,8 +69258,8 @@ async function runCompleteDesignPostProcessor(ctx, options) {
68975
69258
  if (process.env["ZELARI_COMPLETE_DESIGN"] === "0") {
68976
69259
  return { ran: false, reason: "ZELARI_COMPLETE_DESIGN=0 (disabled)" };
68977
69260
  }
68978
- const planJsonPath2 = join40(ctx.rootDir, "plan.json");
68979
- const scriptPath = join40(ctx.projectRoot, "complete-design.mjs");
69261
+ const planJsonPath2 = join41(ctx.rootDir, "plan.json");
69262
+ const scriptPath = join41(ctx.projectRoot, "complete-design.mjs");
68980
69263
  if (!existsSync57(planJsonPath2)) {
68981
69264
  return {
68982
69265
  ran: false,
@@ -69188,8 +69471,8 @@ async function runPostCouncilHook(ctx, options) {
69188
69471
  sources: scope.sources
69189
69472
  } : void 0
69190
69473
  });
69191
- const path126 = writeCouncilCompletion(ctx.rootDir, completion);
69192
- completionHook = { ran: true, path: path126, completion };
69474
+ const path128 = writeCouncilCompletion(ctx.rootDir, completion);
69475
+ completionHook = { ran: true, path: path128, completion };
69193
69476
  } catch (err) {
69194
69477
  completionHook = {
69195
69478
  ran: true,
@@ -69228,13 +69511,13 @@ __export(councilFeedback_exports, {
69228
69511
  FeedbackStore: () => FeedbackStore
69229
69512
  });
69230
69513
  import {
69231
- promises as fs34,
69514
+ promises as fs35,
69232
69515
  existsSync as existsSync58,
69233
69516
  readFileSync as readFileSync47,
69234
69517
  writeFileSync as writeFileSync25,
69235
69518
  mkdirSync as mkdirSync21
69236
69519
  } from "node:fs";
69237
- import path88 from "node:path";
69520
+ import path89 from "node:path";
69238
69521
  var FeedbackStore;
69239
69522
  var init_councilFeedback = __esm({
69240
69523
  "src/cli/councilFeedback.ts"() {
@@ -69351,7 +69634,7 @@ var init_councilFeedback = __esm({
69351
69634
  }
69352
69635
  }
69353
69636
  save() {
69354
- mkdirSync21(path88.dirname(this.file), { recursive: true });
69637
+ mkdirSync21(path89.dirname(this.file), { recursive: true });
69355
69638
  writeFileSync25(
69356
69639
  this.file,
69357
69640
  JSON.stringify({ entries: this.entries }, null, 2),
@@ -69361,7 +69644,7 @@ var init_councilFeedback = __esm({
69361
69644
  /** Async variant of load for callers that prefer async IO. */
69362
69645
  async loadAsync() {
69363
69646
  try {
69364
- const raw = await fs34.readFile(this.file, "utf-8");
69647
+ const raw = await fs35.readFile(this.file, "utf-8");
69365
69648
  const parsed = JSON.parse(raw);
69366
69649
  if (parsed && Array.isArray(parsed.entries)) {
69367
69650
  this.entries = parsed.entries.filter(
@@ -69418,22 +69701,77 @@ var init_buildPolicy = __esm({
69418
69701
  var ledger_exports = {};
69419
69702
  __export(ledger_exports, {
69420
69703
  EVOLUTION_ENV: () => EVOLUTION_ENV,
69704
+ EVOLUTION_PATHS: () => EVOLUTION_PATHS,
69705
+ FINDINGS_REL: () => FINDINGS_REL,
69421
69706
  HONESTY_CHECK_PREFIX: () => HONESTY_CHECK_PREFIX,
69422
69707
  LEDGER_REL: () => LEDGER_REL,
69708
+ appendFindings: () => appendFindings,
69423
69709
  appendLedgerEntry: () => appendLedgerEntry,
69424
69710
  evolutionMode: () => evolutionMode,
69711
+ findingFingerprint: () => findingFingerprint,
69712
+ findingsPath: () => findingsPath,
69425
69713
  honestyFromVerificationResults: () => honestyFromVerificationResults,
69426
69714
  ledgerPath: () => ledgerPath,
69427
69715
  ledgerStats: () => ledgerStats,
69716
+ readFindings: () => readFindings,
69428
69717
  readLedger: () => readLedger
69429
69718
  });
69430
69719
  import { appendFileSync as appendFileSync4, existsSync as existsSync59, mkdirSync as mkdirSync22, readFileSync as readFileSync48 } from "node:fs";
69431
- import path89 from "node:path";
69720
+ import path90 from "node:path";
69721
+ function findingFingerprint(f) {
69722
+ return [f.kind || "unknown", f.operator || "-", f.surface || "-", f.signal || "-"].join("|");
69723
+ }
69724
+ function findingsPath(cwd) {
69725
+ return path90.join(cwd, FINDINGS_REL);
69726
+ }
69727
+ function appendFindings(cwd, findings) {
69728
+ if (evolutionMode() === "0") {
69729
+ return { written: false, reason: `${EVOLUTION_ENV} != shadow \u2014 findings write skipped` };
69730
+ }
69731
+ if (findings.length === 0) {
69732
+ return { written: false, reason: "no findings" };
69733
+ }
69734
+ try {
69735
+ const file2 = findingsPath(cwd);
69736
+ mkdirSync22(path90.dirname(file2), { recursive: true });
69737
+ appendFileSync4(file2, `${findings.map((f) => JSON.stringify(f)).join("\n")}
69738
+ `, "utf8");
69739
+ return { written: true, path: file2 };
69740
+ } catch (err) {
69741
+ return {
69742
+ written: false,
69743
+ reason: `findings append failed (fail-open): ${err instanceof Error ? err.message : String(err)}`
69744
+ };
69745
+ }
69746
+ }
69747
+ function readFindings(cwd) {
69748
+ const file2 = findingsPath(cwd);
69749
+ if (!existsSync59(file2)) return [];
69750
+ let raw;
69751
+ try {
69752
+ raw = readFileSync48(file2, "utf8");
69753
+ } catch {
69754
+ return [];
69755
+ }
69756
+ const out = [];
69757
+ for (const line of raw.split("\n")) {
69758
+ const trimmed = line.trim();
69759
+ if (!trimmed) continue;
69760
+ try {
69761
+ const parsed = JSON.parse(trimmed);
69762
+ if (parsed && typeof parsed === "object" && typeof parsed.kind === "string") {
69763
+ out.push(parsed);
69764
+ }
69765
+ } catch {
69766
+ }
69767
+ }
69768
+ return out;
69769
+ }
69432
69770
  function evolutionMode(env = process.env) {
69433
69771
  return env[EVOLUTION_ENV] === "shadow" ? "shadow" : "0";
69434
69772
  }
69435
69773
  function ledgerPath(cwd) {
69436
- return path89.join(cwd, LEDGER_REL);
69774
+ return path90.join(cwd, LEDGER_REL);
69437
69775
  }
69438
69776
  function honestyFromVerificationResults(results) {
69439
69777
  if (!results) return void 0;
@@ -69448,7 +69786,7 @@ function appendLedgerEntry(cwd, entry) {
69448
69786
  }
69449
69787
  try {
69450
69788
  const file2 = ledgerPath(cwd);
69451
- mkdirSync22(path89.dirname(file2), { recursive: true });
69789
+ mkdirSync22(path90.dirname(file2), { recursive: true });
69452
69790
  appendFileSync4(file2, `${JSON.stringify(entry)}
69453
69791
  `, "utf8");
69454
69792
  return { written: true, path: file2 };
@@ -69559,12 +69897,23 @@ function ledgerStats(entries) {
69559
69897
  byClassFitness
69560
69898
  };
69561
69899
  }
69562
- var EVOLUTION_ENV, LEDGER_REL, HONESTY_CHECK_PREFIX, TIER_WEIGHTS, UNTIERED_WEIGHT;
69900
+ var EVOLUTION_ENV, LEDGER_REL, FINDINGS_REL, EVOLUTION_PATHS, HONESTY_CHECK_PREFIX, TIER_WEIGHTS, UNTIERED_WEIGHT;
69563
69901
  var init_ledger = __esm({
69564
69902
  "src/cli/evolution/ledger.ts"() {
69565
69903
  "use strict";
69566
69904
  EVOLUTION_ENV = "ZELARI_EVOLUTION";
69567
- LEDGER_REL = path89.join(".zelari", "evolution", "ledger.jsonl");
69905
+ LEDGER_REL = path90.join(".zelari", "evolution", "ledger.jsonl");
69906
+ FINDINGS_REL = path90.join(".zelari", "evolution", "findings.jsonl");
69907
+ EVOLUTION_PATHS = {
69908
+ /** Outcome ledger (ADR-0036) — one JSON object per run. */
69909
+ ledger: LEDGER_REL,
69910
+ /** Instance-level findings ledger — the input to the pattern ledger (S1). */
69911
+ findings: FINDINGS_REL,
69912
+ /** Proposals store — owned by tools/eval evolvePropose (read-only here). */
69913
+ proposals: path90.join(".zelari", "evolution", "proposals.jsonl"),
69914
+ /** Failure-pattern clusters — derived, append-only (S1). */
69915
+ patternLedger: path90.join(".zelari", "evolution", "pattern-ledger.jsonl")
69916
+ };
69568
69917
  HONESTY_CHECK_PREFIX = "synthesis.";
69569
69918
  TIER_WEIGHTS = {
69570
69919
  build: 1,
@@ -69706,8 +70055,8 @@ __export(fileBackend_exports, {
69706
70055
  isMemoryEnabled: () => isMemoryEnabled
69707
70056
  });
69708
70057
  import { randomUUID as randomUUID7 } from "node:crypto";
69709
- import { promises as fs35 } from "node:fs";
69710
- import * as path90 from "node:path";
70058
+ import { promises as fs36 } from "node:fs";
70059
+ import * as path91 from "node:path";
69711
70060
  function tokenize2(text) {
69712
70061
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
69713
70062
  }
@@ -69760,9 +70109,9 @@ var init_fileBackend = __esm({
69760
70109
  logPath = "";
69761
70110
  memoryDir = "";
69762
70111
  async init(projectRoot) {
69763
- this.memoryDir = path90.join(projectRoot, ".zelari", "memory");
69764
- this.logPath = path90.join(this.memoryDir, "log.jsonl");
69765
- await fs35.mkdir(this.memoryDir, { recursive: true });
70112
+ this.memoryDir = path91.join(projectRoot, ".zelari", "memory");
70113
+ this.logPath = path91.join(this.memoryDir, "log.jsonl");
70114
+ await fs36.mkdir(this.memoryDir, { recursive: true });
69766
70115
  }
69767
70116
  async add(content, metadata2 = {}, graph) {
69768
70117
  const fact = {
@@ -69772,7 +70121,7 @@ var init_fileBackend = __esm({
69772
70121
  ...graph ? { graph } : {},
69773
70122
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
69774
70123
  };
69775
- await fs35.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
70124
+ await fs36.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
69776
70125
  return fact.id;
69777
70126
  }
69778
70127
  async search(query, options = {}) {
@@ -69800,7 +70149,7 @@ var init_fileBackend = __esm({
69800
70149
  async readAll() {
69801
70150
  let raw;
69802
70151
  try {
69803
- raw = await fs35.readFile(this.logPath, "utf8");
70152
+ raw = await fs36.readFile(this.logPath, "utf8");
69804
70153
  } catch {
69805
70154
  return [];
69806
70155
  }
@@ -69833,23 +70182,23 @@ var init_fileBackend = __esm({
69833
70182
  });
69834
70183
 
69835
70184
  // src/cli/traceStore.ts
69836
- import { promises as fs36 } from "node:fs";
69837
- import * as path91 from "node:path";
70185
+ import { promises as fs37 } from "node:fs";
70186
+ import * as path92 from "node:path";
69838
70187
  function traceDir(projectRoot) {
69839
- return path91.join(projectRoot, ".zelari", "trace");
70188
+ return path92.join(projectRoot, ".zelari", "trace");
69840
70189
  }
69841
70190
  function tracePath(projectRoot, missionId) {
69842
- return path91.join(traceDir(projectRoot), `${missionId}.json`);
70191
+ return path92.join(traceDir(projectRoot), `${missionId}.json`);
69843
70192
  }
69844
70193
  async function saveTrace(projectRoot, missionId, entries) {
69845
70194
  const dir = traceDir(projectRoot);
69846
- await fs36.mkdir(dir, { recursive: true });
70195
+ await fs37.mkdir(dir, { recursive: true });
69847
70196
  const payload = {
69848
70197
  missionId,
69849
70198
  ts: Date.now(),
69850
70199
  entries
69851
70200
  };
69852
- await fs36.writeFile(
70201
+ await fs37.writeFile(
69853
70202
  tracePath(projectRoot, missionId),
69854
70203
  JSON.stringify(payload, null, 2) + "\n",
69855
70204
  "utf8"
@@ -69880,8 +70229,8 @@ __export(zelariMission_exports, {
69880
70229
  runZelariMission: () => runZelariMission
69881
70230
  });
69882
70231
  import { randomUUID as randomUUID8 } from "node:crypto";
69883
- import { promises as fs37 } from "node:fs";
69884
- import * as path92 from "node:path";
70232
+ import { promises as fs38 } from "node:fs";
70233
+ import * as path93 from "node:path";
69885
70234
  function resolveMaxIterations(env = process.env) {
69886
70235
  const raw = env.ZELARI_MISSION_MAX_ITER;
69887
70236
  const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
@@ -69924,10 +70273,10 @@ function isMissionAutoStart(env = process.env) {
69924
70273
  return env.ZELARI_MISSION_AUTO === "1";
69925
70274
  }
69926
70275
  async function writeMissionState(projectRoot, state3) {
69927
- const dir = path92.join(projectRoot, ".zelari");
69928
- await fs37.mkdir(dir, { recursive: true });
69929
- await fs37.writeFile(
69930
- path92.join(dir, "mission-state.json"),
70276
+ const dir = path93.join(projectRoot, ".zelari");
70277
+ await fs38.mkdir(dir, { recursive: true });
70278
+ await fs38.writeFile(
70279
+ path93.join(dir, "mission-state.json"),
69931
70280
  JSON.stringify(state3, null, 2) + "\n",
69932
70281
  "utf8"
69933
70282
  );
@@ -69940,8 +70289,8 @@ async function writeMissionState(projectRoot, state3) {
69940
70289
  }
69941
70290
  async function loadMissionState(projectRoot) {
69942
70291
  try {
69943
- const raw = await fs37.readFile(
69944
- path92.join(projectRoot, ".zelari", "mission-state.json"),
70292
+ const raw = await fs38.readFile(
70293
+ path93.join(projectRoot, ".zelari", "mission-state.json"),
69945
70294
  "utf8"
69946
70295
  );
69947
70296
  const parsed = JSON.parse(raw);
@@ -70700,7 +71049,7 @@ function safeSocketPath(socketPath) {
70700
71049
  return socketPath.trim();
70701
71050
  }
70702
71051
  function startPermissionBroker(socketPath, handlers, opts) {
70703
- const path126 = safeSocketPath(socketPath);
71052
+ const path128 = safeSocketPath(socketPath);
70704
71053
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
70705
71054
  const sockets = /* @__PURE__ */ new Set();
70706
71055
  const server = createServer2((socket) => {
@@ -70800,10 +71149,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
70800
71149
  return new Promise((resolve11, reject) => {
70801
71150
  const onError = (err) => reject(err);
70802
71151
  server.once("error", onError);
70803
- server.listen(path126, () => {
71152
+ server.listen(path128, () => {
70804
71153
  server.removeListener("error", onError);
70805
71154
  resolve11({
70806
- socketPath: path126,
71155
+ socketPath: path128,
70807
71156
  stop: () => new Promise((res) => {
70808
71157
  for (const s of sockets) s.destroy();
70809
71158
  sockets.clear();
@@ -70814,7 +71163,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
70814
71163
  if (done) return;
70815
71164
  done = true;
70816
71165
  if (process.platform !== "win32") {
70817
- unlink(path126, () => res());
71166
+ unlink(path128, () => res());
70818
71167
  } else {
70819
71168
  res();
70820
71169
  }
@@ -70827,11 +71176,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
70827
71176
  });
70828
71177
  }
70829
71178
  function requestBrokerAsk(socketPath, ask, opts) {
70830
- const path126 = safeSocketPath(socketPath);
71179
+ const path128 = safeSocketPath(socketPath);
70831
71180
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
70832
71181
  const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
70833
71182
  return new Promise((resolve11, reject) => {
70834
- const socket = connect(path126);
71183
+ const socket = connect(path128);
70835
71184
  let buffer = "";
70836
71185
  let settled = false;
70837
71186
  const settle = (fn) => {
@@ -70846,7 +71195,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
70846
71195
  settle(
70847
71196
  () => reject(
70848
71197
  new Error(
70849
- `permission broker unavailable at "${path126}" (connect timed out after ${connectTimeoutMs}ms)`
71198
+ `permission broker unavailable at "${path128}" (connect timed out after ${connectTimeoutMs}ms)`
70850
71199
  )
70851
71200
  )
70852
71201
  );
@@ -72087,7 +72436,7 @@ var init_prereqChecks = __esm({
72087
72436
 
72088
72437
  // src/cli/plugins/prefs.ts
72089
72438
  import { existsSync as existsSync63, readFileSync as readFileSync51, writeFileSync as writeFileSync26, mkdirSync as mkdirSync23 } from "node:fs";
72090
- import path99 from "node:path";
72439
+ import path100 from "node:path";
72091
72440
  function getPluginPrefsPath() {
72092
72441
  return pluginsPrefsPath();
72093
72442
  }
@@ -72110,7 +72459,7 @@ function getPluginPrefs() {
72110
72459
  }
72111
72460
  function writePluginPrefs(prefs) {
72112
72461
  const file2 = getPluginPrefsPath();
72113
- mkdirSync23(path99.dirname(file2), { recursive: true });
72462
+ mkdirSync23(path100.dirname(file2), { recursive: true });
72114
72463
  writeFileSync26(file2, JSON.stringify(prefs, null, 2), {
72115
72464
  encoding: "utf-8",
72116
72465
  mode: 384
@@ -72148,7 +72497,7 @@ __export(registry_exports, {
72148
72497
  isBinaryOnPath: () => isBinaryOnPath
72149
72498
  });
72150
72499
  import { existsSync as existsSync64 } from "node:fs";
72151
- import path100 from "node:path";
72500
+ import path101 from "node:path";
72152
72501
  function detectLocalBin(bin) {
72153
72502
  return (cwd) => {
72154
72503
  try {
@@ -72166,7 +72515,7 @@ function isBinaryOnPath(bin, opts = {}) {
72166
72515
  const platform = opts.platform ?? process.platform;
72167
72516
  const exists = opts.exists ?? existsSync64;
72168
72517
  const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
72169
- const pathMod = platform === "win32" ? path100.win32 : path100.posix;
72518
+ const pathMod = platform === "win32" ? path101.win32 : path101.posix;
72170
72519
  const sep5 = platform === "win32" ? ";" : ":";
72171
72520
  const dirs = pathEnv.split(sep5).filter((d) => d.length > 0);
72172
72521
  const candidates = [bin];
@@ -73305,11 +73654,11 @@ var init_policy = __esm({
73305
73654
  });
73306
73655
 
73307
73656
  // src/cli/orchestration/facts.ts
73308
- import { promises as fs46 } from "node:fs";
73309
- import path104 from "node:path";
73657
+ import { promises as fs47 } from "node:fs";
73658
+ import path105 from "node:path";
73310
73659
  async function collectRepoFileCount(root = process.cwd()) {
73311
73660
  try {
73312
- await fs46.readdir(root);
73661
+ await fs47.readdir(root);
73313
73662
  } catch {
73314
73663
  return void 0;
73315
73664
  }
@@ -73320,13 +73669,13 @@ async function collectRepoFileCount(root = process.cwd()) {
73320
73669
  const dir = queue.pop();
73321
73670
  let entries;
73322
73671
  try {
73323
- entries = await fs46.readdir(dir, { withFileTypes: true });
73672
+ entries = await fs47.readdir(dir, { withFileTypes: true });
73324
73673
  } catch {
73325
73674
  continue;
73326
73675
  }
73327
73676
  for (const e of entries) {
73328
73677
  if (e.isDirectory()) {
73329
- if (!SKIP_DIRS2.has(e.name)) queue.push(path104.join(dir, e.name));
73678
+ if (!SKIP_DIRS2.has(e.name)) queue.push(path105.join(dir, e.name));
73330
73679
  } else if (e.isFile()) {
73331
73680
  count++;
73332
73681
  if (count > MAX_WALK_FILES) return count;
@@ -73424,7 +73773,7 @@ var init_streamScrub = __esm({
73424
73773
  });
73425
73774
 
73426
73775
  // src/cli/harnessState.ts
73427
- import path105 from "node:path";
73776
+ import path106 from "node:path";
73428
73777
  function asString4(v) {
73429
73778
  return typeof v === "string" ? v : "";
73430
73779
  }
@@ -73599,7 +73948,7 @@ function contractFor(t) {
73599
73948
  };
73600
73949
  }
73601
73950
  async function readHarnessState(sessionDir, cache5) {
73602
- const report = await readSessionLogCached(path105.join(sessionDir, "events.jsonl"), cache5);
73951
+ const report = await readSessionLogCached(path106.join(sessionDir, "events.jsonl"), cache5);
73603
73952
  return deriveHarnessState(report.events);
73604
73953
  }
73605
73954
  var init_harnessState = __esm({
@@ -73610,12 +73959,12 @@ var init_harnessState = __esm({
73610
73959
  });
73611
73960
 
73612
73961
  // src/cli/headless/harnessStateEmit.ts
73613
- import path106 from "node:path";
73962
+ import path107 from "node:path";
73614
73963
  async function emitHarnessStateEvent(opts) {
73615
73964
  if (opts.output !== "json") return;
73616
73965
  try {
73617
73966
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.workspaceRoot });
73618
- const state3 = await readHarnessState(path106.join(sessionsDir2, opts.spine.sessionId));
73967
+ const state3 = await readHarnessState(path107.join(sessionsDir2, opts.spine.sessionId));
73619
73968
  opts.emitEvent({ type: "harness_state", ...state3 });
73620
73969
  } catch (err) {
73621
73970
  const msg = err instanceof Error ? err.message : String(err);
@@ -74154,13 +74503,13 @@ var init_verifierLifecycle = __esm({
74154
74503
 
74155
74504
  // src/cli/extensions/sandboxedFs.ts
74156
74505
  import { promises as fsp } from "node:fs";
74157
- import path107 from "node:path";
74506
+ import path108 from "node:path";
74158
74507
  function errText(prefix, p3, err) {
74159
74508
  const msg = err instanceof Error ? err.message : String(err);
74160
74509
  return `[extension-fs] ${prefix} "${p3}": ${msg}`;
74161
74510
  }
74162
74511
  function bindSandboxedFs(root) {
74163
- const resolvedRoot = path107.resolve(root);
74512
+ const resolvedRoot = path108.resolve(root);
74164
74513
  return {
74165
74514
  root: resolvedRoot,
74166
74515
  async readFile(relativePath) {
@@ -74176,7 +74525,7 @@ function bindSandboxedFs(root) {
74176
74525
  try {
74177
74526
  const target = resolveSandboxedPath(relativePath, { root: resolvedRoot });
74178
74527
  verifyContainment(target, { root: resolvedRoot });
74179
- await fsp.mkdir(path107.dirname(target), { recursive: true });
74528
+ await fsp.mkdir(path108.dirname(target), { recursive: true });
74180
74529
  await fsp.writeFile(target, data, "utf8");
74181
74530
  return typedOk({ path: target });
74182
74531
  } catch (err) {
@@ -74203,15 +74552,15 @@ var init_sandboxedFs = __esm({
74203
74552
  });
74204
74553
 
74205
74554
  // src/cli/extensions/loader.ts
74206
- import { join as join46 } from "node:path";
74555
+ import { join as join47 } from "node:path";
74207
74556
  import { readdirSync as readdirSync14, readFileSync as readFileSync54 } from "node:fs";
74208
74557
  import { createHash as createHash26 } from "node:crypto";
74209
74558
  import { pathToFileURL as pathToFileURL3 } from "node:url";
74210
74559
  function globalExtensionsDir() {
74211
- return join46(zelariHome(), "extensions");
74560
+ return join47(zelariHome(), "extensions");
74212
74561
  }
74213
74562
  function projectExtensionsDir(projectRoot) {
74214
- return join46(projectRoot, ".zelari", "extensions");
74563
+ return join47(projectRoot, ".zelari", "extensions");
74215
74564
  }
74216
74565
  function sha256File(file2) {
74217
74566
  return createHash26("sha256").update(readFileSync54(file2)).digest("hex");
@@ -74223,7 +74572,7 @@ function candidateFiles(dir) {
74223
74572
  } catch {
74224
74573
  return [];
74225
74574
  }
74226
- return names.filter((n) => EXTENSION_FILE_EXTS.has(n.slice(n.lastIndexOf(".")).toLowerCase())).sort().map((n) => join46(dir, n));
74575
+ return names.filter((n) => EXTENSION_FILE_EXTS.has(n.slice(n.lastIndexOf(".")).toLowerCase())).sort().map((n) => join47(dir, n));
74227
74576
  }
74228
74577
  function extractExtension(mod) {
74229
74578
  const m = mod;
@@ -74245,14 +74594,14 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
74245
74594
  skipped
74246
74595
  };
74247
74596
  const fsRoot = options.fsRoot ?? process.cwd();
74248
- let fs51 = null;
74597
+ let fs52 = null;
74249
74598
  const pending = [];
74250
74599
  for (const dir of dirs) {
74251
74600
  const files = candidateFiles(dir.path);
74252
74601
  if (files.length === 0) continue;
74253
74602
  let lock = null;
74254
74603
  try {
74255
- lock = JSON.parse(readFileSync54(join46(dir.path, EXTENSIONS_LOCK_FILE), "utf8"));
74604
+ lock = JSON.parse(readFileSync54(join47(dir.path, EXTENSIONS_LOCK_FILE), "utf8"));
74256
74605
  } catch {
74257
74606
  lock = null;
74258
74607
  if (dirHasLockFile(dir.path)) {
@@ -74300,9 +74649,9 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
74300
74649
  skipped.push(`${file2}: missing ZelariExtension export`);
74301
74650
  continue;
74302
74651
  }
74303
- if (!fs51) fs51 = bindSandboxedFs(fsRoot);
74652
+ if (!fs52) fs52 = bindSandboxedFs(fsRoot);
74304
74653
  try {
74305
- await runtime.registry.registerExtension(ext, { fs: fs51 });
74654
+ await runtime.registry.registerExtension(ext, { fs: fs52 });
74306
74655
  runtime.loaded.push({ id: ext.id, file: file2, scope });
74307
74656
  } catch (err) {
74308
74657
  const msg = err instanceof Error ? err.message : String(err);
@@ -74319,7 +74668,7 @@ function basenameOf(file2) {
74319
74668
  }
74320
74669
  function dirHasLockFile(dir) {
74321
74670
  try {
74322
- readFileSync54(join46(dir, EXTENSIONS_LOCK_FILE));
74671
+ readFileSync54(join47(dir, EXTENSIONS_LOCK_FILE));
74323
74672
  return true;
74324
74673
  } catch {
74325
74674
  return false;
@@ -74360,8 +74709,8 @@ var init_loader = __esm({
74360
74709
  });
74361
74710
 
74362
74711
  // src/cli/headless/runOneTurn.ts
74363
- import { promises as fs47 } from "node:fs";
74364
- import path108 from "node:path";
74712
+ import { promises as fs48 } from "node:fs";
74713
+ import path109 from "node:path";
74365
74714
  function planModeFromOpts(opts) {
74366
74715
  return (opts.phase ?? "build") === "plan";
74367
74716
  }
@@ -74683,10 +75032,16 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
74683
75032
  wireSplit = { stable: systemMessages[0].content, volatile: "" };
74684
75033
  }
74685
75034
  await spine.beginResourceTurn();
75035
+ const onePager = await buildOnePager({
75036
+ cwd,
75037
+ memory: nativeMemory ?? null,
75038
+ skipCompactRecap: true
75039
+ });
74686
75040
  const modelContext = await buildModelContext({
74687
75041
  fallbackHistory: seededHistory.history,
74688
75042
  session: spine.spine,
74689
75043
  resourceSnapshot: spine.spine.latestResourceSnapshot(),
75044
+ volatileOnePager: onePager,
74690
75045
  phase: opts.phase ?? "build",
74691
75046
  model,
74692
75047
  provider,
@@ -74735,7 +75090,10 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
74735
75090
  cwd,
74736
75091
  providerStream,
74737
75092
  buildLiveness: { mutationRequired: wantWrites, maxRecoveries: 2 },
74738
- requestTail: () => resourceStatusTail(spine.spine.latestResourceSnapshot()),
75093
+ requestTail: () => [
75094
+ ...resourceStatusTail(spine.spine.latestResourceSnapshot()),
75095
+ ...onePager
75096
+ ],
74739
75097
  // 2.6 Phase 3: host-owned pre-dispatch resource gate (doc section 11.3).
74740
75098
  // Advisory by default; ZELARI_RESOURCE_ENFORCEMENT=protected enables the
74741
75099
  // protected verification reserve. Degrade-and-stop (null gate = allow).
@@ -74991,8 +75349,8 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
74991
75349
  if (json3) {
74992
75350
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
74993
75351
  else {
74994
- await fs47.mkdir(path108.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
74995
- await fs47.writeFile(opts.exportSessionPath, json3, "utf8");
75352
+ await fs48.mkdir(path109.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
75353
+ await fs48.writeFile(opts.exportSessionPath, json3, "utf8");
74996
75354
  }
74997
75355
  }
74998
75356
  } catch {
@@ -75065,6 +75423,7 @@ var init_runOneTurn = __esm({
75065
75423
  init_nativeVerification();
75066
75424
  init_verifierLifecycle();
75067
75425
  init_modelContextBuilder();
75426
+ init_onePager();
75068
75427
  init_metrics3();
75069
75428
  init_messageUsage();
75070
75429
  init_headlessSpine();
@@ -75968,6 +76327,150 @@ var init_run = __esm({
75968
76327
  }
75969
76328
  });
75970
76329
 
76330
+ // src/cli/evolution/patternLedger.ts
76331
+ var patternLedger_exports = {};
76332
+ __export(patternLedger_exports, {
76333
+ DEFAULT_MIN_DISTINCT_TASKS: () => DEFAULT_MIN_DISTINCT_TASKS,
76334
+ PATTERN_LEDGER_REL: () => PATTERN_LEDGER_REL,
76335
+ appendClusters: () => appendClusters,
76336
+ categorizeCluster: () => categorizeCluster,
76337
+ clusterFailures: () => clusterFailures,
76338
+ clusterKeyFor: () => clusterKeyFor,
76339
+ makeTaskKey: () => makeTaskKey,
76340
+ patternLedgerPath: () => patternLedgerPath,
76341
+ readClusters: () => readClusters
76342
+ });
76343
+ import { createHash as createHash27 } from "node:crypto";
76344
+ import { appendFileSync as appendFileSync6, existsSync as existsSync69, mkdirSync as mkdirSync26, readFileSync as readFileSync55 } from "node:fs";
76345
+ import path110 from "node:path";
76346
+ function nonEmpty2(v) {
76347
+ return typeof v === "string" && v.trim() !== "" ? v : void 0;
76348
+ }
76349
+ function makeTaskKey(input) {
76350
+ const mission = input.missionTaskId?.trim();
76351
+ if (mission) return mission;
76352
+ const normalized = (input.taskText ?? "").trim().replace(/\s+/g, " ").toLowerCase();
76353
+ if (normalized) return createHash27("sha256").update(normalized).digest("hex").slice(0, 12);
76354
+ return input.sessionId;
76355
+ }
76356
+ function clusterKeyFor(input) {
76357
+ const tool = nonEmpty2(input.tool) ?? "unknown";
76358
+ const errorClass = nonEmpty2(input.errorClass) ?? "unknown";
76359
+ const termination = nonEmpty2(input.termination) ?? nonEmpty2(input.kind) ?? "unknown";
76360
+ return `${tool}|${errorClass}|${termination}`;
76361
+ }
76362
+ function categorizeCluster(input) {
76363
+ const operator = nonEmpty2(input.operator) ?? "";
76364
+ const haystack = `${input.kind ?? ""} ${operator} ${input.patchHint ?? ""}`.toLowerCase();
76365
+ const touchesHarness = /tool|verif|observ|compact|resource|budget|boundary|interrupt|loop|context/.test(haystack);
76366
+ if (operator === "revise_skill" && !touchesHarness) return "model-accommodation";
76367
+ return "harness-repair";
76368
+ }
76369
+ function deriveTool(f) {
76370
+ const ev = f.evidence ?? {};
76371
+ const explicit = nonEmpty2(ev.toolName) ?? nonEmpty2(ev.tool);
76372
+ if (explicit) return explicit;
76373
+ const signal = nonEmpty2(f.signal);
76374
+ return signal && signal.includes(":") ? signal.slice(0, signal.indexOf(":")) : "unknown";
76375
+ }
76376
+ function clusterFailures(findings, opts) {
76377
+ const minDistinct = Math.max(1, Math.floor(opts?.minDistinctTasks ?? DEFAULT_MIN_DISTINCT_TASKS));
76378
+ const buckets = /* @__PURE__ */ new Map();
76379
+ let unmapped = 0;
76380
+ for (const f of findings) {
76381
+ const sessions = f.sessions ?? [];
76382
+ const taskKey = nonEmpty2(f.taskKey) ?? nonEmpty2(sessions[0]);
76383
+ if (!taskKey) {
76384
+ unmapped += 1;
76385
+ continue;
76386
+ }
76387
+ const tool = deriveTool(f);
76388
+ const errorClass = nonEmpty2(f.evidence?.errorClass) ?? "unknown";
76389
+ const termination = nonEmpty2(f.evidence?.termination) ?? nonEmpty2(f.kind) ?? "unknown";
76390
+ const key = clusterKeyFor({ tool, errorClass, termination, kind: f.kind });
76391
+ let b = buckets.get(key);
76392
+ if (!b) {
76393
+ b = { tool, errorClass, termination, count: 0, findings: 0, sessions: /* @__PURE__ */ new Set(), taskKeys: /* @__PURE__ */ new Set(), taskClasses: /* @__PURE__ */ new Set() };
76394
+ buckets.set(key, b);
76395
+ }
76396
+ b.findings += 1;
76397
+ b.count += typeof f.count === "number" ? f.count : 1;
76398
+ for (const s of sessions) b.sessions.add(s);
76399
+ b.taskKeys.add(taskKey);
76400
+ if (!b.operator) b.operator = nonEmpty2(f.operator);
76401
+ if (!b.patchHint) b.patchHint = nonEmpty2(f.surface);
76402
+ const taskClass = nonEmpty2(f.taskClass);
76403
+ if (taskClass) b.taskClasses.add(taskClass);
76404
+ if (f.firstAt && (!b.firstAt || f.firstAt < b.firstAt)) b.firstAt = f.firstAt;
76405
+ if (f.lastAt && (!b.lastAt || f.lastAt > b.lastAt)) b.lastAt = f.lastAt;
76406
+ }
76407
+ const clusters = [];
76408
+ for (const [key, b] of [...buckets.entries()].sort(([a], [c]) => a < c ? -1 : a > c ? 1 : 0)) {
76409
+ if (b.taskKeys.size < minDistinct) {
76410
+ unmapped += b.findings;
76411
+ continue;
76412
+ }
76413
+ clusters.push({
76414
+ id: `c-${String(clusters.length + 1).padStart(4, "0")}`,
76415
+ key,
76416
+ category: categorizeCluster({ kind: b.termination, operator: b.operator, patchHint: b.patchHint ?? key }),
76417
+ tool: b.tool,
76418
+ errorClass: b.errorClass,
76419
+ termination: b.termination,
76420
+ count: b.count,
76421
+ sessions: [...b.sessions].sort(),
76422
+ taskKeys: [...b.taskKeys].sort(),
76423
+ distinctTasks: b.taskKeys.size,
76424
+ taskClasses: [...b.taskClasses].sort(),
76425
+ firstAt: b.firstAt ?? "",
76426
+ lastAt: b.lastAt ?? ""
76427
+ });
76428
+ }
76429
+ return { clusters, unmapped };
76430
+ }
76431
+ function patternLedgerPath(cwd = process.cwd()) {
76432
+ return path110.join(cwd, PATTERN_LEDGER_REL);
76433
+ }
76434
+ async function appendClusters(clusters, cwd = process.cwd()) {
76435
+ if (clusters.length === 0) return;
76436
+ try {
76437
+ const file2 = patternLedgerPath(cwd);
76438
+ mkdirSync26(path110.dirname(file2), { recursive: true });
76439
+ appendFileSync6(file2, `${clusters.map((c) => JSON.stringify(c)).join("\n")}
76440
+ `, "utf8");
76441
+ } catch {
76442
+ }
76443
+ }
76444
+ async function readClusters(cwd = process.cwd()) {
76445
+ const file2 = patternLedgerPath(cwd);
76446
+ if (!existsSync69(file2)) return [];
76447
+ let raw;
76448
+ try {
76449
+ raw = readFileSync55(file2, "utf8");
76450
+ } catch {
76451
+ return [];
76452
+ }
76453
+ const out = [];
76454
+ for (const line of raw.split("\n")) {
76455
+ const trimmed = line.trim();
76456
+ if (!trimmed) continue;
76457
+ try {
76458
+ const parsed = JSON.parse(trimmed);
76459
+ if (parsed && typeof parsed === "object" && typeof parsed.key === "string") out.push(parsed);
76460
+ } catch {
76461
+ }
76462
+ }
76463
+ return out;
76464
+ }
76465
+ var PATTERN_LEDGER_REL, DEFAULT_MIN_DISTINCT_TASKS;
76466
+ var init_patternLedger = __esm({
76467
+ "src/cli/evolution/patternLedger.ts"() {
76468
+ "use strict";
76469
+ PATTERN_LEDGER_REL = path110.join(".zelari", "evolution", "pattern-ledger.jsonl");
76470
+ DEFAULT_MIN_DISTINCT_TASKS = 2;
76471
+ }
76472
+ });
76473
+
75971
76474
  // src/cli/evolution/runTelemetry.ts
75972
76475
  var runTelemetry_exports = {};
75973
76476
  __export(runTelemetry_exports, {
@@ -76045,10 +76548,10 @@ __export(triggerLock_exports, {
76045
76548
  lockPath: () => lockPath,
76046
76549
  releaseLock: () => releaseLock
76047
76550
  });
76048
- import { promises as fs48 } from "node:fs";
76049
- import * as path109 from "node:path";
76551
+ import { promises as fs49 } from "node:fs";
76552
+ import * as path111 from "node:path";
76050
76553
  function lockPath(projectRoot) {
76051
- return path109.join(projectRoot, ".zelari", "trigger.lock");
76554
+ return path111.join(projectRoot, ".zelari", "trigger.lock");
76052
76555
  }
76053
76556
  function isPidAlive(pid) {
76054
76557
  try {
@@ -76061,10 +76564,10 @@ function isPidAlive(pid) {
76061
76564
  }
76062
76565
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
76063
76566
  const lp = lockPath(projectRoot);
76064
- const dir = path109.dirname(lp);
76065
- await fs48.mkdir(dir, { recursive: true });
76567
+ const dir = path111.dirname(lp);
76568
+ await fs49.mkdir(dir, { recursive: true });
76066
76569
  try {
76067
- const raw = await fs48.readFile(lp, "utf8");
76570
+ const raw = await fs49.readFile(lp, "utf8");
76068
76571
  const existing = JSON.parse(raw);
76069
76572
  if (existing.pid && isPidAlive(existing.pid)) {
76070
76573
  return { acquired: false, heldBy: existing.pid, lockPath: lp };
@@ -76075,13 +76578,13 @@ async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date())
76075
76578
  pid: process.pid,
76076
76579
  acquiredAt: now().toISOString()
76077
76580
  };
76078
- await fs48.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
76581
+ await fs49.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
76079
76582
  return { acquired: true, lockPath: lp };
76080
76583
  }
76081
76584
  async function releaseLock(projectRoot) {
76082
76585
  const lp = lockPath(projectRoot);
76083
76586
  try {
76084
- await fs48.unlink(lp);
76587
+ await fs49.unlink(lp);
76085
76588
  } catch {
76086
76589
  }
76087
76590
  }
@@ -76098,8 +76601,8 @@ __export(runHeadless_exports, {
76098
76601
  dispatchHeadlessTurn: () => dispatchHeadlessTurn,
76099
76602
  runHeadless: () => runHeadless
76100
76603
  });
76101
- import { promises as fs49 } from "node:fs";
76102
- import path110 from "node:path";
76604
+ import { promises as fs50 } from "node:fs";
76605
+ import path112 from "node:path";
76103
76606
  import { randomUUID as randomUUID10 } from "node:crypto";
76104
76607
  async function runHeadless(opts) {
76105
76608
  resetTaskSpawnCount();
@@ -76386,11 +76889,11 @@ async function runHeadlessKrakenGraph(opts, provider, model, providerStream, ext
76386
76889
  try {
76387
76890
  let preflightGraph;
76388
76891
  if (opts.runPlan && opts.runPlan.trim() !== "") {
76389
- const planPath = path110.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
76892
+ const planPath = path112.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
76390
76893
  log(`loading pre-flight plan: ${planPath}`);
76391
76894
  let raw;
76392
76895
  try {
76393
- raw = await fs49.readFile(planPath, "utf8");
76896
+ raw = await fs50.readFile(planPath, "utf8");
76394
76897
  } catch (e) {
76395
76898
  log(`plan file not found: ${planPath} (${e.message})`);
76396
76899
  exitCode = 1;
@@ -76444,10 +76947,10 @@ async function runHeadlessKrakenGraph(opts, provider, model, providerStream, ext
76444
76947
  log(formatKrakenGraphAscii2(graph));
76445
76948
  if (opts.planOnly) {
76446
76949
  const planId = randomUUID10();
76447
- const planDir = path110.join(cwd, ".zelari", "radio");
76448
- const planPath = path110.join(planDir, `plan-${planId}.json`);
76449
- await fs49.mkdir(planDir, { recursive: true });
76450
- await fs49.writeFile(
76950
+ const planDir = path112.join(cwd, ".zelari", "radio");
76951
+ const planPath = path112.join(planDir, `plan-${planId}.json`);
76952
+ await fs50.mkdir(planDir, { recursive: true });
76953
+ await fs50.writeFile(
76451
76954
  planPath,
76452
76955
  JSON.stringify(
76453
76956
  { id: graph.id, nodes: [...graph.nodes.values()] },
@@ -76549,16 +77052,32 @@ ${formatKrakenGraphDigest2(
76549
77052
  } catch {
76550
77053
  }
76551
77054
  try {
76552
- const { appendLedgerEntry: appendLedgerEntry2, evolutionMode: evolutionMode2 } = await Promise.resolve().then(() => (init_ledger(), ledger_exports));
77055
+ const { appendLedgerEntry: appendLedgerEntry2, appendFindings: appendFindings2, evolutionMode: evolutionMode2 } = await Promise.resolve().then(() => (init_ledger(), ledger_exports));
76553
77056
  const { classifyTask: classifyTask2 } = await Promise.resolve().then(() => (init_classifyTask(), classifyTask_exports));
77057
+ const { makeTaskKey: makeTaskKey2 } = await Promise.resolve().then(() => (init_patternLedger(), patternLedger_exports));
76554
77058
  if (evolutionMode2() === "shadow") {
77059
+ const taskText = opts.task ?? "";
77060
+ const at = (/* @__PURE__ */ new Date()).toISOString();
77061
+ const taskClass = classifyTask2({ prompt: taskText }).taskClass;
76555
77062
  appendLedgerEntry2(cwd, {
76556
77063
  runId: spine.sessionId,
76557
- at: (/* @__PURE__ */ new Date()).toISOString(),
77064
+ at,
76558
77065
  mode: "shadow",
76559
- taskClass: classifyTask2({ prompt: opts.task ?? "" }).taskClass,
77066
+ taskClass,
76560
77067
  verdict: exitCode === 0 ? "PASS" : exitCode === 3 ? "FAIL" : "UNKNOWN"
76561
77068
  });
77069
+ appendFindings2(cwd, [{
77070
+ kind: "run-termination",
77071
+ operator: "needs_human_review",
77072
+ surface: "run:outcome",
77073
+ signal: exitCode === 0 ? "completed" : "failed",
77074
+ count: 1,
77075
+ sessions: [spine.sessionId],
77076
+ taskKey: makeTaskKey2({ taskText, sessionId: spine.sessionId }),
77077
+ taskClass,
77078
+ firstAt: at,
77079
+ evidence: { termination: exitCode === 0 ? "completed" : exitCode === 3 ? "not-converged" : "error" }
77080
+ }]);
76562
77081
  }
76563
77082
  } catch {
76564
77083
  }
@@ -76692,9 +77211,15 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
76692
77211
  parameters: tool.function.parameters
76693
77212
  }));
76694
77213
  await spine.beginResourceTurn();
77214
+ const onePager = await buildOnePager({
77215
+ cwd,
77216
+ memory: nativeMemory ?? null,
77217
+ skipCompactRecap: true
77218
+ });
76695
77219
  const councilContext = await buildModelContext({
76696
77220
  fallbackHistory: seededHistory.history,
76697
77221
  session: spine.spine,
77222
+ volatileOnePager: onePager,
76698
77223
  phase: councilRunMode === "design-phase" ? "plan" : "build",
76699
77224
  model,
76700
77225
  provider,
@@ -76829,14 +77354,17 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
76829
77354
  } catch {
76830
77355
  }
76831
77356
  try {
76832
- const { appendLedgerEntry: appendLedgerEntry2, evolutionMode: evolutionMode2 } = await Promise.resolve().then(() => (init_ledger(), ledger_exports));
77357
+ const { appendLedgerEntry: appendLedgerEntry2, appendFindings: appendFindings2, evolutionMode: evolutionMode2 } = await Promise.resolve().then(() => (init_ledger(), ledger_exports));
76833
77358
  const { classifyTask: classifyTask2 } = await Promise.resolve().then(() => (init_classifyTask(), classifyTask_exports));
77359
+ const { makeTaskKey: makeTaskKey2 } = await Promise.resolve().then(() => (init_patternLedger(), patternLedger_exports));
76834
77360
  if (evolutionMode2() === "shadow") {
77361
+ const taskClass = classifyTask2({ prompt: effectiveTask }).taskClass;
77362
+ const verdict = signal.aborted ? "UNKNOWN" : exitCode === 0 ? "PASS" : exitCode === 3 ? "FAIL" : "UNKNOWN";
76835
77363
  appendLedgerEntry2(cwd, {
76836
77364
  runId: spine.sessionId,
76837
77365
  at: (/* @__PURE__ */ new Date()).toISOString(),
76838
77366
  mode: "shadow",
76839
- taskClass: classifyTask2({ prompt: effectiveTask }).taskClass,
77367
+ taskClass,
76840
77368
  // Steal #1/#2 wiring: real efficiency + attribution fields — the
76841
77369
  // ledger schema carried them since ADR-0036, this site never wrote them.
76842
77370
  latencyMs: Date.now() - councilStartedAt,
@@ -76851,8 +77379,20 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
76851
77379
  // post-council hook (no verification report in scope, see
76852
77380
  // runHeadlessZelariBody for that path), so the key is omitted.
76853
77381
  ...telemetry.usage().usageReports > 0 ? { cacheHitTokens: telemetry.usage().cacheHitTokens } : {},
76854
- verdict: signal.aborted ? "UNKNOWN" : exitCode === 0 ? "PASS" : exitCode === 3 ? "FAIL" : "UNKNOWN"
77382
+ verdict
76855
77383
  });
77384
+ appendFindings2(cwd, [{
77385
+ kind: "run-termination",
77386
+ operator: "needs_human_review",
77387
+ surface: "run:outcome",
77388
+ signal: verdict === "PASS" ? "completed" : "failed",
77389
+ count: 1,
77390
+ sessions: [spine.sessionId],
77391
+ taskKey: makeTaskKey2({ taskText: effectiveTask, sessionId: spine.sessionId }),
77392
+ taskClass,
77393
+ firstAt: (/* @__PURE__ */ new Date()).toISOString(),
77394
+ evidence: { termination: verdict === "PASS" ? "completed" : verdict === "FAIL" ? "not-converged" : "error" }
77395
+ }]);
76856
77396
  }
76857
77397
  } catch {
76858
77398
  }
@@ -76863,8 +77403,8 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
76863
77403
  if (json3) {
76864
77404
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
76865
77405
  else {
76866
- await fs49.mkdir(path110.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
76867
- await fs49.writeFile(opts.exportSessionPath, json3, "utf8");
77406
+ await fs50.mkdir(path112.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
77407
+ await fs50.writeFile(opts.exportSessionPath, json3, "utf8");
76868
77408
  }
76869
77409
  }
76870
77410
  } catch {
@@ -76964,9 +77504,15 @@ async function runHeadlessZelariBody(opts, provider, model, providerStream, extr
76964
77504
  parameters: tool.function.parameters
76965
77505
  }));
76966
77506
  await spine.beginResourceTurn();
77507
+ const onePager = await buildOnePager({
77508
+ cwd: projectRoot,
77509
+ memory: nativeMissionMemory ?? null,
77510
+ skipCompactRecap: true
77511
+ });
76967
77512
  const missionContext = await buildModelContext({
76968
77513
  fallbackHistory: seededHistory.history,
76969
77514
  session: spine.spine,
77515
+ volatileOnePager: onePager,
76970
77516
  phase: opts.phase ?? "build",
76971
77517
  model,
76972
77518
  provider,
@@ -77341,8 +77887,8 @@ ${ragContext}` : slicePrompt;
77341
77887
  if (json3) {
77342
77888
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
77343
77889
  else {
77344
- await fs49.mkdir(path110.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
77345
- await fs49.writeFile(opts.exportSessionPath, json3, "utf8");
77890
+ await fs50.mkdir(path112.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
77891
+ await fs50.writeFile(opts.exportSessionPath, json3, "utf8");
77346
77892
  }
77347
77893
  }
77348
77894
  } catch {
@@ -77374,6 +77920,7 @@ var init_runHeadless = __esm({
77374
77920
  init_verificationBridge();
77375
77921
  init_completionProofPersist();
77376
77922
  init_modelContextBuilder();
77923
+ init_onePager();
77377
77924
  init_metrics3();
77378
77925
  init_headlessSpine();
77379
77926
  init_harnessStateEmit();
@@ -77874,7 +78421,7 @@ var init_jsonApi = __esm({
77874
78421
  });
77875
78422
 
77876
78423
  // src/cli/memory/mcpAdapter.ts
77877
- import * as path111 from "node:path";
78424
+ import * as path113 from "node:path";
77878
78425
  var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
77879
78426
  var init_mcpAdapter = __esm({
77880
78427
  "src/cli/memory/mcpAdapter.ts"() {
@@ -77910,6 +78457,7 @@ var init_mcpAdapter = __esm({
77910
78457
  confidence: external_exports.number().finite().min(0).max(1).optional(),
77911
78458
  visibility: MemoryVisibilitySchema.default("private"),
77912
78459
  tags: external_exports.array(external_exports.string().min(1).max(120)).max(64).optional(),
78460
+ relevant_when: external_exports.array(external_exports.string().min(1).max(120)).max(8).optional(),
77913
78461
  source,
77914
78462
  metadata: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
77915
78463
  }).strict();
@@ -77940,7 +78488,7 @@ var init_mcpAdapter = __esm({
77940
78488
  {
77941
78489
  name: "zelari_memory_add",
77942
78490
  description: "Add a scoped memory. Secrets are scanned and source.client is enforced by the server.",
77943
- inputSchema: { type: "object", properties: { project_id: { type: "string" }, kind: { type: "string" }, content: { type: "string", maxLength: 64e3 }, importance: { type: "number", minimum: 0, maximum: 1 }, confidence: { type: "number", minimum: 0, maximum: 1 }, visibility: { type: "string", enum: ["project", "private"], default: "private" }, tags: { type: "array", items: { type: "string" } }, source: { type: "object" }, metadata: { type: "object" } }, required: ["project_id", "kind", "content"] }
78491
+ inputSchema: { type: "object", properties: { project_id: { type: "string" }, kind: { type: "string" }, content: { type: "string", maxLength: 64e3 }, importance: { type: "number", minimum: 0, maximum: 1 }, confidence: { type: "number", minimum: 0, maximum: 1 }, visibility: { type: "string", enum: ["project", "private"], default: "private" }, tags: { type: "array", items: { type: "string" } }, relevant_when: { type: "array", items: { type: "string", maxLength: 120 }, maxItems: 8 }, source: { type: "object" }, metadata: { type: "object" } }, required: ["project_id", "kind", "content"] }
77944
78492
  },
77945
78493
  {
77946
78494
  name: "zelari_memory_link",
@@ -78044,8 +78592,8 @@ var init_mcpAdapter = __esm({
78044
78592
  this.takeWrite();
78045
78593
  const externalFile = args.source?.file;
78046
78594
  if (externalFile) {
78047
- const normalized = path111.normalize(externalFile);
78048
- if (path111.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path111.sep}`)) {
78595
+ const normalized = path113.normalize(externalFile);
78596
+ if (path113.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path113.sep}`)) {
78049
78597
  throw new Error("source.file must be project-relative and cannot escape the project");
78050
78598
  }
78051
78599
  }
@@ -78056,6 +78604,7 @@ var init_mcpAdapter = __esm({
78056
78604
  confidence: args.confidence,
78057
78605
  visibility: args.visibility,
78058
78606
  tags: args.tags,
78607
+ relevantWhen: args.relevant_when,
78059
78608
  source: {
78060
78609
  ...args.source ?? {},
78061
78610
  ...externalFile ? { file: externalFile.replace(/\\/g, "/") } : {},
@@ -78549,36 +79098,36 @@ var init_permissionCli = __esm({
78549
79098
 
78550
79099
  // src/cli/companion/config.ts
78551
79100
  import {
78552
- existsSync as existsSync69,
78553
- mkdirSync as mkdirSync26,
78554
- readFileSync as readFileSync55,
79101
+ existsSync as existsSync70,
79102
+ mkdirSync as mkdirSync27,
79103
+ readFileSync as readFileSync56,
78555
79104
  statSync as statSync13,
78556
79105
  writeFileSync as writeFileSync28
78557
79106
  } from "node:fs";
78558
- import { join as join48, resolve as resolve9 } from "node:path";
78559
- import { createHash as createHash27, randomBytes as randomBytes7, timingSafeEqual } from "node:crypto";
79107
+ import { join as join49, resolve as resolve9 } from "node:path";
79108
+ import { createHash as createHash28, randomBytes as randomBytes7, timingSafeEqual } from "node:crypto";
78560
79109
  function getZelariHome() {
78561
79110
  return zelariHome();
78562
79111
  }
78563
79112
  function getCompanionConfigPath() {
78564
- return join48(getZelariHome(), "companion.json");
79113
+ return join49(getZelariHome(), "companion.json");
78565
79114
  }
78566
79115
  function getCompanionTokenPath() {
78567
- return join48(getZelariHome(), "companion.token");
79116
+ return join49(getZelariHome(), "companion.token");
78568
79117
  }
78569
79118
  function ensureHome() {
78570
79119
  const home = getZelariHome();
78571
- if (!existsSync69(home)) {
78572
- mkdirSync26(home, { recursive: true });
79120
+ if (!existsSync70(home)) {
79121
+ mkdirSync27(home, { recursive: true });
78573
79122
  }
78574
79123
  }
78575
79124
  function loadCompanionConfig() {
78576
- const path126 = getCompanionConfigPath();
78577
- if (!existsSync69(path126)) {
79125
+ const path128 = getCompanionConfigPath();
79126
+ if (!existsSync70(path128)) {
78578
79127
  return { projects: [] };
78579
79128
  }
78580
79129
  try {
78581
- const raw = JSON.parse(readFileSync55(path126, "utf8"));
79130
+ const raw = JSON.parse(readFileSync56(path128, "utf8"));
78582
79131
  const projects = Array.isArray(raw.projects) ? raw.projects.filter(
78583
79132
  (p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
78584
79133
  ).map((p3) => ({
@@ -78616,24 +79165,24 @@ function loadOrCreateToken(explicit) {
78616
79165
  return { token: explicit.trim(), created: false };
78617
79166
  }
78618
79167
  ensureHome();
78619
- const path126 = getCompanionTokenPath();
78620
- if (existsSync69(path126)) {
78621
- const t = readFileSync55(path126, "utf8").trim();
79168
+ const path128 = getCompanionTokenPath();
79169
+ if (existsSync70(path128)) {
79170
+ const t = readFileSync56(path128, "utf8").trim();
78622
79171
  if (t) return { token: t, created: false };
78623
79172
  }
78624
79173
  const token = randomBytes7(24).toString("base64url");
78625
- writeFileSync28(path126, token + "\n", "utf8");
79174
+ writeFileSync28(path128, token + "\n", "utf8");
78626
79175
  try {
78627
- const fs51 = __require("node:fs");
78628
- fs51.chmodSync?.(path126, 384);
79176
+ const fs52 = __require("node:fs");
79177
+ fs52.chmodSync?.(path128, 384);
78629
79178
  } catch {
78630
79179
  }
78631
79180
  return { token, created: true };
78632
79181
  }
78633
79182
  function tokenMatches(expected, provided) {
78634
79183
  if (!provided) return false;
78635
- const a = createHash27("sha256").update(expected).digest();
78636
- const b = createHash27("sha256").update(provided).digest();
79184
+ const a = createHash28("sha256").update(expected).digest();
79185
+ const b = createHash28("sha256").update(provided).digest();
78637
79186
  try {
78638
79187
  return timingSafeEqual(a, b);
78639
79188
  } catch {
@@ -78665,8 +79214,8 @@ function resolveFsDirectory(rawPath) {
78665
79214
  return { ok: false, error: `not a directory: ${trimmed}` };
78666
79215
  }
78667
79216
  const abs = resolve9(trimmed);
78668
- const slug = slugFromPath(abs);
78669
- return { ok: true, project: { id: slug, name: slug, path: abs } };
79217
+ const slug2 = slugFromPath(abs);
79218
+ return { ok: true, project: { id: slug2, name: slug2, path: abs } };
78670
79219
  }
78671
79220
  function mergeProjects(cfg, extraPaths) {
78672
79221
  const byId = /* @__PURE__ */ new Map();
@@ -78674,17 +79223,17 @@ function mergeProjects(cfg, extraPaths) {
78674
79223
  byId.set(p3.id, p3);
78675
79224
  }
78676
79225
  for (const raw of extraPaths) {
78677
- const path126 = raw.trim();
78678
- if (!path126) continue;
78679
- let id3 = slugFromPath(path126);
79226
+ const path128 = raw.trim();
79227
+ if (!path128) continue;
79228
+ let id3 = slugFromPath(path128);
78680
79229
  let n = 2;
78681
- while (byId.has(id3) && byId.get(id3).path !== path126) {
78682
- id3 = `${slugFromPath(path126)}-${n++}`;
79230
+ while (byId.has(id3) && byId.get(id3).path !== path128) {
79231
+ id3 = `${slugFromPath(path128)}-${n++}`;
78683
79232
  }
78684
79233
  byId.set(id3, {
78685
79234
  id: id3,
78686
- name: slugFromPath(path126),
78687
- path: path126
79235
+ name: slugFromPath(path128),
79236
+ path: path128
78688
79237
  });
78689
79238
  }
78690
79239
  return [...byId.values()];
@@ -78974,8 +79523,8 @@ var init_askUserBridge = __esm({
78974
79523
  });
78975
79524
 
78976
79525
  // src/cli/serve/spineLockSweep.ts
78977
- import { promises as fs50 } from "node:fs";
78978
- import path112 from "node:path";
79526
+ import { promises as fs51 } from "node:fs";
79527
+ import path114 from "node:path";
78979
79528
  async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
78980
79529
  const dir = sessionsDir2 ?? resolveSessionsDir();
78981
79530
  const onSwept = options.onSwept ?? ((sessionId2, reason) => {
@@ -78988,14 +79537,14 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
78988
79537
  const result = { swept: 0, kept: 0, errors: 0 };
78989
79538
  let entries;
78990
79539
  try {
78991
- entries = await fs50.readdir(dir);
79540
+ entries = await fs51.readdir(dir);
78992
79541
  } catch {
78993
79542
  return result;
78994
79543
  }
78995
79544
  for (const sessionId2 of entries) {
78996
- const lockPath2 = path112.join(dir, sessionId2, "writer.lock");
79545
+ const lockPath2 = path114.join(dir, sessionId2, "writer.lock");
78997
79546
  try {
78998
- const raw = await fs50.readFile(lockPath2, "utf-8");
79547
+ const raw = await fs51.readFile(lockPath2, "utf-8");
78999
79548
  let lockInfo = {};
79000
79549
  try {
79001
79550
  lockInfo = JSON.parse(raw);
@@ -79012,7 +79561,7 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
79012
79561
  result.kept += 1;
79013
79562
  continue;
79014
79563
  }
79015
- await fs50.rm(lockPath2, { force: true });
79564
+ await fs51.rm(lockPath2, { force: true });
79016
79565
  result.swept += 1;
79017
79566
  onSwept(sessionId2, verdict.reason);
79018
79567
  } catch (err) {
@@ -79110,7 +79659,7 @@ __export(harnessServer_exports, {
79110
79659
  startHarnessServer: () => startHarnessServer
79111
79660
  });
79112
79661
  import { createInterface as createInterface3 } from "node:readline";
79113
- import path113 from "node:path";
79662
+ import path115 from "node:path";
79114
79663
  import { randomUUID as randomUUID12 } from "node:crypto";
79115
79664
  function createCliWorkspaceServices(workspaceRoot) {
79116
79665
  const mode = activePolicyLoadMode();
@@ -79145,7 +79694,7 @@ function resolveSessionCreateRoot(params, cwd = process.cwd()) {
79145
79694
  };
79146
79695
  }
79147
79696
  const root = raw.trim();
79148
- if (!path113.isAbsolute(root)) {
79697
+ if (!path115.isAbsolute(root)) {
79149
79698
  return {
79150
79699
  ok: false,
79151
79700
  message: `session.create workspaceRoot must be an absolute path (got '${root}') \u2014 a relative root would resolve against the sidecar cwd (${cwd}) and mix conversations (ADR-0016)`
@@ -79560,7 +80109,7 @@ import { spawn as spawn19 } from "node:child_process";
79560
80109
  import { createInterface as createInterface4 } from "node:readline";
79561
80110
  import { randomUUID as randomUUID13 } from "node:crypto";
79562
80111
  import { writeFileSync as writeFileSync29, unlinkSync as unlinkSync3 } from "node:fs";
79563
- import { join as join49 } from "node:path";
80112
+ import { join as join50 } from "node:path";
79564
80113
  import { tmpdir as tmpdir4 } from "node:os";
79565
80114
  function harnessServerMode() {
79566
80115
  return process.env[HARNESS_SERVER_ENV] === "1";
@@ -79767,7 +80316,7 @@ var init_runManager = __esm({
79767
80316
  }
79768
80317
  let historyFile;
79769
80318
  if (args.history && Array.isArray(args.history) && args.history.length > 0) {
79770
- historyFile = join49(tmpdir4(), `zelari-companion-hist-${run.id}.json`);
80319
+ historyFile = join50(tmpdir4(), `zelari-companion-hist-${run.id}.json`);
79771
80320
  try {
79772
80321
  writeFileSync29(historyFile, JSON.stringify(args.history), "utf8");
79773
80322
  argv.push("--history-file", historyFile);
@@ -80154,8 +80703,8 @@ __export(serve_exports, {
80154
80703
  runCompanionServe: () => runCompanionServe
80155
80704
  });
80156
80705
  import { createServer as createServer3 } from "node:http";
80157
- import { existsSync as existsSync70, readdirSync as readdirSync15 } from "node:fs";
80158
- import { join as join50, resolve as resolve10 } from "node:path";
80706
+ import { existsSync as existsSync71, readdirSync as readdirSync15 } from "node:fs";
80707
+ import { join as join51, resolve as resolve10 } from "node:path";
80159
80708
  function readBody(req, max = 2e6) {
80160
80709
  return new Promise((resolveBody, reject) => {
80161
80710
  const chunks = [];
@@ -80203,7 +80752,7 @@ async function runCompanionServe(opts = {}) {
80203
80752
  let projects = mergeProjects(fileCfg, opts.projects ?? []);
80204
80753
  projects = projects.filter((p3) => {
80205
80754
  const abs = resolve10(p3.path);
80206
- if (!existsSync70(abs)) {
80755
+ if (!existsSync71(abs)) {
80207
80756
  process.stderr.write(
80208
80757
  `[zelari-code serve] skip missing project path: ${p3.path}
80209
80758
  `
@@ -80255,9 +80804,9 @@ async function runCompanionServe(opts = {}) {
80255
80804
  return;
80256
80805
  }
80257
80806
  const url2 = parseUrl(req);
80258
- const path126 = url2.pathname.replace(/\/+$/, "") || "/";
80807
+ const path128 = url2.pathname.replace(/\/+$/, "") || "/";
80259
80808
  try {
80260
- if (req.method === "GET" && (path126 === "/health" || path126 === "/v1/health")) {
80809
+ if (req.method === "GET" && (path128 === "/health" || path128 === "/v1/health")) {
80261
80810
  sendJson2(res, 200, {
80262
80811
  ok: true,
80263
80812
  service: "zelari-companion",
@@ -80269,25 +80818,25 @@ async function runCompanionServe(opts = {}) {
80269
80818
  });
80270
80819
  return;
80271
80820
  }
80272
- if (path126.startsWith("/v1")) {
80821
+ if (path128.startsWith("/v1")) {
80273
80822
  if (!tokenMatches(token, getBearer(req))) {
80274
80823
  sendJson2(res, 401, { ok: false, error: "unauthorized" });
80275
80824
  return;
80276
80825
  }
80277
80826
  }
80278
- if (req.method === "GET" && path126 === "/v1/config") {
80827
+ if (req.method === "GET" && path128 === "/v1/config") {
80279
80828
  const snap = buildDesktopConfigSnapshot();
80280
80829
  sendJson2(res, 200, { ok: true, ...snap });
80281
80830
  return;
80282
80831
  }
80283
- if (req.method === "GET" && path126 === "/v1/fs") {
80832
+ if (req.method === "GET" && path128 === "/v1/fs") {
80284
80833
  const listFsRootsInline = () => {
80285
80834
  if (process.platform === "win32") {
80286
80835
  const roots = [];
80287
80836
  for (let code = 65; code <= 90; code++) {
80288
80837
  const letter = String.fromCharCode(code);
80289
80838
  const drive = `${letter}:\\`;
80290
- if (existsSync70(drive)) {
80839
+ if (existsSync71(drive)) {
80291
80840
  roots.push({
80292
80841
  id: `fs-${letter.toLowerCase()}`,
80293
80842
  name: drive,
@@ -80315,7 +80864,7 @@ async function runCompanionServe(opts = {}) {
80315
80864
  sendJson2(res, 403, { ok: false, error: "path outside allowed roots" });
80316
80865
  return;
80317
80866
  }
80318
- if (!existsSync70(rawParam)) {
80867
+ if (!existsSync71(rawParam)) {
80319
80868
  sendJson2(res, 404, { ok: false, error: "path not found" });
80320
80869
  return;
80321
80870
  }
@@ -80333,13 +80882,13 @@ async function runCompanionServe(opts = {}) {
80333
80882
  parent,
80334
80883
  entries: dirs.map((d) => ({
80335
80884
  name: d.name,
80336
- path: join50(rawParam, d.name),
80885
+ path: join51(rawParam, d.name),
80337
80886
  dir: true
80338
80887
  }))
80339
80888
  });
80340
80889
  return;
80341
80890
  }
80342
- if (req.method === "GET" && path126 === "/v1/projects") {
80891
+ if (req.method === "GET" && path128 === "/v1/projects") {
80343
80892
  sendJson2(res, 200, {
80344
80893
  ok: true,
80345
80894
  projects: projects.map((p3) => ({
@@ -80350,7 +80899,7 @@ async function runCompanionServe(opts = {}) {
80350
80899
  });
80351
80900
  return;
80352
80901
  }
80353
- if (req.method === "GET" && path126 === "/v1/runs") {
80902
+ if (req.method === "GET" && path128 === "/v1/runs") {
80354
80903
  sendJson2(res, 200, {
80355
80904
  ok: true,
80356
80905
  active: runs.getActive(),
@@ -80368,7 +80917,7 @@ async function runCompanionServe(opts = {}) {
80368
80917
  });
80369
80918
  return;
80370
80919
  }
80371
- if (req.method === "POST" && path126 === "/v1/runs") {
80920
+ if (req.method === "POST" && path128 === "/v1/runs") {
80372
80921
  const raw = await readBody(req);
80373
80922
  let body = {};
80374
80923
  try {
@@ -80428,7 +80977,7 @@ async function runCompanionServe(opts = {}) {
80428
80977
  });
80429
80978
  return;
80430
80979
  }
80431
- if (req.method === "POST" && path126 === "/v1/trust") {
80980
+ if (req.method === "POST" && path128 === "/v1/trust") {
80432
80981
  const raw = await readBody(req);
80433
80982
  let body = {};
80434
80983
  try {
@@ -80469,11 +81018,11 @@ async function runCompanionServe(opts = {}) {
80469
81018
  sendJson2(res, 200, { ok: true, denied: runId });
80470
81019
  return;
80471
81020
  }
80472
- if (req.method === "GET" && path126 === "/v1/trust/pending") {
81021
+ if (req.method === "GET" && path128 === "/v1/trust/pending") {
80473
81022
  sendJson2(res, 200, { ok: true, pending: runs.pendingTrust() });
80474
81023
  return;
80475
81024
  }
80476
- const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path126);
81025
+ const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path128);
80477
81026
  if (req.method === "GET" && eventsMatch) {
80478
81027
  const runId = eventsMatch[1];
80479
81028
  const run = runs.getRun(runId);
@@ -80538,7 +81087,7 @@ async function runCompanionServe(opts = {}) {
80538
81087
  }, 500);
80539
81088
  return;
80540
81089
  }
80541
- const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path126);
81090
+ const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path128);
80542
81091
  if (req.method === "POST" && cancelMatch) {
80543
81092
  const runId = cancelMatch[1];
80544
81093
  const result = runs.cancel(runId);
@@ -80549,7 +81098,7 @@ async function runCompanionServe(opts = {}) {
80549
81098
  sendJson2(res, 200, { ok: true, cancelled: runId });
80550
81099
  return;
80551
81100
  }
80552
- const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path126);
81101
+ const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path128);
80553
81102
  if (req.method === "POST" && steerMatch) {
80554
81103
  const runId = steerMatch[1];
80555
81104
  const raw = await readBody(req);
@@ -80573,7 +81122,7 @@ async function runCompanionServe(opts = {}) {
80573
81122
  sendJson2(res, 200, { ok: true, steered: runId, result: result.result });
80574
81123
  return;
80575
81124
  }
80576
- const askMatch = /^\/v1\/runs\/([^/]+)\/(permission|ask)$/.exec(path126);
81125
+ const askMatch = /^\/v1\/runs\/([^/]+)\/(permission|ask)$/.exec(path128);
80577
81126
  if (req.method === "POST" && askMatch) {
80578
81127
  const runId = askMatch[1];
80579
81128
  const kind2 = askMatch[2];
@@ -80834,26 +81383,26 @@ __export(doctor_exports, {
80834
81383
  runDoctor: () => runDoctor
80835
81384
  });
80836
81385
  import { execSync as execSync3 } from "node:child_process";
80837
- import { existsSync as existsSync71, readFileSync as readFileSync56, readlinkSync, statSync as statSync14 } from "node:fs";
81386
+ import { existsSync as existsSync72, readFileSync as readFileSync57, readlinkSync, statSync as statSync14 } from "node:fs";
80838
81387
  import { createRequire as createRequire3 } from "node:module";
80839
81388
  import { fileURLToPath as fileURLToPath3 } from "node:url";
80840
- import path114 from "node:path";
81389
+ import path116 from "node:path";
80841
81390
  function findPackageRoot(start) {
80842
81391
  let dir = start;
80843
81392
  for (let i = 0; i < 6; i += 1) {
80844
- const candidate = path114.join(dir, "package.json");
80845
- if (existsSync71(candidate)) {
81393
+ const candidate = path116.join(dir, "package.json");
81394
+ if (existsSync72(candidate)) {
80846
81395
  try {
80847
- const pkg = JSON.parse(readFileSync56(candidate, "utf8"));
81396
+ const pkg = JSON.parse(readFileSync57(candidate, "utf8"));
80848
81397
  if (pkg.name === "zelari-code") return dir;
80849
81398
  } catch {
80850
81399
  }
80851
81400
  }
80852
- const parent = path114.dirname(dir);
81401
+ const parent = path116.dirname(dir);
80853
81402
  if (parent === dir) break;
80854
81403
  dir = parent;
80855
81404
  }
80856
- return path114.resolve(__dirname3, "..", "..", "..");
81405
+ return path116.resolve(__dirname3, "..", "..", "..");
80857
81406
  }
80858
81407
  function tryExec(cmd) {
80859
81408
  try {
@@ -80867,8 +81416,8 @@ function tryExec(cmd) {
80867
81416
  }
80868
81417
  function readPackageJson4() {
80869
81418
  try {
80870
- const pkgPath = path114.join(packageRoot, "package.json");
80871
- return JSON.parse(readFileSync56(pkgPath, "utf8"));
81419
+ const pkgPath = path116.join(packageRoot, "package.json");
81420
+ return JSON.parse(readFileSync57(pkgPath, "utf8"));
80872
81421
  } catch {
80873
81422
  return null;
80874
81423
  }
@@ -80879,7 +81428,7 @@ function getGlobalPrefix2() {
80879
81428
  return (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || "").trim();
80880
81429
  }
80881
81430
  function isSourceCheckout() {
80882
- return existsSync71(path114.join(packageRoot, "src", "cli", "main.ts")) && existsSync71(path114.join(packageRoot, "apps", "desktop", "package.json"));
81431
+ return existsSync72(path116.join(packageRoot, "src", "cli", "main.ts")) && existsSync72(path116.join(packageRoot, "apps", "desktop", "package.json"));
80883
81432
  }
80884
81433
  function checkShim(pkgName) {
80885
81434
  const prefix = getGlobalPrefix2();
@@ -80888,10 +81437,10 @@ function checkShim(pkgName) {
80888
81437
  }
80889
81438
  const isWin = process.platform === "win32";
80890
81439
  const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
80891
- const shimPath = path114.join(prefix, shimName);
80892
- if (!existsSync71(shimPath)) {
80893
- const localBin = path114.join(packageRoot, "bin", "zelari-code.js");
80894
- if (isSourceCheckout() && existsSync71(localBin)) {
81440
+ const shimPath = path116.join(prefix, shimName);
81441
+ if (!existsSync72(shimPath)) {
81442
+ const localBin = path116.join(packageRoot, "bin", "zelari-code.js");
81443
+ if (isSourceCheckout() && existsSync72(localBin)) {
80895
81444
  return WARN(
80896
81445
  `global shim not found at ${shimPath}
80897
81446
  source checkout \u2014 using ${localBin}
@@ -80914,7 +81463,7 @@ function checkShim(pkgName) {
80914
81463
  try {
80915
81464
  const st = statSync14(shimPath);
80916
81465
  if (isWin) {
80917
- const content = readFileSync56(shimPath, "utf8");
81466
+ const content = readFileSync57(shimPath, "utf8");
80918
81467
  if (content.includes(`${pkgName}\\bin\\`) || content.includes(`${pkgName}/bin/`)) {
80919
81468
  return OK(`shim OK at ${shimPath} (${st.size} bytes)`);
80920
81469
  }
@@ -80932,8 +81481,8 @@ function checkShim(pkgName) {
80932
81481
  fix: npm install -g ${pkgName}@latest --force`
80933
81482
  );
80934
81483
  }
80935
- const resolved = path114.resolve(path114.dirname(shimPath), target);
80936
- const expected = path114.join(
81484
+ const resolved = path116.resolve(path116.dirname(shimPath), target);
81485
+ const expected = path116.join(
80937
81486
  prefix,
80938
81487
  "node_modules",
80939
81488
  pkgName,
@@ -80975,8 +81524,8 @@ function checkNode(pkg) {
80975
81524
  return OK(`node ${raw} (engines.node ${enginesNode ?? ">= 20.0.0"})`);
80976
81525
  }
80977
81526
  function checkBundle() {
80978
- const bundle = path114.join(packageRoot, "dist", "cli", "main.bundled.js");
80979
- if (!existsSync71(bundle)) {
81527
+ const bundle = path116.join(packageRoot, "dist", "cli", "main.bundled.js");
81528
+ if (!existsSync72(bundle)) {
80980
81529
  return FAIL(
80981
81530
  `dist/cli/main.bundled.js missing at ${bundle}
80982
81531
  fix: npm run build:cli (then reinstall or run via tsx)`
@@ -80996,7 +81545,7 @@ function checkRuntimeDeps() {
80996
81545
  const missing = [];
80997
81546
  for (const dep of required2) {
80998
81547
  try {
80999
- const localReq = createRequire3(path114.join(packageRoot, "package.json"));
81548
+ const localReq = createRequire3(path116.join(packageRoot, "package.json"));
81000
81549
  localReq.resolve(dep);
81001
81550
  } catch {
81002
81551
  missing.push(dep);
@@ -81297,7 +81846,7 @@ var init_doctor = __esm({
81297
81846
  init_cacheHitReport();
81298
81847
  init_updater();
81299
81848
  require3 = createRequire3(import.meta.url);
81300
- __dirname3 = path114.dirname(fileURLToPath3(import.meta.url));
81849
+ __dirname3 = path116.dirname(fileURLToPath3(import.meta.url));
81301
81850
  packageRoot = findPackageRoot(__dirname3);
81302
81851
  OK = (message) => ({
81303
81852
  ok: true,
@@ -81480,8 +82029,8 @@ __export(inspectSession_exports, {
81480
82029
  renderInspectReport: () => renderInspectReport,
81481
82030
  runInspectSession: () => runInspectSession
81482
82031
  });
81483
- import path115 from "node:path";
81484
- import { existsSync as existsSync72 } from "node:fs";
82032
+ import path117 from "node:path";
82033
+ import { existsSync as existsSync73 } from "node:fs";
81485
82034
  function formatLimit(limit) {
81486
82035
  return `${Math.round(limit / 1e3)}k`;
81487
82036
  }
@@ -81514,13 +82063,13 @@ function renderInspectReport(state3) {
81514
82063
  }
81515
82064
  async function runInspectSession(opts) {
81516
82065
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.cwd ?? process.cwd() });
81517
- const sessionDir = path115.join(sessionsDir2, opts.sessionId);
81518
- const eventsPath = path115.join(sessionDir, "events.jsonl");
81519
- if (!existsSync72(sessionDir)) {
82066
+ const sessionDir = path117.join(sessionsDir2, opts.sessionId);
82067
+ const eventsPath = path117.join(sessionDir, "events.jsonl");
82068
+ if (!existsSync73(sessionDir)) {
81520
82069
  console.error(`zelari-code inspect: no session directory at ${sessionDir}`);
81521
82070
  return 1;
81522
82071
  }
81523
- if (!existsSync72(eventsPath)) {
82072
+ if (!existsSync73(eventsPath)) {
81524
82073
  console.error(`zelari-code inspect: session directory has no events.jsonl at ${eventsPath}`);
81525
82074
  return 1;
81526
82075
  }
@@ -81549,14 +82098,14 @@ __export(inspect_exports, {
81549
82098
  collectInspectReport: () => collectInspectReport,
81550
82099
  runInspect: () => runInspect
81551
82100
  });
81552
- import path116 from "node:path";
81553
- import { existsSync as existsSync73, readFileSync as readFileSync57, readdirSync as readdirSync16 } from "node:fs";
82101
+ import path118 from "node:path";
82102
+ import { existsSync as existsSync74, readFileSync as readFileSync58, readdirSync as readdirSync16 } from "node:fs";
81554
82103
  async function collectInspectReport(cwd = process.cwd()) {
81555
82104
  ensureBuiltinSkillsLoadedSync();
81556
82105
  const snap = listSkillsSnapshot(cwd);
81557
82106
  const mcp = listMcpServers(cwd);
81558
- const userMcpPath = path116.join(zelariHome(), "mcp.json");
81559
- const projectMcpPath = path116.join(cwd, ".zelari", "mcp.json");
82107
+ const userMcpPath = path118.join(zelariHome(), "mcp.json");
82108
+ const projectMcpPath = path118.join(cwd, ".zelari", "mcp.json");
81560
82109
  const globalHooks = globalHooksDir();
81561
82110
  const projectHooks = projectHooksDir(cwd);
81562
82111
  const projectTrusted = isFolderTrusted(cwd);
@@ -81582,11 +82131,11 @@ async function collectInspectReport(cwd = process.cwd()) {
81582
82131
  folders: listTrustedFolders()
81583
82132
  },
81584
82133
  configSources: [
81585
- { path: userMcpPath, exists: existsSync73(userMcpPath) },
81586
- { path: projectMcpPath, exists: existsSync73(projectMcpPath) },
81587
- { path: path116.join(zelariHome(), "provider.json"), exists: existsSync73(path116.join(zelariHome(), "provider.json")) },
81588
- { path: path116.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync73(path116.join(cwd, ".zelari", "AGENTS.md")) },
81589
- { path: path116.join(cwd, "AGENTS.md"), exists: existsSync73(path116.join(cwd, "AGENTS.md")) }
82134
+ { path: userMcpPath, exists: existsSync74(userMcpPath) },
82135
+ { path: projectMcpPath, exists: existsSync74(projectMcpPath) },
82136
+ { path: path118.join(zelariHome(), "provider.json"), exists: existsSync74(path118.join(zelariHome(), "provider.json")) },
82137
+ { path: path118.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync74(path118.join(cwd, ".zelari", "AGENTS.md")) },
82138
+ { path: path118.join(cwd, "AGENTS.md"), exists: existsSync74(path118.join(cwd, "AGENTS.md")) }
81590
82139
  ],
81591
82140
  skills: {
81592
82141
  total: snap.skills.length,
@@ -81599,7 +82148,7 @@ async function collectInspectReport(cwd = process.cwd()) {
81599
82148
  user: mcp.servers.filter((s) => s.scope === "user").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
81600
82149
  project: mcp.servers.filter((s) => s.scope === "project").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
81601
82150
  projectTrusted,
81602
- projectConfigExists: existsSync73(projectMcpPath)
82151
+ projectConfigExists: existsSync74(projectMcpPath)
81603
82152
  },
81604
82153
  hooks: {
81605
82154
  global: {
@@ -81626,14 +82175,14 @@ function listJsonFiles(dir) {
81626
82175
  }
81627
82176
  function findAgentsMd(cwd) {
81628
82177
  const candidates = [
81629
- path116.join(cwd, "AGENTS.md"),
81630
- path116.join(cwd, ".zelari", "AGENTS.md")
82178
+ path118.join(cwd, "AGENTS.md"),
82179
+ path118.join(cwd, ".zelari", "AGENTS.md")
81631
82180
  ];
81632
82181
  const found = [];
81633
82182
  for (const c of candidates) {
81634
- if (existsSync73(c)) {
82183
+ if (existsSync74(c)) {
81635
82184
  try {
81636
- const text = readFileSync57(c, "utf8");
82185
+ const text = readFileSync58(c, "utf8");
81637
82186
  found.push(`${c} (${text.length} bytes)`);
81638
82187
  } catch {
81639
82188
  found.push(`${c} (unreadable)`);
@@ -81701,8 +82250,8 @@ __export(skillsCheck_exports, {
81701
82250
  formatSkillsCheckReport: () => formatSkillsCheckReport,
81702
82251
  parseFrontmatter: () => parseFrontmatter2
81703
82252
  });
81704
- import { existsSync as existsSync74, readdirSync as readdirSync17, readFileSync as readFileSync58 } from "node:fs";
81705
- import { join as join51 } from "node:path";
82253
+ import { existsSync as existsSync75, readdirSync as readdirSync17, readFileSync as readFileSync59 } from "node:fs";
82254
+ import { join as join52 } from "node:path";
81706
82255
  function parseFrontmatter2(content) {
81707
82256
  const fm = FRONTMATTER_RE2.exec(content);
81708
82257
  if (!fm) return null;
@@ -81723,10 +82272,10 @@ function parseFrontmatter2(content) {
81723
82272
  function messageOf(err) {
81724
82273
  return err instanceof Error ? err.message : String(err);
81725
82274
  }
81726
- function checkSkillMd(path126, content) {
82275
+ function checkSkillMd(path128, content) {
81727
82276
  const lines = [];
81728
82277
  const push = (level, detail) => {
81729
- lines.push({ level, what: `${path126}: ${detail}` });
82278
+ lines.push({ level, what: `${path128}: ${detail}` });
81730
82279
  };
81731
82280
  if (content.length === 0) {
81732
82281
  push("error", "file is empty (the loader requires frontmatter AND a body)");
@@ -81784,7 +82333,7 @@ function checkSkillFiles(options = {}) {
81784
82333
  let existingRoots = 0;
81785
82334
  let skillsChecked = 0;
81786
82335
  for (const root of roots) {
81787
- if (!existsSync74(root)) continue;
82336
+ if (!existsSync75(root)) continue;
81788
82337
  existingRoots += 1;
81789
82338
  let entries;
81790
82339
  try {
@@ -81794,31 +82343,31 @@ function checkSkillFiles(options = {}) {
81794
82343
  continue;
81795
82344
  }
81796
82345
  for (const entry of entries) {
81797
- const dir = join51(root, entry);
81798
- const path126 = join51(dir, "SKILL.md");
81799
- if (!existsSync74(path126)) {
82346
+ const dir = join52(root, entry);
82347
+ const path128 = join52(dir, "SKILL.md");
82348
+ if (!existsSync75(path128)) {
81800
82349
  lines.push({ level: "warn", what: `${dir}: no SKILL.md inside this skills directory (ignored by the loader)` });
81801
82350
  continue;
81802
82351
  }
81803
82352
  let content;
81804
82353
  try {
81805
- content = readFileSync58(path126, "utf8");
82354
+ content = readFileSync59(path128, "utf8");
81806
82355
  } catch (err) {
81807
- lines.push({ level: "error", what: `${path126}: unreadable \u2014 ${messageOf(err)}` });
82356
+ lines.push({ level: "error", what: `${path128}: unreadable \u2014 ${messageOf(err)}` });
81808
82357
  continue;
81809
82358
  }
81810
82359
  skillsChecked += 1;
81811
- lines.push(...checkSkillMd(path126, content));
82360
+ lines.push(...checkSkillMd(path128, content));
81812
82361
  const name = (parseFrontmatter2(content)?.fields["name"] ?? "").trim().toLowerCase();
81813
82362
  if (!name) continue;
81814
82363
  const owner = ownerByName.get(name);
81815
82364
  if (owner) {
81816
82365
  lines.push({
81817
82366
  level: "warn",
81818
- what: `${path126}: name "${name}" is already provided by ${owner} (earlier directory wins; this file is skipped)`
82367
+ what: `${path128}: name "${name}" is already provided by ${owner} (earlier directory wins; this file is skipped)`
81819
82368
  });
81820
82369
  } else {
81821
- ownerByName.set(name, path126);
82370
+ ownerByName.set(name, path128);
81822
82371
  }
81823
82372
  }
81824
82373
  }
@@ -82868,13 +83417,13 @@ var init_command = __esm({
82868
83417
  });
82869
83418
 
82870
83419
  // src/cli/plugins/bundleManifest.ts
82871
- import path117 from "node:path";
83420
+ import path119 from "node:path";
82872
83421
  function stripComment2(value) {
82873
83422
  const { $comment: _comment, ...rest } = value;
82874
83423
  return rest;
82875
83424
  }
82876
83425
  function escapesBundleRoot(p3) {
82877
- if (path117.isAbsolute(p3) || path117.win32.isAbsolute(p3)) return true;
83426
+ if (path119.isAbsolute(p3) || path119.win32.isAbsolute(p3)) return true;
82878
83427
  return p3.split(/[\\/]+/).includes("..");
82879
83428
  }
82880
83429
  function formatIssues(error51, filePath) {
@@ -82987,7 +83536,7 @@ var init_bundleManifest = __esm({
82987
83536
 
82988
83537
  // src/cli/plugins/bundleFs.ts
82989
83538
  import { stat as stat8 } from "node:fs/promises";
82990
- import path118 from "node:path";
83539
+ import path120 from "node:path";
82991
83540
  async function isFile(p3) {
82992
83541
  try {
82993
83542
  return (await stat8(p3)).isFile();
@@ -83006,9 +83555,9 @@ function isRecord(value) {
83006
83555
  return typeof value === "object" && value !== null && !Array.isArray(value);
83007
83556
  }
83008
83557
  async function resolveInsideBundle(root, relPath, at, manifestPath, errors) {
83009
- const abs = path118.resolve(root, relPath);
83010
- const rel2 = path118.relative(root, abs);
83011
- if (rel2 === "" || rel2.startsWith("..") || path118.isAbsolute(rel2)) {
83558
+ const abs = path120.resolve(root, relPath);
83559
+ const rel2 = path120.relative(root, abs);
83560
+ if (rel2 === "" || rel2.startsWith("..") || path120.isAbsolute(rel2)) {
83012
83561
  errors.push(
83013
83562
  `${manifestPath}: invalid bundle manifest at '${at}': path escapes the bundle directory ('${relPath}')`
83014
83563
  );
@@ -83137,7 +83686,7 @@ var init_bundleMcp = __esm({
83137
83686
 
83138
83687
  // src/cli/plugins/bundleLoad.ts
83139
83688
  import { readFile as readFile12 } from "node:fs/promises";
83140
- import path119 from "node:path";
83689
+ import path121 from "node:path";
83141
83690
  async function readSkills(manifestSkills, root, manifestPath, errors) {
83142
83691
  const skills = [];
83143
83692
  for (let i = 0; i < manifestSkills.length; i += 1) {
@@ -83186,8 +83735,8 @@ async function readHooks(manifestHooks, root, manifestPath, errors, warnings) {
83186
83735
  async function readBundle(dir, manifestFileName = BUNDLE_MANIFEST_FILE) {
83187
83736
  const errors = [];
83188
83737
  const warnings = [];
83189
- const root = path119.resolve(dir);
83190
- const manifestPath = path119.join(root, manifestFileName);
83738
+ const root = path121.resolve(dir);
83739
+ const manifestPath = path121.join(root, manifestFileName);
83191
83740
  if (!await isDir(root)) {
83192
83741
  return { errors: [`${root}: not a bundle directory`], warnings };
83193
83742
  }
@@ -83250,12 +83799,12 @@ var init_bundleLoad = __esm({
83250
83799
 
83251
83800
  // src/cli/plugins/bundleDiscover.ts
83252
83801
  import { readdir as readdir4 } from "node:fs/promises";
83253
- import path120 from "node:path";
83802
+ import path122 from "node:path";
83254
83803
  function defaultBundleRoots(projectRoot, state3) {
83255
- const roots = [path120.join(projectRoot, "examples", "extensions")];
83256
- for (const p3 of state3.paths) roots.push(path120.resolve(projectRoot, p3));
83804
+ const roots = [path122.join(projectRoot, "examples", "extensions")];
83805
+ for (const p3 of state3.paths) roots.push(path122.resolve(projectRoot, p3));
83257
83806
  const unique = /* @__PURE__ */ new Map();
83258
- for (const root of roots) unique.set(path120.resolve(root).toLowerCase(), root);
83807
+ for (const root of roots) unique.set(path122.resolve(root).toLowerCase(), root);
83259
83808
  return [...unique.values()];
83260
83809
  }
83261
83810
  async function discoverBundles(roots) {
@@ -83270,9 +83819,9 @@ async function discoverBundles(roots) {
83270
83819
  continue;
83271
83820
  }
83272
83821
  for (const entry of entries) {
83273
- const dir = path120.join(root, entry);
83274
- if (!await isFile(path120.join(dir, BUNDLE_MANIFEST_FILE))) continue;
83275
- const key = path120.resolve(dir);
83822
+ const dir = path122.join(root, entry);
83823
+ if (!await isFile(path122.join(dir, BUNDLE_MANIFEST_FILE))) continue;
83824
+ const key = path122.resolve(dir);
83276
83825
  if (seen.has(key)) continue;
83277
83826
  seen.add(key);
83278
83827
  const result = await readBundle(dir);
@@ -83299,12 +83848,12 @@ var init_bundleDiscover = __esm({
83299
83848
 
83300
83849
  // src/cli/plugins/bundleState.ts
83301
83850
  import { mkdir as mkdir6, readFile as readFile13, writeFile as writeFile5 } from "node:fs/promises";
83302
- import path121 from "node:path";
83851
+ import path123 from "node:path";
83303
83852
  function emptyBundleState() {
83304
83853
  return { enabled: {}, paths: [] };
83305
83854
  }
83306
83855
  function bundleStatePath(projectRoot) {
83307
- return path121.join(projectRoot, BUNDLE_STATE_FILE);
83856
+ return path123.join(projectRoot, BUNDLE_STATE_FILE);
83308
83857
  }
83309
83858
  function isBundleEnabled(state3, name) {
83310
83859
  return state3.enabled[name] === true;
@@ -83344,11 +83893,11 @@ async function readBundleState(projectRoot) {
83344
83893
  return { state: state3, path: file2, errors: [] };
83345
83894
  }
83346
83895
  function withRegisteredScanRoot(state3, projectRoot, bundleDir) {
83347
- const abs = path121.dirname(path121.resolve(bundleDir));
83348
- const rel2 = path121.relative(path121.resolve(projectRoot), abs);
83349
- const value = rel2 === "" || rel2.startsWith("..") || path121.isAbsolute(rel2) ? abs : rel2;
83350
- const paths = state3.paths.map((p3) => path121.normalize(p3));
83351
- if (paths.includes(path121.normalize(value))) return state3;
83896
+ const abs = path123.dirname(path123.resolve(bundleDir));
83897
+ const rel2 = path123.relative(path123.resolve(projectRoot), abs);
83898
+ const value = rel2 === "" || rel2.startsWith("..") || path123.isAbsolute(rel2) ? abs : rel2;
83899
+ const paths = state3.paths.map((p3) => path123.normalize(p3));
83900
+ if (paths.includes(path123.normalize(value))) return state3;
83352
83901
  return { ...state3, paths: [...state3.paths, value] };
83353
83902
  }
83354
83903
  async function setBundleEnabled(opts) {
@@ -83365,7 +83914,7 @@ async function setBundleEnabled(opts) {
83365
83914
  };
83366
83915
  const next = opts.dir ? withRegisteredScanRoot(named, opts.projectRoot, opts.dir) : named;
83367
83916
  try {
83368
- await mkdir6(path121.dirname(read.path), { recursive: true });
83917
+ await mkdir6(path123.dirname(read.path), { recursive: true });
83369
83918
  await writeFile5(read.path, `${JSON.stringify(next, null, 2)}
83370
83919
  `, "utf8");
83371
83920
  } catch (err) {
@@ -83400,7 +83949,7 @@ __export(bundleCommand_exports, {
83400
83949
  runPluginValidate: () => runPluginValidate
83401
83950
  });
83402
83951
  import { readFile as readFile14 } from "node:fs/promises";
83403
- import path122 from "node:path";
83952
+ import path124 from "node:path";
83404
83953
  function parsePluginFlags(argv) {
83405
83954
  const out = {};
83406
83955
  if (argv.includes("--help") || argv.includes("-h")) out.help = true;
@@ -83413,9 +83962,9 @@ function pluginHelpText() {
83413
83962
  return 'zelari-code plugin \u2014 plugin bundles (format v1)\n\nA bundle is a directory with a zelari-plugin.json manifest declaring\nskills, hooks, MCP servers and agents. Validation is static: nothing is\ninstalled, executed or fetched. Bundles are DISABLED until enabled, and\nenablement lives in the project file .zelari/plugins.json.\n\nUsage:\n zelari-code plugin validate <dir> Validate one bundle (exit 0/1)\n zelari-code plugin list [dir...] List discovered bundles + state\n zelari-code plugin enable <dir|name> Enable a bundle (validates first)\n zelari-code plugin disable <dir|name> Disable a bundle (always allowed)\n\nOptions:\n --cwd <path> Project root holding .zelari/plugins.json\n (default: current directory)\n --help, -h This text\n\n`list` scans <projectRoot>/examples/extensions plus every directory\nrecorded in "paths" of .zelari/plugins.json, then any extra dirs given.\n';
83414
83963
  }
83415
83964
  async function resolveBundleName(target, projectRoot, roots) {
83416
- const asDir = path122.resolve(projectRoot, target);
83965
+ const asDir = path124.resolve(projectRoot, target);
83417
83966
  if (await isDir(asDir)) {
83418
- const manifestPath = path122.join(asDir, BUNDLE_MANIFEST_FILE);
83967
+ const manifestPath = path124.join(asDir, BUNDLE_MANIFEST_FILE);
83419
83968
  let raw;
83420
83969
  try {
83421
83970
  raw = await readFile14(manifestPath, "utf8");
@@ -83473,7 +84022,7 @@ async function runPluginList(extraDirs, projectRoot) {
83473
84022
  `);
83474
84023
  const roots = [
83475
84024
  ...defaultBundleRoots(projectRoot, read.state),
83476
- ...extraDirs.map((d) => path122.resolve(projectRoot, d))
84025
+ ...extraDirs.map((d) => path124.resolve(projectRoot, d))
83477
84026
  ];
83478
84027
  const found = await discoverBundles(roots);
83479
84028
  process.stdout.write(`zelari-code plugin list \u2014 project ${projectRoot}
@@ -83538,7 +84087,7 @@ async function runPluginCommand(argv) {
83538
84087
  try {
83539
84088
  const args = argv[0] === "plugin" ? argv.slice(1) : [...argv];
83540
84089
  const opts = parsePluginFlags(args);
83541
- const projectRoot = path122.resolve(opts.cwd ?? process.cwd());
84090
+ const projectRoot = path124.resolve(opts.cwd ?? process.cwd());
83542
84091
  const positional = args.filter((a, i) => !a.startsWith("-") && args[i - 1] !== "--cwd");
83543
84092
  const [subcommand, ...rest] = positional;
83544
84093
  if (opts.help === true || subcommand === void 0) {
@@ -83591,19 +84140,19 @@ var init_bundleCommand = __esm({
83591
84140
  });
83592
84141
 
83593
84142
  // src/cli/commands/spineSession.ts
83594
- import { existsSync as existsSync75, readFileSync as readFileSync59, readdirSync as readdirSync18 } from "node:fs";
83595
- import path123 from "node:path";
84143
+ import { existsSync as existsSync76, readFileSync as readFileSync60, readdirSync as readdirSync18 } from "node:fs";
84144
+ import path125 from "node:path";
83596
84145
  function newestSpineSessionId(sessionsDir2) {
83597
84146
  let names;
83598
84147
  try {
83599
- names = readdirSync18(sessionsDir2).filter((n) => existsSync75(path123.join(sessionsDir2, n, "events.jsonl")));
84148
+ names = readdirSync18(sessionsDir2).filter((n) => existsSync76(path125.join(sessionsDir2, n, "events.jsonl")));
83600
84149
  } catch {
83601
84150
  return null;
83602
84151
  }
83603
84152
  if (names.length === 0) return null;
83604
84153
  const scored = names.map((n) => {
83605
84154
  try {
83606
- const text = readFileSync59(path123.join(sessionsDir2, n, "events.jsonl"), "utf-8");
84155
+ const text = readFileSync60(path125.join(sessionsDir2, n, "events.jsonl"), "utf-8");
83607
84156
  const events = parseSessionLogText("events.jsonl", text).events;
83608
84157
  return { n, ts: events[events.length - 1]?.ts ?? 0 };
83609
84158
  } catch {
@@ -83619,16 +84168,16 @@ function resolveSpineSession(query = {}) {
83619
84168
  const at = (sessionId2) => ({
83620
84169
  sessionId: sessionId2,
83621
84170
  sessionsDir: sessionsDir2,
83622
- eventsPath: path123.join(sessionsDir2, sessionId2, "events.jsonl")
84171
+ eventsPath: path125.join(sessionsDir2, sessionId2, "events.jsonl")
83623
84172
  });
83624
84173
  if (query.sessionId !== void 0 && query.sessionId !== "") {
83625
84174
  const candidate = at(query.sessionId);
83626
- return existsSync75(candidate.eventsPath) ? candidate : { error: `no session spine at ${candidate.eventsPath}` };
84175
+ return existsSync76(candidate.eventsPath) ? candidate : { error: `no session spine at ${candidate.eventsPath}` };
83627
84176
  }
83628
84177
  const marker = getCurrentSessionId();
83629
84178
  if (marker !== null) {
83630
84179
  const candidate = at(marker);
83631
- if (existsSync75(candidate.eventsPath)) return candidate;
84180
+ if (existsSync76(candidate.eventsPath)) return candidate;
83632
84181
  }
83633
84182
  const newest = newestSpineSessionId(sessionsDir2);
83634
84183
  if (newest === null) {
@@ -83652,8 +84201,8 @@ __export(replay_exports, {
83652
84201
  replayHelpText: () => replayHelpText,
83653
84202
  runReplayCommand: () => runReplayCommand
83654
84203
  });
83655
- import { readFileSync as readFileSync60 } from "node:fs";
83656
- import path124 from "node:path";
84204
+ import { readFileSync as readFileSync61 } from "node:fs";
84205
+ import path126 from "node:path";
83657
84206
  function parseReplayFlags(argv) {
83658
84207
  const args = argv[0] === "replay" ? argv.slice(1) : [...argv];
83659
84208
  const out = {};
@@ -83670,7 +84219,7 @@ function replayHelpText() {
83670
84219
  return "zelari-code replay \u2014 replay a session spine (read-only, no LLM, no network)\n\nRe-reads one session log with the core tolerant reader and prints what it\ncontains: tool calls, verify debt, verify runs and decision events\n(permission asks/denials, auto-approvals, jail blocks, ask_user, verify\nrequests). Nothing is written: the log it reads is never modified.\n\nUsage:\n zelari-code replay [<sessionId>] [--json]\n\nWith no <sessionId>: the current-session marker, else the newest spine.\n\nOptions:\n --json Print the full projection as JSON\n --cwd <path> Workspace root for the sessions dir\n (default: current directory;\n ZELARI_SESSIONS_DIR overrides both)\n --help, -h This text\n\nExit code: 0 on a successful replay (spine issues are reported, not\nfatal \u2014 see `zelari-code session validate` to fail on them), 1 when there\nwas nothing to replay.\n";
83671
84220
  }
83672
84221
  function shortPath2(p3, cwd) {
83673
- const rel2 = path124.relative(cwd, p3);
84222
+ const rel2 = path126.relative(cwd, p3);
83674
84223
  return rel2 && !rel2.startsWith("..") ? rel2 : p3;
83675
84224
  }
83676
84225
  function renderReplayReport(input) {
@@ -83745,7 +84294,7 @@ async function runReplayCommand(argv) {
83745
84294
  process.stdout.write(replayHelpText());
83746
84295
  return 0;
83747
84296
  }
83748
- const cwd = path124.resolve(opts.cwd ?? process.cwd());
84297
+ const cwd = path126.resolve(opts.cwd ?? process.cwd());
83749
84298
  const resolved = resolveSpineSession({
83750
84299
  ...opts.sessionId !== void 0 ? { sessionId: opts.sessionId } : {},
83751
84300
  cwd
@@ -83755,7 +84304,7 @@ async function runReplayCommand(argv) {
83755
84304
  `);
83756
84305
  return 1;
83757
84306
  }
83758
- const text = readFileSync60(resolved.eventsPath, "utf-8");
84307
+ const text = readFileSync61(resolved.eventsPath, "utf-8");
83759
84308
  const report = parseSessionLogText(resolved.eventsPath, text);
83760
84309
  const projection = buildProjection(report.events, report.issues);
83761
84310
  if (opts.json === true) {
@@ -83808,8 +84357,8 @@ __export(session_exports, {
83808
84357
  runSessionCommand: () => runSessionCommand,
83809
84358
  sessionHelpText: () => sessionHelpText
83810
84359
  });
83811
- import { readFileSync as readFileSync61 } from "node:fs";
83812
- import path125 from "node:path";
84360
+ import { readFileSync as readFileSync62 } from "node:fs";
84361
+ import path127 from "node:path";
83813
84362
  function parseSessionFlags(argv) {
83814
84363
  const args = argv[0] === "session" ? argv.slice(1) : [...argv];
83815
84364
  const out = {};
@@ -83830,7 +84379,7 @@ function sessionHelpText() {
83830
84379
  return "zelari-code session \u2014 inspect and curate one session spine\n\nUsage:\n zelari-code session validate [<sessionId>] [--json]\n zelari-code session waive-debt <sessionId> <taskId> [--note <text>]\n\nvalidate re-reads the log with the core tolerant reader and reports the\nReplayIssues it collected (corrupt lines, schema mismatches, seq gaps /\nduplicates / non-monotonic seq) with line, seq and reason. With no\n<sessionId>: the current-session marker, else the newest spine.\n\nwaive-debt closes ONE open verify-debt slot (a verify.debt_open with no\nmatching verify.debt_cleared) by appending the cleared event through the\nsame locked writer the runtime uses. A waiver is an OPERATOR assertion,\nnot a verification (ADR-0023) \u2014 the event carries source=waiver plus the\noptional --note, so replay can always tell the two apart.\n\nOptions:\n --json (validate) Print the report as JSON\n --note <text> (waive-debt) Why the slot is being waived\n --cwd <path> Workspace root for the sessions dir\n (default: current directory;\n ZELARI_SESSIONS_DIR overrides both)\n --help, -h This text\n\nExit codes: validate \u2014 0 clean / 1 issues (or no spine). waive-debt \u2014\n0 cleared / 1 bad invocation or unknown taskId / 2 spine locked by a\nlive writer / 3 read or write error.\n";
83831
84380
  }
83832
84381
  function shortPath3(p3, cwd) {
83833
- const rel2 = path125.relative(cwd, p3);
84382
+ const rel2 = path127.relative(cwd, p3);
83834
84383
  return rel2 && !rel2.startsWith("..") ? rel2 : p3;
83835
84384
  }
83836
84385
  function formatIssue(issue2) {
@@ -83870,7 +84419,7 @@ async function runWaiveDebt(opts, cwd) {
83870
84419
  }
83871
84420
  let report;
83872
84421
  try {
83873
- report = parseSessionLogText(resolved.eventsPath, readFileSync61(resolved.eventsPath, "utf-8"));
84422
+ report = parseSessionLogText(resolved.eventsPath, readFileSync62(resolved.eventsPath, "utf-8"));
83874
84423
  } catch (err) {
83875
84424
  process.stderr.write(`[session] ${err instanceof Error ? err.message : String(err)}
83876
84425
  `);
@@ -83893,7 +84442,7 @@ async function runWaiveDebt(opts, cwd) {
83893
84442
  return 1;
83894
84443
  }
83895
84444
  const last = report.events[report.events.length - 1];
83896
- const sessionDir = path125.dirname(resolved.eventsPath);
84445
+ const sessionDir = path127.dirname(resolved.eventsPath);
83897
84446
  let writer;
83898
84447
  try {
83899
84448
  writer = await SessionLogWriter.open(sessionDir, resolved.sessionId, (last?.seq ?? 0) + 1);
@@ -83950,7 +84499,7 @@ async function runSessionCommand(argv) {
83950
84499
  return 1;
83951
84500
  }
83952
84501
  if (subcommand === "waive-debt") {
83953
- return await runWaiveDebt(opts, path125.resolve(opts.cwd ?? process.cwd()));
84502
+ return await runWaiveDebt(opts, path127.resolve(opts.cwd ?? process.cwd()));
83954
84503
  }
83955
84504
  if (subcommand !== "validate") {
83956
84505
  process.stderr.write(`[session] unknown subcommand '${subcommand}'
@@ -83959,7 +84508,7 @@ async function runSessionCommand(argv) {
83959
84508
  process.stdout.write(sessionHelpText());
83960
84509
  return 1;
83961
84510
  }
83962
- const cwd = path125.resolve(opts.cwd ?? process.cwd());
84511
+ const cwd = path127.resolve(opts.cwd ?? process.cwd());
83963
84512
  const resolved = resolveSpineSession({
83964
84513
  ...opts.sessionId !== void 0 ? { sessionId: opts.sessionId } : {},
83965
84514
  cwd
@@ -83969,7 +84518,7 @@ async function runSessionCommand(argv) {
83969
84518
  `);
83970
84519
  return 1;
83971
84520
  }
83972
- const text = readFileSync61(resolved.eventsPath, "utf-8");
84521
+ const text = readFileSync62(resolved.eventsPath, "utf-8");
83973
84522
  const report = parseSessionLogText(resolved.eventsPath, text);
83974
84523
  const last = report.events[report.events.length - 1];
83975
84524
  if (opts.json === true) {
@@ -84103,7 +84652,7 @@ __export(evolve_exports2, {
84103
84652
  parseEvolveFlags: () => parseEvolveFlags,
84104
84653
  runEvolveCommand: () => runEvolveCommand
84105
84654
  });
84106
- import { readFileSync as readFileSync62 } from "node:fs";
84655
+ import { readFileSync as readFileSync63 } from "node:fs";
84107
84656
  function asString5(value) {
84108
84657
  return typeof value === "string" ? value : "";
84109
84658
  }
@@ -84195,9 +84744,9 @@ function verdictLine(v) {
84195
84744
  return ` [hold ] ${v.reason}`;
84196
84745
  }
84197
84746
  const at = `@seq ${v.proposal.decisiveSeq}`;
84198
- const path126 = v.proposal.path !== void 0 ? ` \xB7 ${v.proposal.path}` : "";
84747
+ const path128 = v.proposal.path !== void 0 ? ` \xB7 ${v.proposal.path}` : "";
84199
84748
  const saved = v.action === "shadow" ? ` \xB7 saves ~${v.proposal.estSavedCalls} call` : "";
84200
- return ` [${v.action === "shadow" ? "shadow" : "hold "}] ${v.proposal.kind} ${at}${path126}${saved}${v.action === "shadow" ? "" : ` \u2014 ${v.reason}`}`;
84749
+ return ` [${v.action === "shadow" ? "shadow" : "hold "}] ${v.proposal.kind} ${at}${path128}${saved}${v.action === "shadow" ? "" : ` \u2014 ${v.reason}`}`;
84201
84750
  }
84202
84751
  async function runEvolveCommand(argv) {
84203
84752
  const flags = parseEvolveFlags(argv);
@@ -84221,7 +84770,7 @@ ${evolveHelpText()}`);
84221
84770
  }
84222
84771
  let parsed;
84223
84772
  try {
84224
- parsed = parseSessionLogText("events.jsonl", readFileSync62(target.eventsPath, "utf-8"));
84773
+ parsed = parseSessionLogText("events.jsonl", readFileSync63(target.eventsPath, "utf-8"));
84225
84774
  } catch (err) {
84226
84775
  process.stderr.write(
84227
84776
  `[zelari-code evolve] cannot read ${target.eventsPath}: ${err instanceof Error ? err.message : String(err)}
@@ -88255,6 +88804,7 @@ init_verificationBridge();
88255
88804
  init_completionProof();
88256
88805
  init_opsKnowledge();
88257
88806
  init_repeatCheck();
88807
+ init_onePager();
88258
88808
  init_verifyStatus();
88259
88809
  init_nativeVerification();
88260
88810
  init_spineTelemetry();
@@ -88625,10 +89175,16 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
88625
89175
  const cwd = process.cwd();
88626
89176
  const requestSnapshot = getRequestSnapshotWithUsage(sessionId2);
88627
89177
  await writerRef.current?.spine?.beginResourceTurn();
89178
+ const onePager = await buildOnePager({
89179
+ cwd,
89180
+ memory: memoryService ?? null,
89181
+ skipCompactRecap: true
89182
+ });
88628
89183
  const modelContext = await buildModelContext({
88629
89184
  fallbackHistory: historyForModel,
88630
89185
  session: writerRef.current?.spine ?? null,
88631
89186
  resourceSnapshot: writerRef.current?.spine?.latestResourceSnapshot() ?? null,
89187
+ volatileOnePager: onePager,
88632
89188
  phase: workPhase,
88633
89189
  model: getActiveModel(),
88634
89190
  provider: envConfig?.providerId ?? (localCli || "local"),
@@ -88881,9 +89437,12 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
88881
89437
  ),
88882
89438
  maxRecoveries: 2
88883
89439
  },
88884
- requestTail: () => resourceStatusTail(
88885
- writerRef.current?.spine?.latestResourceSnapshot() ?? null
88886
- ),
89440
+ requestTail: () => [
89441
+ ...resourceStatusTail(
89442
+ writerRef.current?.spine?.latestResourceSnapshot() ?? null
89443
+ ),
89444
+ ...onePager
89445
+ ],
88887
89446
  // 2.6 Phase 3: host-owned pre-dispatch resource gate via the spine
88888
89447
  // mirror (doc section 11.3). Degrade-and-stop (null gate = allow).
88889
89448
  // 2.6.1 (plan §13): argument-aware — bash is essential only when
@@ -89470,9 +90029,15 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
89470
90029
  const anchored = maybeAnchorShortAnswer(text);
89471
90030
  const effectiveText = anchored ?? text;
89472
90031
  await writerRef.current?.spine?.beginResourceTurn();
90032
+ const onePager = await buildOnePager({
90033
+ cwd: process.cwd(),
90034
+ memory: null,
90035
+ skipCompactRecap: true
90036
+ });
89473
90037
  const councilContext = await buildModelContext({
89474
90038
  fallbackHistory: getHistory(),
89475
90039
  session: writerRef.current?.spine ?? null,
90040
+ volatileOnePager: onePager,
89476
90041
  phase: getPhase(),
89477
90042
  model: envConfig.model,
89478
90043
  provider: envConfig.providerId,
@@ -90490,10 +91055,10 @@ init_ledger();
90490
91055
 
90491
91056
  // src/cli/evolution/proposals.ts
90492
91057
  import { existsSync as existsSync60, readFileSync as readFileSync49 } from "node:fs";
90493
- import path93 from "node:path";
90494
- var PROPOSALS_REL = path93.join(".zelari", "evolution", "proposals.jsonl");
91058
+ import path94 from "node:path";
91059
+ var PROPOSALS_REL = path94.join(".zelari", "evolution", "proposals.jsonl");
90495
91060
  function proposalsPath(cwd) {
90496
- return path93.join(cwd, PROPOSALS_REL);
91061
+ return path94.join(cwd, PROPOSALS_REL);
90497
91062
  }
90498
91063
  function readProposalStore(cwd) {
90499
91064
  const file2 = proposalsPath(cwd);
@@ -90680,15 +91245,15 @@ function handleStatusLine(args, opts = {}) {
90680
91245
  init_session();
90681
91246
  init_sessionManager();
90682
91247
  import { existsSync as existsSync61, readFileSync as readFileSync50, readdirSync as readdirSync13 } from "node:fs";
90683
- import path94 from "node:path";
91248
+ import path95 from "node:path";
90684
91249
  var FILE_TOOLS2 = /* @__PURE__ */ new Set(["read_file", "write_file", "edit"]);
90685
91250
  function newestSessionId(sessionsDir2) {
90686
91251
  try {
90687
- const names = readdirSync13(sessionsDir2).filter((n) => existsSync61(path94.join(sessionsDir2, n, "events.jsonl")));
91252
+ const names = readdirSync13(sessionsDir2).filter((n) => existsSync61(path95.join(sessionsDir2, n, "events.jsonl")));
90688
91253
  if (names.length === 0) return null;
90689
91254
  const scored = names.map((n) => {
90690
91255
  try {
90691
- const text = readFileSync50(path94.join(sessionsDir2, n, "events.jsonl"), "utf-8");
91256
+ const text = readFileSync50(path95.join(sessionsDir2, n, "events.jsonl"), "utf-8");
90692
91257
  const last = parseSessionLogText("events.jsonl", text).events;
90693
91258
  return { n, ts: last[last.length - 1]?.ts ?? 0 };
90694
91259
  } catch {
@@ -90702,7 +91267,7 @@ function newestSessionId(sessionsDir2) {
90702
91267
  }
90703
91268
  }
90704
91269
  function shortPath(p3, cwd) {
90705
- const rel2 = path94.relative(cwd, p3);
91270
+ const rel2 = path95.relative(cwd, p3);
90706
91271
  return rel2 && !rel2.startsWith("..") ? rel2 : p3;
90707
91272
  }
90708
91273
  function render(report, cwd, sessionId2) {
@@ -90861,7 +91426,7 @@ function buildSessionReport(opts = {}) {
90861
91426
  const cwd = opts.cwd ?? process.cwd();
90862
91427
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: cwd, env: opts.env });
90863
91428
  const marker = opts.sessionId ?? getCurrentSessionId() ?? void 0;
90864
- const marked = marker ? path94.join(sessionsDir2, marker, "events.jsonl") : null;
91429
+ const marked = marker ? path95.join(sessionsDir2, marker, "events.jsonl") : null;
90865
91430
  const sessionId2 = marker && marked && existsSync61(marked) ? marker : newestSessionId(sessionsDir2);
90866
91431
  if (!sessionId2) {
90867
91432
  return {
@@ -90870,7 +91435,7 @@ function buildSessionReport(opts = {}) {
90870
91435
  markdown: `no session spine found under ${sessionsDir2} \u2014 nothing to report (this is not an error).`
90871
91436
  };
90872
91437
  }
90873
- const eventsPath = path94.join(sessionsDir2, sessionId2, "events.jsonl");
91438
+ const eventsPath = path95.join(sessionsDir2, sessionId2, "events.jsonl");
90874
91439
  let text;
90875
91440
  try {
90876
91441
  text = readFileSync50(eventsPath, "utf-8");
@@ -90964,7 +91529,7 @@ function handleSlashCommand(text, availableSkills) {
90964
91529
  /resume-mission \u2014 resume the persisted mission (.zelari/mission-state.json; TUI twin of --resume-mission)
90965
91530
  /council-feedback <memberId> <1-5> [note] \u2014 rate a council member for future ranking (Task I.2)
90966
91531
  /promote-member <memberId> \u2014 promote a council member to a standalone skill (v3-K)
90967
- /memory [stats|search|show|related|history|retract|forget|consolidate|index|promote|doctor|export|audit] \u2014 inspect native project memory
91532
+ /memory [stats|search|show|related|history|retract|forget|consolidate|dream|index|promote|doctor|export|audit] \u2014 inspect native project memory
90968
91533
  /update [--yes|-y] \u2014 check for zelari-code updates; --yes performs the update (v3-N)
90969
91534
  /plugins \u2014 list optional tool plugins (Playwright, eslint, ruff, LSP servers)
90970
91535
  /plugins install <id> \u2014 install a plugin now (e.g. /plugins install eslint)
@@ -91780,7 +92345,7 @@ async function handleUndo(ctx, warningMessage, doConfirm) {
91780
92345
  init_session();
91781
92346
  init_sessionManager();
91782
92347
  init_messageHelpers();
91783
- import path95 from "node:path";
92348
+ import path96 from "node:path";
91784
92349
  var EMPTY_FIELDS = { name: "", engine: "", cwd: "" };
91785
92350
  function sessionSearchText(fields) {
91786
92351
  return [fields.name, fields.engine, fields.cwd].map((s) => s.trim()).filter((s) => s.length > 0).join(" ");
@@ -91796,7 +92361,7 @@ function shortenPath(p3, max = 28) {
91796
92361
  }
91797
92362
  async function readSessionSearchFields(id3, sessionsDir2 = resolveSessionsDir()) {
91798
92363
  try {
91799
- const report = await readSessionLog(path95.join(sessionsDir2, id3, "events.jsonl"));
92364
+ const report = await readSessionLog(path96.join(sessionsDir2, id3, "events.jsonl"));
91800
92365
  const started = report.events.find((e) => e.kind === "session.started");
91801
92366
  const firstUser = report.events.find((e) => e.kind === "user.message");
91802
92367
  const data = started?.data ?? {};
@@ -92105,8 +92670,8 @@ init_howWeTest();
92105
92670
  init_promotion();
92106
92671
  init_repeatCheck();
92107
92672
  init_worldModel();
92108
- import { promises as fs38 } from "node:fs";
92109
- import * as path96 from "node:path";
92673
+ import { promises as fs39 } from "node:fs";
92674
+ import * as path97 from "node:path";
92110
92675
  var USAGE = [
92111
92676
  "/memory \u2014 backend summary",
92112
92677
  "/memory search <query>",
@@ -92116,6 +92681,7 @@ var USAGE = [
92116
92681
  "/memory retract <id> [reason]",
92117
92682
  "/memory forget <id> --yes",
92118
92683
  "/memory consolidate [query]",
92684
+ "/memory dream [--min-candidates N] \u2014 consolidate pending candidates into durable nodes",
92119
92685
  "/memory index [--force]",
92120
92686
  "/memory promote <id> \u2014 append durable knowledge to managed AGENTS.md section",
92121
92687
  '/memory promote con-<fp> --as-check --command "<cmd>" [--expect-exit N] \u2014 append a WorldCheck',
@@ -92131,25 +92697,34 @@ function sourceLine(source2) {
92131
92697
  const entries = Object.entries(source2).filter(([, value]) => value !== void 0 && value !== "");
92132
92698
  return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
92133
92699
  }
92700
+ function parseMinCandidates(args) {
92701
+ const flagIndex = args.findIndex(
92702
+ (arg) => arg === "--min-candidates" || arg === "--min-occurrences"
92703
+ );
92704
+ const raw = flagIndex >= 0 ? args[flagIndex + 1] : args.find((arg) => /^\d+$/.test(arg));
92705
+ if (raw === void 0) return void 0;
92706
+ const value = Number.parseInt(raw, 10);
92707
+ return Number.isFinite(value) && value > 0 ? value : void 0;
92708
+ }
92134
92709
  function isInside(root, target) {
92135
- const relative6 = path96.relative(root, target);
92136
- return relative6 === "" || !relative6.startsWith("..") && !path96.isAbsolute(relative6);
92710
+ const relative6 = path97.relative(root, target);
92711
+ return relative6 === "" || !relative6.startsWith("..") && !path97.isAbsolute(relative6);
92137
92712
  }
92138
92713
  async function safeExportPath(cwd, requested) {
92139
- const lexicalRoot = path96.resolve(cwd);
92140
- const root = await fs38.realpath(lexicalRoot).catch(() => lexicalRoot);
92141
- const fallback = path96.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
92142
- const target = requested?.trim() ? path96.resolve(root, requested.trim()) : fallback;
92714
+ const lexicalRoot = path97.resolve(cwd);
92715
+ const root = await fs39.realpath(lexicalRoot).catch(() => lexicalRoot);
92716
+ const fallback = path97.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
92717
+ const target = requested?.trim() ? path97.resolve(root, requested.trim()) : fallback;
92143
92718
  if (!isInside(root, target)) {
92144
92719
  throw new Error("Export path must stay inside the active project.");
92145
92720
  }
92146
- const parent = path96.dirname(target);
92147
- const relativeParent = path96.relative(root, parent);
92721
+ const parent = path97.dirname(target);
92722
+ const relativeParent = path97.relative(root, parent);
92148
92723
  let cursor = root;
92149
- for (const segment of relativeParent.split(path96.sep).filter(Boolean)) {
92150
- cursor = path96.join(cursor, segment);
92724
+ for (const segment of relativeParent.split(path97.sep).filter(Boolean)) {
92725
+ cursor = path97.join(cursor, segment);
92151
92726
  try {
92152
- const stat9 = await fs38.lstat(cursor);
92727
+ const stat9 = await fs39.lstat(cursor);
92153
92728
  if (stat9.isSymbolicLink()) {
92154
92729
  throw new Error("Export path must not traverse a symbolic link.");
92155
92730
  }
@@ -92159,7 +92734,7 @@ async function safeExportPath(cwd, requested) {
92159
92734
  }
92160
92735
  }
92161
92736
  try {
92162
- if ((await fs38.lstat(target)).isSymbolicLink()) {
92737
+ if ((await fs39.lstat(target)).isSymbolicLink()) {
92163
92738
  throw new Error("Export target must not be a symbolic link.");
92164
92739
  }
92165
92740
  } catch (error51) {
@@ -92288,6 +92863,15 @@ ${message}` : message
92288
92863
  emit(`[memory] consolidation scanned ${result.scanned} candidate(s), created ${result.created.length} durable node(s), archived ${result.archivedSourceIds.length} source duplicate(s).`);
92289
92864
  return;
92290
92865
  }
92866
+ case "dream": {
92867
+ const minOccurrences = parseMinCandidates(args);
92868
+ const result = await memory.consolidate({
92869
+ source: { agent: "user-cli-dream" },
92870
+ ...minOccurrences === void 0 ? {} : { minOccurrences }
92871
+ });
92872
+ emit(`[memory dream] consolidated ${result.scanned} candidate(s), created ${result.created.length} durable node(s), archived ${result.archivedSourceIds.length} source duplicate(s).`);
92873
+ return;
92874
+ }
92291
92875
  case "index": {
92292
92876
  const result = memory.index ? await memory.index({ force: args.includes("--force") || args.includes("-f") }) : { status: "disabled", scanned: 0, indexed: 0, skipped: 0, failed: 0, interrupted: false };
92293
92877
  emit(
@@ -92350,13 +92934,13 @@ ${message}` : message
92350
92934
  }
92351
92935
  case "export": {
92352
92936
  const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
92353
- await fs38.mkdir(path96.dirname(target), { recursive: true });
92354
- const root = await fs38.realpath(ctx.cwd).catch(() => path96.resolve(ctx.cwd));
92355
- const realParent = await fs38.realpath(path96.dirname(target));
92937
+ await fs39.mkdir(path97.dirname(target), { recursive: true });
92938
+ const root = await fs39.realpath(ctx.cwd).catch(() => path97.resolve(ctx.cwd));
92939
+ const realParent = await fs39.realpath(path97.dirname(target));
92356
92940
  if (!isInside(root, realParent)) {
92357
92941
  throw new Error("Export path resolves outside the active project.");
92358
92942
  }
92359
- await fs38.writeFile(target, JSON.stringify(await memory.export(), null, 2) + "\n", "utf8");
92943
+ await fs39.writeFile(target, JSON.stringify(await memory.export(), null, 2) + "\n", "utf8");
92360
92944
  emit(`[memory] export written to ${target}`);
92361
92945
  return;
92362
92946
  }
@@ -92761,13 +93345,13 @@ ${digest}
92761
93345
  init_auditLogger();
92762
93346
  init_toolRegistry();
92763
93347
  init_messageHelpers();
92764
- import { promises as fs40 } from "node:fs";
93348
+ import { promises as fs41 } from "node:fs";
92765
93349
 
92766
93350
  // src/cli/tools/krakenCsvFanout.ts
92767
93351
  init_zod();
92768
93352
  init_taskTool();
92769
- import { promises as fs39 } from "node:fs";
92770
- import path97 from "node:path";
93353
+ import { promises as fs40 } from "node:fs";
93354
+ import path98 from "node:path";
92771
93355
  import { randomBytes as randomBytes6 } from "node:crypto";
92772
93356
  var CsvFanoutArgsSchema = external_exports.object({
92773
93357
  csv_path: external_exports.string().min(1),
@@ -92788,7 +93372,7 @@ var CsvFanoutArgsSchema = external_exports.object({
92788
93372
  max_runtime_seconds: external_exports.number().int().positive().optional()
92789
93373
  });
92790
93374
  async function readCsv(filePath) {
92791
- const text = await fs39.readFile(filePath, "utf8");
93375
+ const text = await fs40.readFile(filePath, "utf8");
92792
93376
  return parseCsv(text);
92793
93377
  }
92794
93378
  function parseCsv(text) {
@@ -92861,8 +93445,8 @@ function resolveMaxConcurrency(env = process.env) {
92861
93445
  }
92862
93446
  async function runCsvFanout(args, deps, opts) {
92863
93447
  const start = Date.now();
92864
- const absCsv = path97.isAbsolute(args.csv_path) ? args.csv_path : path97.join(opts.parentCwd, args.csv_path);
92865
- const absOut = path97.isAbsolute(args.output_csv_path) ? args.output_csv_path : path97.join(opts.parentCwd, args.output_csv_path);
93448
+ const absCsv = path98.isAbsolute(args.csv_path) ? args.csv_path : path98.join(opts.parentCwd, args.csv_path);
93449
+ const absOut = path98.isAbsolute(args.output_csv_path) ? args.output_csv_path : path98.join(opts.parentCwd, args.output_csv_path);
92866
93450
  const { headers: headers3, rows } = await readCsv(absCsv);
92867
93451
  if (headers3.length === 0) {
92868
93452
  throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
@@ -92918,7 +93502,7 @@ async function runCsvFanout(args, deps, opts) {
92918
93502
  errored += 1;
92919
93503
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
92920
93504
  }
92921
- await fs39.mkdir(path97.dirname(absOut), { recursive: true });
93505
+ await fs40.mkdir(path98.dirname(absOut), { recursive: true });
92922
93506
  await queueWrite(serializeCsv(outHeaders, outputRecords));
92923
93507
  }
92924
93508
  }
@@ -92940,8 +93524,8 @@ async function runCsvFanout(args, deps, opts) {
92940
93524
  }
92941
93525
  async function atomicWrite(file2, contents) {
92942
93526
  const tmp = `${file2}.${process.pid}.${Date.now()}.${randomBytes6(6).toString("hex")}.tmp`;
92943
- await fs39.writeFile(tmp, contents, "utf8");
92944
- await fs39.rename(tmp, file2);
93527
+ await fs40.writeFile(tmp, contents, "utf8");
93528
+ await fs40.rename(tmp, file2);
92945
93529
  }
92946
93530
 
92947
93531
  // src/cli/slashHandlers/krakenFanout.ts
@@ -93039,7 +93623,7 @@ async function handleKrakenFanout(ctx, raw) {
93039
93623
  }
93040
93624
  const absCsv = isAbsolute4(parsed.args.csv_path) ? parsed.args.csv_path : joinPath(ctx.cwd, parsed.args.csv_path);
93041
93625
  try {
93042
- await fs40.access(absCsv);
93626
+ await fs41.access(absCsv);
93043
93627
  } catch {
93044
93628
  appendSystem(ctx.setMessages, `[kraken fanout] source CSV not found: ${absCsv}`);
93045
93629
  return;
@@ -93112,8 +93696,8 @@ function splitArgs(s) {
93112
93696
 
93113
93697
  // src/cli/slashHandlers/krakenWorkbench.ts
93114
93698
  init_messageHelpers();
93115
- import { promises as fs41 } from "node:fs";
93116
- import path98 from "node:path";
93699
+ import { promises as fs42 } from "node:fs";
93700
+ import path99 from "node:path";
93117
93701
 
93118
93702
  // src/cli/kraken/workbenchView.ts
93119
93703
  var EMPTY = {
@@ -93230,15 +93814,15 @@ function formatWorkbenchForTerminal(p3) {
93230
93814
 
93231
93815
  // src/cli/slashHandlers/krakenWorkbench.ts
93232
93816
  async function handleKrakenWorkbench(ctx) {
93233
- const dir = path98.join(ctx.cwd, ".zelari", "radio");
93817
+ const dir = path99.join(ctx.cwd, ".zelari", "radio");
93234
93818
  let latest = null;
93235
93819
  let latestMtime = 0;
93236
93820
  try {
93237
- const files = await fs41.readdir(dir);
93821
+ const files = await fs42.readdir(dir);
93238
93822
  for (const f of files) {
93239
93823
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
93240
- const full = path98.join(dir, f);
93241
- const stat9 = await fs41.stat(full);
93824
+ const full = path99.join(dir, f);
93825
+ const stat9 = await fs42.stat(full);
93242
93826
  if (stat9.mtimeMs > latestMtime) {
93243
93827
  latestMtime = stat9.mtimeMs;
93244
93828
  latest = full;
@@ -93250,14 +93834,14 @@ async function handleKrakenWorkbench(ctx) {
93250
93834
  appendSystem(ctx.setMessages, "[kraken workbench] no workbench file found (.zelari/radio/workbench-*.md)");
93251
93835
  return;
93252
93836
  }
93253
- const content = await fs41.readFile(latest, "utf8");
93837
+ const content = await fs42.readFile(latest, "utf8");
93254
93838
  const parsed = parseWorkbench(content);
93255
93839
  const rendered = formatWorkbenchForTerminal(parsed);
93256
93840
  if (!rendered.trim()) {
93257
- appendSystem(ctx.setMessages, `[kraken workbench] ${path98.basename(latest)}: (no nodes / no events yet)`);
93841
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path99.basename(latest)}: (no nodes / no events yet)`);
93258
93842
  return;
93259
93843
  }
93260
- appendSystem(ctx.setMessages, `[kraken workbench] ${path98.basename(latest)}:
93844
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path99.basename(latest)}:
93261
93845
  ${rendered}`);
93262
93846
  }
93263
93847
 
@@ -93576,20 +94160,20 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
93576
94160
  // src/cli/slashHandlers/promoteMember.ts
93577
94161
  init_messageHelpers();
93578
94162
  init_paths();
93579
- import { promises as fs42 } from "node:fs";
93580
- import path101 from "node:path";
94163
+ import { promises as fs43 } from "node:fs";
94164
+ import path102 from "node:path";
93581
94165
  async function handlePromoteMember(ctx, memberId) {
93582
94166
  try {
93583
94167
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
93584
94168
  const { skill, markdown } = promoteMember2(memberId);
93585
94169
  const skillDir = skillsDir();
93586
- await fs42.mkdir(skillDir, { recursive: true });
93587
- const filePath = path101.join(skillDir, `${skill.id}.md`);
93588
- const previous = await fs42.readFile(filePath, "utf8").catch(() => null);
93589
- const { createHash: createHash28 } = await import("node:crypto");
93590
- const sha = (s) => createHash28("sha256").update(s, "utf8").digest("hex");
94170
+ await fs43.mkdir(skillDir, { recursive: true });
94171
+ const filePath = path102.join(skillDir, `${skill.id}.md`);
94172
+ const previous = await fs43.readFile(filePath, "utf8").catch(() => null);
94173
+ const { createHash: createHash29 } = await import("node:crypto");
94174
+ const sha = (s) => createHash29("sha256").update(s, "utf8").digest("hex");
93591
94175
  const lineage = `<!-- lineage: genome=sha256:${sha(markdown)} parent=${previous ? `sha256:${sha(previous)}` : "none"} promotedBy=user promotedAt=${(/* @__PURE__ */ new Date()).toISOString()} -->`;
93592
- await fs42.writeFile(filePath, `${markdown}
94176
+ await fs43.writeFile(filePath, `${markdown}
93593
94177
  ${lineage}
93594
94178
  `, "utf8");
93595
94179
  appendSystem(
@@ -93609,8 +94193,8 @@ ${lineage}
93609
94193
 
93610
94194
  // src/cli/branchManager.ts
93611
94195
  init_paths();
93612
- import { promises as fs43, existsSync as existsSync65, readFileSync as readFileSync52, writeFileSync as writeFileSync27, mkdirSync as mkdirSync24, statSync as statSync10, rmSync as rmSync5 } from "node:fs";
93613
- import path102 from "node:path";
94196
+ import { promises as fs44, existsSync as existsSync65, readFileSync as readFileSync52, writeFileSync as writeFileSync27, mkdirSync as mkdirSync24, statSync as statSync10, rmSync as rmSync5 } from "node:fs";
94197
+ import path103 from "node:path";
93614
94198
  var META_FILENAME = "meta.json";
93615
94199
  var SESSIONS_SUBDIR = "sessions";
93616
94200
  function getBranchesBaseDir() {
@@ -93620,13 +94204,13 @@ function getSessionsBaseDir() {
93620
94204
  return sessionsDir();
93621
94205
  }
93622
94206
  function branchPathFor(name, baseDir) {
93623
- return path102.join(baseDir, name);
94207
+ return path103.join(baseDir, name);
93624
94208
  }
93625
94209
  function metaPathFor(name, baseDir) {
93626
- return path102.join(baseDir, name, META_FILENAME);
94210
+ return path103.join(baseDir, name, META_FILENAME);
93627
94211
  }
93628
94212
  function sessionsPathFor(name, baseDir) {
93629
- return path102.join(baseDir, name, SESSIONS_SUBDIR);
94213
+ return path103.join(baseDir, name, SESSIONS_SUBDIR);
93630
94214
  }
93631
94215
  function readBranchMeta(name, baseDir) {
93632
94216
  const metaPath = metaPathFor(name, baseDir);
@@ -93651,13 +94235,13 @@ function readBranchMeta(name, baseDir) {
93651
94235
  }
93652
94236
  function writeBranchMeta(name, baseDir, meta3) {
93653
94237
  const metaPath = metaPathFor(name, baseDir);
93654
- mkdirSync24(path102.dirname(metaPath), { recursive: true });
94238
+ mkdirSync24(path103.dirname(metaPath), { recursive: true });
93655
94239
  writeFileSync27(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
93656
94240
  }
93657
94241
  async function countSessions(name, baseDir) {
93658
94242
  const sessionsPath = sessionsPathFor(name, baseDir);
93659
94243
  try {
93660
- const entries = await fs43.readdir(sessionsPath);
94244
+ const entries = await fs44.readdir(sessionsPath);
93661
94245
  return entries.filter((e) => e.endsWith(".jsonl")).length;
93662
94246
  } catch (err) {
93663
94247
  if (err.code === "ENOENT") return 0;
@@ -93702,15 +94286,15 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
93702
94286
  if (branchExists(name, baseDir)) {
93703
94287
  throw new BranchAlreadyExistsError(name);
93704
94288
  }
93705
- const sourcePath = path102.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
94289
+ const sourcePath = path103.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
93706
94290
  if (!existsSync65(sourcePath)) {
93707
94291
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
93708
94292
  }
93709
94293
  const branchPath = branchPathFor(name, baseDir);
93710
94294
  const branchSessionsPath = sessionsPathFor(name, baseDir);
93711
94295
  mkdirSync24(branchSessionsPath, { recursive: true });
93712
- const destPath = path102.join(branchSessionsPath, `${fromSessionId}.jsonl`);
93713
- await fs43.copyFile(sourcePath, destPath);
94296
+ const destPath = path103.join(branchSessionsPath, `${fromSessionId}.jsonl`);
94297
+ await fs44.copyFile(sourcePath, destPath);
93714
94298
  const meta3 = {
93715
94299
  name,
93716
94300
  createdAt: Date.now(),
@@ -93728,7 +94312,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
93728
94312
  async function listBranches(baseDir = getBranchesBaseDir()) {
93729
94313
  let entries;
93730
94314
  try {
93731
- entries = await fs43.readdir(baseDir);
94315
+ entries = await fs44.readdir(baseDir);
93732
94316
  } catch (err) {
93733
94317
  if (err.code === "ENOENT") return [];
93734
94318
  throw err;
@@ -93812,26 +94396,26 @@ async function handleBranchCheckout(ctx, branchName) {
93812
94396
 
93813
94397
  // src/cli/slashHandlers/workspace.ts
93814
94398
  init_messageHelpers();
93815
- import { promises as fs44 } from "node:fs";
93816
- import path103 from "node:path";
94399
+ import { promises as fs45 } from "node:fs";
94400
+ import path104 from "node:path";
93817
94401
  async function handleWorkspaceShow(ctx, what) {
93818
94402
  try {
93819
- const zelari = path103.join(process.cwd(), ".zelari");
94403
+ const zelari = path104.join(process.cwd(), ".zelari");
93820
94404
  let content;
93821
94405
  switch (what) {
93822
94406
  case "plan": {
93823
- const planPath = path103.join(zelari, "plan.md");
94407
+ const planPath = path104.join(zelari, "plan.md");
93824
94408
  try {
93825
- content = await fs44.readFile(planPath, "utf-8");
94409
+ content = await fs45.readFile(planPath, "utf-8");
93826
94410
  } catch {
93827
94411
  content = "(no plan.md yet \u2014 run a council session first)";
93828
94412
  }
93829
94413
  break;
93830
94414
  }
93831
94415
  case "decisions": {
93832
- const decisionsDir = path103.join(zelari, "decisions");
94416
+ const decisionsDir = path104.join(zelari, "decisions");
93833
94417
  try {
93834
- const files = (await fs44.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
94418
+ const files = (await fs45.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
93835
94419
  if (files.length === 0) {
93836
94420
  content = "(no ADRs yet \u2014 invoke /council to generate some)";
93837
94421
  } else {
@@ -93839,7 +94423,7 @@ async function handleWorkspaceShow(ctx, what) {
93839
94423
  `];
93840
94424
  const { parseFrontmatter: parseFrontmatter3 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
93841
94425
  for (const f of files) {
93842
- const raw = await fs44.readFile(path103.join(decisionsDir, f), "utf-8");
94426
+ const raw = await fs45.readFile(path104.join(decisionsDir, f), "utf-8");
93843
94427
  const { meta: meta3, body } = parseFrontmatter3(raw);
93844
94428
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
93845
94429
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -93852,27 +94436,27 @@ async function handleWorkspaceShow(ctx, what) {
93852
94436
  break;
93853
94437
  }
93854
94438
  case "risks": {
93855
- const risksPath = path103.join(zelari, "risks.md");
94439
+ const risksPath = path104.join(zelari, "risks.md");
93856
94440
  try {
93857
- content = await fs44.readFile(risksPath, "utf-8");
94441
+ content = await fs45.readFile(risksPath, "utf-8");
93858
94442
  } catch {
93859
94443
  content = "(no risks.md yet)";
93860
94444
  }
93861
94445
  break;
93862
94446
  }
93863
94447
  case "agents": {
93864
- const agentsPath = path103.join(process.cwd(), "AGENTS.MD");
94448
+ const agentsPath = path104.join(process.cwd(), "AGENTS.MD");
93865
94449
  try {
93866
- content = await fs44.readFile(agentsPath, "utf-8");
94450
+ content = await fs45.readFile(agentsPath, "utf-8");
93867
94451
  } catch {
93868
94452
  content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
93869
94453
  }
93870
94454
  break;
93871
94455
  }
93872
94456
  case "docs": {
93873
- const docsDir = path103.join(zelari, "docs");
94457
+ const docsDir = path104.join(zelari, "docs");
93874
94458
  try {
93875
- const files = (await fs44.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
94459
+ const files = (await fs45.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
93876
94460
  content = files.length ? `# Docs (${files.length})
93877
94461
 
93878
94462
  ` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
@@ -93912,8 +94496,8 @@ async function handleWorkspaceReset(ctx, force) {
93912
94496
  return;
93913
94497
  }
93914
94498
  try {
93915
- const target = path103.join(process.cwd(), ".zelari");
93916
- await fs44.rm(target, { recursive: true, force: true });
94499
+ const target = path104.join(process.cwd(), ".zelari");
94500
+ await fs45.rm(target, { recursive: true, force: true });
93917
94501
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
93918
94502
  } catch (err) {
93919
94503
  appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
@@ -93924,13 +94508,13 @@ async function handleWorkspaceReset(ctx, force) {
93924
94508
  init_provider2();
93925
94509
 
93926
94510
  // src/cli/skillHistory.ts
93927
- import { promises as fs45, existsSync as existsSync66, statSync as statSync11, renameSync as renameSync6, appendFileSync as appendFileSync5, mkdirSync as mkdirSync25 } from "node:fs";
94511
+ import { promises as fs46, existsSync as existsSync66, statSync as statSync11, renameSync as renameSync6, appendFileSync as appendFileSync5, mkdirSync as mkdirSync25 } from "node:fs";
93928
94512
  init_paths();
93929
94513
  var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
93930
94514
  async function readSkillHistory(file2) {
93931
94515
  let raw = "";
93932
94516
  try {
93933
- raw = await fs45.readFile(file2, "utf-8");
94517
+ raw = await fs46.readFile(file2, "utf-8");
93934
94518
  } catch {
93935
94519
  return [];
93936
94520
  }
@@ -95822,8 +96406,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
95822
96406
  let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
95823
96407
  if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
95824
96408
  try {
95825
- const path126 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
95826
- name = path126 && /^[a-z0-9]/.test(path126) ? path126 : "imported-skill";
96409
+ const path128 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
96410
+ name = path128 && /^[a-z0-9]/.test(path128) ? path128 : "imported-skill";
95827
96411
  } catch {
95828
96412
  name = "imported-skill";
95829
96413
  }