zelari-code 2.36.0 → 2.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3482,10 +3482,10 @@ function mergeDefs(...defs) {
3482
3482
  function cloneDef(schema) {
3483
3483
  return mergeDefs(schema._zod.def);
3484
3484
  }
3485
- function getElementAtPath(obj, path100) {
3486
- if (!path100)
3485
+ function getElementAtPath(obj, path101) {
3486
+ if (!path101)
3487
3487
  return obj;
3488
- return path100.reduce((acc, key) => acc?.[key], obj);
3488
+ return path101.reduce((acc, key) => acc?.[key], obj);
3489
3489
  }
3490
3490
  function promiseAllObject(promisesObj) {
3491
3491
  const keys = Object.keys(promisesObj);
@@ -3813,11 +3813,11 @@ function explicitlyAborted(x, startIndex = 0) {
3813
3813
  }
3814
3814
  return false;
3815
3815
  }
3816
- function prefixIssues(path100, issues) {
3816
+ function prefixIssues(path101, issues) {
3817
3817
  return issues.map((iss) => {
3818
3818
  var _a3;
3819
3819
  (_a3 = iss).path ?? (_a3.path = []);
3820
- iss.path.unshift(path100);
3820
+ iss.path.unshift(path101);
3821
3821
  return iss;
3822
3822
  });
3823
3823
  }
@@ -4035,16 +4035,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
4035
4035
  }
4036
4036
  function formatError(error51, mapper = (issue2) => issue2.message) {
4037
4037
  const fieldErrors = { _errors: [] };
4038
- const processError = (error52, path100 = []) => {
4038
+ const processError = (error52, path101 = []) => {
4039
4039
  for (const issue2 of error52.issues) {
4040
4040
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4041
- issue2.errors.map((issues) => processError({ issues }, [...path100, ...issue2.path]));
4041
+ issue2.errors.map((issues) => processError({ issues }, [...path101, ...issue2.path]));
4042
4042
  } else if (issue2.code === "invalid_key") {
4043
- processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4043
+ processError({ issues: issue2.issues }, [...path101, ...issue2.path]);
4044
4044
  } else if (issue2.code === "invalid_element") {
4045
- processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4045
+ processError({ issues: issue2.issues }, [...path101, ...issue2.path]);
4046
4046
  } else {
4047
- const fullpath = [...path100, ...issue2.path];
4047
+ const fullpath = [...path101, ...issue2.path];
4048
4048
  if (fullpath.length === 0) {
4049
4049
  fieldErrors._errors.push(mapper(issue2));
4050
4050
  } else {
@@ -4071,17 +4071,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
4071
4071
  }
4072
4072
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
4073
4073
  const result = { errors: [] };
4074
- const processError = (error52, path100 = []) => {
4074
+ const processError = (error52, path101 = []) => {
4075
4075
  var _a3, _b;
4076
4076
  for (const issue2 of error52.issues) {
4077
4077
  if (issue2.code === "invalid_union" && issue2.errors.length) {
4078
- issue2.errors.map((issues) => processError({ issues }, [...path100, ...issue2.path]));
4078
+ issue2.errors.map((issues) => processError({ issues }, [...path101, ...issue2.path]));
4079
4079
  } else if (issue2.code === "invalid_key") {
4080
- processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4080
+ processError({ issues: issue2.issues }, [...path101, ...issue2.path]);
4081
4081
  } else if (issue2.code === "invalid_element") {
4082
- processError({ issues: issue2.issues }, [...path100, ...issue2.path]);
4082
+ processError({ issues: issue2.issues }, [...path101, ...issue2.path]);
4083
4083
  } else {
4084
- const fullpath = [...path100, ...issue2.path];
4084
+ const fullpath = [...path101, ...issue2.path];
4085
4085
  if (fullpath.length === 0) {
4086
4086
  result.errors.push(mapper(issue2));
4087
4087
  continue;
@@ -4113,8 +4113,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
4113
4113
  }
4114
4114
  function toDotPath(_path) {
4115
4115
  const segs = [];
4116
- const path100 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4117
- for (const seg of path100) {
4116
+ const path101 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
4117
+ for (const seg of path101) {
4118
4118
  if (typeof seg === "number")
4119
4119
  segs.push(`[${seg}]`);
4120
4120
  else if (typeof seg === "symbol")
@@ -17617,13 +17617,13 @@ function resolveRef(ref, ctx) {
17617
17617
  if (!ref.startsWith("#")) {
17618
17618
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
17619
17619
  }
17620
- const path100 = ref.slice(1).split("/").filter(Boolean);
17621
- if (path100.length === 0) {
17620
+ const path101 = ref.slice(1).split("/").filter(Boolean);
17621
+ if (path101.length === 0) {
17622
17622
  return ctx.rootSchema;
17623
17623
  }
17624
17624
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
17625
- if (path100[0] === defsKey) {
17626
- const key = path100[1];
17625
+ if (path101[0] === defsKey) {
17626
+ const key = path101[1];
17627
17627
  if (!key || !ctx.defs[key]) {
17628
17628
  throw new Error(`Reference not found: ${ref}`);
17629
17629
  }
@@ -18457,17 +18457,17 @@ var init_newlines = __esm({
18457
18457
  });
18458
18458
 
18459
18459
  // packages/core/dist/core/tools/builtin/fileEvents.js
18460
- function fileReadEvent(path100, snapshotId) {
18461
- return { kind: "file.read", actor: { type: "tool" }, data: { path: path100, snapshotId } };
18460
+ function fileReadEvent(path101, snapshotId) {
18461
+ return { kind: "file.read", actor: { type: "tool" }, data: { path: path101, snapshotId } };
18462
18462
  }
18463
- function fileAppliedEvent(path100, snapshotId, bytes) {
18464
- return { kind: "file.applied", actor: { type: "tool" }, data: { path: path100, snapshotId, bytes } };
18463
+ function fileAppliedEvent(path101, snapshotId, bytes) {
18464
+ return { kind: "file.applied", actor: { type: "tool" }, data: { path: path101, snapshotId, bytes } };
18465
18465
  }
18466
- function fileRejectedEvent(path100, reason, hint) {
18466
+ function fileRejectedEvent(path101, reason, hint) {
18467
18467
  return {
18468
18468
  kind: "file.rejected",
18469
18469
  actor: { type: "tool" },
18470
- data: hint === void 0 ? { path: path100, reason } : { path: path100, reason, hint }
18470
+ data: hint === void 0 ? { path: path101, reason } : { path: path101, reason, hint }
18471
18471
  };
18472
18472
  }
18473
18473
  function reReadHint(reject) {
@@ -20336,11 +20336,11 @@ var init_tools = __esm({
20336
20336
  if (!ctx.addDocument)
20337
20337
  return "Knowledge vault tool not available.";
20338
20338
  const title = args["title"] || "New Document";
20339
- const path100 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20339
+ const path101 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
20340
20340
  const content = args["content"] || "";
20341
20341
  const tags = args["tags"] || [];
20342
20342
  ctx.addDocument({
20343
- path: path100,
20343
+ path: path101,
20344
20344
  title,
20345
20345
  content,
20346
20346
  format: "markdown",
@@ -20349,7 +20349,7 @@ var init_tools = __esm({
20349
20349
  workspaceId: ctx.workspaceId
20350
20350
  });
20351
20351
  ctx.addActivity("vault", "created document", title);
20352
- return `Document "${title}" created at "${path100}".`;
20352
+ return `Document "${title}" created at "${path101}".`;
20353
20353
  }
20354
20354
  }
20355
20355
  ];
@@ -22036,7 +22036,20 @@ function evaluateKrakenCompletionGate(mode) {
22036
22036
  };
22037
22037
  }
22038
22038
  }
22039
- function buildKrakenRepairPrompt(gate) {
22039
+ function excerptEntries(excerpts) {
22040
+ if (!excerpts) return [];
22041
+ return excerpts instanceof Map ? [...excerpts.entries()] : Object.entries(excerpts);
22042
+ }
22043
+ function excerptBlock(name, raw) {
22044
+ const trimmed = raw.trim();
22045
+ const truncated = trimmed.length > REPAIR_FAIL_EXCERPT_CAP;
22046
+ const tail2 = truncated ? trimmed.slice(trimmed.length - REPAIR_FAIL_EXCERPT_CAP) : trimmed;
22047
+ const lines = [`Failure excerpt (tail, capped ${REPAIR_FAIL_EXCERPT_CAP} chars) \u2014 ${name}:`];
22048
+ if (truncated) lines.push(`\u2026[truncated ${trimmed.length - REPAIR_FAIL_EXCERPT_CAP} chars]`);
22049
+ lines.push(tail2, "");
22050
+ return lines;
22051
+ }
22052
+ function buildKrakenRepairPrompt(gate, excerpts) {
22040
22053
  const lines = [
22041
22054
  `The BUILD turn is ending, but the required checks from kraken_select are not all satisfied (passed ${gate.passed}/${gate.total}).`,
22042
22055
  ""
@@ -22053,6 +22066,36 @@ function buildKrakenRepairPrompt(gate) {
22053
22066
  for (const check2 of gate.unknownChecks) lines.push(`- ${check2}`);
22054
22067
  lines.push("");
22055
22068
  }
22069
+ const entries = excerptEntries(excerpts);
22070
+ if (entries.length > 0) {
22071
+ const byName = new Map(entries);
22072
+ const used = /* @__PURE__ */ new Set();
22073
+ const blocks = [];
22074
+ let emitted = 0;
22075
+ for (const check2 of [...gate.failedChecks, ...gate.unknownChecks]) {
22076
+ if (emitted >= MAX_REPAIR_EXCERPTS) break;
22077
+ const raw = byName.get(check2);
22078
+ if (raw === void 0 || used.has(check2)) continue;
22079
+ used.add(check2);
22080
+ blocks.push(excerptBlock(check2, raw));
22081
+ emitted += 1;
22082
+ }
22083
+ let leadInPushed = false;
22084
+ for (const [name, raw] of entries) {
22085
+ if (emitted >= MAX_REPAIR_EXCERPTS) break;
22086
+ if (used.has(name)) continue;
22087
+ if (!leadInPushed) {
22088
+ blocks.push([
22089
+ "DETERMINISTIC check failures with captured output (criteria pack / task contract):",
22090
+ ""
22091
+ ]);
22092
+ leadInPushed = true;
22093
+ }
22094
+ blocks.push(excerptBlock(name, raw));
22095
+ emitted += 1;
22096
+ }
22097
+ for (const block of blocks) lines.push(...block);
22098
+ }
22056
22099
  lines.push(
22057
22100
  "Recover this turn:",
22058
22101
  "1. The approach selection is settled \u2014 do NOT call kraken_select again.",
@@ -22063,7 +22106,7 @@ function buildKrakenRepairPrompt(gate) {
22063
22106
  );
22064
22107
  return lines.join("\n");
22065
22108
  }
22066
- var OPEN_GATE;
22109
+ var OPEN_GATE, REPAIR_FAIL_EXCERPT_CAP, MAX_REPAIR_EXCERPTS;
22067
22110
  var init_completionGate = __esm({
22068
22111
  "src/cli/kraken/completionGate.ts"() {
22069
22112
  "use strict";
@@ -22076,6 +22119,8 @@ var init_completionGate = __esm({
22076
22119
  failedChecks: [],
22077
22120
  unknownChecks: []
22078
22121
  };
22122
+ REPAIR_FAIL_EXCERPT_CAP = 2e3;
22123
+ MAX_REPAIR_EXCERPTS = 5;
22079
22124
  }
22080
22125
  });
22081
22126
 
@@ -25174,16 +25219,16 @@ function runRetentionFromEnv() {
25174
25219
  maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
25175
25220
  };
25176
25221
  }
25177
- async function dirSize(path100) {
25222
+ async function dirSize(path101) {
25178
25223
  let total = 0;
25179
25224
  let entries;
25180
25225
  try {
25181
- entries = await readdir(path100, { withFileTypes: true });
25226
+ entries = await readdir(path101, { withFileTypes: true });
25182
25227
  } catch {
25183
25228
  return 0;
25184
25229
  }
25185
25230
  for (const entry of entries) {
25186
- const child = join3(path100, entry.name);
25231
+ const child = join3(path101, entry.name);
25187
25232
  if (entry.isDirectory())
25188
25233
  total += await dirSize(child);
25189
25234
  else {
@@ -25210,19 +25255,19 @@ async function enforceRunRetention(runsDir, options = {}) {
25210
25255
  for (const entry of entries) {
25211
25256
  if (!entry.isDirectory())
25212
25257
  continue;
25213
- const path100 = join3(runsDir, entry.name);
25258
+ const path101 = join3(runsDir, entry.name);
25214
25259
  let startedAt = 0;
25215
25260
  let endedAt;
25216
25261
  let completed = false;
25217
25262
  try {
25218
- const manifest = JSON.parse(await readFile(join3(path100, "manifest.json"), "utf8"));
25263
+ const manifest = JSON.parse(await readFile(join3(path101, "manifest.json"), "utf8"));
25219
25264
  startedAt = manifest.startedAt ?? 0;
25220
25265
  endedAt = manifest.endedAt;
25221
25266
  completed = Boolean(endedAt) && manifest.status !== "running";
25222
25267
  } catch {
25223
25268
  completed = false;
25224
25269
  }
25225
- infos.push({ name: entry.name, path: path100, startedAt, endedAt, completed, bytes: await dirSize(path100) });
25270
+ infos.push({ name: entry.name, path: path101, startedAt, endedAt, completed, bytes: await dirSize(path101) });
25226
25271
  }
25227
25272
  const remove = async (info) => {
25228
25273
  await rm(info.path, { recursive: true, force: true });
@@ -25709,12 +25754,12 @@ var init_engine = __esm({
25709
25754
  * content digest) and the returned ref carries the event seq when the
25710
25755
  * emitter resolved one.
25711
25756
  */
25712
- async fsEvidence(observation, path100, sha256, content, extra = {}) {
25757
+ async fsEvidence(observation, path101, sha256, content, extra = {}) {
25713
25758
  const digest = sha256 && content !== void 0 ? sha256(content) : void 0;
25714
- const seq = await this.emitEvidence({ observation, path: path100, ...extra, ...digest ? { digest } : {} });
25759
+ const seq = await this.emitEvidence({ observation, path: path101, ...extra, ...digest ? { digest } : {} });
25715
25760
  return {
25716
25761
  tier: "fs-observation",
25717
- ref: path100,
25762
+ ref: path101,
25718
25763
  capturedAt: Date.now(),
25719
25764
  ...digest ? { digest } : {},
25720
25765
  ...seq !== void 0 ? { seq } : {}
@@ -27184,11 +27229,14 @@ var init_contractCompiler = __esm({
27184
27229
  var verificationBridge_exports = {};
27185
27230
  __export(verificationBridge_exports, {
27186
27231
  STRICT_DONE_EXIT_CODE: () => STRICT_DONE_EXIT_CODE,
27232
+ allowUnverified: () => allowUnverified,
27187
27233
  anchorSelectionEvidence: () => anchorSelectionEvidence,
27188
27234
  evaluateStrictBuildGate: () => evaluateStrictBuildGate,
27189
27235
  evaluateStrictBuildGateFromSession: () => evaluateStrictBuildGateFromSession,
27190
27236
  krakenResultsToContract: () => krakenResultsToContract,
27191
27237
  matchNoteToToolTrace: () => matchNoteToToolTrace,
27238
+ missionClaimExitCode: () => missionClaimExitCode,
27239
+ repairExcerptsFromEvaluation: () => repairExcerptsFromEvaluation,
27192
27240
  strictDoneEnabled: () => strictDoneEnabled,
27193
27241
  strictEnvOverlay: () => strictEnvOverlay,
27194
27242
  strictGateEventPayload: () => strictGateEventPayload,
@@ -27224,20 +27272,20 @@ function criterionId(check2, index) {
27224
27272
  function normalize3(text) {
27225
27273
  return text.toLowerCase().replace(/\s+/g, " ").trim();
27226
27274
  }
27227
- function matchResult(check2, byNormalized) {
27228
- const norm = normalize3(check2);
27229
- const direct = byNormalized.get(norm);
27230
- if (direct) return direct;
27231
- for (const key of byNormalized.keys()) {
27232
- if (key.length >= 8 && (key.includes(norm) || norm.includes(key))) {
27233
- return byNormalized.get(key);
27234
- }
27275
+ function matchResult(check2, byNormalized, byId, id3) {
27276
+ if (byId && id3) {
27277
+ const byCriterion = byId.get(id3);
27278
+ if (byCriterion) return byCriterion;
27235
27279
  }
27236
- return void 0;
27280
+ return byNormalized.get(normalize3(check2));
27237
27281
  }
27238
27282
  function krakenResultsToContract(requiredChecks, results, now = Date.now()) {
27239
27283
  const byNormalized = /* @__PURE__ */ new Map();
27240
- for (const r of results ?? []) byNormalized.set(normalize3(r.check), r);
27284
+ const byId = /* @__PURE__ */ new Map();
27285
+ for (const r of results ?? []) {
27286
+ byNormalized.set(normalize3(r.check), r);
27287
+ if (r.criterionId) byId.set(r.criterionId, r);
27288
+ }
27241
27289
  const criteria = [];
27242
27290
  const verifications = [];
27243
27291
  requiredChecks.forEach((check2, i) => {
@@ -27247,12 +27295,12 @@ function krakenResultsToContract(requiredChecks, results, now = Date.now()) {
27247
27295
  text: check2,
27248
27296
  source: "kraken-selection",
27249
27297
  required: true,
27250
- check: { kind: "none", reason: "verified by verify tentacle report" }
27298
+ check: { kind: "none", reason: "verify tentacle proposal \u2014 runtime evidence required" }
27251
27299
  });
27252
- const reported = matchResult(check2, byNormalized);
27300
+ const reported = matchResult(check2, byNormalized, byId, id3);
27253
27301
  const evidence = reported?.note && reported.note.trim().length > 0 ? [
27254
27302
  {
27255
- tier: "tool-output",
27303
+ tier: "verifier-llm",
27256
27304
  ref: reported.note.trim().slice(0, 500),
27257
27305
  capturedAt: now
27258
27306
  }
@@ -27299,12 +27347,12 @@ async function anchorSelectionEvidence(results, emit, toolTrace) {
27299
27347
  for (const r of results) {
27300
27348
  for (const ev of r.evidence) {
27301
27349
  if (ev.seq !== void 0) continue;
27302
- if (ev.tier === "verifier-llm" || ev.tier === "human") continue;
27350
+ if (ev.tier === "human") continue;
27303
27351
  try {
27304
27352
  const match = toolTrace && toolTrace.length > 0 ? matchNoteToToolTrace(ev.ref, toolTrace) : null;
27305
27353
  if (match) {
27306
27354
  const digest = sha256Hex2(match.output);
27307
- const appended2 = await emit({
27355
+ const appended = await emit({
27308
27356
  kind: "verification.evidence",
27309
27357
  actor: { type: "system", role: "verification" },
27310
27358
  data: {
@@ -27320,16 +27368,17 @@ async function anchorSelectionEvidence(results, emit, toolTrace) {
27320
27368
  ...match.command ? { command: match.command } : {}
27321
27369
  }
27322
27370
  });
27323
- const toolSeq = appended2 && typeof appended2 === "object" && "seq" in appended2 ? Number(appended2.seq) : NaN;
27371
+ const toolSeq = appended && typeof appended === "object" && "seq" in appended ? Number(appended.seq) : NaN;
27324
27372
  if (Number.isFinite(toolSeq) && toolSeq > 0) {
27325
27373
  ev.seq = toolSeq;
27326
27374
  ev.digest = digest;
27375
+ ev.tier = "tool-output";
27327
27376
  ev.ref = `${match.tool}${match.command ? ` ${match.command}` : ""} \u2192 ${match.ok ? "ok" : "error"} @seq`;
27328
27377
  counts.toolResultAnchored += 1;
27329
27378
  }
27330
27379
  continue;
27331
27380
  }
27332
- const appended = await emit({
27381
+ await emit({
27333
27382
  kind: "verification.evidence",
27334
27383
  actor: { type: "system", role: "verification" },
27335
27384
  data: {
@@ -27337,14 +27386,11 @@ async function anchorSelectionEvidence(results, emit, toolTrace) {
27337
27386
  provenance: "note-fallback",
27338
27387
  criterionId: r.criterionId,
27339
27388
  ref: ev.ref,
27340
- tier: ev.tier
27389
+ tier: ev.tier,
27390
+ anchored: false
27341
27391
  }
27342
27392
  });
27343
- const seq = appended && typeof appended === "object" && "seq" in appended ? Number(appended.seq) : NaN;
27344
- if (Number.isFinite(seq) && seq > 0) {
27345
- ev.seq = seq;
27346
- counts.noteFallback += 1;
27347
- }
27393
+ counts.noteFallback += 1;
27348
27394
  } catch {
27349
27395
  }
27350
27396
  }
@@ -27358,7 +27404,8 @@ async function evaluateStrictBuildGate(mode, options = {}) {
27358
27404
  const selectionAvailable = gate.selectionUsed && gate.total > 0;
27359
27405
  const scopeContract = options.taskContract ?? activeContractScope()?.contract;
27360
27406
  const contractPlan = scopeContract ? compileVerificationCriteria(scopeContract) : [];
27361
- if (!selectionAvailable && !nativeOn && contractPlan.length === 0 || !strictOn && !nativeOn) {
27407
+ const nothingBindable = !selectionAvailable && !nativeOn && contractPlan.length === 0;
27408
+ if (!strictOn && !nativeOn) {
27362
27409
  return {
27363
27410
  gate,
27364
27411
  strict: false,
@@ -27368,6 +27415,17 @@ async function evaluateStrictBuildGate(mode, options = {}) {
27368
27415
  summary: gate.blocked ? `blocked: ${gate.failedChecks.length} failed, ${gate.unknownChecks.length} unknown` : "open"
27369
27416
  };
27370
27417
  }
27418
+ if (nothingBindable) {
27419
+ return {
27420
+ gate,
27421
+ strict: true,
27422
+ unverified: true,
27423
+ evaluation: null,
27424
+ native: null,
27425
+ blocked: true,
27426
+ summary: "unverified (strict on: no criteria \u2014 pack off/unbound, no selection contract, no task contract)"
27427
+ };
27428
+ }
27371
27429
  const checks = selectionAvailable ? krakenRequiredChecks() : [];
27372
27430
  const contract = selectionAvailable ? krakenResultsToContract(checks, getKrakenCheckResults()) : { criteria: [], results: [] };
27373
27431
  const anchoring = await anchorSelectionEvidence(
@@ -27389,6 +27447,19 @@ async function evaluateStrictBuildGate(mode, options = {}) {
27389
27447
  const allCriteria = [...contract.criteria, ...native?.criteria ?? [], ...compiled?.criteria ?? []];
27390
27448
  const allResults = [...contract.results, ...native?.results ?? [], ...compiled?.results ?? []];
27391
27449
  if (allCriteria.length === 0) {
27450
+ if (strictOn) {
27451
+ return {
27452
+ gate,
27453
+ strict: true,
27454
+ unverified: true,
27455
+ evaluation: null,
27456
+ native,
27457
+ compiled,
27458
+ results: allResults,
27459
+ blocked: true,
27460
+ summary: "unverified (strict on: native pack bound no command, no selection contract)"
27461
+ };
27462
+ }
27392
27463
  return {
27393
27464
  gate,
27394
27465
  strict: false,
@@ -27414,14 +27485,51 @@ async function evaluateStrictBuildGate(mode, options = {}) {
27414
27485
  summary: blocked ? `blocked (strict ${evaluation?.verdict ?? "n/a"}): ${legacyPart}evidence ${evaluation?.evidenceComplete ? "complete" : "incomplete"}` : `open (strict PASS): ${evaluation?.satisfied.length ?? 0}/${allCriteria.length} criteria pass with evidence`
27415
27486
  };
27416
27487
  }
27417
- function strictGateExitCode(evaluation) {
27418
- return evaluation.strict && evaluation.blocked ? STRICT_DONE_EXIT_CODE : 0;
27488
+ function repairExcerptsFromEvaluation(evaluation) {
27489
+ const excerpts = /* @__PURE__ */ new Map();
27490
+ const nameById = /* @__PURE__ */ new Map();
27491
+ for (const c of [...evaluation.native?.criteria ?? [], ...evaluation.compiled?.criteria ?? []]) {
27492
+ nameById.set(c.id, c.text);
27493
+ }
27494
+ try {
27495
+ krakenRequiredChecks().forEach((text, i) => {
27496
+ if (!nameById.has(criterionId(text, i))) nameById.set(criterionId(text, i), text);
27497
+ });
27498
+ } catch {
27499
+ }
27500
+ for (const r of evaluation.results ?? []) {
27501
+ if (r.status === "pass") continue;
27502
+ const detail = r.detail?.trim();
27503
+ if (!detail) continue;
27504
+ excerpts.set(nameById.get(r.criterionId) ?? r.criterionId, detail);
27505
+ }
27506
+ return excerpts;
27507
+ }
27508
+ function allowUnverified(env = process.env) {
27509
+ const v = env.ZELARI_ALLOW_UNVERIFIED?.toLowerCase();
27510
+ return v === "1" || v === "true" || v === "yes" || v === "on";
27511
+ }
27512
+ function strictGateExitCode(evaluation, env = process.env) {
27513
+ if (evaluation.strict && evaluation.blocked) {
27514
+ if (evaluation.unverified && allowUnverified(env)) return 0;
27515
+ return STRICT_DONE_EXIT_CODE;
27516
+ }
27517
+ return 0;
27518
+ }
27519
+ function missionClaimExitCode(evidenceCount, env = process.env) {
27520
+ if (evidenceCount < 0) return 0;
27521
+ if (evidenceCount > 0) return 0;
27522
+ if (allowUnverified(env)) return 0;
27523
+ return STRICT_DONE_EXIT_CODE;
27419
27524
  }
27420
27525
  function strictGateEventPayload(evaluation) {
27421
27526
  return {
27422
27527
  engine: evaluation.native ? "kraken-legacy+completion-policy+criteria-pack" : "kraken-legacy+completion-policy",
27423
27528
  strict: evaluation.strict,
27424
27529
  verdict: evaluation.evaluation?.verdict ?? (evaluation.blocked ? "BLOCKED" : "PASS"),
27530
+ // M1.2: UNVERIFIED marker — strict on, nothing evaluable. Present only
27531
+ // when true so historical payloads stay byte-identical.
27532
+ ...evaluation.unverified ? { unverified: true } : {},
27425
27533
  legacy: {
27426
27534
  total: evaluation.gate.total,
27427
27535
  passed: evaluation.gate.passed,
@@ -31734,11 +31842,11 @@ var init_synthesisAudit = __esm({
31734
31842
  import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
31735
31843
  import { join as join5 } from "node:path";
31736
31844
  function loadNfrSpec(zelariRoot) {
31737
- const path100 = join5(zelariRoot, "nfr-spec.json");
31738
- if (!existsSync10(path100))
31845
+ const path101 = join5(zelariRoot, "nfr-spec.json");
31846
+ if (!existsSync10(path101))
31739
31847
  return null;
31740
31848
  try {
31741
- const raw = JSON.parse(readFileSync9(path100, "utf8"));
31849
+ const raw = JSON.parse(readFileSync9(path101, "utf8"));
31742
31850
  if (raw.version !== 1 || !Array.isArray(raw.targets))
31743
31851
  return null;
31744
31852
  return raw;
@@ -33854,10 +33962,28 @@ function buildMissionBrief(input) {
33854
33962
  ],
33855
33963
  phases,
33856
33964
  sliceMvp,
33857
- slices: [sliceMvp],
33965
+ slices: buildSlicePlan(sliceMvp, input.planTaskIds, maxTasks),
33858
33966
  userPromptOriginal: userMessage
33859
33967
  };
33860
33968
  }
33969
+ function buildSlicePlan(sliceMvp, planTaskIds, maxTasks) {
33970
+ const ids = Array.isArray(planTaskIds) ? planTaskIds.filter((t) => typeof t === "string" && t) : [];
33971
+ if (ids.length === 0)
33972
+ return [{ ...sliceMvp }];
33973
+ const size = Number.isFinite(maxTasks) && maxTasks > 0 ? Math.floor(maxTasks) : 8;
33974
+ const slices = [];
33975
+ for (let i = 0; i < ids.length; i += size) {
33976
+ const chunk = ids.slice(i, i + size);
33977
+ const index = i / size;
33978
+ slices.push(index === 0 ? { ...sliceMvp, taskIds: chunk, maxTasks: size } : {
33979
+ id: `slice-${index + 1}`,
33980
+ title: `Increment ${index + 1} \u2014 ${chunk.length} plan task(s)`,
33981
+ taskIds: chunk,
33982
+ maxTasks: size
33983
+ });
33984
+ }
33985
+ return slices;
33986
+ }
33861
33987
  var STACK_SIGNALS;
33862
33988
  var init_missionBrief = __esm({
33863
33989
  "packages/core/dist/council/missionBrief.js"() {
@@ -34121,9 +34247,9 @@ var init_types9 = __esm({
34121
34247
  import { readFileSync as readFileSync14 } from "node:fs";
34122
34248
  import { join as join11 } from "node:path";
34123
34249
  function readLessonsDeduped(zelariRoot) {
34124
- const path100 = join11(zelariRoot, LESSONS_FILE);
34250
+ const path101 = join11(zelariRoot, LESSONS_FILE);
34125
34251
  try {
34126
- const raw = readFileSync14(path100, "utf8");
34252
+ const raw = readFileSync14(path101, "utf8");
34127
34253
  const byId = /* @__PURE__ */ new Map();
34128
34254
  for (const line of raw.split(/\r?\n/)) {
34129
34255
  if (!line.trim())
@@ -34224,8 +34350,8 @@ function keywordsFrom(check2, signature) {
34224
34350
  return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
34225
34351
  }
34226
34352
  function writeLesson(zelariRoot, lesson) {
34227
- const path100 = join12(zelariRoot, LESSONS_FILE);
34228
- appendFileSync(path100, `${JSON.stringify(lesson)}
34353
+ const path101 = join12(zelariRoot, LESSONS_FILE);
34354
+ appendFileSync(path101, `${JSON.stringify(lesson)}
34229
34355
  `, "utf8");
34230
34356
  }
34231
34357
  function findSimilar(lessons, signature) {
@@ -34682,6 +34808,7 @@ __export(council_exports, {
34682
34808
  buildMotionFixPrompt: () => buildMotionFixPrompt,
34683
34809
  buildRetryPrompt: () => buildRetryPrompt,
34684
34810
  buildSkillDefinition: () => buildSkillDefinition,
34811
+ buildSlicePlan: () => buildSlicePlan,
34685
34812
  buildSystemPrompt: () => buildSystemPrompt,
34686
34813
  buildSystemPromptSplit: () => buildSystemPromptSplit,
34687
34814
  captureFailure: () => captureFailure,
@@ -36192,9 +36319,9 @@ function findCycle(nodes) {
36192
36319
  if (color.get(start) !== WHITE)
36193
36320
  continue;
36194
36321
  const stack = [[start, 0]];
36195
- const path100 = [];
36322
+ const path101 = [];
36196
36323
  color.set(start, GRAY);
36197
- path100.push(start);
36324
+ path101.push(start);
36198
36325
  while (stack.length > 0) {
36199
36326
  const top = stack[stack.length - 1];
36200
36327
  const [id3, idx] = top;
@@ -36207,17 +36334,17 @@ function findCycle(nodes) {
36207
36334
  continue;
36208
36335
  const c = color.get(dep);
36209
36336
  if (c === GRAY) {
36210
- const at = path100.indexOf(dep);
36211
- return [...path100.slice(at), dep];
36337
+ const at = path101.indexOf(dep);
36338
+ return [...path101.slice(at), dep];
36212
36339
  }
36213
36340
  if (c === WHITE) {
36214
36341
  color.set(dep, GRAY);
36215
- path100.push(dep);
36342
+ path101.push(dep);
36216
36343
  stack.push([dep, 0]);
36217
36344
  }
36218
36345
  } else {
36219
36346
  color.set(id3, BLACK);
36220
- path100.pop();
36347
+ path101.pop();
36221
36348
  stack.pop();
36222
36349
  }
36223
36350
  }
@@ -37137,8 +37264,8 @@ var init_runner = __esm({
37137
37264
  failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
37138
37265
  pending: []
37139
37266
  };
37140
- const path100 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
37141
- 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}`);
37142
37269
  return snapshot;
37143
37270
  }
37144
37271
  callLog(msg, data) {
@@ -38289,7 +38416,7 @@ var CORE_VERSION;
38289
38416
  var init_version = __esm({
38290
38417
  "packages/core/dist/version.js"() {
38291
38418
  "use strict";
38292
- CORE_VERSION = "2.36.0";
38419
+ CORE_VERSION = "2.37.1";
38293
38420
  }
38294
38421
  });
38295
38422
 
@@ -38539,6 +38666,7 @@ __export(dist_exports, {
38539
38666
  buildRetryPrompt: () => buildRetryPrompt,
38540
38667
  buildRuntimeObserverBus: () => buildRuntimeObserverBus,
38541
38668
  buildSkillDefinition: () => buildSkillDefinition,
38669
+ buildSlicePlan: () => buildSlicePlan,
38542
38670
  buildSystemPrompt: () => buildSystemPrompt,
38543
38671
  buildSystemPromptSplit: () => buildSystemPromptSplit,
38544
38672
  canExternalClientMutate: () => canExternalClientMutate,
@@ -40747,9 +40875,9 @@ function spillToolOutput(fullText, meta3) {
40747
40875
  const rnd = randomBytes3(3).toString("hex");
40748
40876
  const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
40749
40877
  const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
40750
- const path100 = join14(dir, file2);
40751
- writeFileSync12(path100, fullText, "utf8");
40752
- return path100;
40878
+ const path101 = join14(dir, file2);
40879
+ writeFileSync12(path101, fullText, "utf8");
40880
+ return path101;
40753
40881
  } catch {
40754
40882
  return null;
40755
40883
  }
@@ -40795,10 +40923,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
40795
40923
  ${tail2}`;
40796
40924
  }
40797
40925
  if (doSpill) {
40798
- const path100 = spillToolOutput(text, { toolName: opts.toolName });
40799
- if (path100) {
40926
+ const path101 = spillToolOutput(text, { toolName: opts.toolName });
40927
+ if (path101) {
40800
40928
  const spillNote = `
40801
- \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`;
40802
40930
  if (preview.includes("] \u2026\n")) {
40803
40931
  preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
40804
40932
  `);
@@ -41569,28 +41697,28 @@ var init_storage = __esm({
41569
41697
  VALID_SCALARS = /^(true|false|null|~)$/i;
41570
41698
  Storage = class {
41571
41699
  /** Read a Markdown file with frontmatter. Throws if not found. */
41572
- read(path100) {
41573
- if (!existsSync19(path100)) {
41574
- throw new Error(`File not found: ${path100}`);
41700
+ read(path101) {
41701
+ if (!existsSync19(path101)) {
41702
+ throw new Error(`File not found: ${path101}`);
41575
41703
  }
41576
- const md = readFileSync17(path100, "utf8");
41704
+ const md = readFileSync17(path101, "utf8");
41577
41705
  return parseFrontmatter(md);
41578
41706
  }
41579
41707
  /** Read a Markdown file; returns null if not found. */
41580
- readIfExists(path100) {
41581
- if (!existsSync19(path100)) return null;
41582
- return this.read(path100);
41708
+ readIfExists(path101) {
41709
+ if (!existsSync19(path101)) return null;
41710
+ return this.read(path101);
41583
41711
  }
41584
41712
  /**
41585
41713
  * Write a Markdown file atomically (tmp + rename). Creates parent dirs.
41586
41714
  * The meta object is serialized as YAML frontmatter; body as Markdown.
41587
41715
  */
41588
- write(path100, meta3, body) {
41589
- mkdirSync10(dirname2(path100), { recursive: true });
41590
- const tmp = path100 + ".tmp-" + process.pid;
41716
+ write(path101, meta3, body) {
41717
+ mkdirSync10(dirname2(path101), { recursive: true });
41718
+ const tmp = path101 + ".tmp-" + process.pid;
41591
41719
  const md = serializeFrontmatter(meta3, body);
41592
41720
  writeFileSync14(tmp, md, "utf8");
41593
- renameSync2(tmp, path100);
41721
+ renameSync2(tmp, path101);
41594
41722
  }
41595
41723
  /** List all .md files in a directory (non-recursive). */
41596
41724
  listMarkdown(dir) {
@@ -41625,6 +41753,24 @@ var init_storage = __esm({
41625
41753
  });
41626
41754
 
41627
41755
  // src/cli/workspace/planStore.ts
41756
+ var planStore_exports = {};
41757
+ __export(planStore_exports, {
41758
+ PLAN_FILES_MAX: () => PLAN_FILES_MAX,
41759
+ PLAN_FILE_GLOB_MAX: () => PLAN_FILE_GLOB_MAX,
41760
+ PLAN_MAX_TASKS: () => PLAN_MAX_TASKS,
41761
+ PLAN_NOTES_MAX: () => PLAN_NOTES_MAX,
41762
+ PLAN_SCHEMA_VERSION: () => PLAN_SCHEMA_VERSION,
41763
+ PLAN_TAG_MAX: () => PLAN_TAG_MAX,
41764
+ PLAN_TASK_STATUSES: () => PLAN_TASK_STATUSES,
41765
+ PLAN_TITLE_MAX: () => PLAN_TITLE_MAX,
41766
+ PlanStoreError: () => PlanStoreError,
41767
+ listOpenPlanTaskIds: () => listOpenPlanTaskIds,
41768
+ nextPlanTaskId: () => nextPlanTaskId,
41769
+ normalizePlanTaskFiles: () => normalizePlanTaskFiles,
41770
+ planJsonPathFor: () => planJsonPathFor,
41771
+ withPlanStore: () => withPlanStore,
41772
+ writePlanTaskArtifact: () => writePlanTaskArtifact
41773
+ });
41628
41774
  import {
41629
41775
  copyFileSync,
41630
41776
  existsSync as existsSync20,
@@ -41647,6 +41793,24 @@ function normalizePlanTaskFiles(values) {
41647
41793
  function planJsonPathFor(projectRoot = process.cwd()) {
41648
41794
  return join17(resolveWorkspaceRoot(projectRoot), "plan.json");
41649
41795
  }
41796
+ async function listOpenPlanTaskIds(projectRoot) {
41797
+ try {
41798
+ const jsonPath = planJsonPathFor(projectRoot);
41799
+ if (!existsSync20(jsonPath)) return [];
41800
+ const parsed = JSON.parse(readFileSync18(jsonPath, "utf8"));
41801
+ if (!Array.isArray(parsed.tasks)) return [];
41802
+ const ids = [];
41803
+ for (const raw of parsed.tasks) {
41804
+ if (raw === null || typeof raw !== "object") continue;
41805
+ const t = raw;
41806
+ if (typeof t.id !== "string" || t.id.length === 0) continue;
41807
+ if (t.status === "pending" || t.status === "in_progress") ids.push(t.id);
41808
+ }
41809
+ return ids;
41810
+ } catch {
41811
+ return [];
41812
+ }
41813
+ }
41650
41814
  async function withPlanStore(projectRoot, fn) {
41651
41815
  const rootDir = resolveWorkspaceRoot(projectRoot);
41652
41816
  return workspaceMutex.run(`${rootDir}:plan`, () => {
@@ -41665,8 +41829,8 @@ function nextPlanTaskId(store6) {
41665
41829
  return `t${store6.counter}`;
41666
41830
  }
41667
41831
  function writePlanTaskArtifact(rootDir, task) {
41668
- const path100 = join17(rootDir, "plan-tasks", `${task.id}.md`);
41669
- mkdirSync11(dirname3(path100), { recursive: true });
41832
+ const path101 = join17(rootDir, "plan-tasks", `${task.id}.md`);
41833
+ mkdirSync11(dirname3(path101), { recursive: true });
41670
41834
  const meta3 = {
41671
41835
  kind: "task",
41672
41836
  id: task.id,
@@ -41687,7 +41851,7 @@ function writePlanTaskArtifact(rootDir, task) {
41687
41851
  task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
41688
41852
  ""
41689
41853
  ].filter((l) => l !== null).join("\n");
41690
- new Storage().write(path100, meta3, body);
41854
+ new Storage().write(path101, meta3, body);
41691
41855
  }
41692
41856
  function loadHandle(rootDir) {
41693
41857
  const jsonPath = join17(rootDir, "plan.json");
@@ -41790,7 +41954,7 @@ function normalizeStatus(raw) {
41790
41954
  function firstString(v) {
41791
41955
  return typeof v === "string" && v.trim().length > 0 ? v : null;
41792
41956
  }
41793
- var PLAN_SCHEMA_VERSION, PLAN_MAX_TASKS, PLAN_TITLE_MAX, PLAN_NOTES_MAX, PLAN_TAG_MAX, PLAN_FILES_MAX, PLAN_FILE_GLOB_MAX, PlanStoreError;
41957
+ var PLAN_SCHEMA_VERSION, PLAN_MAX_TASKS, PLAN_TITLE_MAX, PLAN_NOTES_MAX, PLAN_TAG_MAX, PLAN_TASK_STATUSES, PLAN_FILES_MAX, PLAN_FILE_GLOB_MAX, PlanStoreError;
41794
41958
  var init_planStore = __esm({
41795
41959
  "src/cli/workspace/planStore.ts"() {
41796
41960
  "use strict";
@@ -41801,6 +41965,13 @@ var init_planStore = __esm({
41801
41965
  PLAN_TITLE_MAX = 200;
41802
41966
  PLAN_NOTES_MAX = 2e3;
41803
41967
  PLAN_TAG_MAX = 64;
41968
+ PLAN_TASK_STATUSES = [
41969
+ "pending",
41970
+ "in_progress",
41971
+ "completed",
41972
+ "cancelled",
41973
+ "blocked"
41974
+ ];
41804
41975
  PLAN_FILES_MAX = 32;
41805
41976
  PLAN_FILE_GLOB_MAX = 260;
41806
41977
  PlanStoreError = class extends Error {
@@ -52011,21 +52182,21 @@ function normalizeAuth(auth) {
52011
52182
  return "agent";
52012
52183
  }
52013
52184
  function readSecrets() {
52014
- const path100 = getSshSecretsPath();
52015
- if (!existsSync30(path100)) return {};
52185
+ const path101 = getSshSecretsPath();
52186
+ if (!existsSync30(path101)) return {};
52016
52187
  try {
52017
- return JSON.parse(readFileSync22(path100, "utf8"));
52188
+ return JSON.parse(readFileSync22(path101, "utf8"));
52018
52189
  } catch {
52019
52190
  return {};
52020
52191
  }
52021
52192
  }
52022
52193
  function writeSecrets(data) {
52023
- const path100 = getSshSecretsPath();
52024
- mkdirSync13(dirname4(path100), { recursive: true });
52025
- writeFileSync16(path100, `${JSON.stringify(data, null, 2)}
52194
+ const path101 = getSshSecretsPath();
52195
+ mkdirSync13(dirname4(path101), { recursive: true });
52196
+ writeFileSync16(path101, `${JSON.stringify(data, null, 2)}
52026
52197
  `, "utf8");
52027
52198
  try {
52028
- chmodSync(path100, 384);
52199
+ chmodSync(path101, 384);
52029
52200
  } catch {
52030
52201
  }
52031
52202
  }
@@ -52054,10 +52225,10 @@ function deleteSshPassword(id3) {
52054
52225
  writeSecrets({ passwords });
52055
52226
  }
52056
52227
  function readStore2() {
52057
- const path100 = getSshTargetsPath();
52058
- if (!existsSync30(path100)) return [];
52228
+ const path101 = getSshTargetsPath();
52229
+ if (!existsSync30(path101)) return [];
52059
52230
  try {
52060
- const parsed = JSON.parse(readFileSync22(path100, "utf8"));
52231
+ const parsed = JSON.parse(readFileSync22(path101, "utf8"));
52061
52232
  const list = Array.isArray(parsed.targets) ? parsed.targets : [];
52062
52233
  return list.filter(
52063
52234
  (t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
@@ -52072,11 +52243,11 @@ function readStore2() {
52072
52243
  }
52073
52244
  }
52074
52245
  function writeStore2(targets) {
52075
- const path100 = getSshTargetsPath();
52076
- mkdirSync13(dirname4(path100), { recursive: true });
52246
+ const path101 = getSshTargetsPath();
52247
+ mkdirSync13(dirname4(path101), { recursive: true });
52077
52248
  const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
52078
52249
  writeFileSync16(
52079
- path100,
52250
+ path101,
52080
52251
  `${JSON.stringify({ targets: clean }, null, 2)}
52081
52252
  `,
52082
52253
  "utf8"
@@ -52322,11 +52493,11 @@ function formatSshTargetsForPrompt() {
52322
52493
  ];
52323
52494
  for (const t of targets) {
52324
52495
  const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
52325
- const path100 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
52496
+ const path101 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
52326
52497
  const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
52327
52498
  const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
52328
52499
  lines.push(
52329
- `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path100}${tags}${allow}`
52500
+ `- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path101}${tags}${allow}`
52330
52501
  );
52331
52502
  }
52332
52503
  return lines.join("\n");
@@ -57055,6 +57226,7 @@ function parseHeadlessFlags(argv) {
57055
57226
  let once = false;
57056
57227
  let profile;
57057
57228
  let resumeSessionId;
57229
+ let resumeMission = false;
57058
57230
  let exportSessionPath;
57059
57231
  let strictDone;
57060
57232
  let missionStrict;
@@ -57201,6 +57373,8 @@ function parseHeadlessFlags(argv) {
57201
57373
  }
57202
57374
  profile = next;
57203
57375
  i++;
57376
+ } else if (arg === "--resume-mission") {
57377
+ resumeMission = true;
57204
57378
  } else if (arg === "--resume") {
57205
57379
  const next = argv[i + 1];
57206
57380
  if (!next || next.startsWith("--")) {
@@ -57223,6 +57397,8 @@ function parseHeadlessFlags(argv) {
57223
57397
  missionStrict = true;
57224
57398
  } else if (arg === "--no-mission-strict") {
57225
57399
  missionStrict = false;
57400
+ } else if (arg === "--allow-unverified") {
57401
+ process.env.ZELARI_ALLOW_UNVERIFIED = "1";
57226
57402
  } else if (arg === "--kraken-graph") {
57227
57403
  krakenGraph = argv[i + 1];
57228
57404
  i++;
@@ -57274,6 +57450,7 @@ function parseHeadlessFlags(argv) {
57274
57450
  ...history2 && history2.length > 0 ? { history: history2 } : {},
57275
57451
  ...todos2 && todos2.length > 0 ? { todos: todos2 } : {},
57276
57452
  ...once ? { once: true } : {},
57453
+ ...resumeMission ? { resumeMission: true } : {},
57277
57454
  ...profile ? { profile } : {},
57278
57455
  ...resumeSessionId ? { resumeSessionId } : {},
57279
57456
  ...exportSessionPath ? { exportSessionPath } : {},
@@ -57335,6 +57512,7 @@ __export(headlessSpine_exports, {
57335
57512
  seedHeadlessModelHistory: () => seedHeadlessModelHistory,
57336
57513
  sessionStartedEvent: () => sessionStartedEvent
57337
57514
  });
57515
+ import path67 from "node:path";
57338
57516
  function sessionStartedEvent(handle) {
57339
57517
  return {
57340
57518
  type: "session_started",
@@ -57346,6 +57524,20 @@ function resolveHeadlessProfileId(mode, explicit) {
57346
57524
  if (explicit) return resolveProfile(explicit).id;
57347
57525
  return defaultProfileForMode(mode ?? "kraken");
57348
57526
  }
57527
+ async function countVerificationEvidenceInLog(mirror, sessionId2) {
57528
+ if (mirror.status !== "active" && mirror.status !== "closed") return -1;
57529
+ try {
57530
+ await mirror.flush().catch(() => void 0);
57531
+ const report = await readSessionLog(path67.join(mirror.sessionsDir, sessionId2, "events.jsonl"));
57532
+ return report.events.filter((e) => e.kind === "verification.evidence").length;
57533
+ } catch (err) {
57534
+ process.stderr.write(
57535
+ `[zelari-code] verification-evidence count unavailable (${err instanceof Error ? err.message : String(err)}) \u2014 event-back gate skipped
57536
+ `
57537
+ );
57538
+ return -1;
57539
+ }
57540
+ }
57349
57541
  async function openHeadlessSpine(opts) {
57350
57542
  const profileId = resolveHeadlessProfileId(opts.mode, opts.profile);
57351
57543
  let profileTools = [];
@@ -57417,6 +57609,9 @@ async function openHeadlessSpine(opts) {
57417
57609
  lastVerificationRun() {
57418
57610
  return spine.lastVerificationRun();
57419
57611
  },
57612
+ countVerificationEvidence() {
57613
+ return countVerificationEvidenceInLog(spine, opts.sessionId);
57614
+ },
57420
57615
  missionPhase(phase2, note) {
57421
57616
  spine.missionPhase(phase2, note);
57422
57617
  },
@@ -57524,6 +57719,7 @@ var init_headlessSpine = __esm({
57524
57719
  init_dist();
57525
57720
  init_session();
57526
57721
  init_mission2();
57722
+ init_session();
57527
57723
  init_runtime();
57528
57724
  init_sessionSpine();
57529
57725
  init_budgetRuntime();
@@ -58127,7 +58323,7 @@ var init_planDetect = __esm({
58127
58323
  // src/cli/memory/legacyImport.ts
58128
58324
  import { createHash as createHash18 } from "node:crypto";
58129
58325
  import { promises as fs27 } from "node:fs";
58130
- import * as path67 from "node:path";
58326
+ import * as path68 from "node:path";
58131
58327
  function sourceId(fact, line) {
58132
58328
  return `jsonl:${fact.id ?? createHash18("sha256").update(line).digest("hex")}`;
58133
58329
  }
@@ -58145,7 +58341,7 @@ function timestamp(value) {
58145
58341
  }
58146
58342
  async function importLegacyMemoryLog(backend, service) {
58147
58343
  const result = { found: 0, imported: 0, skipped: 0, corrupt: 0 };
58148
- const logPath = path67.join(path67.dirname(backend.databasePath), "log.jsonl");
58344
+ const logPath = path68.join(path68.dirname(backend.databasePath), "log.jsonl");
58149
58345
  let raw;
58150
58346
  try {
58151
58347
  raw = await fs27.readFile(logPath, "utf8");
@@ -58328,7 +58524,7 @@ var init_sqliteCodec = __esm({
58328
58524
  // src/cli/memory/sqliteRpc.ts
58329
58525
  import { existsSync as existsSync36 } from "node:fs";
58330
58526
  import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
58331
- import * as path68 from "node:path";
58527
+ import * as path69 from "node:path";
58332
58528
  import { Worker } from "node:worker_threads";
58333
58529
  function isBusy(error51) {
58334
58530
  const candidate = error51;
@@ -58337,10 +58533,10 @@ function isBusy(error51) {
58337
58533
  );
58338
58534
  }
58339
58535
  function resolveWorkerUrl() {
58340
- const here = path68.dirname(fileURLToPath2(import.meta.url));
58341
- const direct = path68.join(here, "sqliteWorker.mjs");
58536
+ const here = path69.dirname(fileURLToPath2(import.meta.url));
58537
+ const direct = path69.join(here, "sqliteWorker.mjs");
58342
58538
  if (existsSync36(direct)) return pathToFileURL2(direct);
58343
- return pathToFileURL2(path68.join(here, "memory", "sqliteWorker.mjs"));
58539
+ return pathToFileURL2(path69.join(here, "memory", "sqliteWorker.mjs"));
58344
58540
  }
58345
58541
  var SqliteWorkerRpc;
58346
58542
  var init_sqliteRpc = __esm({
@@ -58629,7 +58825,7 @@ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.node_id = n.id);
58629
58825
  // src/cli/memory/sqliteBackend.ts
58630
58826
  import { createHash as createHash19, randomUUID as randomUUID6 } from "node:crypto";
58631
58827
  import { promises as fs28 } from "node:fs";
58632
- import * as path69 from "node:path";
58828
+ import * as path70 from "node:path";
58633
58829
  function boundedLimit(value, fallback = 50) {
58634
58830
  return Math.max(1, Math.min(Math.floor(value ?? fallback), 1e5));
58635
58831
  }
@@ -58691,16 +58887,16 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
58691
58887
  try {
58692
58888
  resolved = await fs28.realpath(projectRoot);
58693
58889
  } catch {
58694
- resolved = path69.resolve(projectRoot);
58890
+ resolved = path70.resolve(projectRoot);
58695
58891
  }
58696
58892
  if (this.initialized && resolved === this.projectRoot) return;
58697
58893
  if (this.initialized) await this.close();
58698
58894
  const filename = this.options.filename ?? "memory.db";
58699
- if (path69.basename(filename) !== filename || filename === "." || filename === "..") {
58895
+ if (path70.basename(filename) !== filename || filename === "." || filename === "..") {
58700
58896
  throw new Error("SQLite memory filename must not contain a path.");
58701
58897
  }
58702
- const zelariDirectory = path69.join(resolved, ".zelari");
58703
- const directory = path69.join(zelariDirectory, "memory");
58898
+ const zelariDirectory = path70.join(resolved, ".zelari");
58899
+ const directory = path70.join(zelariDirectory, "memory");
58704
58900
  for (const candidate of [zelariDirectory, directory]) {
58705
58901
  let stat8;
58706
58902
  try {
@@ -58719,12 +58915,12 @@ VALUES (${Array.from({ length: 19 }, () => "?").join(",")})`;
58719
58915
  }
58720
58916
  }
58721
58917
  const canonicalDirectory = await fs28.realpath(directory);
58722
- const relativeDirectory = path69.relative(resolved, canonicalDirectory);
58723
- if (relativeDirectory.startsWith("..") || path69.isAbsolute(relativeDirectory)) {
58918
+ const relativeDirectory = path70.relative(resolved, canonicalDirectory);
58919
+ if (relativeDirectory.startsWith("..") || path70.isAbsolute(relativeDirectory)) {
58724
58920
  throw new Error("SQLite memory directory resolves outside the active project.");
58725
58921
  }
58726
58922
  this.projectRoot = resolved;
58727
- this.databasePath = path69.join(canonicalDirectory, filename);
58923
+ this.databasePath = path70.join(canonicalDirectory, filename);
58728
58924
  const opened = await this.rpc.open({
58729
58925
  dbPath: this.databasePath,
58730
58926
  schemaSql: SQLITE_MEMORY_BASE_SCHEMA,
@@ -59257,7 +59453,7 @@ __export(serviceFactory_exports, {
59257
59453
  });
59258
59454
  import { createHash as createHash20 } from "node:crypto";
59259
59455
  import { promises as fs29 } from "node:fs";
59260
- import * as path70 from "node:path";
59456
+ import * as path71 from "node:path";
59261
59457
  function isMemoryV2Enabled(env = process.env) {
59262
59458
  if (env.ZELARI_MEMORY === "0") return false;
59263
59459
  if (env.ZELARI_MEMORY_BACKEND === "file" || env.ZELARI_MEMORY_BACKEND === "jsonl") return false;
@@ -59278,7 +59474,7 @@ async function canonicalProjectId(projectRoot) {
59278
59474
  try {
59279
59475
  canonical = await fs29.realpath(projectRoot);
59280
59476
  } catch {
59281
- canonical = path70.resolve(projectRoot);
59477
+ canonical = path71.resolve(projectRoot);
59282
59478
  }
59283
59479
  canonical = canonical.replace(/\\/g, "/").replace(/\/$/, "");
59284
59480
  if (process.platform === "win32") canonical = canonical.toLocaleLowerCase("en-US");
@@ -59980,8 +60176,8 @@ function readPlan(ctx) {
59980
60176
  } catch {
59981
60177
  }
59982
60178
  }
59983
- const path100 = workspaceFile(ctx.rootDir, "plan");
59984
- const doc = ctx.storage.readIfExists(path100);
60179
+ const path101 = workspaceFile(ctx.rootDir, "plan");
60180
+ const doc = ctx.storage.readIfExists(path101);
59985
60181
  if (!doc) return { phases: [], tasks: [], milestones: [] };
59986
60182
  const meta3 = doc.meta;
59987
60183
  return {
@@ -60162,7 +60358,7 @@ function addMilestoneRecord(ctx, summary, input) {
60162
60358
  dueDate: input.dueDate,
60163
60359
  targetVersion: version2
60164
60360
  });
60165
- const path100 = join31(ctx.rootDir, "milestones", `${id3}.md`);
60361
+ const path101 = join31(ctx.rootDir, "milestones", `${id3}.md`);
60166
60362
  const meta3 = {
60167
60363
  kind: "milestone",
60168
60364
  id: id3,
@@ -60179,7 +60375,7 @@ function addMilestoneRecord(ctx, summary, input) {
60179
60375
  `Target version: ${version2}`,
60180
60376
  ""
60181
60377
  ].join("\n");
60182
- ctx.storage.write(path100, meta3, body);
60378
+ ctx.storage.write(path101, meta3, body);
60183
60379
  return { id: id3, created: true };
60184
60380
  }
60185
60381
  function readPlanSummary(ctx) {
@@ -60383,7 +60579,7 @@ function addIdeaStub(ctx) {
60383
60579
  const tags = args["tags"] ?? [];
60384
60580
  const category = args["category"] ?? "General";
60385
60581
  const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
60386
- const path100 = workspaceArtifact(ctx.rootDir, "decisions", id3);
60582
+ const path101 = workspaceArtifact(ctx.rootDir, "decisions", id3);
60387
60583
  const meta3 = {
60388
60584
  kind: "adr",
60389
60585
  status: "proposed",
@@ -60409,7 +60605,7 @@ function addIdeaStub(ctx) {
60409
60605
  ...consequences.map((c) => `- ${c}`),
60410
60606
  ""
60411
60607
  ].join("\n");
60412
- ctx.storage.write(path100, meta3, body);
60608
+ ctx.storage.write(path101, meta3, body);
60413
60609
  return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
60414
60610
  });
60415
60611
  }
@@ -60491,14 +60687,14 @@ function createDocumentStub(ctx) {
60491
60687
  ctx.storage.write(risksPath, riskMeta, content);
60492
60688
  return `Document "${title}" created at risks.md (workspace root).`;
60493
60689
  }
60494
- const path100 = workspaceArtifact(ctx.rootDir, "docs", slug);
60690
+ const path101 = workspaceArtifact(ctx.rootDir, "docs", slug);
60495
60691
  const meta3 = {
60496
60692
  kind: "doc",
60497
60693
  id: slug,
60498
60694
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
60499
60695
  tags
60500
60696
  };
60501
- ctx.storage.write(path100, meta3, content);
60697
+ ctx.storage.write(path101, meta3, content);
60502
60698
  return `Document "${title}" created at docs/${slug}.md.`;
60503
60699
  });
60504
60700
  }
@@ -61123,10 +61319,10 @@ function getUserMcpPath() {
61123
61319
  function getProjectMcpPath(projectRoot) {
61124
61320
  return join32(projectRoot, ".zelari", "mcp.json");
61125
61321
  }
61126
- function readFile9(path100) {
61127
- if (!existsSync42(path100)) return {};
61322
+ function readFile9(path101) {
61323
+ if (!existsSync42(path101)) return {};
61128
61324
  try {
61129
- const parsed = JSON.parse(readFileSync30(path100, "utf8"));
61325
+ const parsed = JSON.parse(readFileSync30(path101, "utf8"));
61130
61326
  const out = {};
61131
61327
  for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
61132
61328
  const hasCommand = !!cfg && typeof cfg.command === "string" && !!cfg.command.trim();
@@ -61148,10 +61344,10 @@ function readFile9(path100) {
61148
61344
  return {};
61149
61345
  }
61150
61346
  }
61151
- function writeFile3(path100, servers) {
61152
- mkdirSync17(dirname9(path100), { recursive: true });
61347
+ function writeFile3(path101, servers) {
61348
+ mkdirSync17(dirname9(path101), { recursive: true });
61153
61349
  const body = { mcpServers: servers };
61154
- writeFileSync19(path100, `${JSON.stringify(body, null, 2)}
61350
+ writeFileSync19(path101, `${JSON.stringify(body, null, 2)}
61155
61351
  `, "utf8");
61156
61352
  }
61157
61353
  function listMcpServers(projectRoot) {
@@ -61189,9 +61385,9 @@ function upsertMcpServer(opts) {
61189
61385
  error: "either command (stdio) or url (http) is required"
61190
61386
  };
61191
61387
  }
61192
- let path100;
61388
+ let path101;
61193
61389
  if (opts.scope === "user") {
61194
- path100 = getUserMcpPath();
61390
+ path101 = getUserMcpPath();
61195
61391
  } else {
61196
61392
  const root = opts.projectRoot?.trim();
61197
61393
  if (!root) {
@@ -61200,9 +61396,9 @@ function upsertMcpServer(opts) {
61200
61396
  error: "projectRoot required for project scope (Open Folder first)"
61201
61397
  };
61202
61398
  }
61203
- path100 = getProjectMcpPath(root);
61399
+ path101 = getProjectMcpPath(root);
61204
61400
  }
61205
- const current = readFile9(path100);
61401
+ const current = readFile9(path101);
61206
61402
  current[name] = {
61207
61403
  command: hasCommand ? opts.config.command.trim() : void 0,
61208
61404
  args: opts.config.args,
@@ -61213,21 +61409,21 @@ function upsertMcpServer(opts) {
61213
61409
  serial: opts.config.serial,
61214
61410
  enabled: opts.config.enabled !== false
61215
61411
  };
61216
- writeFile3(path100, current);
61217
- return { ok: true, path: path100 };
61412
+ writeFile3(path101, current);
61413
+ return { ok: true, path: path101 };
61218
61414
  }
61219
61415
  function removeMcpServer(opts) {
61220
- const path100 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
61221
- if (!path100) {
61416
+ const path101 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
61417
+ if (!path101) {
61222
61418
  return { ok: false, error: "projectRoot required for project scope" };
61223
61419
  }
61224
- const current = readFile9(path100);
61420
+ const current = readFile9(path101);
61225
61421
  if (!(opts.name in current)) {
61226
- return { ok: false, error: `Server "${opts.name}" not found in ${path100}` };
61422
+ return { ok: false, error: `Server "${opts.name}" not found in ${path101}` };
61227
61423
  }
61228
61424
  delete current[opts.name];
61229
- writeFile3(path100, current);
61230
- return { ok: true, path: path100 };
61425
+ writeFile3(path101, current);
61426
+ return { ok: true, path: path101 };
61231
61427
  }
61232
61428
  var init_mcpConfigIo = __esm({
61233
61429
  "src/cli/mcp/mcpConfigIo.ts"() {
@@ -61698,10 +61894,10 @@ import { createHash as createHash21 } from "node:crypto";
61698
61894
  import { join as join34 } from "node:path";
61699
61895
  import { readFile as readFile10 } from "node:fs/promises";
61700
61896
  async function readPackageJson3(projectRoot) {
61701
- const path100 = join34(projectRoot, "package.json");
61702
- if (!existsSync44(path100)) return null;
61897
+ const path101 = join34(projectRoot, "package.json");
61898
+ if (!existsSync44(path101)) return null;
61703
61899
  try {
61704
- return JSON.parse(await readFile10(path100, "utf8"));
61900
+ return JSON.parse(await readFile10(path101, "utf8"));
61705
61901
  } catch {
61706
61902
  return null;
61707
61903
  }
@@ -61783,9 +61979,9 @@ async function genBuild(ctx) {
61783
61979
  ].join("\n");
61784
61980
  }
61785
61981
  async function genOpenQuestions(ctx) {
61786
- const path100 = join34(ctx.rootDir, "risks.md");
61787
- if (!existsSync44(path100)) return "_No open questions._";
61788
- const content = readFileSync32(path100, "utf8");
61982
+ const path101 = join34(ctx.rootDir, "risks.md");
61983
+ if (!existsSync44(path101)) return "_No open questions._";
61984
+ const content = readFileSync32(path101, "utf8");
61789
61985
  const lines = content.split("\n");
61790
61986
  const questions = [];
61791
61987
  let currentTitle = "";
@@ -62059,9 +62255,9 @@ function versionKey(value) {
62059
62255
  function firstString2(v) {
62060
62256
  return typeof v === "string" && v.trim().length > 0 ? v : null;
62061
62257
  }
62062
- function readFileSyncSafe(path100) {
62258
+ function readFileSyncSafe(path101) {
62063
62259
  try {
62064
- return readFileSync33(path100, "utf8");
62260
+ return readFileSync33(path101, "utf8");
62065
62261
  } catch {
62066
62262
  return null;
62067
62263
  }
@@ -62309,7 +62505,7 @@ __export(evidenceFromSpine_exports, {
62309
62505
  evidenceRefsFromEventLines: () => evidenceRefsFromEventLines
62310
62506
  });
62311
62507
  import { existsSync as existsSync47, readFileSync as readFileSync35 } from "node:fs";
62312
- import path71 from "node:path";
62508
+ import path72 from "node:path";
62313
62509
  function asRecord2(v) {
62314
62510
  return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
62315
62511
  }
@@ -62347,7 +62543,7 @@ function evidenceRefsFromEventLines(lines) {
62347
62543
  }
62348
62544
  function collectSessionEvidenceRefs(sessionId2) {
62349
62545
  try {
62350
- const file2 = path71.join(sessionsDir(), sessionId2, "events.jsonl");
62546
+ const file2 = path72.join(sessionsDir(), sessionId2, "events.jsonl");
62351
62547
  if (!existsSync47(file2)) return [];
62352
62548
  return evidenceRefsFromEventLines(readFileSync35(file2, "utf8").split("\n"));
62353
62549
  } catch {
@@ -62597,8 +62793,8 @@ async function runPostCouncilHook(ctx, options) {
62597
62793
  sources: scope.sources
62598
62794
  } : void 0
62599
62795
  });
62600
- const path100 = writeCouncilCompletion(ctx.rootDir, completion);
62601
- completionHook = { ran: true, path: path100, completion };
62796
+ const path101 = writeCouncilCompletion(ctx.rootDir, completion);
62797
+ completionHook = { ran: true, path: path101, completion };
62602
62798
  } catch (err) {
62603
62799
  completionHook = {
62604
62800
  ran: true,
@@ -62643,7 +62839,7 @@ import {
62643
62839
  writeFileSync as writeFileSync22,
62644
62840
  mkdirSync as mkdirSync18
62645
62841
  } from "node:fs";
62646
- import path72 from "node:path";
62842
+ import path73 from "node:path";
62647
62843
  var FeedbackStore;
62648
62844
  var init_councilFeedback = __esm({
62649
62845
  "src/cli/councilFeedback.ts"() {
@@ -62760,7 +62956,7 @@ var init_councilFeedback = __esm({
62760
62956
  }
62761
62957
  }
62762
62958
  save() {
62763
- mkdirSync18(path72.dirname(this.file), { recursive: true });
62959
+ mkdirSync18(path73.dirname(this.file), { recursive: true });
62764
62960
  writeFileSync22(
62765
62961
  this.file,
62766
62962
  JSON.stringify({ entries: this.entries }, null, 2),
@@ -62835,12 +63031,12 @@ __export(ledger_exports, {
62835
63031
  readLedger: () => readLedger
62836
63032
  });
62837
63033
  import { appendFileSync as appendFileSync4, existsSync as existsSync50, mkdirSync as mkdirSync19, readFileSync as readFileSync38 } from "node:fs";
62838
- import path73 from "node:path";
63034
+ import path74 from "node:path";
62839
63035
  function evolutionMode(env = process.env) {
62840
63036
  return env[EVOLUTION_ENV] === "shadow" ? "shadow" : "0";
62841
63037
  }
62842
63038
  function ledgerPath(cwd) {
62843
- return path73.join(cwd, LEDGER_REL);
63039
+ return path74.join(cwd, LEDGER_REL);
62844
63040
  }
62845
63041
  function appendLedgerEntry(cwd, entry) {
62846
63042
  if (evolutionMode() === "0") {
@@ -62848,7 +63044,7 @@ function appendLedgerEntry(cwd, entry) {
62848
63044
  }
62849
63045
  try {
62850
63046
  const file2 = ledgerPath(cwd);
62851
- mkdirSync19(path73.dirname(file2), { recursive: true });
63047
+ mkdirSync19(path74.dirname(file2), { recursive: true });
62852
63048
  appendFileSync4(file2, `${JSON.stringify(entry)}
62853
63049
  `, "utf8");
62854
63050
  return { written: true, path: file2 };
@@ -62949,7 +63145,7 @@ var init_ledger = __esm({
62949
63145
  "src/cli/evolution/ledger.ts"() {
62950
63146
  "use strict";
62951
63147
  EVOLUTION_ENV = "ZELARI_EVOLUTION";
62952
- LEDGER_REL = path73.join(".zelari", "evolution", "ledger.jsonl");
63148
+ LEDGER_REL = path74.join(".zelari", "evolution", "ledger.jsonl");
62953
63149
  TIER_WEIGHTS = {
62954
63150
  build: 1,
62955
63151
  "tool-output": 1,
@@ -63091,7 +63287,7 @@ __export(fileBackend_exports, {
63091
63287
  });
63092
63288
  import { randomUUID as randomUUID7 } from "node:crypto";
63093
63289
  import { promises as fs31 } from "node:fs";
63094
- import * as path74 from "node:path";
63290
+ import * as path75 from "node:path";
63095
63291
  function tokenize2(text) {
63096
63292
  return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
63097
63293
  }
@@ -63144,8 +63340,8 @@ var init_fileBackend = __esm({
63144
63340
  logPath = "";
63145
63341
  memoryDir = "";
63146
63342
  async init(projectRoot) {
63147
- this.memoryDir = path74.join(projectRoot, ".zelari", "memory");
63148
- this.logPath = path74.join(this.memoryDir, "log.jsonl");
63343
+ this.memoryDir = path75.join(projectRoot, ".zelari", "memory");
63344
+ this.logPath = path75.join(this.memoryDir, "log.jsonl");
63149
63345
  await fs31.mkdir(this.memoryDir, { recursive: true });
63150
63346
  }
63151
63347
  async add(content, metadata2 = {}, graph) {
@@ -63218,12 +63414,12 @@ var init_fileBackend = __esm({
63218
63414
 
63219
63415
  // src/cli/traceStore.ts
63220
63416
  import { promises as fs32 } from "node:fs";
63221
- import * as path75 from "node:path";
63417
+ import * as path76 from "node:path";
63222
63418
  function traceDir(projectRoot) {
63223
- return path75.join(projectRoot, ".zelari", "trace");
63419
+ return path76.join(projectRoot, ".zelari", "trace");
63224
63420
  }
63225
63421
  function tracePath(projectRoot, missionId) {
63226
- return path75.join(traceDir(projectRoot), `${missionId}.json`);
63422
+ return path76.join(traceDir(projectRoot), `${missionId}.json`);
63227
63423
  }
63228
63424
  async function saveTrace(projectRoot, missionId, entries) {
63229
63425
  const dir = traceDir(projectRoot);
@@ -63248,19 +63444,24 @@ var init_traceStore = __esm({
63248
63444
  // src/cli/zelariMission.ts
63249
63445
  var zelariMission_exports = {};
63250
63446
  __export(zelariMission_exports, {
63447
+ MissionResumeError: () => MissionResumeError,
63251
63448
  formatBriefForChat: () => formatBriefForChat,
63252
63449
  isMissionAutoStart: () => isMissionAutoStart,
63450
+ isResumableMission: () => isResumableMission,
63451
+ loadMissionState: () => loadMissionState,
63253
63452
  missionGapKey: () => missionGapKey,
63254
63453
  missionPressure: () => missionPressure,
63255
63454
  resolveMaxCost: () => resolveMaxCost,
63256
63455
  resolveMaxIterations: () => resolveMaxIterations,
63257
63456
  resolveMaxStall: () => resolveMaxStall,
63258
63457
  resolveMaxTokens: () => resolveMaxTokens,
63458
+ resolveMissionSlices: () => resolveMissionSlices,
63459
+ resumeZelariMission: () => resumeZelariMission,
63259
63460
  runZelariMission: () => runZelariMission
63260
63461
  });
63261
63462
  import { randomUUID as randomUUID8 } from "node:crypto";
63262
63463
  import { promises as fs33 } from "node:fs";
63263
- import * as path76 from "node:path";
63464
+ import * as path77 from "node:path";
63264
63465
  function resolveMaxIterations(env = process.env) {
63265
63466
  const raw = env.ZELARI_MISSION_MAX_ITER;
63266
63467
  const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
@@ -63303,10 +63504,10 @@ function isMissionAutoStart(env = process.env) {
63303
63504
  return env.ZELARI_MISSION_AUTO === "1";
63304
63505
  }
63305
63506
  async function writeMissionState(projectRoot, state3) {
63306
- const dir = path76.join(projectRoot, ".zelari");
63507
+ const dir = path77.join(projectRoot, ".zelari");
63307
63508
  await fs33.mkdir(dir, { recursive: true });
63308
63509
  await fs33.writeFile(
63309
- path76.join(dir, "mission-state.json"),
63510
+ path77.join(dir, "mission-state.json"),
63310
63511
  JSON.stringify(state3, null, 2) + "\n",
63311
63512
  "utf8"
63312
63513
  );
@@ -63317,16 +63518,42 @@ async function writeMissionState(projectRoot, state3) {
63317
63518
  }
63318
63519
  }
63319
63520
  }
63320
- function buildSlicePrompt(brief, userMessage, runMode, iteration) {
63521
+ async function loadMissionState(projectRoot) {
63522
+ try {
63523
+ const raw = await fs33.readFile(
63524
+ path77.join(projectRoot, ".zelari", "mission-state.json"),
63525
+ "utf8"
63526
+ );
63527
+ const parsed = JSON.parse(raw);
63528
+ if (!parsed || typeof parsed.missionId !== "string" || !parsed.brief) return void 0;
63529
+ return parsed;
63530
+ } catch {
63531
+ return void 0;
63532
+ }
63533
+ }
63534
+ function isResumableMission(state3) {
63535
+ return !!state3 && state3.status !== "success";
63536
+ }
63537
+ function resolveMissionSlices(brief) {
63538
+ const slices = Array.isArray(brief.slices) ? brief.slices.filter((s) => s && !!s.id) : [];
63539
+ return slices.length ? slices : [brief.sliceMvp];
63540
+ }
63541
+ function countImplementationSlices(state3) {
63542
+ return Array.isArray(state3.trace) ? state3.trace.filter((t) => t?.runMode === "implementation").length : 0;
63543
+ }
63544
+ function buildSlicePrompt(brief, userMessage, runMode, iteration, slice) {
63321
63545
  if (runMode === "design-phase") {
63322
63546
  return `${userMessage}
63323
63547
 
63324
- [Zelari mission] Produce the design-phase plan for the MVP: ${brief.deliverableThisMission}. Keep the first slice to at most ${brief.sliceMvp.maxTasks ?? 8} tasks.`;
63548
+ [Zelari mission] Produce the design-phase plan for the MVP: ${brief.deliverableThisMission}. Keep the first slice to at most ${slice.maxTasks ?? 8} tasks.`;
63325
63549
  }
63326
63550
  const fix = iteration > 1 ? " Address any remaining verification failures recorded in .zelari/completion.json." : "";
63551
+ const isMvpSlice = slice.id === resolveMissionSlices(brief)[0].id;
63552
+ const target = isMvpSlice ? "the MVP slice" : `increment "${slice.title}"`;
63553
+ const scope = slice.taskIds?.length ? ` Scope: plan tasks ${slice.taskIds.join(", ")}.` : "";
63327
63554
  return `${userMessage}
63328
63555
 
63329
- [Zelari mission] Implement the MVP slice: ${brief.deliverableThisMission}.${fix} You MUST create or modify the real project files with write_file / edit \u2014 not just describe them in prose. A run that claims completion without writing any file is a failed run and will not be accepted.`;
63556
+ [Zelari mission] Implement ${target}: ${brief.deliverableThisMission}.${scope}${fix} You MUST create or modify the real project files with write_file / edit \u2014 not just describe them in prose. A run that claims completion without writing any file is a failed run and will not be accepted.`;
63330
63557
  }
63331
63558
  function formatBriefForChat(brief) {
63332
63559
  const lines = [
@@ -63346,34 +63573,74 @@ function formatBriefForChat(brief) {
63346
63573
  lines.push(" out of scope:");
63347
63574
  for (const o of brief.outOfScope) lines.push(` - ${o}`);
63348
63575
  }
63576
+ const slices = resolveMissionSlices(brief);
63349
63577
  lines.push(` MVP slice: ${brief.sliceMvp.title} (\u2264 ${brief.sliceMvp.maxTasks} tasks)`);
63578
+ if (slices.length > 1) {
63579
+ lines.push(` increments: ${slices.length} (gated: slice N+1 starts only when N is green)`);
63580
+ for (const s of slices.slice(1)) lines.push(` - ${s.id}: ${s.title}`);
63581
+ }
63350
63582
  return lines.join("\n");
63351
63583
  }
63352
63584
  async function runZelariMission(userMessage, brief, deps) {
63353
63585
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
63354
- const maxIter = deps.maxIterations ?? resolveMaxIterations(deps.env);
63355
- const maxStall = resolveMaxStall(deps.env);
63356
- const maxCost = resolveMaxCost(deps.env);
63357
- const maxTokens = resolveMaxTokens(deps.env);
63358
- const missionId = deps.missionId ?? `m_${randomUUID8().slice(0, 8)}`;
63359
63586
  const startedAt = now().toISOString();
63360
63587
  const state3 = {
63361
- missionId,
63588
+ missionId: deps.missionId ?? `m_${randomUUID8().slice(0, 8)}`,
63362
63589
  userPrompt: userMessage,
63363
63590
  brief,
63364
63591
  iteration: 0,
63365
- currentSliceId: brief.sliceMvp.id,
63592
+ currentSliceId: resolveMissionSlices(brief)[0].id,
63366
63593
  status: "running",
63367
63594
  lastCompletionOk: false,
63368
63595
  startedAt,
63369
63596
  updatedAt: startedAt
63370
63597
  };
63598
+ return driveMission(userMessage, brief, deps, state3, false);
63599
+ }
63600
+ async function resumeZelariMission(deps) {
63601
+ const loaded = await loadMissionState(deps.projectRoot);
63602
+ if (!loaded) {
63603
+ throw new MissionResumeError(
63604
+ "nessuna missione da riprendere: .zelari/mission-state.json assente o illeggibile."
63605
+ );
63606
+ }
63607
+ if (!isResumableMission(loaded)) {
63608
+ throw new MissionResumeError(
63609
+ `la missione ${loaded.missionId} \xE8 gi\xE0 completata (status=success).`
63610
+ );
63611
+ }
63612
+ const brief = loaded.brief;
63613
+ const userMessage = loaded.userPrompt ?? brief.userPromptOriginal;
63614
+ deps.emit(
63615
+ `[zelari] resume missione ${loaded.missionId} \u2014 step ${loaded.iteration}, slice ${loaded.currentSliceId}, status precedente ${loaded.status}`
63616
+ );
63617
+ return driveMission(userMessage, brief, deps, loaded, true);
63618
+ }
63619
+ async function driveMission(userMessage, brief, deps, state3, resumed) {
63620
+ const now = deps.now ?? (() => /* @__PURE__ */ new Date());
63621
+ const maxIter = deps.maxIterations ?? resolveMaxIterations(deps.env);
63622
+ const maxStall = resolveMaxStall(deps.env);
63623
+ const maxCost = resolveMaxCost(deps.env);
63624
+ const maxTokens = resolveMaxTokens(deps.env);
63625
+ const missionId = state3.missionId;
63626
+ const slices = resolveMissionSlices(brief);
63627
+ let sliceIndex = resumed ? Math.max(
63628
+ 0,
63629
+ slices.findIndex((s) => s.id === state3.currentSliceId)
63630
+ ) : 0;
63631
+ const currentSlice = () => slices[sliceIndex] ?? slices[0];
63632
+ state3.currentSliceId = currentSlice().id;
63633
+ state3.status = "running";
63634
+ state3.updatedAt = now().toISOString();
63371
63635
  await deps.memory.init(deps.projectRoot);
63372
63636
  const persist = async () => {
63373
63637
  await writeMissionState(deps.projectRoot, state3);
63374
63638
  await deps.onStatePersisted?.(state3);
63375
63639
  };
63376
- deps.onMissionPhase?.("design", "mission-start");
63640
+ deps.onMissionPhase?.(
63641
+ resumed ? "build" : "design",
63642
+ resumed ? "mission-resume" : "mission-start"
63643
+ );
63377
63644
  await persist();
63378
63645
  const stateStore = deps.stateStore ?? await getStateStore(deps.projectRoot, deps.env ?? process.env);
63379
63646
  try {
@@ -63381,7 +63648,7 @@ async function runZelariMission(userMessage, brief, deps) {
63381
63648
  } catch {
63382
63649
  }
63383
63650
  let missionCheckpointId;
63384
- if ((deps.env ?? process.env).ZELARI_CHECKPOINT !== "0") {
63651
+ if (!resumed && (deps.env ?? process.env).ZELARI_CHECKPOINT !== "0") {
63385
63652
  const cp = await createCheckpoint(deps.projectRoot, `zelari mission ${missionId}`);
63386
63653
  if (cp.ok) {
63387
63654
  missionCheckpointId = cp.value.id;
@@ -63392,11 +63659,11 @@ async function runZelariMission(userMessage, brief, deps) {
63392
63659
  }
63393
63660
  const designFirst = brief.phases[0]?.mode === "design-phase";
63394
63661
  let noWriteStreak = 0;
63395
- let step = 0;
63396
- let implStep = 0;
63397
- let pendingDesign = designFirst;
63398
- let cumulativeCostUsd = 0;
63399
- let cumulativeTokens = 0;
63662
+ let step = resumed ? state3.iteration : 0;
63663
+ let implStep = resumed ? countImplementationSlices(state3) : 0;
63664
+ let pendingDesign = designFirst && !resumed;
63665
+ let cumulativeCostUsd = resumed ? state3.cumulativeCostUsd ?? 0 : 0;
63666
+ let cumulativeTokens = resumed ? state3.cumulativeTokens ?? 0 : 0;
63400
63667
  const repairHistory = Array.isArray(state3.repairHistory) ? [...state3.repairHistory] : [];
63401
63668
  let forcePivot = false;
63402
63669
  const missionStartMs = now().getTime();
@@ -63424,25 +63691,25 @@ async function runZelariMission(userMessage, brief, deps) {
63424
63691
  });
63425
63692
  const ragContext = formatMemoryHits(hits);
63426
63693
  const promptIter = runMode === "implementation" ? implStep : 1;
63427
- const slicePrompt = buildSlicePrompt(brief, userMessage, runMode, promptIter);
63694
+ const slicePrompt = buildSlicePrompt(brief, userMessage, runMode, promptIter, currentSlice());
63428
63695
  const implementerRetry = runMode === "implementation" && (implStep > 1 || forcePivot);
63429
63696
  const sliceStartedAt = now().toISOString();
63430
63697
  const sliceStartMs = now().getTime();
63431
63698
  if (runMode === "design-phase") {
63432
63699
  deps.emit(
63433
- `[zelari] design-phase (fuori budget) \xB7 step ${step} \xB7 slice ${brief.sliceMvp.id}`
63700
+ `[zelari] design-phase (fuori budget) \xB7 step ${step} \xB7 slice ${currentSlice().id}`
63434
63701
  );
63435
63702
  } else if (deps.buildViaAgent) {
63436
63703
  deps.emit(
63437
- `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 build@agent \xB7 slice ${brief.sliceMvp.id}`
63704
+ `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 build@agent \xB7 slice ${currentSlice().id}`
63438
63705
  );
63439
63706
  } else if (implementerRetry) {
63440
63707
  deps.emit(
63441
- `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 roster ridotto (Minosse+Lucifero) \xB7 slice ${brief.sliceMvp.id}`
63708
+ `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 roster ridotto (Minosse+Lucifero) \xB7 slice ${currentSlice().id}`
63442
63709
  );
63443
63710
  } else {
63444
63711
  deps.emit(
63445
- `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 council completo \xB7 slice ${brief.sliceMvp.id}`
63712
+ `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 council completo \xB7 slice ${currentSlice().id}`
63446
63713
  );
63447
63714
  }
63448
63715
  let result;
@@ -63484,7 +63751,7 @@ async function runZelariMission(userMessage, brief, deps) {
63484
63751
  {
63485
63752
  projectRoot: deps.projectRoot,
63486
63753
  missionId,
63487
- sliceId: brief.sliceMvp.id,
63754
+ sliceId: currentSlice().id,
63488
63755
  source: "council",
63489
63756
  iteration: step,
63490
63757
  memoryKind: result.completionOk ? "outcome" : runMode === "design-phase" ? "decision" : "episode",
@@ -63508,7 +63775,7 @@ async function runZelariMission(userMessage, brief, deps) {
63508
63775
  state3.cumulativeTokens = cumulativeTokens;
63509
63776
  if (!state3.trace) state3.trace = [];
63510
63777
  state3.trace.push({
63511
- sliceId: brief.sliceMvp.id,
63778
+ sliceId: currentSlice().id,
63512
63779
  iteration: step,
63513
63780
  runMode,
63514
63781
  completionOk,
@@ -63533,7 +63800,7 @@ async function runZelariMission(userMessage, brief, deps) {
63533
63800
  env: deps.env,
63534
63801
  mode: "zelari",
63535
63802
  layer: hard ? `mission:impl-${implStep}` : `mission:progress-${implStep}`,
63536
- label: hard ? `zelari ${brief.sliceMvp.id} impl ${implStep} verified` : `zelari ${brief.sliceMvp.id} progress impl ${implStep}`,
63803
+ label: hard ? `zelari ${currentSlice().id} impl ${implStep} verified` : `zelari ${currentSlice().id} progress impl ${implStep}`,
63537
63804
  sessionId: missionId,
63538
63805
  verification: { ok: hard, ran: result.ran },
63539
63806
  force: !hard,
@@ -63572,12 +63839,24 @@ async function runZelariMission(userMessage, brief, deps) {
63572
63839
  budget: { iterationsUsed: implStep, iterationsMax: maxIter }
63573
63840
  });
63574
63841
  deps.onMissionProgress?.(advice, step);
63842
+ if (completionOk && sliceIndex < slices.length - 1) {
63843
+ const doneSlice = currentSlice();
63844
+ sliceIndex += 1;
63845
+ state3.currentSliceId = currentSlice().id;
63846
+ state3.updatedAt = now().toISOString();
63847
+ await persist();
63848
+ deps.emit(
63849
+ `[zelari] \u2713 incremento ${sliceIndex}/${slices.length} verde (${doneSlice.id}) \u2014 avvio ${currentSlice().id}`
63850
+ );
63851
+ continue;
63852
+ }
63575
63853
  if (completionOk) {
63576
63854
  state3.status = "success";
63577
63855
  deps.onMissionPhase?.("done", "mvp-green");
63578
63856
  await persist();
63857
+ const sliceLabel = slices.length === 1 ? "slice MVP" : `ultimo incremento (${currentSlice().id})`;
63579
63858
  deps.emit(
63580
- `[zelari] \u2713 missione completata \u2014 slice MVP verde all'implementazione ${implStep}/${maxIter} (step ${step}).`
63859
+ `[zelari] \u2713 missione completata \u2014 ${sliceLabel} verde all'implementazione ${implStep}/${maxIter} (step ${step}).`
63581
63860
  );
63582
63861
  return state3;
63583
63862
  }
@@ -63655,7 +63934,7 @@ async function runZelariMission(userMessage, brief, deps) {
63655
63934
  );
63656
63935
  return state3;
63657
63936
  }
63658
- var DEFAULT_MAX_ITER, DEFAULT_MAX_STALL;
63937
+ var DEFAULT_MAX_ITER, DEFAULT_MAX_STALL, MissionResumeError;
63659
63938
  var init_zelariMission = __esm({
63660
63939
  "src/cli/zelariMission.ts"() {
63661
63940
  "use strict";
@@ -63668,6 +63947,12 @@ var init_zelariMission = __esm({
63668
63947
  init_traceStore();
63669
63948
  DEFAULT_MAX_ITER = 6;
63670
63949
  DEFAULT_MAX_STALL = 2;
63950
+ MissionResumeError = class extends Error {
63951
+ constructor(message) {
63952
+ super(message);
63953
+ this.name = "MissionResumeError";
63954
+ }
63955
+ };
63671
63956
  }
63672
63957
  });
63673
63958
 
@@ -63995,7 +64280,7 @@ function safeSocketPath(socketPath) {
63995
64280
  return socketPath.trim();
63996
64281
  }
63997
64282
  function startPermissionBroker(socketPath, handlers, opts) {
63998
- const path100 = safeSocketPath(socketPath);
64283
+ const path101 = safeSocketPath(socketPath);
63999
64284
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
64000
64285
  const sockets = /* @__PURE__ */ new Set();
64001
64286
  const server = createServer2((socket) => {
@@ -64095,10 +64380,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
64095
64380
  return new Promise((resolve9, reject) => {
64096
64381
  const onError = (err) => reject(err);
64097
64382
  server.once("error", onError);
64098
- server.listen(path100, () => {
64383
+ server.listen(path101, () => {
64099
64384
  server.removeListener("error", onError);
64100
64385
  resolve9({
64101
- socketPath: path100,
64386
+ socketPath: path101,
64102
64387
  stop: () => new Promise((res) => {
64103
64388
  for (const s of sockets) s.destroy();
64104
64389
  sockets.clear();
@@ -64109,7 +64394,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
64109
64394
  if (done) return;
64110
64395
  done = true;
64111
64396
  if (process.platform !== "win32") {
64112
- unlink(path100, () => res());
64397
+ unlink(path101, () => res());
64113
64398
  } else {
64114
64399
  res();
64115
64400
  }
@@ -64122,11 +64407,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
64122
64407
  });
64123
64408
  }
64124
64409
  function requestBrokerAsk(socketPath, ask, opts) {
64125
- const path100 = safeSocketPath(socketPath);
64410
+ const path101 = safeSocketPath(socketPath);
64126
64411
  const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
64127
64412
  const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
64128
64413
  return new Promise((resolve9, reject) => {
64129
- const socket = connect(path100);
64414
+ const socket = connect(path101);
64130
64415
  let buffer = "";
64131
64416
  let settled = false;
64132
64417
  const settle = (fn) => {
@@ -64141,7 +64426,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
64141
64426
  settle(
64142
64427
  () => reject(
64143
64428
  new Error(
64144
- `permission broker unavailable at "${path100}" (connect timed out after ${connectTimeoutMs}ms)`
64429
+ `permission broker unavailable at "${path101}" (connect timed out after ${connectTimeoutMs}ms)`
64145
64430
  )
64146
64431
  )
64147
64432
  );
@@ -65330,7 +65615,7 @@ var init_prereqChecks = __esm({
65330
65615
 
65331
65616
  // src/cli/plugins/prefs.ts
65332
65617
  import { existsSync as existsSync53, readFileSync as readFileSync40, writeFileSync as writeFileSync23, mkdirSync as mkdirSync20 } from "node:fs";
65333
- import path82 from "node:path";
65618
+ import path83 from "node:path";
65334
65619
  function getPluginPrefsPath() {
65335
65620
  return pluginsPrefsPath();
65336
65621
  }
@@ -65353,7 +65638,7 @@ function getPluginPrefs() {
65353
65638
  }
65354
65639
  function writePluginPrefs(prefs) {
65355
65640
  const file2 = getPluginPrefsPath();
65356
- mkdirSync20(path82.dirname(file2), { recursive: true });
65641
+ mkdirSync20(path83.dirname(file2), { recursive: true });
65357
65642
  writeFileSync23(file2, JSON.stringify(prefs, null, 2), {
65358
65643
  encoding: "utf-8",
65359
65644
  mode: 384
@@ -65391,7 +65676,7 @@ __export(registry_exports, {
65391
65676
  isBinaryOnPath: () => isBinaryOnPath
65392
65677
  });
65393
65678
  import { existsSync as existsSync54 } from "node:fs";
65394
- import path83 from "node:path";
65679
+ import path84 from "node:path";
65395
65680
  function detectLocalBin(bin) {
65396
65681
  return (cwd) => {
65397
65682
  try {
@@ -65409,7 +65694,7 @@ function isBinaryOnPath(bin, opts = {}) {
65409
65694
  const platform = opts.platform ?? process.platform;
65410
65695
  const exists = opts.exists ?? existsSync54;
65411
65696
  const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
65412
- const pathMod = platform === "win32" ? path83.win32 : path83.posix;
65697
+ const pathMod = platform === "win32" ? path84.win32 : path84.posix;
65413
65698
  const sep4 = platform === "win32" ? ";" : ":";
65414
65699
  const dirs = pathEnv.split(sep4).filter((d) => d.length > 0);
65415
65700
  const candidates = [bin];
@@ -66514,7 +66799,7 @@ var init_policy = __esm({
66514
66799
 
66515
66800
  // src/cli/orchestration/facts.ts
66516
66801
  import { promises as fs43 } from "node:fs";
66517
- import path87 from "node:path";
66802
+ import path88 from "node:path";
66518
66803
  async function collectRepoFileCount(root = process.cwd()) {
66519
66804
  try {
66520
66805
  await fs43.readdir(root);
@@ -66534,7 +66819,7 @@ async function collectRepoFileCount(root = process.cwd()) {
66534
66819
  }
66535
66820
  for (const e of entries) {
66536
66821
  if (e.isDirectory()) {
66537
- if (!SKIP_DIRS.has(e.name)) queue.push(path87.join(dir, e.name));
66822
+ if (!SKIP_DIRS.has(e.name)) queue.push(path88.join(dir, e.name));
66538
66823
  } else if (e.isFile()) {
66539
66824
  count++;
66540
66825
  if (count > MAX_WALK_FILES) return count;
@@ -66632,7 +66917,7 @@ var init_streamScrub = __esm({
66632
66917
  });
66633
66918
 
66634
66919
  // src/cli/harnessState.ts
66635
- import path88 from "node:path";
66920
+ import path89 from "node:path";
66636
66921
  function asString4(v) {
66637
66922
  return typeof v === "string" ? v : "";
66638
66923
  }
@@ -66807,7 +67092,7 @@ function contractFor(t) {
66807
67092
  };
66808
67093
  }
66809
67094
  async function readHarnessState(sessionDir) {
66810
- const report = await readSessionLog(path88.join(sessionDir, "events.jsonl"));
67095
+ const report = await readSessionLog(path89.join(sessionDir, "events.jsonl"));
66811
67096
  return deriveHarnessState(report.events);
66812
67097
  }
66813
67098
  var init_harnessState = __esm({
@@ -66818,12 +67103,12 @@ var init_harnessState = __esm({
66818
67103
  });
66819
67104
 
66820
67105
  // src/cli/headless/harnessStateEmit.ts
66821
- import path89 from "node:path";
67106
+ import path90 from "node:path";
66822
67107
  async function emitHarnessStateEvent(opts) {
66823
67108
  if (opts.output !== "json") return;
66824
67109
  try {
66825
67110
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.workspaceRoot });
66826
- const state3 = await readHarnessState(path89.join(sessionsDir2, opts.spine.sessionId));
67111
+ const state3 = await readHarnessState(path90.join(sessionsDir2, opts.spine.sessionId));
66827
67112
  opts.emitEvent({ type: "harness_state", ...state3 });
66828
67113
  } catch (err) {
66829
67114
  const msg = err instanceof Error ? err.message : String(err);
@@ -67380,13 +67665,13 @@ var init_verifierLifecycle = __esm({
67380
67665
 
67381
67666
  // src/cli/extensions/sandboxedFs.ts
67382
67667
  import { promises as fsp } from "node:fs";
67383
- import path90 from "node:path";
67668
+ import path91 from "node:path";
67384
67669
  function errText(prefix, p3, err) {
67385
67670
  const msg = err instanceof Error ? err.message : String(err);
67386
67671
  return `[extension-fs] ${prefix} "${p3}": ${msg}`;
67387
67672
  }
67388
67673
  function bindSandboxedFs(root) {
67389
- const resolvedRoot = path90.resolve(root);
67674
+ const resolvedRoot = path91.resolve(root);
67390
67675
  return {
67391
67676
  root: resolvedRoot,
67392
67677
  async readFile(relativePath) {
@@ -67402,7 +67687,7 @@ function bindSandboxedFs(root) {
67402
67687
  try {
67403
67688
  const target = resolveSandboxedPath(relativePath, { root: resolvedRoot });
67404
67689
  verifyContainment(target, { root: resolvedRoot });
67405
- await fsp.mkdir(path90.dirname(target), { recursive: true });
67690
+ await fsp.mkdir(path91.dirname(target), { recursive: true });
67406
67691
  await fsp.writeFile(target, data, "utf8");
67407
67692
  return typedOk({ path: target });
67408
67693
  } catch (err) {
@@ -67587,7 +67872,7 @@ var init_loader = __esm({
67587
67872
 
67588
67873
  // src/cli/headless/runOneTurn.ts
67589
67874
  import { promises as fs44 } from "node:fs";
67590
- import path91 from "node:path";
67875
+ import path92 from "node:path";
67591
67876
  function planModeFromOpts(opts) {
67592
67877
  return (opts.phase ?? "build") === "plan";
67593
67878
  }
@@ -68065,11 +68350,14 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68065
68350
  return null;
68066
68351
  }
68067
68352
  },
68068
- emit: (input) => spine.appendEvent(input)
68353
+ // F3 seam adapter (same as the gate sites below): the core engine reads
68354
+ // the anchor as `out.seq`, while the spine resolves the seq NUMBER. A bare
68355
+ // number here leaves the review evidence unanchored on the spine.
68356
+ emit: async (input) => ({ seq: await spine.appendEvent(input) })
68069
68357
  };
68070
68358
  const strictEnv = strictEnvOverlay(opts);
68071
68359
  if (pass.finalReason === "completed" && pass.exitCode === 0 && isKrakenMode(opts.mode) && (isKrakenSelectionEnabled() || nativePackEnabled()) && !planModeFromOpts(opts)) {
68072
- const strictGate = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd, env: strictEnv });
68360
+ const strictGate = await evaluateStrictBuildGate("build", { emit: async (input) => ({ seq: await spine.appendEvent(input) }), cwd, env: strictEnv });
68073
68361
  await runAdvisoryVerifierReview(strictGate, verifierReviewDeps).catch(() => void 0);
68074
68362
  const gate = strictGate.gate;
68075
68363
  const verificationPayload = strictGateEventPayload(strictGate);
@@ -68079,7 +68367,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68079
68367
  }
68080
68368
  await writeProofSafe(strictGate, { surface: "kraken", sessionId: spine.sessionId }, cwd);
68081
68369
  if (strictGate.blocked) {
68082
- const repairPrompt = buildKrakenRepairPrompt(gate);
68370
+ const repairPrompt = buildKrakenRepairPrompt(gate, repairExcerptsFromEvaluation(strictGate));
68083
68371
  if (opts.output === "json") {
68084
68372
  emitEvent({
68085
68373
  type: "log",
@@ -68104,7 +68392,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68104
68392
  successfulWrites: pass.successfulWrites + repair.successfulWrites,
68105
68393
  emittedWrites: pass.emittedWrites + repair.emittedWrites
68106
68394
  };
68107
- const after = await evaluateStrictBuildGate("build", { emit: (input) => spine.appendEvent(input), cwd, env: strictEnv });
68395
+ const after = await evaluateStrictBuildGate("build", { emit: async (input) => ({ seq: await spine.appendEvent(input) }), cwd, env: strictEnv });
68108
68396
  await runAdvisoryVerifierReview(after, verifierReviewDeps).catch(() => void 0);
68109
68397
  const afterPayload = strictGateEventPayload(after);
68110
68398
  spine.verificationRun(afterPayload);
@@ -68154,7 +68442,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
68154
68442
  if (json3) {
68155
68443
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
68156
68444
  else {
68157
- await fs44.mkdir(path91.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
68445
+ await fs44.mkdir(path92.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
68158
68446
  await fs44.writeFile(opts.exportSessionPath, json3, "utf8");
68159
68447
  }
68160
68448
  }
@@ -69125,6 +69413,76 @@ var init_run = __esm({
69125
69413
  }
69126
69414
  });
69127
69415
 
69416
+ // src/cli/evolution/runTelemetry.ts
69417
+ var runTelemetry_exports = {};
69418
+ __export(runTelemetry_exports, {
69419
+ RunTelemetryAccumulator: () => RunTelemetryAccumulator
69420
+ });
69421
+ var RunTelemetryAccumulator;
69422
+ var init_runTelemetry = __esm({
69423
+ "src/cli/evolution/runTelemetry.ts"() {
69424
+ "use strict";
69425
+ RunTelemetryAccumulator = class {
69426
+ constructor(meta3 = {}) {
69427
+ this.meta = meta3;
69428
+ }
69429
+ totals = {
69430
+ inputTokens: 0,
69431
+ outputTokens: 0,
69432
+ cacheHitTokens: 0,
69433
+ toolCalls: 0,
69434
+ usageReports: 0
69435
+ };
69436
+ /** Mirror one dispatch/spine event. Never throws on unknown shapes. */
69437
+ observe(ev) {
69438
+ if (!ev || typeof ev !== "object" || !("type" in ev)) return;
69439
+ const e = ev;
69440
+ if (e["type"] === "tool_execution_end") {
69441
+ this.totals.toolCalls += 1;
69442
+ return;
69443
+ }
69444
+ if (e["type"] !== "message_end") return;
69445
+ const usage = e["usage"];
69446
+ if (!usage || typeof usage !== "object") return;
69447
+ const u = usage;
69448
+ if (typeof u["promptTokens"] === "number") this.totals.inputTokens += u["promptTokens"];
69449
+ if (typeof u["completionTokens"] === "number") this.totals.outputTokens += u["completionTokens"];
69450
+ if (typeof u["cachedPromptTokens"] === "number") this.totals.cacheHitTokens += u["cachedPromptTokens"];
69451
+ this.totals.usageReports += 1;
69452
+ }
69453
+ /** Cumulative totals (defensive copy). */
69454
+ usage() {
69455
+ return { ...this.totals };
69456
+ }
69457
+ /**
69458
+ * Final NDJSON `usage` event for JSON hosts (Desktop, competitive bench,
69459
+ * anchor runner). Emitted once per run, after the dispatch stream ends —
69460
+ * `tools/eval/competitive/adapters.ts#parseZelariUsage` reads exactly this
69461
+ * flat `{ inputTokens, outputTokens, cacheHitTokens, model?, provider? }`
69462
+ * shape, so the bench stops recording `tokens: null` with no bench change.
69463
+ */
69464
+ usageEvent() {
69465
+ return {
69466
+ type: "usage",
69467
+ ...this.usage(),
69468
+ ...this.meta.model ? { model: this.meta.model } : {},
69469
+ ...this.meta.provider ? { provider: this.meta.provider } : {}
69470
+ };
69471
+ }
69472
+ /**
69473
+ * Ledger projection: toolCalls always (event-countable), token fields ONLY
69474
+ * when backed by ≥1 provider usage report (unknown ≠ estimated ≠ zero).
69475
+ */
69476
+ ledgerFields() {
69477
+ return {
69478
+ toolCalls: this.totals.toolCalls,
69479
+ ...this.totals.usageReports > 0 ? { inputTokens: this.totals.inputTokens, outputTokens: this.totals.outputTokens } : {}
69480
+ };
69481
+ }
69482
+ };
69483
+ }
69484
+ });
69485
+
69128
69486
  // src/cli/triggerLock.ts
69129
69487
  var triggerLock_exports = {};
69130
69488
  __export(triggerLock_exports, {
@@ -69133,9 +69491,9 @@ __export(triggerLock_exports, {
69133
69491
  releaseLock: () => releaseLock
69134
69492
  });
69135
69493
  import { promises as fs45 } from "node:fs";
69136
- import * as path92 from "node:path";
69494
+ import * as path93 from "node:path";
69137
69495
  function lockPath(projectRoot) {
69138
- return path92.join(projectRoot, ".zelari", "trigger.lock");
69496
+ return path93.join(projectRoot, ".zelari", "trigger.lock");
69139
69497
  }
69140
69498
  function isPidAlive(pid) {
69141
69499
  try {
@@ -69148,7 +69506,7 @@ function isPidAlive(pid) {
69148
69506
  }
69149
69507
  async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
69150
69508
  const lp = lockPath(projectRoot);
69151
- const dir = path92.dirname(lp);
69509
+ const dir = path93.dirname(lp);
69152
69510
  await fs45.mkdir(dir, { recursive: true });
69153
69511
  try {
69154
69512
  const raw = await fs45.readFile(lp, "utf8");
@@ -69180,7 +69538,7 @@ var init_triggerLock = __esm({
69180
69538
 
69181
69539
  // src/cli/runHeadless.ts
69182
69540
  import { promises as fs46 } from "node:fs";
69183
- import path93 from "node:path";
69541
+ import path94 from "node:path";
69184
69542
  import { randomUUID as randomUUID10 } from "node:crypto";
69185
69543
  async function runHeadless(opts) {
69186
69544
  resetTaskSpawnCount();
@@ -69424,7 +69782,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
69424
69782
  try {
69425
69783
  let preflightGraph;
69426
69784
  if (opts.runPlan && opts.runPlan.trim() !== "") {
69427
- const planPath = path93.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
69785
+ const planPath = path94.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
69428
69786
  log(`loading pre-flight plan: ${planPath}`);
69429
69787
  let raw;
69430
69788
  try {
@@ -69467,8 +69825,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
69467
69825
  log(formatKrakenGraphAscii2(graph));
69468
69826
  if (opts.planOnly) {
69469
69827
  const planId = randomUUID10();
69470
- const planDir = path93.join(cwd, ".zelari", "radio");
69471
- const planPath = path93.join(planDir, `plan-${planId}.json`);
69828
+ const planDir = path94.join(cwd, ".zelari", "radio");
69829
+ const planPath = path94.join(planDir, `plan-${planId}.json`);
69472
69830
  await fs46.mkdir(planDir, { recursive: true });
69473
69831
  await fs46.writeFile(
69474
69832
  planPath,
@@ -69729,6 +70087,9 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69729
70087
  const scrub = createStreamScrubber2({ stripQuestion: opts.output !== "json" });
69730
70088
  let lastAssistantText = "";
69731
70089
  let currentAssistantText = "";
70090
+ const { RunTelemetryAccumulator: RunTelemetryAccumulator2 } = await Promise.resolve().then(() => (init_runTelemetry(), runTelemetry_exports));
70091
+ const telemetry = new RunTelemetryAccumulator2({ model, provider });
70092
+ const councilStartedAt = Date.now();
69732
70093
  try {
69733
70094
  const { composeProjectContext: composeProjectContext2 } = await Promise.resolve().then(() => (init_composeContext(), composeContext_exports));
69734
70095
  const { loadDurableContext: loadDurableContext2 } = await Promise.resolve().then(() => (init_loadDurableContext(), loadDurableContext_exports));
@@ -69784,6 +70145,7 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69784
70145
  currentAssistantText = "";
69785
70146
  }
69786
70147
  spine.observe(event);
70148
+ telemetry.observe(event);
69787
70149
  if (event.type === "message_delta" && typeof event.delta === "string") {
69788
70150
  const cleanDelta = scrub.push(event.delta);
69789
70151
  if (cleanDelta.length > 0) currentAssistantText += cleanDelta;
@@ -69811,6 +70173,9 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69811
70173
  }
69812
70174
  }
69813
70175
  }
70176
+ if (opts.output === "json") {
70177
+ emitEvent(telemetry.usageEvent());
70178
+ }
69814
70179
  } catch (err) {
69815
70180
  process.stderr.write(
69816
70181
  `[zelari-code --headless] council error: ${err instanceof Error ? err.message : String(err)}
@@ -69834,6 +70199,12 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69834
70199
  at: (/* @__PURE__ */ new Date()).toISOString(),
69835
70200
  mode: "shadow",
69836
70201
  taskClass: classifyTask2({ prompt: effectiveTask }).taskClass,
70202
+ // Steal #1/#2 wiring: real efficiency + attribution fields — the
70203
+ // ledger schema carried them since ADR-0036, this site never wrote them.
70204
+ latencyMs: Date.now() - councilStartedAt,
70205
+ model,
70206
+ provider,
70207
+ ...telemetry.ledgerFields(),
69837
70208
  verdict: signal.aborted ? "UNKNOWN" : exitCode === 0 ? "PASS" : exitCode === 3 ? "FAIL" : "UNKNOWN"
69838
70209
  });
69839
70210
  }
@@ -69846,7 +70217,7 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69846
70217
  if (json3) {
69847
70218
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
69848
70219
  else {
69849
- await fs46.mkdir(path93.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70220
+ await fs46.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
69850
70221
  await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
69851
70222
  }
69852
70223
  }
@@ -69901,14 +70272,17 @@ async function runHeadlessZelariBody(opts, provider, model, providerStream, extr
69901
70272
  spine.missionPhase("design", "mission-start");
69902
70273
  const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
69903
70274
  const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
70275
+ const { listOpenPlanTaskIds: listOpenPlanTaskIds2 } = await Promise.resolve().then(() => (init_planStore(), planStore_exports));
69904
70276
  const { getMemoryBackend: getMemoryBackend2 } = await Promise.resolve().then(() => (init_fileBackend(), fileBackend_exports));
69905
70277
  const { runZelariMission: runZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
69906
70278
  const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
69907
70279
  const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
69908
70280
  const { runPostCouncilHook: runPostCouncilHook2 } = await Promise.resolve().then(() => (init_postCouncilHook(), postCouncilHook_exports));
70281
+ const planTaskIds = await listOpenPlanTaskIds2(projectRoot);
69909
70282
  const brief = buildMissionBrief2({
69910
70283
  userMessage: opts.task,
69911
- hasPlan: hasWorkspacePlan2(projectRoot)
70284
+ hasPlan: hasWorkspacePlan2(projectRoot),
70285
+ planTaskIds
69912
70286
  });
69913
70287
  const memory = await getMemoryBackend2(
69914
70288
  projectRoot,
@@ -69993,7 +70367,9 @@ ${JSON.stringify({ deliverable: brief.deliverableThisMission, mvp: brief.sliceMv
69993
70367
  }
69994
70368
  }
69995
70369
  try {
69996
- const state3 = await runZelariMission2(missionTask, brief, {
70370
+ const { resumeZelariMission: resumeZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
70371
+ const runMission = (missionDeps) => opts.resumeMission ? resumeZelariMission2(missionDeps) : runZelariMission2(missionTask, brief, missionDeps);
70372
+ const state3 = await runMission({
69997
70373
  projectRoot,
69998
70374
  memory,
69999
70375
  emit,
@@ -70264,6 +70640,22 @@ ${ragContext}` : slicePrompt;
70264
70640
  if (missionGate.blocked) {
70265
70641
  exitCode = strictGateExitCode(missionGate);
70266
70642
  spine.missionPhase("verification", "mission-strict-blocked");
70643
+ } else if (
70644
+ // M2.1/R4b: an open strict gate is not enough — the success claim must
70645
+ // be event-backed: zero `verification.evidence` events in the spine
70646
+ // means narration-only done → strict exit code. Same overlay seam as
70647
+ // the gate above (H10-fix1) so --allow-unverified /
70648
+ // ZELARI_ALLOW_UNVERIFIED=1 waives mission-side too. `opts.phase` is
70649
+ // the only phase/mode discriminant on this site: `--phase plan`
70650
+ // missions are design-only (no verification expected), so the gate
70651
+ // applies unconditionally to build-phase claims.
70652
+ opts.phase !== "plan" && missionClaimExitCode(await spine.countVerificationEvidence(), strictEnvOverlay(opts)) !== 0
70653
+ ) {
70654
+ exitCode = STRICT_DONE_EXIT_CODE;
70655
+ spine.missionPhase("verification", "mission-event-back-missing");
70656
+ process.stderr.write(
70657
+ "[zelari-code --headless] mission success claim has zero verification.evidence events (narration-only done) \u2014 exit 4 (waive with --allow-unverified / ZELARI_ALLOW_UNVERIFIED=1)\n"
70658
+ );
70267
70659
  } else {
70268
70660
  exitCode = 0;
70269
70661
  spine.missionPhase("done", "mission-success");
@@ -70297,7 +70689,7 @@ ${ragContext}` : slicePrompt;
70297
70689
  if (json3) {
70298
70690
  if (opts.exportSessionPath === "-") process.stdout.write(json3 + "\n");
70299
70691
  else {
70300
- await fs46.mkdir(path93.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70692
+ await fs46.mkdir(path94.dirname(opts.exportSessionPath), { recursive: true }).catch(() => void 0);
70301
70693
  await fs46.writeFile(opts.exportSessionPath, json3, "utf8");
70302
70694
  }
70303
70695
  }
@@ -70922,7 +71314,7 @@ function upsertSkill(opts) {
70922
71314
  }
70923
71315
  dir = getProjectSkillsDir(root);
70924
71316
  }
70925
- const path100 = skillFilePath(dir, name);
71317
+ const path101 = skillFilePath(dir, name);
70926
71318
  const content = serializeSkillMd({
70927
71319
  name,
70928
71320
  description,
@@ -70931,13 +71323,13 @@ function upsertSkill(opts) {
70931
71323
  tools: opts.tools,
70932
71324
  cost: opts.cost
70933
71325
  });
70934
- const parsed = parseSkillMd(content, path100);
71326
+ const parsed = parseSkillMd(content, path101);
70935
71327
  if (!parsed) {
70936
71328
  return { ok: false, error: "Generated SKILL.md failed validation" };
70937
71329
  }
70938
- mkdirSync23(dirname13(path100), { recursive: true });
70939
- writeFileSync25(path100, content, "utf8");
70940
- return { ok: true, path: path100 };
71330
+ mkdirSync23(dirname13(path101), { recursive: true });
71331
+ writeFileSync25(path101, content, "utf8");
71332
+ return { ok: true, path: path101 };
70941
71333
  }
70942
71334
  function removeSkill(opts) {
70943
71335
  const name = opts.name.trim().toLowerCase();
@@ -70955,8 +71347,8 @@ function removeSkill(opts) {
70955
71347
  dir = getProjectSkillsDir(root);
70956
71348
  }
70957
71349
  const skillDir = join46(dir, name);
70958
- const path100 = skillFilePath(dir, name);
70959
- if (!existsSync59(path100) && !existsSync59(skillDir)) {
71350
+ const path101 = skillFilePath(dir, name);
71351
+ if (!existsSync59(path101) && !existsSync59(skillDir)) {
70960
71352
  return { ok: false, error: `Skill "${name}" not found in ${dir}` };
70961
71353
  }
70962
71354
  try {
@@ -70967,7 +71359,7 @@ function removeSkill(opts) {
70967
71359
  error: err instanceof Error ? err.message : String(err)
70968
71360
  };
70969
71361
  }
70970
- return { ok: true, path: path100 };
71362
+ return { ok: true, path: path101 };
70971
71363
  }
70972
71364
  var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
70973
71365
  var init_skillConfigIo = __esm({
@@ -71088,7 +71480,7 @@ var init_jsonApi = __esm({
71088
71480
  });
71089
71481
 
71090
71482
  // src/cli/memory/mcpAdapter.ts
71091
- import * as path94 from "node:path";
71483
+ import * as path95 from "node:path";
71092
71484
  var id2, projectId, source, SearchSchema, AddSchema, LinkSchema, RetractSchema, MEMORY_MCP_TOOLS, MemoryMcpAdapter;
71093
71485
  var init_mcpAdapter = __esm({
71094
71486
  "src/cli/memory/mcpAdapter.ts"() {
@@ -71258,8 +71650,8 @@ var init_mcpAdapter = __esm({
71258
71650
  this.takeWrite();
71259
71651
  const externalFile = args.source?.file;
71260
71652
  if (externalFile) {
71261
- const normalized = path94.normalize(externalFile);
71262
- if (path94.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path94.sep}`)) {
71653
+ const normalized = path95.normalize(externalFile);
71654
+ if (path95.isAbsolute(normalized) || normalized === ".." || normalized.startsWith(`..${path95.sep}`)) {
71263
71655
  throw new Error("source.file must be project-relative and cannot escape the project");
71264
71656
  }
71265
71657
  }
@@ -71786,12 +72178,12 @@ function ensureHome() {
71786
72178
  }
71787
72179
  }
71788
72180
  function loadCompanionConfig() {
71789
- const path100 = getCompanionConfigPath();
71790
- if (!existsSync60(path100)) {
72181
+ const path101 = getCompanionConfigPath();
72182
+ if (!existsSync60(path101)) {
71791
72183
  return { projects: [] };
71792
72184
  }
71793
72185
  try {
71794
- const raw = JSON.parse(readFileSync45(path100, "utf8"));
72186
+ const raw = JSON.parse(readFileSync45(path101, "utf8"));
71795
72187
  const projects = Array.isArray(raw.projects) ? raw.projects.filter(
71796
72188
  (p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
71797
72189
  ).map((p3) => ({
@@ -71829,16 +72221,16 @@ function loadOrCreateToken(explicit) {
71829
72221
  return { token: explicit.trim(), created: false };
71830
72222
  }
71831
72223
  ensureHome();
71832
- const path100 = getCompanionTokenPath();
71833
- if (existsSync60(path100)) {
71834
- const t = readFileSync45(path100, "utf8").trim();
72224
+ const path101 = getCompanionTokenPath();
72225
+ if (existsSync60(path101)) {
72226
+ const t = readFileSync45(path101, "utf8").trim();
71835
72227
  if (t) return { token: t, created: false };
71836
72228
  }
71837
72229
  const token = randomBytes7(24).toString("base64url");
71838
- writeFileSync26(path100, token + "\n", "utf8");
72230
+ writeFileSync26(path101, token + "\n", "utf8");
71839
72231
  try {
71840
72232
  const fs48 = __require("node:fs");
71841
- fs48.chmodSync?.(path100, 384);
72233
+ fs48.chmodSync?.(path101, 384);
71842
72234
  } catch {
71843
72235
  }
71844
72236
  return { token, created: true };
@@ -71863,17 +72255,17 @@ function mergeProjects(cfg, extraPaths) {
71863
72255
  byId.set(p3.id, p3);
71864
72256
  }
71865
72257
  for (const raw of extraPaths) {
71866
- const path100 = raw.trim();
71867
- if (!path100) continue;
71868
- let id3 = slugFromPath(path100);
72258
+ const path101 = raw.trim();
72259
+ if (!path101) continue;
72260
+ let id3 = slugFromPath(path101);
71869
72261
  let n = 2;
71870
- while (byId.has(id3) && byId.get(id3).path !== path100) {
71871
- id3 = `${slugFromPath(path100)}-${n++}`;
72262
+ while (byId.has(id3) && byId.get(id3).path !== path101) {
72263
+ id3 = `${slugFromPath(path101)}-${n++}`;
71872
72264
  }
71873
72265
  byId.set(id3, {
71874
72266
  id: id3,
71875
- name: slugFromPath(path100),
71876
- path: path100
72267
+ name: slugFromPath(path101),
72268
+ path: path101
71877
72269
  });
71878
72270
  }
71879
72271
  return [...byId.values()];
@@ -72116,7 +72508,7 @@ var init_askUserBridge = __esm({
72116
72508
 
72117
72509
  // src/cli/serve/spineLockSweep.ts
72118
72510
  import { promises as fs47 } from "node:fs";
72119
- import path95 from "node:path";
72511
+ import path96 from "node:path";
72120
72512
  async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
72121
72513
  const dir = sessionsDir2 ?? resolveSessionsDir();
72122
72514
  const onSwept = options.onSwept ?? ((sessionId2, reason) => {
@@ -72134,7 +72526,7 @@ async function sweepOrphanSpineLocks(sessionsDir2, options = {}) {
72134
72526
  return result;
72135
72527
  }
72136
72528
  for (const sessionId2 of entries) {
72137
- const lockPath2 = path95.join(dir, sessionId2, "writer.lock");
72529
+ const lockPath2 = path96.join(dir, sessionId2, "writer.lock");
72138
72530
  try {
72139
72531
  const raw = await fs47.readFile(lockPath2, "utf-8");
72140
72532
  let lockInfo = {};
@@ -73131,9 +73523,9 @@ async function runCompanionServe(opts = {}) {
73131
73523
  return;
73132
73524
  }
73133
73525
  const url2 = parseUrl(req);
73134
- const path100 = url2.pathname.replace(/\/+$/, "") || "/";
73526
+ const path101 = url2.pathname.replace(/\/+$/, "") || "/";
73135
73527
  try {
73136
- if (req.method === "GET" && (path100 === "/health" || path100 === "/v1/health")) {
73528
+ if (req.method === "GET" && (path101 === "/health" || path101 === "/v1/health")) {
73137
73529
  sendJson2(res, 200, {
73138
73530
  ok: true,
73139
73531
  service: "zelari-companion",
@@ -73145,18 +73537,18 @@ async function runCompanionServe(opts = {}) {
73145
73537
  });
73146
73538
  return;
73147
73539
  }
73148
- if (path100.startsWith("/v1")) {
73540
+ if (path101.startsWith("/v1")) {
73149
73541
  if (!tokenMatches(token, getBearer(req))) {
73150
73542
  sendJson2(res, 401, { ok: false, error: "unauthorized" });
73151
73543
  return;
73152
73544
  }
73153
73545
  }
73154
- if (req.method === "GET" && path100 === "/v1/config") {
73546
+ if (req.method === "GET" && path101 === "/v1/config") {
73155
73547
  const snap = buildDesktopConfigSnapshot();
73156
73548
  sendJson2(res, 200, { ok: true, ...snap });
73157
73549
  return;
73158
73550
  }
73159
- if (req.method === "GET" && path100 === "/v1/projects") {
73551
+ if (req.method === "GET" && path101 === "/v1/projects") {
73160
73552
  sendJson2(res, 200, {
73161
73553
  ok: true,
73162
73554
  projects: projects.map((p3) => ({
@@ -73167,7 +73559,7 @@ async function runCompanionServe(opts = {}) {
73167
73559
  });
73168
73560
  return;
73169
73561
  }
73170
- if (req.method === "GET" && path100 === "/v1/runs") {
73562
+ if (req.method === "GET" && path101 === "/v1/runs") {
73171
73563
  sendJson2(res, 200, {
73172
73564
  ok: true,
73173
73565
  active: runs.getActive(),
@@ -73185,7 +73577,7 @@ async function runCompanionServe(opts = {}) {
73185
73577
  });
73186
73578
  return;
73187
73579
  }
73188
- if (req.method === "POST" && path100 === "/v1/runs") {
73580
+ if (req.method === "POST" && path101 === "/v1/runs") {
73189
73581
  const raw = await readBody(req);
73190
73582
  let body = {};
73191
73583
  try {
@@ -73233,7 +73625,7 @@ async function runCompanionServe(opts = {}) {
73233
73625
  });
73234
73626
  return;
73235
73627
  }
73236
- const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path100);
73628
+ const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path101);
73237
73629
  if (req.method === "GET" && eventsMatch) {
73238
73630
  const runId = eventsMatch[1];
73239
73631
  const run = runs.getRun(runId);
@@ -73298,7 +73690,7 @@ async function runCompanionServe(opts = {}) {
73298
73690
  }, 500);
73299
73691
  return;
73300
73692
  }
73301
- const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path100);
73693
+ const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path101);
73302
73694
  if (req.method === "POST" && cancelMatch) {
73303
73695
  const runId = cancelMatch[1];
73304
73696
  const result = runs.cancel(runId);
@@ -73309,7 +73701,7 @@ async function runCompanionServe(opts = {}) {
73309
73701
  sendJson2(res, 200, { ok: true, cancelled: runId });
73310
73702
  return;
73311
73703
  }
73312
- const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path100);
73704
+ const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path101);
73313
73705
  if (req.method === "POST" && steerMatch) {
73314
73706
  const runId = steerMatch[1];
73315
73707
  const raw = await readBody(req);
@@ -73478,11 +73870,11 @@ import { execSync as execSync2 } from "node:child_process";
73478
73870
  import { existsSync as existsSync62, readFileSync as readFileSync46, readlinkSync, statSync as statSync10 } from "node:fs";
73479
73871
  import { createRequire as createRequire3 } from "node:module";
73480
73872
  import { fileURLToPath as fileURLToPath3 } from "node:url";
73481
- import path96 from "node:path";
73873
+ import path97 from "node:path";
73482
73874
  function findPackageRoot(start) {
73483
73875
  let dir = start;
73484
73876
  for (let i = 0; i < 6; i += 1) {
73485
- const candidate = path96.join(dir, "package.json");
73877
+ const candidate = path97.join(dir, "package.json");
73486
73878
  if (existsSync62(candidate)) {
73487
73879
  try {
73488
73880
  const pkg = JSON.parse(readFileSync46(candidate, "utf8"));
@@ -73490,11 +73882,11 @@ function findPackageRoot(start) {
73490
73882
  } catch {
73491
73883
  }
73492
73884
  }
73493
- const parent = path96.dirname(dir);
73885
+ const parent = path97.dirname(dir);
73494
73886
  if (parent === dir) break;
73495
73887
  dir = parent;
73496
73888
  }
73497
- return path96.resolve(__dirname3, "..", "..", "..");
73889
+ return path97.resolve(__dirname3, "..", "..", "..");
73498
73890
  }
73499
73891
  function tryExec(cmd) {
73500
73892
  try {
@@ -73508,7 +73900,7 @@ function tryExec(cmd) {
73508
73900
  }
73509
73901
  function readPackageJson4() {
73510
73902
  try {
73511
- const pkgPath = path96.join(packageRoot, "package.json");
73903
+ const pkgPath = path97.join(packageRoot, "package.json");
73512
73904
  return JSON.parse(readFileSync46(pkgPath, "utf8"));
73513
73905
  } catch {
73514
73906
  return null;
@@ -73520,7 +73912,7 @@ function getGlobalPrefix() {
73520
73912
  return (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || "").trim();
73521
73913
  }
73522
73914
  function isSourceCheckout() {
73523
- return existsSync62(path96.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path96.join(packageRoot, "apps", "desktop", "package.json"));
73915
+ return existsSync62(path97.join(packageRoot, "src", "cli", "main.ts")) && existsSync62(path97.join(packageRoot, "apps", "desktop", "package.json"));
73524
73916
  }
73525
73917
  function checkShim(pkgName) {
73526
73918
  const prefix = getGlobalPrefix();
@@ -73529,9 +73921,9 @@ function checkShim(pkgName) {
73529
73921
  }
73530
73922
  const isWin = process.platform === "win32";
73531
73923
  const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
73532
- const shimPath = path96.join(prefix, shimName);
73924
+ const shimPath = path97.join(prefix, shimName);
73533
73925
  if (!existsSync62(shimPath)) {
73534
- const localBin = path96.join(packageRoot, "bin", "zelari-code.js");
73926
+ const localBin = path97.join(packageRoot, "bin", "zelari-code.js");
73535
73927
  if (isSourceCheckout() && existsSync62(localBin)) {
73536
73928
  return WARN(
73537
73929
  `global shim not found at ${shimPath}
@@ -73565,8 +73957,8 @@ function checkShim(pkgName) {
73565
73957
  fix: npm install -g ${pkgName}@latest --force`
73566
73958
  );
73567
73959
  }
73568
- const resolved = path96.resolve(path96.dirname(shimPath), target);
73569
- const expected = path96.join(
73960
+ const resolved = path97.resolve(path97.dirname(shimPath), target);
73961
+ const expected = path97.join(
73570
73962
  prefix,
73571
73963
  "node_modules",
73572
73964
  pkgName,
@@ -73608,7 +74000,7 @@ function checkNode(pkg) {
73608
74000
  return OK(`node ${raw} (engines.node ${enginesNode ?? ">= 20.0.0"})`);
73609
74001
  }
73610
74002
  function checkBundle() {
73611
- const bundle = path96.join(packageRoot, "dist", "cli", "main.bundled.js");
74003
+ const bundle = path97.join(packageRoot, "dist", "cli", "main.bundled.js");
73612
74004
  if (!existsSync62(bundle)) {
73613
74005
  return FAIL(
73614
74006
  `dist/cli/main.bundled.js missing at ${bundle}
@@ -73629,7 +74021,7 @@ function checkRuntimeDeps() {
73629
74021
  const missing = [];
73630
74022
  for (const dep of required2) {
73631
74023
  try {
73632
- const localReq = createRequire3(path96.join(packageRoot, "package.json"));
74024
+ const localReq = createRequire3(path97.join(packageRoot, "package.json"));
73633
74025
  localReq.resolve(dep);
73634
74026
  } catch {
73635
74027
  missing.push(dep);
@@ -73906,7 +74298,7 @@ var init_doctor = __esm({
73906
74298
  init_metrics3();
73907
74299
  init_contextGrowthSummary();
73908
74300
  require3 = createRequire3(import.meta.url);
73909
- __dirname3 = path96.dirname(fileURLToPath3(import.meta.url));
74301
+ __dirname3 = path97.dirname(fileURLToPath3(import.meta.url));
73910
74302
  packageRoot = findPackageRoot(__dirname3);
73911
74303
  OK = (message) => ({
73912
74304
  ok: true,
@@ -74015,7 +74407,7 @@ __export(userSettings_exports, {
74015
74407
  settingsOverrides: () => settingsOverrides
74016
74408
  });
74017
74409
  import { existsSync as existsSync63, readFileSync as readFileSync47 } from "node:fs";
74018
- import path97 from "node:path";
74410
+ import path98 from "node:path";
74019
74411
  function parseBool(raw) {
74020
74412
  const v = raw.trim().toLowerCase();
74021
74413
  if (["1", "true", "yes", "on"].includes(v)) return true;
@@ -74082,8 +74474,8 @@ function envValueFor(key, env) {
74082
74474
  function resolveUserSettings(opts = {}) {
74083
74475
  const cwd = opts.cwd ?? process.cwd();
74084
74476
  const env = opts.env ?? process.env;
74085
- const userPath = path97.join(zelariHome(), SETTINGS_FILE_NAME);
74086
- const projectPath = path97.join(cwd, ".zelari", SETTINGS_FILE_NAME);
74477
+ const userPath = path98.join(zelariHome(), SETTINGS_FILE_NAME);
74478
+ const projectPath = path98.join(cwd, ".zelari", SETTINGS_FILE_NAME);
74087
74479
  const warnings = [];
74088
74480
  const userLayer = loadFileLayer(userPath, "user", warnings);
74089
74481
  const projectLayer = loadFileLayer(projectPath, "project", warnings);
@@ -74297,7 +74689,7 @@ __export(inspectSession_exports, {
74297
74689
  renderInspectReport: () => renderInspectReport,
74298
74690
  runInspectSession: () => runInspectSession
74299
74691
  });
74300
- import path98 from "node:path";
74692
+ import path99 from "node:path";
74301
74693
  import { existsSync as existsSync64 } from "node:fs";
74302
74694
  function formatLimit(limit) {
74303
74695
  return `${Math.round(limit / 1e3)}k`;
@@ -74331,8 +74723,8 @@ function renderInspectReport(state3) {
74331
74723
  }
74332
74724
  async function runInspectSession(opts) {
74333
74725
  const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.cwd ?? process.cwd() });
74334
- const sessionDir = path98.join(sessionsDir2, opts.sessionId);
74335
- const eventsPath = path98.join(sessionDir, "events.jsonl");
74726
+ const sessionDir = path99.join(sessionsDir2, opts.sessionId);
74727
+ const eventsPath = path99.join(sessionDir, "events.jsonl");
74336
74728
  if (!existsSync64(sessionDir)) {
74337
74729
  console.error(`zelari-code inspect: no session directory at ${sessionDir}`);
74338
74730
  return 1;
@@ -74366,14 +74758,14 @@ __export(inspect_exports, {
74366
74758
  collectInspectReport: () => collectInspectReport,
74367
74759
  runInspect: () => runInspect
74368
74760
  });
74369
- import path99 from "node:path";
74761
+ import path100 from "node:path";
74370
74762
  import { existsSync as existsSync65, readFileSync as readFileSync48, readdirSync as readdirSync13 } from "node:fs";
74371
74763
  async function collectInspectReport(cwd = process.cwd()) {
74372
74764
  ensureBuiltinSkillsLoadedSync();
74373
74765
  const snap = listSkillsSnapshot(cwd);
74374
74766
  const mcp = listMcpServers(cwd);
74375
- const userMcpPath = path99.join(zelariHome(), "mcp.json");
74376
- const projectMcpPath = path99.join(cwd, ".zelari", "mcp.json");
74767
+ const userMcpPath = path100.join(zelariHome(), "mcp.json");
74768
+ const projectMcpPath = path100.join(cwd, ".zelari", "mcp.json");
74377
74769
  const globalHooks = globalHooksDir();
74378
74770
  const projectHooks = projectHooksDir(cwd);
74379
74771
  const projectTrusted = isFolderTrusted(cwd);
@@ -74401,9 +74793,9 @@ async function collectInspectReport(cwd = process.cwd()) {
74401
74793
  configSources: [
74402
74794
  { path: userMcpPath, exists: existsSync65(userMcpPath) },
74403
74795
  { path: projectMcpPath, exists: existsSync65(projectMcpPath) },
74404
- { path: path99.join(zelariHome(), "provider.json"), exists: existsSync65(path99.join(zelariHome(), "provider.json")) },
74405
- { path: path99.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync65(path99.join(cwd, ".zelari", "AGENTS.md")) },
74406
- { path: path99.join(cwd, "AGENTS.md"), exists: existsSync65(path99.join(cwd, "AGENTS.md")) }
74796
+ { path: path100.join(zelariHome(), "provider.json"), exists: existsSync65(path100.join(zelariHome(), "provider.json")) },
74797
+ { path: path100.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync65(path100.join(cwd, ".zelari", "AGENTS.md")) },
74798
+ { path: path100.join(cwd, "AGENTS.md"), exists: existsSync65(path100.join(cwd, "AGENTS.md")) }
74407
74799
  ],
74408
74800
  skills: {
74409
74801
  total: snap.skills.length,
@@ -74443,8 +74835,8 @@ function listJsonFiles(dir) {
74443
74835
  }
74444
74836
  function findAgentsMd(cwd) {
74445
74837
  const candidates = [
74446
- path99.join(cwd, "AGENTS.md"),
74447
- path99.join(cwd, ".zelari", "AGENTS.md")
74838
+ path100.join(cwd, "AGENTS.md"),
74839
+ path100.join(cwd, ".zelari", "AGENTS.md")
74448
74840
  ];
74449
74841
  const found = [];
74450
74842
  for (const c of candidates) {
@@ -78197,7 +78589,10 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
78197
78589
  progressRuntime.observe(event);
78198
78590
  if (event.type === "agent_end") {
78199
78591
  let krakenSuppressFinish = false;
78200
- const krakenSpineEmit = (input) => writerRef.current?.spine?.appendEvent(input) ?? Promise.resolve(null);
78592
+ const krakenSpineEmit = async (input) => {
78593
+ const seq = await (writerRef.current?.spine?.appendEvent(input) ?? Promise.resolve(null));
78594
+ return { seq };
78595
+ };
78201
78596
  const writeProofSafe2 = (gate) => writeCompletionProof(gate, { meta: { surface: "kraken", sessionId: sessionId2 } }).then(
78202
78597
  () => void 0,
78203
78598
  () => void 0
@@ -78211,7 +78606,9 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
78211
78606
  if (krakenGate.blocked) {
78212
78607
  krakenRepairEnqueued = true;
78213
78608
  markRepairTriggered();
78214
- harness2.enqueue(buildKrakenRepairPrompt(krakenGate));
78609
+ harness2.enqueue(
78610
+ buildKrakenRepairPrompt(krakenGate, repairExcerptsFromEvaluation(strictGate))
78611
+ );
78215
78612
  appendSystem(
78216
78613
  setMessages,
78217
78614
  formatStrictBlockExplanation(strictGate),
@@ -79407,11 +79804,14 @@ async function dispatchZelariPromptImpl(text, deps, pendingRef) {
79407
79804
  }
79408
79805
  const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
79409
79806
  const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
79807
+ const { listOpenPlanTaskIds: listOpenPlanTaskIds2 } = await Promise.resolve().then(() => (init_planStore(), planStore_exports));
79410
79808
  const { formatBriefForChat: formatBriefForChat2, isMissionAutoStart: isMissionAutoStart2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
79411
79809
  const projectRoot = process.cwd();
79810
+ const planTaskIds = await listOpenPlanTaskIds2(projectRoot);
79412
79811
  const brief = buildMissionBrief2({
79413
79812
  userMessage: text,
79414
- hasPlan: hasWorkspacePlan2(projectRoot)
79813
+ hasPlan: hasWorkspacePlan2(projectRoot),
79814
+ planTaskIds
79415
79815
  });
79416
79816
  emit(formatBriefForChat2(brief));
79417
79817
  if (isMissionAutoStart2()) {
@@ -79437,11 +79837,14 @@ async function runZelariMissionInTui(userMessage, deps, emit) {
79437
79837
  const projectRoot = process.cwd();
79438
79838
  const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
79439
79839
  const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
79840
+ const { listOpenPlanTaskIds: listOpenPlanTaskIds2 } = await Promise.resolve().then(() => (init_planStore(), planStore_exports));
79440
79841
  const { getMemoryBackend: getMemoryBackend2 } = await Promise.resolve().then(() => (init_fileBackend(), fileBackend_exports));
79441
79842
  const { runZelariMission: runZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
79843
+ const planTaskIds = await listOpenPlanTaskIds2(projectRoot);
79442
79844
  const brief = buildMissionBrief2({
79443
79845
  userMessage,
79444
- hasPlan: hasWorkspacePlan2(projectRoot)
79846
+ hasPlan: hasWorkspacePlan2(projectRoot),
79847
+ planTaskIds
79445
79848
  });
79446
79849
  const missionSpineHolder = {
79447
79850
  get current() {
@@ -79699,10 +80102,10 @@ init_ledger();
79699
80102
 
79700
80103
  // src/cli/evolution/proposals.ts
79701
80104
  import { existsSync as existsSync51, readFileSync as readFileSync39 } from "node:fs";
79702
- import path77 from "node:path";
79703
- var PROPOSALS_REL = path77.join(".zelari", "evolution", "proposals.jsonl");
80105
+ import path78 from "node:path";
80106
+ var PROPOSALS_REL = path78.join(".zelari", "evolution", "proposals.jsonl");
79704
80107
  function proposalsPath(cwd) {
79705
- return path77.join(cwd, PROPOSALS_REL);
80108
+ return path78.join(cwd, PROPOSALS_REL);
79706
80109
  }
79707
80110
  function readProposalStore(cwd) {
79708
80111
  const file2 = proposalsPath(cwd);
@@ -80812,11 +81215,11 @@ function handleCacheStats(ctx) {
80812
81215
  init_messageHelpers();
80813
81216
  init_serviceFactory();
80814
81217
  import { promises as fs35 } from "node:fs";
80815
- import * as path79 from "node:path";
81218
+ import * as path80 from "node:path";
80816
81219
 
80817
81220
  // src/cli/memory/promotion.ts
80818
81221
  import { promises as fs34 } from "node:fs";
80819
- import * as path78 from "node:path";
81222
+ import * as path79 from "node:path";
80820
81223
  var START = "<!-- zelari:memory-promotions:start -->";
80821
81224
  var END = "<!-- zelari:memory-promotions:end -->";
80822
81225
  var DURABLE_KINDS = /* @__PURE__ */ new Set(["fact", "decision", "constraint", "preference", "procedure"]);
@@ -80827,13 +81230,13 @@ function lineFor(node) {
80827
81230
  }
80828
81231
  async function promoteMemoryToAgentsMd(projectRoot, node) {
80829
81232
  if (node.status !== "active") {
80830
- return { added: false, path: path78.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
81233
+ return { added: false, path: path79.join(projectRoot, "AGENTS.md"), reason: `memory is ${node.status}` };
80831
81234
  }
80832
81235
  if (!DURABLE_KINDS.has(node.kind)) {
80833
- return { added: false, path: path78.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
81236
+ return { added: false, path: path79.join(projectRoot, "AGENTS.md"), reason: `${node.kind} is not a durable instruction kind` };
80834
81237
  }
80835
- const root = await fs34.realpath(projectRoot).catch(() => path78.resolve(projectRoot));
80836
- const target = path78.join(root, "AGENTS.md");
81238
+ const root = await fs34.realpath(projectRoot).catch(() => path79.resolve(projectRoot));
81239
+ const target = path79.join(root, "AGENTS.md");
80837
81240
  try {
80838
81241
  const stat8 = await fs34.lstat(target);
80839
81242
  if (stat8.isSymbolicLink() || !stat8.isFile()) throw new Error("AGENTS.md must be a regular project file.");
@@ -80898,22 +81301,22 @@ function sourceLine(source2) {
80898
81301
  return entries.length ? entries.map(([key, value]) => `${key}=${value}`).join(" \xB7 ") : "unknown";
80899
81302
  }
80900
81303
  function isInside(root, target) {
80901
- const relative6 = path79.relative(root, target);
80902
- return relative6 === "" || !relative6.startsWith("..") && !path79.isAbsolute(relative6);
81304
+ const relative6 = path80.relative(root, target);
81305
+ return relative6 === "" || !relative6.startsWith("..") && !path80.isAbsolute(relative6);
80903
81306
  }
80904
81307
  async function safeExportPath(cwd, requested) {
80905
- const lexicalRoot = path79.resolve(cwd);
81308
+ const lexicalRoot = path80.resolve(cwd);
80906
81309
  const root = await fs35.realpath(lexicalRoot).catch(() => lexicalRoot);
80907
- const fallback = path79.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
80908
- const target = requested?.trim() ? path79.resolve(root, requested.trim()) : fallback;
81310
+ const fallback = path80.join(root, ".zelari", "memory", `export-${Date.now()}.json`);
81311
+ const target = requested?.trim() ? path80.resolve(root, requested.trim()) : fallback;
80909
81312
  if (!isInside(root, target)) {
80910
81313
  throw new Error("Export path must stay inside the active project.");
80911
81314
  }
80912
- const parent = path79.dirname(target);
80913
- const relativeParent = path79.relative(root, parent);
81315
+ const parent = path80.dirname(target);
81316
+ const relativeParent = path80.relative(root, parent);
80914
81317
  let cursor = root;
80915
- for (const segment of relativeParent.split(path79.sep).filter(Boolean)) {
80916
- cursor = path79.join(cursor, segment);
81318
+ for (const segment of relativeParent.split(path80.sep).filter(Boolean)) {
81319
+ cursor = path80.join(cursor, segment);
80917
81320
  try {
80918
81321
  const stat8 = await fs35.lstat(cursor);
80919
81322
  if (stat8.isSymbolicLink()) {
@@ -81085,9 +81488,9 @@ ${message}` : message
81085
81488
  }
81086
81489
  case "export": {
81087
81490
  const target = await safeExportPath(ctx.cwd, args.join(" ").trim() || void 0);
81088
- await fs35.mkdir(path79.dirname(target), { recursive: true });
81089
- const root = await fs35.realpath(ctx.cwd).catch(() => path79.resolve(ctx.cwd));
81090
- const realParent = await fs35.realpath(path79.dirname(target));
81491
+ await fs35.mkdir(path80.dirname(target), { recursive: true });
81492
+ const root = await fs35.realpath(ctx.cwd).catch(() => path80.resolve(ctx.cwd));
81493
+ const realParent = await fs35.realpath(path80.dirname(target));
81091
81494
  if (!isInside(root, realParent)) {
81092
81495
  throw new Error("Export path resolves outside the active project.");
81093
81496
  }
@@ -81302,7 +81705,7 @@ import { promises as fs37 } from "node:fs";
81302
81705
  init_zod();
81303
81706
  init_taskTool();
81304
81707
  import { promises as fs36 } from "node:fs";
81305
- import path80 from "node:path";
81708
+ import path81 from "node:path";
81306
81709
  import { randomBytes as randomBytes6 } from "node:crypto";
81307
81710
  var CsvFanoutArgsSchema = external_exports.object({
81308
81711
  csv_path: external_exports.string().min(1),
@@ -81396,8 +81799,8 @@ function resolveMaxConcurrency(env = process.env) {
81396
81799
  }
81397
81800
  async function runCsvFanout(args, deps, opts) {
81398
81801
  const start = Date.now();
81399
- const absCsv = path80.isAbsolute(args.csv_path) ? args.csv_path : path80.join(opts.parentCwd, args.csv_path);
81400
- const absOut = path80.isAbsolute(args.output_csv_path) ? args.output_csv_path : path80.join(opts.parentCwd, args.output_csv_path);
81802
+ const absCsv = path81.isAbsolute(args.csv_path) ? args.csv_path : path81.join(opts.parentCwd, args.csv_path);
81803
+ const absOut = path81.isAbsolute(args.output_csv_path) ? args.output_csv_path : path81.join(opts.parentCwd, args.output_csv_path);
81401
81804
  const { headers: headers3, rows } = await readCsv(absCsv);
81402
81805
  if (headers3.length === 0) {
81403
81806
  throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
@@ -81453,7 +81856,7 @@ async function runCsvFanout(args, deps, opts) {
81453
81856
  errored += 1;
81454
81857
  errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
81455
81858
  }
81456
- await fs36.mkdir(path80.dirname(absOut), { recursive: true });
81859
+ await fs36.mkdir(path81.dirname(absOut), { recursive: true });
81457
81860
  await queueWrite(serializeCsv(outHeaders, outputRecords));
81458
81861
  }
81459
81862
  }
@@ -81648,7 +82051,7 @@ function splitArgs(s) {
81648
82051
  // src/cli/slashHandlers/krakenWorkbench.ts
81649
82052
  init_messageHelpers();
81650
82053
  import { promises as fs38 } from "node:fs";
81651
- import path81 from "node:path";
82054
+ import path82 from "node:path";
81652
82055
 
81653
82056
  // src/cli/kraken/workbenchView.ts
81654
82057
  var EMPTY = {
@@ -81765,14 +82168,14 @@ function formatWorkbenchForTerminal(p3) {
81765
82168
 
81766
82169
  // src/cli/slashHandlers/krakenWorkbench.ts
81767
82170
  async function handleKrakenWorkbench(ctx) {
81768
- const dir = path81.join(ctx.cwd, ".zelari", "radio");
82171
+ const dir = path82.join(ctx.cwd, ".zelari", "radio");
81769
82172
  let latest = null;
81770
82173
  let latestMtime = 0;
81771
82174
  try {
81772
82175
  const files = await fs38.readdir(dir);
81773
82176
  for (const f of files) {
81774
82177
  if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
81775
- const full = path81.join(dir, f);
82178
+ const full = path82.join(dir, f);
81776
82179
  const stat8 = await fs38.stat(full);
81777
82180
  if (stat8.mtimeMs > latestMtime) {
81778
82181
  latestMtime = stat8.mtimeMs;
@@ -81789,10 +82192,10 @@ async function handleKrakenWorkbench(ctx) {
81789
82192
  const parsed = parseWorkbench(content);
81790
82193
  const rendered = formatWorkbenchForTerminal(parsed);
81791
82194
  if (!rendered.trim()) {
81792
- appendSystem(ctx.setMessages, `[kraken workbench] ${path81.basename(latest)}: (no nodes / no events yet)`);
82195
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path82.basename(latest)}: (no nodes / no events yet)`);
81793
82196
  return;
81794
82197
  }
81795
- appendSystem(ctx.setMessages, `[kraken workbench] ${path81.basename(latest)}:
82198
+ appendSystem(ctx.setMessages, `[kraken workbench] ${path82.basename(latest)}:
81796
82199
  ${rendered}`);
81797
82200
  }
81798
82201
 
@@ -82100,14 +82503,14 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
82100
82503
  init_messageHelpers();
82101
82504
  init_paths();
82102
82505
  import { promises as fs39 } from "node:fs";
82103
- import path84 from "node:path";
82506
+ import path85 from "node:path";
82104
82507
  async function handlePromoteMember(ctx, memberId) {
82105
82508
  try {
82106
82509
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
82107
82510
  const { skill, markdown } = promoteMember2(memberId);
82108
82511
  const skillDir = skillsDir();
82109
82512
  await fs39.mkdir(skillDir, { recursive: true });
82110
- const filePath = path84.join(skillDir, `${skill.id}.md`);
82513
+ const filePath = path85.join(skillDir, `${skill.id}.md`);
82111
82514
  const previous = await fs39.readFile(filePath, "utf8").catch(() => null);
82112
82515
  const { createHash: createHash24 } = await import("node:crypto");
82113
82516
  const sha = (s) => createHash24("sha256").update(s, "utf8").digest("hex");
@@ -82133,7 +82536,7 @@ ${lineage}
82133
82536
  // src/cli/branchManager.ts
82134
82537
  init_paths();
82135
82538
  import { promises as fs40, existsSync as existsSync55, readFileSync as readFileSync41, writeFileSync as writeFileSync24, mkdirSync as mkdirSync21, statSync as statSync7, rmSync as rmSync3 } from "node:fs";
82136
- import path85 from "node:path";
82539
+ import path86 from "node:path";
82137
82540
  var META_FILENAME = "meta.json";
82138
82541
  var SESSIONS_SUBDIR = "sessions";
82139
82542
  function getBranchesBaseDir() {
@@ -82143,13 +82546,13 @@ function getSessionsBaseDir() {
82143
82546
  return sessionsDir();
82144
82547
  }
82145
82548
  function branchPathFor(name, baseDir) {
82146
- return path85.join(baseDir, name);
82549
+ return path86.join(baseDir, name);
82147
82550
  }
82148
82551
  function metaPathFor(name, baseDir) {
82149
- return path85.join(baseDir, name, META_FILENAME);
82552
+ return path86.join(baseDir, name, META_FILENAME);
82150
82553
  }
82151
82554
  function sessionsPathFor(name, baseDir) {
82152
- return path85.join(baseDir, name, SESSIONS_SUBDIR);
82555
+ return path86.join(baseDir, name, SESSIONS_SUBDIR);
82153
82556
  }
82154
82557
  function readBranchMeta(name, baseDir) {
82155
82558
  const metaPath = metaPathFor(name, baseDir);
@@ -82174,7 +82577,7 @@ function readBranchMeta(name, baseDir) {
82174
82577
  }
82175
82578
  function writeBranchMeta(name, baseDir, meta3) {
82176
82579
  const metaPath = metaPathFor(name, baseDir);
82177
- mkdirSync21(path85.dirname(metaPath), { recursive: true });
82580
+ mkdirSync21(path86.dirname(metaPath), { recursive: true });
82178
82581
  writeFileSync24(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
82179
82582
  }
82180
82583
  async function countSessions(name, baseDir) {
@@ -82225,14 +82628,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
82225
82628
  if (branchExists(name, baseDir)) {
82226
82629
  throw new BranchAlreadyExistsError(name);
82227
82630
  }
82228
- const sourcePath = path85.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
82631
+ const sourcePath = path86.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
82229
82632
  if (!existsSync55(sourcePath)) {
82230
82633
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
82231
82634
  }
82232
82635
  const branchPath = branchPathFor(name, baseDir);
82233
82636
  const branchSessionsPath = sessionsPathFor(name, baseDir);
82234
82637
  mkdirSync21(branchSessionsPath, { recursive: true });
82235
- const destPath = path85.join(branchSessionsPath, `${fromSessionId}.jsonl`);
82638
+ const destPath = path86.join(branchSessionsPath, `${fromSessionId}.jsonl`);
82236
82639
  await fs40.copyFile(sourcePath, destPath);
82237
82640
  const meta3 = {
82238
82641
  name,
@@ -82336,14 +82739,14 @@ async function handleBranchCheckout(ctx, branchName) {
82336
82739
  // src/cli/slashHandlers/workspace.ts
82337
82740
  init_messageHelpers();
82338
82741
  import { promises as fs41 } from "node:fs";
82339
- import path86 from "node:path";
82742
+ import path87 from "node:path";
82340
82743
  async function handleWorkspaceShow(ctx, what) {
82341
82744
  try {
82342
- const zelari = path86.join(process.cwd(), ".zelari");
82745
+ const zelari = path87.join(process.cwd(), ".zelari");
82343
82746
  let content;
82344
82747
  switch (what) {
82345
82748
  case "plan": {
82346
- const planPath = path86.join(zelari, "plan.md");
82749
+ const planPath = path87.join(zelari, "plan.md");
82347
82750
  try {
82348
82751
  content = await fs41.readFile(planPath, "utf-8");
82349
82752
  } catch {
@@ -82352,7 +82755,7 @@ async function handleWorkspaceShow(ctx, what) {
82352
82755
  break;
82353
82756
  }
82354
82757
  case "decisions": {
82355
- const decisionsDir = path86.join(zelari, "decisions");
82758
+ const decisionsDir = path87.join(zelari, "decisions");
82356
82759
  try {
82357
82760
  const files = (await fs41.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
82358
82761
  if (files.length === 0) {
@@ -82362,7 +82765,7 @@ async function handleWorkspaceShow(ctx, what) {
82362
82765
  `];
82363
82766
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
82364
82767
  for (const f of files) {
82365
- const raw = await fs41.readFile(path86.join(decisionsDir, f), "utf-8");
82768
+ const raw = await fs41.readFile(path87.join(decisionsDir, f), "utf-8");
82366
82769
  const { meta: meta3, body } = parseFrontmatter2(raw);
82367
82770
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
82368
82771
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -82375,7 +82778,7 @@ async function handleWorkspaceShow(ctx, what) {
82375
82778
  break;
82376
82779
  }
82377
82780
  case "risks": {
82378
- const risksPath = path86.join(zelari, "risks.md");
82781
+ const risksPath = path87.join(zelari, "risks.md");
82379
82782
  try {
82380
82783
  content = await fs41.readFile(risksPath, "utf-8");
82381
82784
  } catch {
@@ -82384,7 +82787,7 @@ async function handleWorkspaceShow(ctx, what) {
82384
82787
  break;
82385
82788
  }
82386
82789
  case "agents": {
82387
- const agentsPath = path86.join(process.cwd(), "AGENTS.MD");
82790
+ const agentsPath = path87.join(process.cwd(), "AGENTS.MD");
82388
82791
  try {
82389
82792
  content = await fs41.readFile(agentsPath, "utf-8");
82390
82793
  } catch {
@@ -82393,7 +82796,7 @@ async function handleWorkspaceShow(ctx, what) {
82393
82796
  break;
82394
82797
  }
82395
82798
  case "docs": {
82396
- const docsDir = path86.join(zelari, "docs");
82799
+ const docsDir = path87.join(zelari, "docs");
82397
82800
  try {
82398
82801
  const files = (await fs41.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
82399
82802
  content = files.length ? `# Docs (${files.length})
@@ -82435,7 +82838,7 @@ async function handleWorkspaceReset(ctx, force) {
82435
82838
  return;
82436
82839
  }
82437
82840
  try {
82438
- const target = path86.join(process.cwd(), ".zelari");
82841
+ const target = path87.join(process.cwd(), ".zelari");
82439
82842
  await fs41.rm(target, { recursive: true, force: true });
82440
82843
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
82441
82844
  } catch (err) {
@@ -84319,8 +84722,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
84319
84722
  let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
84320
84723
  if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
84321
84724
  try {
84322
- 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);
84323
- name = path100 && /^[a-z0-9]/.test(path100) ? path100 : "imported-skill";
84725
+ const path101 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
84726
+ name = path101 && /^[a-z0-9]/.test(path101) ? path101 : "imported-skill";
84324
84727
  } catch {
84325
84728
  name = "imported-skill";
84326
84729
  }
@@ -84733,7 +85136,7 @@ proposals: npm run evolve:propose \u2014 decisions in npm run evolve:decide (P1:
84733
85136
  }
84734
85137
  if (argv.includes("--help") || argv.includes("-h")) {
84735
85138
  console.log(
84736
- "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 --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 --export-session <path> Write zelari-session-export/1 after the run\n --strict-done Evidence-based BUILD completion gate\n --task-file <path> Read the task prompt from a file (Windows argv cap)\n --once Single-cycle run (cron/git-hook triggers, ADR-0014)\n --kraken-graph <goal> Plan + execute a Kraken task graph\n (variant: --kraken-graph-file <path>; kill-switch\n ZELARI_KRAKEN_GRAPH=0)\n --plan-only Serialize the graph plan to .zelari/radio/ and exit 0\n --run-plan <id> Execute a pre-built .zelari/radio/plan-<id>.json\n --gauntlet Host-driven gauntlet loop (builder/critic tentacles)\n --session-export <id> Print a portable 2.0 session export (no LLM)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --serve-harness Long-lived harness kernel for hosts (NDJSON JSON-RPC\n on stdin/stdout; Desktop/companion transport)\n --print-config Print provider/model config as JSON (no secrets)\n --print-settings Print zelari.config.json values + the origin of\n each (default < user < project < env)\n --permissions <p> Permission preset: strict | standard | yolo \u2014 changes\n category DEFAULTS only (env vars and policy files win)\n --evolve-status Evolution ledger stats (read-only; ADR-0036; the\n ledger is written only when ZELARI_EVOLUTION=shadow)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --thinking <spec> Thinking effort (auto|off|low|medium|high|budget:N)\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --login-oauth Start subscription OAuth (grok, chatgpt, anthropic)\n --provider <id> grok | chatgpt | anthropic\n --code <paste> Anthropic magic-link code (CODE#STATE)\n --no-browser Do not open the system browser\n --refresh-oauth Force-refresh an OAuth access token\n --provider <id> grok | chatgpt | anthropic\n --logout-oauth Clear stored OAuth credentials\n --provider <id> grok | chatgpt | anthropic\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable for stdio servers\n --url <endpoint> Streamable HTTP endpoint (e.g. UE 5.8 editor)\n --args <json> JSON array of args (stdio, optional)\n --timeout <ms> Per-server request timeout (http, optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --preset unreal-mcp Unreal Engine 5.8+ editor (MCP over HTTP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ZELARI_MEMORY_MCP=1 Enable the optional external memory MCP server\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
85139
+ "zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor [--json] Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --inspect [--json] Unified project inspection (config, skills, MCP,\n hooks, plugins, AGENTS.md, trust status)\n --trust [path] Trust the cwd (or path) so project MCP + hooks load\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --fix-budget Set recommended ZELARI_MAX_TOOL_LOOP_HARD=180,\n ZELARI_MAX_TOOL_LOOP_ITERATIONS=60, ZELARI_CONTEXT_LIMIT=400000\n at User scope (prevents the agent stopping mid-task)\n --permission-mcp <socket> MCP stdio server for external agent permission prompts\n (spawned by claude --permission-prompt-tool)\n --memory-mcp Optional MCP stdio server for project memory\n --cwd <path> Trusted project root (requires ZELARI_MEMORY_MCP=1)\n --client-id <id> Stable local owner identity for private memories\n --memory-json <json> Read-only project-memory bridge for Zelari Desktop\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)\n zelari/mission mode auto-scopes slices from open tasks in .zelari/plan.json\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --profile <id> Capability profile (minimal/v1|kraken/v1|council/v1|mission/v1)\n --resume <id> Continue a 2.0 spine session\n --resume-mission Resume .zelari/mission-state.json (not the spine)\n --export-session <path> Write zelari-session-export/1 after the run\n --strict-done Evidence-based BUILD completion gate\n --allow-unverified Exit 0 when strict is ON but nothing could be verified (M1.2)\n --task-file <path> Read the task prompt from a file (Windows argv cap)\n --once Single-cycle run (cron/git-hook triggers, ADR-0014)\n --kraken-graph <goal> Plan + execute a Kraken task graph\n (variant: --kraken-graph-file <path>; kill-switch\n ZELARI_KRAKEN_GRAPH=0)\n --plan-only Serialize the graph plan to .zelari/radio/ and exit 0\n --run-plan <id> Execute a pre-built .zelari/radio/plan-<id>.json\n --gauntlet Host-driven gauntlet loop (builder/critic tentacles)\n --session-export <id> Print a portable 2.0 session export (no LLM)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --serve-harness Long-lived harness kernel for hosts (NDJSON JSON-RPC\n on stdin/stdout; Desktop/companion transport)\n --print-config Print provider/model config as JSON (no secrets)\n --print-settings Print zelari.config.json values + the origin of\n each (default < user < project < env)\n --permissions <p> Permission preset: strict | standard | yolo \u2014 changes\n category DEFAULTS only (env vars and policy files win)\n --evolve-status Evolution ledger stats (read-only; ADR-0036; the\n ledger is written only when ZELARI_EVOLUTION=shadow)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --thinking <spec> Thinking effort (auto|off|low|medium|high|budget:N)\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --login-oauth Start subscription OAuth (grok, chatgpt, anthropic)\n --provider <id> grok | chatgpt | anthropic\n --code <paste> Anthropic magic-link code (CODE#STATE)\n --no-browser Do not open the system browser\n --refresh-oauth Force-refresh an OAuth access token\n --provider <id> grok | chatgpt | anthropic\n --logout-oauth Clear stored OAuth credentials\n --provider <id> grok | chatgpt | anthropic\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable for stdio servers\n --url <endpoint> Streamable HTTP endpoint (e.g. UE 5.8 editor)\n --args <json> JSON array of args (stdio, optional)\n --timeout <ms> Per-server request timeout (http, optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --preset unreal-mcp Unreal Engine 5.8+ editor (MCP over HTTP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ZELARI_MEMORY_MCP=1 Enable the optional external memory MCP server\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
84737
85140
  );
84738
85141
  process.exit(0);
84739
85142
  }