zelari-code 2.37.0 → 2.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3482,10 +3482,10 @@ function mergeDefs(...defs) {
3482
3482
  function cloneDef(schema) {
3483
3483
  return mergeDefs(schema._zod.def);
3484
3484
  }
3485
- function getElementAtPath(obj, path100) {
3486
- if (!path100)
3485
+ function getElementAtPath(obj, path101) {
3486
+ if (!path101)
3487
3487
  return obj;
3488
- return path100.reduce((acc, key) => acc?.[key], obj);
3488
+ return path101.reduce((acc, key) => acc?.[key], obj);
3489
3489
  }
3490
3490
  function promiseAllObject(promisesObj) {
3491
3491
  const keys = Object.keys(promisesObj);
@@ -3813,11 +3813,11 @@ function explicitlyAborted(x, startIndex = 0) {
3813
3813
  }
3814
3814
  return false;
3815
3815
  }
3816
- function prefixIssues(path100, issues) {
3816
+ function prefixIssues(path101, issues) {
3817
3817
  return issues.map((iss) => {
3818
3818
  var _a3;
3819
3819
  (_a3 = iss).path ?? (_a3.path = []);
3820
- iss.path.unshift(path100);
3820
+ iss.path.unshift(path101);
3821
3821
  return iss;
3822
3822
  });
3823
3823
  }
@@ -4035,16 +4035,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
4035
4035
  }
4036
4036
  function formatError(error51, mapper = (issue2) => issue2.message) {
4037
4037
  const fieldErrors = { _errors: [] };
4038
- const processError = (error52, path100 = []) => {
4038
+ const processError = (error52, path101 = []) => {
4039
4039
  for (const issue2 of error52.issues) {
4040
4040
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4041
- issue2.errors.map((issues) => processError({ issues }, [...path100, ...issue2.path]));
4041
+ issue2.errors.map((issues) => processError({ issues }, [...path101, ...issue2.path]));
4042
4042
  } else if (issue2.code === "invalid_key") {
4043
- processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4043
+ processError({ issues: issue2.issues }, [...path101, ...issue2.path]);
4044
4044
  } else if (issue2.code === "invalid_element") {
4045
- processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4045
+ processError({ issues: issue2.issues }, [...path101, ...issue2.path]);
4046
4046
  } else {
4047
- const fullpath = [...path100, ...issue2.path];
4047
+ const fullpath = [...path101, ...issue2.path];
4048
4048
  if (fullpath.length === 0) {
4049
4049
  fieldErrors._errors.push(mapper(issue2));
4050
4050
  } else {
@@ -4071,17 +4071,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
4071
4071
  }
4072
4072
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
4073
4073
  const result = { errors: [] };
4074
- const processError = (error52, path100 = []) => {
4074
+ const processError = (error52, path101 = []) => {
4075
4075
  var _a3, _b;
4076
4076
  for (const issue2 of error52.issues) {
4077
4077
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4078
- issue2.errors.map((issues) => processError({ issues }, [...path100, ...issue2.path]));
4078
+ issue2.errors.map((issues) => processError({ issues }, [...path101, ...issue2.path]));
4079
4079
  } else if (issue2.code === "invalid_key") {
4080
- processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4080
+ processError({ issues: issue2.issues }, [...path101, ...issue2.path]);
4081
4081
  } else if (issue2.code === "invalid_element") {
4082
- processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4082
+ processError({ issues: issue2.issues }, [...path101, ...issue2.path]);
4083
4083
  } else {
4084
- const fullpath = [...path100, ...issue2.path];
4084
+ const fullpath = [...path101, ...issue2.path];
4085
4085
  if (fullpath.length === 0) {
4086
4086
  result.errors.push(mapper(issue2));
4087
4087
  continue;
@@ -4113,8 +4113,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
4113
4113
  }
4114
4114
  function toDotPath(_path) {
4115
4115
  const segs = [];
4116
- const path100 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4117
- for (const seg of path100) {
4116
+ const path101 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4117
+ for (const seg of path101) {
4118
4118
  if (typeof seg === "number")
4119
4119
  segs.push(`[${seg}]`);
4120
4120
  else if (typeof seg === "symbol")
@@ -17617,13 +17617,13 @@ function resolveRef(ref, ctx) {
17617
17617
  if (!ref.startsWith("#")) {
17618
17618
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
17619
17619
  }
17620
- const path100 = ref.slice(1).split("/").filter(Boolean);
17621
- if (path100.length === 0) {
17620
+ const path101 = ref.slice(1).split("/").filter(Boolean);
17621
+ if (path101.length === 0) {
17622
17622
  return ctx.rootSchema;
17623
17623
  }
17624
17624
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
17625
- if (path100[0] === defsKey) {
17626
- const key = path100[1];
17625
+ if (path101[0] === defsKey) {
17626
+ const key = path101[1];
17627
17627
  if (!key || !ctx.defs[key]) {
17628
17628
  throw new Error(`Reference not found: ${ref}`);
17629
17629
  }
@@ -18457,17 +18457,17 @@ var init_newlines = __esm({
18457
18457
  });
18458
18458
 
18459
18459
  // packages/core/dist/core/tools/builtin/fileEvents.js
18460
- function fileReadEvent(path100, snapshotId) {
18461
- return { kind: "file.read", actor: { type: "tool" }, data: { path: path100, snapshotId } };
18460
+ function fileReadEvent(path101, snapshotId) {
18461
+ return { kind: "file.read", actor: { type: "tool" }, data: { path: path101, snapshotId } };
18462
18462
  }
18463
- function fileAppliedEvent(path100, snapshotId, bytes) {
18464
- return { kind: "file.applied", actor: { type: "tool" }, data: { path: path100, snapshotId, bytes } };
18463
+ function fileAppliedEvent(path101, snapshotId, bytes) {
18464
+ return { kind: "file.applied", actor: { type: "tool" }, data: { path: path101, snapshotId, bytes } };
18465
18465
  }
18466
- function fileRejectedEvent(path100, reason, hint) {
18466
+ function fileRejectedEvent(path101, reason, hint) {
18467
18467
  return {
18468
18468
  kind: "file.rejected",
18469
18469
  actor: { type: "tool" },
18470
- data: hint === void 0 ? { path: path100, reason } : { path: path100, reason, hint }
18470
+ data: hint === void 0 ? { path: path101, reason } : { path: path101, reason, hint }
18471
18471
  };
18472
18472
  }
18473
18473
  function reReadHint(reject) {
@@ -20336,11 +20336,11 @@ var init_tools = __esm({
20336
20336
  if (!ctx.addDocument)
20337
20337
  return "Knowledge vault tool not available.";
20338
20338
  const title = args["title"] || "New Document";
20339
- const path100 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20339
+ const path101 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20340
20340
  const content = args["content"] || "";
20341
20341
  const tags = args["tags"] || [];
20342
20342
  ctx.addDocument({
20343
- path: path100,
20343
+ path: path101,
20344
20344
  title,
20345
20345
  content,
20346
20346
  format: "markdown",
@@ -20349,7 +20349,7 @@ var init_tools = __esm({
20349
20349
  workspaceId: ctx.workspaceId
20350
20350
  });
20351
20351
  ctx.addActivity("vault", "created document", title);
20352
- return `Document "${title}" created at "${path100}".`;
20352
+ return `Document "${title}" created at "${path101}".`;
20353
20353
  }
20354
20354
  }
20355
20355
  ];
@@ -22036,7 +22036,20 @@ function evaluateKrakenCompletionGate(mode) {
22036
22036
  };
22037
22037
  }
22038
22038
  }
22039
- function buildKrakenRepairPrompt(gate) {
22039
+ function excerptEntries(excerpts) {
22040
+ if (!excerpts) return [];
22041
+ return excerpts instanceof Map ? [...excerpts.entries()] : Object.entries(excerpts);
22042
+ }
22043
+ function excerptBlock(name, raw) {
22044
+ const trimmed = raw.trim();
22045
+ const truncated = trimmed.length > REPAIR_FAIL_EXCERPT_CAP;
22046
+ const tail2 = truncated ? trimmed.slice(trimmed.length - REPAIR_FAIL_EXCERPT_CAP) : trimmed;
22047
+ const lines = [`Failure excerpt (tail, capped ${REPAIR_FAIL_EXCERPT_CAP} chars) \u2014 ${name}:`];
22048
+ if (truncated) lines.push(`\u2026[truncated ${trimmed.length - REPAIR_FAIL_EXCERPT_CAP} chars]`);
22049
+ lines.push(tail2, "");
22050
+ return lines;
22051
+ }
22052
+ function buildKrakenRepairPrompt(gate, excerpts) {
22040
22053
  const lines = [
22041
22054
  `The BUILD turn is ending, but the required checks from kraken_select are not all satisfied (passed ${gate.passed}/${gate.total}).`,
22042
22055
  ""
@@ -22053,6 +22066,36 @@ function buildKrakenRepairPrompt(gate) {
22053
22066
  for (const check2 of gate.unknownChecks) lines.push(`- ${check2}`);
22054
22067
  lines.push("");
22055
22068
  }
22069
+ const entries = excerptEntries(excerpts);
22070
+ if (entries.length > 0) {
22071
+ const byName = new Map(entries);
22072
+ const used = /* @__PURE__ */ new Set();
22073
+ const blocks = [];
22074
+ let emitted = 0;
22075
+ for (const check2 of [...gate.failedChecks, ...gate.unknownChecks]) {
22076
+ if (emitted >= MAX_REPAIR_EXCERPTS) break;
22077
+ const raw = byName.get(check2);
22078
+ if (raw === void 0 || used.has(check2)) continue;
22079
+ used.add(check2);
22080
+ blocks.push(excerptBlock(check2, raw));
22081
+ emitted += 1;
22082
+ }
22083
+ let leadInPushed = false;
22084
+ for (const [name, raw] of entries) {
22085
+ if (emitted >= MAX_REPAIR_EXCERPTS) break;
22086
+ if (used.has(name)) continue;
22087
+ if (!leadInPushed) {
22088
+ blocks.push([
22089
+ "DETERMINISTIC check failures with captured output (criteria pack / task contract):",
22090
+ ""
22091
+ ]);
22092
+ leadInPushed = true;
22093
+ }
22094
+ blocks.push(excerptBlock(name, raw));
22095
+ emitted += 1;
22096
+ }
22097
+ for (const block of blocks) lines.push(...block);
22098
+ }
22056
22099
  lines.push(
22057
22100
  "Recover this turn:",
22058
22101
  "1. The approach selection is settled \u2014 do NOT call kraken_select again.",
@@ -22063,7 +22106,7 @@ function buildKrakenRepairPrompt(gate) {
22063
22106
  );
22064
22107
  return lines.join("\n");
22065
22108
  }
22066
- var OPEN_GATE;
22109
+ var OPEN_GATE, REPAIR_FAIL_EXCERPT_CAP, MAX_REPAIR_EXCERPTS;
22067
22110
  var init_completionGate = __esm({
22068
22111
  "src/cli/kraken/completionGate.ts"() {
22069
22112
  "use strict";
@@ -22076,6 +22119,8 @@ var init_completionGate = __esm({
22076
22119
  failedChecks: [],
22077
22120
  unknownChecks: []
22078
22121
  };
22122
+ REPAIR_FAIL_EXCERPT_CAP = 2e3;
22123
+ MAX_REPAIR_EXCERPTS = 5;
22079
22124
  }
22080
22125
  });
22081
22126
 
@@ -25174,16 +25219,16 @@ function runRetentionFromEnv() {
25174
25219
  maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
25175
25220
  };
25176
25221
  }
25177
- async function dirSize(path100) {
25222
+ async function dirSize(path101) {
25178
25223
  let total = 0;
25179
25224
  let entries;
25180
25225
  try {
25181
- entries = await readdir(path100, { withFileTypes: true });
25226
+ entries = await readdir(path101, { withFileTypes: true });
25182
25227
  } catch {
25183
25228
  return 0;
25184
25229
  }
25185
25230
  for (const entry of entries) {
25186
- const child = join3(path100, entry.name);
25231
+ const child = join3(path101, entry.name);
25187
25232
  if (entry.isDirectory())
25188
25233
  total += await dirSize(child);
25189
25234
  else {
@@ -25210,19 +25255,19 @@ async function enforceRunRetention(runsDir, options = {}) {
25210
25255
  for (const entry of entries) {
25211
25256
  if (!entry.isDirectory())
25212
25257
  continue;
25213
- const path100 = join3(runsDir, entry.name);
25258
+ const path101 = join3(runsDir, entry.name);
25214
25259
  let startedAt = 0;
25215
25260
  let endedAt;
25216
25261
  let completed = false;
25217
25262
  try {
25218
- const manifest = JSON.parse(await readFile(join3(path100, "manifest.json"), "utf8"));
25263
+ const manifest = JSON.parse(await readFile(join3(path101, "manifest.json"), "utf8"));
25219
25264
  startedAt = manifest.startedAt ?? 0;
25220
25265
  endedAt = manifest.endedAt;
25221
25266
  completed = Boolean(endedAt) && manifest.status !== "running";
25222
25267
  } catch {
25223
25268
  completed = false;
25224
25269
  }
25225
- infos.push({ name: entry.name, path: path100, startedAt, endedAt, completed, bytes: await dirSize(path100) });
25270
+ infos.push({ name: entry.name, path: path101, startedAt, endedAt, completed, bytes: await dirSize(path101) });
25226
25271
  }
25227
25272
  const remove = async (info) => {
25228
25273
  await rm(info.path, { recursive: true, force: true });
@@ -25709,12 +25754,12 @@ var init_engine = __esm({
25709
25754
  * content digest) and the returned ref carries the event seq when the
25710
25755
  * emitter resolved one.
25711
25756
  */
25712
- async fsEvidence(observation, path100, sha256, content, extra = {}) {
25757
+ async fsEvidence(observation, path101, sha256, content, extra = {}) {
25713
25758
  const digest = sha256 && content !== void 0 ? sha256(content) : void 0;
25714
- const seq = await this.emitEvidence({ observation, path: path100, ...extra, ...digest ? { digest } : {} });
25759
+ const seq = await this.emitEvidence({ observation, path: path101, ...extra, ...digest ? { digest } : {} });
25715
25760
  return {
25716
25761
  tier: "fs-observation",
25717
- ref: path100,
25762
+ ref: path101,
25718
25763
  capturedAt: Date.now(),
25719
25764
  ...digest ? { digest } : {},
25720
25765
  ...seq !== void 0 ? { seq } : {}
@@ -27184,11 +27229,14 @@ var init_contractCompiler = __esm({
27184
27229
  var verificationBridge_exports = {};
27185
27230
  __export(verificationBridge_exports, {
27186
27231
  STRICT_DONE_EXIT_CODE: () => STRICT_DONE_EXIT_CODE,
27232
+ allowUnverified: () => allowUnverified,
27187
27233
  anchorSelectionEvidence: () => anchorSelectionEvidence,
27188
27234
  evaluateStrictBuildGate: () => evaluateStrictBuildGate,
27189
27235
  evaluateStrictBuildGateFromSession: () => evaluateStrictBuildGateFromSession,
27190
27236
  krakenResultsToContract: () => krakenResultsToContract,
27191
27237
  matchNoteToToolTrace: () => matchNoteToToolTrace,
27238
+ missionClaimExitCode: () => missionClaimExitCode,
27239
+ repairExcerptsFromEvaluation: () => repairExcerptsFromEvaluation,
27192
27240
  strictDoneEnabled: () => strictDoneEnabled,
27193
27241
  strictEnvOverlay: () => strictEnvOverlay,
27194
27242
  strictGateEventPayload: () => strictGateEventPayload,
@@ -27224,20 +27272,20 @@ function criterionId(check2, index) {
27224
27272
  function normalize3(text) {
27225
27273
  return text.toLowerCase().replace(/\s+/g, " ").trim();
27226
27274
  }
27227
- function matchResult(check2, byNormalized) {
27228
- const norm = normalize3(check2);
27229
- const direct = byNormalized.get(norm);
27230
- if (direct) return direct;
27231
- for (const key of byNormalized.keys()) {
27232
- if (key.length >= 8 && (key.includes(norm) || norm.includes(key))) {
27233
- return byNormalized.get(key);
27234
- }
27275
+ function matchResult(check2, byNormalized, byId, id3) {
27276
+ if (byId && id3) {
27277
+ const byCriterion = byId.get(id3);
27278
+ if (byCriterion) return byCriterion;
27235
27279
  }
27236
- return void 0;
27280
+ return byNormalized.get(normalize3(check2));
27237
27281
  }
27238
27282
  function krakenResultsToContract(requiredChecks, results, now = Date.now()) {
27239
27283
  const byNormalized = /* @__PURE__ */ new Map();
27240
- for (const r of results ?? []) byNormalized.set(normalize3(r.check), r);
27284
+ const byId = /* @__PURE__ */ new Map();
27285
+ for (const r of results ?? []) {
27286
+ byNormalized.set(normalize3(r.check), r);
27287
+ if (r.criterionId) byId.set(r.criterionId, r);
27288
+ }
27241
27289
  const criteria = [];
27242
27290
  const verifications = [];
27243
27291
  requiredChecks.forEach((check2, i) => {
@@ -27247,12 +27295,12 @@ function krakenResultsToContract(requiredChecks, results, now = Date.now()) {
27247
27295
  text: check2,
27248
27296
  source: "kraken-selection",
27249
27297
  required: true,
27250
- check: { kind: "none", reason: "verified by verify tentacle report" }
27298
+ check: { kind: "none", reason: "verify tentacle proposal \u2014 runtime evidence required" }
27251
27299
  });
27252
- const reported = matchResult(check2, byNormalized);
27300
+ const reported = matchResult(check2, byNormalized, byId, id3);
27253
27301
  const evidence = reported?.note && reported.note.trim().length > 0 ? [
27254
27302
  {
27255
- tier: "tool-output",
27303
+ tier: "verifier-llm",
27256
27304
  ref: reported.note.trim().slice(0, 500),
27257
27305
  capturedAt: now
27258
27306
  }
@@ -27299,12 +27347,12 @@ async function anchorSelectionEvidence(results, emit, toolTrace) {
27299
27347
  for (const r of results) {
27300
27348
  for (const ev of r.evidence) {
27301
27349
  if (ev.seq !== void 0) continue;
27302
- if (ev.tier === "verifier-llm" || ev.tier === "human") continue;
27350
+ if (ev.tier === "human") continue;
27303
27351
  try {
27304
27352
  const match = toolTrace && toolTrace.length > 0 ? matchNoteToToolTrace(ev.ref, toolTrace) : null;
27305
27353
  if (match) {
27306
27354
  const digest = sha256Hex2(match.output);
27307
- const appended2 = await emit({
27355
+ const appended = await emit({
27308
27356
  kind: "verification.evidence",
27309
27357
  actor: { type: "system", role: "verification" },
27310
27358
  data: {
@@ -27320,16 +27368,17 @@ async function anchorSelectionEvidence(results, emit, toolTrace) {
27320
27368
  ...match.command ? { command: match.command } : {}
27321
27369
  }
27322
27370
  });
27323
- const toolSeq = appended2 && typeof appended2 === "object" && "seq" in appended2 ? Number(appended2.seq) : NaN;
27371
+ const toolSeq = appended && typeof appended === "object" && "seq" in appended ? Number(appended.seq) : NaN;
27324
27372
  if (Number.isFinite(toolSeq) && toolSeq > 0) {
27325
27373
  ev.seq = toolSeq;
27326
27374
  ev.digest = digest;
27375
+ ev.tier = "tool-output";
27327
27376
  ev.ref = `${match.tool}${match.command ? ` ${match.command}` : ""} \u2192 ${match.ok ? "ok" : "error"} @seq`;
27328
27377
  counts.toolResultAnchored += 1;
27329
27378
  }
27330
27379
  continue;
27331
27380
  }
27332
- const appended = await emit({
27381
+ await emit({
27333
27382
  kind: "verification.evidence",
27334
27383
  actor: { type: "system", role: "verification" },
27335
27384
  data: {
@@ -27337,14 +27386,11 @@ async function anchorSelectionEvidence(results, emit, toolTrace) {
27337
27386
  provenance: "note-fallback",
27338
27387
  criterionId: r.criterionId,
27339
27388
  ref: ev.ref,
27340
- tier: ev.tier
27389
+ tier: ev.tier,
27390
+ anchored: false
27341
27391
  }
27342
27392
  });
27343
- const seq = appended && typeof appended === "object" && "seq" in appended ? Number(appended.seq) : NaN;
27344
- if (Number.isFinite(seq) && seq > 0) {
27345
- ev.seq = seq;
27346
- counts.noteFallback += 1;
27347
- }
27393
+ counts.noteFallback += 1;
27348
27394
  } catch {
27349
27395
  }
27350
27396
  }
@@ -27358,7 +27404,8 @@ async function evaluateStrictBuildGate(mode, options = {}) {
27358
27404
  const selectionAvailable = gate.selectionUsed && gate.total > 0;
27359
27405
  const scopeContract = options.taskContract ?? activeContractScope()?.contract;
27360
27406
  const contractPlan = scopeContract ? compileVerificationCriteria(scopeContract) : [];
27361
- if (!selectionAvailable && !nativeOn && contractPlan.length === 0 || !strictOn && !nativeOn) {
27407
+ const nothingBindable = !selectionAvailable && !nativeOn && contractPlan.length === 0;
27408
+ if (!strictOn && !nativeOn) {
27362
27409
  return {
27363
27410
  gate,
27364
27411
  strict: false,
@@ -27368,6 +27415,17 @@ async function evaluateStrictBuildGate(mode, options = {}) {
27368
27415
  summary: gate.blocked ? `blocked: ${gate.failedChecks.length} failed, ${gate.unknownChecks.length} unknown` : "open"
27369
27416
  };
27370
27417
  }
27418
+ if (nothingBindable) {
27419
+ return {
27420
+ gate,
27421
+ strict: true,
27422
+ unverified: true,
27423
+ evaluation: null,
27424
+ native: null,
27425
+ blocked: true,
27426
+ summary: "unverified (strict on: no criteria \u2014 pack off/unbound, no selection contract, no task contract)"
27427
+ };
27428
+ }
27371
27429
  const checks = selectionAvailable ? krakenRequiredChecks() : [];
27372
27430
  const contract = selectionAvailable ? krakenResultsToContract(checks, getKrakenCheckResults()) : { criteria: [], results: [] };
27373
27431
  const anchoring = await anchorSelectionEvidence(
@@ -27389,6 +27447,19 @@ async function evaluateStrictBuildGate(mode, options = {}) {
27389
27447
  const allCriteria = [...contract.criteria, ...native?.criteria ?? [], ...compiled?.criteria ?? []];
27390
27448
  const allResults = [...contract.results, ...native?.results ?? [], ...compiled?.results ?? []];
27391
27449
  if (allCriteria.length === 0) {
27450
+ if (strictOn) {
27451
+ return {
27452
+ gate,
27453
+ strict: true,
27454
+ unverified: true,
27455
+ evaluation: null,
27456
+ native,
27457
+ compiled,
27458
+ results: allResults,
27459
+ blocked: true,
27460
+ summary: "unverified (strict on: native pack bound no command, no selection contract)"
27461
+ };
27462
+ }
27392
27463
  return {
27393
27464
  gate,
27394
27465
  strict: false,
@@ -27414,14 +27485,51 @@ async function evaluateStrictBuildGate(mode, options = {}) {
27414
27485
  summary: blocked ? `blocked (strict ${evaluation?.verdict ?? "n/a"}): ${legacyPart}evidence ${evaluation?.evidenceComplete ? "complete" : "incomplete"}` : `open (strict PASS): ${evaluation?.satisfied.length ?? 0}/${allCriteria.length} criteria pass with evidence`
27415
27486
  };
27416
27487
  }
27417
- function strictGateExitCode(evaluation) {
27418
- return evaluation.strict && evaluation.blocked ? STRICT_DONE_EXIT_CODE : 0;
27488
+ function repairExcerptsFromEvaluation(evaluation) {
27489
+ const excerpts = /* @__PURE__ */ new Map();
27490
+ const nameById = /* @__PURE__ */ new Map();
27491
+ for (const c of [...evaluation.native?.criteria ?? [], ...evaluation.compiled?.criteria ?? []]) {
27492
+ nameById.set(c.id, c.text);
27493
+ }
27494
+ try {
27495
+ krakenRequiredChecks().forEach((text, i) => {
27496
+ if (!nameById.has(criterionId(text, i))) nameById.set(criterionId(text, i), text);
27497
+ });
27498
+ } catch {
27499
+ }
27500
+ for (const r of evaluation.results ?? []) {
27501
+ if (r.status === "pass") continue;
27502
+ const detail = r.detail?.trim();
27503
+ if (!detail) continue;
27504
+ excerpts.set(nameById.get(r.criterionId) ?? r.criterionId, detail);
27505
+ }
27506
+ return excerpts;
27507
+ }
27508
+ function allowUnverified(env = process.env) {
27509
+ const v = env.ZELARI_ALLOW_UNVERIFIED?.toLowerCase();
27510
+ return v === "1" || v === "true" || v === "yes" || v === "on";
27511
+ }
27512
+ function strictGateExitCode(evaluation, env = process.env) {
27513
+ if (evaluation.strict && evaluation.blocked) {
27514
+ if (evaluation.unverified && allowUnverified(env)) return 0;
27515
+ return STRICT_DONE_EXIT_CODE;
27516
+ }
27517
+ return 0;
27518
+ }
27519
+ function missionClaimExitCode(evidenceCount, env = process.env) {
27520
+ if (evidenceCount < 0) return 0;
27521
+ if (evidenceCount > 0) return 0;
27522
+ if (allowUnverified(env)) return 0;
27523
+ return STRICT_DONE_EXIT_CODE;
27419
27524
  }
27420
27525
  function strictGateEventPayload(evaluation) {
27421
27526
  return {
27422
27527
  engine: evaluation.native ? "kraken-legacy+completion-policy+criteria-pack" : "kraken-legacy+completion-policy",
27423
27528
  strict: evaluation.strict,
27424
27529
  verdict: evaluation.evaluation?.verdict ?? (evaluation.blocked ? "BLOCKED" : "PASS"),
27530
+ // M1.2: UNVERIFIED marker — strict on, nothing evaluable. Present only
27531
+ // when true so historical payloads stay byte-identical.
27532
+ ...evaluation.unverified ? { unverified: true } : {},
27425
27533
  legacy: {
27426
27534
  total: evaluation.gate.total,
27427
27535
  passed: evaluation.gate.passed,
@@ -31734,11 +31842,11 @@ var init_synthesisAudit = __esm({
31734
31842
  import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
31735
31843
  import { join as join5 } from "node:path";
31736
31844
  function loadNfrSpec(zelariRoot) {
31737
- const path100 = join5(zelariRoot, "nfr-spec.json");
31738
- if (!existsSync10(path100))
31845
+ const path101 = join5(zelariRoot, "nfr-spec.json");
31846
+ if (!existsSync10(path101))
31739
31847
  return null;
31740
31848
  try {
31741
- const raw = JSON.parse(readFileSync9(path100, "utf8"));
31849
+ const raw = JSON.parse(readFileSync9(path101, "utf8"));
31742
31850
  if (raw.version !== 1 || !Array.isArray(raw.targets))
31743
31851
  return null;
31744
31852
  return raw;
@@ -34139,9 +34247,9 @@ var init_types9 = __esm({
34139
34247
  import { readFileSync as readFileSync14 } from "node:fs";
34140
34248
  import { join as join11 } from "node:path";
34141
34249
  function readLessonsDeduped(zelariRoot) {
34142
- const path100 = join11(zelariRoot, LESSONS_FILE);
34250
+ const path101 = join11(zelariRoot, LESSONS_FILE);
34143
34251
  try {
34144
- const raw = readFileSync14(path100, "utf8");
34252
+ const raw = readFileSync14(path101, "utf8");
34145
34253
  const byId = /* @__PURE__ */ new Map();
34146
34254
  for (const line of raw.split(/\r?\n/)) {
34147
34255
  if (!line.trim())
@@ -34242,8 +34350,8 @@ function keywordsFrom(check2, signature) {
34242
34350
  return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
34243
34351
  }
34244
34352
  function writeLesson(zelariRoot, lesson) {
34245
- const path100 = join12(zelariRoot, LESSONS_FILE);
34246
- appendFileSync(path100, `${JSON.stringify(lesson)}
34353
+ const path101 = join12(zelariRoot, LESSONS_FILE);
34354
+ appendFileSync(path101, `${JSON.stringify(lesson)}
34247
34355
  `, "utf8");
34248
34356
  }
34249
34357
  function findSimilar(lessons, signature) {
@@ -36211,9 +36319,9 @@ function findCycle(nodes) {
36211
36319
  if (color.get(start) !== WHITE)
36212
36320
  continue;
36213
36321
  const stack = [[start, 0]];
36214
- const path100 = [];
36322
+ const path101 = [];
36215
36323
  color.set(start, GRAY);
36216
- path100.push(start);
36324
+ path101.push(start);
36217
36325
  while (stack.length > 0) {
36218
36326
  const top = stack[stack.length - 1];
36219
36327
  const [id3, idx] = top;
@@ -36226,17 +36334,17 @@ function findCycle(nodes) {
36226
36334
  continue;
36227
36335
  const c = color.get(dep);
36228
36336
  if (c === GRAY) {
36229
- const at = path100.indexOf(dep);
36230
- return [...path100.slice(at), dep];
36337
+ const at = path101.indexOf(dep);
36338
+ return [...path101.slice(at), dep];
36231
36339
  }
36232
36340
  if (c === WHITE) {
36233
36341
  color.set(dep, GRAY);
36234
- path100.push(dep);
36342
+ path101.push(dep);
36235
36343
  stack.push([dep, 0]);
36236
36344
  }
36237
36345
  } else {
36238
36346
  color.set(id3, BLACK);
36239
- path100.pop();
36347
+ path101.pop();
36240
36348
  stack.pop();
36241
36349
  }
36242
36350
  }
@@ -37156,8 +37264,8 @@ var init_runner = __esm({
37156
37264
  failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
37157
37265
  pending: []
37158
37266
  };
37159
- const path100 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
37160
- this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path100}`);
37267
+ const path101 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
37268
+ this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path101}`);
37161
37269
  return snapshot;
37162
37270
  }
37163
37271
  callLog(msg, data) {
@@ -38308,7 +38416,7 @@ var CORE_VERSION;
38308
38416
  var init_version = __esm({
38309
38417
  "packages/core/dist/version.js"() {
38310
38418
  "use strict";
38311
- CORE_VERSION = "2.37.0";
38419
+ CORE_VERSION = "2.37.1";
38312
38420
  }
38313
38421
  });
38314
38422
 
@@ -40767,9 +40875,9 @@ function spillToolOutput(fullText, meta3) {
40767
40875
  const rnd = randomBytes3(3).toString("hex");
40768
40876
  const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
40769
40877
  const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
40770
- const path100 = join14(dir, file2);
40771
- writeFileSync12(path100, fullText, "utf8");
40772
- return path100;
40878
+ const path101 = join14(dir, file2);
40879
+ writeFileSync12(path101, fullText, "utf8");
40880
+ return path101;
40773
40881
  } catch {
40774
40882
  return null;
40775
40883
  }
@@ -40815,10 +40923,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
40815
40923
  ${tail2}`;
40816
40924
  }
40817
40925
  if (doSpill) {
40818
- const path100 = spillToolOutput(text, { toolName: opts.toolName });
40819
- if (path100) {
40926
+ const path101 = spillToolOutput(text, { toolName: opts.toolName });
40927
+ if (path101) {
40820
40928
  const spillNote = `
40821
- \u2026 [full output spilled to: ${path100} \u2014 re-read with read_file if you need the complete text] \u2026`;
40929
+ \u2026 [full output spilled to: ${path101} \u2014 re-read with read_file if you need the complete text] \u2026`;
40822
40930
  if (preview.includes("] \u2026\n")) {
40823
40931
  preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
40824
40932
  `);
@@ -41589,28 +41697,28 @@ var init_storage = __esm({
41589
41697
  VALID_SCALARS = /^(true|false|null|~)$/i;
41590
41698
  Storage = class {
41591
41699
  /** Read a Markdown file with frontmatter. Throws if not found. */
41592
- read(path100) {
41593
- if (!existsSync19(path100)) {
41594
- throw new Error(`File not found: ${path100}`);
41700
+ read(path101) {
41701
+ if (!existsSync19(path101)) {
41702
+ throw new Error(`File not found: ${path101}`);
41595
41703
  }
41596
- const md = readFileSync17(path100, "utf8");
41704
+ const md = readFileSync17(path101, "utf8");
41597
41705
  return parseFrontmatter(md);
41598
41706
  }
41599
41707
  /** Read a Markdown file; returns null if not found. */
41600
- readIfExists(path100) {
41601
- if (!existsSync19(path100)) return null;
41602
- return this.read(path100);
41708
+ readIfExists(path101) {
41709
+ if (!existsSync19(path101)) return null;
41710
+ return this.read(path101);
41603
41711
  }
41604
41712
  /**
41605
41713
  * Write a Markdown file atomically (tmp + rename). Creates parent dirs.
41606
41714
  * The meta object is serialized as YAML frontmatter; body as Markdown.
41607
41715
  */
41608
- write(path100, meta3, body) {
41609
- mkdirSync10(dirname2(path100), { recursive: true });
41610
- const tmp = path100 + ".tmp-" + process.pid;
41716
+ write(path101, meta3, body) {
41717
+ mkdirSync10(dirname2(path101), { recursive: true });
41718
+ const tmp = path101 + ".tmp-" + process.pid;
41611
41719
  const md = serializeFrontmatter(meta3, body);
41612
41720
  writeFileSync14(tmp, md, "utf8");
41613
- renameSync2(tmp, path100);
41721
+ renameSync2(tmp, path101);
41614
41722
  }
41615
41723
  /** List all .md files in a directory (non-recursive). */
41616
41724
  listMarkdown(dir) {
@@ -41721,8 +41829,8 @@ function nextPlanTaskId(store6) {
41721
41829
  return `t${store6.counter}`;
41722
41830
  }
41723
41831
  function writePlanTaskArtifact(rootDir, task) {
41724
- const path100 = join17(rootDir, "plan-tasks", `${task.id}.md`);
41725
- mkdirSync11(dirname3(path100), { recursive: true });
41832
+ const path101 = join17(rootDir, "plan-tasks", `${task.id}.md`);
41833
+ mkdirSync11(dirname3(path101), { recursive: true });
41726
41834
  const meta3 = {
41727
41835
  kind: "task",
41728
41836
  id: task.id,
@@ -41743,7 +41851,7 @@ function writePlanTaskArtifact(rootDir, task) {
41743
41851
  task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
41744
41852
  ""
41745
41853
  ].filter((l) => l !== null).join("\n");
41746
- new Storage().write(path100, meta3, body);
41854
+ new Storage().write(path101, meta3, body);
41747
41855
  }
41748
41856
  function loadHandle(rootDir) {
41749
41857
  const jsonPath = join17(rootDir, "plan.json");
@@ -52074,21 +52182,21 @@ function normalizeAuth(auth) {
52074
52182
  return "agent";
52075
52183
  }
52076
52184
  function readSecrets() {
52077
- const path100 = getSshSecretsPath();
52078
- if (!existsSync30(path100)) return {};
52185
+ const path101 = getSshSecretsPath();
52186
+ if (!existsSync30(path101)) return {};
52079
52187
  try {
52080
- return JSON.parse(readFileSync22(path100, "utf8"));
52188
+ return JSON.parse(readFileSync22(path101, "utf8"));
52081
52189
  } catch {
52082
52190
  return {};
52083
52191
  }
52084
52192
  }
52085
52193
  function writeSecrets(data) {
52086
- const path100 = getSshSecretsPath();
52087
- mkdirSync13(dirname4(path100), { recursive: true });
52088
- writeFileSync16(path100, `${JSON.stringify(data, null, 2)}
52194
+ const path101 = getSshSecretsPath();
52195
+ mkdirSync13(dirname4(path101), { recursive: true });
52196
+ writeFileSync16(path101, `${JSON.stringify(data, null, 2)}
52089
52197
  `, "utf8");
52090
52198
  try {
52091
- chmodSync(path100, 384);
52199
+ chmodSync(path101, 384);
52092
52200
  } catch {
52093
52201
  }
52094
52202
  }
@@ -52117,10 +52225,10 @@ function deleteSshPassword(id3) {
52117
52225
  writeSecrets({ passwords });
52118
52226
  }
52119
52227
  function readStore2() {
52120
- const path100 = getSshTargetsPath();
52121
- if (!existsSync30(path100)) return [];
52228
+ const path101 = getSshTargetsPath();
52229
+ if (!existsSync30(path101)) return [];
52122
52230
  try {
52123
- const parsed = JSON.parse(readFileSync22(path100, "utf8"));
52231
+ const parsed = JSON.parse(readFileSync22(path101, "utf8"));
52124
52232
  const list = Array.isArray(parsed.targets) ? parsed.targets : [];
52125
52233
  return list.filter(
52126
52234
  (t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
@@ -52135,11 +52243,11 @@ function readStore2() {
52135
52243
  }
52136
52244
  }
52137
52245
  function writeStore2(targets) {
52138
- const path100 = getSshTargetsPath();
52139
- mkdirSync13(dirname4(path100), { recursive: true });
52246
+ const path101 = getSshTargetsPath();
52247
+ mkdirSync13(dirname4(path101), { recursive: true });
52140
52248
  const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
52141
52249
  writeFileSync16(
52142
- path100,
52250
+ path101,
52143
52251
  `${JSON.stringify({ targets: clean }, null, 2)}
52144
52252
  `,
52145
52253
  "utf8"
@@ -52385,11 +52493,11 @@ function formatSshTargetsForPrompt() {
52385
52493
  ];
52386
52494
  for (const t of targets) {
52387
52495
  const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
52388
- const path100 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
52496
+ const path101 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
52389
52497
  const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
52390
52498
  const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
52391
52499
  lines.push(
52392
- `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path100}${tags}${allow}`
52500
+ `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path101}${tags}${allow}`
52393
52501
  );
52394
52502
  }
52395
52503
  return lines.join("\n");
@@ -57289,6 +57397,8 @@ function parseHeadlessFlags(argv) {
57289
57397
  missionStrict = true;
57290
57398
  } else if (arg === "--no-mission-strict") {
57291
57399
  missionStrict = false;
57400
+ } else if (arg === "--allow-unverified") {
57401
+ process.env.ZELARI_ALLOW_UNVERIFIED = "1";
57292
57402
  } else if (arg === "--kraken-graph") {
57293
57403
  krakenGraph = argv[i + 1];
57294
57404
  i++;
@@ -57402,6 +57512,7 @@ __export(headlessSpine_exports, {
57402
57512
  seedHeadlessModelHistory: () => seedHeadlessModelHistory,
57403
57513
  sessionStartedEvent: () => sessionStartedEvent
57404
57514
  });
57515
+ import path67 from "node:path";
57405
57516
  function sessionStartedEvent(handle) {
57406
57517
  return {
57407
57518
  type: "session_started",
@@ -57413,6 +57524,20 @@ function resolveHeadlessProfileId(mode, explicit) {
57413
57524
  if (explicit) return resolveProfile(explicit).id;
57414
57525
  return defaultProfileForMode(mode ?? "kraken");
57415
57526
  }
57527
+ async function countVerificationEvidenceInLog(mirror, sessionId2) {
57528
+ if (mirror.status !== "active" && mirror.status !== "closed") return -1;
57529
+ try {
57530
+ await mirror.flush().catch(() => void 0);
57531
+ const report = await readSessionLog(path67.join(mirror.sessionsDir, sessionId2, "events.jsonl"));
57532
+ return report.events.filter((e) => e.kind === "verification.evidence").length;
57533
+ } catch (err) {
57534
+ process.stderr.write(
57535
+ `[zelari-code] verification-evidence count unavailable (${err instanceof Error ? err.message : String(err)}) \u2014 event-back gate skipped
57536
+ `
57537
+ );
57538
+ return -1;
57539
+ }
57540
+ }
57416
57541
  async function openHeadlessSpine(opts) {
57417
57542
  const profileId = resolveHeadlessProfileId(opts.mode, opts.profile);
57418
57543
  let profileTools = [];
@@ -57484,6 +57609,9 @@ async function openHeadlessSpine(opts) {
57484
57609
  lastVerificationRun() {
57485
57610
  return spine.lastVerificationRun();
57486
57611
  },
57612
+ countVerificationEvidence() {
57613
+ return countVerificationEvidenceInLog(spine, opts.sessionId);
57614
+ },
57487
57615
  missionPhase(phase2, note) {
57488
57616
  spine.missionPhase(phase2, note);
57489
57617
  },
@@ -57591,6 +57719,7 @@ var init_headlessSpine = __esm({
57591
57719
  init_dist();
57592
57720
  init_session();
57593
57721
  init_mission2();
57722
+ init_session();
57594
57723
  init_runtime();
57595
57724
  init_sessionSpine();
57596
57725
  init_budgetRuntime();
@@ -58194,7 +58323,7 @@ var init_planDetect = __esm({
58194
58323
  // src/cli/memory/legacyImport.ts
58195
58324
  import { createHash as createHash18 } from "node:crypto";
58196
58325
  import { promises as fs27 } from "node:fs";
58197
- import * as path67 from "node:path";
58326
+ import * as path68 from "node:path";
58198
58327
  function sourceId(fact, line) {
58199
58328
  return `jsonl:${fact.id ?? createHash18("sha256").update(line).digest("hex")}`;
58200
58329
  }
@@ -58212,7 +58341,7 @@ function timestamp(value) {
58212
58341
  }
58213
58342
  async function importLegacyMemoryLog(backend, service) {
58214
58343
  const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
58215
- const logPath = path67.join(path67.dirname(backend.databasePath), "log.jsonl");
58344
+ const logPath = path68.join(path68.dirname(backend.databasePath), "log.jsonl");
58216
58345
  let raw;
58217
58346
  try {
58218
58347
  raw = await fs27.readFile(logPath, "utf8");
@@ -58395,7 +58524,7 @@ var init_sqliteCodec = __esm({
58395
58524
  // src/cli/memory/sqliteRpc.ts
58396
58525
  import { existsSync as existsSync36 } from "node:fs";
58397
58526
  import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
58398
- import * as path68 from "node:path";
58527
+ import * as path69 from "node:path";
58399
58528
  import { Worker } from "node:worker_threads";
58400
58529
  function isBusy(error51) {
58401
58530
  const candidate = error51;
@@ -58404,10 +58533,10 @@ function isBusy(error51) {
58404
58533
  );
58405
58534
  }
58406
58535
  function resolveWorkerUrl() {
58407
- const here = path68.dirname(fileURLToPath2(import.meta.url));
58408
- const direct = path68.join(here, "sqliteWorker.mjs");
58536
+ const here = path69.dirname(fileURLToPath2(import.meta.url));
58537
+ const direct = path69.join(here, "sqliteWorker.mjs");
58409
58538
  if (existsSync36(direct)) return pathToFileURL2(direct);
58410
- return pathToFileURL2(path68.join(here, "memory", "sqliteWorker.mjs"));
58539
+ return pathToFileURL2(path69.join(here, "memory", "sqliteWorker.mjs"));
58411
58540
  }
58412
58541
  var SqliteWorkerRpc;
58413
58542
  var init_sqliteRpc = __esm({
@@ -58696,7 +58825,7 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
58696
58825
  // src/cli/memory/sqliteBackend.ts
58697
58826
  import { createHash as createHash19, randomUUID as randomUUID6 } from "node:crypto";
58698
58827
  import { promises as fs28 } from "node:fs";
58699
- import * as path69 from "node:path";
58828
+ import * as path70 from "node:path";
58700
58829
  function boundedLimit(value, fallback = 50) {
58701
58830
  return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
58702
58831
  }
@@ -58758,16 +58887,16 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
58758
58887
  try {
58759
58888
  resolved = await fs28.realpath(projectRoot);
58760
58889
  } catch {
58761
- resolved = path69.resolve(projectRoot);
58890
+ resolved = path70.resolve(projectRoot);
58762
58891
  }
58763
58892
  if (this.initialized && resolved === this.projectRoot) return;
58764
58893
  if (this.initialized) await this.close();
58765
58894
  const filename = this.options.filename ?? "memory.db";
58766
- if (path69.basename(filename) !== filename || filename === "." || filename === "..") {
58895
+ if (path70.basename(filename) !== filename || filename === "." || filename === "..") {
58767
58896
  throw new Error("SQLite memory filename must not contain a path.");
58768
58897
  }
58769
- const zelariDirectory = path69.join(resolved, ".zelari");
58770
- const directory = path69.join(zelariDirectory, "memory");
58898
+ const zelariDirectory = path70.join(resolved, ".zelari");
58899
+ const directory = path70.join(zelariDirectory, "memory");
58771
58900
  for (const candidate of [zelariDirectory, directory]) {
58772
58901
  let stat8;
58773
58902
  try {
@@ -58786,12 +58915,12 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
58786
58915
  }
58787
58916
  }
58788
58917
  const canonicalDirectory = await fs28.realpath(directory);
58789
- const relativeDirectory = path69.relative(resolved, canonicalDirectory);
58790
- if (relativeDirectory.startsWith("..") || path69.isAbsolute(relativeDirectory)) {
58918
+ const relativeDirectory = path70.relative(resolved, canonicalDirectory);
58919
+ if (relativeDirectory.startsWith("..") || path70.isAbsolute(relativeDirectory)) {
58791
58920
  throw new Error("SQLite memory directory resolves outside the active project.");
58792
58921
  }
58793
58922
  this.projectRoot = resolved;
58794
- this.databasePath = path69.join(canonicalDirectory, filename);
58923
+ this.databasePath = path70.join(canonicalDirectory, filename);
58795
58924
  const opened = await this.rpc.open({
58796
58925
  dbPath: this.databasePath,
58797
58926
  schemaSql: SQLITE_MEMORY_BASE_SCHEMA,
@@ -59324,7 +59453,7 @@ __export(serviceFactory_exports, {
59324
59453
  });
59325
59454
  import { createHash as createHash20 } from "node:crypto";
59326
59455
  import { promises as fs29 } from "node:fs";
59327
- import * as path70 from "node:path";
59456
+ import * as path71 from "node:path";
59328
59457
  function isMemoryV2Enabled(env = process.env) {
59329
59458
  if (env.ZELARI_MEMORY === "0") return false;
59330
59459
  if (env.ZELARI_MEMORY_BACKEND === "file" || env.ZELARI_MEMORY_BACKEND === "jsonl") return false;
@@ -59345,7 +59474,7 @@ async function canonicalProjectId(projectRoot) {
59345
59474
  try {
59346
59475
  canonical = await fs29.realpath(projectRoot);
59347
59476
  } catch {
59348
- canonical = path70.resolve(projectRoot);
59477
+ canonical = path71.resolve(projectRoot);
59349
59478
  }
59350
59479
  canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
59351
59480
  if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
@@ -60047,8 +60176,8 @@ function readPlan(ctx) {
60047
60176
  } catch {
60048
60177
  }
60049
60178
  }
60050
- const path100 = workspaceFile(ctx.rootDir, "plan");
60051
- const doc = ctx.storage.readIfExists(path100);
60179
+ const path101 = workspaceFile(ctx.rootDir, "plan");
60180
+ const doc = ctx.storage.readIfExists(path101);
60052
60181
  if (!doc) return { phases: [], tasks: [], milestones: [] };
60053
60182
  const meta3 = doc.meta;
60054
60183
  return {
@@ -60229,7 +60358,7 @@ function addMilestoneRecord(ctx, summary, input) {
60229
60358
  dueDate: input.dueDate,
60230
60359
  targetVersion: version2
60231
60360
  });
60232
- const path100 = join31(ctx.rootDir, "milestones", `${id3}.md`);
60361
+ const path101 = join31(ctx.rootDir, "milestones", `${id3}.md`);
60233
60362
  const meta3 = {
60234
60363
  kind: "milestone",
60235
60364
  id: id3,
@@ -60246,7 +60375,7 @@ function addMilestoneRecord(ctx, summary, input) {
60246
60375
  `Target version: ${version2}`,
60247
60376
  ""
60248
60377
  ].join("\n");
60249
- ctx.storage.write(path100, meta3, body);
60378
+ ctx.storage.write(path101, meta3, body);
60250
60379
  return { id: id3, created: true };
60251
60380
  }
60252
60381
  function readPlanSummary(ctx) {
@@ -60450,7 +60579,7 @@ function addIdeaStub(ctx) {
60450
60579
  const tags = args["tags"] ?? [];
60451
60580
  const category = args["category"] ?? "General";
60452
60581
  const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
60453
- const path100 = workspaceArtifact(ctx.rootDir, "decisions", id3);
60582
+ const path101 = workspaceArtifact(ctx.rootDir, "decisions", id3);
60454
60583
  const meta3 = {
60455
60584
  kind: "adr",
60456
60585
  status: "proposed",
@@ -60476,7 +60605,7 @@ function addIdeaStub(ctx) {
60476
60605
  ...consequences.map((c) => `- ${c}`),
60477
60606
  ""
60478
60607
  ].join("\n");
60479
- ctx.storage.write(path100, meta3, body);
60608
+ ctx.storage.write(path101, meta3, body);
60480
60609
  return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
60481
60610
  });
60482
60611
  }
@@ -60558,14 +60687,14 @@ function createDocumentStub(ctx) {
60558
60687
  ctx.storage.write(risksPath, riskMeta, content);
60559
60688
  return `Document "${title}" created at risks.md (workspace root).`;
60560
60689
  }
60561
- const path100 = workspaceArtifact(ctx.rootDir, "docs", slug);
60690
+ const path101 = workspaceArtifact(ctx.rootDir, "docs", slug);
60562
60691
  const meta3 = {
60563
60692
  kind: "doc",
60564
60693
  id: slug,
60565
60694
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
60566
60695
  tags
60567
60696
  };
60568
- ctx.storage.write(path100, meta3, content);
60697
+ ctx.storage.write(path101, meta3, content);
60569
60698
  return `Document "${title}" created at docs/${slug}.md.`;
60570
60699
  });
60571
60700
  }
@@ -61190,10 +61319,10 @@ function getUserMcpPath() {
61190
61319
  function getProjectMcpPath(projectRoot) {
61191
61320
  return join32(projectRoot, ".zelari", "mcp.json");
61192
61321
  }
61193
- function readFile9(path100) {
61194
- if (!existsSync42(path100)) return {};
61322
+ function readFile9(path101) {
61323
+ if (!existsSync42(path101)) return {};
61195
61324
  try {
61196
- const parsed = JSON.parse(readFileSync30(path100, "utf8"));
61325
+ const parsed = JSON.parse(readFileSync30(path101, "utf8"));
61197
61326
  const out = {};
61198
61327
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
61199
61328
  const hasCommand = !!cfg && typeof cfg.command === "string" && !!cfg.command.trim();
@@ -61215,10 +61344,10 @@ function readFile9(path100) {
61215
61344
  return {};
61216
61345
  }
61217
61346
  }
61218
- function writeFile3(path100, servers) {
61219
- mkdirSync17(dirname9(path100), { recursive: true });
61347
+ function writeFile3(path101, servers) {
61348
+ mkdirSync17(dirname9(path101), { recursive: true });
61220
61349
  const body = { mcpServers: servers };
61221
- writeFileSync19(path100, `${JSON.stringify(body, null, 2)}
61350
+ writeFileSync19(path101, `${JSON.stringify(body, null, 2)}
61222
61351
  `, "utf8");
61223
61352
  }
61224
61353
  function listMcpServers(projectRoot) {
@@ -61256,9 +61385,9 @@ function upsertMcpServer(opts) {
61256
61385
  error: "either command (stdio) or url (http) is required"
61257
61386
  };
61258
61387
  }
61259
- let path100;
61388
+ let path101;
61260
61389
  if (opts.scope === "user") {
61261
- path100 = getUserMcpPath();
61390
+ path101 = getUserMcpPath();
61262
61391
  } else {
61263
61392
  const root = opts.projectRoot?.trim();
61264
61393
  if (!root) {
@@ -61267,9 +61396,9 @@ function upsertMcpServer(opts) {
61267
61396
  error: "projectRoot required for project scope (Open Folder first)"
61268
61397
  };
61269
61398
  }
61270
- path100 = getProjectMcpPath(root);
61399
+ path101 = getProjectMcpPath(root);
61271
61400
  }
61272
- const current = readFile9(path100);
61401
+ const current = readFile9(path101);
61273
61402
  current[name] = {
61274
61403
  command: hasCommand ? opts.config.command.trim() : void 0,
61275
61404
  args: opts.config.args,
@@ -61280,21 +61409,21 @@ function upsertMcpServer(opts) {
61280
61409
  serial: opts.config.serial,
61281
61410
  enabled: opts.config.enabled !== false
61282
61411
  };
61283
- writeFile3(path100, current);
61284
- return { ok: true, path: path100 };
61412
+ writeFile3(path101, current);
61413
+ return { ok: true, path: path101 };
61285
61414
  }
61286
61415
  function removeMcpServer(opts) {
61287
- const path100 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
61288
- if (!path100) {
61416
+ const path101 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
61417
+ if (!path101) {
61289
61418
  return { ok: false, error: "projectRoot required for project scope" };
61290
61419
  }
61291
- const current = readFile9(path100);
61420
+ const current = readFile9(path101);
61292
61421
  if (!(opts.name in current)) {
61293
- return { ok: false, error: `Server "${opts.name}" not found in ${path100}` };
61422
+ return { ok: false, error: `Server "${opts.name}" not found in ${path101}` };
61294
61423
  }
61295
61424
  delete current[opts.name];
61296
- writeFile3(path100, current);
61297
- return { ok: true, path: path100 };
61425
+ writeFile3(path101, current);
61426
+ return { ok: true, path: path101 };
61298
61427
  }
61299
61428
  var init_mcpConfigIo = __esm({
61300
61429
  "src/cli/mcp/mcpConfigIo.ts"() {
@@ -61765,10 +61894,10 @@ import { createHash as createHash21 } from "node:crypto";
61765
61894
  import { join as join34 } from "node:path";
61766
61895
  import { readFile as readFile10 } from "node:fs/promises";
61767
61896
  async function readPackageJson3(projectRoot) {
61768
- const path100 = join34(projectRoot, "package.json");
61769
- if (!existsSync44(path100)) return null;
61897
+ const path101 = join34(projectRoot, "package.json");
61898
+ if (!existsSync44(path101)) return null;
61770
61899
  try {
61771
- return JSON.parse(await readFile10(path100, "utf8"));
61900
+ return JSON.parse(await readFile10(path101, "utf8"));
61772
61901
  } catch {
61773
61902
  return null;
61774
61903
  }
@@ -61850,9 +61979,9 @@ async function genBuild(ctx) {
61850
61979
  ].join("\n");
61851
61980
  }
61852
61981
  async function genOpenQuestions(ctx) {
61853
- const path100 = join34(ctx.rootDir, "risks.md");
61854
- if (!existsSync44(path100)) return "_No open questions._";
61855
- const content = readFileSync32(path100, "utf8");
61982
+ const path101 = join34(ctx.rootDir, "risks.md");
61983
+ if (!existsSync44(path101)) return "_No open questions._";
61984
+ const content = readFileSync32(path101, "utf8");
61856
61985
  const lines = content.split("\n");
61857
61986
  const questions = [];
61858
61987
  let currentTitle = "";
@@ -62126,9 +62255,9 @@ function versionKey(value) {
62126
62255
  function firstString2(v) {
62127
62256
  return typeof v === "string" && v.trim().length > 0 ? v : null;
62128
62257
  }
62129
- function readFileSyncSafe(path100) {
62258
+ function readFileSyncSafe(path101) {
62130
62259
  try {
62131
- return readFileSync33(path100, "utf8");
62260
+ return readFileSync33(path101, "utf8");
62132
62261
  } catch {
62133
62262
  return null;
62134
62263
  }
@@ -62376,7 +62505,7 @@ __export(evidenceFromSpine_exports, {
62376
62505
  evidenceRefsFromEventLines: () => evidenceRefsFromEventLines
62377
62506
  });
62378
62507
  import { existsSync as existsSync47, readFileSync as readFileSync35 } from "node:fs";
62379
- import path71 from "node:path";
62508
+ import path72 from "node:path";
62380
62509
  function asRecord2(v) {
62381
62510
  return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
62382
62511
  }
@@ -62414,7 +62543,7 @@ function evidenceRefsFromEventLines(lines) {
62414
62543
  }
62415
62544
  function collectSessionEvidenceRefs(sessionId2) {
62416
62545
  try {
62417
- const file2 = path71.join(sessionsDir(), sessionId2, "events.jsonl");
62546
+ const file2 = path72.join(sessionsDir(), sessionId2, "events.jsonl");
62418
62547
  if (!existsSync47(file2)) return [];
62419
62548
  return evidenceRefsFromEventLines(readFileSync35(file2, "utf8").split("\n"));
62420
62549
  } catch {
@@ -62664,8 +62793,8 @@ async function runPostCouncilHook(ctx, options) {
62664
62793
  sources: scope.sources
62665
62794
  } : void 0
62666
62795
  });
62667
- const path100 = writeCouncilCompletion(ctx.rootDir, completion);
62668
- completionHook = { ran: true, path: path100, completion };
62796
+ const path101 = writeCouncilCompletion(ctx.rootDir, completion);
62797
+ completionHook = { ran: true, path: path101, completion };
62669
62798
  } catch (err) {
62670
62799
  completionHook = {
62671
62800
  ran: true,
@@ -62710,7 +62839,7 @@ import {
62710
62839
  writeFileSync as writeFileSync22,
62711
62840
  mkdirSync as mkdirSync18
62712
62841
  } from "node:fs";
62713
- import path72 from "node:path";
62842
+ import path73 from "node:path";
62714
62843
  var FeedbackStore;
62715
62844
  var init_councilFeedback = __esm({
62716
62845
  "src/cli/councilFeedback.ts"() {
@@ -62827,7 +62956,7 @@ var init_councilFeedback = __esm({
62827
62956
  }
62828
62957
  }
62829
62958
  save() {
62830
- mkdirSync18(path72.dirname(this.file), { recursive: true });
62959
+ mkdirSync18(path73.dirname(this.file), { recursive: true });
62831
62960
  writeFileSync22(
62832
62961
  this.file,
62833
62962
  JSON.stringify({ entries: this.entries }, null, 2),
@@ -62902,12 +63031,12 @@ __export(ledger_exports, {
62902
63031
  readLedger: () => readLedger
62903
63032
  });
62904
63033
  import { appendFileSync as appendFileSync4, existsSync as existsSync50, mkdirSync as mkdirSync19, readFileSync as readFileSync38 } from "node:fs";
62905
- import path73 from "node:path";
63034
+ import path74 from "node:path";
62906
63035
  function evolutionMode(env = process.env) {
62907
63036
  return env[EVOLUTION_ENV] === "shadow" ? "shadow" : "0";
62908
63037
  }
62909
63038
  function ledgerPath(cwd) {
62910
- return path73.join(cwd, LEDGER_REL);
63039
+ return path74.join(cwd, LEDGER_REL);
62911
63040
  }
62912
63041
  function appendLedgerEntry(cwd, entry) {
62913
63042
  if (evolutionMode() === "0") {
@@ -62915,7 +63044,7 @@ function appendLedgerEntry(cwd, entry) {
62915
63044
  }
62916
63045
  try {
62917
63046
  const file2 = ledgerPath(cwd);
62918
- mkdirSync19(path73.dirname(file2), { recursive: true });
63047
+ mkdirSync19(path74.dirname(file2), { recursive: true });
62919
63048
  appendFileSync4(file2, `${JSON.stringify(entry)}
62920
63049
  `, "utf8");
62921
63050
  return { written: true, path: file2 };
@@ -63016,7 +63145,7 @@ var init_ledger = __esm({
63016
63145
  "src/cli/evolution/ledger.ts"() {
63017
63146
  "use strict";
63018
63147
  EVOLUTION_ENV = "ZELARI_EVOLUTION";
63019
- LEDGER_REL = path73.join(".zelari", "evolution", "ledger.jsonl");
63148
+ LEDGER_REL = path74.join(".zelari", "evolution", "ledger.jsonl");
63020
63149
  TIER_WEIGHTS = {
63021
63150
  build: 1,
63022
63151
  "tool-output": 1,
@@ -63158,7 +63287,7 @@ __export(fileBackend_exports, {
63158
63287
  });
63159
63288
  import { randomUUID as randomUUID7 } from "node:crypto";
63160
63289
  import { promises as fs31 } from "node:fs";
63161
- import * as path74 from "node:path";
63290
+ import * as path75 from "node:path";
63162
63291
  function tokenize2(text) {
63163
63292
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
63164
63293
  }
@@ -63211,8 +63340,8 @@ var init_fileBackend = __esm({
63211
63340
  logPath = "";
63212
63341
  memoryDir = "";
63213
63342
  async init(projectRoot) {
63214
- this.memoryDir = path74.join(projectRoot, ".zelari", "memory");
63215
- this.logPath = path74.join(this.memoryDir, "log.jsonl");
63343
+ this.memoryDir = path75.join(projectRoot, ".zelari", "memory");
63344
+ this.logPath = path75.join(this.memoryDir, "log.jsonl");
63216
63345
  await fs31.mkdir(this.memoryDir, { recursive: true });
63217
63346
  }
63218
63347
  async add(content, metadata2 = {}, graph) {
@@ -63285,12 +63414,12 @@ var init_fileBackend = __esm({
63285
63414
 
63286
63415
  // src/cli/traceStore.ts
63287
63416
  import { promises as fs32 } from "node:fs";
63288
- import * as path75 from "node:path";
63417
+ import * as path76 from "node:path";
63289
63418
  function traceDir(projectRoot) {
63290
- return path75.join(projectRoot, ".zelari", "trace");
63419
+ return path76.join(projectRoot, ".zelari", "trace");
63291
63420
  }
63292
63421
  function tracePath(projectRoot, missionId) {
63293
- return path75.join(traceDir(projectRoot), `${missionId}.json`);
63422
+ return path76.join(traceDir(projectRoot), `${missionId}.json`);
63294
63423
  }
63295
63424
  async function saveTrace(projectRoot, missionId, entries) {
63296
63425
  const dir = traceDir(projectRoot);
@@ -63332,7 +63461,7 @@ __export(zelariMission_exports, {
63332
63461
  });
63333
63462
  import { randomUUID as randomUUID8 } from "node:crypto";
63334
63463
  import { promises as fs33 } from "node:fs";
63335
- import * as path76 from "node:path";
63464
+ import * as path77 from "node:path";
63336
63465
  function resolveMaxIterations(env = process.env) {
63337
63466
  const raw = env.ZELARI_MISSION_MAX_ITER;
63338
63467
  const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
@@ -63375,10 +63504,10 @@ function isMissionAutoStart(env = process.env) {
63375
63504
  return env.ZELARI_MISSION_AUTO === "1";
63376
63505
  }
63377
63506
  async function writeMissionState(projectRoot, state3) {
63378
- const dir = path76.join(projectRoot, ".zelari");
63507
+ const dir = path77.join(projectRoot, ".zelari");
63379
63508
  await fs33.mkdir(dir, { recursive: true });
63380
63509
  await fs33.writeFile(
63381
- path76.join(dir, "mission-state.json"),
63510
+ path77.join(dir, "mission-state.json"),
63382
63511
  JSON.stringify(state3, null, 2) + "\n",
63383
63512
  "utf8"
63384
63513
  );
@@ -63392,7 +63521,7 @@ async function writeMissionState(projectRoot, state3) {
63392
63521
  async function loadMissionState(projectRoot) {
63393
63522
  try {
63394
63523
  const raw = await fs33.readFile(
63395
- path76.join(projectRoot, ".zelari", "mission-state.json"),
63524
+ path77.join(projectRoot, ".zelari", "mission-state.json"),
63396
63525
  "utf8"
63397
63526
  );
63398
63527
  const parsed = JSON.parse(raw);
@@ -64151,7 +64280,7 @@ function safeSocketPath(socketPath) {
64151
64280
  return socketPath.trim();
64152
64281
  }
64153
64282
  function startPermissionBroker(socketPath, handlers, opts) {
64154
- const path100 = safeSocketPath(socketPath);
64283
+ const path101 = safeSocketPath(socketPath);
64155
64284
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
64156
64285
  const sockets = /* @__PURE__ */ new Set();
64157
64286
  const server = createServer2((socket) => {
@@ -64251,10 +64380,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
64251
64380
  return new Promise((resolve9, reject) => {
64252
64381
  const onError = (err) => reject(err);
64253
64382
  server.once("error", onError);
64254
- server.listen(path100, () => {
64383
+ server.listen(path101, () => {
64255
64384
  server.removeListener("error", onError);
64256
64385
  resolve9({
64257
- socketPath: path100,
64386
+ socketPath: path101,
64258
64387
  stop: () => new Promise((res) => {
64259
64388
  for (const s of sockets) s.destroy();
64260
64389
  sockets.clear();
@@ -64265,7 +64394,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
64265
64394
  if (done) return;
64266
64395
  done = true;
64267
64396
  if (process.platform !== "win32") {
64268
- unlink(path100, () => res());
64397
+ unlink(path101, () => res());
64269
64398
  } else {
64270
64399
  res();
64271
64400
  }
@@ -64278,11 +64407,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
64278
64407
  });
64279
64408
  }
64280
64409
  function requestBrokerAsk(socketPath, ask, opts) {
64281
- const path100 = safeSocketPath(socketPath);
64410
+ const path101 = safeSocketPath(socketPath);
64282
64411
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
64283
64412
  const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
64284
64413
  return new Promise((resolve9, reject) => {
64285
- const socket = connect(path100);
64414
+ const socket = connect(path101);
64286
64415
  let buffer = "";
64287
64416
  let settled = false;
64288
64417
  const settle = (fn) => {
@@ -64297,7 +64426,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
64297
64426
  settle(
64298
64427
  () => reject(
64299
64428
  new Error(
64300
- `permission broker unavailable at "${path100}" (connect timed out after ${connectTimeoutMs}ms)`
64429
+ `permission broker unavailable at "${path101}" (connect timed out after ${connectTimeoutMs}ms)`
64301
64430
  )
64302
64431
  )
64303
64432
  );
@@ -65486,7 +65615,7 @@ var init_prereqChecks = __esm({
65486
65615
 
65487
65616
  // src/cli/plugins/prefs.ts
65488
65617
  import { existsSync as existsSync53, readFileSync as readFileSync40, writeFileSync as writeFileSync23, mkdirSync as mkdirSync20 } from "node:fs";
65489
- import path82 from "node:path";
65618
+ import path83 from "node:path";
65490
65619
  function getPluginPrefsPath() {
65491
65620
  return pluginsPrefsPath();
65492
65621
  }
@@ -65509,7 +65638,7 @@ function getPluginPrefs() {
65509
65638
  }
65510
65639
  function writePluginPrefs(prefs) {
65511
65640
  const file2 = getPluginPrefsPath();
65512
- mkdirSync20(path82.dirname(file2), { recursive: true });
65641
+ mkdirSync20(path83.dirname(file2), { recursive: true });
65513
65642
  writeFileSync23(file2, JSON.stringify(prefs, null, 2), {
65514
65643
  encoding: "utf-8",
65515
65644
  mode: 384
@@ -65547,7 +65676,7 @@ __export(registry_exports, {
65547
65676
  isBinaryOnPath: () => isBinaryOnPath
65548
65677
  });
65549
65678
  import { existsSync as existsSync54 } from "node:fs";
65550
- import path83 from "node:path";
65679
+ import path84 from "node:path";
65551
65680
  function detectLocalBin(bin) {
65552
65681
  return (cwd) => {
65553
65682
  try {
@@ -65565,7 +65694,7 @@ function isBinaryOnPath(bin, opts = {}) {
65565
65694
  const platform = opts.platform ?? process.platform;
65566
65695
  const exists = opts.exists ?? existsSync54;
65567
65696
  const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
65568
- const pathMod = platform === "win32" ? path83.win32 : path83.posix;
65697
+ const pathMod = platform === "win32" ? path84.win32 : path84.posix;
65569
65698
  const sep4 = platform === "win32" ? ";" : ":";
65570
65699
  const dirs = pathEnv.split(sep4).filter((d) => d.length > 0);
65571
65700
  const candidates = [bin];
@@ -66670,7 +66799,7 @@ var init_policy = __esm({
66670
66799
 
66671
66800
  // src/cli/orchestration/facts.ts
66672
66801
  import { promises as fs43 } from "node:fs";
66673
- import path87 from "node:path";
66802
+ import path88 from "node:path";
66674
66803
  async function collectRepoFileCount(root = process.cwd()) {
66675
66804
  try {
66676
66805
  await fs43.readdir(root);
@@ -66690,7 +66819,7 @@ async function collectRepoFileCount(root = process.cwd()) {
66690
66819
  }
66691
66820
  for (const e of entries) {
66692
66821
  if (e.isDirectory()) {
66693
- if (!SKIP_DIRS.has(e.name)) queue.push(path87.join(dir, e.name));
66822
+ if (!SKIP_DIRS.has(e.name)) queue.push(path88.join(dir, e.name));
66694
66823
  } else if (e.isFile()) {
66695
66824
  count++;
66696
66825
  if (count > MAX_WALK_FILES) return count;
@@ -66788,7 +66917,7 @@ var init_streamScrub = __esm({
66788
66917
  });
66789
66918
 
66790
66919
  // src/cli/harnessState.ts
66791
- import path88 from "node:path";
66920
+ import path89 from "node:path";
66792
66921
  function asString4(v) {
66793
66922
  return typeof v === "string" ? v : "";
66794
66923
  }
@@ -66963,7 +67092,7 @@ function contractFor(t) {
66963
67092
  };
66964
67093
  }
66965
67094
  async function readHarnessState(sessionDir) {
66966
- const report = await readSessionLog(path88.join(sessionDir, "events.jsonl"));
67095
+ const report = await readSessionLog(path89.join(sessionDir, "events.jsonl"));
66967
67096
  return deriveHarnessState(report.events);
66968
67097
  }
66969
67098
  var init_harnessState = __esm({
@@ -66974,12 +67103,12 @@ var init_harnessState = __esm({
66974
67103
  });
66975
67104
 
66976
67105
  // src/cli/headless/harnessStateEmit.ts
66977
- import path89 from "node:path";
67106
+ import path90 from "node:path";
66978
67107
  async function emitHarnessStateEvent(opts) {
66979
67108
  if (opts.output !== "json") return;
66980
67109
  try {
66981
67110
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.workspaceRoot });
66982
- const state3 = await readHarnessState(path89.join(sessionsDir2, opts.spine.sessionId));
67111
+ const state3 = await readHarnessState(path90.join(sessionsDir2, opts.spine.sessionId));
66983
67112
  opts.emitEvent({ type: "harness_state", ...state3 });
66984
67113
  } catch (err) {
66985
67114
  const msg = err instanceof Error ? err.message : String(err);
@@ -67536,13 +67665,13 @@ var init_verifierLifecycle = __esm({
67536
67665
 
67537
67666
  // src/cli/extensions/sandboxedFs.ts
67538
67667
  import { promises as fsp } from "node:fs";
67539
- import path90 from "node:path";
67668
+ import path91 from "node:path";
67540
67669
  function errText(prefix, p3, err) {
67541
67670
  const msg = err instanceof Error ? err.message : String(err);
67542
67671
  return `[extension-fs] ${prefix} "${p3}": ${msg}`;
67543
67672
  }
67544
67673
  function bindSandboxedFs(root) {
67545
- const resolvedRoot = path90.resolve(root);
67674
+ const resolvedRoot = path91.resolve(root);
67546
67675
  return {
67547
67676
  root: resolvedRoot,
67548
67677
  async readFile(relativePath) {
@@ -67558,7 +67687,7 @@ function bindSandboxedFs(root) {
67558
67687
  try {
67559
67688
  const target = resolveSandboxedPath(relativePath, { root: resolvedRoot });
67560
67689
  verifyContainment(target, { root: resolvedRoot });
67561
- await fsp.mkdir(path90.dirname(target), { recursive: true });
67690
+ await fsp.mkdir(path91.dirname(target), { recursive: true });
67562
67691
  await fsp.writeFile(target, data, "utf8");
67563
67692
  return typedOk({ path: target });
67564
67693
  } catch (err) {
@@ -67743,7 +67872,7 @@ var init_loader = __esm({
67743
67872
 
67744
67873
  // src/cli/headless/runOneTurn.ts
67745
67874
  import { promises as fs44 } from "node:fs";
67746
- import path91 from "node:path";
67875
+ import path92 from "node:path";
67747
67876
  function planModeFromOpts(opts) {
67748
67877
  return (opts.phase ?? "build") === "plan";
67749
67878
  }
@@ -68221,11 +68350,14 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68221
68350
  return null;
68222
68351
  }
68223
68352
  },
68224
- emit: (input) => spine.appendEvent(input)
68353
+ // F3 seam adapter (same as the gate sites below): the core engine reads
68354
+ // the anchor as `out.seq`, while the spine resolves the seq NUMBER. A bare
68355
+ // number here leaves the review evidence unanchored on the spine.
68356
+ emit: async (input) => ({ seq: await spine.appendEvent(input) })
68225
68357
  };
68226
68358
  const strictEnv = strictEnvOverlay(opts);
68227
68359
  if (pass.finalReason === "completed" && pass.exitCode === 0 && isKrakenMode(opts.mode) && (isKrakenSelectionEnabled() || nativePackEnabled()) && !planModeFromOpts(opts)) {
68228
- const strictGate = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd, env: strictEnv });
68360
+ const strictGate = await evaluateStrictBuildGate("build", { emit: async (input) => ({ seq: await spine.appendEvent(input) }), cwd, env: strictEnv });
68229
68361
  await runAdvisoryVerifierReview(strictGate, verifierReviewDeps).catch(() => void 0);
68230
68362
  const gate = strictGate.gate;
68231
68363
  const verificationPayload = strictGateEventPayload(strictGate);
@@ -68235,7 +68367,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68235
68367
  }
68236
68368
  await writeProofSafe(strictGate, { surface: "kraken", sessionId: spine.sessionId }, cwd);
68237
68369
  if (strictGate.blocked) {
68238
- const repairPrompt = buildKrakenRepairPrompt(gate);
68370
+ const repairPrompt = buildKrakenRepairPrompt(gate, repairExcerptsFromEvaluation(strictGate));
68239
68371
  if (opts.output === "json") {
68240
68372
  emitEvent({
68241
68373
  type: "log",
@@ -68260,7 +68392,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68260
68392
  successfulWrites: pass.successfulWrites + repair.successfulWrites,
68261
68393
  emittedWrites: pass.emittedWrites + repair.emittedWrites
68262
68394
  };
68263
- const after = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd, env: strictEnv });
68395
+ const after = await evaluateStrictBuildGate("build", { emit: async (input) => ({ seq: await spine.appendEvent(input) }), cwd, env: strictEnv });
68264
68396
  await runAdvisoryVerifierReview(after, verifierReviewDeps).catch(() => void 0);
68265
68397
  const afterPayload = strictGateEventPayload(after);
68266
68398
  spine.verificationRun(afterPayload);
@@ -68310,7 +68442,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68310
68442
  if (json3) {
68311
68443
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
68312
68444
  else {
68313
- await fs44.mkdir(path91.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
68445
+ await fs44.mkdir(path92.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
68314
68446
  await fs44.writeFile(opts.exportSessionPath, json3, "utf8");
68315
68447
  }
68316
68448
  }
@@ -69359,9 +69491,9 @@ __export(triggerLock_exports, {
69359
69491
  releaseLock: () => releaseLock
69360
69492
  });
69361
69493
  import { promises as fs45 } from "node:fs";
69362
- import * as path92 from "node:path";
69494
+ import * as path93 from "node:path";
69363
69495
  function lockPath(projectRoot) {
69364
- return path92.join(projectRoot, ".zelari", "trigger.lock");
69496
+ return path93.join(projectRoot, ".zelari", "trigger.lock");
69365
69497
  }
69366
69498
  function isPidAlive(pid) {
69367
69499
  try {
@@ -69374,7 +69506,7 @@ function isPidAlive(pid) {
69374
69506
  }
69375
69507
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
69376
69508
  const lp = lockPath(projectRoot);
69377
- const dir = path92.dirname(lp);
69509
+ const dir = path93.dirname(lp);
69378
69510
  await fs45.mkdir(dir, { recursive: true });
69379
69511
  try {
69380
69512
  const raw = await fs45.readFile(lp, "utf8");
@@ -69406,7 +69538,7 @@ var init_triggerLock = __esm({
69406
69538
 
69407
69539
  // src/cli/runHeadless.ts
69408
69540
  import { promises as fs46 } from "node:fs";
69409
- import path93 from "node:path";
69541
+ import path94 from "node:path";
69410
69542
  import { randomUUID as randomUUID10 } from "node:crypto";
69411
69543
  async function runHeadless(opts) {
69412
69544
  resetTaskSpawnCount();
@@ -69650,7 +69782,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
69650
69782
  try {
69651
69783
  let preflightGraph;
69652
69784
  if (opts.runPlan && opts.runPlan.trim() !== "") {
69653
- const planPath = path93.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
69785
+ const planPath = path94.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
69654
69786
  log(`loading pre-flight plan: ${planPath}`);
69655
69787
  let raw;
69656
69788
  try {
@@ -69693,8 +69825,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
69693
69825
  log(formatKrakenGraphAscii2(graph));
69694
69826
  if (opts.planOnly) {
69695
69827
  const planId = randomUUID10();
69696
- const planDir = path93.join(cwd, ".zelari", "radio");
69697
- const planPath = path93.join(planDir, `plan-${planId}.json`);
69828
+ const planDir = path94.join(cwd, ".zelari", "radio");
69829
+ const planPath = path94.join(planDir, `plan-${planId}.json`);
69698
69830
  await fs46.mkdir(planDir, { recursive: true });
69699
69831
  await fs46.writeFile(
69700
69832
  planPath,
@@ -70085,7 +70217,7 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
70085
70217
  if (json3) {
70086
70218
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
70087
70219
  else {
70088
- await fs46.mkdir(path93.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70220
+ await fs46.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70089
70221
  await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
70090
70222
  }
70091
70223
  }
@@ -70508,6 +70640,22 @@ ${ragContext}` : slicePrompt;
70508
70640
  if (missionGate.blocked) {
70509
70641
  exitCode = strictGateExitCode(missionGate);
70510
70642
  spine.missionPhase("verification", "mission-strict-blocked");
70643
+ } else if (
70644
+ // M2.1/R4b: an open strict gate is not enough — the success claim must
70645
+ // be event-backed: zero `verification.evidence` events in the spine
70646
+ // means narration-only done → strict exit code. Same overlay seam as
70647
+ // the gate above (H10-fix1) so --allow-unverified /
70648
+ // ZELARI_ALLOW_UNVERIFIED=1 waives mission-side too. `opts.phase` is
70649
+ // the only phase/mode discriminant on this site: `--phase plan`
70650
+ // missions are design-only (no verification expected), so the gate
70651
+ // applies unconditionally to build-phase claims.
70652
+ opts.phase !== "plan" && missionClaimExitCode(await spine.countVerificationEvidence(), strictEnvOverlay(opts)) !== 0
70653
+ ) {
70654
+ exitCode = STRICT_DONE_EXIT_CODE;
70655
+ spine.missionPhase("verification", "mission-event-back-missing");
70656
+ process.stderr.write(
70657
+ "[zelari-code --headless] mission success claim has zero verification.evidence events (narration-only done) \u2014 exit 4 (waive with --allow-unverified / ZELARI_ALLOW_UNVERIFIED=1)\n"
70658
+ );
70511
70659
  } else {
70512
70660
  exitCode = 0;
70513
70661
  spine.missionPhase("done", "mission-success");
@@ -70541,7 +70689,7 @@ ${ragContext}` : slicePrompt;
70541
70689
  if (json3) {
70542
70690
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
70543
70691
  else {
70544
- await fs46.mkdir(path93.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70692
+ await fs46.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70545
70693
  await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
70546
70694
  }
70547
70695
  }
@@ -71166,7 +71314,7 @@ function upsertSkill(opts) {
71166
71314
  }
71167
71315
  dir = getProjectSkillsDir(root);
71168
71316
  }
71169
- const path100 = skillFilePath(dir, name);
71317
+ const path101 = skillFilePath(dir, name);
71170
71318
  const content = serializeSkillMd({
71171
71319
  name,
71172
71320
  description,
@@ -71175,13 +71323,13 @@ function upsertSkill(opts) {
71175
71323
  tools: opts.tools,
71176
71324
  cost: opts.cost
71177
71325
  });
71178
- const parsed = parseSkillMd(content, path100);
71326
+ const parsed = parseSkillMd(content, path101);
71179
71327
  if (!parsed) {
71180
71328
  return { ok: false, error: "Generated SKILL.md failed validation" };
71181
71329
  }
71182
- mkdirSync23(dirname13(path100), { recursive: true });
71183
- writeFileSync25(path100, content, "utf8");
71184
- return { ok: true, path: path100 };
71330
+ mkdirSync23(dirname13(path101), { recursive: true });
71331
+ writeFileSync25(path101, content, "utf8");
71332
+ return { ok: true, path: path101 };
71185
71333
  }
71186
71334
  function removeSkill(opts) {
71187
71335
  const name = opts.name.trim().toLowerCase();
@@ -71199,8 +71347,8 @@ function removeSkill(opts) {
71199
71347
  dir = getProjectSkillsDir(root);
71200
71348
  }
71201
71349
  const skillDir = join46(dir, name);
71202
- const path100 = skillFilePath(dir, name);
71203
- if (!existsSync59(path100) && !existsSync59(skillDir)) {
71350
+ const path101 = skillFilePath(dir, name);
71351
+ if (!existsSync59(path101) && !existsSync59(skillDir)) {
71204
71352
  return { ok: false, error: `Skill "${name}" not found in ${dir}` };
71205
71353
  }
71206
71354
  try {
@@ -71211,7 +71359,7 @@ function removeSkill(opts) {
71211
71359
  error: err instanceof Error ? err.message : String(err)
71212
71360
  };
71213
71361
  }
71214
- return { ok: true, path: path100 };
71362
+ return { ok: true, path: path101 };
71215
71363
  }
71216
71364
  var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
71217
71365
  var init_skillConfigIo = __esm({
@@ -71332,7 +71480,7 @@ var init_jsonApi = __esm({
71332
71480
  });
71333
71481
 
71334
71482
  // src/cli/memory/mcpAdapter.ts
71335
- import * as path94 from "node:path";
71483
+ import * as path95 from "node:path";
71336
71484
  var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
71337
71485
  var init_mcpAdapter = __esm({
71338
71486
  "src/cli/memory/mcpAdapter.ts"() {
@@ -71502,8 +71650,8 @@ var init_mcpAdapter = __esm({
71502
71650
  this.takeWrite();
71503
71651
  const externalFile = args.source?.file;
71504
71652
  if (externalFile) {
71505
- const normalized = path94.normalize(externalFile);
71506
- if (path94.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path94.sep}`)) {
71653
+ const normalized = path95.normalize(externalFile);
71654
+ if (path95.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path95.sep}`)) {
71507
71655
  throw new Error("source.file must be project-relative and cannot escape the project");
71508
71656
  }
71509
71657
  }
@@ -72030,12 +72178,12 @@ function ensureHome() {
72030
72178
  }
72031
72179
  }
72032
72180
  function loadCompanionConfig() {
72033
- const path100 = getCompanionConfigPath();
72034
- if (!existsSync60(path100)) {
72181
+ const path101 = getCompanionConfigPath();
72182
+ if (!existsSync60(path101)) {
72035
72183
  return { projects: [] };
72036
72184
  }
72037
72185
  try {
72038
- const raw = JSON.parse(readFileSync45(path100, "utf8"));
72186
+ const raw = JSON.parse(readFileSync45(path101, "utf8"));
72039
72187
  const projects = Array.isArray(raw.projects) ? raw.projects.filter(
72040
72188
  (p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
72041
72189
  ).map((p3) => ({
@@ -72073,16 +72221,16 @@ function loadOrCreateToken(explicit) {
72073
72221
  return { token: explicit.trim(), created: false };
72074
72222
  }
72075
72223
  ensureHome();
72076
- const path100 = getCompanionTokenPath();
72077
- if (existsSync60(path100)) {
72078
- const t = readFileSync45(path100, "utf8").trim();
72224
+ const path101 = getCompanionTokenPath();
72225
+ if (existsSync60(path101)) {
72226
+ const t = readFileSync45(path101, "utf8").trim();
72079
72227
  if (t) return { token: t, created: false };
72080
72228
  }
72081
72229
  const token = randomBytes7(24).toString("base64url");
72082
- writeFileSync26(path100, token + "\n", "utf8");
72230
+ writeFileSync26(path101, token + "\n", "utf8");
72083
72231
  try {
72084
72232
  const fs48 = __require("node:fs");
72085
- fs48.chmodSync?.(path100, 384);
72233
+ fs48.chmodSync?.(path101, 384);
72086
72234
  } catch {
72087
72235
  }
72088
72236
  return { token, created: true };
@@ -72107,17 +72255,17 @@ function mergeProjects(cfg, extraPaths) {
72107
72255
  byId.set(p3.id, p3);
72108
72256
  }
72109
72257
  for (const raw of extraPaths) {
72110
- const path100 = raw.trim();
72111
- if (!path100) continue;
72112
- let id3 = slugFromPath(path100);
72258
+ const path101 = raw.trim();
72259
+ if (!path101) continue;
72260
+ let id3 = slugFromPath(path101);
72113
72261
  let n = 2;
72114
- while (byId.has(id3) && byId.get(id3).path !== path100) {
72115
- id3 = `${slugFromPath(path100)}-${n++}`;
72262
+ while (byId.has(id3) && byId.get(id3).path !== path101) {
72263
+ id3 = `${slugFromPath(path101)}-${n++}`;
72116
72264
  }
72117
72265
  byId.set(id3, {
72118
72266
  id: id3,
72119
- name: slugFromPath(path100),
72120
- path: path100
72267
+ name: slugFromPath(path101),
72268
+ path: path101
72121
72269
  });
72122
72270
  }
72123
72271
  return [...byId.values()];
@@ -72360,7 +72508,7 @@ var init_askUserBridge = __esm({
72360
72508
 
72361
72509
  // src/cli/serve/spineLockSweep.ts
72362
72510
  import { promises as fs47 } from "node:fs";
72363
- import path95 from "node:path";
72511
+ import path96 from "node:path";
72364
72512
  async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
72365
72513
  const dir = sessionsDir2 ?? resolveSessionsDir();
72366
72514
  const onSwept = options.onSwept ?? ((sessionId2, reason) => {
@@ -72378,7 +72526,7 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
72378
72526
  return result;
72379
72527
  }
72380
72528
  for (const sessionId2 of entries) {
72381
- const lockPath2 = path95.join(dir, sessionId2, "writer.lock");
72529
+ const lockPath2 = path96.join(dir, sessionId2, "writer.lock");
72382
72530
  try {
72383
72531
  const raw = await fs47.readFile(lockPath2, "utf-8");
72384
72532
  let lockInfo = {};
@@ -73375,9 +73523,9 @@ async function runCompanionServe(opts = {}) {
73375
73523
  return;
73376
73524
  }
73377
73525
  const url2 = parseUrl(req);
73378
- const path100 = url2.pathname.replace(/\/+$/, "") || "/";
73526
+ const path101 = url2.pathname.replace(/\/+$/, "") || "/";
73379
73527
  try {
73380
- if (req.method === "GET" && (path100 === "/health" || path100 === "/v1/health")) {
73528
+ if (req.method === "GET" && (path101 === "/health" || path101 === "/v1/health")) {
73381
73529
  sendJson2(res, 200, {
73382
73530
  ok: true,
73383
73531
  service: "zelari-companion",
@@ -73389,18 +73537,18 @@ async function runCompanionServe(opts = {}) {
73389
73537
  });
73390
73538
  return;
73391
73539
  }
73392
- if (path100.startsWith("/v1")) {
73540
+ if (path101.startsWith("/v1")) {
73393
73541
  if (!tokenMatches(token, getBearer(req))) {
73394
73542
  sendJson2(res, 401, { ok: false, error: "unauthorized" });
73395
73543
  return;
73396
73544
  }
73397
73545
  }
73398
- if (req.method === "GET" && path100 === "/v1/config") {
73546
+ if (req.method === "GET" && path101 === "/v1/config") {
73399
73547
  const snap = buildDesktopConfigSnapshot();
73400
73548
  sendJson2(res, 200, { ok: true, ...snap });
73401
73549
  return;
73402
73550
  }
73403
- if (req.method === "GET" && path100 === "/v1/projects") {
73551
+ if (req.method === "GET" && path101 === "/v1/projects") {
73404
73552
  sendJson2(res, 200, {
73405
73553
  ok: true,
73406
73554
  projects: projects.map((p3) => ({
@@ -73411,7 +73559,7 @@ async function runCompanionServe(opts = {}) {
73411
73559
  });
73412
73560
  return;
73413
73561
  }
73414
- if (req.method === "GET" && path100 === "/v1/runs") {
73562
+ if (req.method === "GET" && path101 === "/v1/runs") {
73415
73563
  sendJson2(res, 200, {
73416
73564
  ok: true,
73417
73565
  active: runs.getActive(),
@@ -73429,7 +73577,7 @@ async function runCompanionServe(opts = {}) {
73429
73577
  });
73430
73578
  return;
73431
73579
  }
73432
- if (req.method === "POST" && path100 === "/v1/runs") {
73580
+ if (req.method === "POST" && path101 === "/v1/runs") {
73433
73581
  const raw = await readBody(req);
73434
73582
  let body = {};
73435
73583
  try {
@@ -73477,7 +73625,7 @@ async function runCompanionServe(opts = {}) {
73477
73625
  });
73478
73626
  return;
73479
73627
  }
73480
- const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path100);
73628
+ const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path101);
73481
73629
  if (req.method === "GET" && eventsMatch) {
73482
73630
  const runId = eventsMatch[1];
73483
73631
  const run = runs.getRun(runId);
@@ -73542,7 +73690,7 @@ async function runCompanionServe(opts = {}) {
73542
73690
  }, 500);
73543
73691
  return;
73544
73692
  }
73545
- const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path100);
73693
+ const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path101);
73546
73694
  if (req.method === "POST" && cancelMatch) {
73547
73695
  const runId = cancelMatch[1];
73548
73696
  const result = runs.cancel(runId);
@@ -73553,7 +73701,7 @@ async function runCompanionServe(opts = {}) {
73553
73701
  sendJson2(res, 200, { ok: true, cancelled: runId });
73554
73702
  return;
73555
73703
  }
73556
- const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path100);
73704
+ const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path101);
73557
73705
  if (req.method === "POST" && steerMatch) {
73558
73706
  const runId = steerMatch[1];
73559
73707
  const raw = await readBody(req);
@@ -73722,11 +73870,11 @@ import { execSync as execSync2 } from "node:child_process";
73722
73870
  import { existsSync as existsSync62, readFileSync as readFileSync46, readlinkSync, statSync as statSync10 } from "node:fs";
73723
73871
  import { createRequire as createRequire3 } from "node:module";
73724
73872
  import { fileURLToPath as fileURLToPath3 } from "node:url";
73725
- import path96 from "node:path";
73873
+ import path97 from "node:path";
73726
73874
  function findPackageRoot(start) {
73727
73875
  let dir = start;
73728
73876
  for (let i = 0; i < 6; i += 1) {
73729
- const candidate = path96.join(dir, "package.json");
73877
+ const candidate = path97.join(dir, "package.json");
73730
73878
  if (existsSync62(candidate)) {
73731
73879
  try {
73732
73880
  const pkg = JSON.parse(readFileSync46(candidate, "utf8"));
@@ -73734,11 +73882,11 @@ function findPackageRoot(start) {
73734
73882
  } catch {
73735
73883
  }
73736
73884
  }
73737
- const parent = path96.dirname(dir);
73885
+ const parent = path97.dirname(dir);
73738
73886
  if (parent === dir) break;
73739
73887
  dir = parent;
73740
73888
  }
73741
- return path96.resolve(__dirname3, "..", "..", "..");
73889
+ return path97.resolve(__dirname3, "..", "..", "..");
73742
73890
  }
73743
73891
  function tryExec(cmd) {
73744
73892
  try {
@@ -73752,7 +73900,7 @@ function tryExec(cmd) {
73752
73900
  }
73753
73901
  function readPackageJson4() {
73754
73902
  try {
73755
- const pkgPath = path96.join(packageRoot, "package.json");
73903
+ const pkgPath = path97.join(packageRoot, "package.json");
73756
73904
  return JSON.parse(readFileSync46(pkgPath, "utf8"));
73757
73905
  } catch {
73758
73906
  return null;
@@ -73764,7 +73912,7 @@ function getGlobalPrefix() {
73764
73912
  return (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || "").trim();
73765
73913
  }
73766
73914
  function isSourceCheckout() {
73767
- return existsSync62(path96.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path96.join(packageRoot, "apps", "desktop", "package.json"));
73915
+ return existsSync62(path97.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path97.join(packageRoot, "apps", "desktop", "package.json"));
73768
73916
  }
73769
73917
  function checkShim(pkgName) {
73770
73918
  const prefix = getGlobalPrefix();
@@ -73773,9 +73921,9 @@ function checkShim(pkgName) {
73773
73921
  }
73774
73922
  const isWin = process.platform === "win32";
73775
73923
  const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
73776
- const shimPath = path96.join(prefix, shimName);
73924
+ const shimPath = path97.join(prefix, shimName);
73777
73925
  if (!existsSync62(shimPath)) {
73778
- const localBin = path96.join(packageRoot, "bin", "zelari-code.js");
73926
+ const localBin = path97.join(packageRoot, "bin", "zelari-code.js");
73779
73927
  if (isSourceCheckout() && existsSync62(localBin)) {
73780
73928
  return WARN(
73781
73929
  `global shim not found at ${shimPath}
@@ -73809,8 +73957,8 @@ function checkShim(pkgName) {
73809
73957
  fix: npm install -g ${pkgName}@latest --force`
73810
73958
  );
73811
73959
  }
73812
- const resolved = path96.resolve(path96.dirname(shimPath), target);
73813
- const expected = path96.join(
73960
+ const resolved = path97.resolve(path97.dirname(shimPath), target);
73961
+ const expected = path97.join(
73814
73962
  prefix,
73815
73963
  "node_modules",
73816
73964
  pkgName,
@@ -73852,7 +74000,7 @@ function checkNode(pkg) {
73852
74000
  return OK(`node ${raw} (engines.node ${enginesNode ?? ">= 20.0.0"})`);
73853
74001
  }
73854
74002
  function checkBundle() {
73855
- const bundle = path96.join(packageRoot, "dist", "cli", "main.bundled.js");
74003
+ const bundle = path97.join(packageRoot, "dist", "cli", "main.bundled.js");
73856
74004
  if (!existsSync62(bundle)) {
73857
74005
  return FAIL(
73858
74006
  `dist/cli/main.bundled.js missing at ${bundle}
@@ -73873,7 +74021,7 @@ function checkRuntimeDeps() {
73873
74021
  const missing = [];
73874
74022
  for (const dep of required2) {
73875
74023
  try {
73876
- const localReq = createRequire3(path96.join(packageRoot, "package.json"));
74024
+ const localReq = createRequire3(path97.join(packageRoot, "package.json"));
73877
74025
  localReq.resolve(dep);
73878
74026
  } catch {
73879
74027
  missing.push(dep);
@@ -74150,7 +74298,7 @@ var init_doctor = __esm({
74150
74298
  init_metrics3();
74151
74299
  init_contextGrowthSummary();
74152
74300
  require3 = createRequire3(import.meta.url);
74153
- __dirname3 = path96.dirname(fileURLToPath3(import.meta.url));
74301
+ __dirname3 = path97.dirname(fileURLToPath3(import.meta.url));
74154
74302
  packageRoot = findPackageRoot(__dirname3);
74155
74303
  OK = (message) => ({
74156
74304
  ok: true,
@@ -74259,7 +74407,7 @@ __export(userSettings_exports, {
74259
74407
  settingsOverrides: () => settingsOverrides
74260
74408
  });
74261
74409
  import { existsSync as existsSync63, readFileSync as readFileSync47 } from "node:fs";
74262
- import path97 from "node:path";
74410
+ import path98 from "node:path";
74263
74411
  function parseBool(raw) {
74264
74412
  const v = raw.trim().toLowerCase();
74265
74413
  if (["1", "true", "yes", "on"].includes(v)) return true;
@@ -74326,8 +74474,8 @@ function envValueFor(key, env) {
74326
74474
  function resolveUserSettings(opts = {}) {
74327
74475
  const cwd = opts.cwd ?? process.cwd();
74328
74476
  const env = opts.env ?? process.env;
74329
- const userPath = path97.join(zelariHome(), SETTINGS_FILE_NAME);
74330
- const projectPath = path97.join(cwd, ".zelari", SETTINGS_FILE_NAME);
74477
+ const userPath = path98.join(zelariHome(), SETTINGS_FILE_NAME);
74478
+ const projectPath = path98.join(cwd, ".zelari", SETTINGS_FILE_NAME);
74331
74479
  const warnings = [];
74332
74480
  const userLayer = loadFileLayer(userPath, "user", warnings);
74333
74481
  const projectLayer = loadFileLayer(projectPath, "project", warnings);
@@ -74541,7 +74689,7 @@ __export(inspectSession_exports, {
74541
74689
  renderInspectReport: () => renderInspectReport,
74542
74690
  runInspectSession: () => runInspectSession
74543
74691
  });
74544
- import path98 from "node:path";
74692
+ import path99 from "node:path";
74545
74693
  import { existsSync as existsSync64 } from "node:fs";
74546
74694
  function formatLimit(limit) {
74547
74695
  return `${Math.round(limit / 1e3)}k`;
@@ -74575,8 +74723,8 @@ function renderInspectReport(state3) {
74575
74723
  }
74576
74724
  async function runInspectSession(opts) {
74577
74725
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.cwd ?? process.cwd() });
74578
- const sessionDir = path98.join(sessionsDir2, opts.sessionId);
74579
- const eventsPath = path98.join(sessionDir, "events.jsonl");
74726
+ const sessionDir = path99.join(sessionsDir2, opts.sessionId);
74727
+ const eventsPath = path99.join(sessionDir, "events.jsonl");
74580
74728
  if (!existsSync64(sessionDir)) {
74581
74729
  console.error(`zelari-code inspect: no session directory at ${sessionDir}`);
74582
74730
  return 1;
@@ -74610,14 +74758,14 @@ __export(inspect_exports, {
74610
74758
  collectInspectReport: () => collectInspectReport,
74611
74759
  runInspect: () => runInspect
74612
74760
  });
74613
- import path99 from "node:path";
74761
+ import path100 from "node:path";
74614
74762
  import { existsSync as existsSync65, readFileSync as readFileSync48, readdirSync as readdirSync13 } from "node:fs";
74615
74763
  async function collectInspectReport(cwd = process.cwd()) {
74616
74764
  ensureBuiltinSkillsLoadedSync();
74617
74765
  const snap = listSkillsSnapshot(cwd);
74618
74766
  const mcp = listMcpServers(cwd);
74619
- const userMcpPath = path99.join(zelariHome(), "mcp.json");
74620
- const projectMcpPath = path99.join(cwd, ".zelari", "mcp.json");
74767
+ const userMcpPath = path100.join(zelariHome(), "mcp.json");
74768
+ const projectMcpPath = path100.join(cwd, ".zelari", "mcp.json");
74621
74769
  const globalHooks = globalHooksDir();
74622
74770
  const projectHooks = projectHooksDir(cwd);
74623
74771
  const projectTrusted = isFolderTrusted(cwd);
@@ -74645,9 +74793,9 @@ async function collectInspectReport(cwd = process.cwd()) {
74645
74793
  configSources: [
74646
74794
  { path: userMcpPath, exists: existsSync65(userMcpPath) },
74647
74795
  { path: projectMcpPath, exists: existsSync65(projectMcpPath) },
74648
- { path: path99.join(zelariHome(), "provider.json"), exists: existsSync65(path99.join(zelariHome(), "provider.json")) },
74649
- { path: path99.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync65(path99.join(cwd, ".zelari", "AGENTS.md")) },
74650
- { path: path99.join(cwd, "AGENTS.md"), exists: existsSync65(path99.join(cwd, "AGENTS.md")) }
74796
+ { path: path100.join(zelariHome(), "provider.json"), exists: existsSync65(path100.join(zelariHome(), "provider.json")) },
74797
+ { path: path100.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync65(path100.join(cwd, ".zelari", "AGENTS.md")) },
74798
+ { path: path100.join(cwd, "AGENTS.md"), exists: existsSync65(path100.join(cwd, "AGENTS.md")) }
74651
74799
  ],
74652
74800
  skills: {
74653
74801
  total: snap.skills.length,
@@ -74687,8 +74835,8 @@ function listJsonFiles(dir) {
74687
74835
  }
74688
74836
  function findAgentsMd(cwd) {
74689
74837
  const candidates = [
74690
- path99.join(cwd, "AGENTS.md"),
74691
- path99.join(cwd, ".zelari", "AGENTS.md")
74838
+ path100.join(cwd, "AGENTS.md"),
74839
+ path100.join(cwd, ".zelari", "AGENTS.md")
74692
74840
  ];
74693
74841
  const found = [];
74694
74842
  for (const c of candidates) {
@@ -78441,7 +78589,10 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
78441
78589
  progressRuntime.observe(event);
78442
78590
  if (event.type === "agent_end") {
78443
78591
  let krakenSuppressFinish = false;
78444
- const krakenSpineEmit = (input) => writerRef.current?.spine?.appendEvent(input) ?? Promise.resolve(null);
78592
+ const krakenSpineEmit = async (input) => {
78593
+ const seq = await (writerRef.current?.spine?.appendEvent(input) ?? Promise.resolve(null));
78594
+ return { seq };
78595
+ };
78445
78596
  const writeProofSafe2 = (gate) => writeCompletionProof(gate, { meta: { surface: "kraken", sessionId: sessionId2 } }).then(
78446
78597
  () => void 0,
78447
78598
  () => void 0
@@ -78455,7 +78606,9 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
78455
78606
  if (krakenGate.blocked) {
78456
78607
  krakenRepairEnqueued = true;
78457
78608
  markRepairTriggered();
78458
- harness2.enqueue(buildKrakenRepairPrompt(krakenGate));
78609
+ harness2.enqueue(
78610
+ buildKrakenRepairPrompt(krakenGate, repairExcerptsFromEvaluation(strictGate))
78611
+ );
78459
78612
  appendSystem(
78460
78613
  setMessages,
78461
78614
  formatStrictBlockExplanation(strictGate),
@@ -79949,10 +80102,10 @@ init_ledger();
79949
80102
 
79950
80103
  // src/cli/evolution/proposals.ts
79951
80104
  import { existsSync as existsSync51, readFileSync as readFileSync39 } from "node:fs";
79952
- import path77 from "node:path";
79953
- var PROPOSALS_REL = path77.join(".zelari", "evolution", "proposals.jsonl");
80105
+ import path78 from "node:path";
80106
+ var PROPOSALS_REL = path78.join(".zelari", "evolution", "proposals.jsonl");
79954
80107
  function proposalsPath(cwd) {
79955
- return path77.join(cwd, PROPOSALS_REL);
80108
+ return path78.join(cwd, PROPOSALS_REL);
79956
80109
  }
79957
80110
  function readProposalStore(cwd) {
79958
80111
  const file2 = proposalsPath(cwd);
@@ -81062,11 +81215,11 @@ function handleCacheStats(ctx) {
81062
81215
  init_messageHelpers();
81063
81216
  init_serviceFactory();
81064
81217
  import { promises as fs35 } from "node:fs";
81065
- import * as path79 from "node:path";
81218
+ import * as path80 from "node:path";
81066
81219
 
81067
81220
  // src/cli/memory/promotion.ts
81068
81221
  import { promises as fs34 } from "node:fs";
81069
- import * as path78 from "node:path";
81222
+ import * as path79 from "node:path";
81070
81223
  var START = "<!-- zelari:memory-promotions:start -->";
81071
81224
  var END = "<!-- zelari:memory-promotions:end -->";
81072
81225
  var DURABLE_KINDS = /* @__PURE__ */ new Set(["fact", "decision", "constraint", "preference", "procedure"]);
@@ -81077,13 +81230,13 @@ function lineFor(node) {
81077
81230
  }
81078
81231
  async function promoteMemoryToAgentsMd(projectRoot, node) {
81079
81232
  if (node.status !== "active") {
81080
- return { added: false, path: path78.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
81233
+ return { added: false, path: path79.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
81081
81234
  }
81082
81235
  if (!DURABLE_KINDS.has(node.kind)) {
81083
- return { added: false, path: path78.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
81236
+ return { added: false, path: path79.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
81084
81237
  }
81085
- const root = await fs34.realpath(projectRoot).catch(() => path78.resolve(projectRoot));
81086
- const target = path78.join(root, "AGENTS.md");
81238
+ const root = await fs34.realpath(projectRoot).catch(() => path79.resolve(projectRoot));
81239
+ const target = path79.join(root, "AGENTS.md");
81087
81240
  try {
81088
81241
  const stat8 = await fs34.lstat(target);
81089
81242
  if (stat8.isSymbolicLink() || !stat8.isFile()) throw new Error("AGENTS.md must be a regular project file.");
@@ -81148,22 +81301,22 @@ function sourceLine(source2) {
81148
81301
  return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
81149
81302
  }
81150
81303
  function isInside(root, target) {
81151
- const relative6 = path79.relative(root, target);
81152
- return relative6 === "" || !relative6.startsWith("..") && !path79.isAbsolute(relative6);
81304
+ const relative6 = path80.relative(root, target);
81305
+ return relative6 === "" || !relative6.startsWith("..") && !path80.isAbsolute(relative6);
81153
81306
  }
81154
81307
  async function safeExportPath(cwd, requested) {
81155
- const lexicalRoot = path79.resolve(cwd);
81308
+ const lexicalRoot = path80.resolve(cwd);
81156
81309
  const root = await fs35.realpath(lexicalRoot).catch(() => lexicalRoot);
81157
- const fallback = path79.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
81158
- const target = requested?.trim() ? path79.resolve(root, requested.trim()) : fallback;
81310
+ const fallback = path80.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
81311
+ const target = requested?.trim() ? path80.resolve(root, requested.trim()) : fallback;
81159
81312
  if (!isInside(root, target)) {
81160
81313
  throw new Error("Export path must stay inside the active project.");
81161
81314
  }
81162
- const parent = path79.dirname(target);
81163
- const relativeParent = path79.relative(root, parent);
81315
+ const parent = path80.dirname(target);
81316
+ const relativeParent = path80.relative(root, parent);
81164
81317
  let cursor = root;
81165
- for (const segment of relativeParent.split(path79.sep).filter(Boolean)) {
81166
- cursor = path79.join(cursor, segment);
81318
+ for (const segment of relativeParent.split(path80.sep).filter(Boolean)) {
81319
+ cursor = path80.join(cursor, segment);
81167
81320
  try {
81168
81321
  const stat8 = await fs35.lstat(cursor);
81169
81322
  if (stat8.isSymbolicLink()) {
@@ -81335,9 +81488,9 @@ ${message}` : message
81335
81488
  }
81336
81489
  case "export": {
81337
81490
  const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
81338
- await fs35.mkdir(path79.dirname(target), { recursive: true });
81339
- const root = await fs35.realpath(ctx.cwd).catch(() => path79.resolve(ctx.cwd));
81340
- const realParent = await fs35.realpath(path79.dirname(target));
81491
+ await fs35.mkdir(path80.dirname(target), { recursive: true });
81492
+ const root = await fs35.realpath(ctx.cwd).catch(() => path80.resolve(ctx.cwd));
81493
+ const realParent = await fs35.realpath(path80.dirname(target));
81341
81494
  if (!isInside(root, realParent)) {
81342
81495
  throw new Error("Export path resolves outside the active project.");
81343
81496
  }
@@ -81552,7 +81705,7 @@ import { promises as fs37 } from "node:fs";
81552
81705
  init_zod();
81553
81706
  init_taskTool();
81554
81707
  import { promises as fs36 } from "node:fs";
81555
- import path80 from "node:path";
81708
+ import path81 from "node:path";
81556
81709
  import { randomBytes as randomBytes6 } from "node:crypto";
81557
81710
  var CsvFanoutArgsSchema = external_exports.object({
81558
81711
  csv_path: external_exports.string().min(1),
@@ -81646,8 +81799,8 @@ function resolveMaxConcurrency(env = process.env) {
81646
81799
  }
81647
81800
  async function runCsvFanout(args, deps, opts) {
81648
81801
  const start = Date.now();
81649
- const absCsv = path80.isAbsolute(args.csv_path) ? args.csv_path : path80.join(opts.parentCwd, args.csv_path);
81650
- const absOut = path80.isAbsolute(args.output_csv_path) ? args.output_csv_path : path80.join(opts.parentCwd, args.output_csv_path);
81802
+ const absCsv = path81.isAbsolute(args.csv_path) ? args.csv_path : path81.join(opts.parentCwd, args.csv_path);
81803
+ const absOut = path81.isAbsolute(args.output_csv_path) ? args.output_csv_path : path81.join(opts.parentCwd, args.output_csv_path);
81651
81804
  const { headers: headers3, rows } = await readCsv(absCsv);
81652
81805
  if (headers3.length === 0) {
81653
81806
  throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
@@ -81703,7 +81856,7 @@ async function runCsvFanout(args, deps, opts) {
81703
81856
  errored += 1;
81704
81857
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
81705
81858
  }
81706
- await fs36.mkdir(path80.dirname(absOut), { recursive: true });
81859
+ await fs36.mkdir(path81.dirname(absOut), { recursive: true });
81707
81860
  await queueWrite(serializeCsv(outHeaders, outputRecords));
81708
81861
  }
81709
81862
  }
@@ -81898,7 +82051,7 @@ function splitArgs(s) {
81898
82051
  // src/cli/slashHandlers/krakenWorkbench.ts
81899
82052
  init_messageHelpers();
81900
82053
  import { promises as fs38 } from "node:fs";
81901
- import path81 from "node:path";
82054
+ import path82 from "node:path";
81902
82055
 
81903
82056
  // src/cli/kraken/workbenchView.ts
81904
82057
  var EMPTY = {
@@ -82015,14 +82168,14 @@ function formatWorkbenchForTerminal(p3) {
82015
82168
 
82016
82169
  // src/cli/slashHandlers/krakenWorkbench.ts
82017
82170
  async function handleKrakenWorkbench(ctx) {
82018
- const dir = path81.join(ctx.cwd, ".zelari", "radio");
82171
+ const dir = path82.join(ctx.cwd, ".zelari", "radio");
82019
82172
  let latest = null;
82020
82173
  let latestMtime = 0;
82021
82174
  try {
82022
82175
  const files = await fs38.readdir(dir);
82023
82176
  for (const f of files) {
82024
82177
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
82025
- const full = path81.join(dir, f);
82178
+ const full = path82.join(dir, f);
82026
82179
  const stat8 = await fs38.stat(full);
82027
82180
  if (stat8.mtimeMs > latestMtime) {
82028
82181
  latestMtime = stat8.mtimeMs;
@@ -82039,10 +82192,10 @@ async function handleKrakenWorkbench(ctx) {
82039
82192
  const parsed = parseWorkbench(content);
82040
82193
  const rendered = formatWorkbenchForTerminal(parsed);
82041
82194
  if (!rendered.trim()) {
82042
- appendSystem(ctx.setMessages, `[kraken workbench] ${path81.basename(latest)}: (no nodes / no events yet)`);
82195
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path82.basename(latest)}: (no nodes / no events yet)`);
82043
82196
  return;
82044
82197
  }
82045
- appendSystem(ctx.setMessages, `[kraken workbench] ${path81.basename(latest)}:
82198
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path82.basename(latest)}:
82046
82199
  ${rendered}`);
82047
82200
  }
82048
82201
 
@@ -82350,14 +82503,14 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
82350
82503
  init_messageHelpers();
82351
82504
  init_paths();
82352
82505
  import { promises as fs39 } from "node:fs";
82353
- import path84 from "node:path";
82506
+ import path85 from "node:path";
82354
82507
  async function handlePromoteMember(ctx, memberId) {
82355
82508
  try {
82356
82509
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
82357
82510
  const { skill, markdown } = promoteMember2(memberId);
82358
82511
  const skillDir = skillsDir();
82359
82512
  await fs39.mkdir(skillDir, { recursive: true });
82360
- const filePath = path84.join(skillDir, `${skill.id}.md`);
82513
+ const filePath = path85.join(skillDir, `${skill.id}.md`);
82361
82514
  const previous = await fs39.readFile(filePath, "utf8").catch(() => null);
82362
82515
  const { createHash: createHash24 } = await import("node:crypto");
82363
82516
  const sha = (s) => createHash24("sha256").update(s, "utf8").digest("hex");
@@ -82383,7 +82536,7 @@ ${lineage}
82383
82536
  // src/cli/branchManager.ts
82384
82537
  init_paths();
82385
82538
  import { promises as fs40, existsSync as existsSync55, readFileSync as readFileSync41, writeFileSync as writeFileSync24, mkdirSync as mkdirSync21, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
82386
- import path85 from "node:path";
82539
+ import path86 from "node:path";
82387
82540
  var META_FILENAME = "meta.json";
82388
82541
  var SESSIONS_SUBDIR = "sessions";
82389
82542
  function getBranchesBaseDir() {
@@ -82393,13 +82546,13 @@ function getSessionsBaseDir() {
82393
82546
  return sessionsDir();
82394
82547
  }
82395
82548
  function branchPathFor(name, baseDir) {
82396
- return path85.join(baseDir, name);
82549
+ return path86.join(baseDir, name);
82397
82550
  }
82398
82551
  function metaPathFor(name, baseDir) {
82399
- return path85.join(baseDir, name, META_FILENAME);
82552
+ return path86.join(baseDir, name, META_FILENAME);
82400
82553
  }
82401
82554
  function sessionsPathFor(name, baseDir) {
82402
- return path85.join(baseDir, name, SESSIONS_SUBDIR);
82555
+ return path86.join(baseDir, name, SESSIONS_SUBDIR);
82403
82556
  }
82404
82557
  function readBranchMeta(name, baseDir) {
82405
82558
  const metaPath = metaPathFor(name, baseDir);
@@ -82424,7 +82577,7 @@ function readBranchMeta(name, baseDir) {
82424
82577
  }
82425
82578
  function writeBranchMeta(name, baseDir, meta3) {
82426
82579
  const metaPath = metaPathFor(name, baseDir);
82427
- mkdirSync21(path85.dirname(metaPath), { recursive: true });
82580
+ mkdirSync21(path86.dirname(metaPath), { recursive: true });
82428
82581
  writeFileSync24(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
82429
82582
  }
82430
82583
  async function countSessions(name, baseDir) {
@@ -82475,14 +82628,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
82475
82628
  if (branchExists(name, baseDir)) {
82476
82629
  throw new BranchAlreadyExistsError(name);
82477
82630
  }
82478
- const sourcePath = path85.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
82631
+ const sourcePath = path86.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
82479
82632
  if (!existsSync55(sourcePath)) {
82480
82633
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
82481
82634
  }
82482
82635
  const branchPath = branchPathFor(name, baseDir);
82483
82636
  const branchSessionsPath = sessionsPathFor(name, baseDir);
82484
82637
  mkdirSync21(branchSessionsPath, { recursive: true });
82485
- const destPath = path85.join(branchSessionsPath, `${fromSessionId}.jsonl`);
82638
+ const destPath = path86.join(branchSessionsPath, `${fromSessionId}.jsonl`);
82486
82639
  await fs40.copyFile(sourcePath, destPath);
82487
82640
  const meta3 = {
82488
82641
  name,
@@ -82586,14 +82739,14 @@ async function handleBranchCheckout(ctx, branchName) {
82586
82739
  // src/cli/slashHandlers/workspace.ts
82587
82740
  init_messageHelpers();
82588
82741
  import { promises as fs41 } from "node:fs";
82589
- import path86 from "node:path";
82742
+ import path87 from "node:path";
82590
82743
  async function handleWorkspaceShow(ctx, what) {
82591
82744
  try {
82592
- const zelari = path86.join(process.cwd(), ".zelari");
82745
+ const zelari = path87.join(process.cwd(), ".zelari");
82593
82746
  let content;
82594
82747
  switch (what) {
82595
82748
  case "plan": {
82596
- const planPath = path86.join(zelari, "plan.md");
82749
+ const planPath = path87.join(zelari, "plan.md");
82597
82750
  try {
82598
82751
  content = await fs41.readFile(planPath, "utf-8");
82599
82752
  } catch {
@@ -82602,7 +82755,7 @@ async function handleWorkspaceShow(ctx, what) {
82602
82755
  break;
82603
82756
  }
82604
82757
  case "decisions": {
82605
- const decisionsDir = path86.join(zelari, "decisions");
82758
+ const decisionsDir = path87.join(zelari, "decisions");
82606
82759
  try {
82607
82760
  const files = (await fs41.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
82608
82761
  if (files.length === 0) {
@@ -82612,7 +82765,7 @@ async function handleWorkspaceShow(ctx, what) {
82612
82765
  `];
82613
82766
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
82614
82767
  for (const f of files) {
82615
- const raw = await fs41.readFile(path86.join(decisionsDir, f), "utf-8");
82768
+ const raw = await fs41.readFile(path87.join(decisionsDir, f), "utf-8");
82616
82769
  const { meta: meta3, body } = parseFrontmatter2(raw);
82617
82770
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
82618
82771
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -82625,7 +82778,7 @@ async function handleWorkspaceShow(ctx, what) {
82625
82778
  break;
82626
82779
  }
82627
82780
  case "risks": {
82628
- const risksPath = path86.join(zelari, "risks.md");
82781
+ const risksPath = path87.join(zelari, "risks.md");
82629
82782
  try {
82630
82783
  content = await fs41.readFile(risksPath, "utf-8");
82631
82784
  } catch {
@@ -82634,7 +82787,7 @@ async function handleWorkspaceShow(ctx, what) {
82634
82787
  break;
82635
82788
  }
82636
82789
  case "agents": {
82637
- const agentsPath = path86.join(process.cwd(), "AGENTS.MD");
82790
+ const agentsPath = path87.join(process.cwd(), "AGENTS.MD");
82638
82791
  try {
82639
82792
  content = await fs41.readFile(agentsPath, "utf-8");
82640
82793
  } catch {
@@ -82643,7 +82796,7 @@ async function handleWorkspaceShow(ctx, what) {
82643
82796
  break;
82644
82797
  }
82645
82798
  case "docs": {
82646
- const docsDir = path86.join(zelari, "docs");
82799
+ const docsDir = path87.join(zelari, "docs");
82647
82800
  try {
82648
82801
  const files = (await fs41.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
82649
82802
  content = files.length ? `# Docs (${files.length})
@@ -82685,7 +82838,7 @@ async function handleWorkspaceReset(ctx, force) {
82685
82838
  return;
82686
82839
  }
82687
82840
  try {
82688
- const target = path86.join(process.cwd(), ".zelari");
82841
+ const target = path87.join(process.cwd(), ".zelari");
82689
82842
  await fs41.rm(target, { recursive: true, force: true });
82690
82843
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
82691
82844
  } catch (err) {
@@ -84569,8 +84722,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
84569
84722
  let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
84570
84723
  if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
84571
84724
  try {
84572
- const path100 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
84573
- name = path100 && /^[a-z0-9]/.test(path100) ? path100 : "imported-skill";
84725
+ const path101 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
84726
+ name = path101 && /^[a-z0-9]/.test(path101) ? path101 : "imported-skill";
84574
84727
  } catch {
84575
84728
  name = "imported-skill";
84576
84729
  }
@@ -84983,7 +85136,7 @@ proposals: npm run evolve:propose \u2014 decisions in npm run evolve:decide (P1:
84983
85136
  }
84984
85137
  if (argv.includes("--help") || argv.includes("-h")) {
84985
85138
  console.log(
84986
- "zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor [--json] Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --inspect [--json] Unified project inspection (config, skills, MCP,\n hooks, plugins, AGENTS.md, trust status)\n --trust [path] Trust the cwd (or path) so project MCP + hooks load\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --fix-budget Set recommended ZELARI_MAX_TOOL_LOOP_HARD=180,\n ZELARI_MAX_TOOL_LOOP_ITERATIONS=60, ZELARI_CONTEXT_LIMIT=400000\n at User scope (prevents the agent stopping mid-task)\n --permission-mcp <socket> MCP stdio server for external agent permission prompts\n (spawned by claude --permission-prompt-tool)\n --memory-mcp Optional MCP stdio server for project memory\n --cwd <path> Trusted project root (requires ZELARI_MEMORY_MCP=1)\n --client-id <id> Stable local owner identity for private memories\n --memory-json <json> Read-only project-memory bridge for Zelari Desktop\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)\n zelari/mission mode auto-scopes slices from open tasks in .zelari/plan.json\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --profile <id> Capability profile (minimal/v1|kraken/v1|council/v1|mission/v1)\n --resume <id> Continue a 2.0 spine session\n --resume-mission Resume .zelari/mission-state.json (not the spine)\n --export-session <path> Write zelari-session-export/1 after the run\n --strict-done Evidence-based BUILD completion gate\n --task-file <path> Read the task prompt from a file (Windows argv cap)\n --once Single-cycle run (cron/git-hook triggers, ADR-0014)\n --kraken-graph <goal> Plan + execute a Kraken task graph\n (variant: --kraken-graph-file <path>; kill-switch\n ZELARI_KRAKEN_GRAPH=0)\n --plan-only Serialize the graph plan to .zelari/radio/ and exit 0\n --run-plan <id> Execute a pre-built .zelari/radio/plan-<id>.json\n --gauntlet Host-driven gauntlet loop (builder/critic tentacles)\n --session-export <id> Print a portable 2.0 session export (no LLM)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --serve-harness Long-lived harness kernel for hosts (NDJSON JSON-RPC\n on stdin/stdout; Desktop/companion transport)\n --print-config Print provider/model config as JSON (no secrets)\n --print-settings Print zelari.config.json values + the origin of\n each (default < user < project < env)\n --permissions <p> Permission preset: strict | standard | yolo \u2014 changes\n category DEFAULTS only (env vars and policy files win)\n --evolve-status Evolution ledger stats (read-only; ADR-0036; the\n ledger is written only when ZELARI_EVOLUTION=shadow)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --thinking <spec> Thinking effort (auto|off|low|medium|high|budget:N)\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --login-oauth Start subscription OAuth (grok, chatgpt, anthropic)\n --provider <id> grok | chatgpt | anthropic\n --code <paste> Anthropic magic-link code (CODE#STATE)\n --no-browser Do not open the system browser\n --refresh-oauth Force-refresh an OAuth access token\n --provider <id> grok | chatgpt | anthropic\n --logout-oauth Clear stored OAuth credentials\n --provider <id> grok | chatgpt | anthropic\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable for stdio servers\n --url <endpoint> Streamable HTTP endpoint (e.g. UE 5.8 editor)\n --args <json> JSON array of args (stdio, optional)\n --timeout <ms> Per-server request timeout (http, optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --preset unreal-mcp Unreal Engine 5.8+ editor (MCP over HTTP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ZELARI_MEMORY_MCP=1 Enable the optional external memory MCP server\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
85139
+ "zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor [--json] Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --inspect [--json] Unified project inspection (config, skills, MCP,\n hooks, plugins, AGENTS.md, trust status)\n --trust [path] Trust the cwd (or path) so project MCP + hooks load\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --fix-budget Set recommended ZELARI_MAX_TOOL_LOOP_HARD=180,\n ZELARI_MAX_TOOL_LOOP_ITERATIONS=60, ZELARI_CONTEXT_LIMIT=400000\n at User scope (prevents the agent stopping mid-task)\n --permission-mcp <socket> MCP stdio server for external agent permission prompts\n (spawned by claude --permission-prompt-tool)\n --memory-mcp Optional MCP stdio server for project memory\n --cwd <path> Trusted project root (requires ZELARI_MEMORY_MCP=1)\n --client-id <id> Stable local owner identity for private memories\n --memory-json <json> Read-only project-memory bridge for Zelari Desktop\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)\n zelari/mission mode auto-scopes slices from open tasks in .zelari/plan.json\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --profile <id> Capability profile (minimal/v1|kraken/v1|council/v1|mission/v1)\n --resume <id> Continue a 2.0 spine session\n --resume-mission Resume .zelari/mission-state.json (not the spine)\n --export-session <path> Write zelari-session-export/1 after the run\n --strict-done Evidence-based BUILD completion gate\n --allow-unverified Exit 0 when strict is ON but nothing could be verified (M1.2)\n --task-file <path> Read the task prompt from a file (Windows argv cap)\n --once Single-cycle run (cron/git-hook triggers, ADR-0014)\n --kraken-graph <goal> Plan + execute a Kraken task graph\n (variant: --kraken-graph-file <path>; kill-switch\n ZELARI_KRAKEN_GRAPH=0)\n --plan-only Serialize the graph plan to .zelari/radio/ and exit 0\n --run-plan <id> Execute a pre-built .zelari/radio/plan-<id>.json\n --gauntlet Host-driven gauntlet loop (builder/critic tentacles)\n --session-export <id> Print a portable 2.0 session export (no LLM)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --serve-harness Long-lived harness kernel for hosts (NDJSON JSON-RPC\n on stdin/stdout; Desktop/companion transport)\n --print-config Print provider/model config as JSON (no secrets)\n --print-settings Print zelari.config.json values + the origin of\n each (default < user < project < env)\n --permissions <p> Permission preset: strict | standard | yolo \u2014 changes\n category DEFAULTS only (env vars and policy files win)\n --evolve-status Evolution ledger stats (read-only; ADR-0036; the\n ledger is written only when ZELARI_EVOLUTION=shadow)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --thinking <spec> Thinking effort (auto|off|low|medium|high|budget:N)\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --login-oauth Start subscription OAuth (grok, chatgpt, anthropic)\n --provider <id> grok | chatgpt | anthropic\n --code <paste> Anthropic magic-link code (CODE#STATE)\n --no-browser Do not open the system browser\n --refresh-oauth Force-refresh an OAuth access token\n --provider <id> grok | chatgpt | anthropic\n --logout-oauth Clear stored OAuth credentials\n --provider <id> grok | chatgpt | anthropic\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable for stdio servers\n --url <endpoint> Streamable HTTP endpoint (e.g. UE 5.8 editor)\n --args <json> JSON array of args (stdio, optional)\n --timeout <ms> Per-server request timeout (http, optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --preset unreal-mcp Unreal Engine 5.8+ editor (MCP over HTTP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ZELARI_MEMORY_MCP=1 Enable the optional external memory MCP server\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
84987
85140
  );
84988
85141
  process.exit(0);
84989
85142
  }