zelari-code 2.40.0 → 2.41.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.
@@ -3482,10 +3482,10 @@ function mergeDefs(...defs) {
3482
3482
  function cloneDef(schema) {
3483
3483
  return mergeDefs(schema._zod.def);
3484
3484
  }
3485
- function getElementAtPath(obj, path102) {
3486
- if (!path102)
3485
+ function getElementAtPath(obj, path103) {
3486
+ if (!path103)
3487
3487
  return obj;
3488
- return path102.reduce((acc, key) => acc?.[key], obj);
3488
+ return path103.reduce((acc, key) => acc?.[key], obj);
3489
3489
  }
3490
3490
  function promiseAllObject(promisesObj) {
3491
3491
  const keys = Object.keys(promisesObj);
@@ -3813,11 +3813,11 @@ function explicitlyAborted(x, startIndex = 0) {
3813
3813
  }
3814
3814
  return false;
3815
3815
  }
3816
- function prefixIssues(path102, issues) {
3816
+ function prefixIssues(path103, issues) {
3817
3817
  return issues.map((iss) => {
3818
3818
  var _a3;
3819
3819
  (_a3 = iss).path ?? (_a3.path = []);
3820
- iss.path.unshift(path102);
3820
+ iss.path.unshift(path103);
3821
3821
  return iss;
3822
3822
  });
3823
3823
  }
@@ -4035,16 +4035,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
4035
4035
  }
4036
4036
  function formatError(error51, mapper = (issue2) => issue2.message) {
4037
4037
  const fieldErrors = { _errors: [] };
4038
- const processError = (error52, path102 = []) => {
4038
+ const processError = (error52, path103 = []) => {
4039
4039
  for (const issue2 of error52.issues) {
4040
4040
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4041
- issue2.errors.map((issues) => processError({ issues }, [...path102, ...issue2.path]));
4041
+ issue2.errors.map((issues) => processError({ issues }, [...path103, ...issue2.path]));
4042
4042
  } else if (issue2.code === "invalid_key") {
4043
- processError({ issues: issue2.issues }, [...path102, ...issue2.path]);
4043
+ processError({ issues: issue2.issues }, [...path103, ...issue2.path]);
4044
4044
  } else if (issue2.code === "invalid_element") {
4045
- processError({ issues: issue2.issues }, [...path102, ...issue2.path]);
4045
+ processError({ issues: issue2.issues }, [...path103, ...issue2.path]);
4046
4046
  } else {
4047
- const fullpath = [...path102, ...issue2.path];
4047
+ const fullpath = [...path103, ...issue2.path];
4048
4048
  if (fullpath.length === 0) {
4049
4049
  fieldErrors._errors.push(mapper(issue2));
4050
4050
  } else {
@@ -4071,17 +4071,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
4071
4071
  }
4072
4072
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
4073
4073
  const result = { errors: [] };
4074
- const processError = (error52, path102 = []) => {
4074
+ const processError = (error52, path103 = []) => {
4075
4075
  var _a3, _b;
4076
4076
  for (const issue2 of error52.issues) {
4077
4077
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4078
- issue2.errors.map((issues) => processError({ issues }, [...path102, ...issue2.path]));
4078
+ issue2.errors.map((issues) => processError({ issues }, [...path103, ...issue2.path]));
4079
4079
  } else if (issue2.code === "invalid_key") {
4080
- processError({ issues: issue2.issues }, [...path102, ...issue2.path]);
4080
+ processError({ issues: issue2.issues }, [...path103, ...issue2.path]);
4081
4081
  } else if (issue2.code === "invalid_element") {
4082
- processError({ issues: issue2.issues }, [...path102, ...issue2.path]);
4082
+ processError({ issues: issue2.issues }, [...path103, ...issue2.path]);
4083
4083
  } else {
4084
- const fullpath = [...path102, ...issue2.path];
4084
+ const fullpath = [...path103, ...issue2.path];
4085
4085
  if (fullpath.length === 0) {
4086
4086
  result.errors.push(mapper(issue2));
4087
4087
  continue;
@@ -4113,8 +4113,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
4113
4113
  }
4114
4114
  function toDotPath(_path) {
4115
4115
  const segs = [];
4116
- const path102 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4117
- for (const seg of path102) {
4116
+ const path103 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4117
+ for (const seg of path103) {
4118
4118
  if (typeof seg === "number")
4119
4119
  segs.push(`[${seg}]`);
4120
4120
  else if (typeof seg === "symbol")
@@ -17617,13 +17617,13 @@ function resolveRef(ref, ctx) {
17617
17617
  if (!ref.startsWith("#")) {
17618
17618
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
17619
17619
  }
17620
- const path102 = ref.slice(1).split("/").filter(Boolean);
17621
- if (path102.length === 0) {
17620
+ const path103 = ref.slice(1).split("/").filter(Boolean);
17621
+ if (path103.length === 0) {
17622
17622
  return ctx.rootSchema;
17623
17623
  }
17624
17624
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
17625
- if (path102[0] === defsKey) {
17626
- const key = path102[1];
17625
+ if (path103[0] === defsKey) {
17626
+ const key = path103[1];
17627
17627
  if (!key || !ctx.defs[key]) {
17628
17628
  throw new Error(`Reference not found: ${ref}`);
17629
17629
  }
@@ -18457,17 +18457,17 @@ var init_newlines = __esm({
18457
18457
  });
18458
18458
 
18459
18459
  // packages/core/dist/core/tools/builtin/fileEvents.js
18460
- function fileReadEvent(path102, snapshotId) {
18461
- return { kind: "file.read", actor: { type: "tool" }, data: { path: path102, snapshotId } };
18460
+ function fileReadEvent(path103, snapshotId) {
18461
+ return { kind: "file.read", actor: { type: "tool" }, data: { path: path103, snapshotId } };
18462
18462
  }
18463
- function fileAppliedEvent(path102, snapshotId, bytes) {
18464
- return { kind: "file.applied", actor: { type: "tool" }, data: { path: path102, snapshotId, bytes } };
18463
+ function fileAppliedEvent(path103, snapshotId, bytes) {
18464
+ return { kind: "file.applied", actor: { type: "tool" }, data: { path: path103, snapshotId, bytes } };
18465
18465
  }
18466
- function fileRejectedEvent(path102, reason, hint) {
18466
+ function fileRejectedEvent(path103, reason, hint) {
18467
18467
  return {
18468
18468
  kind: "file.rejected",
18469
18469
  actor: { type: "tool" },
18470
- data: hint === void 0 ? { path: path102, reason } : { path: path102, reason, hint }
18470
+ data: hint === void 0 ? { path: path103, reason } : { path: path103, reason, hint }
18471
18471
  };
18472
18472
  }
18473
18473
  function reReadHint(reject) {
@@ -20336,11 +20336,11 @@ var init_tools = __esm({
20336
20336
  if (!ctx.addDocument)
20337
20337
  return "Knowledge vault tool not available.";
20338
20338
  const title = args["title"] || "New Document";
20339
- const path102 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20339
+ const path103 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20340
20340
  const content = args["content"] || "";
20341
20341
  const tags = args["tags"] || [];
20342
20342
  ctx.addDocument({
20343
- path: path102,
20343
+ path: path103,
20344
20344
  title,
20345
20345
  content,
20346
20346
  format: "markdown",
@@ -20349,7 +20349,7 @@ var init_tools = __esm({
20349
20349
  workspaceId: ctx.workspaceId
20350
20350
  });
20351
20351
  ctx.addActivity("vault", "created document", title);
20352
- return `Document "${title}" created at "${path102}".`;
20352
+ return `Document "${title}" created at "${path103}".`;
20353
20353
  }
20354
20354
  }
20355
20355
  ];
@@ -23878,7 +23878,7 @@ async function createExecutionContext(options = {}) {
23878
23878
  workspaceKind: workspace.kind
23879
23879
  }
23880
23880
  });
23881
- const fs49 = options.fs ?? new NodeFsProvider(workspace);
23881
+ const fs50 = options.fs ?? new NodeFsProvider(workspace);
23882
23882
  const shell = options.shell ?? new NodeShellProvider(workspace);
23883
23883
  const subagent = options.subagent ?? NOOP_SUBAGENT_PROVIDER;
23884
23884
  const env = options.env ?? process.env;
@@ -23886,7 +23886,7 @@ async function createExecutionContext(options = {}) {
23886
23886
  sessionId: sessionId2,
23887
23887
  profile,
23888
23888
  workspace,
23889
- fs: fs49,
23889
+ fs: fs50,
23890
23890
  shell,
23891
23891
  subagent,
23892
23892
  appendSessionEvent: (input) => writer.append(input),
@@ -25287,16 +25287,16 @@ function runRetentionFromEnv() {
25287
25287
  maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
25288
25288
  };
25289
25289
  }
25290
- async function dirSize(path102) {
25290
+ async function dirSize(path103) {
25291
25291
  let total = 0;
25292
25292
  let entries;
25293
25293
  try {
25294
- entries = await readdir(path102, { withFileTypes: true });
25294
+ entries = await readdir(path103, { withFileTypes: true });
25295
25295
  } catch {
25296
25296
  return 0;
25297
25297
  }
25298
25298
  for (const entry of entries) {
25299
- const child = join3(path102, entry.name);
25299
+ const child = join3(path103, entry.name);
25300
25300
  if (entry.isDirectory())
25301
25301
  total += await dirSize(child);
25302
25302
  else {
@@ -25323,19 +25323,19 @@ async function enforceRunRetention(runsDir, options = {}) {
25323
25323
  for (const entry of entries) {
25324
25324
  if (!entry.isDirectory())
25325
25325
  continue;
25326
- const path102 = join3(runsDir, entry.name);
25326
+ const path103 = join3(runsDir, entry.name);
25327
25327
  let startedAt = 0;
25328
25328
  let endedAt;
25329
25329
  let completed = false;
25330
25330
  try {
25331
- const manifest = JSON.parse(await readFile(join3(path102, "manifest.json"), "utf8"));
25331
+ const manifest = JSON.parse(await readFile(join3(path103, "manifest.json"), "utf8"));
25332
25332
  startedAt = manifest.startedAt ?? 0;
25333
25333
  endedAt = manifest.endedAt;
25334
25334
  completed = Boolean(endedAt) && manifest.status !== "running";
25335
25335
  } catch {
25336
25336
  completed = false;
25337
25337
  }
25338
- infos.push({ name: entry.name, path: path102, startedAt, endedAt, completed, bytes: await dirSize(path102) });
25338
+ infos.push({ name: entry.name, path: path103, startedAt, endedAt, completed, bytes: await dirSize(path103) });
25339
25339
  }
25340
25340
  const remove = async (info) => {
25341
25341
  await rm(info.path, { recursive: true, force: true });
@@ -25893,12 +25893,12 @@ var init_engine = __esm({
25893
25893
  * content digest) and the returned ref carries the event seq when the
25894
25894
  * emitter resolved one.
25895
25895
  */
25896
- async fsEvidence(observation, path102, sha2562, content, extra = {}) {
25896
+ async fsEvidence(observation, path103, sha2562, content, extra = {}) {
25897
25897
  const digest = sha2562 && content !== void 0 ? sha2562(content) : void 0;
25898
- const seq = await this.emitEvidence({ observation, path: path102, ...extra, ...digest ? { digest } : {} });
25898
+ const seq = await this.emitEvidence({ observation, path: path103, ...extra, ...digest ? { digest } : {} });
25899
25899
  return {
25900
25900
  tier: "fs-observation",
25901
- ref: path102,
25901
+ ref: path103,
25902
25902
  capturedAt: Date.now(),
25903
25903
  ...digest ? { digest } : {},
25904
25904
  ...seq !== void 0 ? { seq } : {}
@@ -25906,25 +25906,25 @@ var init_engine = __esm({
25906
25906
  }
25907
25907
  async evalFileExists(check2, done) {
25908
25908
  const sha2562 = this.options.sha256 ?? defaultSha256;
25909
- const fs49 = this.services.fs;
25910
- if (!fs49)
25909
+ const fs50 = this.services.fs;
25910
+ if (!fs50)
25911
25911
  return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
25912
- const exists = await fs49.exists(check2.path);
25912
+ const exists = await fs50.exists(check2.path);
25913
25913
  if (!exists) {
25914
25914
  await this.emitEvidence({ observation: "file-exists", path: check2.path, exists: false });
25915
25915
  return done({ status: "fail", evidence: [], detail: `file not found: ${check2.path}` });
25916
25916
  }
25917
- const content = await fs49.readFile(check2.path).catch(() => "");
25917
+ const content = await fs50.readFile(check2.path).catch(() => "");
25918
25918
  return done({
25919
25919
  status: "pass",
25920
25920
  evidence: [await this.fsEvidence("file-exists", check2.path, sha2562, content, { exists: true })]
25921
25921
  });
25922
25922
  }
25923
25923
  async evalFileAbsent(check2, done) {
25924
- const fs49 = this.services.fs;
25925
- if (!fs49)
25924
+ const fs50 = this.services.fs;
25925
+ if (!fs50)
25926
25926
  return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
25927
- const exists = await fs49.exists(check2.path);
25927
+ const exists = await fs50.exists(check2.path);
25928
25928
  if (exists) {
25929
25929
  await this.emitEvidence({ observation: "file-absent", path: check2.path, exists: true });
25930
25930
  return done({ status: "fail", evidence: [], detail: `file still present: ${check2.path}` });
@@ -25936,12 +25936,12 @@ var init_engine = __esm({
25936
25936
  }
25937
25937
  async evalFileContains(check2, done) {
25938
25938
  const sha2562 = this.options.sha256 ?? defaultSha256;
25939
- const fs49 = this.services.fs;
25940
- if (!fs49)
25939
+ const fs50 = this.services.fs;
25940
+ if (!fs50)
25941
25941
  return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
25942
25942
  let content;
25943
25943
  try {
25944
- content = await fs49.readFile(check2.path);
25944
+ content = await fs50.readFile(check2.path);
25945
25945
  } catch {
25946
25946
  await this.emitEvidence({ observation: "file-contains", path: check2.path, readable: false });
25947
25947
  return done({ status: "fail", evidence: [], detail: `file not readable: ${check2.path}` });
@@ -32107,11 +32107,11 @@ var init_synthesisAudit = __esm({
32107
32107
  import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
32108
32108
  import { join as join5 } from "node:path";
32109
32109
  function loadNfrSpec(zelariRoot) {
32110
- const path102 = join5(zelariRoot, "nfr-spec.json");
32111
- if (!existsSync10(path102))
32110
+ const path103 = join5(zelariRoot, "nfr-spec.json");
32111
+ if (!existsSync10(path103))
32112
32112
  return null;
32113
32113
  try {
32114
- const raw = JSON.parse(readFileSync9(path102, "utf8"));
32114
+ const raw = JSON.parse(readFileSync9(path103, "utf8"));
32115
32115
  if (raw.version !== 1 || !Array.isArray(raw.targets))
32116
32116
  return null;
32117
32117
  return raw;
@@ -34512,9 +34512,9 @@ var init_types9 = __esm({
34512
34512
  import { readFileSync as readFileSync14 } from "node:fs";
34513
34513
  import { join as join11 } from "node:path";
34514
34514
  function readLessonsDeduped(zelariRoot) {
34515
- const path102 = join11(zelariRoot, LESSONS_FILE);
34515
+ const path103 = join11(zelariRoot, LESSONS_FILE);
34516
34516
  try {
34517
- const raw = readFileSync14(path102, "utf8");
34517
+ const raw = readFileSync14(path103, "utf8");
34518
34518
  const byId = /* @__PURE__ */ new Map();
34519
34519
  for (const line of raw.split(/\r?\n/)) {
34520
34520
  if (!line.trim())
@@ -34615,8 +34615,8 @@ function keywordsFrom(check2, signature) {
34615
34615
  return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
34616
34616
  }
34617
34617
  function writeLesson(zelariRoot, lesson) {
34618
- const path102 = join12(zelariRoot, LESSONS_FILE);
34619
- appendFileSync(path102, `${JSON.stringify(lesson)}
34618
+ const path103 = join12(zelariRoot, LESSONS_FILE);
34619
+ appendFileSync(path103, `${JSON.stringify(lesson)}
34620
34620
  `, "utf8");
34621
34621
  }
34622
34622
  function findSimilar(lessons, signature) {
@@ -36584,9 +36584,9 @@ function findCycle(nodes) {
36584
36584
  if (color.get(start) !== WHITE)
36585
36585
  continue;
36586
36586
  const stack = [[start, 0]];
36587
- const path102 = [];
36587
+ const path103 = [];
36588
36588
  color.set(start, GRAY);
36589
- path102.push(start);
36589
+ path103.push(start);
36590
36590
  while (stack.length > 0) {
36591
36591
  const top = stack[stack.length - 1];
36592
36592
  const [id3, idx] = top;
@@ -36599,17 +36599,17 @@ function findCycle(nodes) {
36599
36599
  continue;
36600
36600
  const c = color.get(dep);
36601
36601
  if (c === GRAY) {
36602
- const at = path102.indexOf(dep);
36603
- return [...path102.slice(at), dep];
36602
+ const at = path103.indexOf(dep);
36603
+ return [...path103.slice(at), dep];
36604
36604
  }
36605
36605
  if (c === WHITE) {
36606
36606
  color.set(dep, GRAY);
36607
- path102.push(dep);
36607
+ path103.push(dep);
36608
36608
  stack.push([dep, 0]);
36609
36609
  }
36610
36610
  } else {
36611
36611
  color.set(id3, BLACK);
36612
- path102.pop();
36612
+ path103.pop();
36613
36613
  stack.pop();
36614
36614
  }
36615
36615
  }
@@ -37529,8 +37529,8 @@ var init_runner = __esm({
37529
37529
  failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
37530
37530
  pending: []
37531
37531
  };
37532
- const path102 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
37533
- this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path102}`);
37532
+ const path103 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
37533
+ this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path103}`);
37534
37534
  return snapshot;
37535
37535
  }
37536
37536
  callLog(msg, data) {
@@ -38826,7 +38826,7 @@ var CORE_VERSION;
38826
38826
  var init_version = __esm({
38827
38827
  "packages/core/dist/version.js"() {
38828
38828
  "use strict";
38829
- CORE_VERSION = "2.39.0";
38829
+ CORE_VERSION = "2.41.0";
38830
38830
  }
38831
38831
  });
38832
38832
 
@@ -41308,9 +41308,9 @@ function spillToolOutput(fullText, meta3) {
41308
41308
  const rnd = randomBytes3(3).toString("hex");
41309
41309
  const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
41310
41310
  const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
41311
- const path102 = join14(dir, file2);
41312
- writeFileSync12(path102, fullText, "utf8");
41313
- return path102;
41311
+ const path103 = join14(dir, file2);
41312
+ writeFileSync12(path103, fullText, "utf8");
41313
+ return path103;
41314
41314
  } catch {
41315
41315
  return null;
41316
41316
  }
@@ -41356,10 +41356,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
41356
41356
  ${tail2}`;
41357
41357
  }
41358
41358
  if (doSpill) {
41359
- const path102 = spillToolOutput(text, { toolName: opts.toolName });
41360
- if (path102) {
41359
+ const path103 = spillToolOutput(text, { toolName: opts.toolName });
41360
+ if (path103) {
41361
41361
  const spillNote = `
41362
- \u2026 [full output spilled to: ${path102} \u2014 re-read with read_file if you need the complete text] \u2026`;
41362
+ \u2026 [full output spilled to: ${path103} \u2014 re-read with read_file if you need the complete text] \u2026`;
41363
41363
  if (preview.includes("] \u2026\n")) {
41364
41364
  preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
41365
41365
  `);
@@ -42162,28 +42162,28 @@ var init_storage = __esm({
42162
42162
  VALID_SCALARS = /^(true|false|null|~)$/i;
42163
42163
  Storage = class {
42164
42164
  /** Read a Markdown file with frontmatter. Throws if not found. */
42165
- read(path102) {
42166
- if (!existsSync19(path102)) {
42167
- throw new Error(`File not found: ${path102}`);
42165
+ read(path103) {
42166
+ if (!existsSync19(path103)) {
42167
+ throw new Error(`File not found: ${path103}`);
42168
42168
  }
42169
- const md = readFileSync17(path102, "utf8");
42169
+ const md = readFileSync17(path103, "utf8");
42170
42170
  return parseFrontmatter(md);
42171
42171
  }
42172
42172
  /** Read a Markdown file; returns null if not found. */
42173
- readIfExists(path102) {
42174
- if (!existsSync19(path102)) return null;
42175
- return this.read(path102);
42173
+ readIfExists(path103) {
42174
+ if (!existsSync19(path103)) return null;
42175
+ return this.read(path103);
42176
42176
  }
42177
42177
  /**
42178
42178
  * Write a Markdown file atomically (tmp + rename). Creates parent dirs.
42179
42179
  * The meta object is serialized as YAML frontmatter; body as Markdown.
42180
42180
  */
42181
- write(path102, meta3, body) {
42182
- mkdirSync10(dirname2(path102), { recursive: true });
42183
- const tmp = path102 + ".tmp-" + process.pid;
42181
+ write(path103, meta3, body) {
42182
+ mkdirSync10(dirname2(path103), { recursive: true });
42183
+ const tmp = path103 + ".tmp-" + process.pid;
42184
42184
  const md = serializeFrontmatter(meta3, body);
42185
42185
  writeFileSync14(tmp, md, "utf8");
42186
- renameSync2(tmp, path102);
42186
+ renameSync2(tmp, path103);
42187
42187
  }
42188
42188
  /** List all .md files in a directory (non-recursive). */
42189
42189
  listMarkdown(dir) {
@@ -42294,8 +42294,8 @@ function nextPlanTaskId(store6) {
42294
42294
  return `t${store6.counter}`;
42295
42295
  }
42296
42296
  function writePlanTaskArtifact(rootDir, task) {
42297
- const path102 = join17(rootDir, "plan-tasks", `${task.id}.md`);
42298
- mkdirSync11(dirname3(path102), { recursive: true });
42297
+ const path103 = join17(rootDir, "plan-tasks", `${task.id}.md`);
42298
+ mkdirSync11(dirname3(path103), { recursive: true });
42299
42299
  const meta3 = {
42300
42300
  kind: "task",
42301
42301
  id: task.id,
@@ -42316,7 +42316,7 @@ function writePlanTaskArtifact(rootDir, task) {
42316
42316
  task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
42317
42317
  ""
42318
42318
  ].filter((l) => l !== null).join("\n");
42319
- new Storage().write(path102, meta3, body);
42319
+ new Storage().write(path103, meta3, body);
42320
42320
  }
42321
42321
  function loadHandle(rootDir) {
42322
42322
  const jsonPath = join17(rootDir, "plan.json");
@@ -43721,6 +43721,46 @@ function formatPromoteNotice(node) {
43721
43721
  const preview = node.content.replace(/\s+/g, " ").trim().slice(0, 120);
43722
43722
  return `[memory] candidato AGENTS.MD: ${node.kind} \u201C${preview}\u201D \u2014 /memory promote ${node.id}`;
43723
43723
  }
43724
+ function parsePromoteArgs(args = []) {
43725
+ const result = { asCheck: false };
43726
+ const tokens = [...args];
43727
+ for (let i = 0; i < tokens.length; i += 1) {
43728
+ const token = tokens[i] ?? "";
43729
+ const inline = token.startsWith("--") && token.includes("=") ? token.split("=") : null;
43730
+ const flag = inline ? inline[0] ?? "" : token;
43731
+ const inlineValue = inline ? inline.slice(1).join("=") : void 0;
43732
+ if (flag === "--as-check") {
43733
+ result.asCheck = true;
43734
+ continue;
43735
+ }
43736
+ if (COMMAND_FLAGS.has(flag) || EXIT_FLAGS.has(flag)) {
43737
+ const parts = [];
43738
+ if (inlineValue !== void 0 && inlineValue !== "") parts.push(inlineValue);
43739
+ else {
43740
+ while (i + 1 < tokens.length && !(tokens[i + 1] ?? "").startsWith("-")) {
43741
+ parts.push(tokens[i + 1] ?? "");
43742
+ i += 1;
43743
+ }
43744
+ }
43745
+ const value = parts.join(" ").replace(/^\s*["']|["']\s*$/g, "").trim();
43746
+ if (EXIT_FLAGS.has(flag)) {
43747
+ const exit = Number(value);
43748
+ if (!value || !Number.isInteger(exit)) {
43749
+ return { ...result, error: `expect-exit must be an integer, got \u201C${value}\u201D.` };
43750
+ }
43751
+ result.expectExit = exit;
43752
+ continue;
43753
+ }
43754
+ if (!value) return { ...result, error: "missing value for --command." };
43755
+ result.command = value;
43756
+ continue;
43757
+ }
43758
+ if (token.startsWith("-")) return { ...result, error: `unknown flag \u201C${token}\u201D.` };
43759
+ if (!result.id) result.id = token;
43760
+ else if (!result.command) return { ...result, error: `unexpected argument \u201C${token}\u201D.` };
43761
+ }
43762
+ return result;
43763
+ }
43724
43764
  function lineFor(node) {
43725
43765
  const content = node.content.replace(/\s+/g, " ").replace(/-->/g, "\u2014>").trim().slice(0, 2e3);
43726
43766
  const provenance = node.source.agent ? `; source=${node.source.agent}` : "";
@@ -43778,7 +43818,7 @@ ${END}
43778
43818
  }
43779
43819
  return { added: true, path: target };
43780
43820
  }
43781
- var START, END, DURABLE_KINDS, PROMOTE_MIN_IMPORTANCE, PROMOTE_MIN_CONFIDENCE;
43821
+ var START, END, DURABLE_KINDS, PROMOTE_MIN_IMPORTANCE, PROMOTE_MIN_CONFIDENCE, PROMOTE_USAGE, COMMAND_FLAGS, EXIT_FLAGS;
43782
43822
  var init_promotion = __esm({
43783
43823
  "src/cli/memory/promotion.ts"() {
43784
43824
  "use strict";
@@ -43787,6 +43827,9 @@ var init_promotion = __esm({
43787
43827
  DURABLE_KINDS = /* @__PURE__ */ new Set(["fact", "decision", "constraint", "preference", "procedure"]);
43788
43828
  PROMOTE_MIN_IMPORTANCE = 0.7;
43789
43829
  PROMOTE_MIN_CONFIDENCE = 0.8;
43830
+ PROMOTE_USAGE = 'Usage: /memory promote <id> [--as-check --command "<comando>" [--expect-exit N]]';
43831
+ COMMAND_FLAGS = /* @__PURE__ */ new Set(["--command", "-c"]);
43832
+ EXIT_FLAGS = /* @__PURE__ */ new Set(["--expect-exit", "-e", "--expectExit"]);
43790
43833
  }
43791
43834
  });
43792
43835
 
@@ -44133,6 +44176,48 @@ async function runBacktest(cwd, signal) {
44133
44176
  await appendTimeline(cwd, { kind: "backtest", ok: summary.ok, passed, failed, total: results.length });
44134
44177
  return summary;
44135
44178
  }
44179
+ async function readChecksStrict(cwd) {
44180
+ const p3 = path44.join(worldDir(cwd), CHECKS_FILE);
44181
+ let raw;
44182
+ try {
44183
+ raw = await fs19.readFile(p3, "utf8");
44184
+ } catch (error51) {
44185
+ if (error51.code === "ENOENT") return [];
44186
+ throw error51;
44187
+ }
44188
+ let parsed;
44189
+ try {
44190
+ parsed = JSON.parse(raw);
44191
+ } catch {
44192
+ throw new Error(`${p3} is not valid JSON \u2014 refusing to overwrite it.`);
44193
+ }
44194
+ if (!parsed || !Array.isArray(parsed.checks)) {
44195
+ throw new Error(`${p3} has no "checks" array \u2014 refusing to overwrite it.`);
44196
+ }
44197
+ return parsed.checks;
44198
+ }
44199
+ async function appendWorldCheck(cwd, check2) {
44200
+ const dir = await ensureWorldDir(cwd);
44201
+ const file2 = path44.join(dir, CHECKS_FILE);
44202
+ const checks = await readChecksStrict(cwd);
44203
+ if (checks.some((entry) => entry?.id === check2.id)) {
44204
+ return { added: false, count: checks.length, path: file2, reason: "duplicate" };
44205
+ }
44206
+ const next = { checks: [...checks, check2] };
44207
+ const temporary = `${file2}.tmp-${process.pid}-${Date.now()}`;
44208
+ await fs19.writeFile(temporary, JSON.stringify(next, null, 2) + "\n", {
44209
+ encoding: "utf8",
44210
+ flag: "wx"
44211
+ });
44212
+ try {
44213
+ await fs19.rename(temporary, file2);
44214
+ } catch (error51) {
44215
+ await fs19.unlink(temporary).catch(() => void 0);
44216
+ throw error51;
44217
+ }
44218
+ await appendTimeline(cwd, { kind: "world_check_appended", id: check2.id, count: next.checks.length });
44219
+ return { added: true, count: next.checks.length, path: file2 };
44220
+ }
44136
44221
  function createWorldModelTools() {
44137
44222
  if (process.env["ZELARI_SCHEMA_LOOP"] === "0") return [];
44138
44223
  return [
@@ -53356,21 +53441,21 @@ function normalizeAuth(auth) {
53356
53441
  return "agent";
53357
53442
  }
53358
53443
  function readSecrets() {
53359
- const path102 = getSshSecretsPath();
53360
- if (!existsSync30(path102)) return {};
53444
+ const path103 = getSshSecretsPath();
53445
+ if (!existsSync30(path103)) return {};
53361
53446
  try {
53362
- return JSON.parse(readFileSync22(path102, "utf8"));
53447
+ return JSON.parse(readFileSync22(path103, "utf8"));
53363
53448
  } catch {
53364
53449
  return {};
53365
53450
  }
53366
53451
  }
53367
53452
  function writeSecrets(data) {
53368
- const path102 = getSshSecretsPath();
53369
- mkdirSync13(dirname4(path102), { recursive: true });
53370
- writeFileSync16(path102, `${JSON.stringify(data, null, 2)}
53453
+ const path103 = getSshSecretsPath();
53454
+ mkdirSync13(dirname4(path103), { recursive: true });
53455
+ writeFileSync16(path103, `${JSON.stringify(data, null, 2)}
53371
53456
  `, "utf8");
53372
53457
  try {
53373
- chmodSync(path102, 384);
53458
+ chmodSync(path103, 384);
53374
53459
  } catch {
53375
53460
  }
53376
53461
  }
@@ -53399,10 +53484,10 @@ function deleteSshPassword(id3) {
53399
53484
  writeSecrets({ passwords });
53400
53485
  }
53401
53486
  function readStore2() {
53402
- const path102 = getSshTargetsPath();
53403
- if (!existsSync30(path102)) return [];
53487
+ const path103 = getSshTargetsPath();
53488
+ if (!existsSync30(path103)) return [];
53404
53489
  try {
53405
- const parsed = JSON.parse(readFileSync22(path102, "utf8"));
53490
+ const parsed = JSON.parse(readFileSync22(path103, "utf8"));
53406
53491
  const list = Array.isArray(parsed.targets) ? parsed.targets : [];
53407
53492
  return list.filter(
53408
53493
  (t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
@@ -53417,11 +53502,11 @@ function readStore2() {
53417
53502
  }
53418
53503
  }
53419
53504
  function writeStore2(targets) {
53420
- const path102 = getSshTargetsPath();
53421
- mkdirSync13(dirname4(path102), { recursive: true });
53505
+ const path103 = getSshTargetsPath();
53506
+ mkdirSync13(dirname4(path103), { recursive: true });
53422
53507
  const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
53423
53508
  writeFileSync16(
53424
- path102,
53509
+ path103,
53425
53510
  `${JSON.stringify({ targets: clean }, null, 2)}
53426
53511
  `,
53427
53512
  "utf8"
@@ -53667,11 +53752,11 @@ function formatSshTargetsForPrompt() {
53667
53752
  ];
53668
53753
  for (const t of targets) {
53669
53754
  const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
53670
- const path102 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
53755
+ const path103 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
53671
53756
  const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
53672
53757
  const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
53673
53758
  lines.push(
53674
- `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path102}${tags}${allow}`
53759
+ `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path103}${tags}${allow}`
53675
53760
  );
53676
53761
  }
53677
53762
  return lines.join("\n");
@@ -57697,6 +57782,162 @@ var init_completionProof = __esm({
57697
57782
  }
57698
57783
  });
57699
57784
 
57785
+ // src/cli/memory/howWeTest.ts
57786
+ import { promises as fs28 } from "node:fs";
57787
+ import * as path67 from "node:path";
57788
+ function metaString(node, key) {
57789
+ const value = node.metadata?.[key];
57790
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
57791
+ }
57792
+ function metaNumber(node, key) {
57793
+ const value = node.metadata?.[key];
57794
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
57795
+ }
57796
+ function rowFromNode(node) {
57797
+ if (node.kind !== "procedure" || node.status !== "active") return null;
57798
+ if (node.metadata?.verified !== true) return null;
57799
+ const key = metaString(node, "opsKnowledgeKey");
57800
+ const command = metaString(node, "command");
57801
+ const digest = metaString(node, "digest");
57802
+ if (!key || !command || !digest) return null;
57803
+ const seq = metaNumber(node, "seq");
57804
+ return {
57805
+ key,
57806
+ criterionId: metaString(node, "criterionId") ?? "unknown",
57807
+ command,
57808
+ digest,
57809
+ ...seq === void 0 ? {} : { seq }
57810
+ };
57811
+ }
57812
+ function collectHowWeTestRows(nodes) {
57813
+ const rows = nodes.map(rowFromNode).filter((row) => row !== null);
57814
+ rows.sort((a, b) => a.key.localeCompare(b.key) || (a.seq ?? -1) - (b.seq ?? -1));
57815
+ const byKey = /* @__PURE__ */ new Map();
57816
+ for (const row of rows) byKey.set(row.key, row);
57817
+ return [...byKey.values()].sort(
57818
+ (a, b) => a.criterionId.localeCompare(b.criterionId) || a.command.localeCompare(b.command)
57819
+ );
57820
+ }
57821
+ function shortDigest(digest) {
57822
+ return digest.length <= 8 ? digest : digest.slice(0, 8);
57823
+ }
57824
+ function escapeCell(value) {
57825
+ return value.replace(/\r?\n/g, " ").replace(/`/g, "'").trim();
57826
+ }
57827
+ function projectHowWeTest(rows) {
57828
+ const lines = [
57829
+ "# How we test",
57830
+ "",
57831
+ HOW_WE_TEST_HEADER,
57832
+ "",
57833
+ "Procedure verificate (deterministiche, evidence-backed): quello che una run",
57834
+ "ha dimostrato resta qui per gli agenti e per gli umani che vengono dopo.",
57835
+ "Generato da zelari \u2014 rigenera con `/memory how-we-test`.",
57836
+ ""
57837
+ ];
57838
+ if (rows.length === 0) {
57839
+ lines.push("_Nessuna procedura verificata ancora: niente da proiettare._", "");
57840
+ return lines.join("\n");
57841
+ }
57842
+ let current = null;
57843
+ for (const row of rows) {
57844
+ if (row.criterionId !== current) {
57845
+ current = row.criterionId;
57846
+ lines.push(`## ${current}`, "");
57847
+ }
57848
+ const seq = row.seq === void 0 ? "\u2014" : `seq ${row.seq}`;
57849
+ lines.push(`- \`${escapeCell(row.command)}\` \u2014 exit 0 \u2014 digest \`${shortDigest(row.digest)}\` \u2014 ultima osservazione ${seq}`);
57850
+ }
57851
+ lines.push("");
57852
+ return lines.join("\n");
57853
+ }
57854
+ function isMissing(error51) {
57855
+ return error51?.code === "ENOENT";
57856
+ }
57857
+ async function writeHowWeTest(projectRoot, rows) {
57858
+ const target = path67.join(projectRoot, HOW_WE_TEST_RELATIVE);
57859
+ try {
57860
+ if ((await fs28.lstat(target)).isSymbolicLink()) {
57861
+ return { written: false, path: target, rows: rows.length, reason: "target is a symbolic link" };
57862
+ }
57863
+ } catch (error51) {
57864
+ if (!isMissing(error51)) {
57865
+ return {
57866
+ written: false,
57867
+ path: target,
57868
+ rows: rows.length,
57869
+ reason: error51 instanceof Error ? error51.message : String(error51)
57870
+ };
57871
+ }
57872
+ }
57873
+ await fs28.mkdir(path67.dirname(target), { recursive: true });
57874
+ const temporary = `${target}.tmp-${process.pid}-${Date.now()}`;
57875
+ await fs28.writeFile(temporary, projectHowWeTest(rows), { encoding: "utf8", flag: "wx" });
57876
+ try {
57877
+ await fs28.rename(temporary, target);
57878
+ } catch (error51) {
57879
+ await fs28.unlink(temporary).catch(() => void 0);
57880
+ throw error51;
57881
+ }
57882
+ return { written: true, path: target, rows: rows.length };
57883
+ }
57884
+ function nodesFromDump(dump) {
57885
+ if (Array.isArray(dump)) return dump;
57886
+ const nodes = dump?.nodes;
57887
+ return Array.isArray(nodes) ? nodes : [];
57888
+ }
57889
+ async function listNodes(source2) {
57890
+ if (typeof source2.export !== "function") return null;
57891
+ try {
57892
+ return nodesFromDump(await source2.export());
57893
+ } catch {
57894
+ return null;
57895
+ }
57896
+ }
57897
+ async function listVerifiedProcedureNodes(source2) {
57898
+ const nodes = await listNodes(source2);
57899
+ if (!nodes) return null;
57900
+ return nodes.filter((node) => node.kind === "procedure" && node.metadata?.verified === true);
57901
+ }
57902
+ async function regenerateHowWeTest(source2, projectRoot) {
57903
+ const nodes = await listVerifiedProcedureNodes(source2);
57904
+ if (!nodes) {
57905
+ return {
57906
+ written: false,
57907
+ path: path67.join(projectRoot, HOW_WE_TEST_RELATIVE),
57908
+ rows: 0,
57909
+ reason: "memory backend cannot enumerate procedures"
57910
+ };
57911
+ }
57912
+ try {
57913
+ return await writeHowWeTest(projectRoot, collectHowWeTestRows(nodes));
57914
+ } catch (error51) {
57915
+ return {
57916
+ written: false,
57917
+ path: path67.join(projectRoot, HOW_WE_TEST_RELATIVE),
57918
+ rows: 0,
57919
+ reason: error51 instanceof Error ? error51.message : String(error51)
57920
+ };
57921
+ }
57922
+ }
57923
+ async function regenerateHowWeTestSafe(source2, projectRoot) {
57924
+ const nodes = await listVerifiedProcedureNodes(source2);
57925
+ if (!nodes) return null;
57926
+ try {
57927
+ return await writeHowWeTest(projectRoot, collectHowWeTestRows(nodes));
57928
+ } catch {
57929
+ return null;
57930
+ }
57931
+ }
57932
+ var HOW_WE_TEST_RELATIVE, HOW_WE_TEST_HEADER;
57933
+ var init_howWeTest = __esm({
57934
+ "src/cli/memory/howWeTest.ts"() {
57935
+ "use strict";
57936
+ HOW_WE_TEST_RELATIVE = path67.join(".zelari", "how-we-test.md");
57937
+ HOW_WE_TEST_HEADER = "<!-- generato \u2014 non editare (rigenera con /memory how-we-test) -->";
57938
+ }
57939
+ });
57940
+
57700
57941
  // src/cli/memory/repeatFailure.ts
57701
57942
  import { createHash as createHash18 } from "node:crypto";
57702
57943
  function failureFingerprint(command, exitCode, digest) {
@@ -57731,10 +57972,102 @@ var init_repeatFailure = __esm({
57731
57972
  }
57732
57973
  });
57733
57974
 
57975
+ // src/cli/memory/repeatCheck.ts
57976
+ function metaString2(node, key) {
57977
+ const value = node.metadata?.[key];
57978
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
57979
+ }
57980
+ function metaNumber2(node, key) {
57981
+ const value = node.metadata?.[key];
57982
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
57983
+ }
57984
+ function checkIdForFingerprint(fingerprint) {
57985
+ return `con-${fingerprint}`;
57986
+ }
57987
+ function constraintFromNode(node) {
57988
+ if (!node) return null;
57989
+ const fingerprint = metaString2(node, "fingerprint");
57990
+ const command = metaString2(node, "command");
57991
+ const digest = metaString2(node, "digest");
57992
+ if (!fingerprint || !command || !digest) return null;
57993
+ const criterionId2 = metaString2(node, "criterionId");
57994
+ return {
57995
+ fingerprint,
57996
+ command,
57997
+ digest,
57998
+ exitCode: metaNumber2(node, "exitCode") ?? guessExitCode(command),
57999
+ ...criterionId2 ? { criterionId: criterionId2 } : {}
58000
+ };
58001
+ }
58002
+ function sameCommand(a, b) {
58003
+ return failureCommandLabel(a).toLowerCase() === failureCommandLabel(b).toLowerCase();
58004
+ }
58005
+ function pickFixProcedure(constraint, procedures = []) {
58006
+ return procedures.find((node) => {
58007
+ if (node.kind !== "procedure" || node.status !== "active") return false;
58008
+ if (node.metadata?.verified !== true) return false;
58009
+ const digest = metaString2(node, "digest");
58010
+ const command = metaString2(node, "command");
58011
+ if (!digest || digest !== constraint.digest || !command) return false;
58012
+ return !sameCommand(command, constraint.command);
58013
+ });
58014
+ }
58015
+ function commandFromProcedure(procedure) {
58016
+ return metaString2(procedure, "command") ?? PLACEHOLDER_COMMAND;
58017
+ }
58018
+ function proposalFromConstraint(constraint, procedures = []) {
58019
+ const fix = pickFixProcedure(constraint, procedures);
58020
+ const command = fix ? commandFromProcedure(fix) : PLACEHOLDER_COMMAND;
58021
+ return {
58022
+ fp: constraint.fingerprint,
58023
+ command: constraint.command,
58024
+ exit: constraint.exitCode,
58025
+ digest: constraint.digest,
58026
+ checkId: checkIdForFingerprint(constraint.fingerprint),
58027
+ derivedFromProcedure: fix !== void 0,
58028
+ suggestedCheck: {
58029
+ id: checkIdForFingerprint(constraint.fingerprint),
58030
+ command,
58031
+ expectExit: 0
58032
+ }
58033
+ };
58034
+ }
58035
+ function confirmCheck(proposal, confirmed = {}) {
58036
+ const command = (confirmed.command ?? "").replace(/^\s*["']|["']\s*$/g, "").trim();
58037
+ if (!command || command === PLACEHOLDER_COMMAND) return null;
58038
+ const expectExit = typeof confirmed.expectExit === "number" && Number.isInteger(confirmed.expectExit) ? confirmed.expectExit : proposal.suggestedCheck.expectExit ?? 0;
58039
+ return { id: proposal.checkId, command, expectExit };
58040
+ }
58041
+ function formatCheckProposalNotice(proposal) {
58042
+ const preview = failureCommandLabel(proposal.command).replace(/\s+/g, " ").slice(0, 120);
58043
+ const suffix = proposal.derivedFromProcedure ? `--as-check --command "${proposal.suggestedCheck.command}"` : '--as-check --command "<comando>"';
58044
+ return `[memory] candidato WorldCheck: \u201C${preview}\u201D (exit ${proposal.exit}) \u2014 /memory promote ${proposal.checkId} ${suffix}`;
58045
+ }
58046
+ function checkConfirmationHint(proposal) {
58047
+ return proposal.derivedFromProcedure ? `[memory] proposta di check (applicazione sempre manuale):
58048
+ id: ${proposal.checkId}
58049
+ comando suggerito (da procedura verificata): ${proposal.suggestedCheck.command}
58050
+ exit atteso: ${proposal.suggestedCheck.expectExit}
58051
+ conferma con: /memory promote ${proposal.checkId} --as-check --command "${proposal.suggestedCheck.command}"` : `[memory] proposta di check (applicazione sempre manuale):
58052
+ id: ${proposal.checkId}
58053
+ comando fallito (NON ri-eseguito automaticamente): ${failureCommandLabel(proposal.command)}
58054
+ digest: ${proposal.digest} \xB7 exit ${proposal.exit}
58055
+ nessuna procedura verificata per lo stesso digest: scrivi il comando di regressione,
58056
+ conferma con: /memory promote ${proposal.checkId} --as-check --command "<comando>"`;
58057
+ }
58058
+ var PLACEHOLDER_COMMAND;
58059
+ var init_repeatCheck = __esm({
58060
+ "src/cli/memory/repeatCheck.ts"() {
58061
+ "use strict";
58062
+ init_repeatFailure();
58063
+ PLACEHOLDER_COMMAND = "<confirm-command>";
58064
+ }
58065
+ });
58066
+
57734
58067
  // src/cli/memory/legacyImport.ts
57735
58068
  import { createHash as createHash19 } from "node:crypto";
57736
- import { promises as fs28 } from "node:fs";
57737
- import * as path67 from "node:path";
58069
+ import { promises as fs29 } from "node:fs";
58070
+ import * as path68 from "node:path";
57738
58071
  function sourceId(fact, line) {
57739
58072
  return `jsonl:${fact.id ?? createHash19("sha256").update(line).digest("hex")}`;
57740
58073
  }
@@ -57755,7 +58088,7 @@ function isPermanentSkip(error51) {
57755
58088
  }
57756
58089
  async function isImportComplete(markerPath) {
57757
58090
  try {
57758
- const marker = JSON.parse(await fs28.readFile(markerPath, "utf8"));
58091
+ const marker = JSON.parse(await fs29.readFile(markerPath, "utf8"));
57759
58092
  return typeof marker?.found === "number" && typeof marker?.at === "string";
57760
58093
  } catch {
57761
58094
  return false;
@@ -57764,20 +58097,20 @@ async function isImportComplete(markerPath) {
57764
58097
  async function markImportComplete(markerPath, found) {
57765
58098
  const temporary = `${markerPath}.tmp`;
57766
58099
  try {
57767
- await fs28.writeFile(temporary, `${JSON.stringify({ found, at: (/* @__PURE__ */ new Date()).toISOString() })}
58100
+ await fs29.writeFile(temporary, `${JSON.stringify({ found, at: (/* @__PURE__ */ new Date()).toISOString() })}
57768
58101
  `, "utf8");
57769
- await fs28.rename(temporary, markerPath);
58102
+ await fs29.rename(temporary, markerPath);
57770
58103
  } catch {
57771
58104
  }
57772
58105
  }
57773
58106
  async function importLegacyMemoryLog(backend, service) {
57774
58107
  const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
57775
- const memoryDir = path67.dirname(backend.databasePath);
57776
- const markerPath = path67.join(memoryDir, LEGACY_IMPORT_MARKER);
58108
+ const memoryDir = path68.dirname(backend.databasePath);
58109
+ const markerPath = path68.join(memoryDir, LEGACY_IMPORT_MARKER);
57777
58110
  if (await isImportComplete(markerPath)) return result;
57778
58111
  let raw;
57779
58112
  try {
57780
- raw = await fs28.readFile(path67.join(memoryDir, "log.jsonl"), "utf8");
58113
+ raw = await fs29.readFile(path68.join(memoryDir, "log.jsonl"), "utf8");
57781
58114
  } catch {
57782
58115
  return result;
57783
58116
  }
@@ -57969,7 +58302,7 @@ var init_sqliteCodec = __esm({
57969
58302
  // src/cli/memory/sqliteRpc.ts
57970
58303
  import { existsSync as existsSync34 } from "node:fs";
57971
58304
  import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
57972
- import * as path68 from "node:path";
58305
+ import * as path69 from "node:path";
57973
58306
  import { Worker } from "node:worker_threads";
57974
58307
  function isBusy(error51) {
57975
58308
  const candidate = error51;
@@ -57978,10 +58311,10 @@ function isBusy(error51) {
57978
58311
  );
57979
58312
  }
57980
58313
  function resolveWorkerUrl() {
57981
- const here = path68.dirname(fileURLToPath2(import.meta.url));
57982
- const direct = path68.join(here, "sqliteWorker.mjs");
58314
+ const here = path69.dirname(fileURLToPath2(import.meta.url));
58315
+ const direct = path69.join(here, "sqliteWorker.mjs");
57983
58316
  if (existsSync34(direct)) return pathToFileURL2(direct);
57984
- return pathToFileURL2(path68.join(here, "memory", "sqliteWorker.mjs"));
58317
+ return pathToFileURL2(path69.join(here, "memory", "sqliteWorker.mjs"));
57985
58318
  }
57986
58319
  var SqliteWorkerRpc;
57987
58320
  var init_sqliteRpc = __esm({
@@ -58269,8 +58602,8 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
58269
58602
 
58270
58603
  // src/cli/memory/sqliteBackend.ts
58271
58604
  import { createHash as createHash20, randomUUID as randomUUID5 } from "node:crypto";
58272
- import { promises as fs29 } from "node:fs";
58273
- import * as path69 from "node:path";
58605
+ import { promises as fs30 } from "node:fs";
58606
+ import * as path70 from "node:path";
58274
58607
  function boundedLimit(value, fallback = 50) {
58275
58608
  return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
58276
58609
  }
@@ -58331,42 +58664,42 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
58331
58664
  async init(projectRoot) {
58332
58665
  let resolved;
58333
58666
  try {
58334
- resolved = await fs29.realpath(projectRoot);
58667
+ resolved = await fs30.realpath(projectRoot);
58335
58668
  } catch {
58336
- resolved = path69.resolve(projectRoot);
58669
+ resolved = path70.resolve(projectRoot);
58337
58670
  }
58338
58671
  if (this.initialized && resolved === this.projectRoot) return;
58339
58672
  if (this.initialized) await this.close();
58340
58673
  const filename = this.options.filename ?? "memory.db";
58341
- if (path69.basename(filename) !== filename || filename === "." || filename === "..") {
58674
+ if (path70.basename(filename) !== filename || filename === "." || filename === "..") {
58342
58675
  throw new Error("SQLite memory filename must not contain a path.");
58343
58676
  }
58344
- const zelariDirectory = path69.join(resolved, ".zelari");
58345
- const directory = path69.join(zelariDirectory, "memory");
58677
+ const zelariDirectory = path70.join(resolved, ".zelari");
58678
+ const directory = path70.join(zelariDirectory, "memory");
58346
58679
  for (const candidate of [zelariDirectory, directory]) {
58347
58680
  let stat8;
58348
58681
  try {
58349
- stat8 = await fs29.lstat(candidate);
58682
+ stat8 = await fs30.lstat(candidate);
58350
58683
  } catch (error51) {
58351
58684
  if (error51.code !== "ENOENT") throw error51;
58352
58685
  try {
58353
- await fs29.mkdir(candidate);
58686
+ await fs30.mkdir(candidate);
58354
58687
  } catch (mkdirError) {
58355
58688
  if (mkdirError.code !== "EEXIST") throw mkdirError;
58356
58689
  }
58357
- stat8 = await fs29.lstat(candidate);
58690
+ stat8 = await fs30.lstat(candidate);
58358
58691
  }
58359
58692
  if (stat8.isSymbolicLink() || !stat8.isDirectory()) {
58360
58693
  throw new Error(`Memory directory is not a real directory: ${candidate}`);
58361
58694
  }
58362
58695
  }
58363
- const canonicalDirectory = await fs29.realpath(directory);
58364
- const relativeDirectory = path69.relative(resolved, canonicalDirectory);
58365
- if (relativeDirectory.startsWith("..") || path69.isAbsolute(relativeDirectory)) {
58696
+ const canonicalDirectory = await fs30.realpath(directory);
58697
+ const relativeDirectory = path70.relative(resolved, canonicalDirectory);
58698
+ if (relativeDirectory.startsWith("..") || path70.isAbsolute(relativeDirectory)) {
58366
58699
  throw new Error("SQLite memory directory resolves outside the active project.");
58367
58700
  }
58368
58701
  this.projectRoot = resolved;
58369
- this.databasePath = path69.join(canonicalDirectory, filename);
58702
+ this.databasePath = path70.join(canonicalDirectory, filename);
58370
58703
  const opened = await this.rpc.open({
58371
58704
  dbPath: this.databasePath,
58372
58705
  schemaSql: SQLITE_MEMORY_BASE_SCHEMA,
@@ -58908,8 +59241,8 @@ __export(serviceFactory_exports, {
58908
59241
  isMemoryV2Enabled: () => isMemoryV2Enabled
58909
59242
  });
58910
59243
  import { createHash as createHash21 } from "node:crypto";
58911
- import { promises as fs30 } from "node:fs";
58912
- import * as path70 from "node:path";
59244
+ import { promises as fs31 } from "node:fs";
59245
+ import * as path71 from "node:path";
58913
59246
  function isMemoryV2Enabled(env = process.env) {
58914
59247
  if (env.ZELARI_MEMORY === "0") return false;
58915
59248
  if (env.ZELARI_MEMORY_BACKEND === "file" || env.ZELARI_MEMORY_BACKEND === "jsonl") return false;
@@ -58928,9 +59261,9 @@ function semanticMinScore(env) {
58928
59261
  async function canonicalProjectId(projectRoot) {
58929
59262
  let canonical;
58930
59263
  try {
58931
- canonical = await fs30.realpath(projectRoot);
59264
+ canonical = await fs31.realpath(projectRoot);
58932
59265
  } catch {
58933
- canonical = path70.resolve(projectRoot);
59266
+ canonical = path71.resolve(projectRoot);
58934
59267
  }
58935
59268
  canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
58936
59269
  if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
@@ -59167,6 +59500,8 @@ async function promoteOpsKnowledge(gate, deps) {
59167
59500
  let skippedDuplicate = 0;
59168
59501
  let constraintsCreated = 0;
59169
59502
  const proposals = [];
59503
+ const checkProposals = [];
59504
+ const procedureNodes = fails.length > 0 ? await listVerifiedProcedureNodes(memory) ?? [] : [];
59170
59505
  for (const candidate of pass) {
59171
59506
  const outcome = await rememberProcedure(memory, candidate, { sessionId: deps.sessionId });
59172
59507
  if (outcome === "created") {
@@ -59186,11 +59521,14 @@ async function promoteOpsKnowledge(gate, deps) {
59186
59521
  constraintsCreated += 1;
59187
59522
  const node = await memory.get(outcome.constraintId);
59188
59523
  if (node && meetsPromoteThreshold(node)) proposals.push(formatPromoteNotice(node));
59524
+ const constraint = constraintFromNode(node);
59525
+ if (constraint) checkProposals.push(proposalFromConstraint(constraint, procedureNodes));
59189
59526
  } else if (outcome.constraint === "duplicate") {
59190
59527
  skippedDuplicate += 1;
59191
59528
  }
59192
59529
  }
59193
- return { enabled: true, created, skippedDuplicate, constraintsCreated, proposals };
59530
+ if (created > 0) await regenerateHowWeTestSafe(memory, deps.projectRoot);
59531
+ return { enabled: true, created, skippedDuplicate, constraintsCreated, proposals, checkProposals };
59194
59532
  }
59195
59533
  async function promoteOpsKnowledgeSafe(gate, deps) {
59196
59534
  try {
@@ -59206,7 +59544,8 @@ function emptyResult(enabled, skippedReason) {
59206
59544
  created: 0,
59207
59545
  skippedDuplicate: 0,
59208
59546
  constraintsCreated: 0,
59209
- proposals: []
59547
+ proposals: [],
59548
+ checkProposals: []
59210
59549
  };
59211
59550
  }
59212
59551
  async function openMemory(projectRoot, env) {
@@ -59222,7 +59561,9 @@ var ALLOWED_TIERS;
59222
59561
  var init_opsKnowledge = __esm({
59223
59562
  "src/cli/memory/opsKnowledge.ts"() {
59224
59563
  "use strict";
59564
+ init_howWeTest();
59225
59565
  init_promotion();
59566
+ init_repeatCheck();
59226
59567
  init_repeatFailure();
59227
59568
  init_repeatFailure();
59228
59569
  ALLOWED_TIERS = /* @__PURE__ */ new Set(["command-output", "fs-observation"]);
@@ -59312,20 +59653,20 @@ var init_askUserTimeout = __esm({
59312
59653
 
59313
59654
  // src/cli/state/fileStateStore.ts
59314
59655
  import { createHash as createHash23, randomUUID as randomUUID6 } from "node:crypto";
59315
- import { promises as fs31 } from "node:fs";
59316
- import * as path71 from "node:path";
59656
+ import { promises as fs32 } from "node:fs";
59657
+ import * as path72 from "node:path";
59317
59658
  function shortId() {
59318
59659
  return randomUUID6().replace(/-/g, "").slice(0, 12);
59319
59660
  }
59320
59661
  async function writeJsonAtomic(filePath, data) {
59321
- await fs31.mkdir(path71.dirname(filePath), { recursive: true });
59662
+ await fs32.mkdir(path72.dirname(filePath), { recursive: true });
59322
59663
  const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
59323
- await fs31.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
59324
- await fs31.rename(tmp, filePath);
59664
+ await fs32.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
59665
+ await fs32.rename(tmp, filePath);
59325
59666
  }
59326
59667
  async function readJsonFile(filePath) {
59327
59668
  try {
59328
- const raw = await fs31.readFile(filePath, "utf8");
59669
+ const raw = await fs32.readFile(filePath, "utf8");
59329
59670
  return JSON.parse(raw);
59330
59671
  } catch {
59331
59672
  return null;
@@ -59379,13 +59720,13 @@ var init_fileStateStore = __esm({
59379
59720
  indexPath = "";
59380
59721
  async init(projectRoot) {
59381
59722
  this.root = projectRoot;
59382
- this.stateDir = path71.join(projectRoot, ".zelari", "state");
59383
- this.commitsDir = path71.join(this.stateDir, "commits");
59384
- this.artifactsDir = path71.join(this.stateDir, "artifacts");
59385
- this.headPath = path71.join(this.stateDir, "HEAD.json");
59386
- this.indexPath = path71.join(this.stateDir, "index.jsonl");
59387
- await fs31.mkdir(this.commitsDir, { recursive: true });
59388
- await fs31.mkdir(this.artifactsDir, { recursive: true });
59723
+ this.stateDir = path72.join(projectRoot, ".zelari", "state");
59724
+ this.commitsDir = path72.join(this.stateDir, "commits");
59725
+ this.artifactsDir = path72.join(this.stateDir, "artifacts");
59726
+ this.headPath = path72.join(this.stateDir, "HEAD.json");
59727
+ this.indexPath = path72.join(this.stateDir, "index.jsonl");
59728
+ await fs32.mkdir(this.commitsDir, { recursive: true });
59729
+ await fs32.mkdir(this.artifactsDir, { recursive: true });
59389
59730
  }
59390
59731
  async commit(input) {
59391
59732
  if (!input.force && input.verification.ran && !input.verification.ok) {
@@ -59396,13 +59737,13 @@ var init_fileStateStore = __esm({
59396
59737
  const discoveries = input.discoveries ?? [];
59397
59738
  const parent = await this.head();
59398
59739
  const id3 = shortId();
59399
- const artifactRel = path71.join("artifacts", id3);
59400
- const artifactAbs = path71.join(this.artifactsDir, id3);
59401
- await fs31.mkdir(artifactAbs, { recursive: true });
59740
+ const artifactRel = path72.join("artifacts", id3);
59741
+ const artifactAbs = path72.join(this.artifactsDir, id3);
59742
+ await fs32.mkdir(artifactAbs, { recursive: true });
59402
59743
  const summary = defaultSummary(input, discoveries);
59403
- await fs31.writeFile(path71.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
59404
- await writeJsonAtomic(path71.join(artifactAbs, "discoveries.json"), discoveries);
59405
- await writeJsonAtomic(path71.join(artifactAbs, "verification.json"), input.verification);
59744
+ await fs32.writeFile(path72.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
59745
+ await writeJsonAtomic(path72.join(artifactAbs, "discoveries.json"), discoveries);
59746
+ await writeJsonAtomic(path72.join(artifactAbs, "verification.json"), input.verification);
59406
59747
  const meta3 = {
59407
59748
  id: id3,
59408
59749
  parentId: parent?.id ?? null,
@@ -59414,16 +59755,16 @@ var init_fileStateStore = __esm({
59414
59755
  workspaceCheckpointId: input.workspaceCheckpointId,
59415
59756
  verification: {
59416
59757
  ...input.verification,
59417
- reportPath: input.verification.reportPath ?? path71.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
59758
+ reportPath: input.verification.reportPath ?? path72.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
59418
59759
  },
59419
59760
  changedPaths: input.changedPaths ?? [],
59420
59761
  stablePromptHash: input.stablePromptHash,
59421
59762
  discoveryCount: discoveries.length,
59422
59763
  artifactDir: artifactRel.replace(/\\/g, "/")
59423
59764
  };
59424
- await writeJsonAtomic(path71.join(this.commitsDir, `${id3}.json`), meta3);
59765
+ await writeJsonAtomic(path72.join(this.commitsDir, `${id3}.json`), meta3);
59425
59766
  await writeJsonAtomic(this.headPath, { id: id3, updatedAt: meta3.createdAt });
59426
- await fs31.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
59767
+ await fs32.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
59427
59768
  return stripStored(meta3);
59428
59769
  }
59429
59770
  async head() {
@@ -59432,13 +59773,13 @@ var init_fileStateStore = __esm({
59432
59773
  return this.get(head.id);
59433
59774
  }
59434
59775
  async get(id3) {
59435
- const stored = await readJsonFile(path71.join(this.commitsDir, `${id3}.json`));
59776
+ const stored = await readJsonFile(path72.join(this.commitsDir, `${id3}.json`));
59436
59777
  return stored ? stripStored(stored) : null;
59437
59778
  }
59438
59779
  async list(limit = 20) {
59439
59780
  let raw;
59440
59781
  try {
59441
- raw = await fs31.readFile(this.indexPath, "utf8");
59782
+ raw = await fs32.readFile(this.indexPath, "utf8");
59442
59783
  } catch {
59443
59784
  return [];
59444
59785
  }
@@ -59471,9 +59812,9 @@ var init_fileStateStore = __esm({
59471
59812
  async loadDiscoveries(id3) {
59472
59813
  const meta3 = id3 ? await this.get(id3) : await this.head();
59473
59814
  if (!meta3) return [];
59474
- const stored = await readJsonFile(path71.join(this.commitsDir, `${meta3.id}.json`));
59815
+ const stored = await readJsonFile(path72.join(this.commitsDir, `${meta3.id}.json`));
59475
59816
  if (!stored?.artifactDir) return [];
59476
- const discPath = path71.join(this.stateDir, stored.artifactDir, "discoveries.json");
59817
+ const discPath = path72.join(this.stateDir, stored.artifactDir, "discoveries.json");
59477
59818
  return await readJsonFile(discPath) ?? [];
59478
59819
  }
59479
59820
  async materializeContext(id3, maxChars = DEFAULT_MATERIALIZE_CHARS) {
@@ -59684,7 +60025,7 @@ __export(conversationContext_exports, {
59684
60025
  setLastClarification: () => setLastClarification
59685
60026
  });
59686
60027
  import { existsSync as existsSync35 } from "node:fs";
59687
- import { join as join26 } from "node:path";
60028
+ import { join as join27 } from "node:path";
59688
60029
  function getHistory() {
59689
60030
  return history;
59690
60031
  }
@@ -59693,7 +60034,7 @@ function setHistory(messages) {
59693
60034
  history = projected === messages ? [...messages] : projected;
59694
60035
  }
59695
60036
  function compactInPlace(cwd = process.cwd()) {
59696
- const durableStatePresent = existsSync35(join26(cwd, ".zelari", "state", "HEAD.json"));
60037
+ const durableStatePresent = existsSync35(join27(cwd, ".zelari", "state", "HEAD.json"));
59697
60038
  history = applySessionSurface(compactHistory(history, { durableStatePresent }));
59698
60039
  }
59699
60040
  function appendMessages(msgs) {
@@ -60076,10 +60417,10 @@ var init_mode = __esm({
60076
60417
 
60077
60418
  // src/cli/headless.ts
60078
60419
  import { readFileSync as readFileSync24 } from "node:fs";
60079
- import path72 from "node:path";
60420
+ import path73 from "node:path";
60080
60421
  function resolveHeadlessCwd(opts) {
60081
60422
  const raw = typeof opts.cwd === "string" ? opts.cwd.trim() : "";
60082
- return path72.resolve(raw.length > 0 ? raw : process.cwd());
60423
+ return path73.resolve(raw.length > 0 ? raw : process.cwd());
60083
60424
  }
60084
60425
  function defaultProfileForMode(mode) {
60085
60426
  switch (mode) {
@@ -60395,7 +60736,7 @@ __export(headlessSpine_exports, {
60395
60736
  seedHeadlessModelHistory: () => seedHeadlessModelHistory,
60396
60737
  sessionStartedEvent: () => sessionStartedEvent
60397
60738
  });
60398
- import path73 from "node:path";
60739
+ import path74 from "node:path";
60399
60740
  function sessionStartedEvent(handle) {
60400
60741
  return {
60401
60742
  type: "session_started",
@@ -60412,7 +60753,7 @@ async function countVerificationEvidenceInLog(mirror, sessionId2) {
60412
60753
  try {
60413
60754
  await mirror.flush().catch(() => void 0);
60414
60755
  const report = await readSessionLogCached(
60415
- path73.join(mirror.sessionsDir, sessionId2, "events.jsonl"),
60756
+ path74.join(mirror.sessionsDir, sessionId2, "events.jsonl"),
60416
60757
  mirror.replayCache
60417
60758
  );
60418
60759
  return report.events.filter((e) => e.kind === "verification.evidence").length;
@@ -61188,9 +61529,9 @@ __export(planDetect_exports, {
61188
61529
  hasWorkspacePlan: () => hasWorkspacePlan
61189
61530
  });
61190
61531
  import { existsSync as existsSync36, readFileSync as readFileSync25 } from "node:fs";
61191
- import { join as join27 } from "node:path";
61532
+ import { join as join28 } from "node:path";
61192
61533
  function hasWorkspacePlan(projectRoot = process.cwd()) {
61193
- const planPath = join27(resolveWorkspaceRoot(projectRoot), "plan.json");
61534
+ const planPath = join28(resolveWorkspaceRoot(projectRoot), "plan.json");
61194
61535
  if (!existsSync36(planPath)) return false;
61195
61536
  try {
61196
61537
  const parsed = JSON.parse(readFileSync25(planPath, "utf8"));
@@ -61208,10 +61549,10 @@ var init_planDetect = __esm({
61208
61549
 
61209
61550
  // src/cli/workspace/projectInstructions.ts
61210
61551
  import { existsSync as existsSync37, readFileSync as readFileSync26 } from "node:fs";
61211
- import { join as join28 } from "node:path";
61552
+ import { join as join29 } from "node:path";
61212
61553
  function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
61213
61554
  for (const name of CANDIDATES) {
61214
- const full = join28(projectRoot, name);
61555
+ const full = join29(projectRoot, name);
61215
61556
  if (!existsSync37(full)) continue;
61216
61557
  try {
61217
61558
  let raw = readFileSync26(full, "utf8");
@@ -61259,7 +61600,7 @@ __export(workspaceSummary_exports, {
61259
61600
  buildZelariReadHint: () => buildZelariReadHint
61260
61601
  });
61261
61602
  import { existsSync as existsSync38, readFileSync as readFileSync27, readdirSync as readdirSync7, statSync as statSync5 } from "node:fs";
61262
- import { join as join29, relative as relative2 } from "node:path";
61603
+ import { join as join30, relative as relative2 } from "node:path";
61263
61604
  function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
61264
61605
  const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
61265
61606
  const name = safeProjectName(projectRoot);
@@ -61292,7 +61633,7 @@ function formatTaskLine(t) {
61292
61633
  }
61293
61634
  function buildPlanSummary(projectRoot = process.cwd(), options) {
61294
61635
  const zelariRoot = resolveWorkspaceRoot(projectRoot);
61295
- const planPath = join29(zelariRoot, "plan.json");
61636
+ const planPath = join30(zelariRoot, "plan.json");
61296
61637
  if (!existsSync38(planPath)) return null;
61297
61638
  let plan;
61298
61639
  try {
@@ -61435,7 +61776,7 @@ function pickNextTask(open2) {
61435
61776
  )[0];
61436
61777
  }
61437
61778
  function buildZelariReadHint(projectRoot = process.cwd()) {
61438
- const planPath = join29(resolveWorkspaceRoot(projectRoot), "plan.json");
61779
+ const planPath = join30(resolveWorkspaceRoot(projectRoot), "plan.json");
61439
61780
  if (!existsSync38(planPath)) return "";
61440
61781
  return [
61441
61782
  "# Council workspace detected (.zelari/) \u2014 DRAFT vault",
@@ -61451,7 +61792,7 @@ function safeProjectName(root) {
61451
61792
  }
61452
61793
  }
61453
61794
  function readPackageJson2(projectRoot) {
61454
- const p3 = join29(projectRoot, "package.json");
61795
+ const p3 = join30(projectRoot, "package.json");
61455
61796
  if (!existsSync38(p3)) return null;
61456
61797
  try {
61457
61798
  return JSON.parse(readFileSync27(p3, "utf8"));
@@ -61504,11 +61845,11 @@ function listShallow(projectRoot, maxEntries) {
61504
61845
  out.push(`\u2026 (+${top.length - count} more)`);
61505
61846
  break;
61506
61847
  }
61507
- const rel2 = relative2(projectRoot, join29(projectRoot, entry.name));
61848
+ const rel2 = relative2(projectRoot, join30(projectRoot, entry.name));
61508
61849
  if (entry.isDirectory()) {
61509
61850
  let inner = "";
61510
61851
  try {
61511
- const sub = readdirSync7(join29(projectRoot, entry.name), {
61852
+ const sub = readdirSync7(join30(projectRoot, entry.name), {
61512
61853
  withFileTypes: true
61513
61854
  }).filter((e) => !e.name.startsWith(".")).slice(0, 4).map((e) => e.name);
61514
61855
  if (sub.length > 0)
@@ -61557,11 +61898,11 @@ var init_workspaceSummary = __esm({
61557
61898
 
61558
61899
  // src/cli/workspace/buildLessonsSummary.ts
61559
61900
  import { existsSync as existsSync39 } from "node:fs";
61560
- import { join as join30 } from "node:path";
61901
+ import { join as join31 } from "node:path";
61561
61902
  function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
61562
61903
  if (process.env["ZELARI_LESSONS"] === "0") return null;
61563
61904
  const zelariRoot = resolveWorkspaceRoot(projectRoot);
61564
- if (!existsSync39(join30(zelariRoot, "lessons.jsonl"))) return null;
61905
+ if (!existsSync39(join31(zelariRoot, "lessons.jsonl"))) return null;
61565
61906
  const lessons = recallLessons(zelariRoot, {
61566
61907
  maxLessons: 5,
61567
61908
  maxBytes: 2048,
@@ -61583,7 +61924,7 @@ __export(composeContext_exports, {
61583
61924
  composeProjectContext: () => composeProjectContext
61584
61925
  });
61585
61926
  import { existsSync as existsSync40, readdirSync as readdirSync8, readFileSync as readFileSync28 } from "node:fs";
61586
- import { join as join31 } from "node:path";
61927
+ import { join as join32 } from "node:path";
61587
61928
  function cap2(text, max, label) {
61588
61929
  if (!text || text.length <= max) return { text: text || "", truncated: false };
61589
61930
  return {
@@ -61600,7 +61941,7 @@ function buildDesignIndex(projectRoot, maxChars) {
61600
61941
  "# Design vault index (.zelari/) \u2014 HYPOTHESES only",
61601
61942
  "Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
61602
61943
  ];
61603
- const docsDir = join31(root, "docs");
61944
+ const docsDir = join32(root, "docs");
61604
61945
  if (existsSync40(docsDir)) {
61605
61946
  try {
61606
61947
  const docs = readdirSync8(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
@@ -61615,11 +61956,11 @@ function buildDesignIndex(projectRoot, maxChars) {
61615
61956
  }
61616
61957
  }
61617
61958
  for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
61618
- if (existsSync40(join31(root, name))) {
61959
+ if (existsSync40(join32(root, name))) {
61619
61960
  lines.push(`- .zelari/${name} present`);
61620
61961
  }
61621
61962
  }
61622
- const decisionsDir = join31(root, "decisions");
61963
+ const decisionsDir = join32(root, "decisions");
61623
61964
  if (existsSync40(decisionsDir)) {
61624
61965
  try {
61625
61966
  const n = readdirSync8(decisionsDir).filter((f) => f.endsWith(".md")).length;
@@ -61721,14 +62062,14 @@ function composeProjectContext(input) {
61721
62062
  }
61722
62063
  function readDurableHeadSync(projectRoot) {
61723
62064
  try {
61724
- const headPath = join31(projectRoot, ".zelari", "state", "HEAD.json");
62065
+ const headPath = join32(projectRoot, ".zelari", "state", "HEAD.json");
61725
62066
  if (!existsSync40(headPath)) return "";
61726
62067
  const head = JSON.parse(readFileSync28(headPath, "utf8"));
61727
62068
  if (!head?.id) return "";
61728
- const metaPath = join31(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
62069
+ const metaPath = join32(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
61729
62070
  if (!existsSync40(metaPath)) return "";
61730
62071
  const meta3 = JSON.parse(readFileSync28(metaPath, "utf8"));
61731
- const discPath = meta3.artifactDir ? join31(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join31(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
62072
+ const discPath = meta3.artifactDir ? join32(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join32(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
61732
62073
  let discoveries = [];
61733
62074
  if (existsSync40(discPath)) {
61734
62075
  discoveries = JSON.parse(readFileSync28(discPath, "utf8"));
@@ -61812,7 +62153,7 @@ import {
61812
62153
  mkdirSync as mkdirSync16,
61813
62154
  renameSync as renameSync5
61814
62155
  } from "node:fs";
61815
- import { join as join32, basename as basename4, dirname as dirname8, relative as relative3 } from "node:path";
62156
+ import { join as join33, basename as basename4, dirname as dirname9, relative as relative3 } from "node:path";
61816
62157
  function createWorkspaceContext(projectRoot = process.cwd()) {
61817
62158
  const rootDir = resolveWorkspaceRoot(projectRoot);
61818
62159
  return {
@@ -61822,7 +62163,7 @@ function createWorkspaceContext(projectRoot = process.cwd()) {
61822
62163
  };
61823
62164
  }
61824
62165
  function planJsonPath(ctx) {
61825
- return join32(ctx.rootDir, "plan.json");
62166
+ return join33(ctx.rootDir, "plan.json");
61826
62167
  }
61827
62168
  function readPlan(ctx) {
61828
62169
  const jsonPath = planJsonPath(ctx);
@@ -61841,8 +62182,8 @@ function readPlan(ctx) {
61841
62182
  } catch {
61842
62183
  }
61843
62184
  }
61844
- const path102 = workspaceFile(ctx.rootDir, "plan");
61845
- const doc = ctx.storage.readIfExists(path102);
62185
+ const path103 = workspaceFile(ctx.rootDir, "plan");
62186
+ const doc = ctx.storage.readIfExists(path103);
61846
62187
  if (!doc) return { phases: [], tasks: [], milestones: [] };
61847
62188
  const meta3 = doc.meta;
61848
62189
  return {
@@ -61853,7 +62194,7 @@ function readPlan(ctx) {
61853
62194
  }
61854
62195
  function writePlan(ctx, summary) {
61855
62196
  const jsonPath = planJsonPath(ctx);
61856
- mkdirSync16(dirname8(jsonPath), { recursive: true });
62197
+ mkdirSync16(dirname9(jsonPath), { recursive: true });
61857
62198
  const tmp = jsonPath + ".tmp-" + process.pid;
61858
62199
  writeFileSync18(
61859
62200
  tmp,
@@ -61935,7 +62276,7 @@ function renderPlanBody(summary) {
61935
62276
  return lines.join("\n");
61936
62277
  }
61937
62278
  function nextAdrId(ctx) {
61938
- const decisionsDir = join32(ctx.rootDir, "decisions");
62279
+ const decisionsDir = join33(ctx.rootDir, "decisions");
61939
62280
  if (!existsSync41(decisionsDir)) return "001";
61940
62281
  const existing = readdirSync9(decisionsDir).filter((f) => f.endsWith(".md")).map((f) => f.match(/^(\d+)-/)).filter((m) => !!m).map((m) => parseInt(m[1], 10));
61941
62282
  const max = existing.length === 0 ? 0 : Math.max(...existing);
@@ -61981,7 +62322,7 @@ function addTaskRecord(ctx, summary, phaseId, t, options) {
61981
62322
  // plan.json record (they already live in tags + the artifact body md).
61982
62323
  files: t.fileRefs
61983
62324
  });
61984
- const taskPath = join32(ctx.rootDir, "plan-tasks", `${id3}.md`);
62325
+ const taskPath = join33(ctx.rootDir, "plan-tasks", `${id3}.md`);
61985
62326
  const meta3 = {
61986
62327
  kind: "task",
61987
62328
  id: id3,
@@ -62023,7 +62364,7 @@ function addMilestoneRecord(ctx, summary, input) {
62023
62364
  dueDate: input.dueDate,
62024
62365
  targetVersion: version2
62025
62366
  });
62026
- const path102 = join32(ctx.rootDir, "milestones", `${id3}.md`);
62367
+ const path103 = join33(ctx.rootDir, "milestones", `${id3}.md`);
62027
62368
  const meta3 = {
62028
62369
  kind: "milestone",
62029
62370
  id: id3,
@@ -62040,7 +62381,7 @@ function addMilestoneRecord(ctx, summary, input) {
62040
62381
  `Target version: ${version2}`,
62041
62382
  ""
62042
62383
  ].join("\n");
62043
- ctx.storage.write(path102, meta3, body);
62384
+ ctx.storage.write(path103, meta3, body);
62044
62385
  return { id: id3, created: true };
62045
62386
  }
62046
62387
  function readPlanSummary(ctx) {
@@ -62244,7 +62585,7 @@ function addIdeaStub(ctx) {
62244
62585
  const tags = args["tags"] ?? [];
62245
62586
  const category = args["category"] ?? "General";
62246
62587
  const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
62247
- const path102 = workspaceArtifact(ctx.rootDir, "decisions", id3);
62588
+ const path103 = workspaceArtifact(ctx.rootDir, "decisions", id3);
62248
62589
  const meta3 = {
62249
62590
  kind: "adr",
62250
62591
  status: "proposed",
@@ -62270,7 +62611,7 @@ function addIdeaStub(ctx) {
62270
62611
  ...consequences.map((c) => `- ${c}`),
62271
62612
  ""
62272
62613
  ].join("\n");
62273
- ctx.storage.write(path102, meta3, body);
62614
+ ctx.storage.write(path103, meta3, body);
62274
62615
  return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
62275
62616
  });
62276
62617
  }
@@ -62321,7 +62662,7 @@ function createNfrSpecStub(ctx) {
62321
62662
  },
62322
62663
  planFeatureKeywords: Array.isArray(args["planFeatureKeywords"]) ? args["planFeatureKeywords"] : void 0
62323
62664
  };
62324
- const outPath = join32(ctx.rootDir, "nfr-spec.json");
62665
+ const outPath = join33(ctx.rootDir, "nfr-spec.json");
62325
62666
  writeFileSync18(outPath, JSON.stringify(spec, null, 2), "utf8");
62326
62667
  return `NFR spec written to nfr-spec.json (${targets.length} target(s)).`;
62327
62668
  });
@@ -62352,14 +62693,14 @@ function createDocumentStub(ctx) {
62352
62693
  ctx.storage.write(risksPath, riskMeta, content);
62353
62694
  return `Document "${title}" created at risks.md (workspace root).`;
62354
62695
  }
62355
- const path102 = workspaceArtifact(ctx.rootDir, "docs", slug);
62696
+ const path103 = workspaceArtifact(ctx.rootDir, "docs", slug);
62356
62697
  const meta3 = {
62357
62698
  kind: "doc",
62358
62699
  id: slug,
62359
62700
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
62360
62701
  tags
62361
62702
  };
62362
- ctx.storage.write(path102, meta3, content);
62703
+ ctx.storage.write(path103, meta3, content);
62363
62704
  return `Document "${title}" created at docs/${slug}.md.`;
62364
62705
  });
62365
62706
  }
@@ -62385,11 +62726,11 @@ function searchDocumentsStub(ctx) {
62385
62726
  (w) => w.length >= 3 && w !== "or" && w !== "and" && w !== "the"
62386
62727
  );
62387
62728
  const files = [
62388
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "decisions")),
62389
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "docs")),
62390
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "reviews")),
62391
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "plan-tasks")),
62392
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "milestones")),
62729
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "decisions")),
62730
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "docs")),
62731
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "reviews")),
62732
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "plan-tasks")),
62733
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "milestones")),
62393
62734
  workspaceFile(ctx.rootDir, "plan"),
62394
62735
  workspaceFile(ctx.rootDir, "risks")
62395
62736
  ];
@@ -62447,9 +62788,9 @@ function linkDocumentsStub(ctx) {
62447
62788
  const toId = args["toId"] ?? args["targetId"] ?? args["targetPathOrTitle"];
62448
62789
  if (!fromId || !toId) return "linkDocuments requires fromId and toId.";
62449
62790
  const allFiles = [
62450
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "decisions")),
62451
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "docs")),
62452
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "reviews"))
62791
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "decisions")),
62792
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "docs")),
62793
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "reviews"))
62453
62794
  ];
62454
62795
  const source2 = allFiles.find((f) => {
62455
62796
  try {
@@ -62480,9 +62821,9 @@ function getDocumentBacklinksStub(ctx) {
62480
62821
  const targetId = args["targetId"] ?? args["id"];
62481
62822
  if (!targetId) return "getDocumentBacklinks requires targetId.";
62482
62823
  const allFiles = [
62483
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "decisions")),
62484
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "docs")),
62485
- ...ctx.storage.listMarkdown(join32(ctx.rootDir, "reviews"))
62824
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "decisions")),
62825
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "docs")),
62826
+ ...ctx.storage.listMarkdown(join33(ctx.rootDir, "reviews"))
62486
62827
  ];
62487
62828
  const backlinks = [];
62488
62829
  for (const file2 of allFiles) {
@@ -62977,17 +63318,17 @@ import {
62977
63318
  readFileSync as readFileSync30,
62978
63319
  writeFileSync as writeFileSync19
62979
63320
  } from "node:fs";
62980
- import { dirname as dirname9, join as join33 } from "node:path";
63321
+ import { dirname as dirname10, join as join34 } from "node:path";
62981
63322
  function getUserMcpPath() {
62982
- return join33(zelariHome(), "mcp.json");
63323
+ return join34(zelariHome(), "mcp.json");
62983
63324
  }
62984
63325
  function getProjectMcpPath(projectRoot) {
62985
- return join33(projectRoot, ".zelari", "mcp.json");
63326
+ return join34(projectRoot, ".zelari", "mcp.json");
62986
63327
  }
62987
- function readFile10(path102) {
62988
- if (!existsSync42(path102)) return {};
63328
+ function readFile10(path103) {
63329
+ if (!existsSync42(path103)) return {};
62989
63330
  try {
62990
- const parsed = JSON.parse(readFileSync30(path102, "utf8"));
63331
+ const parsed = JSON.parse(readFileSync30(path103, "utf8"));
62991
63332
  const out = {};
62992
63333
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
62993
63334
  const hasCommand = !!cfg && typeof cfg.command === "string" && !!cfg.command.trim();
@@ -63009,10 +63350,10 @@ function readFile10(path102) {
63009
63350
  return {};
63010
63351
  }
63011
63352
  }
63012
- function writeFile4(path102, servers) {
63013
- mkdirSync17(dirname9(path102), { recursive: true });
63353
+ function writeFile4(path103, servers) {
63354
+ mkdirSync17(dirname10(path103), { recursive: true });
63014
63355
  const body = { mcpServers: servers };
63015
- writeFileSync19(path102, `${JSON.stringify(body, null, 2)}
63356
+ writeFileSync19(path103, `${JSON.stringify(body, null, 2)}
63016
63357
  `, "utf8");
63017
63358
  }
63018
63359
  function listMcpServers(projectRoot) {
@@ -63050,9 +63391,9 @@ function upsertMcpServer(opts) {
63050
63391
  error: "either command (stdio) or url (http) is required"
63051
63392
  };
63052
63393
  }
63053
- let path102;
63394
+ let path103;
63054
63395
  if (opts.scope === "user") {
63055
- path102 = getUserMcpPath();
63396
+ path103 = getUserMcpPath();
63056
63397
  } else {
63057
63398
  const root = opts.projectRoot?.trim();
63058
63399
  if (!root) {
@@ -63061,9 +63402,9 @@ function upsertMcpServer(opts) {
63061
63402
  error: "projectRoot required for project scope (Open Folder first)"
63062
63403
  };
63063
63404
  }
63064
- path102 = getProjectMcpPath(root);
63405
+ path103 = getProjectMcpPath(root);
63065
63406
  }
63066
- const current = readFile10(path102);
63407
+ const current = readFile10(path103);
63067
63408
  current[name] = {
63068
63409
  command: hasCommand ? opts.config.command.trim() : void 0,
63069
63410
  args: opts.config.args,
@@ -63074,21 +63415,21 @@ function upsertMcpServer(opts) {
63074
63415
  serial: opts.config.serial,
63075
63416
  enabled: opts.config.enabled !== false
63076
63417
  };
63077
- writeFile4(path102, current);
63078
- return { ok: true, path: path102 };
63418
+ writeFile4(path103, current);
63419
+ return { ok: true, path: path103 };
63079
63420
  }
63080
63421
  function removeMcpServer(opts) {
63081
- const path102 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
63082
- if (!path102) {
63422
+ const path103 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
63423
+ if (!path103) {
63083
63424
  return { ok: false, error: "projectRoot required for project scope" };
63084
63425
  }
63085
- const current = readFile10(path102);
63426
+ const current = readFile10(path103);
63086
63427
  if (!(opts.name in current)) {
63087
- return { ok: false, error: `Server "${opts.name}" not found in ${path102}` };
63428
+ return { ok: false, error: `Server "${opts.name}" not found in ${path103}` };
63088
63429
  }
63089
63430
  delete current[opts.name];
63090
- writeFile4(path102, current);
63091
- return { ok: true, path: path102 };
63431
+ writeFile4(path103, current);
63432
+ return { ok: true, path: path103 };
63092
63433
  }
63093
63434
  var init_mcpConfigIo = __esm({
63094
63435
  "src/cli/mcp/mcpConfigIo.ts"() {
@@ -63261,15 +63602,15 @@ __export(mcpManager_exports, {
63261
63602
  registerMcpTools: () => registerMcpTools
63262
63603
  });
63263
63604
  import { existsSync as existsSync43, readFileSync as readFileSync31 } from "node:fs";
63264
- import { join as join34 } from "node:path";
63605
+ import { join as join35 } from "node:path";
63265
63606
  function readMcpConfig(projectRoot = process.cwd(), opts) {
63266
63607
  const merged = {};
63267
63608
  const paths = [];
63268
63609
  if (process.env["ZELARI_MCP_USER"] !== "0") {
63269
- paths.push(join34(zelariHome(), "mcp.json"));
63610
+ paths.push(join35(zelariHome(), "mcp.json"));
63270
63611
  }
63271
63612
  if (!opts?.skipProjectMcp) {
63272
- paths.push(join34(projectRoot, ".zelari", "mcp.json"));
63613
+ paths.push(join35(projectRoot, ".zelari", "mcp.json"));
63273
63614
  }
63274
63615
  for (const p3 of paths) {
63275
63616
  if (!existsSync43(p3)) continue;
@@ -63290,7 +63631,7 @@ async function ensureLoaded(projectRoot) {
63290
63631
  if (state2.loaded) return;
63291
63632
  state2.loaded = true;
63292
63633
  const trusted = isFolderTrusted(projectRoot);
63293
- if (!trusted && existsSync43(join34(projectRoot, ".zelari", "mcp.json"))) {
63634
+ if (!trusted && existsSync43(join35(projectRoot, ".zelari", "mcp.json"))) {
63294
63635
  state2.warnings.push(
63295
63636
  "[mcp] project .zelari/mcp.json ignored \u2014 folder not trusted (run /trust or `zelari-code --trust` to enable project MCP)"
63296
63637
  );
@@ -63556,13 +63897,13 @@ __export(agentsMd_exports, {
63556
63897
  });
63557
63898
  import { existsSync as existsSync44, readFileSync as readFileSync32, writeFileSync as writeFileSync20 } from "node:fs";
63558
63899
  import { createHash as createHash24 } from "node:crypto";
63559
- import { join as join35 } from "node:path";
63900
+ import { join as join36 } from "node:path";
63560
63901
  import { readFile as readFile11 } from "node:fs/promises";
63561
63902
  async function readPackageJson3(projectRoot) {
63562
- const path102 = join35(projectRoot, "package.json");
63563
- if (!existsSync44(path102)) return null;
63903
+ const path103 = join36(projectRoot, "package.json");
63904
+ if (!existsSync44(path103)) return null;
63564
63905
  try {
63565
- return JSON.parse(await readFile11(path102, "utf8"));
63906
+ return JSON.parse(await readFile11(path103, "utf8"));
63566
63907
  } catch {
63567
63908
  return null;
63568
63909
  }
@@ -63584,7 +63925,7 @@ async function genTechStack(ctx) {
63584
63925
  ].join("\n");
63585
63926
  }
63586
63927
  async function genDecisions(ctx) {
63587
- const decisionsDir = join35(ctx.rootDir, "decisions");
63928
+ const decisionsDir = join36(ctx.rootDir, "decisions");
63588
63929
  if (!existsSync44(decisionsDir)) return "_No ADRs yet._";
63589
63930
  const files = ctx.storage.listMarkdown(decisionsDir).sort();
63590
63931
  const accepted = [];
@@ -63610,7 +63951,7 @@ async function genDecisions(ctx) {
63610
63951
  }
63611
63952
  async function genConventions(ctx) {
63612
63953
  const lines = [];
63613
- const claudeMd = join35(ctx.projectRoot, "CLAUDE.MD");
63954
+ const claudeMd = join36(ctx.projectRoot, "CLAUDE.MD");
63614
63955
  if (existsSync44(claudeMd)) {
63615
63956
  const content = readFileSync32(claudeMd, "utf8");
63616
63957
  const match = content.match(/## Architecture rules[\s\S]+?(?=\n## |\n*$)/);
@@ -63644,9 +63985,9 @@ async function genBuild(ctx) {
63644
63985
  ].join("\n");
63645
63986
  }
63646
63987
  async function genOpenQuestions(ctx) {
63647
- const path102 = join35(ctx.rootDir, "risks.md");
63648
- if (!existsSync44(path102)) return "_No open questions._";
63649
- const content = readFileSync32(path102, "utf8");
63988
+ const path103 = join36(ctx.rootDir, "risks.md");
63989
+ if (!existsSync44(path103)) return "_No open questions._";
63990
+ const content = readFileSync32(path103, "utf8");
63650
63991
  const lines = content.split("\n");
63651
63992
  const questions = [];
63652
63993
  let currentTitle = "";
@@ -63720,7 +64061,7 @@ function titleCase(id3) {
63720
64061
  return id3.split("-").map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
63721
64062
  }
63722
64063
  async function updateAgentsMd(ctx, projectRoot) {
63723
- const agentsPath = join35(projectRoot, "AGENTS.MD");
64064
+ const agentsPath = join36(projectRoot, "AGENTS.MD");
63724
64065
  if (existsSync44(agentsPath)) {
63725
64066
  const content = readFileSync32(agentsPath, "utf8");
63726
64067
  const hasAnyMarker = AUTO_SECTIONS.some((id3) => content.includes(MARKER_OPEN(id3)));
@@ -63892,11 +64233,11 @@ var init_completeDesign = __esm({
63892
64233
 
63893
64234
  // src/cli/workspace/planDriftCheck.ts
63894
64235
  import { existsSync as existsSync45, readFileSync as readFileSync33, readdirSync as readdirSync10, statSync as statSync6, writeFileSync as writeFileSync21 } from "node:fs";
63895
- import { join as join36 } from "node:path";
64236
+ import { join as join37 } from "node:path";
63896
64237
  function findCanonicalDoc(rootDir) {
63897
- const docsDir = join36(rootDir, "docs");
64238
+ const docsDir = join37(rootDir, "docs");
63898
64239
  if (!existsSync45(docsDir)) return null;
63899
- const candidates = readdirSync10(docsDir).filter((f) => /^plan-canonical.*\.md$/i.test(f)).map((f) => ({ f, mtime: statSync6(join36(docsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
64240
+ const candidates = readdirSync10(docsDir).filter((f) => /^plan-canonical.*\.md$/i.test(f)).map((f) => ({ f, mtime: statSync6(join37(docsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
63900
64241
  return candidates.length > 0 ? candidates[0].f : null;
63901
64242
  }
63902
64243
  function parseCanonicalDoc(text) {
@@ -63920,9 +64261,9 @@ function versionKey(value) {
63920
64261
  function firstString2(v) {
63921
64262
  return typeof v === "string" && v.trim().length > 0 ? v : null;
63922
64263
  }
63923
- function readFileSyncSafe(path102) {
64264
+ function readFileSyncSafe(path103) {
63924
64265
  try {
63925
- return readFileSync33(path102, "utf8");
64266
+ return readFileSync33(path103, "utf8");
63926
64267
  } catch {
63927
64268
  return null;
63928
64269
  }
@@ -63931,7 +64272,7 @@ async function runPlanDriftCheck(rootDir) {
63931
64272
  if (process.env["ZELARI_DRIFT_CHECK"] === "0") {
63932
64273
  return { ran: false, reason: "ZELARI_DRIFT_CHECK=0 (disabled)" };
63933
64274
  }
63934
- const planPath = join36(rootDir, "plan.json");
64275
+ const planPath = join37(rootDir, "plan.json");
63935
64276
  if (!existsSync45(planPath)) {
63936
64277
  return { ran: false, reason: ".zelari/plan.json missing (not design-phase)" };
63937
64278
  }
@@ -63947,7 +64288,7 @@ async function runPlanDriftCheck(rootDir) {
63947
64288
  const milestones = Array.isArray(plan.milestones) ? plan.milestones : [];
63948
64289
  const phaseIds = new Set(phases.map((p3) => typeof p3.id === "string" ? p3.id : "").filter(Boolean));
63949
64290
  const canonicalName = findCanonicalDoc(rootDir);
63950
- const canonicalText = canonicalName ? readFileSyncSafe(join36(rootDir, "docs", canonicalName)) : null;
64291
+ const canonicalText = canonicalName ? readFileSyncSafe(join37(rootDir, "docs", canonicalName)) : null;
63951
64292
  if (canonicalText !== null) {
63952
64293
  const { activePhases, blockedPrefixes } = parseCanonicalDoc(canonicalText);
63953
64294
  for (const id3 of activePhases) {
@@ -64026,7 +64367,7 @@ async function runPlanDriftCheck(rootDir) {
64026
64367
  const canonicalParsed = canonicalName !== null && canonicalText !== null;
64027
64368
  let reportPath;
64028
64369
  try {
64029
- reportPath = join36(rootDir, "drift-report.json");
64370
+ reportPath = join37(rootDir, "drift-report.json");
64030
64371
  writeFileSync21(
64031
64372
  reportPath,
64032
64373
  JSON.stringify(
@@ -64064,7 +64405,7 @@ var init_planDriftCheck = __esm({
64064
64405
  // src/cli/workspace/projectSmoke.ts
64065
64406
  import { spawn as spawn15 } from "node:child_process";
64066
64407
  import { existsSync as existsSync46, readFileSync as readFileSync34 } from "node:fs";
64067
- import { join as join37 } from "node:path";
64408
+ import { join as join38 } from "node:path";
64068
64409
  function pickSmokeScript(scripts) {
64069
64410
  if (!scripts) return null;
64070
64411
  for (const name of SMOKE_SCRIPT_PRIORITY) {
@@ -64076,7 +64417,7 @@ async function runProjectSmoke(projectRoot, timeoutMs2 = DEFAULT_TIMEOUT_MS3) {
64076
64417
  if (process.env["ZELARI_SMOKE"] === "0") {
64077
64418
  return { ran: false, reason: "ZELARI_SMOKE=0 (disabled)" };
64078
64419
  }
64079
- const pkgPath = join37(projectRoot, "package.json");
64420
+ const pkgPath = join38(projectRoot, "package.json");
64080
64421
  if (!existsSync46(pkgPath)) {
64081
64422
  return { ran: false, reason: "no package.json (skipped)" };
64082
64423
  }
@@ -64170,7 +64511,7 @@ __export(evidenceFromSpine_exports, {
64170
64511
  evidenceRefsFromEventLines: () => evidenceRefsFromEventLines
64171
64512
  });
64172
64513
  import { existsSync as existsSync47, readFileSync as readFileSync35 } from "node:fs";
64173
- import path74 from "node:path";
64514
+ import path75 from "node:path";
64174
64515
  function asRecord2(v) {
64175
64516
  return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
64176
64517
  }
@@ -64208,7 +64549,7 @@ function evidenceRefsFromEventLines(lines) {
64208
64549
  }
64209
64550
  function collectSessionEvidenceRefs(sessionId2) {
64210
64551
  try {
64211
- const file2 = path74.join(sessionsDir(), sessionId2, "events.jsonl");
64552
+ const file2 = path75.join(sessionsDir(), sessionId2, "events.jsonl");
64212
64553
  if (!existsSync47(file2)) return [];
64213
64554
  return evidenceRefsFromEventLines(readFileSync35(file2, "utf8").split("\n"));
64214
64555
  } catch {
@@ -64234,7 +64575,7 @@ __export(postCouncilHook_exports, {
64234
64575
  });
64235
64576
  import { spawn as spawn16 } from "node:child_process";
64236
64577
  import { existsSync as existsSync48, readFileSync as readFileSync36 } from "node:fs";
64237
- import { join as join38 } from "node:path";
64578
+ import { join as join39 } from "node:path";
64238
64579
  async function runCompleteDesignPostProcessor(ctx, options) {
64239
64580
  if (options?.runMode === "implementation") {
64240
64581
  return {
@@ -64245,8 +64586,8 @@ async function runCompleteDesignPostProcessor(ctx, options) {
64245
64586
  if (process.env["ZELARI_COMPLETE_DESIGN"] === "0") {
64246
64587
  return { ran: false, reason: "ZELARI_COMPLETE_DESIGN=0 (disabled)" };
64247
64588
  }
64248
- const planJsonPath2 = join38(ctx.rootDir, "plan.json");
64249
- const scriptPath = join38(ctx.projectRoot, "complete-design.mjs");
64589
+ const planJsonPath2 = join39(ctx.rootDir, "plan.json");
64590
+ const scriptPath = join39(ctx.projectRoot, "complete-design.mjs");
64250
64591
  if (!existsSync48(planJsonPath2)) {
64251
64592
  return {
64252
64593
  ran: false,
@@ -64458,8 +64799,8 @@ async function runPostCouncilHook(ctx, options) {
64458
64799
  sources: scope.sources
64459
64800
  } : void 0
64460
64801
  });
64461
- const path102 = writeCouncilCompletion(ctx.rootDir, completion);
64462
- completionHook = { ran: true, path: path102, completion };
64802
+ const path103 = writeCouncilCompletion(ctx.rootDir, completion);
64803
+ completionHook = { ran: true, path: path103, completion };
64463
64804
  } catch (err) {
64464
64805
  completionHook = {
64465
64806
  ran: true,
@@ -64498,13 +64839,13 @@ __export(councilFeedback_exports, {
64498
64839
  FeedbackStore: () => FeedbackStore
64499
64840
  });
64500
64841
  import {
64501
- promises as fs32,
64842
+ promises as fs33,
64502
64843
  existsSync as existsSync49,
64503
64844
  readFileSync as readFileSync37,
64504
64845
  writeFileSync as writeFileSync22,
64505
64846
  mkdirSync as mkdirSync18
64506
64847
  } from "node:fs";
64507
- import path75 from "node:path";
64848
+ import path76 from "node:path";
64508
64849
  var FeedbackStore;
64509
64850
  var init_councilFeedback = __esm({
64510
64851
  "src/cli/councilFeedback.ts"() {
@@ -64621,7 +64962,7 @@ var init_councilFeedback = __esm({
64621
64962
  }
64622
64963
  }
64623
64964
  save() {
64624
- mkdirSync18(path75.dirname(this.file), { recursive: true });
64965
+ mkdirSync18(path76.dirname(this.file), { recursive: true });
64625
64966
  writeFileSync22(
64626
64967
  this.file,
64627
64968
  JSON.stringify({ entries: this.entries }, null, 2),
@@ -64631,7 +64972,7 @@ var init_councilFeedback = __esm({
64631
64972
  /** Async variant of load for callers that prefer async IO. */
64632
64973
  async loadAsync() {
64633
64974
  try {
64634
- const raw = await fs32.readFile(this.file, "utf-8");
64975
+ const raw = await fs33.readFile(this.file, "utf-8");
64635
64976
  const parsed = JSON.parse(raw);
64636
64977
  if (parsed && Array.isArray(parsed.entries)) {
64637
64978
  this.entries = parsed.entries.filter(
@@ -64696,12 +65037,12 @@ __export(ledger_exports, {
64696
65037
  readLedger: () => readLedger
64697
65038
  });
64698
65039
  import { appendFileSync as appendFileSync4, existsSync as existsSync50, mkdirSync as mkdirSync19, readFileSync as readFileSync38 } from "node:fs";
64699
- import path76 from "node:path";
65040
+ import path77 from "node:path";
64700
65041
  function evolutionMode(env = process.env) {
64701
65042
  return env[EVOLUTION_ENV] === "shadow" ? "shadow" : "0";
64702
65043
  }
64703
65044
  function ledgerPath(cwd) {
64704
- return path76.join(cwd, LEDGER_REL);
65045
+ return path77.join(cwd, LEDGER_REL);
64705
65046
  }
64706
65047
  function appendLedgerEntry(cwd, entry) {
64707
65048
  if (evolutionMode() === "0") {
@@ -64709,7 +65050,7 @@ function appendLedgerEntry(cwd, entry) {
64709
65050
  }
64710
65051
  try {
64711
65052
  const file2 = ledgerPath(cwd);
64712
- mkdirSync19(path76.dirname(file2), { recursive: true });
65053
+ mkdirSync19(path77.dirname(file2), { recursive: true });
64713
65054
  appendFileSync4(file2, `${JSON.stringify(entry)}
64714
65055
  `, "utf8");
64715
65056
  return { written: true, path: file2 };
@@ -64810,7 +65151,7 @@ var init_ledger = __esm({
64810
65151
  "src/cli/evolution/ledger.ts"() {
64811
65152
  "use strict";
64812
65153
  EVOLUTION_ENV = "ZELARI_EVOLUTION";
64813
- LEDGER_REL = path76.join(".zelari", "evolution", "ledger.jsonl");
65154
+ LEDGER_REL = path77.join(".zelari", "evolution", "ledger.jsonl");
64814
65155
  TIER_WEIGHTS = {
64815
65156
  build: 1,
64816
65157
  "tool-output": 1,
@@ -64951,8 +65292,8 @@ __export(fileBackend_exports, {
64951
65292
  isMemoryEnabled: () => isMemoryEnabled
64952
65293
  });
64953
65294
  import { randomUUID as randomUUID7 } from "node:crypto";
64954
- import { promises as fs33 } from "node:fs";
64955
- import * as path77 from "node:path";
65295
+ import { promises as fs34 } from "node:fs";
65296
+ import * as path78 from "node:path";
64956
65297
  function tokenize2(text) {
64957
65298
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
64958
65299
  }
@@ -65005,9 +65346,9 @@ var init_fileBackend = __esm({
65005
65346
  logPath = "";
65006
65347
  memoryDir = "";
65007
65348
  async init(projectRoot) {
65008
- this.memoryDir = path77.join(projectRoot, ".zelari", "memory");
65009
- this.logPath = path77.join(this.memoryDir, "log.jsonl");
65010
- await fs33.mkdir(this.memoryDir, { recursive: true });
65349
+ this.memoryDir = path78.join(projectRoot, ".zelari", "memory");
65350
+ this.logPath = path78.join(this.memoryDir, "log.jsonl");
65351
+ await fs34.mkdir(this.memoryDir, { recursive: true });
65011
65352
  }
65012
65353
  async add(content, metadata2 = {}, graph) {
65013
65354
  const fact = {
@@ -65017,7 +65358,7 @@ var init_fileBackend = __esm({
65017
65358
  ...graph ? { graph } : {},
65018
65359
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
65019
65360
  };
65020
- await fs33.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
65361
+ await fs34.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
65021
65362
  return fact.id;
65022
65363
  }
65023
65364
  async search(query, options = {}) {
@@ -65045,7 +65386,7 @@ var init_fileBackend = __esm({
65045
65386
  async readAll() {
65046
65387
  let raw;
65047
65388
  try {
65048
- raw = await fs33.readFile(this.logPath, "utf8");
65389
+ raw = await fs34.readFile(this.logPath, "utf8");
65049
65390
  } catch {
65050
65391
  return [];
65051
65392
  }
@@ -65078,23 +65419,23 @@ var init_fileBackend = __esm({
65078
65419
  });
65079
65420
 
65080
65421
  // src/cli/traceStore.ts
65081
- import { promises as fs34 } from "node:fs";
65082
- import * as path78 from "node:path";
65422
+ import { promises as fs35 } from "node:fs";
65423
+ import * as path79 from "node:path";
65083
65424
  function traceDir(projectRoot) {
65084
- return path78.join(projectRoot, ".zelari", "trace");
65425
+ return path79.join(projectRoot, ".zelari", "trace");
65085
65426
  }
65086
65427
  function tracePath(projectRoot, missionId) {
65087
- return path78.join(traceDir(projectRoot), `${missionId}.json`);
65428
+ return path79.join(traceDir(projectRoot), `${missionId}.json`);
65088
65429
  }
65089
65430
  async function saveTrace(projectRoot, missionId, entries) {
65090
65431
  const dir = traceDir(projectRoot);
65091
- await fs34.mkdir(dir, { recursive: true });
65432
+ await fs35.mkdir(dir, { recursive: true });
65092
65433
  const payload = {
65093
65434
  missionId,
65094
65435
  ts: Date.now(),
65095
65436
  entries
65096
65437
  };
65097
- await fs34.writeFile(
65438
+ await fs35.writeFile(
65098
65439
  tracePath(projectRoot, missionId),
65099
65440
  JSON.stringify(payload, null, 2) + "\n",
65100
65441
  "utf8"
@@ -65125,8 +65466,8 @@ __export(zelariMission_exports, {
65125
65466
  runZelariMission: () => runZelariMission
65126
65467
  });
65127
65468
  import { randomUUID as randomUUID8 } from "node:crypto";
65128
- import { promises as fs35 } from "node:fs";
65129
- import * as path79 from "node:path";
65469
+ import { promises as fs36 } from "node:fs";
65470
+ import * as path80 from "node:path";
65130
65471
  function resolveMaxIterations(env = process.env) {
65131
65472
  const raw = env.ZELARI_MISSION_MAX_ITER;
65132
65473
  const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
@@ -65169,10 +65510,10 @@ function isMissionAutoStart(env = process.env) {
65169
65510
  return env.ZELARI_MISSION_AUTO === "1";
65170
65511
  }
65171
65512
  async function writeMissionState(projectRoot, state3) {
65172
- const dir = path79.join(projectRoot, ".zelari");
65173
- await fs35.mkdir(dir, { recursive: true });
65174
- await fs35.writeFile(
65175
- path79.join(dir, "mission-state.json"),
65513
+ const dir = path80.join(projectRoot, ".zelari");
65514
+ await fs36.mkdir(dir, { recursive: true });
65515
+ await fs36.writeFile(
65516
+ path80.join(dir, "mission-state.json"),
65176
65517
  JSON.stringify(state3, null, 2) + "\n",
65177
65518
  "utf8"
65178
65519
  );
@@ -65185,8 +65526,8 @@ async function writeMissionState(projectRoot, state3) {
65185
65526
  }
65186
65527
  async function loadMissionState(projectRoot) {
65187
65528
  try {
65188
- const raw = await fs35.readFile(
65189
- path79.join(projectRoot, ".zelari", "mission-state.json"),
65529
+ const raw = await fs36.readFile(
65530
+ path80.join(projectRoot, ".zelari", "mission-state.json"),
65190
65531
  "utf8"
65191
65532
  );
65192
65533
  const parsed = JSON.parse(raw);
@@ -65945,7 +66286,7 @@ function safeSocketPath(socketPath) {
65945
66286
  return socketPath.trim();
65946
66287
  }
65947
66288
  function startPermissionBroker(socketPath, handlers, opts) {
65948
- const path102 = safeSocketPath(socketPath);
66289
+ const path103 = safeSocketPath(socketPath);
65949
66290
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
65950
66291
  const sockets = /* @__PURE__ */ new Set();
65951
66292
  const server = createServer2((socket) => {
@@ -66045,10 +66386,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
66045
66386
  return new Promise((resolve9, reject) => {
66046
66387
  const onError = (err) => reject(err);
66047
66388
  server.once("error", onError);
66048
- server.listen(path102, () => {
66389
+ server.listen(path103, () => {
66049
66390
  server.removeListener("error", onError);
66050
66391
  resolve9({
66051
- socketPath: path102,
66392
+ socketPath: path103,
66052
66393
  stop: () => new Promise((res) => {
66053
66394
  for (const s of sockets) s.destroy();
66054
66395
  sockets.clear();
@@ -66059,7 +66400,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
66059
66400
  if (done) return;
66060
66401
  done = true;
66061
66402
  if (process.platform !== "win32") {
66062
- unlink(path102, () => res());
66403
+ unlink(path103, () => res());
66063
66404
  } else {
66064
66405
  res();
66065
66406
  }
@@ -66072,11 +66413,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
66072
66413
  });
66073
66414
  }
66074
66415
  function requestBrokerAsk(socketPath, ask, opts) {
66075
- const path102 = safeSocketPath(socketPath);
66416
+ const path103 = safeSocketPath(socketPath);
66076
66417
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
66077
66418
  const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
66078
66419
  return new Promise((resolve9, reject) => {
66079
- const socket = connect(path102);
66420
+ const socket = connect(path103);
66080
66421
  let buffer = "";
66081
66422
  let settled = false;
66082
66423
  const settle = (fn) => {
@@ -66091,7 +66432,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
66091
66432
  settle(
66092
66433
  () => reject(
66093
66434
  new Error(
66094
- `permission broker unavailable at "${path102}" (connect timed out after ${connectTimeoutMs}ms)`
66435
+ `permission broker unavailable at "${path103}" (connect timed out after ${connectTimeoutMs}ms)`
66095
66436
  )
66096
66437
  )
66097
66438
  );
@@ -66909,7 +67250,7 @@ __export(prereqChecks_exports, {
66909
67250
  });
66910
67251
  import { execSync, spawnSync as spawnSync2 } from "node:child_process";
66911
67252
  import { existsSync as existsSync52 } from "node:fs";
66912
- import { dirname as dirname11 } from "node:path";
67253
+ import { dirname as dirname12 } from "node:path";
66913
67254
  function isWslBashPath2(p3) {
66914
67255
  if (!p3 || typeof p3 !== "string") return false;
66915
67256
  const n = p3.replace(/\//g, "\\").toLowerCase();
@@ -67015,7 +67356,7 @@ function resolveAgentShellSync() {
67015
67356
  function agentProbeEnv() {
67016
67357
  const env = { ...process.env };
67017
67358
  try {
67018
- const nodeDir = dirname11(process.execPath);
67359
+ const nodeDir = dirname12(process.execPath);
67019
67360
  if (!nodeDir) return env;
67020
67361
  const sep4 = process.platform === "win32" ? ";" : ":";
67021
67362
  const current = env.PATH ?? env.Path ?? "";
@@ -67280,7 +67621,7 @@ var init_prereqChecks = __esm({
67280
67621
 
67281
67622
  // src/cli/plugins/prefs.ts
67282
67623
  import { existsSync as existsSync53, readFileSync as readFileSync40, writeFileSync as writeFileSync23, mkdirSync as mkdirSync20 } from "node:fs";
67283
- import path84 from "node:path";
67624
+ import path85 from "node:path";
67284
67625
  function getPluginPrefsPath() {
67285
67626
  return pluginsPrefsPath();
67286
67627
  }
@@ -67303,7 +67644,7 @@ function getPluginPrefs() {
67303
67644
  }
67304
67645
  function writePluginPrefs(prefs) {
67305
67646
  const file2 = getPluginPrefsPath();
67306
- mkdirSync20(path84.dirname(file2), { recursive: true });
67647
+ mkdirSync20(path85.dirname(file2), { recursive: true });
67307
67648
  writeFileSync23(file2, JSON.stringify(prefs, null, 2), {
67308
67649
  encoding: "utf-8",
67309
67650
  mode: 384
@@ -67341,7 +67682,7 @@ __export(registry_exports, {
67341
67682
  isBinaryOnPath: () => isBinaryOnPath
67342
67683
  });
67343
67684
  import { existsSync as existsSync54 } from "node:fs";
67344
- import path85 from "node:path";
67685
+ import path86 from "node:path";
67345
67686
  function detectLocalBin(bin) {
67346
67687
  return (cwd) => {
67347
67688
  try {
@@ -67359,7 +67700,7 @@ function isBinaryOnPath(bin, opts = {}) {
67359
67700
  const platform = opts.platform ?? process.platform;
67360
67701
  const exists = opts.exists ?? existsSync54;
67361
67702
  const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
67362
- const pathMod = platform === "win32" ? path85.win32 : path85.posix;
67703
+ const pathMod = platform === "win32" ? path86.win32 : path86.posix;
67363
67704
  const sep4 = platform === "win32" ? ";" : ":";
67364
67705
  const dirs = pathEnv.split(sep4).filter((d) => d.length > 0);
67365
67706
  const candidates = [bin];
@@ -68463,11 +68804,11 @@ var init_policy = __esm({
68463
68804
  });
68464
68805
 
68465
68806
  // src/cli/orchestration/facts.ts
68466
- import { promises as fs44 } from "node:fs";
68467
- import path89 from "node:path";
68807
+ import { promises as fs45 } from "node:fs";
68808
+ import path90 from "node:path";
68468
68809
  async function collectRepoFileCount(root = process.cwd()) {
68469
68810
  try {
68470
- await fs44.readdir(root);
68811
+ await fs45.readdir(root);
68471
68812
  } catch {
68472
68813
  return void 0;
68473
68814
  }
@@ -68478,13 +68819,13 @@ async function collectRepoFileCount(root = process.cwd()) {
68478
68819
  const dir = queue.pop();
68479
68820
  let entries;
68480
68821
  try {
68481
- entries = await fs44.readdir(dir, { withFileTypes: true });
68822
+ entries = await fs45.readdir(dir, { withFileTypes: true });
68482
68823
  } catch {
68483
68824
  continue;
68484
68825
  }
68485
68826
  for (const e of entries) {
68486
68827
  if (e.isDirectory()) {
68487
- if (!SKIP_DIRS.has(e.name)) queue.push(path89.join(dir, e.name));
68828
+ if (!SKIP_DIRS.has(e.name)) queue.push(path90.join(dir, e.name));
68488
68829
  } else if (e.isFile()) {
68489
68830
  count++;
68490
68831
  if (count > MAX_WALK_FILES) return count;
@@ -68582,7 +68923,7 @@ var init_streamScrub = __esm({
68582
68923
  });
68583
68924
 
68584
68925
  // src/cli/harnessState.ts
68585
- import path90 from "node:path";
68926
+ import path91 from "node:path";
68586
68927
  function asString4(v) {
68587
68928
  return typeof v === "string" ? v : "";
68588
68929
  }
@@ -68757,7 +69098,7 @@ function contractFor(t) {
68757
69098
  };
68758
69099
  }
68759
69100
  async function readHarnessState(sessionDir, cache4) {
68760
- const report = await readSessionLogCached(path90.join(sessionDir, "events.jsonl"), cache4);
69101
+ const report = await readSessionLogCached(path91.join(sessionDir, "events.jsonl"), cache4);
68761
69102
  return deriveHarnessState(report.events);
68762
69103
  }
68763
69104
  var init_harnessState = __esm({
@@ -68768,12 +69109,12 @@ var init_harnessState = __esm({
68768
69109
  });
68769
69110
 
68770
69111
  // src/cli/headless/harnessStateEmit.ts
68771
- import path91 from "node:path";
69112
+ import path92 from "node:path";
68772
69113
  async function emitHarnessStateEvent(opts) {
68773
69114
  if (opts.output !== "json") return;
68774
69115
  try {
68775
69116
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.workspaceRoot });
68776
- const state3 = await readHarnessState(path91.join(sessionsDir2, opts.spine.sessionId));
69117
+ const state3 = await readHarnessState(path92.join(sessionsDir2, opts.spine.sessionId));
68777
69118
  opts.emitEvent({ type: "harness_state", ...state3 });
68778
69119
  } catch (err) {
68779
69120
  const msg = err instanceof Error ? err.message : String(err);
@@ -69330,13 +69671,13 @@ var init_verifierLifecycle = __esm({
69330
69671
 
69331
69672
  // src/cli/extensions/sandboxedFs.ts
69332
69673
  import { promises as fsp } from "node:fs";
69333
- import path92 from "node:path";
69674
+ import path93 from "node:path";
69334
69675
  function errText(prefix, p3, err) {
69335
69676
  const msg = err instanceof Error ? err.message : String(err);
69336
69677
  return `[extension-fs] ${prefix} "${p3}": ${msg}`;
69337
69678
  }
69338
69679
  function bindSandboxedFs(root) {
69339
- const resolvedRoot = path92.resolve(root);
69680
+ const resolvedRoot = path93.resolve(root);
69340
69681
  return {
69341
69682
  root: resolvedRoot,
69342
69683
  async readFile(relativePath) {
@@ -69352,7 +69693,7 @@ function bindSandboxedFs(root) {
69352
69693
  try {
69353
69694
  const target = resolveSandboxedPath(relativePath, { root: resolvedRoot });
69354
69695
  verifyContainment(target, { root: resolvedRoot });
69355
- await fsp.mkdir(path92.dirname(target), { recursive: true });
69696
+ await fsp.mkdir(path93.dirname(target), { recursive: true });
69356
69697
  await fsp.writeFile(target, data, "utf8");
69357
69698
  return typedOk({ path: target });
69358
69699
  } catch (err) {
@@ -69379,15 +69720,15 @@ var init_sandboxedFs = __esm({
69379
69720
  });
69380
69721
 
69381
69722
  // src/cli/extensions/loader.ts
69382
- import { join as join44 } from "node:path";
69723
+ import { join as join45 } from "node:path";
69383
69724
  import { readdirSync as readdirSync11, readFileSync as readFileSync43 } from "node:fs";
69384
69725
  import { createHash as createHash25 } from "node:crypto";
69385
69726
  import { pathToFileURL as pathToFileURL3 } from "node:url";
69386
69727
  function globalExtensionsDir() {
69387
- return join44(zelariHome(), "extensions");
69728
+ return join45(zelariHome(), "extensions");
69388
69729
  }
69389
69730
  function projectExtensionsDir(projectRoot) {
69390
- return join44(projectRoot, ".zelari", "extensions");
69731
+ return join45(projectRoot, ".zelari", "extensions");
69391
69732
  }
69392
69733
  function sha256File(file2) {
69393
69734
  return createHash25("sha256").update(readFileSync43(file2)).digest("hex");
@@ -69399,7 +69740,7 @@ function candidateFiles(dir) {
69399
69740
  } catch {
69400
69741
  return [];
69401
69742
  }
69402
- return names.filter((n) => EXTENSION_FILE_EXTS.has(n.slice(n.lastIndexOf(".")).toLowerCase())).sort().map((n) => join44(dir, n));
69743
+ return names.filter((n) => EXTENSION_FILE_EXTS.has(n.slice(n.lastIndexOf(".")).toLowerCase())).sort().map((n) => join45(dir, n));
69403
69744
  }
69404
69745
  function extractExtension(mod) {
69405
69746
  const m = mod;
@@ -69421,14 +69762,14 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
69421
69762
  skipped
69422
69763
  };
69423
69764
  const fsRoot = options.fsRoot ?? process.cwd();
69424
- let fs49 = null;
69765
+ let fs50 = null;
69425
69766
  const pending = [];
69426
69767
  for (const dir of dirs) {
69427
69768
  const files = candidateFiles(dir.path);
69428
69769
  if (files.length === 0) continue;
69429
69770
  let lock = null;
69430
69771
  try {
69431
- lock = JSON.parse(readFileSync43(join44(dir.path, EXTENSIONS_LOCK_FILE), "utf8"));
69772
+ lock = JSON.parse(readFileSync43(join45(dir.path, EXTENSIONS_LOCK_FILE), "utf8"));
69432
69773
  } catch {
69433
69774
  lock = null;
69434
69775
  if (dirHasLockFile(dir.path)) {
@@ -69476,9 +69817,9 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
69476
69817
  skipped.push(`${file2}: missing ZelariExtension export`);
69477
69818
  continue;
69478
69819
  }
69479
- if (!fs49) fs49 = bindSandboxedFs(fsRoot);
69820
+ if (!fs50) fs50 = bindSandboxedFs(fsRoot);
69480
69821
  try {
69481
- await runtime.registry.registerExtension(ext, { fs: fs49 });
69822
+ await runtime.registry.registerExtension(ext, { fs: fs50 });
69482
69823
  runtime.loaded.push({ id: ext.id, file: file2, scope });
69483
69824
  } catch (err) {
69484
69825
  const msg = err instanceof Error ? err.message : String(err);
@@ -69495,7 +69836,7 @@ function basenameOf(file2) {
69495
69836
  }
69496
69837
  function dirHasLockFile(dir) {
69497
69838
  try {
69498
- readFileSync43(join44(dir, EXTENSIONS_LOCK_FILE));
69839
+ readFileSync43(join45(dir, EXTENSIONS_LOCK_FILE));
69499
69840
  return true;
69500
69841
  } catch {
69501
69842
  return false;
@@ -69536,8 +69877,8 @@ var init_loader = __esm({
69536
69877
  });
69537
69878
 
69538
69879
  // src/cli/headless/runOneTurn.ts
69539
- import { promises as fs45 } from "node:fs";
69540
- import path93 from "node:path";
69880
+ import { promises as fs46 } from "node:fs";
69881
+ import path94 from "node:path";
69541
69882
  function planModeFromOpts(opts) {
69542
69883
  return (opts.phase ?? "build") === "plan";
69543
69884
  }
@@ -69590,7 +69931,18 @@ async function writeProofSafe(gate, meta3, baseDir = process.cwd()) {
69590
69931
  `
69591
69932
  );
69592
69933
  }
69593
- await promoteOpsKnowledgeSafe(gate, { projectRoot: baseDir, sessionId: meta3.sessionId });
69934
+ return promoteOpsKnowledgeSafe(gate, { projectRoot: baseDir, sessionId: meta3.sessionId });
69935
+ }
69936
+ function surfaceOpsKnowledgeNotices(result, opts) {
69937
+ const notices = [
69938
+ ...result.proposals,
69939
+ ...result.checkProposals.map(formatCheckProposalNotice)
69940
+ ];
69941
+ for (const notice of notices) {
69942
+ if (opts.output === "json") emitEvent({ type: "log", message: notice });
69943
+ else process.stderr.write(`[zelari-code --headless] ${notice}
69944
+ `);
69945
+ }
69594
69946
  }
69595
69947
  async function runOneTurn(opts, provider, model, providerStream, extras) {
69596
69948
  const sessionId2 = crypto.randomUUID();
@@ -70031,7 +70383,10 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
70031
70383
  if (opts.output === "json") {
70032
70384
  emitEvent({ type: "verification_run", ...verificationPayload });
70033
70385
  }
70034
- await writeProofSafe(strictGate, { surface: "kraken", sessionId: spine.sessionId }, cwd);
70386
+ surfaceOpsKnowledgeNotices(
70387
+ await writeProofSafe(strictGate, { surface: "kraken", sessionId: spine.sessionId }, cwd),
70388
+ opts
70389
+ );
70035
70390
  if (strictGate.blocked) {
70036
70391
  const repairPrompt = buildKrakenRepairPrompt(gate, repairExcerptsFromEvaluation(strictGate));
70037
70392
  if (opts.output === "json") {
@@ -70065,7 +70420,10 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
70065
70420
  if (opts.output === "json") {
70066
70421
  emitEvent({ type: "verification_run", ...afterPayload });
70067
70422
  }
70068
- await writeProofSafe(after, { surface: "kraken", sessionId: spine.sessionId }, cwd);
70423
+ surfaceOpsKnowledgeNotices(
70424
+ await writeProofSafe(after, { surface: "kraken", sessionId: spine.sessionId }, cwd),
70425
+ opts
70426
+ );
70069
70427
  if (!after.blocked) markRepairSucceeded();
70070
70428
  else {
70071
70429
  strictExit = strictGateExitCode(after);
@@ -70108,8 +70466,8 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
70108
70466
  if (json3) {
70109
70467
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
70110
70468
  else {
70111
- await fs45.mkdir(path93.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70112
- await fs45.writeFile(opts.exportSessionPath, json3, "utf8");
70469
+ await fs46.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70470
+ await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
70113
70471
  }
70114
70472
  }
70115
70473
  } catch {
@@ -70175,6 +70533,7 @@ var init_runOneTurn = __esm({
70175
70533
  init_completionProof();
70176
70534
  init_completionProofPersist();
70177
70535
  init_opsKnowledge();
70536
+ init_repeatCheck();
70178
70537
  init_nativeVerification();
70179
70538
  init_verifierLifecycle();
70180
70539
  init_modelContextBuilder();
@@ -71157,10 +71516,10 @@ __export(triggerLock_exports, {
71157
71516
  lockPath: () => lockPath,
71158
71517
  releaseLock: () => releaseLock
71159
71518
  });
71160
- import { promises as fs46 } from "node:fs";
71161
- import * as path94 from "node:path";
71519
+ import { promises as fs47 } from "node:fs";
71520
+ import * as path95 from "node:path";
71162
71521
  function lockPath(projectRoot) {
71163
- return path94.join(projectRoot, ".zelari", "trigger.lock");
71522
+ return path95.join(projectRoot, ".zelari", "trigger.lock");
71164
71523
  }
71165
71524
  function isPidAlive(pid) {
71166
71525
  try {
@@ -71173,10 +71532,10 @@ function isPidAlive(pid) {
71173
71532
  }
71174
71533
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
71175
71534
  const lp = lockPath(projectRoot);
71176
- const dir = path94.dirname(lp);
71177
- await fs46.mkdir(dir, { recursive: true });
71535
+ const dir = path95.dirname(lp);
71536
+ await fs47.mkdir(dir, { recursive: true });
71178
71537
  try {
71179
- const raw = await fs46.readFile(lp, "utf8");
71538
+ const raw = await fs47.readFile(lp, "utf8");
71180
71539
  const existing = JSON.parse(raw);
71181
71540
  if (existing.pid && isPidAlive(existing.pid)) {
71182
71541
  return { acquired: false, heldBy: existing.pid, lockPath: lp };
@@ -71187,13 +71546,13 @@ async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date())
71187
71546
  pid: process.pid,
71188
71547
  acquiredAt: now().toISOString()
71189
71548
  };
71190
- await fs46.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
71549
+ await fs47.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
71191
71550
  return { acquired: true, lockPath: lp };
71192
71551
  }
71193
71552
  async function releaseLock(projectRoot) {
71194
71553
  const lp = lockPath(projectRoot);
71195
71554
  try {
71196
- await fs46.unlink(lp);
71555
+ await fs47.unlink(lp);
71197
71556
  } catch {
71198
71557
  }
71199
71558
  }
@@ -71204,8 +71563,8 @@ var init_triggerLock = __esm({
71204
71563
  });
71205
71564
 
71206
71565
  // src/cli/runHeadless.ts
71207
- import { promises as fs47 } from "node:fs";
71208
- import path95 from "node:path";
71566
+ import { promises as fs48 } from "node:fs";
71567
+ import path96 from "node:path";
71209
71568
  import { randomUUID as randomUUID10 } from "node:crypto";
71210
71569
  async function runHeadless(opts) {
71211
71570
  resetTaskSpawnCount();
@@ -71479,11 +71838,11 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
71479
71838
  try {
71480
71839
  let preflightGraph;
71481
71840
  if (opts.runPlan && opts.runPlan.trim() !== "") {
71482
- const planPath = path95.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
71841
+ const planPath = path96.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
71483
71842
  log(`loading pre-flight plan: ${planPath}`);
71484
71843
  let raw;
71485
71844
  try {
71486
- raw = await fs47.readFile(planPath, "utf8");
71845
+ raw = await fs48.readFile(planPath, "utf8");
71487
71846
  } catch (e) {
71488
71847
  log(`plan file not found: ${planPath} (${e.message})`);
71489
71848
  exitCode = 1;
@@ -71522,10 +71881,10 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
71522
71881
  log(formatKrakenGraphAscii2(graph));
71523
71882
  if (opts.planOnly) {
71524
71883
  const planId = randomUUID10();
71525
- const planDir = path95.join(cwd, ".zelari", "radio");
71526
- const planPath = path95.join(planDir, `plan-${planId}.json`);
71527
- await fs47.mkdir(planDir, { recursive: true });
71528
- await fs47.writeFile(
71884
+ const planDir = path96.join(cwd, ".zelari", "radio");
71885
+ const planPath = path96.join(planDir, `plan-${planId}.json`);
71886
+ await fs48.mkdir(planDir, { recursive: true });
71887
+ await fs48.writeFile(
71529
71888
  planPath,
71530
71889
  JSON.stringify(
71531
71890
  { id: graph.id, nodes: [...graph.nodes.values()] },
@@ -71914,8 +72273,8 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
71914
72273
  if (json3) {
71915
72274
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
71916
72275
  else {
71917
- await fs47.mkdir(path95.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
71918
- await fs47.writeFile(opts.exportSessionPath, json3, "utf8");
72276
+ await fs48.mkdir(path96.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
72277
+ await fs48.writeFile(opts.exportSessionPath, json3, "utf8");
71919
72278
  }
71920
72279
  }
71921
72280
  } catch {
@@ -72386,8 +72745,8 @@ ${ragContext}` : slicePrompt;
72386
72745
  if (json3) {
72387
72746
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
72388
72747
  else {
72389
- await fs47.mkdir(path95.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
72390
- await fs47.writeFile(opts.exportSessionPath, json3, "utf8");
72748
+ await fs48.mkdir(path96.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
72749
+ await fs48.writeFile(opts.exportSessionPath, json3, "utf8");
72391
72750
  }
72392
72751
  }
72393
72752
  } catch {
@@ -72850,7 +73209,7 @@ import {
72850
73209
  rmSync as rmSync4,
72851
73210
  writeFileSync as writeFileSync25
72852
73211
  } from "node:fs";
72853
- import { dirname as dirname13, join as join46 } from "node:path";
73212
+ import { dirname as dirname14, join as join47 } from "node:path";
72854
73213
  function ensureBuiltinSkillsLoadedSync() {
72855
73214
  if (builtinsLoaded) return;
72856
73215
  for (const spec of BUILTIN_SKILL_MODULES) {
@@ -72861,13 +73220,13 @@ function ensureBuiltinSkillsLoadedSync() {
72861
73220
  }
72862
73221
  }
72863
73222
  function getUserSkillsDir() {
72864
- return join46(zelariHome(), "skills");
73223
+ return join47(zelariHome(), "skills");
72865
73224
  }
72866
73225
  function getProjectSkillsDir(projectRoot) {
72867
- return join46(projectRoot, ".zelari", "skills");
73226
+ return join47(projectRoot, ".zelari", "skills");
72868
73227
  }
72869
73228
  function skillFilePath(dir, name) {
72870
- return join46(dir, name, "SKILL.md");
73229
+ return join47(dir, name, "SKILL.md");
72871
73230
  }
72872
73231
  function classifyScope(skillPath, projectRoot) {
72873
73232
  const userDir = getUserSkillsDir().replace(/\\/g, "/");
@@ -72943,9 +73302,9 @@ function listSkillsSnapshot(projectRoot) {
72943
73302
  const skills = [];
72944
73303
  const seen = /* @__PURE__ */ new Set();
72945
73304
  if (root) {
72946
- scanSkillsDir(join46(root, ".zelari", "skills"), root, seen, skills);
72947
- scanSkillsDir(join46(root, ".claude", "skills"), root, seen, skills);
72948
- scanSkillsDir(join46(root, ".opencode", "skills"), root, seen, skills);
73305
+ scanSkillsDir(join47(root, ".zelari", "skills"), root, seen, skills);
73306
+ scanSkillsDir(join47(root, ".claude", "skills"), root, seen, skills);
73307
+ scanSkillsDir(join47(root, ".opencode", "skills"), root, seen, skills);
72949
73308
  }
72950
73309
  scanSkillsDir(userSkillsDir, root, seen, skills);
72951
73310
  for (const s of listCodingSkills()) {
@@ -73011,7 +73370,7 @@ function upsertSkill(opts) {
73011
73370
  }
73012
73371
  dir = getProjectSkillsDir(root);
73013
73372
  }
73014
- const path102 = skillFilePath(dir, name);
73373
+ const path103 = skillFilePath(dir, name);
73015
73374
  const content = serializeSkillMd({
73016
73375
  name,
73017
73376
  description,
@@ -73020,13 +73379,13 @@ function upsertSkill(opts) {
73020
73379
  tools: opts.tools,
73021
73380
  cost: opts.cost
73022
73381
  });
73023
- const parsed = parseSkillMd(content, path102);
73382
+ const parsed = parseSkillMd(content, path103);
73024
73383
  if (!parsed) {
73025
73384
  return { ok: false, error: "Generated SKILL.md failed validation" };
73026
73385
  }
73027
- mkdirSync23(dirname13(path102), { recursive: true });
73028
- writeFileSync25(path102, content, "utf8");
73029
- return { ok: true, path: path102 };
73386
+ mkdirSync23(dirname14(path103), { recursive: true });
73387
+ writeFileSync25(path103, content, "utf8");
73388
+ return { ok: true, path: path103 };
73030
73389
  }
73031
73390
  function removeSkill(opts) {
73032
73391
  const name = opts.name.trim().toLowerCase();
@@ -73043,9 +73402,9 @@ function removeSkill(opts) {
73043
73402
  }
73044
73403
  dir = getProjectSkillsDir(root);
73045
73404
  }
73046
- const skillDir = join46(dir, name);
73047
- const path102 = skillFilePath(dir, name);
73048
- if (!existsSync59(path102) && !existsSync59(skillDir)) {
73405
+ const skillDir = join47(dir, name);
73406
+ const path103 = skillFilePath(dir, name);
73407
+ if (!existsSync59(path103) && !existsSync59(skillDir)) {
73049
73408
  return { ok: false, error: `Skill "${name}" not found in ${dir}` };
73050
73409
  }
73051
73410
  try {
@@ -73056,7 +73415,7 @@ function removeSkill(opts) {
73056
73415
  error: err instanceof Error ? err.message : String(err)
73057
73416
  };
73058
73417
  }
73059
- return { ok: true, path: path102 };
73418
+ return { ok: true, path: path103 };
73060
73419
  }
73061
73420
  var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
73062
73421
  var init_skillConfigIo = __esm({
@@ -73177,7 +73536,7 @@ var init_jsonApi = __esm({
73177
73536
  });
73178
73537
 
73179
73538
  // src/cli/memory/mcpAdapter.ts
73180
- import * as path96 from "node:path";
73539
+ import * as path97 from "node:path";
73181
73540
  var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
73182
73541
  var init_mcpAdapter = __esm({
73183
73542
  "src/cli/memory/mcpAdapter.ts"() {
@@ -73347,8 +73706,8 @@ var init_mcpAdapter = __esm({
73347
73706
  this.takeWrite();
73348
73707
  const externalFile = args.source?.file;
73349
73708
  if (externalFile) {
73350
- const normalized = path96.normalize(externalFile);
73351
- if (path96.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path96.sep}`)) {
73709
+ const normalized = path97.normalize(externalFile);
73710
+ if (path97.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path97.sep}`)) {
73352
73711
  throw new Error("source.file must be project-relative and cannot escape the project");
73353
73712
  }
73354
73713
  }
@@ -73857,16 +74216,16 @@ import {
73857
74216
  readFileSync as readFileSync45,
73858
74217
  writeFileSync as writeFileSync26
73859
74218
  } from "node:fs";
73860
- import { join as join47 } from "node:path";
74219
+ import { join as join48 } from "node:path";
73861
74220
  import { createHash as createHash26, randomBytes as randomBytes7, timingSafeEqual } from "node:crypto";
73862
74221
  function getZelariHome() {
73863
74222
  return zelariHome();
73864
74223
  }
73865
74224
  function getCompanionConfigPath() {
73866
- return join47(getZelariHome(), "companion.json");
74225
+ return join48(getZelariHome(), "companion.json");
73867
74226
  }
73868
74227
  function getCompanionTokenPath() {
73869
- return join47(getZelariHome(), "companion.token");
74228
+ return join48(getZelariHome(), "companion.token");
73870
74229
  }
73871
74230
  function ensureHome() {
73872
74231
  const home = getZelariHome();
@@ -73875,12 +74234,12 @@ function ensureHome() {
73875
74234
  }
73876
74235
  }
73877
74236
  function loadCompanionConfig() {
73878
- const path102 = getCompanionConfigPath();
73879
- if (!existsSync60(path102)) {
74237
+ const path103 = getCompanionConfigPath();
74238
+ if (!existsSync60(path103)) {
73880
74239
  return { projects: [] };
73881
74240
  }
73882
74241
  try {
73883
- const raw = JSON.parse(readFileSync45(path102, "utf8"));
74242
+ const raw = JSON.parse(readFileSync45(path103, "utf8"));
73884
74243
  const projects = Array.isArray(raw.projects) ? raw.projects.filter(
73885
74244
  (p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
73886
74245
  ).map((p3) => ({
@@ -73918,16 +74277,16 @@ function loadOrCreateToken(explicit) {
73918
74277
  return { token: explicit.trim(), created: false };
73919
74278
  }
73920
74279
  ensureHome();
73921
- const path102 = getCompanionTokenPath();
73922
- if (existsSync60(path102)) {
73923
- const t = readFileSync45(path102, "utf8").trim();
74280
+ const path103 = getCompanionTokenPath();
74281
+ if (existsSync60(path103)) {
74282
+ const t = readFileSync45(path103, "utf8").trim();
73924
74283
  if (t) return { token: t, created: false };
73925
74284
  }
73926
74285
  const token = randomBytes7(24).toString("base64url");
73927
- writeFileSync26(path102, token + "\n", "utf8");
74286
+ writeFileSync26(path103, token + "\n", "utf8");
73928
74287
  try {
73929
- const fs49 = __require("node:fs");
73930
- fs49.chmodSync?.(path102, 384);
74288
+ const fs50 = __require("node:fs");
74289
+ fs50.chmodSync?.(path103, 384);
73931
74290
  } catch {
73932
74291
  }
73933
74292
  return { token, created: true };
@@ -73952,17 +74311,17 @@ function mergeProjects(cfg, extraPaths) {
73952
74311
  byId.set(p3.id, p3);
73953
74312
  }
73954
74313
  for (const raw of extraPaths) {
73955
- const path102 = raw.trim();
73956
- if (!path102) continue;
73957
- let id3 = slugFromPath(path102);
74314
+ const path103 = raw.trim();
74315
+ if (!path103) continue;
74316
+ let id3 = slugFromPath(path103);
73958
74317
  let n = 2;
73959
- while (byId.has(id3) && byId.get(id3).path !== path102) {
73960
- id3 = `${slugFromPath(path102)}-${n++}`;
74318
+ while (byId.has(id3) && byId.get(id3).path !== path103) {
74319
+ id3 = `${slugFromPath(path103)}-${n++}`;
73961
74320
  }
73962
74321
  byId.set(id3, {
73963
74322
  id: id3,
73964
- name: slugFromPath(path102),
73965
- path: path102
74323
+ name: slugFromPath(path103),
74324
+ path: path103
73966
74325
  });
73967
74326
  }
73968
74327
  return [...byId.values()];
@@ -74204,8 +74563,8 @@ var init_askUserBridge = __esm({
74204
74563
  });
74205
74564
 
74206
74565
  // src/cli/serve/spineLockSweep.ts
74207
- import { promises as fs48 } from "node:fs";
74208
- import path97 from "node:path";
74566
+ import { promises as fs49 } from "node:fs";
74567
+ import path98 from "node:path";
74209
74568
  async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
74210
74569
  const dir = sessionsDir2 ?? resolveSessionsDir();
74211
74570
  const onSwept = options.onSwept ?? ((sessionId2, reason) => {
@@ -74218,14 +74577,14 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
74218
74577
  const result = { swept: 0, kept: 0, errors: 0 };
74219
74578
  let entries;
74220
74579
  try {
74221
- entries = await fs48.readdir(dir);
74580
+ entries = await fs49.readdir(dir);
74222
74581
  } catch {
74223
74582
  return result;
74224
74583
  }
74225
74584
  for (const sessionId2 of entries) {
74226
- const lockPath2 = path97.join(dir, sessionId2, "writer.lock");
74585
+ const lockPath2 = path98.join(dir, sessionId2, "writer.lock");
74227
74586
  try {
74228
- const raw = await fs48.readFile(lockPath2, "utf-8");
74587
+ const raw = await fs49.readFile(lockPath2, "utf-8");
74229
74588
  let lockInfo = {};
74230
74589
  try {
74231
74590
  lockInfo = JSON.parse(raw);
@@ -74242,7 +74601,7 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
74242
74601
  result.kept += 1;
74243
74602
  continue;
74244
74603
  }
74245
- await fs48.rm(lockPath2, { force: true });
74604
+ await fs49.rm(lockPath2, { force: true });
74246
74605
  result.swept += 1;
74247
74606
  onSwept(sessionId2, verdict.reason);
74248
74607
  } catch (err) {
@@ -74676,7 +75035,7 @@ import { spawn as spawn18 } from "node:child_process";
74676
75035
  import { createInterface as createInterface4 } from "node:readline";
74677
75036
  import { randomUUID as randomUUID13 } from "node:crypto";
74678
75037
  import { writeFileSync as writeFileSync27, unlinkSync as unlinkSync3 } from "node:fs";
74679
- import { join as join48 } from "node:path";
75038
+ import { join as join49 } from "node:path";
74680
75039
  import { tmpdir as tmpdir4 } from "node:os";
74681
75040
  function harnessServerMode() {
74682
75041
  return process.env[HARNESS_SERVER_ENV] === "1";
@@ -74798,7 +75157,7 @@ var init_runManager = __esm({
74798
75157
  }
74799
75158
  let historyFile;
74800
75159
  if (args.history && Array.isArray(args.history) && args.history.length > 0) {
74801
- historyFile = join48(tmpdir4(), `zelari-companion-hist-${id3}.json`);
75160
+ historyFile = join49(tmpdir4(), `zelari-companion-hist-${id3}.json`);
74802
75161
  try {
74803
75162
  writeFileSync27(historyFile, JSON.stringify(args.history), "utf8");
74804
75163
  argv.push("--history-file", historyFile);
@@ -75221,9 +75580,9 @@ async function runCompanionServe(opts = {}) {
75221
75580
  return;
75222
75581
  }
75223
75582
  const url2 = parseUrl(req);
75224
- const path102 = url2.pathname.replace(/\/+$/, "") || "/";
75583
+ const path103 = url2.pathname.replace(/\/+$/, "") || "/";
75225
75584
  try {
75226
- if (req.method === "GET" && (path102 === "/health" || path102 === "/v1/health")) {
75585
+ if (req.method === "GET" && (path103 === "/health" || path103 === "/v1/health")) {
75227
75586
  sendJson2(res, 200, {
75228
75587
  ok: true,
75229
75588
  service: "zelari-companion",
@@ -75235,18 +75594,18 @@ async function runCompanionServe(opts = {}) {
75235
75594
  });
75236
75595
  return;
75237
75596
  }
75238
- if (path102.startsWith("/v1")) {
75597
+ if (path103.startsWith("/v1")) {
75239
75598
  if (!tokenMatches(token, getBearer(req))) {
75240
75599
  sendJson2(res, 401, { ok: false, error: "unauthorized" });
75241
75600
  return;
75242
75601
  }
75243
75602
  }
75244
- if (req.method === "GET" && path102 === "/v1/config") {
75603
+ if (req.method === "GET" && path103 === "/v1/config") {
75245
75604
  const snap = buildDesktopConfigSnapshot();
75246
75605
  sendJson2(res, 200, { ok: true, ...snap });
75247
75606
  return;
75248
75607
  }
75249
- if (req.method === "GET" && path102 === "/v1/projects") {
75608
+ if (req.method === "GET" && path103 === "/v1/projects") {
75250
75609
  sendJson2(res, 200, {
75251
75610
  ok: true,
75252
75611
  projects: projects.map((p3) => ({
@@ -75257,7 +75616,7 @@ async function runCompanionServe(opts = {}) {
75257
75616
  });
75258
75617
  return;
75259
75618
  }
75260
- if (req.method === "GET" && path102 === "/v1/runs") {
75619
+ if (req.method === "GET" && path103 === "/v1/runs") {
75261
75620
  sendJson2(res, 200, {
75262
75621
  ok: true,
75263
75622
  active: runs.getActive(),
@@ -75275,7 +75634,7 @@ async function runCompanionServe(opts = {}) {
75275
75634
  });
75276
75635
  return;
75277
75636
  }
75278
- if (req.method === "POST" && path102 === "/v1/runs") {
75637
+ if (req.method === "POST" && path103 === "/v1/runs") {
75279
75638
  const raw = await readBody(req);
75280
75639
  let body = {};
75281
75640
  try {
@@ -75323,7 +75682,7 @@ async function runCompanionServe(opts = {}) {
75323
75682
  });
75324
75683
  return;
75325
75684
  }
75326
- const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path102);
75685
+ const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path103);
75327
75686
  if (req.method === "GET" && eventsMatch) {
75328
75687
  const runId = eventsMatch[1];
75329
75688
  const run = runs.getRun(runId);
@@ -75388,7 +75747,7 @@ async function runCompanionServe(opts = {}) {
75388
75747
  }, 500);
75389
75748
  return;
75390
75749
  }
75391
- const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path102);
75750
+ const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path103);
75392
75751
  if (req.method === "POST" && cancelMatch) {
75393
75752
  const runId = cancelMatch[1];
75394
75753
  const result = runs.cancel(runId);
@@ -75399,7 +75758,7 @@ async function runCompanionServe(opts = {}) {
75399
75758
  sendJson2(res, 200, { ok: true, cancelled: runId });
75400
75759
  return;
75401
75760
  }
75402
- const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path102);
75761
+ const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path103);
75403
75762
  if (req.method === "POST" && steerMatch) {
75404
75763
  const runId = steerMatch[1];
75405
75764
  const raw = await readBody(req);
@@ -75568,11 +75927,11 @@ import { execSync as execSync2 } from "node:child_process";
75568
75927
  import { existsSync as existsSync62, readFileSync as readFileSync46, readlinkSync, statSync as statSync10 } from "node:fs";
75569
75928
  import { createRequire as createRequire3 } from "node:module";
75570
75929
  import { fileURLToPath as fileURLToPath3 } from "node:url";
75571
- import path98 from "node:path";
75930
+ import path99 from "node:path";
75572
75931
  function findPackageRoot(start) {
75573
75932
  let dir = start;
75574
75933
  for (let i = 0; i < 6; i += 1) {
75575
- const candidate = path98.join(dir, "package.json");
75934
+ const candidate = path99.join(dir, "package.json");
75576
75935
  if (existsSync62(candidate)) {
75577
75936
  try {
75578
75937
  const pkg = JSON.parse(readFileSync46(candidate, "utf8"));
@@ -75580,11 +75939,11 @@ function findPackageRoot(start) {
75580
75939
  } catch {
75581
75940
  }
75582
75941
  }
75583
- const parent = path98.dirname(dir);
75942
+ const parent = path99.dirname(dir);
75584
75943
  if (parent === dir) break;
75585
75944
  dir = parent;
75586
75945
  }
75587
- return path98.resolve(__dirname3, "..", "..", "..");
75946
+ return path99.resolve(__dirname3, "..", "..", "..");
75588
75947
  }
75589
75948
  function tryExec(cmd) {
75590
75949
  try {
@@ -75598,7 +75957,7 @@ function tryExec(cmd) {
75598
75957
  }
75599
75958
  function readPackageJson4() {
75600
75959
  try {
75601
- const pkgPath = path98.join(packageRoot, "package.json");
75960
+ const pkgPath = path99.join(packageRoot, "package.json");
75602
75961
  return JSON.parse(readFileSync46(pkgPath, "utf8"));
75603
75962
  } catch {
75604
75963
  return null;
@@ -75610,7 +75969,7 @@ function getGlobalPrefix() {
75610
75969
  return (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || "").trim();
75611
75970
  }
75612
75971
  function isSourceCheckout() {
75613
- return existsSync62(path98.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path98.join(packageRoot, "apps", "desktop", "package.json"));
75972
+ return existsSync62(path99.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path99.join(packageRoot, "apps", "desktop", "package.json"));
75614
75973
  }
75615
75974
  function checkShim(pkgName) {
75616
75975
  const prefix = getGlobalPrefix();
@@ -75619,9 +75978,9 @@ function checkShim(pkgName) {
75619
75978
  }
75620
75979
  const isWin = process.platform === "win32";
75621
75980
  const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
75622
- const shimPath = path98.join(prefix, shimName);
75981
+ const shimPath = path99.join(prefix, shimName);
75623
75982
  if (!existsSync62(shimPath)) {
75624
- const localBin = path98.join(packageRoot, "bin", "zelari-code.js");
75983
+ const localBin = path99.join(packageRoot, "bin", "zelari-code.js");
75625
75984
  if (isSourceCheckout() && existsSync62(localBin)) {
75626
75985
  return WARN(
75627
75986
  `global shim not found at ${shimPath}
@@ -75655,8 +76014,8 @@ function checkShim(pkgName) {
75655
76014
  fix: npm install -g ${pkgName}@latest --force`
75656
76015
  );
75657
76016
  }
75658
- const resolved = path98.resolve(path98.dirname(shimPath), target);
75659
- const expected = path98.join(
76017
+ const resolved = path99.resolve(path99.dirname(shimPath), target);
76018
+ const expected = path99.join(
75660
76019
  prefix,
75661
76020
  "node_modules",
75662
76021
  pkgName,
@@ -75698,7 +76057,7 @@ function checkNode(pkg) {
75698
76057
  return OK(`node ${raw} (engines.node ${enginesNode ?? ">= 20.0.0"})`);
75699
76058
  }
75700
76059
  function checkBundle() {
75701
- const bundle = path98.join(packageRoot, "dist", "cli", "main.bundled.js");
76060
+ const bundle = path99.join(packageRoot, "dist", "cli", "main.bundled.js");
75702
76061
  if (!existsSync62(bundle)) {
75703
76062
  return FAIL(
75704
76063
  `dist/cli/main.bundled.js missing at ${bundle}
@@ -75719,7 +76078,7 @@ function checkRuntimeDeps() {
75719
76078
  const missing = [];
75720
76079
  for (const dep of required2) {
75721
76080
  try {
75722
- const localReq = createRequire3(path98.join(packageRoot, "package.json"));
76081
+ const localReq = createRequire3(path99.join(packageRoot, "package.json"));
75723
76082
  localReq.resolve(dep);
75724
76083
  } catch {
75725
76084
  missing.push(dep);
@@ -75996,7 +76355,7 @@ var init_doctor = __esm({
75996
76355
  init_metrics3();
75997
76356
  init_contextGrowthSummary();
75998
76357
  require3 = createRequire3(import.meta.url);
75999
- __dirname3 = path98.dirname(fileURLToPath3(import.meta.url));
76358
+ __dirname3 = path99.dirname(fileURLToPath3(import.meta.url));
76000
76359
  packageRoot = findPackageRoot(__dirname3);
76001
76360
  OK = (message) => ({
76002
76361
  ok: true,
@@ -76105,7 +76464,7 @@ __export(userSettings_exports, {
76105
76464
  settingsOverrides: () => settingsOverrides
76106
76465
  });
76107
76466
  import { existsSync as existsSync63, readFileSync as readFileSync47 } from "node:fs";
76108
- import path99 from "node:path";
76467
+ import path100 from "node:path";
76109
76468
  function parseBool(raw) {
76110
76469
  const v = raw.trim().toLowerCase();
76111
76470
  if (["1", "true", "yes", "on"].includes(v)) return true;
@@ -76172,8 +76531,8 @@ function envValueFor(key, env) {
76172
76531
  function resolveUserSettings(opts = {}) {
76173
76532
  const cwd = opts.cwd ?? process.cwd();
76174
76533
  const env = opts.env ?? process.env;
76175
- const userPath = path99.join(zelariHome(), SETTINGS_FILE_NAME);
76176
- const projectPath = path99.join(cwd, ".zelari", SETTINGS_FILE_NAME);
76534
+ const userPath = path100.join(zelariHome(), SETTINGS_FILE_NAME);
76535
+ const projectPath = path100.join(cwd, ".zelari", SETTINGS_FILE_NAME);
76177
76536
  const warnings = [];
76178
76537
  const userLayer = loadFileLayer(userPath, "user", warnings);
76179
76538
  const projectLayer = loadFileLayer(projectPath, "project", warnings);
@@ -76387,7 +76746,7 @@ __export(inspectSession_exports, {
76387
76746
  renderInspectReport: () => renderInspectReport,
76388
76747
  runInspectSession: () => runInspectSession
76389
76748
  });
76390
- import path100 from "node:path";
76749
+ import path101 from "node:path";
76391
76750
  import { existsSync as existsSync64 } from "node:fs";
76392
76751
  function formatLimit(limit) {
76393
76752
  return `${Math.round(limit / 1e3)}k`;
@@ -76421,8 +76780,8 @@ function renderInspectReport(state3) {
76421
76780
  }
76422
76781
  async function runInspectSession(opts) {
76423
76782
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.cwd ?? process.cwd() });
76424
- const sessionDir = path100.join(sessionsDir2, opts.sessionId);
76425
- const eventsPath = path100.join(sessionDir, "events.jsonl");
76783
+ const sessionDir = path101.join(sessionsDir2, opts.sessionId);
76784
+ const eventsPath = path101.join(sessionDir, "events.jsonl");
76426
76785
  if (!existsSync64(sessionDir)) {
76427
76786
  console.error(`zelari-code inspect: no session directory at ${sessionDir}`);
76428
76787
  return 1;
@@ -76456,14 +76815,14 @@ __export(inspect_exports, {
76456
76815
  collectInspectReport: () => collectInspectReport,
76457
76816
  runInspect: () => runInspect
76458
76817
  });
76459
- import path101 from "node:path";
76818
+ import path102 from "node:path";
76460
76819
  import { existsSync as existsSync65, readFileSync as readFileSync48, readdirSync as readdirSync13 } from "node:fs";
76461
76820
  async function collectInspectReport(cwd = process.cwd()) {
76462
76821
  ensureBuiltinSkillsLoadedSync();
76463
76822
  const snap = listSkillsSnapshot(cwd);
76464
76823
  const mcp = listMcpServers(cwd);
76465
- const userMcpPath = path101.join(zelariHome(), "mcp.json");
76466
- const projectMcpPath = path101.join(cwd, ".zelari", "mcp.json");
76824
+ const userMcpPath = path102.join(zelariHome(), "mcp.json");
76825
+ const projectMcpPath = path102.join(cwd, ".zelari", "mcp.json");
76467
76826
  const globalHooks = globalHooksDir();
76468
76827
  const projectHooks = projectHooksDir(cwd);
76469
76828
  const projectTrusted = isFolderTrusted(cwd);
@@ -76491,9 +76850,9 @@ async function collectInspectReport(cwd = process.cwd()) {
76491
76850
  configSources: [
76492
76851
  { path: userMcpPath, exists: existsSync65(userMcpPath) },
76493
76852
  { path: projectMcpPath, exists: existsSync65(projectMcpPath) },
76494
- { path: path101.join(zelariHome(), "provider.json"), exists: existsSync65(path101.join(zelariHome(), "provider.json")) },
76495
- { path: path101.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync65(path101.join(cwd, ".zelari", "AGENTS.md")) },
76496
- { path: path101.join(cwd, "AGENTS.md"), exists: existsSync65(path101.join(cwd, "AGENTS.md")) }
76853
+ { path: path102.join(zelariHome(), "provider.json"), exists: existsSync65(path102.join(zelariHome(), "provider.json")) },
76854
+ { path: path102.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync65(path102.join(cwd, ".zelari", "AGENTS.md")) },
76855
+ { path: path102.join(cwd, "AGENTS.md"), exists: existsSync65(path102.join(cwd, "AGENTS.md")) }
76497
76856
  ],
76498
76857
  skills: {
76499
76858
  total: snap.skills.length,
@@ -76533,8 +76892,8 @@ function listJsonFiles(dir) {
76533
76892
  }
76534
76893
  function findAgentsMd(cwd) {
76535
76894
  const candidates = [
76536
- path101.join(cwd, "AGENTS.md"),
76537
- path101.join(cwd, ".zelari", "AGENTS.md")
76895
+ path102.join(cwd, "AGENTS.md"),
76896
+ path102.join(cwd, ".zelari", "AGENTS.md")
76538
76897
  ];
76539
76898
  const found = [];
76540
76899
  for (const c of candidates) {
@@ -79566,6 +79925,7 @@ init_completionGate();
79566
79925
  init_verificationBridge();
79567
79926
  init_completionProof();
79568
79927
  init_opsKnowledge();
79928
+ init_repeatCheck();
79569
79929
  init_verifyStatus();
79570
79930
  init_nativeVerification();
79571
79931
  init_spineTelemetry();
@@ -80199,10 +80559,17 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
80199
80559
  () => void 0,
80200
80560
  () => void 0
80201
80561
  );
80202
- await promoteOpsKnowledgeSafe(gate, {
80562
+ const opsKnowledge = await promoteOpsKnowledgeSafe(gate, {
80203
80563
  projectRoot: process.cwd(),
80204
80564
  sessionId: sessionId2
80205
80565
  });
80566
+ const notices = [
80567
+ ...opsKnowledge.proposals,
80568
+ ...opsKnowledge.checkProposals.map(formatCheckProposalNotice)
80569
+ ];
80570
+ if (notices.length > 0) {
80571
+ appendSystem(setMessages, notices.join("\n"), Date.now());
80572
+ }
80206
80573
  };
80207
80574
  if (event.reason === "completed" && !krakenRepairEnqueued && (isKrakenSelectionEnabled() || nativePackEnabled()) && workPhase === "build") {
80208
80575
  const strictGate = await evaluateStrictBuildGate("build", { emit: krakenSpineEmit });
@@ -81741,10 +82108,10 @@ init_ledger();
81741
82108
 
81742
82109
  // src/cli/evolution/proposals.ts
81743
82110
  import { existsSync as existsSync51, readFileSync as readFileSync39 } from "node:fs";
81744
- import path80 from "node:path";
81745
- var PROPOSALS_REL = path80.join(".zelari", "evolution", "proposals.jsonl");
82111
+ import path81 from "node:path";
82112
+ var PROPOSALS_REL = path81.join(".zelari", "evolution", "proposals.jsonl");
81746
82113
  function proposalsPath(cwd) {
81747
- return path80.join(cwd, PROPOSALS_REL);
82114
+ return path81.join(cwd, PROPOSALS_REL);
81748
82115
  }
81749
82116
  function readProposalStore(cwd) {
81750
82117
  const file2 = proposalsPath(cwd);
@@ -82868,9 +83235,12 @@ function handleCacheStats(ctx) {
82868
83235
  // src/cli/slashHandlers/memory.ts
82869
83236
  init_messageHelpers();
82870
83237
  init_serviceFactory();
83238
+ init_howWeTest();
82871
83239
  init_promotion();
82872
- import { promises as fs36 } from "node:fs";
82873
- import * as path81 from "node:path";
83240
+ init_repeatCheck();
83241
+ init_worldModel();
83242
+ import { promises as fs37 } from "node:fs";
83243
+ import * as path82 from "node:path";
82874
83244
  var USAGE = [
82875
83245
  "/memory \u2014 backend summary",
82876
83246
  "/memory search <query>",
@@ -82882,6 +83252,8 @@ var USAGE = [
82882
83252
  "/memory consolidate [query]",
82883
83253
  "/memory index [--force]",
82884
83254
  "/memory promote <id> \u2014 append durable knowledge to managed AGENTS.md section",
83255
+ '/memory promote con-<fp> --as-check --command "<cmd>" [--expect-exit N] \u2014 append a WorldCheck',
83256
+ "/memory how-we-test \u2014 regenerate .zelari/how-we-test.md from verified procedures",
82885
83257
  "/memory stats | doctor | export [project-relative-path]",
82886
83258
  "/memory audit \u2014 read-only decay + contradiction report (nothing is mutated)"
82887
83259
  ].join("\n ");
@@ -82894,24 +83266,24 @@ function sourceLine(source2) {
82894
83266
  return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
82895
83267
  }
82896
83268
  function isInside(root, target) {
82897
- const relative6 = path81.relative(root, target);
82898
- return relative6 === "" || !relative6.startsWith("..") && !path81.isAbsolute(relative6);
83269
+ const relative6 = path82.relative(root, target);
83270
+ return relative6 === "" || !relative6.startsWith("..") && !path82.isAbsolute(relative6);
82899
83271
  }
82900
83272
  async function safeExportPath(cwd, requested) {
82901
- const lexicalRoot = path81.resolve(cwd);
82902
- const root = await fs36.realpath(lexicalRoot).catch(() => lexicalRoot);
82903
- const fallback = path81.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
82904
- const target = requested?.trim() ? path81.resolve(root, requested.trim()) : fallback;
83273
+ const lexicalRoot = path82.resolve(cwd);
83274
+ const root = await fs37.realpath(lexicalRoot).catch(() => lexicalRoot);
83275
+ const fallback = path82.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
83276
+ const target = requested?.trim() ? path82.resolve(root, requested.trim()) : fallback;
82905
83277
  if (!isInside(root, target)) {
82906
83278
  throw new Error("Export path must stay inside the active project.");
82907
83279
  }
82908
- const parent = path81.dirname(target);
82909
- const relativeParent = path81.relative(root, parent);
83280
+ const parent = path82.dirname(target);
83281
+ const relativeParent = path82.relative(root, parent);
82910
83282
  let cursor = root;
82911
- for (const segment of relativeParent.split(path81.sep).filter(Boolean)) {
82912
- cursor = path81.join(cursor, segment);
83283
+ for (const segment of relativeParent.split(path82.sep).filter(Boolean)) {
83284
+ cursor = path82.join(cursor, segment);
82913
83285
  try {
82914
- const stat8 = await fs36.lstat(cursor);
83286
+ const stat8 = await fs37.lstat(cursor);
82915
83287
  if (stat8.isSymbolicLink()) {
82916
83288
  throw new Error("Export path must not traverse a symbolic link.");
82917
83289
  }
@@ -82921,7 +83293,7 @@ async function safeExportPath(cwd, requested) {
82921
83293
  }
82922
83294
  }
82923
83295
  try {
82924
- if ((await fs36.lstat(target)).isSymbolicLink()) {
83296
+ if ((await fs37.lstat(target)).isSymbolicLink()) {
82925
83297
  throw new Error("Export target must not be a symbolic link.");
82926
83298
  }
82927
83299
  } catch (error51) {
@@ -83058,10 +83430,21 @@ ${message}` : message
83058
83430
  );
83059
83431
  return;
83060
83432
  }
83433
+ case "how-we-test": {
83434
+ const result = await regenerateHowWeTest(memory, ctx.cwd);
83435
+ emit(result.written ? `[memory] how-we-test written to ${result.path} (${result.rows} procedure(s))` : `[memory] how-we-test not written: ${result.reason ?? "nothing to project"}.`);
83436
+ return;
83437
+ }
83061
83438
  case "promote": {
83062
- const memoryId = args[0];
83439
+ const parsed = parsePromoteArgs(args);
83440
+ if (parsed.error) {
83441
+ emit(`[memory] ${parsed.error}
83442
+ ${PROMOTE_USAGE}`);
83443
+ return;
83444
+ }
83445
+ const memoryId = parsed.id;
83063
83446
  if (!memoryId) {
83064
- emit("Usage: /memory promote <id>");
83447
+ emit(PROMOTE_USAGE);
83065
83448
  return;
83066
83449
  }
83067
83450
  const node = await memory.get(memoryId);
@@ -83069,6 +83452,26 @@ ${message}` : message
83069
83452
  emit(`[memory] ${memoryId} not found in this project.`);
83070
83453
  return;
83071
83454
  }
83455
+ if (parsed.asCheck) {
83456
+ const constraint = constraintFromNode(node);
83457
+ if (!constraint) {
83458
+ emit(`[memory] ${memoryId} is not a repeat-failure constraint (no fingerprint/command/digest) \u2014 nothing to turn into a check.`);
83459
+ return;
83460
+ }
83461
+ const nodes = await listVerifiedProcedureNodes(memory);
83462
+ const proposal = proposalFromConstraint(constraint, nodes ?? []);
83463
+ const check2 = confirmCheck(proposal, {
83464
+ command: parsed.command,
83465
+ ...parsed.expectExit === void 0 ? {} : { expectExit: parsed.expectExit }
83466
+ });
83467
+ if (!check2) {
83468
+ emit(checkConfirmationHint(proposal));
83469
+ return;
83470
+ }
83471
+ const appended = await appendWorldCheck(ctx.cwd, check2);
83472
+ emit(appended.added ? `[memory] check \u201C${check2.id}\u201D appended to ${appended.path} (${appended.count} check(s))` : `[memory] check \u201C${check2.id}\u201D already present in ${appended.path} \u2014 file untouched.`);
83473
+ return;
83474
+ }
83072
83475
  const promoted = await promoteMemoryToAgentsMd(ctx.cwd, node);
83073
83476
  emit(promoted.added ? `[memory] promoted ${memoryId} to ${promoted.path}` : `[memory] ${memoryId} not promoted: ${promoted.reason ?? "policy rejected it"}.`);
83074
83477
  return;
@@ -83081,13 +83484,13 @@ ${message}` : message
83081
83484
  }
83082
83485
  case "export": {
83083
83486
  const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
83084
- await fs36.mkdir(path81.dirname(target), { recursive: true });
83085
- const root = await fs36.realpath(ctx.cwd).catch(() => path81.resolve(ctx.cwd));
83086
- const realParent = await fs36.realpath(path81.dirname(target));
83487
+ await fs37.mkdir(path82.dirname(target), { recursive: true });
83488
+ const root = await fs37.realpath(ctx.cwd).catch(() => path82.resolve(ctx.cwd));
83489
+ const realParent = await fs37.realpath(path82.dirname(target));
83087
83490
  if (!isInside(root, realParent)) {
83088
83491
  throw new Error("Export path resolves outside the active project.");
83089
83492
  }
83090
- await fs36.writeFile(target, JSON.stringify(await memory.export(), null, 2) + "\n", "utf8");
83493
+ await fs37.writeFile(target, JSON.stringify(await memory.export(), null, 2) + "\n", "utf8");
83091
83494
  emit(`[memory] export written to ${target}`);
83092
83495
  return;
83093
83496
  }
@@ -83329,13 +83732,13 @@ ${digest}
83329
83732
  init_auditLogger();
83330
83733
  init_toolRegistry();
83331
83734
  init_messageHelpers();
83332
- import { promises as fs38 } from "node:fs";
83735
+ import { promises as fs39 } from "node:fs";
83333
83736
 
83334
83737
  // src/cli/tools/krakenCsvFanout.ts
83335
83738
  init_zod();
83336
83739
  init_taskTool();
83337
- import { promises as fs37 } from "node:fs";
83338
- import path82 from "node:path";
83740
+ import { promises as fs38 } from "node:fs";
83741
+ import path83 from "node:path";
83339
83742
  import { randomBytes as randomBytes6 } from "node:crypto";
83340
83743
  var CsvFanoutArgsSchema = external_exports.object({
83341
83744
  csv_path: external_exports.string().min(1),
@@ -83356,7 +83759,7 @@ var CsvFanoutArgsSchema = external_exports.object({
83356
83759
  max_runtime_seconds: external_exports.number().int().positive().optional()
83357
83760
  });
83358
83761
  async function readCsv(filePath) {
83359
- const text = await fs37.readFile(filePath, "utf8");
83762
+ const text = await fs38.readFile(filePath, "utf8");
83360
83763
  return parseCsv(text);
83361
83764
  }
83362
83765
  function parseCsv(text) {
@@ -83429,8 +83832,8 @@ function resolveMaxConcurrency(env = process.env) {
83429
83832
  }
83430
83833
  async function runCsvFanout(args, deps, opts) {
83431
83834
  const start = Date.now();
83432
- const absCsv = path82.isAbsolute(args.csv_path) ? args.csv_path : path82.join(opts.parentCwd, args.csv_path);
83433
- const absOut = path82.isAbsolute(args.output_csv_path) ? args.output_csv_path : path82.join(opts.parentCwd, args.output_csv_path);
83835
+ const absCsv = path83.isAbsolute(args.csv_path) ? args.csv_path : path83.join(opts.parentCwd, args.csv_path);
83836
+ const absOut = path83.isAbsolute(args.output_csv_path) ? args.output_csv_path : path83.join(opts.parentCwd, args.output_csv_path);
83434
83837
  const { headers: headers3, rows } = await readCsv(absCsv);
83435
83838
  if (headers3.length === 0) {
83436
83839
  throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
@@ -83486,7 +83889,7 @@ async function runCsvFanout(args, deps, opts) {
83486
83889
  errored += 1;
83487
83890
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
83488
83891
  }
83489
- await fs37.mkdir(path82.dirname(absOut), { recursive: true });
83892
+ await fs38.mkdir(path83.dirname(absOut), { recursive: true });
83490
83893
  await queueWrite(serializeCsv(outHeaders, outputRecords));
83491
83894
  }
83492
83895
  }
@@ -83508,8 +83911,8 @@ async function runCsvFanout(args, deps, opts) {
83508
83911
  }
83509
83912
  async function atomicWrite(file2, contents) {
83510
83913
  const tmp = `${file2}.${process.pid}.${Date.now()}.${randomBytes6(6).toString("hex")}.tmp`;
83511
- await fs37.writeFile(tmp, contents, "utf8");
83512
- await fs37.rename(tmp, file2);
83914
+ await fs38.writeFile(tmp, contents, "utf8");
83915
+ await fs38.rename(tmp, file2);
83513
83916
  }
83514
83917
 
83515
83918
  // src/cli/slashHandlers/krakenFanout.ts
@@ -83607,7 +84010,7 @@ async function handleKrakenFanout(ctx, raw) {
83607
84010
  }
83608
84011
  const absCsv = isAbsolute3(parsed.args.csv_path) ? parsed.args.csv_path : joinPath(ctx.cwd, parsed.args.csv_path);
83609
84012
  try {
83610
- await fs38.access(absCsv);
84013
+ await fs39.access(absCsv);
83611
84014
  } catch {
83612
84015
  appendSystem(ctx.setMessages, `[kraken fanout] source CSV not found: ${absCsv}`);
83613
84016
  return;
@@ -83680,8 +84083,8 @@ function splitArgs(s) {
83680
84083
 
83681
84084
  // src/cli/slashHandlers/krakenWorkbench.ts
83682
84085
  init_messageHelpers();
83683
- import { promises as fs39 } from "node:fs";
83684
- import path83 from "node:path";
84086
+ import { promises as fs40 } from "node:fs";
84087
+ import path84 from "node:path";
83685
84088
 
83686
84089
  // src/cli/kraken/workbenchView.ts
83687
84090
  var EMPTY = {
@@ -83798,15 +84201,15 @@ function formatWorkbenchForTerminal(p3) {
83798
84201
 
83799
84202
  // src/cli/slashHandlers/krakenWorkbench.ts
83800
84203
  async function handleKrakenWorkbench(ctx) {
83801
- const dir = path83.join(ctx.cwd, ".zelari", "radio");
84204
+ const dir = path84.join(ctx.cwd, ".zelari", "radio");
83802
84205
  let latest = null;
83803
84206
  let latestMtime = 0;
83804
84207
  try {
83805
- const files = await fs39.readdir(dir);
84208
+ const files = await fs40.readdir(dir);
83806
84209
  for (const f of files) {
83807
84210
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
83808
- const full = path83.join(dir, f);
83809
- const stat8 = await fs39.stat(full);
84211
+ const full = path84.join(dir, f);
84212
+ const stat8 = await fs40.stat(full);
83810
84213
  if (stat8.mtimeMs > latestMtime) {
83811
84214
  latestMtime = stat8.mtimeMs;
83812
84215
  latest = full;
@@ -83818,14 +84221,14 @@ async function handleKrakenWorkbench(ctx) {
83818
84221
  appendSystem(ctx.setMessages, "[kraken workbench] no workbench file found (.zelari/radio/workbench-*.md)");
83819
84222
  return;
83820
84223
  }
83821
- const content = await fs39.readFile(latest, "utf8");
84224
+ const content = await fs40.readFile(latest, "utf8");
83822
84225
  const parsed = parseWorkbench(content);
83823
84226
  const rendered = formatWorkbenchForTerminal(parsed);
83824
84227
  if (!rendered.trim()) {
83825
- appendSystem(ctx.setMessages, `[kraken workbench] ${path83.basename(latest)}: (no nodes / no events yet)`);
84228
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path84.basename(latest)}: (no nodes / no events yet)`);
83826
84229
  return;
83827
84230
  }
83828
- appendSystem(ctx.setMessages, `[kraken workbench] ${path83.basename(latest)}:
84231
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path84.basename(latest)}:
83829
84232
  ${rendered}`);
83830
84233
  }
83831
84234
 
@@ -84132,20 +84535,20 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
84132
84535
  // src/cli/slashHandlers/promoteMember.ts
84133
84536
  init_messageHelpers();
84134
84537
  init_paths();
84135
- import { promises as fs40 } from "node:fs";
84136
- import path86 from "node:path";
84538
+ import { promises as fs41 } from "node:fs";
84539
+ import path87 from "node:path";
84137
84540
  async function handlePromoteMember(ctx, memberId) {
84138
84541
  try {
84139
84542
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
84140
84543
  const { skill, markdown } = promoteMember2(memberId);
84141
84544
  const skillDir = skillsDir();
84142
- await fs40.mkdir(skillDir, { recursive: true });
84143
- const filePath = path86.join(skillDir, `${skill.id}.md`);
84144
- const previous = await fs40.readFile(filePath, "utf8").catch(() => null);
84545
+ await fs41.mkdir(skillDir, { recursive: true });
84546
+ const filePath = path87.join(skillDir, `${skill.id}.md`);
84547
+ const previous = await fs41.readFile(filePath, "utf8").catch(() => null);
84145
84548
  const { createHash: createHash27 } = await import("node:crypto");
84146
84549
  const sha = (s) => createHash27("sha256").update(s, "utf8").digest("hex");
84147
84550
  const lineage = `<!-- lineage: genome=sha256:${sha(markdown)} parent=${previous ? `sha256:${sha(previous)}` : "none"} promotedBy=user promotedAt=${(/* @__PURE__ */ new Date()).toISOString()} -->`;
84148
- await fs40.writeFile(filePath, `${markdown}
84551
+ await fs41.writeFile(filePath, `${markdown}
84149
84552
  ${lineage}
84150
84553
  `, "utf8");
84151
84554
  appendSystem(
@@ -84165,8 +84568,8 @@ ${lineage}
84165
84568
 
84166
84569
  // src/cli/branchManager.ts
84167
84570
  init_paths();
84168
- import { promises as fs41, existsSync as existsSync55, readFileSync as readFileSync41, writeFileSync as writeFileSync24, mkdirSync as mkdirSync21, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
84169
- import path87 from "node:path";
84571
+ import { promises as fs42, existsSync as existsSync55, readFileSync as readFileSync41, writeFileSync as writeFileSync24, mkdirSync as mkdirSync21, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
84572
+ import path88 from "node:path";
84170
84573
  var META_FILENAME = "meta.json";
84171
84574
  var SESSIONS_SUBDIR = "sessions";
84172
84575
  function getBranchesBaseDir() {
@@ -84176,13 +84579,13 @@ function getSessionsBaseDir() {
84176
84579
  return sessionsDir();
84177
84580
  }
84178
84581
  function branchPathFor(name, baseDir) {
84179
- return path87.join(baseDir, name);
84582
+ return path88.join(baseDir, name);
84180
84583
  }
84181
84584
  function metaPathFor(name, baseDir) {
84182
- return path87.join(baseDir, name, META_FILENAME);
84585
+ return path88.join(baseDir, name, META_FILENAME);
84183
84586
  }
84184
84587
  function sessionsPathFor(name, baseDir) {
84185
- return path87.join(baseDir, name, SESSIONS_SUBDIR);
84588
+ return path88.join(baseDir, name, SESSIONS_SUBDIR);
84186
84589
  }
84187
84590
  function readBranchMeta(name, baseDir) {
84188
84591
  const metaPath = metaPathFor(name, baseDir);
@@ -84207,13 +84610,13 @@ function readBranchMeta(name, baseDir) {
84207
84610
  }
84208
84611
  function writeBranchMeta(name, baseDir, meta3) {
84209
84612
  const metaPath = metaPathFor(name, baseDir);
84210
- mkdirSync21(path87.dirname(metaPath), { recursive: true });
84613
+ mkdirSync21(path88.dirname(metaPath), { recursive: true });
84211
84614
  writeFileSync24(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
84212
84615
  }
84213
84616
  async function countSessions(name, baseDir) {
84214
84617
  const sessionsPath = sessionsPathFor(name, baseDir);
84215
84618
  try {
84216
- const entries = await fs41.readdir(sessionsPath);
84619
+ const entries = await fs42.readdir(sessionsPath);
84217
84620
  return entries.filter((e) => e.endsWith(".jsonl")).length;
84218
84621
  } catch (err) {
84219
84622
  if (err.code === "ENOENT") return 0;
@@ -84258,15 +84661,15 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
84258
84661
  if (branchExists(name, baseDir)) {
84259
84662
  throw new BranchAlreadyExistsError(name);
84260
84663
  }
84261
- const sourcePath = path87.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
84664
+ const sourcePath = path88.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
84262
84665
  if (!existsSync55(sourcePath)) {
84263
84666
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
84264
84667
  }
84265
84668
  const branchPath = branchPathFor(name, baseDir);
84266
84669
  const branchSessionsPath = sessionsPathFor(name, baseDir);
84267
84670
  mkdirSync21(branchSessionsPath, { recursive: true });
84268
- const destPath = path87.join(branchSessionsPath, `${fromSessionId}.jsonl`);
84269
- await fs41.copyFile(sourcePath, destPath);
84671
+ const destPath = path88.join(branchSessionsPath, `${fromSessionId}.jsonl`);
84672
+ await fs42.copyFile(sourcePath, destPath);
84270
84673
  const meta3 = {
84271
84674
  name,
84272
84675
  createdAt: Date.now(),
@@ -84284,7 +84687,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
84284
84687
  async function listBranches(baseDir = getBranchesBaseDir()) {
84285
84688
  let entries;
84286
84689
  try {
84287
- entries = await fs41.readdir(baseDir);
84690
+ entries = await fs42.readdir(baseDir);
84288
84691
  } catch (err) {
84289
84692
  if (err.code === "ENOENT") return [];
84290
84693
  throw err;
@@ -84368,26 +84771,26 @@ async function handleBranchCheckout(ctx, branchName) {
84368
84771
 
84369
84772
  // src/cli/slashHandlers/workspace.ts
84370
84773
  init_messageHelpers();
84371
- import { promises as fs42 } from "node:fs";
84372
- import path88 from "node:path";
84774
+ import { promises as fs43 } from "node:fs";
84775
+ import path89 from "node:path";
84373
84776
  async function handleWorkspaceShow(ctx, what) {
84374
84777
  try {
84375
- const zelari = path88.join(process.cwd(), ".zelari");
84778
+ const zelari = path89.join(process.cwd(), ".zelari");
84376
84779
  let content;
84377
84780
  switch (what) {
84378
84781
  case "plan": {
84379
- const planPath = path88.join(zelari, "plan.md");
84782
+ const planPath = path89.join(zelari, "plan.md");
84380
84783
  try {
84381
- content = await fs42.readFile(planPath, "utf-8");
84784
+ content = await fs43.readFile(planPath, "utf-8");
84382
84785
  } catch {
84383
84786
  content = "(no plan.md yet \u2014 run a council session first)";
84384
84787
  }
84385
84788
  break;
84386
84789
  }
84387
84790
  case "decisions": {
84388
- const decisionsDir = path88.join(zelari, "decisions");
84791
+ const decisionsDir = path89.join(zelari, "decisions");
84389
84792
  try {
84390
- const files = (await fs42.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
84793
+ const files = (await fs43.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
84391
84794
  if (files.length === 0) {
84392
84795
  content = "(no ADRs yet \u2014 invoke /council to generate some)";
84393
84796
  } else {
@@ -84395,7 +84798,7 @@ async function handleWorkspaceShow(ctx, what) {
84395
84798
  `];
84396
84799
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
84397
84800
  for (const f of files) {
84398
- const raw = await fs42.readFile(path88.join(decisionsDir, f), "utf-8");
84801
+ const raw = await fs43.readFile(path89.join(decisionsDir, f), "utf-8");
84399
84802
  const { meta: meta3, body } = parseFrontmatter2(raw);
84400
84803
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
84401
84804
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -84408,27 +84811,27 @@ async function handleWorkspaceShow(ctx, what) {
84408
84811
  break;
84409
84812
  }
84410
84813
  case "risks": {
84411
- const risksPath = path88.join(zelari, "risks.md");
84814
+ const risksPath = path89.join(zelari, "risks.md");
84412
84815
  try {
84413
- content = await fs42.readFile(risksPath, "utf-8");
84816
+ content = await fs43.readFile(risksPath, "utf-8");
84414
84817
  } catch {
84415
84818
  content = "(no risks.md yet)";
84416
84819
  }
84417
84820
  break;
84418
84821
  }
84419
84822
  case "agents": {
84420
- const agentsPath = path88.join(process.cwd(), "AGENTS.MD");
84823
+ const agentsPath = path89.join(process.cwd(), "AGENTS.MD");
84421
84824
  try {
84422
- content = await fs42.readFile(agentsPath, "utf-8");
84825
+ content = await fs43.readFile(agentsPath, "utf-8");
84423
84826
  } catch {
84424
84827
  content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
84425
84828
  }
84426
84829
  break;
84427
84830
  }
84428
84831
  case "docs": {
84429
- const docsDir = path88.join(zelari, "docs");
84832
+ const docsDir = path89.join(zelari, "docs");
84430
84833
  try {
84431
- const files = (await fs42.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
84834
+ const files = (await fs43.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
84432
84835
  content = files.length ? `# Docs (${files.length})
84433
84836
 
84434
84837
  ` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
@@ -84468,8 +84871,8 @@ async function handleWorkspaceReset(ctx, force) {
84468
84871
  return;
84469
84872
  }
84470
84873
  try {
84471
- const target = path88.join(process.cwd(), ".zelari");
84472
- await fs42.rm(target, { recursive: true, force: true });
84874
+ const target = path89.join(process.cwd(), ".zelari");
84875
+ await fs43.rm(target, { recursive: true, force: true });
84473
84876
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
84474
84877
  } catch (err) {
84475
84878
  appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
@@ -84480,13 +84883,13 @@ async function handleWorkspaceReset(ctx, force) {
84480
84883
  init_provider2();
84481
84884
 
84482
84885
  // src/cli/skillHistory.ts
84483
- import { promises as fs43, existsSync as existsSync56, statSync as statSync8, renameSync as renameSync6, appendFileSync as appendFileSync5, mkdirSync as mkdirSync22 } from "node:fs";
84886
+ import { promises as fs44, existsSync as existsSync56, statSync as statSync8, renameSync as renameSync6, appendFileSync as appendFileSync5, mkdirSync as mkdirSync22 } from "node:fs";
84484
84887
  init_paths();
84485
84888
  var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
84486
84889
  async function readSkillHistory(file2) {
84487
84890
  let raw = "";
84488
84891
  try {
84489
- raw = await fs43.readFile(file2, "utf-8");
84892
+ raw = await fs44.readFile(file2, "utf-8");
84490
84893
  } catch {
84491
84894
  return [];
84492
84895
  }
@@ -86366,8 +86769,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
86366
86769
  let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
86367
86770
  if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
86368
86771
  try {
86369
- const path102 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
86370
- name = path102 && /^[a-z0-9]/.test(path102) ? path102 : "imported-skill";
86772
+ const path103 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
86773
+ name = path103 && /^[a-z0-9]/.test(path103) ? path103 : "imported-skill";
86371
86774
  } catch {
86372
86775
  name = "imported-skill";
86373
86776
  }