zelari-code 2.11.2 → 2.12.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.
@@ -3288,10 +3288,10 @@ function mergeDefs(...defs) {
3288
3288
  function cloneDef(schema) {
3289
3289
  return mergeDefs(schema._zod.def);
3290
3290
  }
3291
- function getElementAtPath(obj, path72) {
3292
- if (!path72)
3291
+ function getElementAtPath(obj, path74) {
3292
+ if (!path74)
3293
3293
  return obj;
3294
- return path72.reduce((acc, key) => acc?.[key], obj);
3294
+ return path74.reduce((acc, key) => acc?.[key], obj);
3295
3295
  }
3296
3296
  function promiseAllObject(promisesObj) {
3297
3297
  const keys = Object.keys(promisesObj);
@@ -3619,11 +3619,11 @@ function explicitlyAborted(x, startIndex = 0) {
3619
3619
  }
3620
3620
  return false;
3621
3621
  }
3622
- function prefixIssues(path72, issues) {
3622
+ function prefixIssues(path74, issues) {
3623
3623
  return issues.map((iss) => {
3624
3624
  var _a3;
3625
3625
  (_a3 = iss).path ?? (_a3.path = []);
3626
- iss.path.unshift(path72);
3626
+ iss.path.unshift(path74);
3627
3627
  return iss;
3628
3628
  });
3629
3629
  }
@@ -3841,16 +3841,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
3841
3841
  }
3842
3842
  function formatError(error51, mapper = (issue2) => issue2.message) {
3843
3843
  const fieldErrors = { _errors: [] };
3844
- const processError = (error52, path72 = []) => {
3844
+ const processError = (error52, path74 = []) => {
3845
3845
  for (const issue2 of error52.issues) {
3846
3846
  if (issue2.code === "invalid_union" && issue2.errors.length) {
3847
- issue2.errors.map((issues) => processError({ issues }, [...path72, ...issue2.path]));
3847
+ issue2.errors.map((issues) => processError({ issues }, [...path74, ...issue2.path]));
3848
3848
  } else if (issue2.code === "invalid_key") {
3849
- processError({ issues: issue2.issues }, [...path72, ...issue2.path]);
3849
+ processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
3850
3850
  } else if (issue2.code === "invalid_element") {
3851
- processError({ issues: issue2.issues }, [...path72, ...issue2.path]);
3851
+ processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
3852
3852
  } else {
3853
- const fullpath = [...path72, ...issue2.path];
3853
+ const fullpath = [...path74, ...issue2.path];
3854
3854
  if (fullpath.length === 0) {
3855
3855
  fieldErrors._errors.push(mapper(issue2));
3856
3856
  } else {
@@ -3877,17 +3877,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
3877
3877
  }
3878
3878
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
3879
3879
  const result = { errors: [] };
3880
- const processError = (error52, path72 = []) => {
3880
+ const processError = (error52, path74 = []) => {
3881
3881
  var _a3, _b;
3882
3882
  for (const issue2 of error52.issues) {
3883
3883
  if (issue2.code === "invalid_union" && issue2.errors.length) {
3884
- issue2.errors.map((issues) => processError({ issues }, [...path72, ...issue2.path]));
3884
+ issue2.errors.map((issues) => processError({ issues }, [...path74, ...issue2.path]));
3885
3885
  } else if (issue2.code === "invalid_key") {
3886
- processError({ issues: issue2.issues }, [...path72, ...issue2.path]);
3886
+ processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
3887
3887
  } else if (issue2.code === "invalid_element") {
3888
- processError({ issues: issue2.issues }, [...path72, ...issue2.path]);
3888
+ processError({ issues: issue2.issues }, [...path74, ...issue2.path]);
3889
3889
  } else {
3890
- const fullpath = [...path72, ...issue2.path];
3890
+ const fullpath = [...path74, ...issue2.path];
3891
3891
  if (fullpath.length === 0) {
3892
3892
  result.errors.push(mapper(issue2));
3893
3893
  continue;
@@ -3919,8 +3919,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
3919
3919
  }
3920
3920
  function toDotPath(_path) {
3921
3921
  const segs = [];
3922
- const path72 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
3923
- for (const seg of path72) {
3922
+ const path74 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
3923
+ for (const seg of path74) {
3924
3924
  if (typeof seg === "number")
3925
3925
  segs.push(`[${seg}]`);
3926
3926
  else if (typeof seg === "symbol")
@@ -17423,13 +17423,13 @@ function resolveRef(ref, ctx) {
17423
17423
  if (!ref.startsWith("#")) {
17424
17424
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
17425
17425
  }
17426
- const path72 = ref.slice(1).split("/").filter(Boolean);
17427
- if (path72.length === 0) {
17426
+ const path74 = ref.slice(1).split("/").filter(Boolean);
17427
+ if (path74.length === 0) {
17428
17428
  return ctx.rootSchema;
17429
17429
  }
17430
17430
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
17431
- if (path72[0] === defsKey) {
17432
- const key = path72[1];
17431
+ if (path74[0] === defsKey) {
17432
+ const key = path74[1];
17433
17433
  if (!key || !ctx.defs[key]) {
17434
17434
  throw new Error(`Reference not found: ${ref}`);
17435
17435
  }
@@ -19765,11 +19765,11 @@ var init_tools = __esm({
19765
19765
  if (!ctx.addDocument)
19766
19766
  return "Knowledge vault tool not available.";
19767
19767
  const title = args["title"] || "New Document";
19768
- const path72 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
19768
+ const path74 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
19769
19769
  const content = args["content"] || "";
19770
19770
  const tags = args["tags"] || [];
19771
19771
  ctx.addDocument({
19772
- path: path72,
19772
+ path: path74,
19773
19773
  title,
19774
19774
  content,
19775
19775
  format: "markdown",
@@ -19778,7 +19778,7 @@ var init_tools = __esm({
19778
19778
  workspaceId: ctx.workspaceId
19779
19779
  });
19780
19780
  ctx.addActivity("vault", "created document", title);
19781
- return `Document "${title}" created at "${path72}".`;
19781
+ return `Document "${title}" created at "${path74}".`;
19782
19782
  }
19783
19783
  }
19784
19784
  ];
@@ -25734,11 +25734,11 @@ var init_synthesisAudit = __esm({
25734
25734
  import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
25735
25735
  import { join as join4 } from "node:path";
25736
25736
  function loadNfrSpec(zelariRoot) {
25737
- const path72 = join4(zelariRoot, "nfr-spec.json");
25738
- if (!existsSync7(path72))
25737
+ const path74 = join4(zelariRoot, "nfr-spec.json");
25738
+ if (!existsSync7(path74))
25739
25739
  return null;
25740
25740
  try {
25741
- const raw = JSON.parse(readFileSync7(path72, "utf8"));
25741
+ const raw = JSON.parse(readFileSync7(path74, "utf8"));
25742
25742
  if (raw.version !== 1 || !Array.isArray(raw.targets))
25743
25743
  return null;
25744
25744
  return raw;
@@ -28044,9 +28044,9 @@ var init_types5 = __esm({
28044
28044
  import { readFileSync as readFileSync12 } from "node:fs";
28045
28045
  import { join as join10 } from "node:path";
28046
28046
  function readLessonsDeduped(zelariRoot) {
28047
- const path72 = join10(zelariRoot, LESSONS_FILE);
28047
+ const path74 = join10(zelariRoot, LESSONS_FILE);
28048
28048
  try {
28049
- const raw = readFileSync12(path72, "utf8");
28049
+ const raw = readFileSync12(path74, "utf8");
28050
28050
  const byId = /* @__PURE__ */ new Map();
28051
28051
  for (const line of raw.split(/\r?\n/)) {
28052
28052
  if (!line.trim())
@@ -28147,8 +28147,8 @@ function keywordsFrom(check2, signature) {
28147
28147
  return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
28148
28148
  }
28149
28149
  function writeLesson(zelariRoot, lesson) {
28150
- const path72 = join11(zelariRoot, LESSONS_FILE);
28151
- appendFileSync(path72, `${JSON.stringify(lesson)}
28150
+ const path74 = join11(zelariRoot, LESSONS_FILE);
28151
+ appendFileSync(path74, `${JSON.stringify(lesson)}
28152
28152
  `, "utf8");
28153
28153
  }
28154
28154
  function findSimilar(lessons, signature) {
@@ -30111,9 +30111,9 @@ function findCycle(nodes) {
30111
30111
  if (color.get(start) !== WHITE)
30112
30112
  continue;
30113
30113
  const stack = [[start, 0]];
30114
- const path72 = [];
30114
+ const path74 = [];
30115
30115
  color.set(start, GRAY);
30116
- path72.push(start);
30116
+ path74.push(start);
30117
30117
  while (stack.length > 0) {
30118
30118
  const top = stack[stack.length - 1];
30119
30119
  const [id3, idx] = top;
@@ -30126,17 +30126,17 @@ function findCycle(nodes) {
30126
30126
  continue;
30127
30127
  const c = color.get(dep);
30128
30128
  if (c === GRAY) {
30129
- const at = path72.indexOf(dep);
30130
- return [...path72.slice(at), dep];
30129
+ const at = path74.indexOf(dep);
30130
+ return [...path74.slice(at), dep];
30131
30131
  }
30132
30132
  if (c === WHITE) {
30133
30133
  color.set(dep, GRAY);
30134
- path72.push(dep);
30134
+ path74.push(dep);
30135
30135
  stack.push([dep, 0]);
30136
30136
  }
30137
30137
  } else {
30138
30138
  color.set(id3, BLACK);
30139
- path72.pop();
30139
+ path74.pop();
30140
30140
  stack.pop();
30141
30141
  }
30142
30142
  }
@@ -31056,8 +31056,8 @@ var init_runner = __esm({
31056
31056
  failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
31057
31057
  pending: []
31058
31058
  };
31059
- const path72 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
31060
- this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path72}`);
31059
+ const path74 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
31060
+ this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path74}`);
31061
31061
  return snapshot;
31062
31062
  }
31063
31063
  callLog(msg, data) {
@@ -33499,16 +33499,16 @@ function runRetentionFromEnv() {
33499
33499
  maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
33500
33500
  };
33501
33501
  }
33502
- async function dirSize(path72) {
33502
+ async function dirSize(path74) {
33503
33503
  let total = 0;
33504
33504
  let entries;
33505
33505
  try {
33506
- entries = await readdir(path72, { withFileTypes: true });
33506
+ entries = await readdir(path74, { withFileTypes: true });
33507
33507
  } catch {
33508
33508
  return 0;
33509
33509
  }
33510
33510
  for (const entry of entries) {
33511
- const child = join13(path72, entry.name);
33511
+ const child = join13(path74, entry.name);
33512
33512
  if (entry.isDirectory())
33513
33513
  total += await dirSize(child);
33514
33514
  else {
@@ -33535,19 +33535,19 @@ async function enforceRunRetention(runsDir, options = {}) {
33535
33535
  for (const entry of entries) {
33536
33536
  if (!entry.isDirectory())
33537
33537
  continue;
33538
- const path72 = join13(runsDir, entry.name);
33538
+ const path74 = join13(runsDir, entry.name);
33539
33539
  let startedAt = 0;
33540
33540
  let endedAt;
33541
33541
  let completed = false;
33542
33542
  try {
33543
- const manifest = JSON.parse(await readFile(join13(path72, "manifest.json"), "utf8"));
33543
+ const manifest = JSON.parse(await readFile(join13(path74, "manifest.json"), "utf8"));
33544
33544
  startedAt = manifest.startedAt ?? 0;
33545
33545
  endedAt = manifest.endedAt;
33546
33546
  completed = Boolean(endedAt) && manifest.status !== "running";
33547
33547
  } catch {
33548
33548
  completed = false;
33549
33549
  }
33550
- infos.push({ name: entry.name, path: path72, startedAt, endedAt, completed, bytes: await dirSize(path72) });
33550
+ infos.push({ name: entry.name, path: path74, startedAt, endedAt, completed, bytes: await dirSize(path74) });
33551
33551
  }
33552
33552
  const remove = async (info) => {
33553
33553
  await rm(info.path, { recursive: true, force: true });
@@ -34319,12 +34319,12 @@ var init_engine = __esm({
34319
34319
  * content digest) and the returned ref carries the event seq when the
34320
34320
  * emitter resolved one.
34321
34321
  */
34322
- async fsEvidence(observation, path72, sha256, content, extra = {}) {
34322
+ async fsEvidence(observation, path74, sha256, content, extra = {}) {
34323
34323
  const digest = sha256 && content !== void 0 ? sha256(content) : void 0;
34324
- const seq = await this.emitEvidence({ observation, path: path72, ...extra, ...digest ? { digest } : {} });
34324
+ const seq = await this.emitEvidence({ observation, path: path74, ...extra, ...digest ? { digest } : {} });
34325
34325
  return {
34326
34326
  tier: "fs-observation",
34327
- ref: path72,
34327
+ ref: path74,
34328
34328
  capturedAt: Date.now(),
34329
34329
  ...digest ? { digest } : {},
34330
34330
  ...seq !== void 0 ? { seq } : {}
@@ -34706,7 +34706,8 @@ var init_verifier = __esm({
34706
34706
  });
34707
34707
  VERIFIER_SYSTEM_PROMPT = [
34708
34708
  "You are an independent completion verifier.",
34709
- "You receive a work summary and deterministic verification results.",
34709
+ "You receive the original task, a git diff summary, a test output excerpt,",
34710
+ "and deterministic verification results \u2014 never the builder narration.",
34710
34711
  "Answer with a single JSON object and nothing else:",
34711
34712
  '{"verdict":"confirmed|rejected|unknown","score":0..1,"rationale":"..."}',
34712
34713
  "Rules: never confirm when a required deterministic check failed or is unknown;",
@@ -34741,8 +34742,14 @@ var init_verifier = __esm({
34741
34742
  try {
34742
34743
  response = await this.deps.callModel({
34743
34744
  system: VERIFIER_SYSTEM_PROMPT,
34745
+ // Blind review payload: evidence only (task, diff summary, test output
34746
+ // excerpt, deterministic results). Builder narration/reasoning is
34747
+ // structurally excluded — undefined keys are omitted.
34744
34748
  user: JSON.stringify({
34749
+ ...request.task === void 0 ? {} : { task: request.task },
34745
34750
  summary: request.summary,
34751
+ ...request.diffSummary === void 0 ? {} : { diffSummary: request.diffSummary },
34752
+ ...request.testOutputExcerpt === void 0 ? {} : { testOutputExcerpt: request.testOutputExcerpt },
34746
34753
  deterministicResults: request.results.map((r) => ({
34747
34754
  criterionId: r.criterionId,
34748
34755
  status: r.status,
@@ -37457,9 +37464,9 @@ function spillToolOutput(fullText, meta3) {
37457
37464
  const rnd = randomBytes3(3).toString("hex");
37458
37465
  const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
37459
37466
  const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
37460
- const path72 = join14(dir, file2);
37461
- writeFileSync11(path72, fullText, "utf8");
37462
- return path72;
37467
+ const path74 = join14(dir, file2);
37468
+ writeFileSync11(path74, fullText, "utf8");
37469
+ return path74;
37463
37470
  } catch {
37464
37471
  return null;
37465
37472
  }
@@ -37505,10 +37512,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
37505
37512
  ${tail2}`;
37506
37513
  }
37507
37514
  if (doSpill) {
37508
- const path72 = spillToolOutput(text, { toolName: opts.toolName });
37509
- if (path72) {
37515
+ const path74 = spillToolOutput(text, { toolName: opts.toolName });
37516
+ if (path74) {
37510
37517
  const spillNote = `
37511
- \u2026 [full output spilled to: ${path72} \u2014 re-read with read_file if you need the complete text] \u2026`;
37518
+ \u2026 [full output spilled to: ${path74} \u2014 re-read with read_file if you need the complete text] \u2026`;
37512
37519
  if (preview.includes("] \u2026\n")) {
37513
37520
  preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
37514
37521
  `);
@@ -40340,28 +40347,28 @@ var init_storage = __esm({
40340
40347
  VALID_SCALARS = /^(true|false|null|~)$/i;
40341
40348
  Storage = class {
40342
40349
  /** Read a Markdown file with frontmatter. Throws if not found. */
40343
- read(path72) {
40344
- if (!existsSync19(path72)) {
40345
- throw new Error(`File not found: ${path72}`);
40350
+ read(path74) {
40351
+ if (!existsSync19(path74)) {
40352
+ throw new Error(`File not found: ${path74}`);
40346
40353
  }
40347
- const md = readFileSync16(path72, "utf8");
40354
+ const md = readFileSync16(path74, "utf8");
40348
40355
  return parseFrontmatter(md);
40349
40356
  }
40350
40357
  /** Read a Markdown file; returns null if not found. */
40351
- readIfExists(path72) {
40352
- if (!existsSync19(path72)) return null;
40353
- return this.read(path72);
40358
+ readIfExists(path74) {
40359
+ if (!existsSync19(path74)) return null;
40360
+ return this.read(path74);
40354
40361
  }
40355
40362
  /**
40356
40363
  * Write a Markdown file atomically (tmp + rename). Creates parent dirs.
40357
40364
  * The meta object is serialized as YAML frontmatter; body as Markdown.
40358
40365
  */
40359
- write(path72, meta3, body) {
40360
- mkdirSync10(dirname2(path72), { recursive: true });
40361
- const tmp = path72 + ".tmp-" + process.pid;
40366
+ write(path74, meta3, body) {
40367
+ mkdirSync10(dirname2(path74), { recursive: true });
40368
+ const tmp = path74 + ".tmp-" + process.pid;
40362
40369
  const md = serializeFrontmatter(meta3, body);
40363
40370
  writeFileSync13(tmp, md, "utf8");
40364
- renameSync(tmp, path72);
40371
+ renameSync(tmp, path74);
40365
40372
  }
40366
40373
  /** List all .md files in a directory (non-recursive). */
40367
40374
  listMarkdown(dir) {
@@ -40423,8 +40430,8 @@ function nextPlanTaskId(store6) {
40423
40430
  return `t${store6.counter}`;
40424
40431
  }
40425
40432
  function writePlanTaskArtifact(rootDir, task) {
40426
- const path72 = join18(rootDir, "plan-tasks", `${task.id}.md`);
40427
- mkdirSync11(dirname3(path72), { recursive: true });
40433
+ const path74 = join18(rootDir, "plan-tasks", `${task.id}.md`);
40434
+ mkdirSync11(dirname3(path74), { recursive: true });
40428
40435
  const meta3 = {
40429
40436
  kind: "task",
40430
40437
  id: task.id,
@@ -40445,7 +40452,7 @@ function writePlanTaskArtifact(rootDir, task) {
40445
40452
  task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
40446
40453
  ""
40447
40454
  ].filter((l) => l !== null).join("\n");
40448
- new Storage().write(path72, meta3, body);
40455
+ new Storage().write(path74, meta3, body);
40449
40456
  }
40450
40457
  function loadHandle(rootDir) {
40451
40458
  const jsonPath = join18(rootDir, "plan.json");
@@ -43733,21 +43740,21 @@ function normalizeAuth(auth) {
43733
43740
  return "agent";
43734
43741
  }
43735
43742
  function readSecrets() {
43736
- const path72 = getSshSecretsPath();
43737
- if (!existsSync23(path72)) return {};
43743
+ const path74 = getSshSecretsPath();
43744
+ if (!existsSync23(path74)) return {};
43738
43745
  try {
43739
- return JSON.parse(readFileSync20(path72, "utf8"));
43746
+ return JSON.parse(readFileSync20(path74, "utf8"));
43740
43747
  } catch {
43741
43748
  return {};
43742
43749
  }
43743
43750
  }
43744
43751
  function writeSecrets(data) {
43745
- const path72 = getSshSecretsPath();
43746
- mkdirSync12(dirname4(path72), { recursive: true });
43747
- writeFileSync15(path72, `${JSON.stringify(data, null, 2)}
43752
+ const path74 = getSshSecretsPath();
43753
+ mkdirSync12(dirname4(path74), { recursive: true });
43754
+ writeFileSync15(path74, `${JSON.stringify(data, null, 2)}
43748
43755
  `, "utf8");
43749
43756
  try {
43750
- chmodSync(path72, 384);
43757
+ chmodSync(path74, 384);
43751
43758
  } catch {
43752
43759
  }
43753
43760
  }
@@ -43776,10 +43783,10 @@ function deleteSshPassword(id3) {
43776
43783
  writeSecrets({ passwords });
43777
43784
  }
43778
43785
  function readStore2() {
43779
- const path72 = getSshTargetsPath();
43780
- if (!existsSync23(path72)) return [];
43786
+ const path74 = getSshTargetsPath();
43787
+ if (!existsSync23(path74)) return [];
43781
43788
  try {
43782
- const parsed = JSON.parse(readFileSync20(path72, "utf8"));
43789
+ const parsed = JSON.parse(readFileSync20(path74, "utf8"));
43783
43790
  const list = Array.isArray(parsed.targets) ? parsed.targets : [];
43784
43791
  return list.filter(
43785
43792
  (t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
@@ -43794,11 +43801,11 @@ function readStore2() {
43794
43801
  }
43795
43802
  }
43796
43803
  function writeStore2(targets) {
43797
- const path72 = getSshTargetsPath();
43798
- mkdirSync12(dirname4(path72), { recursive: true });
43804
+ const path74 = getSshTargetsPath();
43805
+ mkdirSync12(dirname4(path74), { recursive: true });
43799
43806
  const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
43800
43807
  writeFileSync15(
43801
- path72,
43808
+ path74,
43802
43809
  `${JSON.stringify({ targets: clean }, null, 2)}
43803
43810
  `,
43804
43811
  "utf8"
@@ -44044,11 +44051,11 @@ function formatSshTargetsForPrompt() {
44044
44051
  ];
44045
44052
  for (const t of targets) {
44046
44053
  const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
44047
- const path72 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
44054
+ const path74 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
44048
44055
  const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
44049
44056
  const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
44050
44057
  lines.push(
44051
- `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path72}${tags}${allow}`
44058
+ `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path74}${tags}${allow}`
44052
44059
  );
44053
44060
  }
44054
44061
  return lines.join("\n");
@@ -45048,6 +45055,19 @@ function defaultPermissionPolicy(overrides) {
45048
45055
  ...overrides
45049
45056
  };
45050
45057
  }
45058
+ function moreRestrictive(a, b) {
45059
+ return ACTION_RANK2[a] >= ACTION_RANK2[b] ? a : b;
45060
+ }
45061
+ function intersectPermissionPolicy(parent, child) {
45062
+ return {
45063
+ read: moreRestrictive(parent.read, child.read),
45064
+ write: moreRestrictive(parent.write, child.write),
45065
+ execute: moreRestrictive(parent.execute, child.execute),
45066
+ network: moreRestrictive(parent.network, child.network),
45067
+ ui: moreRestrictive(parent.ui, child.ui),
45068
+ auto: parent.auto && child.auto
45069
+ };
45070
+ }
45051
45071
  function resolveToolPermission(toolName, required2, policy) {
45052
45072
  if (!required2.length) {
45053
45073
  return { action: "allow", reason: "", categories: [] };
@@ -45083,12 +45103,13 @@ function resolveToolPermission(toolName, required2, policy) {
45083
45103
  categories: hit
45084
45104
  };
45085
45105
  }
45086
- var sessionToolGrants, sessionCategoryGrants;
45106
+ var sessionToolGrants, sessionCategoryGrants, ACTION_RANK2;
45087
45107
  var init_toolPermissions = __esm({
45088
45108
  "src/cli/safety/toolPermissions.ts"() {
45089
45109
  "use strict";
45090
45110
  sessionToolGrants = /* @__PURE__ */ new Set();
45091
45111
  sessionCategoryGrants = /* @__PURE__ */ new Set();
45112
+ ACTION_RANK2 = { allow: 0, ask: 1, deny: 2 };
45092
45113
  }
45093
45114
  });
45094
45115
 
@@ -45265,10 +45286,194 @@ var init_lifecycleHooks = __esm({
45265
45286
  }
45266
45287
  });
45267
45288
 
45289
+ // src/cli/safety/policyEngine.ts
45290
+ import { readFileSync as readFileSync22 } from "node:fs";
45291
+ import { homedir as homedir10 } from "node:os";
45292
+ import path40 from "node:path";
45293
+ function emptyPolicySet() {
45294
+ return { agents: /* @__PURE__ */ new Map(), warnings: [] };
45295
+ }
45296
+ function agentRulesFor(set2, agent) {
45297
+ return set2.agents.get(agent) ?? EMPTY_POLICY_RULE_SET;
45298
+ }
45299
+ function globToRegExp(pattern) {
45300
+ let src = "^";
45301
+ for (let i = 0; i < pattern.length; i++) {
45302
+ const ch = pattern[i];
45303
+ if (ch === "*") {
45304
+ while (pattern[i + 1] === "*") i++;
45305
+ src += ".*";
45306
+ } else if ("\\^$.|?+()[]{}".includes(ch)) {
45307
+ src += "\\" + ch;
45308
+ } else {
45309
+ src += ch;
45310
+ }
45311
+ }
45312
+ return new RegExp(src + "$");
45313
+ }
45314
+ function normalizeForMatch(value) {
45315
+ return value.replace(/\\/g, "/");
45316
+ }
45317
+ function resolvePolicyRule(rules, value) {
45318
+ const v = normalizeForMatch(value);
45319
+ for (const rule of rules) {
45320
+ if (globToRegExp(normalizeForMatch(rule.match)).test(v)) return rule;
45321
+ }
45322
+ return null;
45323
+ }
45324
+ function mergeRuleEffect(base2, rule) {
45325
+ if (!rule) return base2;
45326
+ return EFFECT_RANK[rule.effect] > EFFECT_RANK[base2] ? rule.effect : base2;
45327
+ }
45328
+ function pathCandidates(value, root) {
45329
+ const norm = normalizeForMatch(value);
45330
+ if (!root) return [norm];
45331
+ const prefix = normalizeForMatch(root).replace(/\/+$/, "") + "/";
45332
+ const stripped = norm.toLowerCase().startsWith(prefix.toLowerCase()) ? norm.slice(prefix.length) : null;
45333
+ return stripped !== null ? [stripped, norm] : [norm];
45334
+ }
45335
+ function matchAgentPolicyRule(rules, required2, args, root) {
45336
+ if (!rules) return null;
45337
+ const a = args !== null && typeof args === "object" ? args : {};
45338
+ if (required2.includes("execute")) {
45339
+ const cmd = a["command"];
45340
+ if (typeof cmd === "string" && cmd !== "") {
45341
+ const hit = resolvePolicyRule(rules.shell, cmd);
45342
+ if (hit) return hit;
45343
+ }
45344
+ }
45345
+ if (required2.includes("write")) {
45346
+ const p3 = typeof a["path"] === "string" ? a["path"] : typeof a["file_path"] === "string" ? a["file_path"] : "";
45347
+ if (p3 !== "") {
45348
+ for (const candidate of pathCandidates(p3, root)) {
45349
+ const hit = resolvePolicyRule(rules.edit, candidate);
45350
+ if (hit) return hit;
45351
+ }
45352
+ }
45353
+ }
45354
+ return null;
45355
+ }
45356
+ function isPolicyEngineDisabled() {
45357
+ const v = process.env.ZELARI_POLICY?.trim().toLowerCase();
45358
+ return v === "0" || v === "false" || v === "no" || v === "off";
45359
+ }
45360
+ function isPlainObject2(v) {
45361
+ return typeof v === "object" && v !== null && !Array.isArray(v);
45362
+ }
45363
+ function parseRuleList(raw, origin, warnings) {
45364
+ if (raw === void 0) return [];
45365
+ if (!Array.isArray(raw)) {
45366
+ warnings.push(`${origin}: expected an array of rules, got ${typeof raw} \u2014 section ignored.`);
45367
+ return [];
45368
+ }
45369
+ const out = [];
45370
+ raw.forEach((item, i) => {
45371
+ const where = `${origin}[${i}]`;
45372
+ if (!isPlainObject2(item)) {
45373
+ warnings.push(`${where}: rule is not an object \u2014 skipped.`);
45374
+ return;
45375
+ }
45376
+ const match = item["match"];
45377
+ const effect = item["effect"];
45378
+ const reason = item["reason"];
45379
+ if (typeof match !== "string" || match.trim() === "") {
45380
+ warnings.push(`${where}: missing or empty "match" \u2014 skipped.`);
45381
+ return;
45382
+ }
45383
+ if (effect !== "allow" && effect !== "ask" && effect !== "deny") {
45384
+ warnings.push(`${where} ("${match}"): "effect" must be allow|ask|deny \u2014 skipped.`);
45385
+ return;
45386
+ }
45387
+ out.push(
45388
+ typeof reason === "string" && reason.trim() !== "" ? { match, effect, reason } : { match, effect }
45389
+ );
45390
+ });
45391
+ return out;
45392
+ }
45393
+ function parsePolicyFile(raw, origin, warnings) {
45394
+ if (!isPlainObject2(raw)) {
45395
+ warnings.push(`${origin}: policy file is not a JSON object \u2014 file ignored.`);
45396
+ return null;
45397
+ }
45398
+ const version2 = raw["version"];
45399
+ if (version2 !== void 0 && version2 !== 1) {
45400
+ warnings.push(`${origin}: unsupported "version" ${JSON.stringify(version2)} (expected 1) \u2014 file ignored.`);
45401
+ return null;
45402
+ }
45403
+ const agentsRaw = raw["agents"];
45404
+ if (agentsRaw === void 0) {
45405
+ warnings.push(`${origin}: no "agents" key \u2014 file ignored.`);
45406
+ return null;
45407
+ }
45408
+ if (!isPlainObject2(agentsRaw)) {
45409
+ warnings.push(`${origin}: "agents" is not an object \u2014 file ignored.`);
45410
+ return null;
45411
+ }
45412
+ const out = /* @__PURE__ */ new Map();
45413
+ for (const [key, val] of Object.entries(agentsRaw)) {
45414
+ const agent = key.trim().toLowerCase();
45415
+ if (!KNOWN_AGENTS.has(agent)) {
45416
+ warnings.push(`${origin}: unknown agent "${key}" (known: ${POLICY_AGENTS.join(" | ")}) \u2014 ignored.`);
45417
+ continue;
45418
+ }
45419
+ if (!isPlainObject2(val)) {
45420
+ warnings.push(`${origin}: agents.${key} is not an object \u2014 ignored.`);
45421
+ continue;
45422
+ }
45423
+ const shell = parseRuleList(val["shell"], `${origin} agents.${key}.shell`, warnings);
45424
+ const edit = parseRuleList(val["edit"], `${origin} agents.${key}.edit`, warnings);
45425
+ out.set(agent, { shell, edit });
45426
+ }
45427
+ return out;
45428
+ }
45429
+ function readPolicyFile(file2, warnings) {
45430
+ let text;
45431
+ try {
45432
+ text = readFileSync22(file2, "utf8");
45433
+ } catch {
45434
+ return /* @__PURE__ */ new Map();
45435
+ }
45436
+ let parsed;
45437
+ try {
45438
+ parsed = JSON.parse(text);
45439
+ } catch (err) {
45440
+ warnings.push(
45441
+ `${file2}: invalid JSON (${err instanceof Error ? err.message : String(err)}) \u2014 file ignored.`
45442
+ );
45443
+ return /* @__PURE__ */ new Map();
45444
+ }
45445
+ return parsePolicyFile(parsed, file2, warnings) ?? /* @__PURE__ */ new Map();
45446
+ }
45447
+ function loadPolicySet(root, opts = {}) {
45448
+ if (isPolicyEngineDisabled()) return emptyPolicySet();
45449
+ const warnings = [];
45450
+ const project = readPolicyFile(path40.join(root, ".zelari", "policy.json"), warnings);
45451
+ const global = readPolicyFile(path40.join(opts.homeDir ?? homedir10(), ".zelari", "policy.json"), warnings);
45452
+ const agents = /* @__PURE__ */ new Map();
45453
+ for (const [agent, g] of global) {
45454
+ agents.set(agent, { shell: [...g.shell], edit: [...g.edit] });
45455
+ }
45456
+ for (const [agent, p3] of project) {
45457
+ const g = agents.get(agent) ?? EMPTY_POLICY_RULE_SET;
45458
+ agents.set(agent, { shell: [...p3.shell, ...g.shell], edit: [...p3.edit, ...g.edit] });
45459
+ }
45460
+ return { agents, warnings };
45461
+ }
45462
+ var POLICY_AGENTS, KNOWN_AGENTS, EMPTY_POLICY_RULE_SET, EFFECT_RANK;
45463
+ var init_policyEngine = __esm({
45464
+ "src/cli/safety/policyEngine.ts"() {
45465
+ "use strict";
45466
+ POLICY_AGENTS = ["lead", "explore", "general", "verify"];
45467
+ KNOWN_AGENTS = new Set(POLICY_AGENTS);
45468
+ EMPTY_POLICY_RULE_SET = { shell: [], edit: [] };
45469
+ EFFECT_RANK = { allow: 0, ask: 1, deny: 2 };
45470
+ }
45471
+ });
45472
+
45268
45473
  // src/cli/toolResultCache.ts
45269
45474
  import { createHash as createHash13 } from "node:crypto";
45270
45475
  import { promises as fs19 } from "node:fs";
45271
- import path40 from "node:path";
45476
+ import path41 from "node:path";
45272
45477
  function isToolCacheEnabled() {
45273
45478
  const raw = process.env.ZELARI_TOOL_CACHE;
45274
45479
  return raw !== "0" && raw !== "false" && raw !== "off";
@@ -45353,7 +45558,7 @@ async function statKey(toolName, input, ctx) {
45353
45558
  if (!input || typeof input !== "object") return null;
45354
45559
  const rawPath = input.path;
45355
45560
  if (typeof rawPath !== "string" || rawPath.length === 0) return null;
45356
- const abs = path40.isAbsolute(rawPath) ? rawPath : path40.join(ctx.cwd, rawPath);
45561
+ const abs = path41.isAbsolute(rawPath) ? rawPath : path41.join(ctx.cwd, rawPath);
45357
45562
  try {
45358
45563
  const st = await fs19.stat(abs);
45359
45564
  return hashKey({
@@ -45402,10 +45607,13 @@ var init_toolResultCache = __esm({
45402
45607
  // src/cli/tools/krakenModel.ts
45403
45608
  var krakenModel_exports = {};
45404
45609
  __export(krakenModel_exports, {
45610
+ inferModelFamily: () => inferModelFamily,
45405
45611
  isCheapModelId: () => isCheapModelId,
45406
45612
  isKrakenAutoModelEnabled: () => isKrakenAutoModelEnabled,
45407
45613
  parseQualifiedModelRef: () => parseQualifiedModelRef,
45408
45614
  pickCheapModel: () => pickCheapModel,
45615
+ pickDifferentFamily: () => pickDifferentFamily,
45616
+ resolveCrossModelVerifier: () => resolveCrossModelVerifier,
45409
45617
  resolveKrakenPlannerModel: () => resolveKrakenPlannerModel,
45410
45618
  resolveKrakenSubModel: () => resolveKrakenSubModel,
45411
45619
  resolveKrakenSubModelAsync: () => resolveKrakenSubModelAsync,
@@ -45450,6 +45658,44 @@ function parseQualifiedModelRef(ref) {
45450
45658
  if (!provider || !model) return null;
45451
45659
  return { provider, model };
45452
45660
  }
45661
+ function inferModelFamily(provider, model) {
45662
+ const p3 = (provider ?? "").trim().toLowerCase();
45663
+ const m = (model ?? "").trim().toLowerCase();
45664
+ const hay = `${p3} ${m}`.trim();
45665
+ if (!hay) return "other";
45666
+ if (/\b(zhipu|glm)\b/.test(hay)) return "zhipu";
45667
+ if (/\b(google|gemini)\b/.test(hay)) return "google";
45668
+ if (/\b(xai|grok)\b/.test(hay)) return "xai";
45669
+ if (/\b(anthropic|claude)\b/.test(hay)) return "anthropic";
45670
+ if (/\b(openai|chatgpt|codex)\b/.test(hay) || /\bgpt\b/.test(hay) || /(^|\s)o[134]($|[-_.])/.test(hay)) {
45671
+ return "openai";
45672
+ }
45673
+ return p3 || "other";
45674
+ }
45675
+ function pickDifferentFamily(builder, candidates) {
45676
+ const builderFamily = inferModelFamily(builder.provider, builder.model);
45677
+ for (const c of candidates) {
45678
+ const provider = c.provider?.trim() ?? "";
45679
+ const model = c.model?.trim() ?? "";
45680
+ if (!provider || !model) continue;
45681
+ if (inferModelFamily(provider, model) !== builderFamily) {
45682
+ return { provider, model };
45683
+ }
45684
+ }
45685
+ return null;
45686
+ }
45687
+ function resolveCrossModelVerifier(builder, candidates, env = process.env) {
45688
+ const cross = (env.ZELARI_KRAKEN_CROSS_MODEL ?? "").trim().toLowerCase();
45689
+ if (cross === "0" || cross === "false" || cross === "off") return null;
45690
+ const specific = env.ZELARI_KRAKEN_VERIFY_MODEL?.trim();
45691
+ if (specific) {
45692
+ const qualified = parseQualifiedModelRef(specific);
45693
+ if (qualified) return qualified;
45694
+ const provider = builder.provider?.trim();
45695
+ return provider ? { provider, model: specific } : null;
45696
+ }
45697
+ return pickDifferentFamily(builder, candidates);
45698
+ }
45453
45699
  function resolveKrakenSubModel(agent, parentModel, env = process.env, opts = {}) {
45454
45700
  const kindKey = agent === "explore" ? "ZELARI_KRAKEN_EXPLORE_MODEL" : agent === "verify" ? "ZELARI_KRAKEN_VERIFY_MODEL" : "ZELARI_KRAKEN_GENERAL_MODEL";
45455
45701
  const specific = env[kindKey]?.trim();
@@ -45462,6 +45708,13 @@ function resolveKrakenSubModel(agent, parentModel, env = process.env, opts = {})
45462
45708
  }
45463
45709
  return shared2;
45464
45710
  }
45711
+ if (agent === "verify" && opts.familyCandidates && opts.familyCandidates.length > 0) {
45712
+ const picked = pickDifferentFamily(
45713
+ { provider: opts.provider ?? "", model: parentModel },
45714
+ opts.familyCandidates
45715
+ );
45716
+ if (picked) return `${picked.provider}/${picked.model}`;
45717
+ }
45465
45718
  if ((agent === "explore" || agent === "verify") && isKrakenAutoModelEnabled(env) && opts.candidates && opts.candidates.length > 0) {
45466
45719
  const picked = pickCheapModel(parentModel, opts.candidates);
45467
45720
  if (picked) return picked;
@@ -45557,7 +45810,11 @@ function createBuiltinToolRegistry(options = {}) {
45557
45810
  const allowMutators = !readOnly && !verifyMode && !gauntletParent;
45558
45811
  const allowBash = (allowMutators || verifyMode) && !gauntletParent;
45559
45812
  const permPolicy = options.permissionPolicy ?? defaultPermissionPolicy();
45560
- const withPerm = (t) => wrapWithPermissions(t, permPolicy, options.onPermissionAsk);
45813
+ const agentPolicyRules = agentRulesFor(
45814
+ loadPolicySet(root),
45815
+ options.policyAgent ?? "lead"
45816
+ );
45817
+ const withPerm = (t) => wrapWithPermissions(t, permPolicy, options.onPermissionAsk, agentPolicyRules, root);
45561
45818
  registry4.register(withPerm(safeReadFile));
45562
45819
  registry4.register(withPerm(safeGrepContent));
45563
45820
  registry4.register(withPerm(safeListFiles));
@@ -45691,6 +45948,10 @@ function createBuiltinToolRegistry(options = {}) {
45691
45948
  root,
45692
45949
  audit,
45693
45950
  sessionId: sessionId2,
45951
+ // P0.4 capability inheritance: tentacles intersect THIS
45952
+ // registry's own policy (permPolicy above) — they can never
45953
+ // exceed it.
45954
+ parentPolicy: permPolicy,
45694
45955
  ...options.subAgentProvider ? { provider: options.subAgentProvider } : {},
45695
45956
  ...options.subAgentModel ? { model: options.subAgentModel } : {}
45696
45957
  }),
@@ -45768,7 +46029,7 @@ function taskAgentToProfile(agent) {
45768
46029
  return "explore";
45769
46030
  }
45770
46031
  function createKrakenSubAgentContextFactory(opts) {
45771
- const { root, audit, sessionId: sessionId2, provider: providerOverride, model: modelOverride } = opts;
46032
+ const { root, audit, sessionId: sessionId2, provider: providerOverride, model: modelOverride, parentPolicy } = opts;
45772
46033
  return async ({ agent, cwd: subCwd }) => {
45773
46034
  const cfg = providerOverride ? await providerConfigFor(providerOverride) : await providerFromEnv();
45774
46035
  if (!cfg) return null;
@@ -45787,6 +46048,11 @@ function createKrakenSubAgentContextFactory(opts) {
45787
46048
  const subCfg = { ...effCfg, model };
45788
46049
  const subProfile = taskAgentToProfile(agent);
45789
46050
  const subRoot = subCwd || root;
46051
+ const agentPolicyForSubProfile = defaultPermissionPolicy({ auto: true });
46052
+ const effectiveSubPolicy = intersectPermissionPolicy(
46053
+ parentPolicy ?? agentPolicyForSubProfile,
46054
+ agentPolicyForSubProfile
46055
+ );
45790
46056
  const { registry: subRegistry } = createBuiltinToolRegistry({
45791
46057
  root: subRoot,
45792
46058
  audit,
@@ -45796,7 +46062,9 @@ function createKrakenSubAgentContextFactory(opts) {
45796
46062
  enableSkill: agent === "general",
45797
46063
  diagnostics: false,
45798
46064
  lspProvider: null,
45799
- permissionPolicy: defaultPermissionPolicy({ auto: true })
46065
+ permissionPolicy: effectiveSubPolicy,
46066
+ // P0.5: the tentacle's agent identity drives per-agent policy rules.
46067
+ policyAgent: agent
45800
46068
  });
45801
46069
  return {
45802
46070
  providerStream: buildProviderStream(subCfg),
@@ -45813,7 +46081,7 @@ function createKrakenSubAgentContextFactory(opts) {
45813
46081
  };
45814
46082
  };
45815
46083
  }
45816
- function wrapWithPermissions(original, policy, onAsk) {
46084
+ function wrapWithPermissions(original, policy, onAsk, agentRules, root) {
45817
46085
  const required2 = original.permissions ?? [];
45818
46086
  const decisionProbe = resolveToolPermission(original.name, required2, policy);
45819
46087
  if (decisionProbe.action === "allow" && !required2.includes("write") && !required2.includes("execute")) {
@@ -45822,13 +46090,21 @@ function wrapWithPermissions(original, policy, onAsk) {
45822
46090
  ...original,
45823
46091
  execute: async (input, ctx) => {
45824
46092
  const decision = resolveToolPermission(original.name, required2, policy);
45825
- if (decision.action === "deny") {
45826
- return typedErr(`[permission] ${decision.reason}`);
45827
- }
45828
- if (decision.action === "ask") {
46093
+ const rule = agentRules ? matchAgentPolicyRule(
46094
+ agentRules,
46095
+ required2,
46096
+ input ?? {},
46097
+ root ?? process.cwd()
46098
+ ) : null;
46099
+ const action = mergeRuleEffect(decision.action, rule);
46100
+ const rulePrefix = rule ? `[policy] rule '${rule.match}'${rule.reason ? ` \u2014 ${rule.reason}` : ""}` : "";
46101
+ if (action === "deny") {
46102
+ return typedErr(`[permission] ${rulePrefix || decision.reason}`);
46103
+ }
46104
+ if (action === "ask") {
45829
46105
  if (!onAsk) {
45830
46106
  return typedErr(
45831
- `[permission] ${decision.reason} No interactive approval available (set ZELARI_AUTO=1 to auto-allow, or configure onPermissionAsk).`
46107
+ `[permission] ${rulePrefix ? `${rulePrefix} ` : ""}${decision.reason} No interactive approval available (set ZELARI_AUTO=1 to auto-allow, or configure onPermissionAsk).`
45832
46108
  );
45833
46109
  }
45834
46110
  try {
@@ -46044,6 +46320,7 @@ var init_toolRegistry = __esm({
46044
46320
  init_providerConfig();
46045
46321
  init_toolPermissions();
46046
46322
  init_lifecycleHooks();
46323
+ init_policyEngine();
46047
46324
  init_toolResultCache();
46048
46325
  init_toolTypes();
46049
46326
  init_skills2();
@@ -46064,7 +46341,7 @@ var init_toolRegistry = __esm({
46064
46341
 
46065
46342
  // src/cli/metrics.ts
46066
46343
  import { promises as fs20, existsSync as existsSync25, statSync as statSync4, renameSync as renameSync3, appendFileSync as appendFileSync3, mkdirSync as mkdirSync14 } from "node:fs";
46067
- import path41 from "node:path";
46344
+ import path42 from "node:path";
46068
46345
  import os9 from "node:os";
46069
46346
  async function readMetrics(file2) {
46070
46347
  let raw = "";
@@ -46113,8 +46390,8 @@ var init_metrics3 = __esm({
46113
46390
  file;
46114
46391
  writeQueue = Promise.resolve();
46115
46392
  constructor(file2) {
46116
- this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path41.join(os9.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
46117
- mkdirSync14(path41.dirname(this.file), { recursive: true });
46393
+ this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path42.join(os9.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
46394
+ mkdirSync14(path42.dirname(this.file), { recursive: true });
46118
46395
  }
46119
46396
  /** Metrics file path — doctor/summary readers use this. */
46120
46397
  get filePath() {
@@ -46246,12 +46523,12 @@ Current policy: **lead only**.
46246
46523
  // src/cli/state/fileStateStore.ts
46247
46524
  import { createHash as createHash15, randomUUID as randomUUID3 } from "node:crypto";
46248
46525
  import { promises as fs21 } from "node:fs";
46249
- import * as path43 from "node:path";
46526
+ import * as path45 from "node:path";
46250
46527
  function shortId() {
46251
46528
  return randomUUID3().replace(/-/g, "").slice(0, 12);
46252
46529
  }
46253
46530
  async function writeJsonAtomic(filePath, data) {
46254
- await fs21.mkdir(path43.dirname(filePath), { recursive: true });
46531
+ await fs21.mkdir(path45.dirname(filePath), { recursive: true });
46255
46532
  const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
46256
46533
  await fs21.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
46257
46534
  await fs21.rename(tmp, filePath);
@@ -46312,11 +46589,11 @@ var init_fileStateStore = __esm({
46312
46589
  indexPath = "";
46313
46590
  async init(projectRoot) {
46314
46591
  this.root = projectRoot;
46315
- this.stateDir = path43.join(projectRoot, ".zelari", "state");
46316
- this.commitsDir = path43.join(this.stateDir, "commits");
46317
- this.artifactsDir = path43.join(this.stateDir, "artifacts");
46318
- this.headPath = path43.join(this.stateDir, "HEAD.json");
46319
- this.indexPath = path43.join(this.stateDir, "index.jsonl");
46592
+ this.stateDir = path45.join(projectRoot, ".zelari", "state");
46593
+ this.commitsDir = path45.join(this.stateDir, "commits");
46594
+ this.artifactsDir = path45.join(this.stateDir, "artifacts");
46595
+ this.headPath = path45.join(this.stateDir, "HEAD.json");
46596
+ this.indexPath = path45.join(this.stateDir, "index.jsonl");
46320
46597
  await fs21.mkdir(this.commitsDir, { recursive: true });
46321
46598
  await fs21.mkdir(this.artifactsDir, { recursive: true });
46322
46599
  }
@@ -46329,13 +46606,13 @@ var init_fileStateStore = __esm({
46329
46606
  const discoveries = input.discoveries ?? [];
46330
46607
  const parent = await this.head();
46331
46608
  const id3 = shortId();
46332
- const artifactRel = path43.join("artifacts", id3);
46333
- const artifactAbs = path43.join(this.artifactsDir, id3);
46609
+ const artifactRel = path45.join("artifacts", id3);
46610
+ const artifactAbs = path45.join(this.artifactsDir, id3);
46334
46611
  await fs21.mkdir(artifactAbs, { recursive: true });
46335
46612
  const summary = defaultSummary(input, discoveries);
46336
- await fs21.writeFile(path43.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
46337
- await writeJsonAtomic(path43.join(artifactAbs, "discoveries.json"), discoveries);
46338
- await writeJsonAtomic(path43.join(artifactAbs, "verification.json"), input.verification);
46613
+ await fs21.writeFile(path45.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
46614
+ await writeJsonAtomic(path45.join(artifactAbs, "discoveries.json"), discoveries);
46615
+ await writeJsonAtomic(path45.join(artifactAbs, "verification.json"), input.verification);
46339
46616
  const meta3 = {
46340
46617
  id: id3,
46341
46618
  parentId: parent?.id ?? null,
@@ -46347,14 +46624,14 @@ var init_fileStateStore = __esm({
46347
46624
  workspaceCheckpointId: input.workspaceCheckpointId,
46348
46625
  verification: {
46349
46626
  ...input.verification,
46350
- reportPath: input.verification.reportPath ?? path43.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
46627
+ reportPath: input.verification.reportPath ?? path45.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
46351
46628
  },
46352
46629
  changedPaths: input.changedPaths ?? [],
46353
46630
  stablePromptHash: input.stablePromptHash,
46354
46631
  discoveryCount: discoveries.length,
46355
46632
  artifactDir: artifactRel.replace(/\\/g, "/")
46356
46633
  };
46357
- await writeJsonAtomic(path43.join(this.commitsDir, `${id3}.json`), meta3);
46634
+ await writeJsonAtomic(path45.join(this.commitsDir, `${id3}.json`), meta3);
46358
46635
  await writeJsonAtomic(this.headPath, { id: id3, updatedAt: meta3.createdAt });
46359
46636
  await fs21.appendFile(this.indexPath, JSON.stringify({ id: id3, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
46360
46637
  return stripStored(meta3);
@@ -46365,7 +46642,7 @@ var init_fileStateStore = __esm({
46365
46642
  return this.get(head.id);
46366
46643
  }
46367
46644
  async get(id3) {
46368
- const stored = await readJsonFile(path43.join(this.commitsDir, `${id3}.json`));
46645
+ const stored = await readJsonFile(path45.join(this.commitsDir, `${id3}.json`));
46369
46646
  return stored ? stripStored(stored) : null;
46370
46647
  }
46371
46648
  async list(limit = 20) {
@@ -46404,9 +46681,9 @@ var init_fileStateStore = __esm({
46404
46681
  async loadDiscoveries(id3) {
46405
46682
  const meta3 = id3 ? await this.get(id3) : await this.head();
46406
46683
  if (!meta3) return [];
46407
- const stored = await readJsonFile(path43.join(this.commitsDir, `${meta3.id}.json`));
46684
+ const stored = await readJsonFile(path45.join(this.commitsDir, `${meta3.id}.json`));
46408
46685
  if (!stored?.artifactDir) return [];
46409
- const discPath = path43.join(this.stateDir, stored.artifactDir, "discoveries.json");
46686
+ const discPath = path45.join(this.stateDir, stored.artifactDir, "discoveries.json");
46410
46687
  return await readJsonFile(discPath) ?? [];
46411
46688
  }
46412
46689
  async materializeContext(id3, maxChars = DEFAULT_MATERIALIZE_CHARS) {
@@ -47357,7 +47634,7 @@ var init_mode = __esm({
47357
47634
  });
47358
47635
 
47359
47636
  // src/cli/headless.ts
47360
- import { readFileSync as readFileSync22 } from "node:fs";
47637
+ import { readFileSync as readFileSync23 } from "node:fs";
47361
47638
  function defaultProfileForMode(mode) {
47362
47639
  switch (mode) {
47363
47640
  case "council":
@@ -47378,6 +47655,7 @@ function parseHeadlessFlags(argv) {
47378
47655
  let phase2 = "build";
47379
47656
  let modeExplicit = false;
47380
47657
  let councilFlag = false;
47658
+ let sawModeAuto = false;
47381
47659
  let provider;
47382
47660
  let model;
47383
47661
  let history2;
@@ -47412,7 +47690,7 @@ function parseHeadlessFlags(argv) {
47412
47690
  const next = argv[i + 1];
47413
47691
  if (next) {
47414
47692
  try {
47415
- const fromFile = readFileSync22(next, "utf-8");
47693
+ const fromFile = readFileSync23(next, "utf-8");
47416
47694
  if (fromFile.trim()) task = fromFile;
47417
47695
  } catch {
47418
47696
  }
@@ -47422,11 +47700,17 @@ function parseHeadlessFlags(argv) {
47422
47700
  councilFlag = true;
47423
47701
  } else if (arg === "--mode") {
47424
47702
  const next = argv[i + 1];
47703
+ if (next !== void 0 && next.trim().toLowerCase() === "auto") {
47704
+ sawModeAuto = true;
47705
+ modeExplicit = true;
47706
+ i++;
47707
+ continue;
47708
+ }
47425
47709
  const parsed = next ? parseMode(next) : null;
47426
47710
  if (!parsed) {
47427
47711
  return {
47428
47712
  options: null,
47429
- error: `--mode requires 'kraken', 'council', or 'zelari' (agent=alias), got '${next ?? "(missing)"}'`
47713
+ error: `--mode requires 'kraken', 'council', 'zelari', or 'auto' (agent=alias), got '${next ?? "(missing)"}'`
47430
47714
  };
47431
47715
  }
47432
47716
  mode = parsed;
@@ -47455,7 +47739,7 @@ function parseHeadlessFlags(argv) {
47455
47739
  let raw = null;
47456
47740
  if (arg === "--history-file") {
47457
47741
  try {
47458
- raw = readFileSync22(next, "utf-8");
47742
+ raw = readFileSync23(next, "utf-8");
47459
47743
  } catch {
47460
47744
  raw = null;
47461
47745
  }
@@ -47550,7 +47834,7 @@ function parseHeadlessFlags(argv) {
47550
47834
  const next = argv[i + 1];
47551
47835
  if (next) {
47552
47836
  try {
47553
- const fromFile = readFileSync22(next, "utf-8");
47837
+ const fromFile = readFileSync23(next, "utf-8");
47554
47838
  if (fromFile.trim()) krakenGraph = fromFile;
47555
47839
  } catch {
47556
47840
  }
@@ -47588,6 +47872,7 @@ function parseHeadlessFlags(argv) {
47588
47872
  mode,
47589
47873
  phase: phase2,
47590
47874
  useCouncil: mode === "council",
47875
+ ...sawModeAuto ? { orchestrationAuto: true } : {},
47591
47876
  provider,
47592
47877
  model,
47593
47878
  ...history2 && history2.length > 0 ? { history: history2 } : {},
@@ -48115,7 +48400,7 @@ var init_claudeProvider = __esm({
48115
48400
  // src/cli/memory/legacyImport.ts
48116
48401
  import { createHash as createHash16 } from "node:crypto";
48117
48402
  import { promises as fs22 } from "node:fs";
48118
- import * as path44 from "node:path";
48403
+ import * as path46 from "node:path";
48119
48404
  function sourceId(fact, line) {
48120
48405
  return `jsonl:${fact.id ?? createHash16("sha256").update(line).digest("hex")}`;
48121
48406
  }
@@ -48133,7 +48418,7 @@ function timestamp(value) {
48133
48418
  }
48134
48419
  async function importLegacyMemoryLog(backend, service) {
48135
48420
  const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
48136
- const logPath = path44.join(path44.dirname(backend.databasePath), "log.jsonl");
48421
+ const logPath = path46.join(path46.dirname(backend.databasePath), "log.jsonl");
48137
48422
  let raw;
48138
48423
  try {
48139
48424
  raw = await fs22.readFile(logPath, "utf8");
@@ -48316,7 +48601,7 @@ var init_sqliteCodec = __esm({
48316
48601
  // src/cli/memory/sqliteRpc.ts
48317
48602
  import { existsSync as existsSync27 } from "node:fs";
48318
48603
  import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
48319
- import * as path45 from "node:path";
48604
+ import * as path47 from "node:path";
48320
48605
  import { Worker } from "node:worker_threads";
48321
48606
  function isBusy(error51) {
48322
48607
  const candidate = error51;
@@ -48325,10 +48610,10 @@ function isBusy(error51) {
48325
48610
  );
48326
48611
  }
48327
48612
  function resolveWorkerUrl() {
48328
- const here = path45.dirname(fileURLToPath2(import.meta.url));
48329
- const direct = path45.join(here, "sqliteWorker.mjs");
48613
+ const here = path47.dirname(fileURLToPath2(import.meta.url));
48614
+ const direct = path47.join(here, "sqliteWorker.mjs");
48330
48615
  if (existsSync27(direct)) return pathToFileURL2(direct);
48331
- return pathToFileURL2(path45.join(here, "memory", "sqliteWorker.mjs"));
48616
+ return pathToFileURL2(path47.join(here, "memory", "sqliteWorker.mjs"));
48332
48617
  }
48333
48618
  var SqliteWorkerRpc;
48334
48619
  var init_sqliteRpc = __esm({
@@ -48617,7 +48902,7 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
48617
48902
  // src/cli/memory/sqliteBackend.ts
48618
48903
  import { createHash as createHash17, randomUUID as randomUUID4 } from "node:crypto";
48619
48904
  import { promises as fs23 } from "node:fs";
48620
- import * as path46 from "node:path";
48905
+ import * as path48 from "node:path";
48621
48906
  function boundedLimit(value, fallback = 50) {
48622
48907
  return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
48623
48908
  }
@@ -48679,16 +48964,16 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
48679
48964
  try {
48680
48965
  resolved = await fs23.realpath(projectRoot);
48681
48966
  } catch {
48682
- resolved = path46.resolve(projectRoot);
48967
+ resolved = path48.resolve(projectRoot);
48683
48968
  }
48684
48969
  if (this.initialized && resolved === this.projectRoot) return;
48685
48970
  if (this.initialized) await this.close();
48686
48971
  const filename = this.options.filename ?? "memory.db";
48687
- if (path46.basename(filename) !== filename || filename === "." || filename === "..") {
48972
+ if (path48.basename(filename) !== filename || filename === "." || filename === "..") {
48688
48973
  throw new Error("SQLite memory filename must not contain a path.");
48689
48974
  }
48690
- const zelariDirectory = path46.join(resolved, ".zelari");
48691
- const directory = path46.join(zelariDirectory, "memory");
48975
+ const zelariDirectory = path48.join(resolved, ".zelari");
48976
+ const directory = path48.join(zelariDirectory, "memory");
48692
48977
  for (const candidate of [zelariDirectory, directory]) {
48693
48978
  let stat2;
48694
48979
  try {
@@ -48707,12 +48992,12 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
48707
48992
  }
48708
48993
  }
48709
48994
  const canonicalDirectory = await fs23.realpath(directory);
48710
- const relativeDirectory = path46.relative(resolved, canonicalDirectory);
48711
- if (relativeDirectory.startsWith("..") || path46.isAbsolute(relativeDirectory)) {
48995
+ const relativeDirectory = path48.relative(resolved, canonicalDirectory);
48996
+ if (relativeDirectory.startsWith("..") || path48.isAbsolute(relativeDirectory)) {
48712
48997
  throw new Error("SQLite memory directory resolves outside the active project.");
48713
48998
  }
48714
48999
  this.projectRoot = resolved;
48715
- this.databasePath = path46.join(canonicalDirectory, filename);
49000
+ this.databasePath = path48.join(canonicalDirectory, filename);
48716
49001
  const opened = await this.rpc.open({
48717
49002
  dbPath: this.databasePath,
48718
49003
  schemaSql: SQLITE_MEMORY_BASE_SCHEMA,
@@ -49245,7 +49530,7 @@ __export(serviceFactory_exports, {
49245
49530
  });
49246
49531
  import { createHash as createHash18 } from "node:crypto";
49247
49532
  import { promises as fs24 } from "node:fs";
49248
- import * as path47 from "node:path";
49533
+ import * as path49 from "node:path";
49249
49534
  function isMemoryV2Enabled(env = process.env) {
49250
49535
  if (env.ZELARI_MEMORY === "0") return false;
49251
49536
  if (env.ZELARI_MEMORY_BACKEND === "file" || env.ZELARI_MEMORY_BACKEND === "jsonl") return false;
@@ -49266,7 +49551,7 @@ async function canonicalProjectId(projectRoot) {
49266
49551
  try {
49267
49552
  canonical = await fs24.realpath(projectRoot);
49268
49553
  } catch {
49269
- canonical = path47.resolve(projectRoot);
49554
+ canonical = path49.resolve(projectRoot);
49270
49555
  }
49271
49556
  canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
49272
49557
  if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
@@ -49334,14 +49619,14 @@ var init_serviceFactory = __esm({
49334
49619
  });
49335
49620
 
49336
49621
  // src/cli/workspace/projectInstructions.ts
49337
- import { existsSync as existsSync28, readFileSync as readFileSync23 } from "node:fs";
49622
+ import { existsSync as existsSync28, readFileSync as readFileSync24 } from "node:fs";
49338
49623
  import { join as join26 } from "node:path";
49339
49624
  function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
49340
49625
  for (const name of CANDIDATES) {
49341
49626
  const full = join26(projectRoot, name);
49342
49627
  if (!existsSync28(full)) continue;
49343
49628
  try {
49344
- let raw = readFileSync23(full, "utf8");
49629
+ let raw = readFileSync24(full, "utf8");
49345
49630
  raw = raw.replace(/\r\n/g, "\n").trim();
49346
49631
  if (!raw) continue;
49347
49632
  if (raw.length <= maxChars) {
@@ -49385,7 +49670,7 @@ __export(workspaceSummary_exports, {
49385
49670
  buildWorkspaceSummary: () => buildWorkspaceSummary,
49386
49671
  buildZelariReadHint: () => buildZelariReadHint
49387
49672
  });
49388
- import { existsSync as existsSync29, readFileSync as readFileSync24, readdirSync as readdirSync6, statSync as statSync5 } from "node:fs";
49673
+ import { existsSync as existsSync29, readFileSync as readFileSync25, readdirSync as readdirSync6, statSync as statSync5 } from "node:fs";
49389
49674
  import { join as join27, relative as relative2 } from "node:path";
49390
49675
  function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
49391
49676
  const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
@@ -49423,7 +49708,7 @@ function buildPlanSummary(projectRoot = process.cwd(), options) {
49423
49708
  if (!existsSync29(planPath)) return null;
49424
49709
  let plan;
49425
49710
  try {
49426
- plan = JSON.parse(readFileSync24(planPath, "utf8"));
49711
+ plan = JSON.parse(readFileSync25(planPath, "utf8"));
49427
49712
  } catch {
49428
49713
  return null;
49429
49714
  }
@@ -49581,7 +49866,7 @@ function readPackageJson(projectRoot) {
49581
49866
  const p3 = join27(projectRoot, "package.json");
49582
49867
  if (!existsSync29(p3)) return null;
49583
49868
  try {
49584
- return JSON.parse(readFileSync24(p3, "utf8"));
49869
+ return JSON.parse(readFileSync25(p3, "utf8"));
49585
49870
  } catch {
49586
49871
  return null;
49587
49872
  }
@@ -49709,7 +49994,7 @@ var composeContext_exports = {};
49709
49994
  __export(composeContext_exports, {
49710
49995
  composeProjectContext: () => composeProjectContext
49711
49996
  });
49712
- import { existsSync as existsSync31, readdirSync as readdirSync7, readFileSync as readFileSync25 } from "node:fs";
49997
+ import { existsSync as existsSync31, readdirSync as readdirSync7, readFileSync as readFileSync26 } from "node:fs";
49713
49998
  import { join as join29 } from "node:path";
49714
49999
  function cap2(text, max, label) {
49715
50000
  if (!text || text.length <= max) return { text: text || "", truncated: false };
@@ -49850,15 +50135,15 @@ function readDurableHeadSync(projectRoot) {
49850
50135
  try {
49851
50136
  const headPath = join29(projectRoot, ".zelari", "state", "HEAD.json");
49852
50137
  if (!existsSync31(headPath)) return "";
49853
- const head = JSON.parse(readFileSync25(headPath, "utf8"));
50138
+ const head = JSON.parse(readFileSync26(headPath, "utf8"));
49854
50139
  if (!head?.id) return "";
49855
50140
  const metaPath = join29(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
49856
50141
  if (!existsSync31(metaPath)) return "";
49857
- const meta3 = JSON.parse(readFileSync25(metaPath, "utf8"));
50142
+ const meta3 = JSON.parse(readFileSync26(metaPath, "utf8"));
49858
50143
  const discPath = meta3.artifactDir ? join29(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join29(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
49859
50144
  let discoveries = [];
49860
50145
  if (existsSync31(discPath)) {
49861
- discoveries = JSON.parse(readFileSync25(discPath, "utf8"));
50146
+ discoveries = JSON.parse(readFileSync26(discPath, "utf8"));
49862
50147
  }
49863
50148
  const reusable = discoveries.filter((d) => d.reusable !== false);
49864
50149
  const lines = [
@@ -49891,13 +50176,13 @@ var planDetect_exports = {};
49891
50176
  __export(planDetect_exports, {
49892
50177
  hasWorkspacePlan: () => hasWorkspacePlan
49893
50178
  });
49894
- import { existsSync as existsSync32, readFileSync as readFileSync26 } from "node:fs";
50179
+ import { existsSync as existsSync32, readFileSync as readFileSync27 } from "node:fs";
49895
50180
  import { join as join30 } from "node:path";
49896
50181
  function hasWorkspacePlan(projectRoot = process.cwd()) {
49897
50182
  const planPath = join30(resolveWorkspaceRoot(projectRoot), "plan.json");
49898
50183
  if (!existsSync32(planPath)) return false;
49899
50184
  try {
49900
- const parsed = JSON.parse(readFileSync26(planPath, "utf8"));
50185
+ const parsed = JSON.parse(readFileSync27(planPath, "utf8"));
49901
50186
  return Array.isArray(parsed.phases) && parsed.phases.length > 0;
49902
50187
  } catch {
49903
50188
  return false;
@@ -49959,7 +50244,7 @@ import {
49959
50244
  existsSync as existsSync33,
49960
50245
  readdirSync as readdirSync8,
49961
50246
  writeFileSync as writeFileSync17,
49962
- readFileSync as readFileSync27,
50247
+ readFileSync as readFileSync28,
49963
50248
  mkdirSync as mkdirSync15,
49964
50249
  renameSync as renameSync4
49965
50250
  } from "node:fs";
@@ -49980,7 +50265,7 @@ function readPlan(ctx) {
49980
50265
  if (existsSync33(jsonPath)) {
49981
50266
  try {
49982
50267
  const parsed = JSON.parse(
49983
- readFileSync27(jsonPath, "utf8")
50268
+ readFileSync28(jsonPath, "utf8")
49984
50269
  );
49985
50270
  const { phases, tasks, milestones, ...root } = parsed;
49986
50271
  return {
@@ -49992,8 +50277,8 @@ function readPlan(ctx) {
49992
50277
  } catch {
49993
50278
  }
49994
50279
  }
49995
- const path72 = workspaceFile(ctx.rootDir, "plan");
49996
- const doc = ctx.storage.readIfExists(path72);
50280
+ const path74 = workspaceFile(ctx.rootDir, "plan");
50281
+ const doc = ctx.storage.readIfExists(path74);
49997
50282
  if (!doc) return { phases: [], tasks: [], milestones: [] };
49998
50283
  const meta3 = doc.meta;
49999
50284
  return {
@@ -50171,7 +50456,7 @@ function addMilestoneRecord(ctx, summary, input) {
50171
50456
  dueDate: input.dueDate,
50172
50457
  targetVersion: version2
50173
50458
  });
50174
- const path72 = join31(ctx.rootDir, "milestones", `${id3}.md`);
50459
+ const path74 = join31(ctx.rootDir, "milestones", `${id3}.md`);
50175
50460
  const meta3 = {
50176
50461
  kind: "milestone",
50177
50462
  id: id3,
@@ -50188,7 +50473,7 @@ function addMilestoneRecord(ctx, summary, input) {
50188
50473
  `Target version: ${version2}`,
50189
50474
  ""
50190
50475
  ].join("\n");
50191
- ctx.storage.write(path72, meta3, body);
50476
+ ctx.storage.write(path74, meta3, body);
50192
50477
  return { id: id3, created: true };
50193
50478
  }
50194
50479
  function readPlanSummary(ctx) {
@@ -50392,7 +50677,7 @@ function addIdeaStub(ctx) {
50392
50677
  const tags = args["tags"] ?? [];
50393
50678
  const category = args["category"] ?? "General";
50394
50679
  const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
50395
- const path72 = workspaceArtifact(ctx.rootDir, "decisions", id3);
50680
+ const path74 = workspaceArtifact(ctx.rootDir, "decisions", id3);
50396
50681
  const meta3 = {
50397
50682
  kind: "adr",
50398
50683
  status: "proposed",
@@ -50418,7 +50703,7 @@ function addIdeaStub(ctx) {
50418
50703
  ...consequences.map((c) => `- ${c}`),
50419
50704
  ""
50420
50705
  ].join("\n");
50421
- ctx.storage.write(path72, meta3, body);
50706
+ ctx.storage.write(path74, meta3, body);
50422
50707
  return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
50423
50708
  });
50424
50709
  }
@@ -50500,14 +50785,14 @@ function createDocumentStub(ctx) {
50500
50785
  ctx.storage.write(risksPath, riskMeta, content);
50501
50786
  return `Document "${title}" created at risks.md (workspace root).`;
50502
50787
  }
50503
- const path72 = workspaceArtifact(ctx.rootDir, "docs", slug);
50788
+ const path74 = workspaceArtifact(ctx.rootDir, "docs", slug);
50504
50789
  const meta3 = {
50505
50790
  kind: "doc",
50506
50791
  id: slug,
50507
50792
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
50508
50793
  tags
50509
50794
  };
50510
- ctx.storage.write(path72, meta3, content);
50795
+ ctx.storage.write(path74, meta3, content);
50511
50796
  return `Document "${title}" created at docs/${slug}.md.`;
50512
50797
  });
50513
50798
  }
@@ -50544,7 +50829,7 @@ function searchDocumentsStub(ctx) {
50544
50829
  const results = [];
50545
50830
  for (const file2 of files) {
50546
50831
  if (!existsSync33(file2)) continue;
50547
- const raw = readFileSync27(file2, "utf8");
50832
+ const raw = readFileSync28(file2, "utf8");
50548
50833
  const content = raw.toLowerCase();
50549
50834
  let idx = -1;
50550
50835
  let matchLen = 0;
@@ -50883,21 +51168,21 @@ var init_mcpClient = __esm({
50883
51168
  import {
50884
51169
  existsSync as existsSync34,
50885
51170
  mkdirSync as mkdirSync16,
50886
- readFileSync as readFileSync28,
51171
+ readFileSync as readFileSync29,
50887
51172
  writeFileSync as writeFileSync18
50888
51173
  } from "node:fs";
50889
51174
  import { dirname as dirname9, join as join32 } from "node:path";
50890
- import { homedir as homedir10 } from "node:os";
51175
+ import { homedir as homedir11 } from "node:os";
50891
51176
  function getUserMcpPath() {
50892
- return join32(homedir10(), ".zelari-code", "mcp.json");
51177
+ return join32(homedir11(), ".zelari-code", "mcp.json");
50893
51178
  }
50894
51179
  function getProjectMcpPath(projectRoot) {
50895
51180
  return join32(projectRoot, ".zelari", "mcp.json");
50896
51181
  }
50897
- function readFile4(path72) {
50898
- if (!existsSync34(path72)) return {};
51182
+ function readFile4(path74) {
51183
+ if (!existsSync34(path74)) return {};
50899
51184
  try {
50900
- const parsed = JSON.parse(readFileSync28(path72, "utf8"));
51185
+ const parsed = JSON.parse(readFileSync29(path74, "utf8"));
50901
51186
  const out = {};
50902
51187
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
50903
51188
  if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
@@ -50913,10 +51198,10 @@ function readFile4(path72) {
50913
51198
  return {};
50914
51199
  }
50915
51200
  }
50916
- function writeFile2(path72, servers) {
50917
- mkdirSync16(dirname9(path72), { recursive: true });
51201
+ function writeFile3(path74, servers) {
51202
+ mkdirSync16(dirname9(path74), { recursive: true });
50918
51203
  const body = { mcpServers: servers };
50919
- writeFileSync18(path72, `${JSON.stringify(body, null, 2)}
51204
+ writeFileSync18(path74, `${JSON.stringify(body, null, 2)}
50920
51205
  `, "utf8");
50921
51206
  }
50922
51207
  function listMcpServers(projectRoot) {
@@ -50949,9 +51234,9 @@ function upsertMcpServer(opts) {
50949
51234
  if (!opts.config.command?.trim()) {
50950
51235
  return { ok: false, error: "command is required" };
50951
51236
  }
50952
- let path72;
51237
+ let path74;
50953
51238
  if (opts.scope === "user") {
50954
- path72 = getUserMcpPath();
51239
+ path74 = getUserMcpPath();
50955
51240
  } else {
50956
51241
  const root = opts.projectRoot?.trim();
50957
51242
  if (!root) {
@@ -50960,30 +51245,30 @@ function upsertMcpServer(opts) {
50960
51245
  error: "projectRoot required for project scope (Open Folder first)"
50961
51246
  };
50962
51247
  }
50963
- path72 = getProjectMcpPath(root);
51248
+ path74 = getProjectMcpPath(root);
50964
51249
  }
50965
- const current = readFile4(path72);
51250
+ const current = readFile4(path74);
50966
51251
  current[name] = {
50967
51252
  command: opts.config.command.trim(),
50968
51253
  args: opts.config.args,
50969
51254
  env: opts.config.env,
50970
51255
  enabled: opts.config.enabled !== false
50971
51256
  };
50972
- writeFile2(path72, current);
50973
- return { ok: true, path: path72 };
51257
+ writeFile3(path74, current);
51258
+ return { ok: true, path: path74 };
50974
51259
  }
50975
51260
  function removeMcpServer(opts) {
50976
- const path72 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
50977
- if (!path72) {
51261
+ const path74 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
51262
+ if (!path74) {
50978
51263
  return { ok: false, error: "projectRoot required for project scope" };
50979
51264
  }
50980
- const current = readFile4(path72);
51265
+ const current = readFile4(path74);
50981
51266
  if (!(opts.name in current)) {
50982
- return { ok: false, error: `Server "${opts.name}" not found in ${path72}` };
51267
+ return { ok: false, error: `Server "${opts.name}" not found in ${path74}` };
50983
51268
  }
50984
51269
  delete current[opts.name];
50985
- writeFile2(path72, current);
50986
- return { ok: true, path: path72 };
51270
+ writeFile3(path74, current);
51271
+ return { ok: true, path: path74 };
50987
51272
  }
50988
51273
  var init_mcpConfigIo = __esm({
50989
51274
  "src/cli/mcp/mcpConfigIo.ts"() {
@@ -51125,14 +51410,14 @@ __export(mcpManager_exports, {
51125
51410
  readMcpConfig: () => readMcpConfig,
51126
51411
  registerMcpTools: () => registerMcpTools
51127
51412
  });
51128
- import { existsSync as existsSync35, readFileSync as readFileSync29 } from "node:fs";
51413
+ import { existsSync as existsSync35, readFileSync as readFileSync30 } from "node:fs";
51129
51414
  import { join as join33 } from "node:path";
51130
- import { homedir as homedir11 } from "node:os";
51415
+ import { homedir as homedir12 } from "node:os";
51131
51416
  function readMcpConfig(projectRoot = process.cwd(), opts) {
51132
51417
  const merged = {};
51133
51418
  const paths = [];
51134
51419
  if (process.env["ZELARI_MCP_USER"] !== "0") {
51135
- paths.push(join33(homedir11(), ".zelari-code", "mcp.json"));
51420
+ paths.push(join33(homedir12(), ".zelari-code", "mcp.json"));
51136
51421
  }
51137
51422
  if (!opts?.skipProjectMcp) {
51138
51423
  paths.push(join33(projectRoot, ".zelari", "mcp.json"));
@@ -51140,7 +51425,7 @@ function readMcpConfig(projectRoot = process.cwd(), opts) {
51140
51425
  for (const p3 of paths) {
51141
51426
  if (!existsSync35(p3)) continue;
51142
51427
  try {
51143
- const parsed = JSON.parse(readFileSync29(p3, "utf8"));
51428
+ const parsed = JSON.parse(readFileSync30(p3, "utf8"));
51144
51429
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
51145
51430
  if (!cfg || typeof cfg.command !== "string" || cfg.command.length === 0) continue;
51146
51431
  merged[name] = cfg;
@@ -51379,15 +51664,15 @@ __export(agentsMd_exports, {
51379
51664
  serializeAgentsMd: () => serializeAgentsMd,
51380
51665
  updateAgentsMd: () => updateAgentsMd
51381
51666
  });
51382
- import { existsSync as existsSync36, readFileSync as readFileSync30, writeFileSync as writeFileSync19 } from "node:fs";
51667
+ import { existsSync as existsSync36, readFileSync as readFileSync31, writeFileSync as writeFileSync19 } from "node:fs";
51383
51668
  import { createHash as createHash19 } from "node:crypto";
51384
51669
  import { join as join34 } from "node:path";
51385
51670
  import { readFile as readFile5 } from "node:fs/promises";
51386
51671
  async function readPackageJson2(projectRoot) {
51387
- const path72 = join34(projectRoot, "package.json");
51388
- if (!existsSync36(path72)) return null;
51672
+ const path74 = join34(projectRoot, "package.json");
51673
+ if (!existsSync36(path74)) return null;
51389
51674
  try {
51390
- return JSON.parse(await readFile5(path72, "utf8"));
51675
+ return JSON.parse(await readFile5(path74, "utf8"));
51391
51676
  } catch {
51392
51677
  return null;
51393
51678
  }
@@ -51437,7 +51722,7 @@ async function genConventions(ctx) {
51437
51722
  const lines = [];
51438
51723
  const claudeMd = join34(ctx.projectRoot, "CLAUDE.MD");
51439
51724
  if (existsSync36(claudeMd)) {
51440
- const content = readFileSync30(claudeMd, "utf8");
51725
+ const content = readFileSync31(claudeMd, "utf8");
51441
51726
  const match = content.match(/## Architecture rules[\s\S]+?(?=\n## |\n*$)/);
51442
51727
  if (match) {
51443
51728
  lines.push('<!-- Extracted from CLAUDE.MD "Architecture rules" -->');
@@ -51469,9 +51754,9 @@ async function genBuild(ctx) {
51469
51754
  ].join("\n");
51470
51755
  }
51471
51756
  async function genOpenQuestions(ctx) {
51472
- const path72 = join34(ctx.rootDir, "risks.md");
51473
- if (!existsSync36(path72)) return "_No open questions._";
51474
- const content = readFileSync30(path72, "utf8");
51757
+ const path74 = join34(ctx.rootDir, "risks.md");
51758
+ if (!existsSync36(path74)) return "_No open questions._";
51759
+ const content = readFileSync31(path74, "utf8");
51475
51760
  const lines = content.split("\n");
51476
51761
  const questions = [];
51477
51762
  let currentTitle = "";
@@ -51547,7 +51832,7 @@ function titleCase(id3) {
51547
51832
  async function updateAgentsMd(ctx, projectRoot) {
51548
51833
  const agentsPath = join34(projectRoot, "AGENTS.MD");
51549
51834
  if (existsSync36(agentsPath)) {
51550
- const content = readFileSync30(agentsPath, "utf8");
51835
+ const content = readFileSync31(agentsPath, "utf8");
51551
51836
  const hasAnyMarker = AUTO_SECTIONS.some((id3) => content.includes(MARKER_OPEN(id3)));
51552
51837
  if (!hasAnyMarker) {
51553
51838
  return {
@@ -51563,7 +51848,7 @@ async function updateAgentsMd(ctx, projectRoot) {
51563
51848
  }
51564
51849
  let manualContent = "";
51565
51850
  if (existsSync36(agentsPath)) {
51566
- const { manualBlocks } = parseAgentsMd(readFileSync30(agentsPath, "utf8"));
51851
+ const { manualBlocks } = parseAgentsMd(readFileSync31(agentsPath, "utf8"));
51567
51852
  manualContent = manualBlocks.after;
51568
51853
  } else {
51569
51854
  const projectName2 = projectName(projectRoot);
@@ -51579,7 +51864,7 @@ async function updateAgentsMd(ctx, projectRoot) {
51579
51864
  ""
51580
51865
  ].join("\n");
51581
51866
  }
51582
- const oldContent = existsSync36(agentsPath) ? readFileSync30(agentsPath, "utf8") : "";
51867
+ const oldContent = existsSync36(agentsPath) ? readFileSync31(agentsPath, "utf8") : "";
51583
51868
  const { sections: oldSections } = parseAgentsMd(oldContent);
51584
51869
  const changedSections = [];
51585
51870
  for (const id3 of AUTO_SECTIONS) {
@@ -51716,7 +52001,7 @@ var init_completeDesign = __esm({
51716
52001
  });
51717
52002
 
51718
52003
  // src/cli/workspace/planDriftCheck.ts
51719
- import { existsSync as existsSync37, readFileSync as readFileSync31, readdirSync as readdirSync9, statSync as statSync6, writeFileSync as writeFileSync20 } from "node:fs";
52004
+ import { existsSync as existsSync37, readFileSync as readFileSync32, readdirSync as readdirSync9, statSync as statSync6, writeFileSync as writeFileSync20 } from "node:fs";
51720
52005
  import { join as join35 } from "node:path";
51721
52006
  function findCanonicalDoc(rootDir) {
51722
52007
  const docsDir = join35(rootDir, "docs");
@@ -51745,9 +52030,9 @@ function versionKey(value) {
51745
52030
  function firstString2(v) {
51746
52031
  return typeof v === "string" && v.trim().length > 0 ? v : null;
51747
52032
  }
51748
- function readFileSyncSafe(path72) {
52033
+ function readFileSyncSafe(path74) {
51749
52034
  try {
51750
- return readFileSync31(path72, "utf8");
52035
+ return readFileSync32(path74, "utf8");
51751
52036
  } catch {
51752
52037
  return null;
51753
52038
  }
@@ -51762,7 +52047,7 @@ async function runPlanDriftCheck(rootDir) {
51762
52047
  }
51763
52048
  let plan;
51764
52049
  try {
51765
- plan = JSON.parse(readFileSync31(planPath, "utf8"));
52050
+ plan = JSON.parse(readFileSync32(planPath, "utf8"));
51766
52051
  } catch {
51767
52052
  return { ran: false, reason: ".zelari/plan.json corrupt" };
51768
52053
  }
@@ -51888,7 +52173,7 @@ var init_planDriftCheck = __esm({
51888
52173
 
51889
52174
  // src/cli/workspace/projectSmoke.ts
51890
52175
  import { spawn as spawn14 } from "node:child_process";
51891
- import { existsSync as existsSync38, readFileSync as readFileSync32 } from "node:fs";
52176
+ import { existsSync as existsSync38, readFileSync as readFileSync33 } from "node:fs";
51892
52177
  import { join as join36 } from "node:path";
51893
52178
  function pickSmokeScript(scripts) {
51894
52179
  if (!scripts) return null;
@@ -51907,7 +52192,7 @@ async function runProjectSmoke(projectRoot, timeoutMs2 = DEFAULT_TIMEOUT_MS3) {
51907
52192
  }
51908
52193
  let scripts = {};
51909
52194
  try {
51910
- const pkg = JSON.parse(readFileSync32(pkgPath, "utf8"));
52195
+ const pkg = JSON.parse(readFileSync33(pkgPath, "utf8"));
51911
52196
  scripts = pkg.scripts ?? {};
51912
52197
  } catch {
51913
52198
  return { ran: false, reason: "package.json unreadable (skipped)" };
@@ -51995,7 +52280,7 @@ __export(postCouncilHook_exports, {
51995
52280
  runPostCouncilHook: () => runPostCouncilHook
51996
52281
  });
51997
52282
  import { spawn as spawn15 } from "node:child_process";
51998
- import { existsSync as existsSync39, readFileSync as readFileSync33 } from "node:fs";
52283
+ import { existsSync as existsSync39, readFileSync as readFileSync34 } from "node:fs";
51999
52284
  import { join as join37 } from "node:path";
52000
52285
  async function runCompleteDesignPostProcessor(ctx, options) {
52001
52286
  if (options?.runMode === "implementation") {
@@ -52017,7 +52302,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
52017
52302
  }
52018
52303
  let phaseCount = 0;
52019
52304
  try {
52020
- const parsed = JSON.parse(readFileSync33(planJsonPath2, "utf8"));
52305
+ const parsed = JSON.parse(readFileSync34(planJsonPath2, "utf8"));
52021
52306
  phaseCount = Array.isArray(parsed.phases) ? parsed.phases.length : 0;
52022
52307
  } catch {
52023
52308
  return { ran: false, reason: ".zelari/plan.json corrupt" };
@@ -52210,8 +52495,8 @@ async function runPostCouncilHook(ctx, options) {
52210
52495
  sources: scope.sources
52211
52496
  } : void 0
52212
52497
  });
52213
- const path72 = writeCouncilCompletion(ctx.rootDir, completion);
52214
- completionHook = { ran: true, path: path72, completion };
52498
+ const path74 = writeCouncilCompletion(ctx.rootDir, completion);
52499
+ completionHook = { ran: true, path: path74, completion };
52215
52500
  } catch (err) {
52216
52501
  completionHook = {
52217
52502
  ran: true,
@@ -52252,11 +52537,11 @@ __export(councilFeedback_exports, {
52252
52537
  import {
52253
52538
  promises as fs25,
52254
52539
  existsSync as existsSync40,
52255
- readFileSync as readFileSync34,
52540
+ readFileSync as readFileSync35,
52256
52541
  writeFileSync as writeFileSync21,
52257
52542
  mkdirSync as mkdirSync17
52258
52543
  } from "node:fs";
52259
- import path48 from "node:path";
52544
+ import path50 from "node:path";
52260
52545
  import os10 from "node:os";
52261
52546
  var FeedbackStore;
52262
52547
  var init_councilFeedback = __esm({
@@ -52267,7 +52552,7 @@ var init_councilFeedback = __esm({
52267
52552
  now;
52268
52553
  entries = [];
52269
52554
  constructor(options = {}) {
52270
- this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path48.join(os10.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
52555
+ this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path50.join(os10.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
52271
52556
  this.now = options.now ?? Date.now;
52272
52557
  this.load();
52273
52558
  }
@@ -52362,7 +52647,7 @@ var init_councilFeedback = __esm({
52362
52647
  load() {
52363
52648
  if (!existsSync40(this.file)) return;
52364
52649
  try {
52365
- const raw = readFileSync34(this.file, "utf-8");
52650
+ const raw = readFileSync35(this.file, "utf-8");
52366
52651
  const parsed = JSON.parse(raw);
52367
52652
  if (parsed && Array.isArray(parsed.entries)) {
52368
52653
  this.entries = parsed.entries.filter(
@@ -52373,7 +52658,7 @@ var init_councilFeedback = __esm({
52373
52658
  }
52374
52659
  }
52375
52660
  save() {
52376
- mkdirSync17(path48.dirname(this.file), { recursive: true });
52661
+ mkdirSync17(path50.dirname(this.file), { recursive: true });
52377
52662
  writeFileSync21(
52378
52663
  this.file,
52379
52664
  JSON.stringify({ entries: this.entries }, null, 2),
@@ -52441,7 +52726,7 @@ import { execFile as execFile3 } from "node:child_process";
52441
52726
  import { promisify as promisify2 } from "node:util";
52442
52727
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
52443
52728
  import { tmpdir as tmpdir2 } from "node:os";
52444
- import path49 from "node:path";
52729
+ import path51 from "node:path";
52445
52730
  import { randomUUID as randomUUID5 } from "node:crypto";
52446
52731
  async function git3(cwd, args, env) {
52447
52732
  const { stdout } = await execFileAsync2("git", ["-C", cwd, ...args], {
@@ -52461,8 +52746,8 @@ async function isGitRepo(cwd) {
52461
52746
  return await gitSafe(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true";
52462
52747
  }
52463
52748
  async function withTempIndex(fn) {
52464
- const dir = mkdtempSync(path49.join(tmpdir2(), "zelari-ckpt-"));
52465
- const indexFile = path49.join(dir, "index");
52749
+ const dir = mkdtempSync(path51.join(tmpdir2(), "zelari-ckpt-"));
52750
+ const indexFile = path51.join(dir, "index");
52466
52751
  try {
52467
52752
  return await fn(indexFile);
52468
52753
  } finally {
@@ -52553,7 +52838,7 @@ async function restoreCheckpoint(cwd, id3) {
52553
52838
  const deleted = [];
52554
52839
  for (const rel2 of added) {
52555
52840
  try {
52556
- rmSync2(path49.join(cwd, rel2), { force: true });
52841
+ rmSync2(path51.join(cwd, rel2), { force: true });
52557
52842
  deleted.push(rel2);
52558
52843
  } catch {
52559
52844
  }
@@ -52654,7 +52939,7 @@ __export(fileBackend_exports, {
52654
52939
  });
52655
52940
  import { randomUUID as randomUUID6 } from "node:crypto";
52656
52941
  import { promises as fs26 } from "node:fs";
52657
- import * as path50 from "node:path";
52942
+ import * as path52 from "node:path";
52658
52943
  function tokenize(text) {
52659
52944
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
52660
52945
  }
@@ -52705,8 +52990,8 @@ var init_fileBackend = __esm({
52705
52990
  logPath = "";
52706
52991
  memoryDir = "";
52707
52992
  async init(projectRoot) {
52708
- this.memoryDir = path50.join(projectRoot, ".zelari", "memory");
52709
- this.logPath = path50.join(this.memoryDir, "log.jsonl");
52993
+ this.memoryDir = path52.join(projectRoot, ".zelari", "memory");
52994
+ this.logPath = path52.join(this.memoryDir, "log.jsonl");
52710
52995
  await fs26.mkdir(this.memoryDir, { recursive: true });
52711
52996
  }
52712
52997
  async add(content, metadata2 = {}, graph) {
@@ -52779,12 +53064,12 @@ var init_fileBackend = __esm({
52779
53064
 
52780
53065
  // src/cli/traceStore.ts
52781
53066
  import { promises as fs27 } from "node:fs";
52782
- import * as path51 from "node:path";
53067
+ import * as path53 from "node:path";
52783
53068
  function traceDir(projectRoot) {
52784
- return path51.join(projectRoot, ".zelari", "trace");
53069
+ return path53.join(projectRoot, ".zelari", "trace");
52785
53070
  }
52786
53071
  function tracePath(projectRoot, missionId) {
52787
- return path51.join(traceDir(projectRoot), `${missionId}.json`);
53072
+ return path53.join(traceDir(projectRoot), `${missionId}.json`);
52788
53073
  }
52789
53074
  async function saveTrace(projectRoot, missionId, entries) {
52790
53075
  const dir = traceDir(projectRoot);
@@ -52821,7 +53106,7 @@ __export(zelariMission_exports, {
52821
53106
  });
52822
53107
  import { randomUUID as randomUUID7 } from "node:crypto";
52823
53108
  import { promises as fs28 } from "node:fs";
52824
- import * as path52 from "node:path";
53109
+ import * as path54 from "node:path";
52825
53110
  function resolveMaxIterations(env = process.env) {
52826
53111
  const raw = env.ZELARI_MISSION_MAX_ITER;
52827
53112
  const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
@@ -52864,10 +53149,10 @@ function isMissionAutoStart(env = process.env) {
52864
53149
  return env.ZELARI_MISSION_AUTO === "1";
52865
53150
  }
52866
53151
  async function writeMissionState(projectRoot, state3) {
52867
- const dir = path52.join(projectRoot, ".zelari");
53152
+ const dir = path54.join(projectRoot, ".zelari");
52868
53153
  await fs28.mkdir(dir, { recursive: true });
52869
53154
  await fs28.writeFile(
52870
- path52.join(dir, "mission-state.json"),
53155
+ path54.join(dir, "mission-state.json"),
52871
53156
  JSON.stringify(state3, null, 2) + "\n",
52872
53157
  "utf8"
52873
53158
  );
@@ -53542,7 +53827,7 @@ function safeSocketPath(socketPath) {
53542
53827
  return socketPath.trim();
53543
53828
  }
53544
53829
  function startPermissionBroker(socketPath, handlers, opts) {
53545
- const path72 = safeSocketPath(socketPath);
53830
+ const path74 = safeSocketPath(socketPath);
53546
53831
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
53547
53832
  const sockets = /* @__PURE__ */ new Set();
53548
53833
  const server = createServer2((socket) => {
@@ -53642,10 +53927,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
53642
53927
  return new Promise((resolve7, reject) => {
53643
53928
  const onError = (err) => reject(err);
53644
53929
  server.once("error", onError);
53645
- server.listen(path72, () => {
53930
+ server.listen(path74, () => {
53646
53931
  server.removeListener("error", onError);
53647
53932
  resolve7({
53648
- socketPath: path72,
53933
+ socketPath: path74,
53649
53934
  stop: () => new Promise((res) => {
53650
53935
  for (const s of sockets) s.destroy();
53651
53936
  sockets.clear();
@@ -53656,7 +53941,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
53656
53941
  if (done) return;
53657
53942
  done = true;
53658
53943
  if (process.platform !== "win32") {
53659
- unlink(path72, () => res());
53944
+ unlink(path74, () => res());
53660
53945
  } else {
53661
53946
  res();
53662
53947
  }
@@ -53669,11 +53954,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
53669
53954
  });
53670
53955
  }
53671
53956
  function requestBrokerAsk(socketPath, ask, opts) {
53672
- const path72 = safeSocketPath(socketPath);
53957
+ const path74 = safeSocketPath(socketPath);
53673
53958
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
53674
53959
  const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
53675
53960
  return new Promise((resolve7, reject) => {
53676
- const socket = connect(path72);
53961
+ const socket = connect(path74);
53677
53962
  let buffer = "";
53678
53963
  let settled = false;
53679
53964
  const settle = (fn) => {
@@ -53688,7 +53973,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
53688
53973
  settle(
53689
53974
  () => reject(
53690
53975
  new Error(
53691
- `permission broker unavailable at "${path72}" (connect timed out after ${connectTimeoutMs}ms)`
53976
+ `permission broker unavailable at "${path74}" (connect timed out after ${connectTimeoutMs}ms)`
53692
53977
  )
53693
53978
  )
53694
53979
  );
@@ -54431,9 +54716,9 @@ __export(graphMemory_exports, {
54431
54716
  toGraphSnapshot: () => toGraphSnapshot
54432
54717
  });
54433
54718
  import { promises as fs31 } from "node:fs";
54434
- import path56 from "node:path";
54719
+ import path58 from "node:path";
54435
54720
  function snapshotPath(cwd) {
54436
- return path56.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
54721
+ return path58.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
54437
54722
  }
54438
54723
  function toGraphSnapshot(graph, opts) {
54439
54724
  const unresolved = (opts.unresolvedFindings ?? []).map((u) => ({
@@ -54460,7 +54745,7 @@ async function saveGraphSnapshot(cwd, snapshot) {
54460
54745
  try {
54461
54746
  await fs31.access(cwd);
54462
54747
  const file2 = snapshotPath(cwd);
54463
- await fs31.mkdir(path56.dirname(file2), { recursive: true });
54748
+ await fs31.mkdir(path58.dirname(file2), { recursive: true });
54464
54749
  await fs31.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
54465
54750
  } catch {
54466
54751
  }
@@ -54527,7 +54812,7 @@ var SNAPSHOT_DIR, SNAPSHOT_FILE, MAX_SNAPSHOT_FINDINGS_CHARS;
54527
54812
  var init_graphMemory = __esm({
54528
54813
  "src/cli/kraken/graphMemory.ts"() {
54529
54814
  "use strict";
54530
- SNAPSHOT_DIR = path56.join(".zelari", "kraken");
54815
+ SNAPSHOT_DIR = path58.join(".zelari", "kraken");
54531
54816
  SNAPSHOT_FILE = "last-graph.json";
54532
54817
  MAX_SNAPSHOT_FINDINGS_CHARS = 400;
54533
54818
  }
@@ -54543,14 +54828,14 @@ var init_tentacle = __esm({
54543
54828
 
54544
54829
  // src/cli/kraken/workbench.ts
54545
54830
  import { promises as fs32 } from "node:fs";
54546
- import path57 from "node:path";
54831
+ import path59 from "node:path";
54547
54832
  function isWorkbenchEnabled(env = process.env) {
54548
54833
  const v = (env.ZELARI_KRAKEN_WORKBENCH ?? "1").trim().toLowerCase();
54549
54834
  if (v === "0" || v === "false" || v === "no" || v === "off") return false;
54550
54835
  return true;
54551
54836
  }
54552
54837
  function workbenchPath(cwd, graphId) {
54553
- return path57.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
54838
+ return path59.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
54554
54839
  }
54555
54840
  function countByStatus2(nodes) {
54556
54841
  const out = { pending: 0, running: 0, done: 0, error: 0, skipped: 0 };
@@ -54713,7 +54998,7 @@ var init_workbench = __esm({
54713
54998
  if (!this.enabled) return null;
54714
54999
  if (!this.dirty && this.lastWrite) return this.lastWrite;
54715
55000
  const out = workbenchPath(this.cwd, this.graphId);
54716
- await fs32.mkdir(path57.dirname(out), { recursive: true });
55001
+ await fs32.mkdir(path59.dirname(out), { recursive: true });
54717
55002
  const body = this.render();
54718
55003
  const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
54719
55004
  await fs32.writeFile(tmp, body, "utf8");
@@ -54910,7 +55195,7 @@ __export(executor_exports, {
54910
55195
  thoroughnessForKind: () => thoroughnessForKind
54911
55196
  });
54912
55197
  import { existsSync as existsSync41 } from "node:fs";
54913
- import path58 from "node:path";
55198
+ import path60 from "node:path";
54914
55199
  function resolveMaxParallel(env = process.env) {
54915
55200
  const raw = env.ZELARI_KRAKEN_MAX_PARALLEL;
54916
55201
  if (raw === void 0 || raw === "") return DEFAULT_MAX_PARALLEL;
@@ -54968,7 +55253,7 @@ function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultC
54968
55253
  }
54969
55254
  function defaultChecksExists(cwd) {
54970
55255
  try {
54971
- return existsSync41(path58.join(cwd, ".zelari", "world", "checks.json"));
55256
+ return existsSync41(path60.join(cwd, ".zelari", "world", "checks.json"));
54972
55257
  } catch {
54973
55258
  return false;
54974
55259
  }
@@ -56364,17 +56649,17 @@ var init_prereqChecks = __esm({
56364
56649
  });
56365
56650
 
56366
56651
  // src/cli/plugins/prefs.ts
56367
- import { existsSync as existsSync43, readFileSync as readFileSync35, writeFileSync as writeFileSync22, mkdirSync as mkdirSync18 } from "node:fs";
56368
- import path61 from "node:path";
56652
+ import { existsSync as existsSync43, readFileSync as readFileSync36, writeFileSync as writeFileSync22, mkdirSync as mkdirSync18 } from "node:fs";
56653
+ import path63 from "node:path";
56369
56654
  import os11 from "node:os";
56370
56655
  function getPluginPrefsPath() {
56371
- return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path61.join(os11.homedir(), ".tmp", "zelari-code", "plugins.json");
56656
+ return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path63.join(os11.homedir(), ".tmp", "zelari-code", "plugins.json");
56372
56657
  }
56373
56658
  function getPluginPrefs() {
56374
56659
  const file2 = getPluginPrefsPath();
56375
56660
  try {
56376
56661
  if (!existsSync43(file2)) return { ...DEFAULTS2, dontAskAgain: {} };
56377
- const raw = readFileSync35(file2, "utf-8");
56662
+ const raw = readFileSync36(file2, "utf-8");
56378
56663
  const parsed = JSON.parse(raw);
56379
56664
  if (parsed && typeof parsed === "object" && parsed.dontAskAgain && typeof parsed.dontAskAgain === "object") {
56380
56665
  const clean = {};
@@ -56389,7 +56674,7 @@ function getPluginPrefs() {
56389
56674
  }
56390
56675
  function writePluginPrefs(prefs) {
56391
56676
  const file2 = getPluginPrefsPath();
56392
- mkdirSync18(path61.dirname(file2), { recursive: true });
56677
+ mkdirSync18(path63.dirname(file2), { recursive: true });
56393
56678
  writeFileSync22(file2, JSON.stringify(prefs, null, 2), {
56394
56679
  encoding: "utf-8",
56395
56680
  mode: 384
@@ -56426,7 +56711,7 @@ __export(registry_exports, {
56426
56711
  isBinaryOnPath: () => isBinaryOnPath
56427
56712
  });
56428
56713
  import { existsSync as existsSync44 } from "node:fs";
56429
- import path62 from "node:path";
56714
+ import path64 from "node:path";
56430
56715
  function detectLocalBin(bin) {
56431
56716
  return (cwd) => {
56432
56717
  try {
@@ -56444,7 +56729,7 @@ function isBinaryOnPath(bin, opts = {}) {
56444
56729
  const platform = opts.platform ?? process.platform;
56445
56730
  const exists = opts.exists ?? existsSync44;
56446
56731
  const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
56447
- const pathMod = platform === "win32" ? path62.win32 : path62.posix;
56732
+ const pathMod = platform === "win32" ? path64.win32 : path64.posix;
56448
56733
  const sep4 = platform === "win32" ? ";" : ":";
56449
56734
  const dirs = pathEnv.split(sep4).filter((d) => d.length > 0);
56450
56735
  const candidates = [bin];
@@ -57176,7 +57461,7 @@ __export(atMentions_exports, {
57176
57461
  extractAtMentions: () => extractAtMentions,
57177
57462
  hasAtMentions: () => hasAtMentions
57178
57463
  });
57179
- import { existsSync as existsSync47, readFileSync as readFileSync37, statSync as statSync9 } from "node:fs";
57464
+ import { existsSync as existsSync47, readFileSync as readFileSync38, statSync as statSync9 } from "node:fs";
57180
57465
  import { basename as basename4, isAbsolute as isAbsolute4, relative as relative5, resolve as resolve5, sep as sep2 } from "node:path";
57181
57466
  function isImagePath(abs) {
57182
57467
  const ext = abs.split(".").pop()?.toLowerCase() ?? "";
@@ -57282,7 +57567,7 @@ function resolveMention(token, cwd) {
57282
57567
  note: `image too large (${Math.round(st.size / 1024)} KB) \u2014 path only`
57283
57568
  };
57284
57569
  }
57285
- const dataBase64 = readFileSync37(abs).toString("base64");
57570
+ const dataBase64 = readFileSync38(abs).toString("base64");
57286
57571
  return {
57287
57572
  raw: token,
57288
57573
  path: rel2,
@@ -57293,7 +57578,7 @@ function resolveMention(token, cwd) {
57293
57578
  };
57294
57579
  }
57295
57580
  try {
57296
- const buf = readFileSync37(abs);
57581
+ const buf = readFileSync38(abs);
57297
57582
  const head = buf.subarray(0, 800).toString("utf8");
57298
57583
  if (!isProbablyText(abs, head)) {
57299
57584
  return {
@@ -58278,9 +58563,9 @@ __export(triggerLock_exports, {
58278
58563
  releaseLock: () => releaseLock
58279
58564
  });
58280
58565
  import { promises as fs40 } from "node:fs";
58281
- import * as path67 from "node:path";
58566
+ import * as path69 from "node:path";
58282
58567
  function lockPath(projectRoot) {
58283
- return path67.join(projectRoot, ".zelari", "trigger.lock");
58568
+ return path69.join(projectRoot, ".zelari", "trigger.lock");
58284
58569
  }
58285
58570
  function isPidAlive(pid) {
58286
58571
  try {
@@ -58293,7 +58578,7 @@ function isPidAlive(pid) {
58293
58578
  }
58294
58579
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
58295
58580
  const lp = lockPath(projectRoot);
58296
- const dir = path67.dirname(lp);
58581
+ const dir = path69.dirname(lp);
58297
58582
  await fs40.mkdir(dir, { recursive: true });
58298
58583
  try {
58299
58584
  const raw = await fs40.readFile(lp, "utf8");
@@ -58721,12 +59006,12 @@ import {
58721
59006
  existsSync as existsSync49,
58722
59007
  mkdirSync as mkdirSync21,
58723
59008
  readdirSync as readdirSync10,
58724
- readFileSync as readFileSync38,
59009
+ readFileSync as readFileSync39,
58725
59010
  rmSync as rmSync4,
58726
59011
  writeFileSync as writeFileSync24
58727
59012
  } from "node:fs";
58728
59013
  import { dirname as dirname13, join as join45 } from "node:path";
58729
- import { homedir as homedir12 } from "node:os";
59014
+ import { homedir as homedir13 } from "node:os";
58730
59015
  function ensureBuiltinSkillsLoadedSync() {
58731
59016
  if (builtinsLoaded) return;
58732
59017
  for (const spec of BUILTIN_SKILL_MODULES) {
@@ -58737,7 +59022,7 @@ function ensureBuiltinSkillsLoadedSync() {
58737
59022
  }
58738
59023
  }
58739
59024
  function getUserSkillsDir() {
58740
- return join45(homedir12(), ".zelari-code", "skills");
59025
+ return join45(homedir13(), ".zelari-code", "skills");
58741
59026
  }
58742
59027
  function getProjectSkillsDir(projectRoot) {
58743
59028
  return join45(projectRoot, ".zelari", "skills");
@@ -58803,7 +59088,7 @@ function scanSkillsDir(dir, projectRoot, seen, out) {
58803
59088
  const skillPath = skillFilePath(dir, entry);
58804
59089
  if (!existsSync49(skillPath)) continue;
58805
59090
  try {
58806
- const parsed = parseSkillMd(readFileSync38(skillPath, "utf8"), skillPath);
59091
+ const parsed = parseSkillMd(readFileSync39(skillPath, "utf8"), skillPath);
58807
59092
  if (!parsed) continue;
58808
59093
  if (seen.has(parsed.name)) continue;
58809
59094
  seen.add(parsed.name);
@@ -58887,7 +59172,7 @@ function upsertSkill(opts) {
58887
59172
  }
58888
59173
  dir = getProjectSkillsDir(root);
58889
59174
  }
58890
- const path72 = skillFilePath(dir, name);
59175
+ const path74 = skillFilePath(dir, name);
58891
59176
  const content = serializeSkillMd({
58892
59177
  name,
58893
59178
  description,
@@ -58896,13 +59181,13 @@ function upsertSkill(opts) {
58896
59181
  tools: opts.tools,
58897
59182
  cost: opts.cost
58898
59183
  });
58899
- const parsed = parseSkillMd(content, path72);
59184
+ const parsed = parseSkillMd(content, path74);
58900
59185
  if (!parsed) {
58901
59186
  return { ok: false, error: "Generated SKILL.md failed validation" };
58902
59187
  }
58903
- mkdirSync21(dirname13(path72), { recursive: true });
58904
- writeFileSync24(path72, content, "utf8");
58905
- return { ok: true, path: path72 };
59188
+ mkdirSync21(dirname13(path74), { recursive: true });
59189
+ writeFileSync24(path74, content, "utf8");
59190
+ return { ok: true, path: path74 };
58906
59191
  }
58907
59192
  function removeSkill(opts) {
58908
59193
  const name = opts.name.trim().toLowerCase();
@@ -58920,8 +59205,8 @@ function removeSkill(opts) {
58920
59205
  dir = getProjectSkillsDir(root);
58921
59206
  }
58922
59207
  const skillDir = join45(dir, name);
58923
- const path72 = skillFilePath(dir, name);
58924
- if (!existsSync49(path72) && !existsSync49(skillDir)) {
59208
+ const path74 = skillFilePath(dir, name);
59209
+ if (!existsSync49(path74) && !existsSync49(skillDir)) {
58925
59210
  return { ok: false, error: `Skill "${name}" not found in ${dir}` };
58926
59211
  }
58927
59212
  try {
@@ -58932,7 +59217,7 @@ function removeSkill(opts) {
58932
59217
  error: err instanceof Error ? err.message : String(err)
58933
59218
  };
58934
59219
  }
58935
- return { ok: true, path: path72 };
59220
+ return { ok: true, path: path74 };
58936
59221
  }
58937
59222
  var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
58938
59223
  var init_skillConfigIo = __esm({
@@ -59051,7 +59336,7 @@ var init_jsonApi = __esm({
59051
59336
  });
59052
59337
 
59053
59338
  // src/cli/memory/mcpAdapter.ts
59054
- import * as path69 from "node:path";
59339
+ import * as path71 from "node:path";
59055
59340
  var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
59056
59341
  var init_mcpAdapter = __esm({
59057
59342
  "src/cli/memory/mcpAdapter.ts"() {
@@ -59221,8 +59506,8 @@ var init_mcpAdapter = __esm({
59221
59506
  this.takeWrite();
59222
59507
  const externalFile = args.source?.file;
59223
59508
  if (externalFile) {
59224
- const normalized = path69.normalize(externalFile);
59225
- if (path69.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path69.sep}`)) {
59509
+ const normalized = path71.normalize(externalFile);
59510
+ if (path71.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path71.sep}`)) {
59226
59511
  throw new Error("source.file must be project-relative and cannot escape the project");
59227
59512
  }
59228
59513
  }
@@ -59728,14 +60013,14 @@ var init_permissionCli = __esm({
59728
60013
  import {
59729
60014
  existsSync as existsSync50,
59730
60015
  mkdirSync as mkdirSync22,
59731
- readFileSync as readFileSync39,
60016
+ readFileSync as readFileSync40,
59732
60017
  writeFileSync as writeFileSync25
59733
60018
  } from "node:fs";
59734
60019
  import { join as join46 } from "node:path";
59735
- import { homedir as homedir13 } from "node:os";
60020
+ import { homedir as homedir14 } from "node:os";
59736
60021
  import { createHash as createHash20, randomBytes as randomBytes6, timingSafeEqual } from "node:crypto";
59737
60022
  function getZelariHome() {
59738
- return join46(homedir13(), ".zelari-code");
60023
+ return join46(homedir14(), ".zelari-code");
59739
60024
  }
59740
60025
  function getCompanionConfigPath() {
59741
60026
  return join46(getZelariHome(), "companion.json");
@@ -59750,12 +60035,12 @@ function ensureHome() {
59750
60035
  }
59751
60036
  }
59752
60037
  function loadCompanionConfig() {
59753
- const path72 = getCompanionConfigPath();
59754
- if (!existsSync50(path72)) {
60038
+ const path74 = getCompanionConfigPath();
60039
+ if (!existsSync50(path74)) {
59755
60040
  return { projects: [] };
59756
60041
  }
59757
60042
  try {
59758
- const raw = JSON.parse(readFileSync39(path72, "utf8"));
60043
+ const raw = JSON.parse(readFileSync40(path74, "utf8"));
59759
60044
  const projects = Array.isArray(raw.projects) ? raw.projects.filter(
59760
60045
  (p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
59761
60046
  ).map((p3) => ({
@@ -59793,16 +60078,16 @@ function loadOrCreateToken(explicit) {
59793
60078
  return { token: explicit.trim(), created: false };
59794
60079
  }
59795
60080
  ensureHome();
59796
- const path72 = getCompanionTokenPath();
59797
- if (existsSync50(path72)) {
59798
- const t = readFileSync39(path72, "utf8").trim();
60081
+ const path74 = getCompanionTokenPath();
60082
+ if (existsSync50(path74)) {
60083
+ const t = readFileSync40(path74, "utf8").trim();
59799
60084
  if (t) return { token: t, created: false };
59800
60085
  }
59801
60086
  const token = randomBytes6(24).toString("base64url");
59802
- writeFileSync25(path72, token + "\n", "utf8");
60087
+ writeFileSync25(path74, token + "\n", "utf8");
59803
60088
  try {
59804
60089
  const fs42 = __require("node:fs");
59805
- fs42.chmodSync?.(path72, 384);
60090
+ fs42.chmodSync?.(path74, 384);
59806
60091
  } catch {
59807
60092
  }
59808
60093
  return { token, created: true };
@@ -59827,17 +60112,17 @@ function mergeProjects(cfg, extraPaths) {
59827
60112
  byId.set(p3.id, p3);
59828
60113
  }
59829
60114
  for (const raw of extraPaths) {
59830
- const path72 = raw.trim();
59831
- if (!path72) continue;
59832
- let id3 = slugFromPath(path72);
60115
+ const path74 = raw.trim();
60116
+ if (!path74) continue;
60117
+ let id3 = slugFromPath(path74);
59833
60118
  let n = 2;
59834
- while (byId.has(id3) && byId.get(id3).path !== path72) {
59835
- id3 = `${slugFromPath(path72)}-${n++}`;
60119
+ while (byId.has(id3) && byId.get(id3).path !== path74) {
60120
+ id3 = `${slugFromPath(path74)}-${n++}`;
59836
60121
  }
59837
60122
  byId.set(id3, {
59838
60123
  id: id3,
59839
- name: slugFromPath(path72),
59840
- path: path72
60124
+ name: slugFromPath(path74),
60125
+ path: path74
59841
60126
  });
59842
60127
  }
59843
60128
  return [...byId.values()];
@@ -60214,9 +60499,9 @@ async function runCompanionServe(opts = {}) {
60214
60499
  return;
60215
60500
  }
60216
60501
  const url2 = parseUrl(req);
60217
- const path72 = url2.pathname.replace(/\/+$/, "") || "/";
60502
+ const path74 = url2.pathname.replace(/\/+$/, "") || "/";
60218
60503
  try {
60219
- if (req.method === "GET" && (path72 === "/health" || path72 === "/v1/health")) {
60504
+ if (req.method === "GET" && (path74 === "/health" || path74 === "/v1/health")) {
60220
60505
  sendJson2(res, 200, {
60221
60506
  ok: true,
60222
60507
  service: "zelari-companion",
@@ -60228,18 +60513,18 @@ async function runCompanionServe(opts = {}) {
60228
60513
  });
60229
60514
  return;
60230
60515
  }
60231
- if (path72.startsWith("/v1")) {
60516
+ if (path74.startsWith("/v1")) {
60232
60517
  if (!tokenMatches(token, getBearer(req))) {
60233
60518
  sendJson2(res, 401, { ok: false, error: "unauthorized" });
60234
60519
  return;
60235
60520
  }
60236
60521
  }
60237
- if (req.method === "GET" && path72 === "/v1/config") {
60522
+ if (req.method === "GET" && path74 === "/v1/config") {
60238
60523
  const snap = buildDesktopConfigSnapshot();
60239
60524
  sendJson2(res, 200, { ok: true, ...snap });
60240
60525
  return;
60241
60526
  }
60242
- if (req.method === "GET" && path72 === "/v1/projects") {
60527
+ if (req.method === "GET" && path74 === "/v1/projects") {
60243
60528
  sendJson2(res, 200, {
60244
60529
  ok: true,
60245
60530
  projects: projects.map((p3) => ({
@@ -60250,7 +60535,7 @@ async function runCompanionServe(opts = {}) {
60250
60535
  });
60251
60536
  return;
60252
60537
  }
60253
- if (req.method === "GET" && path72 === "/v1/runs") {
60538
+ if (req.method === "GET" && path74 === "/v1/runs") {
60254
60539
  sendJson2(res, 200, {
60255
60540
  ok: true,
60256
60541
  active: runs.getActive(),
@@ -60268,7 +60553,7 @@ async function runCompanionServe(opts = {}) {
60268
60553
  });
60269
60554
  return;
60270
60555
  }
60271
- if (req.method === "POST" && path72 === "/v1/runs") {
60556
+ if (req.method === "POST" && path74 === "/v1/runs") {
60272
60557
  const raw = await readBody(req);
60273
60558
  let body = {};
60274
60559
  try {
@@ -60315,7 +60600,7 @@ async function runCompanionServe(opts = {}) {
60315
60600
  });
60316
60601
  return;
60317
60602
  }
60318
- const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path72);
60603
+ const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path74);
60319
60604
  if (req.method === "GET" && eventsMatch) {
60320
60605
  const runId = eventsMatch[1];
60321
60606
  const run = runs.getRun(runId);
@@ -60380,7 +60665,7 @@ async function runCompanionServe(opts = {}) {
60380
60665
  }, 500);
60381
60666
  return;
60382
60667
  }
60383
- const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path72);
60668
+ const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path74);
60384
60669
  if (req.method === "POST" && cancelMatch) {
60385
60670
  const runId = cancelMatch[1];
60386
60671
  const result = runs.cancel(runId);
@@ -60530,26 +60815,26 @@ __export(doctor_exports, {
60530
60815
  runDoctor: () => runDoctor
60531
60816
  });
60532
60817
  import { execSync as execSync2 } from "node:child_process";
60533
- import { existsSync as existsSync52, readFileSync as readFileSync40, readlinkSync, statSync as statSync10 } from "node:fs";
60818
+ import { existsSync as existsSync52, readFileSync as readFileSync41, readlinkSync, statSync as statSync10 } from "node:fs";
60534
60819
  import { createRequire as createRequire3 } from "node:module";
60535
60820
  import { fileURLToPath as fileURLToPath3 } from "node:url";
60536
- import path70 from "node:path";
60821
+ import path72 from "node:path";
60537
60822
  function findPackageRoot(start) {
60538
60823
  let dir = start;
60539
60824
  for (let i = 0; i < 6; i += 1) {
60540
- const candidate = path70.join(dir, "package.json");
60825
+ const candidate = path72.join(dir, "package.json");
60541
60826
  if (existsSync52(candidate)) {
60542
60827
  try {
60543
- const pkg = JSON.parse(readFileSync40(candidate, "utf8"));
60828
+ const pkg = JSON.parse(readFileSync41(candidate, "utf8"));
60544
60829
  if (pkg.name === "zelari-code") return dir;
60545
60830
  } catch {
60546
60831
  }
60547
60832
  }
60548
- const parent = path70.dirname(dir);
60833
+ const parent = path72.dirname(dir);
60549
60834
  if (parent === dir) break;
60550
60835
  dir = parent;
60551
60836
  }
60552
- return path70.resolve(__dirname3, "..", "..", "..");
60837
+ return path72.resolve(__dirname3, "..", "..", "..");
60553
60838
  }
60554
60839
  function tryExec(cmd) {
60555
60840
  try {
@@ -60563,8 +60848,8 @@ function tryExec(cmd) {
60563
60848
  }
60564
60849
  function readPackageJson3() {
60565
60850
  try {
60566
- const pkgPath = path70.join(packageRoot, "package.json");
60567
- return JSON.parse(readFileSync40(pkgPath, "utf8"));
60851
+ const pkgPath = path72.join(packageRoot, "package.json");
60852
+ return JSON.parse(readFileSync41(pkgPath, "utf8"));
60568
60853
  } catch {
60569
60854
  return null;
60570
60855
  }
@@ -60579,7 +60864,7 @@ function checkShim(pkgName) {
60579
60864
  }
60580
60865
  const isWin = process.platform === "win32";
60581
60866
  const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
60582
- const shimPath = path70.join(prefix, shimName);
60867
+ const shimPath = path72.join(prefix, shimName);
60583
60868
  if (!existsSync52(shimPath)) {
60584
60869
  return FAIL(
60585
60870
  `shim not found at ${shimPath}
@@ -60589,7 +60874,7 @@ function checkShim(pkgName) {
60589
60874
  try {
60590
60875
  const st = statSync10(shimPath);
60591
60876
  if (isWin) {
60592
- const content = readFileSync40(shimPath, "utf8");
60877
+ const content = readFileSync41(shimPath, "utf8");
60593
60878
  if (content.includes(`${pkgName}\\bin\\`) || content.includes(`${pkgName}/bin/`)) {
60594
60879
  return OK(`shim OK at ${shimPath} (${st.size} bytes)`);
60595
60880
  }
@@ -60607,8 +60892,8 @@ function checkShim(pkgName) {
60607
60892
  fix: npm install -g ${pkgName}@latest --force`
60608
60893
  );
60609
60894
  }
60610
- const resolved = path70.resolve(path70.dirname(shimPath), target);
60611
- const expected = path70.join(
60895
+ const resolved = path72.resolve(path72.dirname(shimPath), target);
60896
+ const expected = path72.join(
60612
60897
  prefix,
60613
60898
  "node_modules",
60614
60899
  pkgName,
@@ -60647,7 +60932,7 @@ function checkNode(pkg) {
60647
60932
  return OK(`node ${raw}`);
60648
60933
  }
60649
60934
  function checkBundle() {
60650
- const bundle = path70.join(packageRoot, "dist", "cli", "main.bundled.js");
60935
+ const bundle = path72.join(packageRoot, "dist", "cli", "main.bundled.js");
60651
60936
  if (!existsSync52(bundle)) {
60652
60937
  return FAIL(
60653
60938
  `dist/cli/main.bundled.js missing at ${bundle}
@@ -60668,7 +60953,7 @@ function checkRuntimeDeps() {
60668
60953
  const missing = [];
60669
60954
  for (const dep of required2) {
60670
60955
  try {
60671
- const localReq = createRequire3(path70.join(packageRoot, "package.json"));
60956
+ const localReq = createRequire3(path72.join(packageRoot, "package.json"));
60672
60957
  localReq.resolve(dep);
60673
60958
  } catch {
60674
60959
  missing.push(dep);
@@ -60868,7 +61153,7 @@ var init_doctor = __esm({
60868
61153
  init_metrics3();
60869
61154
  init_contextGrowthSummary();
60870
61155
  require3 = createRequire3(import.meta.url);
60871
- __dirname3 = path70.dirname(fileURLToPath3(import.meta.url));
61156
+ __dirname3 = path72.dirname(fileURLToPath3(import.meta.url));
60872
61157
  packageRoot = findPackageRoot(__dirname3);
60873
61158
  OK = (message) => ({
60874
61159
  ok: true,
@@ -61052,15 +61337,15 @@ __export(inspect_exports, {
61052
61337
  collectInspectReport: () => collectInspectReport,
61053
61338
  runInspect: () => runInspect
61054
61339
  });
61055
- import path71 from "node:path";
61056
- import { existsSync as existsSync53, readFileSync as readFileSync41, readdirSync as readdirSync11 } from "node:fs";
61057
- import { homedir as homedir14 } from "node:os";
61340
+ import path73 from "node:path";
61341
+ import { existsSync as existsSync53, readFileSync as readFileSync42, readdirSync as readdirSync11 } from "node:fs";
61342
+ import { homedir as homedir15 } from "node:os";
61058
61343
  async function collectInspectReport(cwd = process.cwd()) {
61059
61344
  ensureBuiltinSkillsLoadedSync();
61060
61345
  const snap = listSkillsSnapshot(cwd);
61061
61346
  const mcp = listMcpServers(cwd);
61062
- const userMcpPath = path71.join(homedir14(), ".zelari-code", "mcp.json");
61063
- const projectMcpPath = path71.join(cwd, ".zelari", "mcp.json");
61347
+ const userMcpPath = path73.join(homedir15(), ".zelari-code", "mcp.json");
61348
+ const projectMcpPath = path73.join(cwd, ".zelari", "mcp.json");
61064
61349
  const globalHooks = globalHooksDir();
61065
61350
  const projectHooks = projectHooksDir(cwd);
61066
61351
  const projectTrusted = isFolderTrusted(cwd);
@@ -61088,9 +61373,9 @@ async function collectInspectReport(cwd = process.cwd()) {
61088
61373
  configSources: [
61089
61374
  { path: userMcpPath, exists: existsSync53(userMcpPath) },
61090
61375
  { path: projectMcpPath, exists: existsSync53(projectMcpPath) },
61091
- { path: path71.join(homedir14(), ".zelari-code", "provider.json"), exists: existsSync53(path71.join(homedir14(), ".zelari-code", "provider.json")) },
61092
- { path: path71.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync53(path71.join(cwd, ".zelari", "AGENTS.md")) },
61093
- { path: path71.join(cwd, "AGENTS.md"), exists: existsSync53(path71.join(cwd, "AGENTS.md")) }
61376
+ { path: path73.join(homedir15(), ".zelari-code", "provider.json"), exists: existsSync53(path73.join(homedir15(), ".zelari-code", "provider.json")) },
61377
+ { path: path73.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync53(path73.join(cwd, ".zelari", "AGENTS.md")) },
61378
+ { path: path73.join(cwd, "AGENTS.md"), exists: existsSync53(path73.join(cwd, "AGENTS.md")) }
61094
61379
  ],
61095
61380
  skills: {
61096
61381
  total: snap.skills.length,
@@ -61130,14 +61415,14 @@ function listJsonFiles(dir) {
61130
61415
  }
61131
61416
  function findAgentsMd(cwd) {
61132
61417
  const candidates = [
61133
- path71.join(cwd, "AGENTS.md"),
61134
- path71.join(cwd, ".zelari", "AGENTS.md")
61418
+ path73.join(cwd, "AGENTS.md"),
61419
+ path73.join(cwd, ".zelari", "AGENTS.md")
61135
61420
  ];
61136
61421
  const found = [];
61137
61422
  for (const c of candidates) {
61138
61423
  if (existsSync53(c)) {
61139
61424
  try {
61140
- const text = readFileSync41(c, "utf8");
61425
+ const text = readFileSync42(c, "utf8");
61141
61426
  found.push(`${c} (${text.length} bytes)`);
61142
61427
  } catch {
61143
61428
  found.push(`${c} (unreadable)`);
@@ -64431,10 +64716,11 @@ import { createHash as createHash14 } from "node:crypto";
64431
64716
  init_runtime2();
64432
64717
  init_verification2();
64433
64718
  import { readFile as readFile3 } from "node:fs/promises";
64434
- import path42 from "node:path";
64719
+ import path43 from "node:path";
64435
64720
  function nativePackEnabled(env = process.env) {
64436
64721
  const v = env.ZELARI_VERIFY_PACK?.toLowerCase();
64437
- return v === "1" || v === "on" || v === "true";
64722
+ if (v === "0" || v === "off" || v === "false") return false;
64723
+ return true;
64438
64724
  }
64439
64725
  function resolvePackCommands(env, scripts) {
64440
64726
  const pick2 = (override, scriptName) => {
@@ -64458,7 +64744,7 @@ function packTimeoutMs(env = process.env) {
64458
64744
  }
64459
64745
  async function readPackageScripts(cwd = process.cwd()) {
64460
64746
  try {
64461
- const raw = await readFile3(path42.join(cwd, "package.json"), "utf-8");
64747
+ const raw = await readFile3(path43.join(cwd, "package.json"), "utf-8");
64462
64748
  const parsed = JSON.parse(raw);
64463
64749
  if (parsed && typeof parsed === "object" && typeof parsed.scripts === "object") {
64464
64750
  return parsed.scripts;
@@ -64497,7 +64783,8 @@ function strictDoneEnabled(surface = "kraken") {
64497
64783
  return true;
64498
64784
  }
64499
64785
  const v = process.env.ZELARI_STRICT_DONE;
64500
- return v === "1" || v === "true";
64786
+ if (v === "0" || v === "false") return false;
64787
+ return true;
64501
64788
  }
64502
64789
  function criterionId(check2, index) {
64503
64790
  const slug = check2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
@@ -64734,6 +65021,145 @@ function strictGateEventPayload(evaluation) {
64734
65021
  };
64735
65022
  }
64736
65023
 
65024
+ // src/cli/kraken/completionProof.ts
65025
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
65026
+ import path44 from "node:path";
65027
+ function verdictOf(evaluation) {
65028
+ return evaluation.evaluation?.verdict ?? (evaluation.blocked ? "BLOCKED" : "PASS");
65029
+ }
65030
+ function cell(text, max = 200) {
65031
+ const flat = text.replace(/\r?\n/g, " ").replace(/\|/g, "\\|").trim();
65032
+ return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
65033
+ }
65034
+ function evidenceCell(result) {
65035
+ if (!result || result.evidence.length === 0) return "\u2014";
65036
+ return result.evidence.map((e) => {
65037
+ const parts = [e.tier];
65038
+ if (e.seq !== void 0) parts.push(`seq ${e.seq}`);
65039
+ if (e.digest) parts.push(`digest ${e.digest.slice(0, 8)}\u2026`);
65040
+ return parts.join(" \xB7 ");
65041
+ }).join("; ");
65042
+ }
65043
+ function proofRows(evaluation) {
65044
+ const nativeById = new Map(
65045
+ (evaluation.native?.criteria ?? []).map((c) => [c.id, c])
65046
+ );
65047
+ const rows = /* @__PURE__ */ new Map();
65048
+ for (const result of evaluation.results ?? []) {
65049
+ const criterion = nativeById.get(result.criterionId);
65050
+ rows.set(result.criterionId, {
65051
+ id: result.criterionId,
65052
+ text: criterion?.text ?? null,
65053
+ required: criterion ? criterion.required : true,
65054
+ status: result.status,
65055
+ result
65056
+ });
65057
+ }
65058
+ for (const unsatisfied of evaluation.evaluation?.unsatisfied ?? []) {
65059
+ if (rows.has(unsatisfied.id)) continue;
65060
+ const criterion = nativeById.get(unsatisfied.id);
65061
+ rows.set(unsatisfied.id, {
65062
+ id: unsatisfied.id,
65063
+ text: criterion?.text ?? null,
65064
+ required: true,
65065
+ // satisfied/unsatisfied lists cover required criteria only
65066
+ status: unsatisfied.status,
65067
+ result: null
65068
+ });
65069
+ }
65070
+ return [...rows.values()];
65071
+ }
65072
+ function renderMarkdown(evaluation, meta3) {
65073
+ const lines = [
65074
+ "# Completion Proof",
65075
+ "",
65076
+ "Strict build-gate proof-of-work (ADR-0023). The machine-readable twin of",
65077
+ "this document \u2014 `completion-proof.json` \u2014 is the exact `verification.run`",
65078
+ "payload sent to the session spine.",
65079
+ "",
65080
+ `- **Verdict**: **${verdictOf(evaluation)}**`,
65081
+ `- **Strict gate**: ${evaluation.strict ? "on" : "off"}`,
65082
+ `- **Turn blocked**: ${evaluation.blocked ? "yes" : "no"}`,
65083
+ `- **Summary**: ${cell(evaluation.summary, 400)}`,
65084
+ `- **Legacy selection gate**: ${evaluation.gate.passed}/${evaluation.gate.total} passed` + (evaluation.gate.failedChecks.length > 0 ? `; failed: ${evaluation.gate.failedChecks.length}` : "") + (evaluation.gate.unknownChecks.length > 0 ? `; unknown: ${evaluation.gate.unknownChecks.length}` : "")
65085
+ ];
65086
+ if (meta3.surface) lines.push(`- **Surface**: ${meta3.surface}`);
65087
+ if (meta3.sessionId) lines.push(`- **Session**: ${meta3.sessionId} (session spine)`);
65088
+ if (meta3.generatedAt !== void 0) {
65089
+ lines.push(`- **Generated**: ${new Date(meta3.generatedAt).toISOString()}`);
65090
+ }
65091
+ const rows = proofRows(evaluation);
65092
+ lines.push("", "## Criteria", "", "| Criterion | Required | Status | Evidence |", "| --- | --- | --- | --- |");
65093
+ if (rows.length === 0) {
65094
+ lines.push("| _none \u2014 no criteria joined this evaluation_ | \u2014 | \u2014 | \u2014 |");
65095
+ }
65096
+ for (const row of rows) {
65097
+ const label = row.text ? `\`${row.id}\` \u2014 ${cell(row.text)}` : `\`${row.id}\``;
65098
+ lines.push(`| ${label} | ${row.required ? "yes" : "no"} | ${row.status} | ${evidenceCell(row.result)} |`);
65099
+ }
65100
+ const unsatisfied = evaluation.evaluation?.unsatisfied ?? [];
65101
+ if (unsatisfied.length > 0) {
65102
+ lines.push("", "### Unsatisfied", "");
65103
+ for (const u of unsatisfied) lines.push(`- \`${u.id}\`: **${u.status}** \u2014 ${cell(u.reason, 300)}`);
65104
+ }
65105
+ const native = evaluation.native;
65106
+ if (native) {
65107
+ lines.push(
65108
+ "",
65109
+ `## Native criteria pack \u2014 ${native.packId}`,
65110
+ "",
65111
+ "| Criterion | Command | Status | Detail |",
65112
+ "| --- | --- | --- | --- |"
65113
+ );
65114
+ for (const result of native.results) {
65115
+ const criterion = native.criteria.find((c) => c.id === result.criterionId);
65116
+ const check2 = criterion?.check;
65117
+ const command = check2?.kind === "command" ? check2.command : "\u2014";
65118
+ const label = criterion?.text ? `\`${result.criterionId}\` \u2014 ${cell(criterion.text, 120)}` : `\`${result.criterionId}\``;
65119
+ lines.push(`| ${label} | \`${cell(command, 120)}\` | ${result.status} | ${cell(result.detail ?? "\u2014")} |`);
65120
+ }
65121
+ }
65122
+ const review = evaluation.review;
65123
+ if (review) {
65124
+ lines.push(
65125
+ "",
65126
+ "## Advisory verifier review",
65127
+ "",
65128
+ "_Advisory only \u2014 this review cannot change the gate verdict above._",
65129
+ "",
65130
+ `- **Verdict**: ${review.verdict}`
65131
+ );
65132
+ if (review.score !== void 0) lines.push(`- **Score**: ${review.score}`);
65133
+ const model = review.effectiveModel.model ?? review.effectiveModel.provider ?? review.effectiveModel.mode;
65134
+ lines.push(`- **Model**: ${model}${review.usedLogprobs ? " (logprobs)" : ""}`);
65135
+ if (review.fallback) lines.push(`- **Fallback**: ${review.fallback}`);
65136
+ if (review.rationale) lines.push(`- **Rationale**: ${cell(review.rationale, 400)}`);
65137
+ }
65138
+ lines.push("", "---", "", "Machine record: `completion-proof.json` (same directory).");
65139
+ return `${lines.join("\n")}
65140
+ `;
65141
+ }
65142
+ function renderCompletionProof(evaluation, meta3 = {}) {
65143
+ return {
65144
+ markdown: renderMarkdown(evaluation, meta3),
65145
+ json: JSON.stringify(strictGateEventPayload(evaluation), null, 2)
65146
+ };
65147
+ }
65148
+ async function writeCompletionProof(evaluation, options = {}) {
65149
+ try {
65150
+ const dir = path44.join(options.baseDir ?? process.cwd(), ".zelari");
65151
+ await mkdir2(dir, { recursive: true });
65152
+ const { markdown, json: json3 } = renderCompletionProof(evaluation, options.meta);
65153
+ const markdownPath = path44.join(dir, "completion-proof.md");
65154
+ const jsonPath = path44.join(dir, "completion-proof.json");
65155
+ await writeFile2(markdownPath, markdown, "utf8");
65156
+ await writeFile2(jsonPath, json3, "utf8");
65157
+ return { markdownPath, jsonPath };
65158
+ } catch {
65159
+ return null;
65160
+ }
65161
+ }
65162
+
64737
65163
  // src/cli/hooks/permissionPicker.ts
64738
65164
  init_toolPermissions();
64739
65165
 
@@ -65774,10 +66200,15 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
65774
66200
  if (event.type === "agent_end") {
65775
66201
  let krakenSuppressFinish = false;
65776
66202
  const krakenSpineEmit = (input) => writerRef.current?.spine?.appendEvent(input) ?? Promise.resolve(null);
66203
+ const writeProofSafe2 = (gate) => writeCompletionProof(gate, { meta: { surface: "kraken", sessionId: sessionId2 } }).then(
66204
+ () => void 0,
66205
+ () => void 0
66206
+ );
65777
66207
  if (event.reason === "completed" && !krakenRepairEnqueued && (isKrakenSelectionEnabled() || nativePackEnabled()) && workPhase === "build") {
65778
66208
  const strictGate = await evaluateStrictBuildGate("build", { emit: krakenSpineEmit });
65779
66209
  const krakenGate = strictGate.gate;
65780
66210
  writerRef.current?.spine?.verificationRun(strictGateEventPayload(strictGate));
66211
+ await writeProofSafe2(strictGate);
65781
66212
  if (krakenGate.blocked) {
65782
66213
  krakenRepairEnqueued = true;
65783
66214
  markRepairTriggered();
@@ -65791,10 +66222,13 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
65791
66222
  krakenSuppressFinish = true;
65792
66223
  }
65793
66224
  }
65794
- if (event.reason === "completed" && krakenRepairEnqueued && !(await evaluateStrictBuildGate("build", { emit: krakenSpineEmit })).blocked) {
66225
+ const repairCheck = event.reason === "completed" && krakenRepairEnqueued ? await evaluateStrictBuildGate("build", { emit: krakenSpineEmit }) : null;
66226
+ if (repairCheck) await writeProofSafe2(repairCheck);
66227
+ if (repairCheck && !repairCheck.blocked) {
65795
66228
  markRepairSucceeded();
65796
66229
  } else if (event.reason === "completed" && krakenRepairEnqueued) {
65797
66230
  const still = await evaluateStrictBuildGate("build", { emit: krakenSpineEmit });
66231
+ await writeProofSafe2(still);
65798
66232
  if (still.blocked) {
65799
66233
  appendSystem(
65800
66234
  setMessages,
@@ -67910,7 +68344,7 @@ init_sessionManager();
67910
68344
  // src/cli/gitOps.ts
67911
68345
  import { execFile as execFile4 } from "node:child_process";
67912
68346
  import { promisify as promisify3 } from "node:util";
67913
- import path53 from "node:path";
68347
+ import path55 from "node:path";
67914
68348
  var execFileAsync3 = promisify3(execFile4);
67915
68349
  async function git4(cwd, args) {
67916
68350
  try {
@@ -67956,7 +68390,7 @@ async function undoWorkingChanges(opts = {}) {
67956
68390
  };
67957
68391
  }
67958
68392
  function defaultProjectRoot() {
67959
- return path53.resolve(__dirname, "..", "..", "..");
68393
+ return path55.resolve(__dirname, "..", "..", "..");
67960
68394
  }
67961
68395
 
67962
68396
  // src/cli/slashHandlers/git.ts
@@ -68243,11 +68677,11 @@ function handleCacheStats(ctx) {
68243
68677
  init_messageHelpers();
68244
68678
  init_serviceFactory();
68245
68679
  import { promises as fs30 } from "node:fs";
68246
- import * as path55 from "node:path";
68680
+ import * as path57 from "node:path";
68247
68681
 
68248
68682
  // src/cli/memory/promotion.ts
68249
68683
  import { promises as fs29 } from "node:fs";
68250
- import * as path54 from "node:path";
68684
+ import * as path56 from "node:path";
68251
68685
  var START = "<!-- zelari:memory-promotions:start -->";
68252
68686
  var END = "<!-- zelari:memory-promotions:end -->";
68253
68687
  var DURABLE_KINDS = /* @__PURE__ */ new Set(["fact", "decision", "constraint", "preference", "procedure"]);
@@ -68258,13 +68692,13 @@ function lineFor(node) {
68258
68692
  }
68259
68693
  async function promoteMemoryToAgentsMd(projectRoot, node) {
68260
68694
  if (node.status !== "active") {
68261
- return { added: false, path: path54.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
68695
+ return { added: false, path: path56.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
68262
68696
  }
68263
68697
  if (!DURABLE_KINDS.has(node.kind)) {
68264
- return { added: false, path: path54.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
68698
+ return { added: false, path: path56.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
68265
68699
  }
68266
- const root = await fs29.realpath(projectRoot).catch(() => path54.resolve(projectRoot));
68267
- const target = path54.join(root, "AGENTS.md");
68700
+ const root = await fs29.realpath(projectRoot).catch(() => path56.resolve(projectRoot));
68701
+ const target = path56.join(root, "AGENTS.md");
68268
68702
  try {
68269
68703
  const stat2 = await fs29.lstat(target);
68270
68704
  if (stat2.isSymbolicLink() || !stat2.isFile()) throw new Error("AGENTS.md must be a regular project file.");
@@ -68329,22 +68763,22 @@ function sourceLine(source2) {
68329
68763
  return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
68330
68764
  }
68331
68765
  function isInside(root, target) {
68332
- const relative6 = path55.relative(root, target);
68333
- return relative6 === "" || !relative6.startsWith("..") && !path55.isAbsolute(relative6);
68766
+ const relative6 = path57.relative(root, target);
68767
+ return relative6 === "" || !relative6.startsWith("..") && !path57.isAbsolute(relative6);
68334
68768
  }
68335
68769
  async function safeExportPath(cwd, requested) {
68336
- const lexicalRoot = path55.resolve(cwd);
68770
+ const lexicalRoot = path57.resolve(cwd);
68337
68771
  const root = await fs30.realpath(lexicalRoot).catch(() => lexicalRoot);
68338
- const fallback = path55.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
68339
- const target = requested?.trim() ? path55.resolve(root, requested.trim()) : fallback;
68772
+ const fallback = path57.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
68773
+ const target = requested?.trim() ? path57.resolve(root, requested.trim()) : fallback;
68340
68774
  if (!isInside(root, target)) {
68341
68775
  throw new Error("Export path must stay inside the active project.");
68342
68776
  }
68343
- const parent = path55.dirname(target);
68344
- const relativeParent = path55.relative(root, parent);
68777
+ const parent = path57.dirname(target);
68778
+ const relativeParent = path57.relative(root, parent);
68345
68779
  let cursor = root;
68346
- for (const segment of relativeParent.split(path55.sep).filter(Boolean)) {
68347
- cursor = path55.join(cursor, segment);
68780
+ for (const segment of relativeParent.split(path57.sep).filter(Boolean)) {
68781
+ cursor = path57.join(cursor, segment);
68348
68782
  try {
68349
68783
  const stat2 = await fs30.lstat(cursor);
68350
68784
  if (stat2.isSymbolicLink()) {
@@ -68516,9 +68950,9 @@ ${message}` : message
68516
68950
  }
68517
68951
  case "export": {
68518
68952
  const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
68519
- await fs30.mkdir(path55.dirname(target), { recursive: true });
68520
- const root = await fs30.realpath(ctx.cwd).catch(() => path55.resolve(ctx.cwd));
68521
- const realParent = await fs30.realpath(path55.dirname(target));
68953
+ await fs30.mkdir(path57.dirname(target), { recursive: true });
68954
+ const root = await fs30.realpath(ctx.cwd).catch(() => path57.resolve(ctx.cwd));
68955
+ const realParent = await fs30.realpath(path57.dirname(target));
68522
68956
  if (!isInside(root, realParent)) {
68523
68957
  throw new Error("Export path resolves outside the active project.");
68524
68958
  }
@@ -68714,7 +69148,7 @@ import { promises as fs34 } from "node:fs";
68714
69148
  init_zod();
68715
69149
  init_taskTool();
68716
69150
  import { promises as fs33 } from "node:fs";
68717
- import path59 from "node:path";
69151
+ import path61 from "node:path";
68718
69152
  import { randomBytes as randomBytes5 } from "node:crypto";
68719
69153
  var CsvFanoutArgsSchema = external_exports.object({
68720
69154
  csv_path: external_exports.string().min(1),
@@ -68808,8 +69242,8 @@ function resolveMaxConcurrency(env = process.env) {
68808
69242
  }
68809
69243
  async function runCsvFanout(args, deps, opts) {
68810
69244
  const start = Date.now();
68811
- const absCsv = path59.isAbsolute(args.csv_path) ? args.csv_path : path59.join(opts.parentCwd, args.csv_path);
68812
- const absOut = path59.isAbsolute(args.output_csv_path) ? args.output_csv_path : path59.join(opts.parentCwd, args.output_csv_path);
69245
+ const absCsv = path61.isAbsolute(args.csv_path) ? args.csv_path : path61.join(opts.parentCwd, args.csv_path);
69246
+ const absOut = path61.isAbsolute(args.output_csv_path) ? args.output_csv_path : path61.join(opts.parentCwd, args.output_csv_path);
68813
69247
  const { headers: headers2, rows } = await readCsv(absCsv);
68814
69248
  if (headers2.length === 0) {
68815
69249
  throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
@@ -68865,7 +69299,7 @@ async function runCsvFanout(args, deps, opts) {
68865
69299
  errored += 1;
68866
69300
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
68867
69301
  }
68868
- await fs33.mkdir(path59.dirname(absOut), { recursive: true });
69302
+ await fs33.mkdir(path61.dirname(absOut), { recursive: true });
68869
69303
  await queueWrite(serializeCsv(outHeaders, outputRecords));
68870
69304
  }
68871
69305
  }
@@ -69060,7 +69494,7 @@ function splitArgs(s) {
69060
69494
  // src/cli/slashHandlers/krakenWorkbench.ts
69061
69495
  init_messageHelpers();
69062
69496
  import { promises as fs35 } from "node:fs";
69063
- import path60 from "node:path";
69497
+ import path62 from "node:path";
69064
69498
 
69065
69499
  // src/cli/kraken/workbenchView.ts
69066
69500
  var EMPTY = {
@@ -69177,14 +69611,14 @@ function formatWorkbenchForTerminal(p3) {
69177
69611
 
69178
69612
  // src/cli/slashHandlers/krakenWorkbench.ts
69179
69613
  async function handleKrakenWorkbench(ctx) {
69180
- const dir = path60.join(ctx.cwd, ".zelari", "radio");
69614
+ const dir = path62.join(ctx.cwd, ".zelari", "radio");
69181
69615
  let latest = null;
69182
69616
  let latestMtime = 0;
69183
69617
  try {
69184
69618
  const files = await fs35.readdir(dir);
69185
69619
  for (const f of files) {
69186
69620
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
69187
- const full = path60.join(dir, f);
69621
+ const full = path62.join(dir, f);
69188
69622
  const stat2 = await fs35.stat(full);
69189
69623
  if (stat2.mtimeMs > latestMtime) {
69190
69624
  latestMtime = stat2.mtimeMs;
@@ -69201,10 +69635,10 @@ async function handleKrakenWorkbench(ctx) {
69201
69635
  const parsed = parseWorkbench(content);
69202
69636
  const rendered = formatWorkbenchForTerminal(parsed);
69203
69637
  if (!rendered.trim()) {
69204
- appendSystem(ctx.setMessages, `[kraken workbench] ${path60.basename(latest)}: (no nodes / no events yet)`);
69638
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path62.basename(latest)}: (no nodes / no events yet)`);
69205
69639
  return;
69206
69640
  }
69207
- appendSystem(ctx.setMessages, `[kraken workbench] ${path60.basename(latest)}:
69641
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path62.basename(latest)}:
69208
69642
  ${rendered}`);
69209
69643
  }
69210
69644
 
@@ -69511,15 +69945,15 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
69511
69945
  // src/cli/slashHandlers/promoteMember.ts
69512
69946
  init_messageHelpers();
69513
69947
  import { promises as fs36 } from "node:fs";
69514
- import path63 from "node:path";
69948
+ import path65 from "node:path";
69515
69949
  import os12 from "node:os";
69516
69950
  async function handlePromoteMember(ctx, memberId) {
69517
69951
  try {
69518
69952
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
69519
69953
  const { skill, markdown } = promoteMember2(memberId);
69520
- const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path63.join(os12.homedir(), ".tmp", "zelari-code", "skills");
69954
+ const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path65.join(os12.homedir(), ".tmp", "zelari-code", "skills");
69521
69955
  await fs36.mkdir(skillDir, { recursive: true });
69522
- const filePath = path63.join(skillDir, `${skill.id}.md`);
69956
+ const filePath = path65.join(skillDir, `${skill.id}.md`);
69523
69957
  await fs36.writeFile(filePath, markdown, "utf8");
69524
69958
  appendSystem(
69525
69959
  ctx.setMessages,
@@ -69536,25 +69970,25 @@ async function handlePromoteMember(ctx, memberId) {
69536
69970
  }
69537
69971
 
69538
69972
  // src/cli/branchManager.ts
69539
- import { promises as fs37, existsSync as existsSync45, readFileSync as readFileSync36, writeFileSync as writeFileSync23, mkdirSync as mkdirSync19, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
69540
- import path64 from "node:path";
69973
+ import { promises as fs37, existsSync as existsSync45, readFileSync as readFileSync37, writeFileSync as writeFileSync23, mkdirSync as mkdirSync19, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
69974
+ import path66 from "node:path";
69541
69975
  import os13 from "node:os";
69542
69976
  var META_FILENAME = "meta.json";
69543
69977
  var SESSIONS_SUBDIR = "sessions";
69544
69978
  function getBranchesBaseDir() {
69545
- return process.env.ANATHEMA_BRANCHES_DIR ?? path64.join(os13.homedir(), ".tmp", "zelari-code", "branches");
69979
+ return process.env.ANATHEMA_BRANCHES_DIR ?? path66.join(os13.homedir(), ".tmp", "zelari-code", "branches");
69546
69980
  }
69547
69981
  function getSessionsBaseDir() {
69548
- return process.env.ANATHEMA_SESSIONS_DIR ?? path64.join(os13.homedir(), ".tmp", "zelari-code", "sessions");
69982
+ return process.env.ANATHEMA_SESSIONS_DIR ?? path66.join(os13.homedir(), ".tmp", "zelari-code", "sessions");
69549
69983
  }
69550
69984
  function branchPathFor(name, baseDir) {
69551
- return path64.join(baseDir, name);
69985
+ return path66.join(baseDir, name);
69552
69986
  }
69553
69987
  function metaPathFor(name, baseDir) {
69554
- return path64.join(baseDir, name, META_FILENAME);
69988
+ return path66.join(baseDir, name, META_FILENAME);
69555
69989
  }
69556
69990
  function sessionsPathFor(name, baseDir) {
69557
- return path64.join(baseDir, name, SESSIONS_SUBDIR);
69991
+ return path66.join(baseDir, name, SESSIONS_SUBDIR);
69558
69992
  }
69559
69993
  function readBranchMeta(name, baseDir) {
69560
69994
  const metaPath = metaPathFor(name, baseDir);
@@ -69562,7 +69996,7 @@ function readBranchMeta(name, baseDir) {
69562
69996
  throw new BranchNotFoundError(`Branch "${name}" not found`);
69563
69997
  }
69564
69998
  try {
69565
- const raw = readFileSync36(metaPath, "utf-8");
69999
+ const raw = readFileSync37(metaPath, "utf-8");
69566
70000
  const parsed = JSON.parse(raw);
69567
70001
  if (!parsed || typeof parsed !== "object" || typeof parsed.name !== "string" || typeof parsed.createdAt !== "number" || typeof parsed.fromSessionId !== "string") {
69568
70002
  throw new BranchCorruptError(`Branch "${name}" meta.json is malformed`);
@@ -69579,7 +70013,7 @@ function readBranchMeta(name, baseDir) {
69579
70013
  }
69580
70014
  function writeBranchMeta(name, baseDir, meta3) {
69581
70015
  const metaPath = metaPathFor(name, baseDir);
69582
- mkdirSync19(path64.dirname(metaPath), { recursive: true });
70016
+ mkdirSync19(path66.dirname(metaPath), { recursive: true });
69583
70017
  writeFileSync23(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
69584
70018
  }
69585
70019
  async function countSessions(name, baseDir) {
@@ -69630,14 +70064,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
69630
70064
  if (branchExists(name, baseDir)) {
69631
70065
  throw new BranchAlreadyExistsError(name);
69632
70066
  }
69633
- const sourcePath = path64.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
70067
+ const sourcePath = path66.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
69634
70068
  if (!existsSync45(sourcePath)) {
69635
70069
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
69636
70070
  }
69637
70071
  const branchPath = branchPathFor(name, baseDir);
69638
70072
  const branchSessionsPath = sessionsPathFor(name, baseDir);
69639
70073
  mkdirSync19(branchSessionsPath, { recursive: true });
69640
- const destPath = path64.join(branchSessionsPath, `${fromSessionId}.jsonl`);
70074
+ const destPath = path66.join(branchSessionsPath, `${fromSessionId}.jsonl`);
69641
70075
  await fs37.copyFile(sourcePath, destPath);
69642
70076
  const meta3 = {
69643
70077
  name,
@@ -69741,14 +70175,14 @@ async function handleBranchCheckout(ctx, branchName) {
69741
70175
  // src/cli/slashHandlers/workspace.ts
69742
70176
  init_messageHelpers();
69743
70177
  import { promises as fs38 } from "node:fs";
69744
- import path65 from "node:path";
70178
+ import path67 from "node:path";
69745
70179
  async function handleWorkspaceShow(ctx, what) {
69746
70180
  try {
69747
- const zelari = path65.join(process.cwd(), ".zelari");
70181
+ const zelari = path67.join(process.cwd(), ".zelari");
69748
70182
  let content;
69749
70183
  switch (what) {
69750
70184
  case "plan": {
69751
- const planPath = path65.join(zelari, "plan.md");
70185
+ const planPath = path67.join(zelari, "plan.md");
69752
70186
  try {
69753
70187
  content = await fs38.readFile(planPath, "utf-8");
69754
70188
  } catch {
@@ -69757,7 +70191,7 @@ async function handleWorkspaceShow(ctx, what) {
69757
70191
  break;
69758
70192
  }
69759
70193
  case "decisions": {
69760
- const decisionsDir = path65.join(zelari, "decisions");
70194
+ const decisionsDir = path67.join(zelari, "decisions");
69761
70195
  try {
69762
70196
  const files = (await fs38.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
69763
70197
  if (files.length === 0) {
@@ -69767,7 +70201,7 @@ async function handleWorkspaceShow(ctx, what) {
69767
70201
  `];
69768
70202
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
69769
70203
  for (const f of files) {
69770
- const raw = await fs38.readFile(path65.join(decisionsDir, f), "utf-8");
70204
+ const raw = await fs38.readFile(path67.join(decisionsDir, f), "utf-8");
69771
70205
  const { meta: meta3, body } = parseFrontmatter2(raw);
69772
70206
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
69773
70207
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -69780,7 +70214,7 @@ async function handleWorkspaceShow(ctx, what) {
69780
70214
  break;
69781
70215
  }
69782
70216
  case "risks": {
69783
- const risksPath = path65.join(zelari, "risks.md");
70217
+ const risksPath = path67.join(zelari, "risks.md");
69784
70218
  try {
69785
70219
  content = await fs38.readFile(risksPath, "utf-8");
69786
70220
  } catch {
@@ -69789,7 +70223,7 @@ async function handleWorkspaceShow(ctx, what) {
69789
70223
  break;
69790
70224
  }
69791
70225
  case "agents": {
69792
- const agentsPath = path65.join(process.cwd(), "AGENTS.MD");
70226
+ const agentsPath = path67.join(process.cwd(), "AGENTS.MD");
69793
70227
  try {
69794
70228
  content = await fs38.readFile(agentsPath, "utf-8");
69795
70229
  } catch {
@@ -69798,7 +70232,7 @@ async function handleWorkspaceShow(ctx, what) {
69798
70232
  break;
69799
70233
  }
69800
70234
  case "docs": {
69801
- const docsDir = path65.join(zelari, "docs");
70235
+ const docsDir = path67.join(zelari, "docs");
69802
70236
  try {
69803
70237
  const files = (await fs38.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
69804
70238
  content = files.length ? `# Docs (${files.length})
@@ -69840,7 +70274,7 @@ async function handleWorkspaceReset(ctx, force) {
69840
70274
  return;
69841
70275
  }
69842
70276
  try {
69843
- const target = path65.join(process.cwd(), ".zelari");
70277
+ const target = path67.join(process.cwd(), ".zelari");
69844
70278
  await fs38.rm(target, { recursive: true, force: true });
69845
70279
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
69846
70280
  } catch (err) {
@@ -69852,7 +70286,7 @@ async function handleWorkspaceReset(ctx, force) {
69852
70286
  init_provider2();
69853
70287
 
69854
70288
  // src/cli/slashHandlers/skills.ts
69855
- import path66 from "node:path";
70289
+ import path68 from "node:path";
69856
70290
  import os14 from "node:os";
69857
70291
 
69858
70292
  // src/cli/skillHistory.ts
@@ -69981,7 +70415,7 @@ function handleSkillPicker(ctx, skills, openPicker, fallbackMessage) {
69981
70415
  });
69982
70416
  }
69983
70417
  async function handleSkillStats(ctx, skillId) {
69984
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path66.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
70418
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path68.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
69985
70419
  try {
69986
70420
  const records = await readSkillHistory(historyFile);
69987
70421
  const stats = getSkillStats(records, skillId);
@@ -69997,7 +70431,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
69997
70431
  appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
69998
70432
  return;
69999
70433
  }
70000
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path66.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
70434
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path68.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
70001
70435
  try {
70002
70436
  const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
70003
70437
  appendSystem(ctx.setMessages, formatted);
@@ -71512,6 +71946,54 @@ init_candidateRegistry();
71512
71946
  init_metrics2();
71513
71947
  init_completionGate();
71514
71948
  init_delegationPolicy();
71949
+
71950
+ // src/cli/orchestration/policy.ts
71951
+ var DEFAULT_MAX_SOLO_CHARS = 300;
71952
+ var KRAKEN_SIGNALS = [
71953
+ { re: /\bimplement(?:s|ed|ing)?\b/i, reason: "implementation signal" },
71954
+ { re: /\brefactor(?:ing|ed)?\b/i, reason: "refactor signal" },
71955
+ { re: /\bmigrat(?:e|es|ed|ion|ing)\b/i, reason: "migration signal" },
71956
+ {
71957
+ re: /\b(?:add|build|create|introduce)\b[^.?!]{0,48}\b(?:feature|endpoint|module|service|command|api|registry|runtime)\b/i,
71958
+ reason: "new-capability signal"
71959
+ },
71960
+ {
71961
+ re: /\b(?:unit|integration|e2e|end-to-end)\s+(?:tests?|testing|specs?)\b|\bwrite\s+(?:the\s+|some\s+)?tests?\b/i,
71962
+ reason: "test-writing signal"
71963
+ },
71964
+ {
71965
+ re: /\b\d+\s*-?\s*(?:files?|modules?|packages?|components?|services?|endpoints?|worktrees?)\b/i,
71966
+ reason: "multi-artifact count"
71967
+ },
71968
+ {
71969
+ re: /\b(?:across|spanning|between|touching)\s+(?:all\s+|the\s+)?(?:\w+\s+){0,2}(?:files|modules|packages|layers|surfaces)\b/i,
71970
+ reason: "cross-cutting scope"
71971
+ }
71972
+ ];
71973
+ var QUESTION_RE = /\?\s*$|^(?:who|what|why|when|where|which|how|is|are|was|were|does|do|did|can|could|should|would|will)\b/i;
71974
+ var EXPLAIN_RE = /\b(?:explain|describe|summarize|summarise|clarify|walk\W*me\W*through)\b/i;
71975
+ var READONLY_RE = /\b(?:find|show|list|grep|search|locate|inspect|read|check|review|where\W+is)\b/i;
71976
+ function chooseOrchestration(task, opts = {}) {
71977
+ const text = String(task ?? "").trim();
71978
+ const failClosed = () => ({
71979
+ surface: "solo",
71980
+ reason: "fail-closed default"
71981
+ });
71982
+ if (!text) return failClosed();
71983
+ for (const { re, reason } of KRAKEN_SIGNALS) {
71984
+ if (re.test(text)) return { surface: "kraken", reason };
71985
+ }
71986
+ if (QUESTION_RE.test(text)) return { surface: "solo", reason: "question-shaped task" };
71987
+ if (EXPLAIN_RE.test(text)) return { surface: "solo", reason: "explanation request" };
71988
+ if (READONLY_RE.test(text)) return { surface: "solo", reason: "read-only request" };
71989
+ const budget = opts.maxSoloChars ?? DEFAULT_MAX_SOLO_CHARS;
71990
+ if (text.length <= budget) {
71991
+ return { surface: "solo", reason: "small task, no heavy signals" };
71992
+ }
71993
+ return failClosed();
71994
+ }
71995
+
71996
+ // src/cli/runHeadless.ts
71515
71997
  init_headless();
71516
71998
  init_claudeProvider();
71517
71999
  init_skills2();
@@ -71550,12 +72032,13 @@ function createStreamScrubber2() {
71550
72032
  init_taskTool();
71551
72033
  init_sessionTodos();
71552
72034
  import { promises as fs41 } from "node:fs";
71553
- import path68 from "node:path";
72035
+ import path70 from "node:path";
71554
72036
  import { randomUUID as randomUUID8 } from "node:crypto";
71555
72037
 
71556
72038
  // src/cli/kraken/verifierLifecycle.ts
71557
72039
  init_verification2();
71558
72040
  init_krakenSelectTool();
72041
+ init_krakenModel();
71559
72042
 
71560
72043
  // src/cli/kraken/verifierResolution.ts
71561
72044
  init_providerConfig();
@@ -71599,18 +72082,61 @@ function makeVerifierCallModel(loadStream, identity, timeoutMs2 = 12e4) {
71599
72082
  return { text, provider: identity.provider, model: identity.model };
71600
72083
  };
71601
72084
  }
71602
- function resolveIdentity(selection, session) {
72085
+ function resolveIdentity(selection, session, familyCandidates, env = process.env) {
71603
72086
  if (selection.mode === "fixed") {
71604
72087
  return { provider: selection.provider, model: selection.model };
71605
72088
  }
71606
- return session && session.provider && session.model ? session : null;
72089
+ if (!session || !session.provider || !session.model) return null;
72090
+ if (familyCandidates && familyCandidates.length > 0) {
72091
+ const cross = resolveCrossModelVerifier(session, familyCandidates, env);
72092
+ if (cross) return { provider: cross.provider, model: cross.model };
72093
+ }
72094
+ return session;
72095
+ }
72096
+ function isTestEvidenceCriterion(criterionId2) {
72097
+ const id3 = criterionId2.toLowerCase();
72098
+ return ["test", "typecheck", "build", "lint"].some((k) => id3.includes(k));
72099
+ }
72100
+ function extractTestOutputExcerpt(results, maxChars = 4e3) {
72101
+ const lines = [];
72102
+ for (const r of results) {
72103
+ if (!isTestEvidenceCriterion(r.criterionId)) continue;
72104
+ lines.push([r.criterionId, r.status, r.detail].filter(Boolean).join(" \u2014 "));
72105
+ }
72106
+ if (lines.length === 0) return "";
72107
+ return lines.join("\n").slice(0, maxChars);
72108
+ }
72109
+ async function buildBlindReviewInput(evaluation, deps) {
72110
+ const results = evaluation.results ?? [];
72111
+ const passed = results.filter((r) => r.status === "pass").length;
72112
+ const verdict = evaluation.evaluation?.verdict ?? "UNKNOWN";
72113
+ const summary = `Kraken BUILD turn \u2014 deterministic evidence: ${passed}/${results.length} criteria pass, completion verdict ${verdict}.`;
72114
+ const task = deps.task?.trim();
72115
+ const testOutputExcerpt = extractTestOutputExcerpt(results);
72116
+ let diffSummary;
72117
+ try {
72118
+ const res = await (deps.getDiff ?? getWorkingDiff)({
72119
+ cwd: deps.cwd ?? process.cwd(),
72120
+ maxChars: 8e3,
72121
+ staged: true
72122
+ });
72123
+ if (res && !res.empty && res.diff) diffSummary = res.diff;
72124
+ } catch {
72125
+ }
72126
+ return {
72127
+ ...task ? { task } : {},
72128
+ summary,
72129
+ ...diffSummary !== void 0 ? { diffSummary } : {},
72130
+ ...testOutputExcerpt ? { testOutputExcerpt } : {},
72131
+ results
72132
+ };
71607
72133
  }
71608
72134
  async function runAdvisoryVerifierReview(evaluation, deps = {}) {
71609
72135
  if (!evaluation.evaluation || !evaluation.results) return null;
71610
72136
  const env = deps.env ?? process.env;
71611
72137
  const selection = deps.selection ?? loadVerifierModelSelection();
71612
72138
  if (!verifierReviewEnabled(selection, env)) return null;
71613
- const identity = resolveIdentity(selection, deps.session);
72139
+ const identity = resolveIdentity(selection, deps.session, deps.familyCandidates, env);
71614
72140
  let callModel = deps.callModel;
71615
72141
  if (!callModel) {
71616
72142
  if (!identity || !deps.loadStream) return null;
@@ -71627,11 +72153,9 @@ async function runAdvisoryVerifierReview(evaluation, deps = {}) {
71627
72153
  emit: deps.emit,
71628
72154
  env
71629
72155
  });
71630
- const passed = evaluation.results.filter((r) => r.status === "pass").length;
71631
- const summary = `Kraken BUILD turn \u2014 deterministic evidence: ${passed}/${evaluation.results.length} criteria pass, completion verdict ${evaluation.evaluation.verdict}.`;
72156
+ const blind = await buildBlindReviewInput(evaluation, deps);
71632
72157
  const review = await service.reviewCompletion({
71633
- summary,
71634
- results: evaluation.results,
72158
+ ...blind,
71635
72159
  session: deps.session
71636
72160
  });
71637
72161
  evaluation.review = review;
@@ -71945,6 +72469,13 @@ ${err.stack}` : "";
71945
72469
  model
71946
72470
  });
71947
72471
  }
72472
+ if (opts.orchestrationAuto) {
72473
+ const verdict = chooseOrchestration(opts.task ?? "");
72474
+ const line = `[orchestration] --mode auto -> surface=${verdict.surface} (${verdict.reason})`;
72475
+ if (opts.output === "json") emitEvent({ type: "log", message: line });
72476
+ else process.stderr.write(`[zelari-code --headless] ${line}
72477
+ `);
72478
+ }
71948
72479
  const mode = opts.mode ?? (opts.useCouncil ? "council" : "kraken");
71949
72480
  const profileId = resolveHeadlessProfileId(mode, opts.profile);
71950
72481
  if (opts.output === "json") {
@@ -72018,7 +72549,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
72018
72549
  try {
72019
72550
  let preflightGraph;
72020
72551
  if (opts.runPlan && opts.runPlan.trim() !== "") {
72021
- const planPath = path68.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
72552
+ const planPath = path70.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
72022
72553
  log(`loading pre-flight plan: ${planPath}`);
72023
72554
  let raw;
72024
72555
  try {
@@ -72058,8 +72589,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
72058
72589
  log(formatKrakenGraphAscii2(graph));
72059
72590
  if (opts.planOnly) {
72060
72591
  const planId = randomUUID8();
72061
- const planDir = path68.join(cwd, ".zelari", "radio");
72062
- const planPath = path68.join(planDir, `plan-${planId}.json`);
72592
+ const planDir = path70.join(cwd, ".zelari", "radio");
72593
+ const planPath = path70.join(planDir, `plan-${planId}.json`);
72063
72594
  await fs41.mkdir(planDir, { recursive: true });
72064
72595
  await fs41.writeFile(
72065
72596
  planPath,
@@ -72087,6 +72618,18 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
72087
72618
  root: cwd,
72088
72619
  audit,
72089
72620
  sessionId: sessionId2,
72621
+ // P0.4 capability inheritance: tentacles intersect the headless
72622
+ // parent policy. Headless runs are auto-allow (the same literal
72623
+ // the main headless registry below uses), so this is a no-op
72624
+ // today — wired for correctness if that default ever tightens.
72625
+ parentPolicy: {
72626
+ read: "allow",
72627
+ write: "allow",
72628
+ execute: "allow",
72629
+ network: "allow",
72630
+ ui: "allow",
72631
+ auto: true
72632
+ },
72090
72633
  // Anchor every tentacle to the SAME provider/model this run
72091
72634
  // resolved (Desktop's selector, or --provider/--model), instead
72092
72635
  // of the persisted provider.json default the factory falls back
@@ -72179,6 +72722,12 @@ async function registerHeadlessMcp(toolRegistry, opts) {
72179
72722
  }
72180
72723
  }
72181
72724
  }
72725
+ function writeProofSafe(gate, meta3, baseDir = process.cwd()) {
72726
+ return writeCompletionProof(gate, { baseDir, meta: meta3 }).then(
72727
+ () => void 0,
72728
+ () => void 0
72729
+ );
72730
+ }
72182
72731
  async function runHeadlessSingle(opts, provider, model, providerStream) {
72183
72732
  const sessionId2 = crypto.randomUUID();
72184
72733
  const memoryFactory = await Promise.resolve().then(() => (init_serviceFactory(), serviceFactory_exports));
@@ -72517,6 +73066,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
72517
73066
  let strictExit = 0;
72518
73067
  const verifierReviewDeps = {
72519
73068
  session: { provider, model },
73069
+ task: effectiveTask,
72520
73070
  loadStream: async (providerId, modelId) => {
72521
73071
  if (providerId === provider) return providerStream;
72522
73072
  try {
@@ -72544,6 +73094,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
72544
73094
  if (opts.output === "json") {
72545
73095
  emitEvent({ type: "verification_run", ...verificationPayload });
72546
73096
  }
73097
+ await writeProofSafe(strictGate, { surface: "kraken", sessionId: spine.sessionId });
72547
73098
  if (strictGate.blocked) {
72548
73099
  const repairPrompt = buildKrakenRepairPrompt(gate);
72549
73100
  if (opts.output === "json") {
@@ -72577,6 +73128,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
72577
73128
  if (opts.output === "json") {
72578
73129
  emitEvent({ type: "verification_run", ...afterPayload });
72579
73130
  }
73131
+ await writeProofSafe(after, { surface: "kraken", sessionId: spine.sessionId });
72580
73132
  if (!after.blocked) markRepairSucceeded();
72581
73133
  else {
72582
73134
  strictExit = strictGateExitCode(after);
@@ -72610,7 +73162,7 @@ async function runHeadlessSingle(opts, provider, model, providerStream) {
72610
73162
  if (json3) {
72611
73163
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
72612
73164
  else {
72613
- await fs41.mkdir(path68.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
73165
+ await fs41.mkdir(path70.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
72614
73166
  await fs41.writeFile(opts.exportSessionPath, json3, "utf8");
72615
73167
  }
72616
73168
  }
@@ -72839,7 +73391,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
72839
73391
  if (json3) {
72840
73392
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
72841
73393
  else {
72842
- await fs41.mkdir(path68.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
73394
+ await fs41.mkdir(path70.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
72843
73395
  await fs41.writeFile(opts.exportSessionPath, json3, "utf8");
72844
73396
  }
72845
73397
  }
@@ -73219,6 +73771,7 @@ ${ragContext}` : slicePrompt;
73219
73771
  if (opts.output === "json") {
73220
73772
  emitEvent({ type: "verification_run", ...missionVerificationPayload });
73221
73773
  }
73774
+ await writeProofSafe(missionGate, { surface: "mission", sessionId: spine.sessionId }, projectRoot);
73222
73775
  if (missionGate.blocked) {
73223
73776
  exitCode = strictGateExitCode(missionGate);
73224
73777
  spine.missionPhase("verification", "mission-strict-blocked");
@@ -73253,7 +73806,7 @@ ${ragContext}` : slicePrompt;
73253
73806
  if (json3) {
73254
73807
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
73255
73808
  else {
73256
- await fs41.mkdir(path68.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
73809
+ await fs41.mkdir(path70.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
73257
73810
  await fs41.writeFile(opts.exportSessionPath, json3, "utf8");
73258
73811
  }
73259
73812
  }
@@ -73455,8 +74008,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
73455
74008
  let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
73456
74009
  if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
73457
74010
  try {
73458
- const path72 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
73459
- name = path72 && /^[a-z0-9]/.test(path72) ? path72 : "imported-skill";
74011
+ const path74 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
74012
+ name = path74 && /^[a-z0-9]/.test(path74) ? path74 : "imported-skill";
73460
74013
  } catch {
73461
74014
  name = "imported-skill";
73462
74015
  }