zelari-code 2.37.0 → 2.37.2

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.2";
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");
@@ -48175,6 +48283,7 @@ function frozenProfile(input) {
48175
48283
  Object.freeze(input.buildRecovery);
48176
48284
  Object.freeze(input.sampling);
48177
48285
  Object.freeze(input.compaction);
48286
+ if (input.stream) Object.freeze(input.stream);
48178
48287
  return Object.freeze(input);
48179
48288
  }
48180
48289
  function resolveHarnessProfile(model, providerId) {
@@ -48247,6 +48356,18 @@ var init_capabilities = __esm({
48247
48356
  buildRecovery: { forceToolChoice: true, maxForcedTurns: 1 },
48248
48357
  sampling: { temperature: 0.7 },
48249
48358
  compaction: { ...SHARED_COMPACTION },
48359
+ // Copied from Grok Build (`~/.grok/config.toml` + user-guide):
48360
+ // inference_idle_timeout_secs = 600
48361
+ // max_retries = 8
48362
+ // xAI SDK timeout = 3600s on reasoning models
48363
+ // grok-4.6 xhigh reasons with hidden tokens + SSE keep-alives and no
48364
+ // content for minutes; a 5-min useful-token idle kills BUILD.
48365
+ stream: {
48366
+ idleMs: 6e5,
48367
+ firstTokenIdleMs: 6e5,
48368
+ maxMs: 36e5,
48369
+ maxRetries: 8
48370
+ },
48250
48371
  profile: "grok"
48251
48372
  });
48252
48373
  MINIMAX_M3_CAPS = frozenProfile({
@@ -50871,18 +50992,40 @@ var openai_compatible_exports = {};
50871
50992
  __export(openai_compatible_exports, {
50872
50993
  PROVIDER_CONNECT_TIMEOUT_MS: () => PROVIDER_CONNECT_TIMEOUT_MS,
50873
50994
  PROVIDER_ENDPOINTS: () => PROVIDER_ENDPOINTS,
50995
+ PROVIDER_FIRST_TOKEN_IDLE_MS: () => PROVIDER_FIRST_TOKEN_IDLE_MS,
50874
50996
  PROVIDER_STREAM_IDLE_MS: () => PROVIDER_STREAM_IDLE_MS,
50875
50997
  PROVIDER_STREAM_MAX_MS: () => PROVIDER_STREAM_MAX_MS,
50876
50998
  dataUriFromImage: () => dataUriFromImage,
50999
+ glmModelLooksVision: () => glmModelLooksVision,
51000
+ isGlmCodingEndpoint: () => isGlmCodingEndpoint,
51001
+ isTextOnlyContentRejection: () => isTextOnlyContentRejection,
50877
51002
  modelSupportsVision: () => modelSupportsVision,
50878
51003
  openaiCompatibleProvider: () => openaiCompatibleProvider,
50879
51004
  parseCachedPromptTokens: () => parseCachedPromptTokens,
50880
51005
  providerConfigFor: () => providerConfigFor,
50881
51006
  providerFromEnv: () => providerFromEnv,
50882
51007
  readChunkWithTimeout: () => readChunkWithTimeout,
51008
+ resetTextOnlyVisionMemory: () => resetTextOnlyVisionMemory,
50883
51009
  resolveActiveProvider: () => resolveActiveProvider2,
50884
- resolveBaseUrl: () => resolveBaseUrl
50885
- });
51010
+ resolveBaseUrl: () => resolveBaseUrl,
51011
+ resolveStreamTimeouts: () => resolveStreamTimeouts
51012
+ });
51013
+ function resolveStreamTimeouts(capabilities) {
51014
+ const envIdle = process.env.ZELARI_PROVIDER_STREAM_IDLE_MS ?? process.env.ZELARI_PROVIDER_TIMEOUT_MS;
51015
+ const envFirst = process.env.ZELARI_PROVIDER_FIRST_TOKEN_IDLE_MS;
51016
+ const envMax = process.env.ZELARI_PROVIDER_STREAM_MAX_MS;
51017
+ const envRetries = process.env.ZELARI_PROVIDER_MAX_RETRIES;
51018
+ const idleMs = envIdle ? PROVIDER_STREAM_IDLE_MS : capabilities.stream?.idleMs ?? PROVIDER_STREAM_IDLE_MS;
51019
+ const firstRaw = envFirst ? PROVIDER_FIRST_TOKEN_IDLE_MS : capabilities.stream?.firstTokenIdleMs ?? PROVIDER_FIRST_TOKEN_IDLE_MS;
51020
+ const maxMs = envMax ? PROVIDER_STREAM_MAX_MS : capabilities.stream?.maxMs ?? PROVIDER_STREAM_MAX_MS;
51021
+ const maxRetries = envRetries ? MAX_RETRIES : capabilities.stream?.maxRetries ?? MAX_RETRIES;
51022
+ return {
51023
+ idleMs,
51024
+ firstTokenIdleMs: Math.max(firstRaw, idleMs),
51025
+ maxMs,
51026
+ maxRetries
51027
+ };
51028
+ }
50886
51029
  function abortableSleep(ms, signal) {
50887
51030
  return new Promise((resolve9) => {
50888
51031
  if (signal?.aborted) return resolve9();
@@ -50901,6 +51044,12 @@ function isTimeoutAbortMessage(msg) {
50901
51044
  const m = msg.toLowerCase();
50902
51045
  return m.includes("aborted due to timeout") || m.includes("timeout") || m.includes("the operation was aborted");
50903
51046
  }
51047
+ function formatStreamIdleError(elapsedMs, budgetMs, kind2) {
51048
+ const elapsedS = Math.max(1, Math.round(elapsedMs / 1e3));
51049
+ const budgetS = Math.max(1, Math.round(budgetMs / 1e3));
51050
+ const why = kind2 === "keep-alive" ? "no content tokens \u2014 keep-alive frames don't count" : "no tokens";
51051
+ return `Provider stream idle for ${elapsedS}s of ${budgetS}s (${why}). The model/gateway stalled \u2014 try again or switch model. Override with ZELARI_PROVIDER_STREAM_IDLE_MS or ZELARI_PROVIDER_FIRST_TOKEN_IDLE_MS.`;
51052
+ }
50904
51053
  async function readChunkWithTimeout(reader, opts) {
50905
51054
  if (opts.signal?.aborted) {
50906
51055
  throw new Error("aborted");
@@ -50914,9 +51063,7 @@ async function readChunkWithTimeout(reader, opts) {
50914
51063
  }
50915
51064
  const idleElapsed = now - opts.lastUsefulAt();
50916
51065
  if (idleElapsed >= opts.idleMs) {
50917
- throw new Error(
50918
- `Provider stream idle for ${Math.round(idleElapsed / 1e3)}s (no content tokens \u2014 keep-alive frames don't count). The model/gateway stalled \u2014 try again or switch model. Override with ZELARI_PROVIDER_STREAM_IDLE_MS.`
50919
- );
51066
+ throw new Error(formatStreamIdleError(idleElapsed, opts.idleMs, "keep-alive"));
50920
51067
  }
50921
51068
  const waitMs = Math.min(opts.idleMs - idleElapsed, remaining);
50922
51069
  let idleTimer;
@@ -50926,11 +51073,8 @@ async function readChunkWithTimeout(reader, opts) {
50926
51073
  reader.read(),
50927
51074
  new Promise((_, reject) => {
50928
51075
  idleTimer = setTimeout(() => {
50929
- reject(
50930
- new Error(
50931
- `Provider stream idle for ${Math.round(waitMs / 1e3)}s (no tokens). The model/gateway stalled \u2014 try again or switch model. Override with ZELARI_PROVIDER_STREAM_IDLE_MS.`
50932
- )
50933
- );
51076
+ const elapsed = Date.now() - opts.lastUsefulAt();
51077
+ reject(new Error(formatStreamIdleError(elapsed, opts.idleMs, "silence")));
50934
51078
  }, waitMs);
50935
51079
  if (opts.signal) {
50936
51080
  onAbort = () => reject(new Error("aborted"));
@@ -50952,9 +51096,52 @@ function backoffDelay(attempt, retryAfterHeader) {
50952
51096
  }
50953
51097
  return Math.min(BACKOFF_BASE_MS * 2 ** attempt, BACKOFF_CAP_MS);
50954
51098
  }
50955
- function modelSupportsVision(_model) {
50956
- const force = process.env.ZELARI_VISION;
50957
- return !(force === "0" || force === "false" || force === "off");
51099
+ function visionMemoryKey(model, probe) {
51100
+ return `${probe?.providerId ?? ""}::${model}::${probe?.baseUrl ?? ""}`;
51101
+ }
51102
+ function resetTextOnlyVisionMemory() {
51103
+ textOnlyVisionMemory.clear();
51104
+ }
51105
+ function isGlmCodingEndpoint(baseUrl) {
51106
+ if (!baseUrl) return false;
51107
+ return /\/coding(\/|$)/i.test(baseUrl);
51108
+ }
51109
+ function glmModelLooksVision(model) {
51110
+ const n = model.trim().toLowerCase();
51111
+ if (!n) return false;
51112
+ if (/(?:^|[-_/.])(?:vl|vision)(?:[-_/.]|$)/.test(n)) return true;
51113
+ return /^glm[-_.]?[\w.]*v(?:-|$)/.test(n);
51114
+ }
51115
+ function glmModelIsTextOnly(model) {
51116
+ const n = model.trim().toLowerCase();
51117
+ if (!n.startsWith("glm")) return false;
51118
+ return !glmModelLooksVision(n);
51119
+ }
51120
+ function isTextOnlyContentRejection(status, body) {
51121
+ if (status !== 400) return false;
51122
+ if (!/messages\.content\.type/i.test(body)) return false;
51123
+ return /allowed values/i.test(body) || /\[\s*['"]text['"]\s*\]/.test(body) || /取值范围/.test(body) || /is invalid/i.test(body);
51124
+ }
51125
+ function messagesHaveImageUrl(messages) {
51126
+ for (const m of messages) {
51127
+ const content = m.content;
51128
+ if (!Array.isArray(content)) continue;
51129
+ for (const part of content) {
51130
+ if (part && typeof part === "object" && part.type === "image_url") {
51131
+ return true;
51132
+ }
51133
+ }
51134
+ }
51135
+ return false;
51136
+ }
51137
+ function modelSupportsVision(model, probe) {
51138
+ const force = (process.env.ZELARI_VISION ?? "").trim().toLowerCase();
51139
+ if (force === "0" || force === "false" || force === "off") return false;
51140
+ if (force === "1" || force === "true" || force === "on") return true;
51141
+ if (textOnlyVisionMemory.has(visionMemoryKey(model, probe))) return false;
51142
+ if (isGlmCodingEndpoint(probe?.baseUrl)) return false;
51143
+ if (glmModelIsTextOnly(model)) return false;
51144
+ return true;
50958
51145
  }
50959
51146
  function dataUriFromImage(img) {
50960
51147
  return `data:${img.mime};base64,${img.dataBase64}`;
@@ -51074,29 +51261,38 @@ function positiveEnvInt(name) {
51074
51261
  function openaiCompatibleProvider(config2) {
51075
51262
  return async function* (params) {
51076
51263
  const capabilities = capabilitiesFor(params.model, config2.providerId);
51077
- const vision = modelSupportsVision(params.model);
51264
+ const streamTimeouts = resolveStreamTimeouts(capabilities);
51265
+ const visionProbe = {
51266
+ providerId: config2.providerId,
51267
+ baseUrl: config2.baseUrl
51268
+ };
51269
+ let vision = modelSupportsVision(params.model, visionProbe);
51078
51270
  const msgsIn = params.messages;
51079
- let toolRunImages = [];
51080
- const messages = msgsIn.flatMap((m, i) => {
51081
- const cacheable = !(m.role === "user" && m.images && m.images.length > 0);
51082
- if (cacheable) {
51083
- const cached2 = messageMappingCache.get(m);
51084
- if (cached2) return [cached2];
51085
- }
51086
- const mapped = mapAgentMessage(m, vision);
51087
- if (cacheable) messageMappingCache.set(m, mapped);
51088
- if (m.role === "tool") {
51089
- if (m.images && m.images.length > 0) toolRunImages.push(...m.images);
51090
- const next = msgsIn[i + 1];
51091
- const runEnds = !next || next.role !== "tool";
51092
- if (runEnds && vision && toolRunImages.length > 0) {
51093
- const followUp = imagesFollowUpMessage(toolRunImages);
51094
- toolRunImages = [];
51095
- return [mapped, followUp];
51096
- }
51097
- }
51098
- return [mapped];
51099
- });
51271
+ const wireMessages = (visionFlag) => {
51272
+ let toolRunImages = [];
51273
+ return msgsIn.flatMap((m, i) => {
51274
+ const cacheable = visionFlag && !(m.role === "user" && m.images && m.images.length > 0);
51275
+ if (cacheable) {
51276
+ const cached2 = messageMappingCache.get(m);
51277
+ if (cached2) return [cached2];
51278
+ }
51279
+ const mapped = mapAgentMessage(m, visionFlag);
51280
+ if (cacheable) messageMappingCache.set(m, mapped);
51281
+ if (m.role === "tool") {
51282
+ if (m.images && m.images.length > 0) toolRunImages.push(...m.images);
51283
+ const next = msgsIn[i + 1];
51284
+ const runEnds = !next || next.role !== "tool";
51285
+ if (runEnds && visionFlag && toolRunImages.length > 0) {
51286
+ const followUp = imagesFollowUpMessage(toolRunImages);
51287
+ toolRunImages = [];
51288
+ return [mapped, followUp];
51289
+ }
51290
+ if (runEnds) toolRunImages = [];
51291
+ }
51292
+ return [mapped];
51293
+ });
51294
+ };
51295
+ let messages = wireMessages(vision);
51100
51296
  const generation = params.generation;
51101
51297
  const body = {
51102
51298
  // Use `params.model` (per-call override from AgentHarness, e.g. for
@@ -51146,6 +51342,7 @@ function openaiCompatibleProvider(config2) {
51146
51342
  const recoveryAttempt = generation?.recoveryAttempt ?? 1;
51147
51343
  const forceRecoveryTool = generation?.toolChoice === "required" && capabilities.buildRecovery.forceToolChoice && recoveryAttempt <= capabilities.buildRecovery.maxForcedTurns;
51148
51344
  body.tool_choice = forceRecoveryTool ? "required" : "auto";
51345
+ if (config2.providerId === "glm") body.tool_stream = true;
51149
51346
  }
51150
51347
  const headers3 = {
51151
51348
  "Content-Type": "application/json",
@@ -51160,7 +51357,7 @@ function openaiCompatibleProvider(config2) {
51160
51357
  let response;
51161
51358
  let lastErrText = "";
51162
51359
  let lastStatus = 0;
51163
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt += 1) {
51360
+ for (let attempt = 0; attempt <= streamTimeouts.maxRetries; attempt += 1) {
51164
51361
  if (params.signal?.aborted) {
51165
51362
  yield { kind: "error", message: "aborted" };
51166
51363
  return;
@@ -51201,7 +51398,7 @@ function openaiCompatibleProvider(config2) {
51201
51398
  yield { kind: "error", message: "aborted" };
51202
51399
  return;
51203
51400
  }
51204
- const maxAttempts = isTimeoutAbortMessage(lastErrText) ? Math.min(1, MAX_RETRIES) : MAX_RETRIES;
51401
+ const maxAttempts = isTimeoutAbortMessage(lastErrText) ? Math.min(1, streamTimeouts.maxRetries) : streamTimeouts.maxRetries;
51205
51402
  if (attempt < maxAttempts) {
51206
51403
  await abortableSleep(backoffDelay(attempt, null), params.signal);
51207
51404
  continue;
@@ -51212,7 +51409,14 @@ function openaiCompatibleProvider(config2) {
51212
51409
  if (response.ok && response.body) break;
51213
51410
  lastStatus = response.status;
51214
51411
  lastErrText = await response.text().catch(() => "");
51215
- if (!RETRYABLE_STATUSES.has(response.status) || attempt >= MAX_RETRIES) break;
51412
+ if (vision && isTextOnlyContentRejection(lastStatus, lastErrText) && messagesHaveImageUrl(messages)) {
51413
+ textOnlyVisionMemory.add(visionMemoryKey(params.model, visionProbe));
51414
+ vision = false;
51415
+ messages = wireMessages(false);
51416
+ body.messages = messages;
51417
+ continue;
51418
+ }
51419
+ if (!RETRYABLE_STATUSES.has(response.status) || attempt >= streamTimeouts.maxRetries) break;
51216
51420
  const retryAfter = response.headers.get("retry-after");
51217
51421
  await abortableSleep(backoffDelay(attempt, retryAfter), params.signal);
51218
51422
  }
@@ -51258,17 +51462,19 @@ function openaiCompatibleProvider(config2) {
51258
51462
  }
51259
51463
  toolCallAccumulator.clear();
51260
51464
  };
51261
- const streamDeadline = Date.now() + PROVIDER_STREAM_MAX_MS;
51465
+ const streamDeadline = Date.now() + streamTimeouts.maxMs;
51262
51466
  let lastUsefulAt = Date.now();
51467
+ let emittedUseful = false;
51263
51468
  const markUseful = () => {
51264
51469
  lastUsefulAt = Date.now();
51470
+ emittedUseful = true;
51265
51471
  };
51266
51472
  try {
51267
51473
  while (true) {
51268
51474
  let chunk;
51269
51475
  try {
51270
51476
  chunk = await readChunkWithTimeout(reader, {
51271
- idleMs: PROVIDER_STREAM_IDLE_MS,
51477
+ idleMs: emittedUseful ? streamTimeouts.idleMs : streamTimeouts.firstTokenIdleMs,
51272
51478
  deadlineMs: streamDeadline,
51273
51479
  signal: params.signal,
51274
51480
  lastUsefulAt: () => lastUsefulAt
@@ -51323,17 +51529,33 @@ function openaiCompatibleProvider(config2) {
51323
51529
  }
51324
51530
  };
51325
51531
  }
51326
- if (typeof delta?.content === "string" && delta.content.length > 0) {
51532
+ const content = delta?.content;
51533
+ if (typeof content === "string" && content.length > 0) {
51327
51534
  markUseful();
51328
- yield { kind: "text", delta: delta.content };
51535
+ yield { kind: "text", delta: content };
51536
+ } else if (Array.isArray(content)) {
51537
+ for (const part of content) {
51538
+ if (!part || typeof part !== "object") continue;
51539
+ const p3 = part;
51540
+ const text = typeof p3.text === "string" ? p3.text : "";
51541
+ if (!text) continue;
51542
+ markUseful();
51543
+ const partType = typeof p3.type === "string" ? p3.type : "text";
51544
+ yield {
51545
+ kind: partType === "reasoning" || partType === "thinking" ? "thinking" : "text",
51546
+ delta: text
51547
+ };
51548
+ }
51329
51549
  }
51330
- const reasoning = delta?.reasoning_content ?? delta?.reasoning;
51331
- if (typeof reasoning === "string" && reasoning.length > 0) {
51550
+ const reasoningRaw = delta?.reasoning_content ?? delta?.reasoning ?? delta?.thinking;
51551
+ const reasoning = typeof reasoningRaw === "string" ? reasoningRaw : reasoningRaw && typeof reasoningRaw === "object" && typeof reasoningRaw.text === "string" ? reasoningRaw.text : reasoningRaw && typeof reasoningRaw === "object" && typeof reasoningRaw.content === "string" ? reasoningRaw.content : "";
51552
+ if (reasoning.length > 0) {
51332
51553
  markUseful();
51333
51554
  yield { kind: "thinking", delta: reasoning };
51334
51555
  }
51335
51556
  const details = delta?.reasoning_details;
51336
- if (Array.isArray(details)) {
51557
+ if (Array.isArray(details) && details.length > 0) {
51558
+ markUseful();
51337
51559
  for (const d of details) {
51338
51560
  if (!d || typeof d !== "object") continue;
51339
51561
  const t = d.text;
@@ -51353,6 +51575,7 @@ function openaiCompatibleProvider(config2) {
51353
51575
  }
51354
51576
  }
51355
51577
  if (Array.isArray(delta?.tool_calls)) {
51578
+ markUseful();
51356
51579
  for (const tc of delta.tool_calls) {
51357
51580
  const idx = tc.index ?? 0;
51358
51581
  const existing = toolCallAccumulator.get(idx) ?? {
@@ -51419,7 +51642,7 @@ async function providerConfigFor(providerId) {
51419
51642
  ...extraFromStored(providerId)
51420
51643
  };
51421
51644
  }
51422
- var RETRYABLE_STATUSES, MAX_RETRIES, BACKOFF_BASE_MS, BACKOFF_CAP_MS, PROVIDER_CONNECT_TIMEOUT_MS, PROVIDER_STREAM_IDLE_MS, PROVIDER_STREAM_MAX_MS, PROVIDER_ENDPOINTS, messageMappingCache;
51645
+ var RETRYABLE_STATUSES, MAX_RETRIES, BACKOFF_BASE_MS, BACKOFF_CAP_MS, PROVIDER_CONNECT_TIMEOUT_MS, PROVIDER_STREAM_IDLE_MS, PROVIDER_FIRST_TOKEN_IDLE_MS, PROVIDER_STREAM_MAX_MS, textOnlyVisionMemory, PROVIDER_ENDPOINTS, messageMappingCache;
51423
51646
  var init_openai_compatible = __esm({
51424
51647
  "src/cli/provider/openai-compatible.ts"() {
51425
51648
  "use strict";
@@ -51445,11 +51668,17 @@ var init_openai_compatible = __esm({
51445
51668
  const n = raw ? Number.parseInt(raw, 10) : 3e5;
51446
51669
  return Number.isFinite(n) && n >= 15e3 ? n : 3e5;
51447
51670
  })();
51671
+ PROVIDER_FIRST_TOKEN_IDLE_MS = (() => {
51672
+ const raw = process.env.ZELARI_PROVIDER_FIRST_TOKEN_IDLE_MS;
51673
+ const n = raw ? Number.parseInt(raw, 10) : 6e5;
51674
+ return Number.isFinite(n) && n >= 15e3 ? n : 6e5;
51675
+ })();
51448
51676
  PROVIDER_STREAM_MAX_MS = (() => {
51449
51677
  const raw = process.env.ZELARI_PROVIDER_STREAM_MAX_MS;
51450
51678
  const n = raw ? Number.parseInt(raw, 10) : 18e5;
51451
51679
  return Number.isFinite(n) && n >= 6e4 ? n : 18e5;
51452
51680
  })();
51681
+ textOnlyVisionMemory = /* @__PURE__ */ new Set();
51453
51682
  PROVIDER_ENDPOINTS = {
51454
51683
  "openai-compatible": "https://api.x.ai/v1",
51455
51684
  "minimax": "https://api.minimax.io/v1",
@@ -52074,21 +52303,21 @@ function normalizeAuth(auth) {
52074
52303
  return "agent";
52075
52304
  }
52076
52305
  function readSecrets() {
52077
- const path100 = getSshSecretsPath();
52078
- if (!existsSync30(path100)) return {};
52306
+ const path101 = getSshSecretsPath();
52307
+ if (!existsSync30(path101)) return {};
52079
52308
  try {
52080
- return JSON.parse(readFileSync22(path100, "utf8"));
52309
+ return JSON.parse(readFileSync22(path101, "utf8"));
52081
52310
  } catch {
52082
52311
  return {};
52083
52312
  }
52084
52313
  }
52085
52314
  function writeSecrets(data) {
52086
- const path100 = getSshSecretsPath();
52087
- mkdirSync13(dirname4(path100), { recursive: true });
52088
- writeFileSync16(path100, `${JSON.stringify(data, null, 2)}
52315
+ const path101 = getSshSecretsPath();
52316
+ mkdirSync13(dirname4(path101), { recursive: true });
52317
+ writeFileSync16(path101, `${JSON.stringify(data, null, 2)}
52089
52318
  `, "utf8");
52090
52319
  try {
52091
- chmodSync(path100, 384);
52320
+ chmodSync(path101, 384);
52092
52321
  } catch {
52093
52322
  }
52094
52323
  }
@@ -52117,10 +52346,10 @@ function deleteSshPassword(id3) {
52117
52346
  writeSecrets({ passwords });
52118
52347
  }
52119
52348
  function readStore2() {
52120
- const path100 = getSshTargetsPath();
52121
- if (!existsSync30(path100)) return [];
52349
+ const path101 = getSshTargetsPath();
52350
+ if (!existsSync30(path101)) return [];
52122
52351
  try {
52123
- const parsed = JSON.parse(readFileSync22(path100, "utf8"));
52352
+ const parsed = JSON.parse(readFileSync22(path101, "utf8"));
52124
52353
  const list = Array.isArray(parsed.targets) ? parsed.targets : [];
52125
52354
  return list.filter(
52126
52355
  (t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
@@ -52135,11 +52364,11 @@ function readStore2() {
52135
52364
  }
52136
52365
  }
52137
52366
  function writeStore2(targets) {
52138
- const path100 = getSshTargetsPath();
52139
- mkdirSync13(dirname4(path100), { recursive: true });
52367
+ const path101 = getSshTargetsPath();
52368
+ mkdirSync13(dirname4(path101), { recursive: true });
52140
52369
  const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
52141
52370
  writeFileSync16(
52142
- path100,
52371
+ path101,
52143
52372
  `${JSON.stringify({ targets: clean }, null, 2)}
52144
52373
  `,
52145
52374
  "utf8"
@@ -52385,11 +52614,11 @@ function formatSshTargetsForPrompt() {
52385
52614
  ];
52386
52615
  for (const t of targets) {
52387
52616
  const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
52388
- const path100 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
52617
+ const path101 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
52389
52618
  const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
52390
52619
  const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
52391
52620
  lines.push(
52392
- `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path100}${tags}${allow}`
52621
+ `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path101}${tags}${allow}`
52393
52622
  );
52394
52623
  }
52395
52624
  return lines.join("\n");
@@ -57289,6 +57518,8 @@ function parseHeadlessFlags(argv) {
57289
57518
  missionStrict = true;
57290
57519
  } else if (arg === "--no-mission-strict") {
57291
57520
  missionStrict = false;
57521
+ } else if (arg === "--allow-unverified") {
57522
+ process.env.ZELARI_ALLOW_UNVERIFIED = "1";
57292
57523
  } else if (arg === "--kraken-graph") {
57293
57524
  krakenGraph = argv[i + 1];
57294
57525
  i++;
@@ -57402,6 +57633,7 @@ __export(headlessSpine_exports, {
57402
57633
  seedHeadlessModelHistory: () => seedHeadlessModelHistory,
57403
57634
  sessionStartedEvent: () => sessionStartedEvent
57404
57635
  });
57636
+ import path67 from "node:path";
57405
57637
  function sessionStartedEvent(handle) {
57406
57638
  return {
57407
57639
  type: "session_started",
@@ -57413,6 +57645,20 @@ function resolveHeadlessProfileId(mode, explicit) {
57413
57645
  if (explicit) return resolveProfile(explicit).id;
57414
57646
  return defaultProfileForMode(mode ?? "kraken");
57415
57647
  }
57648
+ async function countVerificationEvidenceInLog(mirror, sessionId2) {
57649
+ if (mirror.status !== "active" && mirror.status !== "closed") return -1;
57650
+ try {
57651
+ await mirror.flush().catch(() => void 0);
57652
+ const report = await readSessionLog(path67.join(mirror.sessionsDir, sessionId2, "events.jsonl"));
57653
+ return report.events.filter((e) => e.kind === "verification.evidence").length;
57654
+ } catch (err) {
57655
+ process.stderr.write(
57656
+ `[zelari-code] verification-evidence count unavailable (${err instanceof Error ? err.message : String(err)}) \u2014 event-back gate skipped
57657
+ `
57658
+ );
57659
+ return -1;
57660
+ }
57661
+ }
57416
57662
  async function openHeadlessSpine(opts) {
57417
57663
  const profileId = resolveHeadlessProfileId(opts.mode, opts.profile);
57418
57664
  let profileTools = [];
@@ -57484,6 +57730,9 @@ async function openHeadlessSpine(opts) {
57484
57730
  lastVerificationRun() {
57485
57731
  return spine.lastVerificationRun();
57486
57732
  },
57733
+ countVerificationEvidence() {
57734
+ return countVerificationEvidenceInLog(spine, opts.sessionId);
57735
+ },
57487
57736
  missionPhase(phase2, note) {
57488
57737
  spine.missionPhase(phase2, note);
57489
57738
  },
@@ -57591,6 +57840,7 @@ var init_headlessSpine = __esm({
57591
57840
  init_dist();
57592
57841
  init_session();
57593
57842
  init_mission2();
57843
+ init_session();
57594
57844
  init_runtime();
57595
57845
  init_sessionSpine();
57596
57846
  init_budgetRuntime();
@@ -58194,7 +58444,7 @@ var init_planDetect = __esm({
58194
58444
  // src/cli/memory/legacyImport.ts
58195
58445
  import { createHash as createHash18 } from "node:crypto";
58196
58446
  import { promises as fs27 } from "node:fs";
58197
- import * as path67 from "node:path";
58447
+ import * as path68 from "node:path";
58198
58448
  function sourceId(fact, line) {
58199
58449
  return `jsonl:${fact.id ?? createHash18("sha256").update(line).digest("hex")}`;
58200
58450
  }
@@ -58212,7 +58462,7 @@ function timestamp(value) {
58212
58462
  }
58213
58463
  async function importLegacyMemoryLog(backend, service) {
58214
58464
  const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
58215
- const logPath = path67.join(path67.dirname(backend.databasePath), "log.jsonl");
58465
+ const logPath = path68.join(path68.dirname(backend.databasePath), "log.jsonl");
58216
58466
  let raw;
58217
58467
  try {
58218
58468
  raw = await fs27.readFile(logPath, "utf8");
@@ -58395,7 +58645,7 @@ var init_sqliteCodec = __esm({
58395
58645
  // src/cli/memory/sqliteRpc.ts
58396
58646
  import { existsSync as existsSync36 } from "node:fs";
58397
58647
  import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
58398
- import * as path68 from "node:path";
58648
+ import * as path69 from "node:path";
58399
58649
  import { Worker } from "node:worker_threads";
58400
58650
  function isBusy(error51) {
58401
58651
  const candidate = error51;
@@ -58404,10 +58654,10 @@ function isBusy(error51) {
58404
58654
  );
58405
58655
  }
58406
58656
  function resolveWorkerUrl() {
58407
- const here = path68.dirname(fileURLToPath2(import.meta.url));
58408
- const direct = path68.join(here, "sqliteWorker.mjs");
58657
+ const here = path69.dirname(fileURLToPath2(import.meta.url));
58658
+ const direct = path69.join(here, "sqliteWorker.mjs");
58409
58659
  if (existsSync36(direct)) return pathToFileURL2(direct);
58410
- return pathToFileURL2(path68.join(here, "memory", "sqliteWorker.mjs"));
58660
+ return pathToFileURL2(path69.join(here, "memory", "sqliteWorker.mjs"));
58411
58661
  }
58412
58662
  var SqliteWorkerRpc;
58413
58663
  var init_sqliteRpc = __esm({
@@ -58696,7 +58946,7 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
58696
58946
  // src/cli/memory/sqliteBackend.ts
58697
58947
  import { createHash as createHash19, randomUUID as randomUUID6 } from "node:crypto";
58698
58948
  import { promises as fs28 } from "node:fs";
58699
- import * as path69 from "node:path";
58949
+ import * as path70 from "node:path";
58700
58950
  function boundedLimit(value, fallback = 50) {
58701
58951
  return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
58702
58952
  }
@@ -58758,16 +59008,16 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
58758
59008
  try {
58759
59009
  resolved = await fs28.realpath(projectRoot);
58760
59010
  } catch {
58761
- resolved = path69.resolve(projectRoot);
59011
+ resolved = path70.resolve(projectRoot);
58762
59012
  }
58763
59013
  if (this.initialized && resolved === this.projectRoot) return;
58764
59014
  if (this.initialized) await this.close();
58765
59015
  const filename = this.options.filename ?? "memory.db";
58766
- if (path69.basename(filename) !== filename || filename === "." || filename === "..") {
59016
+ if (path70.basename(filename) !== filename || filename === "." || filename === "..") {
58767
59017
  throw new Error("SQLite memory filename must not contain a path.");
58768
59018
  }
58769
- const zelariDirectory = path69.join(resolved, ".zelari");
58770
- const directory = path69.join(zelariDirectory, "memory");
59019
+ const zelariDirectory = path70.join(resolved, ".zelari");
59020
+ const directory = path70.join(zelariDirectory, "memory");
58771
59021
  for (const candidate of [zelariDirectory, directory]) {
58772
59022
  let stat8;
58773
59023
  try {
@@ -58786,12 +59036,12 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
58786
59036
  }
58787
59037
  }
58788
59038
  const canonicalDirectory = await fs28.realpath(directory);
58789
- const relativeDirectory = path69.relative(resolved, canonicalDirectory);
58790
- if (relativeDirectory.startsWith("..") || path69.isAbsolute(relativeDirectory)) {
59039
+ const relativeDirectory = path70.relative(resolved, canonicalDirectory);
59040
+ if (relativeDirectory.startsWith("..") || path70.isAbsolute(relativeDirectory)) {
58791
59041
  throw new Error("SQLite memory directory resolves outside the active project.");
58792
59042
  }
58793
59043
  this.projectRoot = resolved;
58794
- this.databasePath = path69.join(canonicalDirectory, filename);
59044
+ this.databasePath = path70.join(canonicalDirectory, filename);
58795
59045
  const opened = await this.rpc.open({
58796
59046
  dbPath: this.databasePath,
58797
59047
  schemaSql: SQLITE_MEMORY_BASE_SCHEMA,
@@ -59324,7 +59574,7 @@ __export(serviceFactory_exports, {
59324
59574
  });
59325
59575
  import { createHash as createHash20 } from "node:crypto";
59326
59576
  import { promises as fs29 } from "node:fs";
59327
- import * as path70 from "node:path";
59577
+ import * as path71 from "node:path";
59328
59578
  function isMemoryV2Enabled(env = process.env) {
59329
59579
  if (env.ZELARI_MEMORY === "0") return false;
59330
59580
  if (env.ZELARI_MEMORY_BACKEND === "file" || env.ZELARI_MEMORY_BACKEND === "jsonl") return false;
@@ -59345,7 +59595,7 @@ async function canonicalProjectId(projectRoot) {
59345
59595
  try {
59346
59596
  canonical = await fs29.realpath(projectRoot);
59347
59597
  } catch {
59348
- canonical = path70.resolve(projectRoot);
59598
+ canonical = path71.resolve(projectRoot);
59349
59599
  }
59350
59600
  canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
59351
59601
  if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
@@ -60047,8 +60297,8 @@ function readPlan(ctx) {
60047
60297
  } catch {
60048
60298
  }
60049
60299
  }
60050
- const path100 = workspaceFile(ctx.rootDir, "plan");
60051
- const doc = ctx.storage.readIfExists(path100);
60300
+ const path101 = workspaceFile(ctx.rootDir, "plan");
60301
+ const doc = ctx.storage.readIfExists(path101);
60052
60302
  if (!doc) return { phases: [], tasks: [], milestones: [] };
60053
60303
  const meta3 = doc.meta;
60054
60304
  return {
@@ -60229,7 +60479,7 @@ function addMilestoneRecord(ctx, summary, input) {
60229
60479
  dueDate: input.dueDate,
60230
60480
  targetVersion: version2
60231
60481
  });
60232
- const path100 = join31(ctx.rootDir, "milestones", `${id3}.md`);
60482
+ const path101 = join31(ctx.rootDir, "milestones", `${id3}.md`);
60233
60483
  const meta3 = {
60234
60484
  kind: "milestone",
60235
60485
  id: id3,
@@ -60246,7 +60496,7 @@ function addMilestoneRecord(ctx, summary, input) {
60246
60496
  `Target version: ${version2}`,
60247
60497
  ""
60248
60498
  ].join("\n");
60249
- ctx.storage.write(path100, meta3, body);
60499
+ ctx.storage.write(path101, meta3, body);
60250
60500
  return { id: id3, created: true };
60251
60501
  }
60252
60502
  function readPlanSummary(ctx) {
@@ -60450,7 +60700,7 @@ function addIdeaStub(ctx) {
60450
60700
  const tags = args["tags"] ?? [];
60451
60701
  const category = args["category"] ?? "General";
60452
60702
  const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
60453
- const path100 = workspaceArtifact(ctx.rootDir, "decisions", id3);
60703
+ const path101 = workspaceArtifact(ctx.rootDir, "decisions", id3);
60454
60704
  const meta3 = {
60455
60705
  kind: "adr",
60456
60706
  status: "proposed",
@@ -60476,7 +60726,7 @@ function addIdeaStub(ctx) {
60476
60726
  ...consequences.map((c) => `- ${c}`),
60477
60727
  ""
60478
60728
  ].join("\n");
60479
- ctx.storage.write(path100, meta3, body);
60729
+ ctx.storage.write(path101, meta3, body);
60480
60730
  return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
60481
60731
  });
60482
60732
  }
@@ -60558,14 +60808,14 @@ function createDocumentStub(ctx) {
60558
60808
  ctx.storage.write(risksPath, riskMeta, content);
60559
60809
  return `Document "${title}" created at risks.md (workspace root).`;
60560
60810
  }
60561
- const path100 = workspaceArtifact(ctx.rootDir, "docs", slug);
60811
+ const path101 = workspaceArtifact(ctx.rootDir, "docs", slug);
60562
60812
  const meta3 = {
60563
60813
  kind: "doc",
60564
60814
  id: slug,
60565
60815
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
60566
60816
  tags
60567
60817
  };
60568
- ctx.storage.write(path100, meta3, content);
60818
+ ctx.storage.write(path101, meta3, content);
60569
60819
  return `Document "${title}" created at docs/${slug}.md.`;
60570
60820
  });
60571
60821
  }
@@ -61190,10 +61440,10 @@ function getUserMcpPath() {
61190
61440
  function getProjectMcpPath(projectRoot) {
61191
61441
  return join32(projectRoot, ".zelari", "mcp.json");
61192
61442
  }
61193
- function readFile9(path100) {
61194
- if (!existsSync42(path100)) return {};
61443
+ function readFile9(path101) {
61444
+ if (!existsSync42(path101)) return {};
61195
61445
  try {
61196
- const parsed = JSON.parse(readFileSync30(path100, "utf8"));
61446
+ const parsed = JSON.parse(readFileSync30(path101, "utf8"));
61197
61447
  const out = {};
61198
61448
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
61199
61449
  const hasCommand = !!cfg && typeof cfg.command === "string" && !!cfg.command.trim();
@@ -61215,10 +61465,10 @@ function readFile9(path100) {
61215
61465
  return {};
61216
61466
  }
61217
61467
  }
61218
- function writeFile3(path100, servers) {
61219
- mkdirSync17(dirname9(path100), { recursive: true });
61468
+ function writeFile3(path101, servers) {
61469
+ mkdirSync17(dirname9(path101), { recursive: true });
61220
61470
  const body = { mcpServers: servers };
61221
- writeFileSync19(path100, `${JSON.stringify(body, null, 2)}
61471
+ writeFileSync19(path101, `${JSON.stringify(body, null, 2)}
61222
61472
  `, "utf8");
61223
61473
  }
61224
61474
  function listMcpServers(projectRoot) {
@@ -61256,9 +61506,9 @@ function upsertMcpServer(opts) {
61256
61506
  error: "either command (stdio) or url (http) is required"
61257
61507
  };
61258
61508
  }
61259
- let path100;
61509
+ let path101;
61260
61510
  if (opts.scope === "user") {
61261
- path100 = getUserMcpPath();
61511
+ path101 = getUserMcpPath();
61262
61512
  } else {
61263
61513
  const root = opts.projectRoot?.trim();
61264
61514
  if (!root) {
@@ -61267,9 +61517,9 @@ function upsertMcpServer(opts) {
61267
61517
  error: "projectRoot required for project scope (Open Folder first)"
61268
61518
  };
61269
61519
  }
61270
- path100 = getProjectMcpPath(root);
61520
+ path101 = getProjectMcpPath(root);
61271
61521
  }
61272
- const current = readFile9(path100);
61522
+ const current = readFile9(path101);
61273
61523
  current[name] = {
61274
61524
  command: hasCommand ? opts.config.command.trim() : void 0,
61275
61525
  args: opts.config.args,
@@ -61280,21 +61530,21 @@ function upsertMcpServer(opts) {
61280
61530
  serial: opts.config.serial,
61281
61531
  enabled: opts.config.enabled !== false
61282
61532
  };
61283
- writeFile3(path100, current);
61284
- return { ok: true, path: path100 };
61533
+ writeFile3(path101, current);
61534
+ return { ok: true, path: path101 };
61285
61535
  }
61286
61536
  function removeMcpServer(opts) {
61287
- const path100 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
61288
- if (!path100) {
61537
+ const path101 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
61538
+ if (!path101) {
61289
61539
  return { ok: false, error: "projectRoot required for project scope" };
61290
61540
  }
61291
- const current = readFile9(path100);
61541
+ const current = readFile9(path101);
61292
61542
  if (!(opts.name in current)) {
61293
- return { ok: false, error: `Server "${opts.name}" not found in ${path100}` };
61543
+ return { ok: false, error: `Server "${opts.name}" not found in ${path101}` };
61294
61544
  }
61295
61545
  delete current[opts.name];
61296
- writeFile3(path100, current);
61297
- return { ok: true, path: path100 };
61546
+ writeFile3(path101, current);
61547
+ return { ok: true, path: path101 };
61298
61548
  }
61299
61549
  var init_mcpConfigIo = __esm({
61300
61550
  "src/cli/mcp/mcpConfigIo.ts"() {
@@ -61765,10 +62015,10 @@ import { createHash as createHash21 } from "node:crypto";
61765
62015
  import { join as join34 } from "node:path";
61766
62016
  import { readFile as readFile10 } from "node:fs/promises";
61767
62017
  async function readPackageJson3(projectRoot) {
61768
- const path100 = join34(projectRoot, "package.json");
61769
- if (!existsSync44(path100)) return null;
62018
+ const path101 = join34(projectRoot, "package.json");
62019
+ if (!existsSync44(path101)) return null;
61770
62020
  try {
61771
- return JSON.parse(await readFile10(path100, "utf8"));
62021
+ return JSON.parse(await readFile10(path101, "utf8"));
61772
62022
  } catch {
61773
62023
  return null;
61774
62024
  }
@@ -61850,9 +62100,9 @@ async function genBuild(ctx) {
61850
62100
  ].join("\n");
61851
62101
  }
61852
62102
  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");
62103
+ const path101 = join34(ctx.rootDir, "risks.md");
62104
+ if (!existsSync44(path101)) return "_No open questions._";
62105
+ const content = readFileSync32(path101, "utf8");
61856
62106
  const lines = content.split("\n");
61857
62107
  const questions = [];
61858
62108
  let currentTitle = "";
@@ -62126,9 +62376,9 @@ function versionKey(value) {
62126
62376
  function firstString2(v) {
62127
62377
  return typeof v === "string" && v.trim().length > 0 ? v : null;
62128
62378
  }
62129
- function readFileSyncSafe(path100) {
62379
+ function readFileSyncSafe(path101) {
62130
62380
  try {
62131
- return readFileSync33(path100, "utf8");
62381
+ return readFileSync33(path101, "utf8");
62132
62382
  } catch {
62133
62383
  return null;
62134
62384
  }
@@ -62376,7 +62626,7 @@ __export(evidenceFromSpine_exports, {
62376
62626
  evidenceRefsFromEventLines: () => evidenceRefsFromEventLines
62377
62627
  });
62378
62628
  import { existsSync as existsSync47, readFileSync as readFileSync35 } from "node:fs";
62379
- import path71 from "node:path";
62629
+ import path72 from "node:path";
62380
62630
  function asRecord2(v) {
62381
62631
  return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
62382
62632
  }
@@ -62414,7 +62664,7 @@ function evidenceRefsFromEventLines(lines) {
62414
62664
  }
62415
62665
  function collectSessionEvidenceRefs(sessionId2) {
62416
62666
  try {
62417
- const file2 = path71.join(sessionsDir(), sessionId2, "events.jsonl");
62667
+ const file2 = path72.join(sessionsDir(), sessionId2, "events.jsonl");
62418
62668
  if (!existsSync47(file2)) return [];
62419
62669
  return evidenceRefsFromEventLines(readFileSync35(file2, "utf8").split("\n"));
62420
62670
  } catch {
@@ -62664,8 +62914,8 @@ async function runPostCouncilHook(ctx, options) {
62664
62914
  sources: scope.sources
62665
62915
  } : void 0
62666
62916
  });
62667
- const path100 = writeCouncilCompletion(ctx.rootDir, completion);
62668
- completionHook = { ran: true, path: path100, completion };
62917
+ const path101 = writeCouncilCompletion(ctx.rootDir, completion);
62918
+ completionHook = { ran: true, path: path101, completion };
62669
62919
  } catch (err) {
62670
62920
  completionHook = {
62671
62921
  ran: true,
@@ -62710,7 +62960,7 @@ import {
62710
62960
  writeFileSync as writeFileSync22,
62711
62961
  mkdirSync as mkdirSync18
62712
62962
  } from "node:fs";
62713
- import path72 from "node:path";
62963
+ import path73 from "node:path";
62714
62964
  var FeedbackStore;
62715
62965
  var init_councilFeedback = __esm({
62716
62966
  "src/cli/councilFeedback.ts"() {
@@ -62827,7 +63077,7 @@ var init_councilFeedback = __esm({
62827
63077
  }
62828
63078
  }
62829
63079
  save() {
62830
- mkdirSync18(path72.dirname(this.file), { recursive: true });
63080
+ mkdirSync18(path73.dirname(this.file), { recursive: true });
62831
63081
  writeFileSync22(
62832
63082
  this.file,
62833
63083
  JSON.stringify({ entries: this.entries }, null, 2),
@@ -62902,12 +63152,12 @@ __export(ledger_exports, {
62902
63152
  readLedger: () => readLedger
62903
63153
  });
62904
63154
  import { appendFileSync as appendFileSync4, existsSync as existsSync50, mkdirSync as mkdirSync19, readFileSync as readFileSync38 } from "node:fs";
62905
- import path73 from "node:path";
63155
+ import path74 from "node:path";
62906
63156
  function evolutionMode(env = process.env) {
62907
63157
  return env[EVOLUTION_ENV] === "shadow" ? "shadow" : "0";
62908
63158
  }
62909
63159
  function ledgerPath(cwd) {
62910
- return path73.join(cwd, LEDGER_REL);
63160
+ return path74.join(cwd, LEDGER_REL);
62911
63161
  }
62912
63162
  function appendLedgerEntry(cwd, entry) {
62913
63163
  if (evolutionMode() === "0") {
@@ -62915,7 +63165,7 @@ function appendLedgerEntry(cwd, entry) {
62915
63165
  }
62916
63166
  try {
62917
63167
  const file2 = ledgerPath(cwd);
62918
- mkdirSync19(path73.dirname(file2), { recursive: true });
63168
+ mkdirSync19(path74.dirname(file2), { recursive: true });
62919
63169
  appendFileSync4(file2, `${JSON.stringify(entry)}
62920
63170
  `, "utf8");
62921
63171
  return { written: true, path: file2 };
@@ -63016,7 +63266,7 @@ var init_ledger = __esm({
63016
63266
  "src/cli/evolution/ledger.ts"() {
63017
63267
  "use strict";
63018
63268
  EVOLUTION_ENV = "ZELARI_EVOLUTION";
63019
- LEDGER_REL = path73.join(".zelari", "evolution", "ledger.jsonl");
63269
+ LEDGER_REL = path74.join(".zelari", "evolution", "ledger.jsonl");
63020
63270
  TIER_WEIGHTS = {
63021
63271
  build: 1,
63022
63272
  "tool-output": 1,
@@ -63158,7 +63408,7 @@ __export(fileBackend_exports, {
63158
63408
  });
63159
63409
  import { randomUUID as randomUUID7 } from "node:crypto";
63160
63410
  import { promises as fs31 } from "node:fs";
63161
- import * as path74 from "node:path";
63411
+ import * as path75 from "node:path";
63162
63412
  function tokenize2(text) {
63163
63413
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
63164
63414
  }
@@ -63211,8 +63461,8 @@ var init_fileBackend = __esm({
63211
63461
  logPath = "";
63212
63462
  memoryDir = "";
63213
63463
  async init(projectRoot) {
63214
- this.memoryDir = path74.join(projectRoot, ".zelari", "memory");
63215
- this.logPath = path74.join(this.memoryDir, "log.jsonl");
63464
+ this.memoryDir = path75.join(projectRoot, ".zelari", "memory");
63465
+ this.logPath = path75.join(this.memoryDir, "log.jsonl");
63216
63466
  await fs31.mkdir(this.memoryDir, { recursive: true });
63217
63467
  }
63218
63468
  async add(content, metadata2 = {}, graph) {
@@ -63285,12 +63535,12 @@ var init_fileBackend = __esm({
63285
63535
 
63286
63536
  // src/cli/traceStore.ts
63287
63537
  import { promises as fs32 } from "node:fs";
63288
- import * as path75 from "node:path";
63538
+ import * as path76 from "node:path";
63289
63539
  function traceDir(projectRoot) {
63290
- return path75.join(projectRoot, ".zelari", "trace");
63540
+ return path76.join(projectRoot, ".zelari", "trace");
63291
63541
  }
63292
63542
  function tracePath(projectRoot, missionId) {
63293
- return path75.join(traceDir(projectRoot), `${missionId}.json`);
63543
+ return path76.join(traceDir(projectRoot), `${missionId}.json`);
63294
63544
  }
63295
63545
  async function saveTrace(projectRoot, missionId, entries) {
63296
63546
  const dir = traceDir(projectRoot);
@@ -63332,7 +63582,7 @@ __export(zelariMission_exports, {
63332
63582
  });
63333
63583
  import { randomUUID as randomUUID8 } from "node:crypto";
63334
63584
  import { promises as fs33 } from "node:fs";
63335
- import * as path76 from "node:path";
63585
+ import * as path77 from "node:path";
63336
63586
  function resolveMaxIterations(env = process.env) {
63337
63587
  const raw = env.ZELARI_MISSION_MAX_ITER;
63338
63588
  const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
@@ -63375,10 +63625,10 @@ function isMissionAutoStart(env = process.env) {
63375
63625
  return env.ZELARI_MISSION_AUTO === "1";
63376
63626
  }
63377
63627
  async function writeMissionState(projectRoot, state3) {
63378
- const dir = path76.join(projectRoot, ".zelari");
63628
+ const dir = path77.join(projectRoot, ".zelari");
63379
63629
  await fs33.mkdir(dir, { recursive: true });
63380
63630
  await fs33.writeFile(
63381
- path76.join(dir, "mission-state.json"),
63631
+ path77.join(dir, "mission-state.json"),
63382
63632
  JSON.stringify(state3, null, 2) + "\n",
63383
63633
  "utf8"
63384
63634
  );
@@ -63392,7 +63642,7 @@ async function writeMissionState(projectRoot, state3) {
63392
63642
  async function loadMissionState(projectRoot) {
63393
63643
  try {
63394
63644
  const raw = await fs33.readFile(
63395
- path76.join(projectRoot, ".zelari", "mission-state.json"),
63645
+ path77.join(projectRoot, ".zelari", "mission-state.json"),
63396
63646
  "utf8"
63397
63647
  );
63398
63648
  const parsed = JSON.parse(raw);
@@ -64151,7 +64401,7 @@ function safeSocketPath(socketPath) {
64151
64401
  return socketPath.trim();
64152
64402
  }
64153
64403
  function startPermissionBroker(socketPath, handlers, opts) {
64154
- const path100 = safeSocketPath(socketPath);
64404
+ const path101 = safeSocketPath(socketPath);
64155
64405
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
64156
64406
  const sockets = /* @__PURE__ */ new Set();
64157
64407
  const server = createServer2((socket) => {
@@ -64251,10 +64501,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
64251
64501
  return new Promise((resolve9, reject) => {
64252
64502
  const onError = (err) => reject(err);
64253
64503
  server.once("error", onError);
64254
- server.listen(path100, () => {
64504
+ server.listen(path101, () => {
64255
64505
  server.removeListener("error", onError);
64256
64506
  resolve9({
64257
- socketPath: path100,
64507
+ socketPath: path101,
64258
64508
  stop: () => new Promise((res) => {
64259
64509
  for (const s of sockets) s.destroy();
64260
64510
  sockets.clear();
@@ -64265,7 +64515,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
64265
64515
  if (done) return;
64266
64516
  done = true;
64267
64517
  if (process.platform !== "win32") {
64268
- unlink(path100, () => res());
64518
+ unlink(path101, () => res());
64269
64519
  } else {
64270
64520
  res();
64271
64521
  }
@@ -64278,11 +64528,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
64278
64528
  });
64279
64529
  }
64280
64530
  function requestBrokerAsk(socketPath, ask, opts) {
64281
- const path100 = safeSocketPath(socketPath);
64531
+ const path101 = safeSocketPath(socketPath);
64282
64532
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
64283
64533
  const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
64284
64534
  return new Promise((resolve9, reject) => {
64285
- const socket = connect(path100);
64535
+ const socket = connect(path101);
64286
64536
  let buffer = "";
64287
64537
  let settled = false;
64288
64538
  const settle = (fn) => {
@@ -64297,7 +64547,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
64297
64547
  settle(
64298
64548
  () => reject(
64299
64549
  new Error(
64300
- `permission broker unavailable at "${path100}" (connect timed out after ${connectTimeoutMs}ms)`
64550
+ `permission broker unavailable at "${path101}" (connect timed out after ${connectTimeoutMs}ms)`
64301
64551
  )
64302
64552
  )
64303
64553
  );
@@ -65486,7 +65736,7 @@ var init_prereqChecks = __esm({
65486
65736
 
65487
65737
  // src/cli/plugins/prefs.ts
65488
65738
  import { existsSync as existsSync53, readFileSync as readFileSync40, writeFileSync as writeFileSync23, mkdirSync as mkdirSync20 } from "node:fs";
65489
- import path82 from "node:path";
65739
+ import path83 from "node:path";
65490
65740
  function getPluginPrefsPath() {
65491
65741
  return pluginsPrefsPath();
65492
65742
  }
@@ -65509,7 +65759,7 @@ function getPluginPrefs() {
65509
65759
  }
65510
65760
  function writePluginPrefs(prefs) {
65511
65761
  const file2 = getPluginPrefsPath();
65512
- mkdirSync20(path82.dirname(file2), { recursive: true });
65762
+ mkdirSync20(path83.dirname(file2), { recursive: true });
65513
65763
  writeFileSync23(file2, JSON.stringify(prefs, null, 2), {
65514
65764
  encoding: "utf-8",
65515
65765
  mode: 384
@@ -65547,7 +65797,7 @@ __export(registry_exports, {
65547
65797
  isBinaryOnPath: () => isBinaryOnPath
65548
65798
  });
65549
65799
  import { existsSync as existsSync54 } from "node:fs";
65550
- import path83 from "node:path";
65800
+ import path84 from "node:path";
65551
65801
  function detectLocalBin(bin) {
65552
65802
  return (cwd) => {
65553
65803
  try {
@@ -65565,7 +65815,7 @@ function isBinaryOnPath(bin, opts = {}) {
65565
65815
  const platform = opts.platform ?? process.platform;
65566
65816
  const exists = opts.exists ?? existsSync54;
65567
65817
  const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
65568
- const pathMod = platform === "win32" ? path83.win32 : path83.posix;
65818
+ const pathMod = platform === "win32" ? path84.win32 : path84.posix;
65569
65819
  const sep4 = platform === "win32" ? ";" : ":";
65570
65820
  const dirs = pathEnv.split(sep4).filter((d) => d.length > 0);
65571
65821
  const candidates = [bin];
@@ -66670,7 +66920,7 @@ var init_policy = __esm({
66670
66920
 
66671
66921
  // src/cli/orchestration/facts.ts
66672
66922
  import { promises as fs43 } from "node:fs";
66673
- import path87 from "node:path";
66923
+ import path88 from "node:path";
66674
66924
  async function collectRepoFileCount(root = process.cwd()) {
66675
66925
  try {
66676
66926
  await fs43.readdir(root);
@@ -66690,7 +66940,7 @@ async function collectRepoFileCount(root = process.cwd()) {
66690
66940
  }
66691
66941
  for (const e of entries) {
66692
66942
  if (e.isDirectory()) {
66693
- if (!SKIP_DIRS.has(e.name)) queue.push(path87.join(dir, e.name));
66943
+ if (!SKIP_DIRS.has(e.name)) queue.push(path88.join(dir, e.name));
66694
66944
  } else if (e.isFile()) {
66695
66945
  count++;
66696
66946
  if (count > MAX_WALK_FILES) return count;
@@ -66788,7 +67038,7 @@ var init_streamScrub = __esm({
66788
67038
  });
66789
67039
 
66790
67040
  // src/cli/harnessState.ts
66791
- import path88 from "node:path";
67041
+ import path89 from "node:path";
66792
67042
  function asString4(v) {
66793
67043
  return typeof v === "string" ? v : "";
66794
67044
  }
@@ -66963,7 +67213,7 @@ function contractFor(t) {
66963
67213
  };
66964
67214
  }
66965
67215
  async function readHarnessState(sessionDir) {
66966
- const report = await readSessionLog(path88.join(sessionDir, "events.jsonl"));
67216
+ const report = await readSessionLog(path89.join(sessionDir, "events.jsonl"));
66967
67217
  return deriveHarnessState(report.events);
66968
67218
  }
66969
67219
  var init_harnessState = __esm({
@@ -66974,12 +67224,12 @@ var init_harnessState = __esm({
66974
67224
  });
66975
67225
 
66976
67226
  // src/cli/headless/harnessStateEmit.ts
66977
- import path89 from "node:path";
67227
+ import path90 from "node:path";
66978
67228
  async function emitHarnessStateEvent(opts) {
66979
67229
  if (opts.output !== "json") return;
66980
67230
  try {
66981
67231
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.workspaceRoot });
66982
- const state3 = await readHarnessState(path89.join(sessionsDir2, opts.spine.sessionId));
67232
+ const state3 = await readHarnessState(path90.join(sessionsDir2, opts.spine.sessionId));
66983
67233
  opts.emitEvent({ type: "harness_state", ...state3 });
66984
67234
  } catch (err) {
66985
67235
  const msg = err instanceof Error ? err.message : String(err);
@@ -67536,13 +67786,13 @@ var init_verifierLifecycle = __esm({
67536
67786
 
67537
67787
  // src/cli/extensions/sandboxedFs.ts
67538
67788
  import { promises as fsp } from "node:fs";
67539
- import path90 from "node:path";
67789
+ import path91 from "node:path";
67540
67790
  function errText(prefix, p3, err) {
67541
67791
  const msg = err instanceof Error ? err.message : String(err);
67542
67792
  return `[extension-fs] ${prefix} "${p3}": ${msg}`;
67543
67793
  }
67544
67794
  function bindSandboxedFs(root) {
67545
- const resolvedRoot = path90.resolve(root);
67795
+ const resolvedRoot = path91.resolve(root);
67546
67796
  return {
67547
67797
  root: resolvedRoot,
67548
67798
  async readFile(relativePath) {
@@ -67558,7 +67808,7 @@ function bindSandboxedFs(root) {
67558
67808
  try {
67559
67809
  const target = resolveSandboxedPath(relativePath, { root: resolvedRoot });
67560
67810
  verifyContainment(target, { root: resolvedRoot });
67561
- await fsp.mkdir(path90.dirname(target), { recursive: true });
67811
+ await fsp.mkdir(path91.dirname(target), { recursive: true });
67562
67812
  await fsp.writeFile(target, data, "utf8");
67563
67813
  return typedOk({ path: target });
67564
67814
  } catch (err) {
@@ -67743,7 +67993,7 @@ var init_loader = __esm({
67743
67993
 
67744
67994
  // src/cli/headless/runOneTurn.ts
67745
67995
  import { promises as fs44 } from "node:fs";
67746
- import path91 from "node:path";
67996
+ import path92 from "node:path";
67747
67997
  function planModeFromOpts(opts) {
67748
67998
  return (opts.phase ?? "build") === "plan";
67749
67999
  }
@@ -68221,11 +68471,14 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68221
68471
  return null;
68222
68472
  }
68223
68473
  },
68224
- emit: (input) => spine.appendEvent(input)
68474
+ // F3 seam adapter (same as the gate sites below): the core engine reads
68475
+ // the anchor as `out.seq`, while the spine resolves the seq NUMBER. A bare
68476
+ // number here leaves the review evidence unanchored on the spine.
68477
+ emit: async (input) => ({ seq: await spine.appendEvent(input) })
68225
68478
  };
68226
68479
  const strictEnv = strictEnvOverlay(opts);
68227
68480
  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 });
68481
+ const strictGate = await evaluateStrictBuildGate("build", { emit: async (input) => ({ seq: await spine.appendEvent(input) }), cwd, env: strictEnv });
68229
68482
  await runAdvisoryVerifierReview(strictGate, verifierReviewDeps).catch(() => void 0);
68230
68483
  const gate = strictGate.gate;
68231
68484
  const verificationPayload = strictGateEventPayload(strictGate);
@@ -68235,7 +68488,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68235
68488
  }
68236
68489
  await writeProofSafe(strictGate, { surface: "kraken", sessionId: spine.sessionId }, cwd);
68237
68490
  if (strictGate.blocked) {
68238
- const repairPrompt = buildKrakenRepairPrompt(gate);
68491
+ const repairPrompt = buildKrakenRepairPrompt(gate, repairExcerptsFromEvaluation(strictGate));
68239
68492
  if (opts.output === "json") {
68240
68493
  emitEvent({
68241
68494
  type: "log",
@@ -68260,7 +68513,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68260
68513
  successfulWrites: pass.successfulWrites + repair.successfulWrites,
68261
68514
  emittedWrites: pass.emittedWrites + repair.emittedWrites
68262
68515
  };
68263
- const after = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd, env: strictEnv });
68516
+ const after = await evaluateStrictBuildGate("build", { emit: async (input) => ({ seq: await spine.appendEvent(input) }), cwd, env: strictEnv });
68264
68517
  await runAdvisoryVerifierReview(after, verifierReviewDeps).catch(() => void 0);
68265
68518
  const afterPayload = strictGateEventPayload(after);
68266
68519
  spine.verificationRun(afterPayload);
@@ -68310,7 +68563,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68310
68563
  if (json3) {
68311
68564
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
68312
68565
  else {
68313
- await fs44.mkdir(path91.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
68566
+ await fs44.mkdir(path92.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
68314
68567
  await fs44.writeFile(opts.exportSessionPath, json3, "utf8");
68315
68568
  }
68316
68569
  }
@@ -69359,9 +69612,9 @@ __export(triggerLock_exports, {
69359
69612
  releaseLock: () => releaseLock
69360
69613
  });
69361
69614
  import { promises as fs45 } from "node:fs";
69362
- import * as path92 from "node:path";
69615
+ import * as path93 from "node:path";
69363
69616
  function lockPath(projectRoot) {
69364
- return path92.join(projectRoot, ".zelari", "trigger.lock");
69617
+ return path93.join(projectRoot, ".zelari", "trigger.lock");
69365
69618
  }
69366
69619
  function isPidAlive(pid) {
69367
69620
  try {
@@ -69374,7 +69627,7 @@ function isPidAlive(pid) {
69374
69627
  }
69375
69628
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
69376
69629
  const lp = lockPath(projectRoot);
69377
- const dir = path92.dirname(lp);
69630
+ const dir = path93.dirname(lp);
69378
69631
  await fs45.mkdir(dir, { recursive: true });
69379
69632
  try {
69380
69633
  const raw = await fs45.readFile(lp, "utf8");
@@ -69406,7 +69659,7 @@ var init_triggerLock = __esm({
69406
69659
 
69407
69660
  // src/cli/runHeadless.ts
69408
69661
  import { promises as fs46 } from "node:fs";
69409
- import path93 from "node:path";
69662
+ import path94 from "node:path";
69410
69663
  import { randomUUID as randomUUID10 } from "node:crypto";
69411
69664
  async function runHeadless(opts) {
69412
69665
  resetTaskSpawnCount();
@@ -69650,7 +69903,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
69650
69903
  try {
69651
69904
  let preflightGraph;
69652
69905
  if (opts.runPlan && opts.runPlan.trim() !== "") {
69653
- const planPath = path93.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
69906
+ const planPath = path94.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
69654
69907
  log(`loading pre-flight plan: ${planPath}`);
69655
69908
  let raw;
69656
69909
  try {
@@ -69693,8 +69946,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
69693
69946
  log(formatKrakenGraphAscii2(graph));
69694
69947
  if (opts.planOnly) {
69695
69948
  const planId = randomUUID10();
69696
- const planDir = path93.join(cwd, ".zelari", "radio");
69697
- const planPath = path93.join(planDir, `plan-${planId}.json`);
69949
+ const planDir = path94.join(cwd, ".zelari", "radio");
69950
+ const planPath = path94.join(planDir, `plan-${planId}.json`);
69698
69951
  await fs46.mkdir(planDir, { recursive: true });
69699
69952
  await fs46.writeFile(
69700
69953
  planPath,
@@ -70085,7 +70338,7 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
70085
70338
  if (json3) {
70086
70339
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
70087
70340
  else {
70088
- await fs46.mkdir(path93.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70341
+ await fs46.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70089
70342
  await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
70090
70343
  }
70091
70344
  }
@@ -70508,6 +70761,22 @@ ${ragContext}` : slicePrompt;
70508
70761
  if (missionGate.blocked) {
70509
70762
  exitCode = strictGateExitCode(missionGate);
70510
70763
  spine.missionPhase("verification", "mission-strict-blocked");
70764
+ } else if (
70765
+ // M2.1/R4b: an open strict gate is not enough — the success claim must
70766
+ // be event-backed: zero `verification.evidence` events in the spine
70767
+ // means narration-only done → strict exit code. Same overlay seam as
70768
+ // the gate above (H10-fix1) so --allow-unverified /
70769
+ // ZELARI_ALLOW_UNVERIFIED=1 waives mission-side too. `opts.phase` is
70770
+ // the only phase/mode discriminant on this site: `--phase plan`
70771
+ // missions are design-only (no verification expected), so the gate
70772
+ // applies unconditionally to build-phase claims.
70773
+ opts.phase !== "plan" && missionClaimExitCode(await spine.countVerificationEvidence(), strictEnvOverlay(opts)) !== 0
70774
+ ) {
70775
+ exitCode = STRICT_DONE_EXIT_CODE;
70776
+ spine.missionPhase("verification", "mission-event-back-missing");
70777
+ process.stderr.write(
70778
+ "[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"
70779
+ );
70511
70780
  } else {
70512
70781
  exitCode = 0;
70513
70782
  spine.missionPhase("done", "mission-success");
@@ -70541,7 +70810,7 @@ ${ragContext}` : slicePrompt;
70541
70810
  if (json3) {
70542
70811
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
70543
70812
  else {
70544
- await fs46.mkdir(path93.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70813
+ await fs46.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70545
70814
  await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
70546
70815
  }
70547
70816
  }
@@ -71166,7 +71435,7 @@ function upsertSkill(opts) {
71166
71435
  }
71167
71436
  dir = getProjectSkillsDir(root);
71168
71437
  }
71169
- const path100 = skillFilePath(dir, name);
71438
+ const path101 = skillFilePath(dir, name);
71170
71439
  const content = serializeSkillMd({
71171
71440
  name,
71172
71441
  description,
@@ -71175,13 +71444,13 @@ function upsertSkill(opts) {
71175
71444
  tools: opts.tools,
71176
71445
  cost: opts.cost
71177
71446
  });
71178
- const parsed = parseSkillMd(content, path100);
71447
+ const parsed = parseSkillMd(content, path101);
71179
71448
  if (!parsed) {
71180
71449
  return { ok: false, error: "Generated SKILL.md failed validation" };
71181
71450
  }
71182
- mkdirSync23(dirname13(path100), { recursive: true });
71183
- writeFileSync25(path100, content, "utf8");
71184
- return { ok: true, path: path100 };
71451
+ mkdirSync23(dirname13(path101), { recursive: true });
71452
+ writeFileSync25(path101, content, "utf8");
71453
+ return { ok: true, path: path101 };
71185
71454
  }
71186
71455
  function removeSkill(opts) {
71187
71456
  const name = opts.name.trim().toLowerCase();
@@ -71199,8 +71468,8 @@ function removeSkill(opts) {
71199
71468
  dir = getProjectSkillsDir(root);
71200
71469
  }
71201
71470
  const skillDir = join46(dir, name);
71202
- const path100 = skillFilePath(dir, name);
71203
- if (!existsSync59(path100) && !existsSync59(skillDir)) {
71471
+ const path101 = skillFilePath(dir, name);
71472
+ if (!existsSync59(path101) && !existsSync59(skillDir)) {
71204
71473
  return { ok: false, error: `Skill "${name}" not found in ${dir}` };
71205
71474
  }
71206
71475
  try {
@@ -71211,7 +71480,7 @@ function removeSkill(opts) {
71211
71480
  error: err instanceof Error ? err.message : String(err)
71212
71481
  };
71213
71482
  }
71214
- return { ok: true, path: path100 };
71483
+ return { ok: true, path: path101 };
71215
71484
  }
71216
71485
  var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
71217
71486
  var init_skillConfigIo = __esm({
@@ -71332,7 +71601,7 @@ var init_jsonApi = __esm({
71332
71601
  });
71333
71602
 
71334
71603
  // src/cli/memory/mcpAdapter.ts
71335
- import * as path94 from "node:path";
71604
+ import * as path95 from "node:path";
71336
71605
  var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
71337
71606
  var init_mcpAdapter = __esm({
71338
71607
  "src/cli/memory/mcpAdapter.ts"() {
@@ -71502,8 +71771,8 @@ var init_mcpAdapter = __esm({
71502
71771
  this.takeWrite();
71503
71772
  const externalFile = args.source?.file;
71504
71773
  if (externalFile) {
71505
- const normalized = path94.normalize(externalFile);
71506
- if (path94.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path94.sep}`)) {
71774
+ const normalized = path95.normalize(externalFile);
71775
+ if (path95.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path95.sep}`)) {
71507
71776
  throw new Error("source.file must be project-relative and cannot escape the project");
71508
71777
  }
71509
71778
  }
@@ -72030,12 +72299,12 @@ function ensureHome() {
72030
72299
  }
72031
72300
  }
72032
72301
  function loadCompanionConfig() {
72033
- const path100 = getCompanionConfigPath();
72034
- if (!existsSync60(path100)) {
72302
+ const path101 = getCompanionConfigPath();
72303
+ if (!existsSync60(path101)) {
72035
72304
  return { projects: [] };
72036
72305
  }
72037
72306
  try {
72038
- const raw = JSON.parse(readFileSync45(path100, "utf8"));
72307
+ const raw = JSON.parse(readFileSync45(path101, "utf8"));
72039
72308
  const projects = Array.isArray(raw.projects) ? raw.projects.filter(
72040
72309
  (p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
72041
72310
  ).map((p3) => ({
@@ -72073,16 +72342,16 @@ function loadOrCreateToken(explicit) {
72073
72342
  return { token: explicit.trim(), created: false };
72074
72343
  }
72075
72344
  ensureHome();
72076
- const path100 = getCompanionTokenPath();
72077
- if (existsSync60(path100)) {
72078
- const t = readFileSync45(path100, "utf8").trim();
72345
+ const path101 = getCompanionTokenPath();
72346
+ if (existsSync60(path101)) {
72347
+ const t = readFileSync45(path101, "utf8").trim();
72079
72348
  if (t) return { token: t, created: false };
72080
72349
  }
72081
72350
  const token = randomBytes7(24).toString("base64url");
72082
- writeFileSync26(path100, token + "\n", "utf8");
72351
+ writeFileSync26(path101, token + "\n", "utf8");
72083
72352
  try {
72084
72353
  const fs48 = __require("node:fs");
72085
- fs48.chmodSync?.(path100, 384);
72354
+ fs48.chmodSync?.(path101, 384);
72086
72355
  } catch {
72087
72356
  }
72088
72357
  return { token, created: true };
@@ -72107,17 +72376,17 @@ function mergeProjects(cfg, extraPaths) {
72107
72376
  byId.set(p3.id, p3);
72108
72377
  }
72109
72378
  for (const raw of extraPaths) {
72110
- const path100 = raw.trim();
72111
- if (!path100) continue;
72112
- let id3 = slugFromPath(path100);
72379
+ const path101 = raw.trim();
72380
+ if (!path101) continue;
72381
+ let id3 = slugFromPath(path101);
72113
72382
  let n = 2;
72114
- while (byId.has(id3) && byId.get(id3).path !== path100) {
72115
- id3 = `${slugFromPath(path100)}-${n++}`;
72383
+ while (byId.has(id3) && byId.get(id3).path !== path101) {
72384
+ id3 = `${slugFromPath(path101)}-${n++}`;
72116
72385
  }
72117
72386
  byId.set(id3, {
72118
72387
  id: id3,
72119
- name: slugFromPath(path100),
72120
- path: path100
72388
+ name: slugFromPath(path101),
72389
+ path: path101
72121
72390
  });
72122
72391
  }
72123
72392
  return [...byId.values()];
@@ -72360,7 +72629,7 @@ var init_askUserBridge = __esm({
72360
72629
 
72361
72630
  // src/cli/serve/spineLockSweep.ts
72362
72631
  import { promises as fs47 } from "node:fs";
72363
- import path95 from "node:path";
72632
+ import path96 from "node:path";
72364
72633
  async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
72365
72634
  const dir = sessionsDir2 ?? resolveSessionsDir();
72366
72635
  const onSwept = options.onSwept ?? ((sessionId2, reason) => {
@@ -72378,7 +72647,7 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
72378
72647
  return result;
72379
72648
  }
72380
72649
  for (const sessionId2 of entries) {
72381
- const lockPath2 = path95.join(dir, sessionId2, "writer.lock");
72650
+ const lockPath2 = path96.join(dir, sessionId2, "writer.lock");
72382
72651
  try {
72383
72652
  const raw = await fs47.readFile(lockPath2, "utf-8");
72384
72653
  let lockInfo = {};
@@ -73375,9 +73644,9 @@ async function runCompanionServe(opts = {}) {
73375
73644
  return;
73376
73645
  }
73377
73646
  const url2 = parseUrl(req);
73378
- const path100 = url2.pathname.replace(/\/+$/, "") || "/";
73647
+ const path101 = url2.pathname.replace(/\/+$/, "") || "/";
73379
73648
  try {
73380
- if (req.method === "GET" && (path100 === "/health" || path100 === "/v1/health")) {
73649
+ if (req.method === "GET" && (path101 === "/health" || path101 === "/v1/health")) {
73381
73650
  sendJson2(res, 200, {
73382
73651
  ok: true,
73383
73652
  service: "zelari-companion",
@@ -73389,18 +73658,18 @@ async function runCompanionServe(opts = {}) {
73389
73658
  });
73390
73659
  return;
73391
73660
  }
73392
- if (path100.startsWith("/v1")) {
73661
+ if (path101.startsWith("/v1")) {
73393
73662
  if (!tokenMatches(token, getBearer(req))) {
73394
73663
  sendJson2(res, 401, { ok: false, error: "unauthorized" });
73395
73664
  return;
73396
73665
  }
73397
73666
  }
73398
- if (req.method === "GET" && path100 === "/v1/config") {
73667
+ if (req.method === "GET" && path101 === "/v1/config") {
73399
73668
  const snap = buildDesktopConfigSnapshot();
73400
73669
  sendJson2(res, 200, { ok: true, ...snap });
73401
73670
  return;
73402
73671
  }
73403
- if (req.method === "GET" && path100 === "/v1/projects") {
73672
+ if (req.method === "GET" && path101 === "/v1/projects") {
73404
73673
  sendJson2(res, 200, {
73405
73674
  ok: true,
73406
73675
  projects: projects.map((p3) => ({
@@ -73411,7 +73680,7 @@ async function runCompanionServe(opts = {}) {
73411
73680
  });
73412
73681
  return;
73413
73682
  }
73414
- if (req.method === "GET" && path100 === "/v1/runs") {
73683
+ if (req.method === "GET" && path101 === "/v1/runs") {
73415
73684
  sendJson2(res, 200, {
73416
73685
  ok: true,
73417
73686
  active: runs.getActive(),
@@ -73429,7 +73698,7 @@ async function runCompanionServe(opts = {}) {
73429
73698
  });
73430
73699
  return;
73431
73700
  }
73432
- if (req.method === "POST" && path100 === "/v1/runs") {
73701
+ if (req.method === "POST" && path101 === "/v1/runs") {
73433
73702
  const raw = await readBody(req);
73434
73703
  let body = {};
73435
73704
  try {
@@ -73477,7 +73746,7 @@ async function runCompanionServe(opts = {}) {
73477
73746
  });
73478
73747
  return;
73479
73748
  }
73480
- const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path100);
73749
+ const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path101);
73481
73750
  if (req.method === "GET" && eventsMatch) {
73482
73751
  const runId = eventsMatch[1];
73483
73752
  const run = runs.getRun(runId);
@@ -73542,7 +73811,7 @@ async function runCompanionServe(opts = {}) {
73542
73811
  }, 500);
73543
73812
  return;
73544
73813
  }
73545
- const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path100);
73814
+ const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path101);
73546
73815
  if (req.method === "POST" && cancelMatch) {
73547
73816
  const runId = cancelMatch[1];
73548
73817
  const result = runs.cancel(runId);
@@ -73553,7 +73822,7 @@ async function runCompanionServe(opts = {}) {
73553
73822
  sendJson2(res, 200, { ok: true, cancelled: runId });
73554
73823
  return;
73555
73824
  }
73556
- const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path100);
73825
+ const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path101);
73557
73826
  if (req.method === "POST" && steerMatch) {
73558
73827
  const runId = steerMatch[1];
73559
73828
  const raw = await readBody(req);
@@ -73722,11 +73991,11 @@ import { execSync as execSync2 } from "node:child_process";
73722
73991
  import { existsSync as existsSync62, readFileSync as readFileSync46, readlinkSync, statSync as statSync10 } from "node:fs";
73723
73992
  import { createRequire as createRequire3 } from "node:module";
73724
73993
  import { fileURLToPath as fileURLToPath3 } from "node:url";
73725
- import path96 from "node:path";
73994
+ import path97 from "node:path";
73726
73995
  function findPackageRoot(start) {
73727
73996
  let dir = start;
73728
73997
  for (let i = 0; i < 6; i += 1) {
73729
- const candidate = path96.join(dir, "package.json");
73998
+ const candidate = path97.join(dir, "package.json");
73730
73999
  if (existsSync62(candidate)) {
73731
74000
  try {
73732
74001
  const pkg = JSON.parse(readFileSync46(candidate, "utf8"));
@@ -73734,11 +74003,11 @@ function findPackageRoot(start) {
73734
74003
  } catch {
73735
74004
  }
73736
74005
  }
73737
- const parent = path96.dirname(dir);
74006
+ const parent = path97.dirname(dir);
73738
74007
  if (parent === dir) break;
73739
74008
  dir = parent;
73740
74009
  }
73741
- return path96.resolve(__dirname3, "..", "..", "..");
74010
+ return path97.resolve(__dirname3, "..", "..", "..");
73742
74011
  }
73743
74012
  function tryExec(cmd) {
73744
74013
  try {
@@ -73752,7 +74021,7 @@ function tryExec(cmd) {
73752
74021
  }
73753
74022
  function readPackageJson4() {
73754
74023
  try {
73755
- const pkgPath = path96.join(packageRoot, "package.json");
74024
+ const pkgPath = path97.join(packageRoot, "package.json");
73756
74025
  return JSON.parse(readFileSync46(pkgPath, "utf8"));
73757
74026
  } catch {
73758
74027
  return null;
@@ -73764,7 +74033,7 @@ function getGlobalPrefix() {
73764
74033
  return (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || "").trim();
73765
74034
  }
73766
74035
  function isSourceCheckout() {
73767
- return existsSync62(path96.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path96.join(packageRoot, "apps", "desktop", "package.json"));
74036
+ return existsSync62(path97.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path97.join(packageRoot, "apps", "desktop", "package.json"));
73768
74037
  }
73769
74038
  function checkShim(pkgName) {
73770
74039
  const prefix = getGlobalPrefix();
@@ -73773,9 +74042,9 @@ function checkShim(pkgName) {
73773
74042
  }
73774
74043
  const isWin = process.platform === "win32";
73775
74044
  const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
73776
- const shimPath = path96.join(prefix, shimName);
74045
+ const shimPath = path97.join(prefix, shimName);
73777
74046
  if (!existsSync62(shimPath)) {
73778
- const localBin = path96.join(packageRoot, "bin", "zelari-code.js");
74047
+ const localBin = path97.join(packageRoot, "bin", "zelari-code.js");
73779
74048
  if (isSourceCheckout() && existsSync62(localBin)) {
73780
74049
  return WARN(
73781
74050
  `global shim not found at ${shimPath}
@@ -73809,8 +74078,8 @@ function checkShim(pkgName) {
73809
74078
  fix: npm install -g ${pkgName}@latest --force`
73810
74079
  );
73811
74080
  }
73812
- const resolved = path96.resolve(path96.dirname(shimPath), target);
73813
- const expected = path96.join(
74081
+ const resolved = path97.resolve(path97.dirname(shimPath), target);
74082
+ const expected = path97.join(
73814
74083
  prefix,
73815
74084
  "node_modules",
73816
74085
  pkgName,
@@ -73852,7 +74121,7 @@ function checkNode(pkg) {
73852
74121
  return OK(`node ${raw} (engines.node ${enginesNode ?? ">= 20.0.0"})`);
73853
74122
  }
73854
74123
  function checkBundle() {
73855
- const bundle = path96.join(packageRoot, "dist", "cli", "main.bundled.js");
74124
+ const bundle = path97.join(packageRoot, "dist", "cli", "main.bundled.js");
73856
74125
  if (!existsSync62(bundle)) {
73857
74126
  return FAIL(
73858
74127
  `dist/cli/main.bundled.js missing at ${bundle}
@@ -73873,7 +74142,7 @@ function checkRuntimeDeps() {
73873
74142
  const missing = [];
73874
74143
  for (const dep of required2) {
73875
74144
  try {
73876
- const localReq = createRequire3(path96.join(packageRoot, "package.json"));
74145
+ const localReq = createRequire3(path97.join(packageRoot, "package.json"));
73877
74146
  localReq.resolve(dep);
73878
74147
  } catch {
73879
74148
  missing.push(dep);
@@ -74150,7 +74419,7 @@ var init_doctor = __esm({
74150
74419
  init_metrics3();
74151
74420
  init_contextGrowthSummary();
74152
74421
  require3 = createRequire3(import.meta.url);
74153
- __dirname3 = path96.dirname(fileURLToPath3(import.meta.url));
74422
+ __dirname3 = path97.dirname(fileURLToPath3(import.meta.url));
74154
74423
  packageRoot = findPackageRoot(__dirname3);
74155
74424
  OK = (message) => ({
74156
74425
  ok: true,
@@ -74259,7 +74528,7 @@ __export(userSettings_exports, {
74259
74528
  settingsOverrides: () => settingsOverrides
74260
74529
  });
74261
74530
  import { existsSync as existsSync63, readFileSync as readFileSync47 } from "node:fs";
74262
- import path97 from "node:path";
74531
+ import path98 from "node:path";
74263
74532
  function parseBool(raw) {
74264
74533
  const v = raw.trim().toLowerCase();
74265
74534
  if (["1", "true", "yes", "on"].includes(v)) return true;
@@ -74326,8 +74595,8 @@ function envValueFor(key, env) {
74326
74595
  function resolveUserSettings(opts = {}) {
74327
74596
  const cwd = opts.cwd ?? process.cwd();
74328
74597
  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);
74598
+ const userPath = path98.join(zelariHome(), SETTINGS_FILE_NAME);
74599
+ const projectPath = path98.join(cwd, ".zelari", SETTINGS_FILE_NAME);
74331
74600
  const warnings = [];
74332
74601
  const userLayer = loadFileLayer(userPath, "user", warnings);
74333
74602
  const projectLayer = loadFileLayer(projectPath, "project", warnings);
@@ -74541,7 +74810,7 @@ __export(inspectSession_exports, {
74541
74810
  renderInspectReport: () => renderInspectReport,
74542
74811
  runInspectSession: () => runInspectSession
74543
74812
  });
74544
- import path98 from "node:path";
74813
+ import path99 from "node:path";
74545
74814
  import { existsSync as existsSync64 } from "node:fs";
74546
74815
  function formatLimit(limit) {
74547
74816
  return `${Math.round(limit / 1e3)}k`;
@@ -74575,8 +74844,8 @@ function renderInspectReport(state3) {
74575
74844
  }
74576
74845
  async function runInspectSession(opts) {
74577
74846
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.cwd ?? process.cwd() });
74578
- const sessionDir = path98.join(sessionsDir2, opts.sessionId);
74579
- const eventsPath = path98.join(sessionDir, "events.jsonl");
74847
+ const sessionDir = path99.join(sessionsDir2, opts.sessionId);
74848
+ const eventsPath = path99.join(sessionDir, "events.jsonl");
74580
74849
  if (!existsSync64(sessionDir)) {
74581
74850
  console.error(`zelari-code inspect: no session directory at ${sessionDir}`);
74582
74851
  return 1;
@@ -74610,14 +74879,14 @@ __export(inspect_exports, {
74610
74879
  collectInspectReport: () => collectInspectReport,
74611
74880
  runInspect: () => runInspect
74612
74881
  });
74613
- import path99 from "node:path";
74882
+ import path100 from "node:path";
74614
74883
  import { existsSync as existsSync65, readFileSync as readFileSync48, readdirSync as readdirSync13 } from "node:fs";
74615
74884
  async function collectInspectReport(cwd = process.cwd()) {
74616
74885
  ensureBuiltinSkillsLoadedSync();
74617
74886
  const snap = listSkillsSnapshot(cwd);
74618
74887
  const mcp = listMcpServers(cwd);
74619
- const userMcpPath = path99.join(zelariHome(), "mcp.json");
74620
- const projectMcpPath = path99.join(cwd, ".zelari", "mcp.json");
74888
+ const userMcpPath = path100.join(zelariHome(), "mcp.json");
74889
+ const projectMcpPath = path100.join(cwd, ".zelari", "mcp.json");
74621
74890
  const globalHooks = globalHooksDir();
74622
74891
  const projectHooks = projectHooksDir(cwd);
74623
74892
  const projectTrusted = isFolderTrusted(cwd);
@@ -74645,9 +74914,9 @@ async function collectInspectReport(cwd = process.cwd()) {
74645
74914
  configSources: [
74646
74915
  { path: userMcpPath, exists: existsSync65(userMcpPath) },
74647
74916
  { 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")) }
74917
+ { path: path100.join(zelariHome(), "provider.json"), exists: existsSync65(path100.join(zelariHome(), "provider.json")) },
74918
+ { path: path100.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync65(path100.join(cwd, ".zelari", "AGENTS.md")) },
74919
+ { path: path100.join(cwd, "AGENTS.md"), exists: existsSync65(path100.join(cwd, "AGENTS.md")) }
74651
74920
  ],
74652
74921
  skills: {
74653
74922
  total: snap.skills.length,
@@ -74687,8 +74956,8 @@ function listJsonFiles(dir) {
74687
74956
  }
74688
74957
  function findAgentsMd(cwd) {
74689
74958
  const candidates = [
74690
- path99.join(cwd, "AGENTS.md"),
74691
- path99.join(cwd, ".zelari", "AGENTS.md")
74959
+ path100.join(cwd, "AGENTS.md"),
74960
+ path100.join(cwd, ".zelari", "AGENTS.md")
74692
74961
  ];
74693
74962
  const found = [];
74694
74963
  for (const c of candidates) {
@@ -78441,7 +78710,10 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
78441
78710
  progressRuntime.observe(event);
78442
78711
  if (event.type === "agent_end") {
78443
78712
  let krakenSuppressFinish = false;
78444
- const krakenSpineEmit = (input) => writerRef.current?.spine?.appendEvent(input) ?? Promise.resolve(null);
78713
+ const krakenSpineEmit = async (input) => {
78714
+ const seq = await (writerRef.current?.spine?.appendEvent(input) ?? Promise.resolve(null));
78715
+ return { seq };
78716
+ };
78445
78717
  const writeProofSafe2 = (gate) => writeCompletionProof(gate, { meta: { surface: "kraken", sessionId: sessionId2 } }).then(
78446
78718
  () => void 0,
78447
78719
  () => void 0
@@ -78455,7 +78727,9 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
78455
78727
  if (krakenGate.blocked) {
78456
78728
  krakenRepairEnqueued = true;
78457
78729
  markRepairTriggered();
78458
- harness2.enqueue(buildKrakenRepairPrompt(krakenGate));
78730
+ harness2.enqueue(
78731
+ buildKrakenRepairPrompt(krakenGate, repairExcerptsFromEvaluation(strictGate))
78732
+ );
78459
78733
  appendSystem(
78460
78734
  setMessages,
78461
78735
  formatStrictBlockExplanation(strictGate),
@@ -79949,10 +80223,10 @@ init_ledger();
79949
80223
 
79950
80224
  // src/cli/evolution/proposals.ts
79951
80225
  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");
80226
+ import path78 from "node:path";
80227
+ var PROPOSALS_REL = path78.join(".zelari", "evolution", "proposals.jsonl");
79954
80228
  function proposalsPath(cwd) {
79955
- return path77.join(cwd, PROPOSALS_REL);
80229
+ return path78.join(cwd, PROPOSALS_REL);
79956
80230
  }
79957
80231
  function readProposalStore(cwd) {
79958
80232
  const file2 = proposalsPath(cwd);
@@ -81062,11 +81336,11 @@ function handleCacheStats(ctx) {
81062
81336
  init_messageHelpers();
81063
81337
  init_serviceFactory();
81064
81338
  import { promises as fs35 } from "node:fs";
81065
- import * as path79 from "node:path";
81339
+ import * as path80 from "node:path";
81066
81340
 
81067
81341
  // src/cli/memory/promotion.ts
81068
81342
  import { promises as fs34 } from "node:fs";
81069
- import * as path78 from "node:path";
81343
+ import * as path79 from "node:path";
81070
81344
  var START = "<!-- zelari:memory-promotions:start -->";
81071
81345
  var END = "<!-- zelari:memory-promotions:end -->";
81072
81346
  var DURABLE_KINDS = /* @__PURE__ */ new Set(["fact", "decision", "constraint", "preference", "procedure"]);
@@ -81077,13 +81351,13 @@ function lineFor(node) {
81077
81351
  }
81078
81352
  async function promoteMemoryToAgentsMd(projectRoot, node) {
81079
81353
  if (node.status !== "active") {
81080
- return { added: false, path: path78.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
81354
+ return { added: false, path: path79.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
81081
81355
  }
81082
81356
  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` };
81357
+ return { added: false, path: path79.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
81084
81358
  }
81085
- const root = await fs34.realpath(projectRoot).catch(() => path78.resolve(projectRoot));
81086
- const target = path78.join(root, "AGENTS.md");
81359
+ const root = await fs34.realpath(projectRoot).catch(() => path79.resolve(projectRoot));
81360
+ const target = path79.join(root, "AGENTS.md");
81087
81361
  try {
81088
81362
  const stat8 = await fs34.lstat(target);
81089
81363
  if (stat8.isSymbolicLink() || !stat8.isFile()) throw new Error("AGENTS.md must be a regular project file.");
@@ -81148,22 +81422,22 @@ function sourceLine(source2) {
81148
81422
  return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
81149
81423
  }
81150
81424
  function isInside(root, target) {
81151
- const relative6 = path79.relative(root, target);
81152
- return relative6 === "" || !relative6.startsWith("..") && !path79.isAbsolute(relative6);
81425
+ const relative6 = path80.relative(root, target);
81426
+ return relative6 === "" || !relative6.startsWith("..") && !path80.isAbsolute(relative6);
81153
81427
  }
81154
81428
  async function safeExportPath(cwd, requested) {
81155
- const lexicalRoot = path79.resolve(cwd);
81429
+ const lexicalRoot = path80.resolve(cwd);
81156
81430
  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;
81431
+ const fallback = path80.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
81432
+ const target = requested?.trim() ? path80.resolve(root, requested.trim()) : fallback;
81159
81433
  if (!isInside(root, target)) {
81160
81434
  throw new Error("Export path must stay inside the active project.");
81161
81435
  }
81162
- const parent = path79.dirname(target);
81163
- const relativeParent = path79.relative(root, parent);
81436
+ const parent = path80.dirname(target);
81437
+ const relativeParent = path80.relative(root, parent);
81164
81438
  let cursor = root;
81165
- for (const segment of relativeParent.split(path79.sep).filter(Boolean)) {
81166
- cursor = path79.join(cursor, segment);
81439
+ for (const segment of relativeParent.split(path80.sep).filter(Boolean)) {
81440
+ cursor = path80.join(cursor, segment);
81167
81441
  try {
81168
81442
  const stat8 = await fs35.lstat(cursor);
81169
81443
  if (stat8.isSymbolicLink()) {
@@ -81335,9 +81609,9 @@ ${message}` : message
81335
81609
  }
81336
81610
  case "export": {
81337
81611
  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));
81612
+ await fs35.mkdir(path80.dirname(target), { recursive: true });
81613
+ const root = await fs35.realpath(ctx.cwd).catch(() => path80.resolve(ctx.cwd));
81614
+ const realParent = await fs35.realpath(path80.dirname(target));
81341
81615
  if (!isInside(root, realParent)) {
81342
81616
  throw new Error("Export path resolves outside the active project.");
81343
81617
  }
@@ -81552,7 +81826,7 @@ import { promises as fs37 } from "node:fs";
81552
81826
  init_zod();
81553
81827
  init_taskTool();
81554
81828
  import { promises as fs36 } from "node:fs";
81555
- import path80 from "node:path";
81829
+ import path81 from "node:path";
81556
81830
  import { randomBytes as randomBytes6 } from "node:crypto";
81557
81831
  var CsvFanoutArgsSchema = external_exports.object({
81558
81832
  csv_path: external_exports.string().min(1),
@@ -81646,8 +81920,8 @@ function resolveMaxConcurrency(env = process.env) {
81646
81920
  }
81647
81921
  async function runCsvFanout(args, deps, opts) {
81648
81922
  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);
81923
+ const absCsv = path81.isAbsolute(args.csv_path) ? args.csv_path : path81.join(opts.parentCwd, args.csv_path);
81924
+ const absOut = path81.isAbsolute(args.output_csv_path) ? args.output_csv_path : path81.join(opts.parentCwd, args.output_csv_path);
81651
81925
  const { headers: headers3, rows } = await readCsv(absCsv);
81652
81926
  if (headers3.length === 0) {
81653
81927
  throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
@@ -81703,7 +81977,7 @@ async function runCsvFanout(args, deps, opts) {
81703
81977
  errored += 1;
81704
81978
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
81705
81979
  }
81706
- await fs36.mkdir(path80.dirname(absOut), { recursive: true });
81980
+ await fs36.mkdir(path81.dirname(absOut), { recursive: true });
81707
81981
  await queueWrite(serializeCsv(outHeaders, outputRecords));
81708
81982
  }
81709
81983
  }
@@ -81898,7 +82172,7 @@ function splitArgs(s) {
81898
82172
  // src/cli/slashHandlers/krakenWorkbench.ts
81899
82173
  init_messageHelpers();
81900
82174
  import { promises as fs38 } from "node:fs";
81901
- import path81 from "node:path";
82175
+ import path82 from "node:path";
81902
82176
 
81903
82177
  // src/cli/kraken/workbenchView.ts
81904
82178
  var EMPTY = {
@@ -82015,14 +82289,14 @@ function formatWorkbenchForTerminal(p3) {
82015
82289
 
82016
82290
  // src/cli/slashHandlers/krakenWorkbench.ts
82017
82291
  async function handleKrakenWorkbench(ctx) {
82018
- const dir = path81.join(ctx.cwd, ".zelari", "radio");
82292
+ const dir = path82.join(ctx.cwd, ".zelari", "radio");
82019
82293
  let latest = null;
82020
82294
  let latestMtime = 0;
82021
82295
  try {
82022
82296
  const files = await fs38.readdir(dir);
82023
82297
  for (const f of files) {
82024
82298
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
82025
- const full = path81.join(dir, f);
82299
+ const full = path82.join(dir, f);
82026
82300
  const stat8 = await fs38.stat(full);
82027
82301
  if (stat8.mtimeMs > latestMtime) {
82028
82302
  latestMtime = stat8.mtimeMs;
@@ -82039,10 +82313,10 @@ async function handleKrakenWorkbench(ctx) {
82039
82313
  const parsed = parseWorkbench(content);
82040
82314
  const rendered = formatWorkbenchForTerminal(parsed);
82041
82315
  if (!rendered.trim()) {
82042
- appendSystem(ctx.setMessages, `[kraken workbench] ${path81.basename(latest)}: (no nodes / no events yet)`);
82316
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path82.basename(latest)}: (no nodes / no events yet)`);
82043
82317
  return;
82044
82318
  }
82045
- appendSystem(ctx.setMessages, `[kraken workbench] ${path81.basename(latest)}:
82319
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path82.basename(latest)}:
82046
82320
  ${rendered}`);
82047
82321
  }
82048
82322
 
@@ -82350,14 +82624,14 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
82350
82624
  init_messageHelpers();
82351
82625
  init_paths();
82352
82626
  import { promises as fs39 } from "node:fs";
82353
- import path84 from "node:path";
82627
+ import path85 from "node:path";
82354
82628
  async function handlePromoteMember(ctx, memberId) {
82355
82629
  try {
82356
82630
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
82357
82631
  const { skill, markdown } = promoteMember2(memberId);
82358
82632
  const skillDir = skillsDir();
82359
82633
  await fs39.mkdir(skillDir, { recursive: true });
82360
- const filePath = path84.join(skillDir, `${skill.id}.md`);
82634
+ const filePath = path85.join(skillDir, `${skill.id}.md`);
82361
82635
  const previous = await fs39.readFile(filePath, "utf8").catch(() => null);
82362
82636
  const { createHash: createHash24 } = await import("node:crypto");
82363
82637
  const sha = (s) => createHash24("sha256").update(s, "utf8").digest("hex");
@@ -82383,7 +82657,7 @@ ${lineage}
82383
82657
  // src/cli/branchManager.ts
82384
82658
  init_paths();
82385
82659
  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";
82660
+ import path86 from "node:path";
82387
82661
  var META_FILENAME = "meta.json";
82388
82662
  var SESSIONS_SUBDIR = "sessions";
82389
82663
  function getBranchesBaseDir() {
@@ -82393,13 +82667,13 @@ function getSessionsBaseDir() {
82393
82667
  return sessionsDir();
82394
82668
  }
82395
82669
  function branchPathFor(name, baseDir) {
82396
- return path85.join(baseDir, name);
82670
+ return path86.join(baseDir, name);
82397
82671
  }
82398
82672
  function metaPathFor(name, baseDir) {
82399
- return path85.join(baseDir, name, META_FILENAME);
82673
+ return path86.join(baseDir, name, META_FILENAME);
82400
82674
  }
82401
82675
  function sessionsPathFor(name, baseDir) {
82402
- return path85.join(baseDir, name, SESSIONS_SUBDIR);
82676
+ return path86.join(baseDir, name, SESSIONS_SUBDIR);
82403
82677
  }
82404
82678
  function readBranchMeta(name, baseDir) {
82405
82679
  const metaPath = metaPathFor(name, baseDir);
@@ -82424,7 +82698,7 @@ function readBranchMeta(name, baseDir) {
82424
82698
  }
82425
82699
  function writeBranchMeta(name, baseDir, meta3) {
82426
82700
  const metaPath = metaPathFor(name, baseDir);
82427
- mkdirSync21(path85.dirname(metaPath), { recursive: true });
82701
+ mkdirSync21(path86.dirname(metaPath), { recursive: true });
82428
82702
  writeFileSync24(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
82429
82703
  }
82430
82704
  async function countSessions(name, baseDir) {
@@ -82475,14 +82749,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
82475
82749
  if (branchExists(name, baseDir)) {
82476
82750
  throw new BranchAlreadyExistsError(name);
82477
82751
  }
82478
- const sourcePath = path85.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
82752
+ const sourcePath = path86.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
82479
82753
  if (!existsSync55(sourcePath)) {
82480
82754
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
82481
82755
  }
82482
82756
  const branchPath = branchPathFor(name, baseDir);
82483
82757
  const branchSessionsPath = sessionsPathFor(name, baseDir);
82484
82758
  mkdirSync21(branchSessionsPath, { recursive: true });
82485
- const destPath = path85.join(branchSessionsPath, `${fromSessionId}.jsonl`);
82759
+ const destPath = path86.join(branchSessionsPath, `${fromSessionId}.jsonl`);
82486
82760
  await fs40.copyFile(sourcePath, destPath);
82487
82761
  const meta3 = {
82488
82762
  name,
@@ -82586,14 +82860,14 @@ async function handleBranchCheckout(ctx, branchName) {
82586
82860
  // src/cli/slashHandlers/workspace.ts
82587
82861
  init_messageHelpers();
82588
82862
  import { promises as fs41 } from "node:fs";
82589
- import path86 from "node:path";
82863
+ import path87 from "node:path";
82590
82864
  async function handleWorkspaceShow(ctx, what) {
82591
82865
  try {
82592
- const zelari = path86.join(process.cwd(), ".zelari");
82866
+ const zelari = path87.join(process.cwd(), ".zelari");
82593
82867
  let content;
82594
82868
  switch (what) {
82595
82869
  case "plan": {
82596
- const planPath = path86.join(zelari, "plan.md");
82870
+ const planPath = path87.join(zelari, "plan.md");
82597
82871
  try {
82598
82872
  content = await fs41.readFile(planPath, "utf-8");
82599
82873
  } catch {
@@ -82602,7 +82876,7 @@ async function handleWorkspaceShow(ctx, what) {
82602
82876
  break;
82603
82877
  }
82604
82878
  case "decisions": {
82605
- const decisionsDir = path86.join(zelari, "decisions");
82879
+ const decisionsDir = path87.join(zelari, "decisions");
82606
82880
  try {
82607
82881
  const files = (await fs41.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
82608
82882
  if (files.length === 0) {
@@ -82612,7 +82886,7 @@ async function handleWorkspaceShow(ctx, what) {
82612
82886
  `];
82613
82887
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
82614
82888
  for (const f of files) {
82615
- const raw = await fs41.readFile(path86.join(decisionsDir, f), "utf-8");
82889
+ const raw = await fs41.readFile(path87.join(decisionsDir, f), "utf-8");
82616
82890
  const { meta: meta3, body } = parseFrontmatter2(raw);
82617
82891
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
82618
82892
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -82625,7 +82899,7 @@ async function handleWorkspaceShow(ctx, what) {
82625
82899
  break;
82626
82900
  }
82627
82901
  case "risks": {
82628
- const risksPath = path86.join(zelari, "risks.md");
82902
+ const risksPath = path87.join(zelari, "risks.md");
82629
82903
  try {
82630
82904
  content = await fs41.readFile(risksPath, "utf-8");
82631
82905
  } catch {
@@ -82634,7 +82908,7 @@ async function handleWorkspaceShow(ctx, what) {
82634
82908
  break;
82635
82909
  }
82636
82910
  case "agents": {
82637
- const agentsPath = path86.join(process.cwd(), "AGENTS.MD");
82911
+ const agentsPath = path87.join(process.cwd(), "AGENTS.MD");
82638
82912
  try {
82639
82913
  content = await fs41.readFile(agentsPath, "utf-8");
82640
82914
  } catch {
@@ -82643,7 +82917,7 @@ async function handleWorkspaceShow(ctx, what) {
82643
82917
  break;
82644
82918
  }
82645
82919
  case "docs": {
82646
- const docsDir = path86.join(zelari, "docs");
82920
+ const docsDir = path87.join(zelari, "docs");
82647
82921
  try {
82648
82922
  const files = (await fs41.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
82649
82923
  content = files.length ? `# Docs (${files.length})
@@ -82685,7 +82959,7 @@ async function handleWorkspaceReset(ctx, force) {
82685
82959
  return;
82686
82960
  }
82687
82961
  try {
82688
- const target = path86.join(process.cwd(), ".zelari");
82962
+ const target = path87.join(process.cwd(), ".zelari");
82689
82963
  await fs41.rm(target, { recursive: true, force: true });
82690
82964
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
82691
82965
  } catch (err) {
@@ -84569,8 +84843,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
84569
84843
  let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
84570
84844
  if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
84571
84845
  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";
84846
+ 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);
84847
+ name = path101 && /^[a-z0-9]/.test(path101) ? path101 : "imported-skill";
84574
84848
  } catch {
84575
84849
  name = "imported-skill";
84576
84850
  }
@@ -84983,7 +85257,7 @@ proposals: npm run evolve:propose \u2014 decisions in npm run evolve:decide (P1:
84983
85257
  }
84984
85258
  if (argv.includes("--help") || argv.includes("-h")) {
84985
85259
  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"
85260
+ "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
85261
  );
84988
85262
  process.exit(0);
84989
85263
  }