zelari-code 2.36.0 → 2.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -33854,10 +33854,28 @@ function buildMissionBrief(input) {
33854
33854
  ],
33855
33855
  phases,
33856
33856
  sliceMvp,
33857
- slices: [sliceMvp],
33857
+ slices: buildSlicePlan(sliceMvp, input.planTaskIds, maxTasks),
33858
33858
  userPromptOriginal: userMessage
33859
33859
  };
33860
33860
  }
33861
+ function buildSlicePlan(sliceMvp, planTaskIds, maxTasks) {
33862
+ const ids = Array.isArray(planTaskIds) ? planTaskIds.filter((t) => typeof t === "string" && t) : [];
33863
+ if (ids.length === 0)
33864
+ return [{ ...sliceMvp }];
33865
+ const size = Number.isFinite(maxTasks) && maxTasks > 0 ? Math.floor(maxTasks) : 8;
33866
+ const slices = [];
33867
+ for (let i = 0; i < ids.length; i += size) {
33868
+ const chunk = ids.slice(i, i + size);
33869
+ const index = i / size;
33870
+ slices.push(index === 0 ? { ...sliceMvp, taskIds: chunk, maxTasks: size } : {
33871
+ id: `slice-${index + 1}`,
33872
+ title: `Increment ${index + 1} \u2014 ${chunk.length} plan task(s)`,
33873
+ taskIds: chunk,
33874
+ maxTasks: size
33875
+ });
33876
+ }
33877
+ return slices;
33878
+ }
33861
33879
  var STACK_SIGNALS;
33862
33880
  var init_missionBrief = __esm({
33863
33881
  "packages/core/dist/council/missionBrief.js"() {
@@ -34682,6 +34700,7 @@ __export(council_exports, {
34682
34700
  buildMotionFixPrompt: () => buildMotionFixPrompt,
34683
34701
  buildRetryPrompt: () => buildRetryPrompt,
34684
34702
  buildSkillDefinition: () => buildSkillDefinition,
34703
+ buildSlicePlan: () => buildSlicePlan,
34685
34704
  buildSystemPrompt: () => buildSystemPrompt,
34686
34705
  buildSystemPromptSplit: () => buildSystemPromptSplit,
34687
34706
  captureFailure: () => captureFailure,
@@ -38289,7 +38308,7 @@ var CORE_VERSION;
38289
38308
  var init_version = __esm({
38290
38309
  "packages/core/dist/version.js"() {
38291
38310
  "use strict";
38292
- CORE_VERSION = "2.36.0";
38311
+ CORE_VERSION = "2.37.0";
38293
38312
  }
38294
38313
  });
38295
38314
 
@@ -38539,6 +38558,7 @@ __export(dist_exports, {
38539
38558
  buildRetryPrompt: () => buildRetryPrompt,
38540
38559
  buildRuntimeObserverBus: () => buildRuntimeObserverBus,
38541
38560
  buildSkillDefinition: () => buildSkillDefinition,
38561
+ buildSlicePlan: () => buildSlicePlan,
38542
38562
  buildSystemPrompt: () => buildSystemPrompt,
38543
38563
  buildSystemPromptSplit: () => buildSystemPromptSplit,
38544
38564
  canExternalClientMutate: () => canExternalClientMutate,
@@ -41625,6 +41645,24 @@ var init_storage = __esm({
41625
41645
  });
41626
41646
 
41627
41647
  // src/cli/workspace/planStore.ts
41648
+ var planStore_exports = {};
41649
+ __export(planStore_exports, {
41650
+ PLAN_FILES_MAX: () => PLAN_FILES_MAX,
41651
+ PLAN_FILE_GLOB_MAX: () => PLAN_FILE_GLOB_MAX,
41652
+ PLAN_MAX_TASKS: () => PLAN_MAX_TASKS,
41653
+ PLAN_NOTES_MAX: () => PLAN_NOTES_MAX,
41654
+ PLAN_SCHEMA_VERSION: () => PLAN_SCHEMA_VERSION,
41655
+ PLAN_TAG_MAX: () => PLAN_TAG_MAX,
41656
+ PLAN_TASK_STATUSES: () => PLAN_TASK_STATUSES,
41657
+ PLAN_TITLE_MAX: () => PLAN_TITLE_MAX,
41658
+ PlanStoreError: () => PlanStoreError,
41659
+ listOpenPlanTaskIds: () => listOpenPlanTaskIds,
41660
+ nextPlanTaskId: () => nextPlanTaskId,
41661
+ normalizePlanTaskFiles: () => normalizePlanTaskFiles,
41662
+ planJsonPathFor: () => planJsonPathFor,
41663
+ withPlanStore: () => withPlanStore,
41664
+ writePlanTaskArtifact: () => writePlanTaskArtifact
41665
+ });
41628
41666
  import {
41629
41667
  copyFileSync,
41630
41668
  existsSync as existsSync20,
@@ -41647,6 +41685,24 @@ function normalizePlanTaskFiles(values) {
41647
41685
  function planJsonPathFor(projectRoot = process.cwd()) {
41648
41686
  return join17(resolveWorkspaceRoot(projectRoot), "plan.json");
41649
41687
  }
41688
+ async function listOpenPlanTaskIds(projectRoot) {
41689
+ try {
41690
+ const jsonPath = planJsonPathFor(projectRoot);
41691
+ if (!existsSync20(jsonPath)) return [];
41692
+ const parsed = JSON.parse(readFileSync18(jsonPath, "utf8"));
41693
+ if (!Array.isArray(parsed.tasks)) return [];
41694
+ const ids = [];
41695
+ for (const raw of parsed.tasks) {
41696
+ if (raw === null || typeof raw !== "object") continue;
41697
+ const t = raw;
41698
+ if (typeof t.id !== "string" || t.id.length === 0) continue;
41699
+ if (t.status === "pending" || t.status === "in_progress") ids.push(t.id);
41700
+ }
41701
+ return ids;
41702
+ } catch {
41703
+ return [];
41704
+ }
41705
+ }
41650
41706
  async function withPlanStore(projectRoot, fn) {
41651
41707
  const rootDir = resolveWorkspaceRoot(projectRoot);
41652
41708
  return workspaceMutex.run(`${rootDir}:plan`, () => {
@@ -41790,7 +41846,7 @@ function normalizeStatus(raw) {
41790
41846
  function firstString(v) {
41791
41847
  return typeof v === "string" && v.trim().length > 0 ? v : null;
41792
41848
  }
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;
41849
+ 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
41850
  var init_planStore = __esm({
41795
41851
  "src/cli/workspace/planStore.ts"() {
41796
41852
  "use strict";
@@ -41801,6 +41857,13 @@ var init_planStore = __esm({
41801
41857
  PLAN_TITLE_MAX = 200;
41802
41858
  PLAN_NOTES_MAX = 2e3;
41803
41859
  PLAN_TAG_MAX = 64;
41860
+ PLAN_TASK_STATUSES = [
41861
+ "pending",
41862
+ "in_progress",
41863
+ "completed",
41864
+ "cancelled",
41865
+ "blocked"
41866
+ ];
41804
41867
  PLAN_FILES_MAX = 32;
41805
41868
  PLAN_FILE_GLOB_MAX = 260;
41806
41869
  PlanStoreError = class extends Error {
@@ -57055,6 +57118,7 @@ function parseHeadlessFlags(argv) {
57055
57118
  let once = false;
57056
57119
  let profile;
57057
57120
  let resumeSessionId;
57121
+ let resumeMission = false;
57058
57122
  let exportSessionPath;
57059
57123
  let strictDone;
57060
57124
  let missionStrict;
@@ -57201,6 +57265,8 @@ function parseHeadlessFlags(argv) {
57201
57265
  }
57202
57266
  profile = next;
57203
57267
  i++;
57268
+ } else if (arg === "--resume-mission") {
57269
+ resumeMission = true;
57204
57270
  } else if (arg === "--resume") {
57205
57271
  const next = argv[i + 1];
57206
57272
  if (!next || next.startsWith("--")) {
@@ -57274,6 +57340,7 @@ function parseHeadlessFlags(argv) {
57274
57340
  ...history2 && history2.length > 0 ? { history: history2 } : {},
57275
57341
  ...todos2 && todos2.length > 0 ? { todos: todos2 } : {},
57276
57342
  ...once ? { once: true } : {},
57343
+ ...resumeMission ? { resumeMission: true } : {},
57277
57344
  ...profile ? { profile } : {},
57278
57345
  ...resumeSessionId ? { resumeSessionId } : {},
57279
57346
  ...exportSessionPath ? { exportSessionPath } : {},
@@ -63248,14 +63315,19 @@ var init_traceStore = __esm({
63248
63315
  // src/cli/zelariMission.ts
63249
63316
  var zelariMission_exports = {};
63250
63317
  __export(zelariMission_exports, {
63318
+ MissionResumeError: () => MissionResumeError,
63251
63319
  formatBriefForChat: () => formatBriefForChat,
63252
63320
  isMissionAutoStart: () => isMissionAutoStart,
63321
+ isResumableMission: () => isResumableMission,
63322
+ loadMissionState: () => loadMissionState,
63253
63323
  missionGapKey: () => missionGapKey,
63254
63324
  missionPressure: () => missionPressure,
63255
63325
  resolveMaxCost: () => resolveMaxCost,
63256
63326
  resolveMaxIterations: () => resolveMaxIterations,
63257
63327
  resolveMaxStall: () => resolveMaxStall,
63258
63328
  resolveMaxTokens: () => resolveMaxTokens,
63329
+ resolveMissionSlices: () => resolveMissionSlices,
63330
+ resumeZelariMission: () => resumeZelariMission,
63259
63331
  runZelariMission: () => runZelariMission
63260
63332
  });
63261
63333
  import { randomUUID as randomUUID8 } from "node:crypto";
@@ -63317,16 +63389,42 @@ async function writeMissionState(projectRoot, state3) {
63317
63389
  }
63318
63390
  }
63319
63391
  }
63320
- function buildSlicePrompt(brief, userMessage, runMode, iteration) {
63392
+ async function loadMissionState(projectRoot) {
63393
+ try {
63394
+ const raw = await fs33.readFile(
63395
+ path76.join(projectRoot, ".zelari", "mission-state.json"),
63396
+ "utf8"
63397
+ );
63398
+ const parsed = JSON.parse(raw);
63399
+ if (!parsed || typeof parsed.missionId !== "string" || !parsed.brief) return void 0;
63400
+ return parsed;
63401
+ } catch {
63402
+ return void 0;
63403
+ }
63404
+ }
63405
+ function isResumableMission(state3) {
63406
+ return !!state3 && state3.status !== "success";
63407
+ }
63408
+ function resolveMissionSlices(brief) {
63409
+ const slices = Array.isArray(brief.slices) ? brief.slices.filter((s) => s && !!s.id) : [];
63410
+ return slices.length ? slices : [brief.sliceMvp];
63411
+ }
63412
+ function countImplementationSlices(state3) {
63413
+ return Array.isArray(state3.trace) ? state3.trace.filter((t) => t?.runMode === "implementation").length : 0;
63414
+ }
63415
+ function buildSlicePrompt(brief, userMessage, runMode, iteration, slice) {
63321
63416
  if (runMode === "design-phase") {
63322
63417
  return `${userMessage}
63323
63418
 
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.`;
63419
+ [Zelari mission] Produce the design-phase plan for the MVP: ${brief.deliverableThisMission}. Keep the first slice to at most ${slice.maxTasks ?? 8} tasks.`;
63325
63420
  }
63326
63421
  const fix = iteration > 1 ? " Address any remaining verification failures recorded in .zelari/completion.json." : "";
63422
+ const isMvpSlice = slice.id === resolveMissionSlices(brief)[0].id;
63423
+ const target = isMvpSlice ? "the MVP slice" : `increment "${slice.title}"`;
63424
+ const scope = slice.taskIds?.length ? ` Scope: plan tasks ${slice.taskIds.join(", ")}.` : "";
63327
63425
  return `${userMessage}
63328
63426
 
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.`;
63427
+ [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
63428
  }
63331
63429
  function formatBriefForChat(brief) {
63332
63430
  const lines = [
@@ -63346,34 +63444,74 @@ function formatBriefForChat(brief) {
63346
63444
  lines.push(" out of scope:");
63347
63445
  for (const o of brief.outOfScope) lines.push(` - ${o}`);
63348
63446
  }
63447
+ const slices = resolveMissionSlices(brief);
63349
63448
  lines.push(` MVP slice: ${brief.sliceMvp.title} (\u2264 ${brief.sliceMvp.maxTasks} tasks)`);
63449
+ if (slices.length > 1) {
63450
+ lines.push(` increments: ${slices.length} (gated: slice N+1 starts only when N is green)`);
63451
+ for (const s of slices.slice(1)) lines.push(` - ${s.id}: ${s.title}`);
63452
+ }
63350
63453
  return lines.join("\n");
63351
63454
  }
63352
63455
  async function runZelariMission(userMessage, brief, deps) {
63353
63456
  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
63457
  const startedAt = now().toISOString();
63360
63458
  const state3 = {
63361
- missionId,
63459
+ missionId: deps.missionId ?? `m_${randomUUID8().slice(0, 8)}`,
63362
63460
  userPrompt: userMessage,
63363
63461
  brief,
63364
63462
  iteration: 0,
63365
- currentSliceId: brief.sliceMvp.id,
63463
+ currentSliceId: resolveMissionSlices(brief)[0].id,
63366
63464
  status: "running",
63367
63465
  lastCompletionOk: false,
63368
63466
  startedAt,
63369
63467
  updatedAt: startedAt
63370
63468
  };
63469
+ return driveMission(userMessage, brief, deps, state3, false);
63470
+ }
63471
+ async function resumeZelariMission(deps) {
63472
+ const loaded = await loadMissionState(deps.projectRoot);
63473
+ if (!loaded) {
63474
+ throw new MissionResumeError(
63475
+ "nessuna missione da riprendere: .zelari/mission-state.json assente o illeggibile."
63476
+ );
63477
+ }
63478
+ if (!isResumableMission(loaded)) {
63479
+ throw new MissionResumeError(
63480
+ `la missione ${loaded.missionId} \xE8 gi\xE0 completata (status=success).`
63481
+ );
63482
+ }
63483
+ const brief = loaded.brief;
63484
+ const userMessage = loaded.userPrompt ?? brief.userPromptOriginal;
63485
+ deps.emit(
63486
+ `[zelari] resume missione ${loaded.missionId} \u2014 step ${loaded.iteration}, slice ${loaded.currentSliceId}, status precedente ${loaded.status}`
63487
+ );
63488
+ return driveMission(userMessage, brief, deps, loaded, true);
63489
+ }
63490
+ async function driveMission(userMessage, brief, deps, state3, resumed) {
63491
+ const now = deps.now ?? (() => /* @__PURE__ */ new Date());
63492
+ const maxIter = deps.maxIterations ?? resolveMaxIterations(deps.env);
63493
+ const maxStall = resolveMaxStall(deps.env);
63494
+ const maxCost = resolveMaxCost(deps.env);
63495
+ const maxTokens = resolveMaxTokens(deps.env);
63496
+ const missionId = state3.missionId;
63497
+ const slices = resolveMissionSlices(brief);
63498
+ let sliceIndex = resumed ? Math.max(
63499
+ 0,
63500
+ slices.findIndex((s) => s.id === state3.currentSliceId)
63501
+ ) : 0;
63502
+ const currentSlice = () => slices[sliceIndex] ?? slices[0];
63503
+ state3.currentSliceId = currentSlice().id;
63504
+ state3.status = "running";
63505
+ state3.updatedAt = now().toISOString();
63371
63506
  await deps.memory.init(deps.projectRoot);
63372
63507
  const persist = async () => {
63373
63508
  await writeMissionState(deps.projectRoot, state3);
63374
63509
  await deps.onStatePersisted?.(state3);
63375
63510
  };
63376
- deps.onMissionPhase?.("design", "mission-start");
63511
+ deps.onMissionPhase?.(
63512
+ resumed ? "build" : "design",
63513
+ resumed ? "mission-resume" : "mission-start"
63514
+ );
63377
63515
  await persist();
63378
63516
  const stateStore = deps.stateStore ?? await getStateStore(deps.projectRoot, deps.env ?? process.env);
63379
63517
  try {
@@ -63381,7 +63519,7 @@ async function runZelariMission(userMessage, brief, deps) {
63381
63519
  } catch {
63382
63520
  }
63383
63521
  let missionCheckpointId;
63384
- if ((deps.env ?? process.env).ZELARI_CHECKPOINT !== "0") {
63522
+ if (!resumed && (deps.env ?? process.env).ZELARI_CHECKPOINT !== "0") {
63385
63523
  const cp = await createCheckpoint(deps.projectRoot, `zelari mission ${missionId}`);
63386
63524
  if (cp.ok) {
63387
63525
  missionCheckpointId = cp.value.id;
@@ -63392,11 +63530,11 @@ async function runZelariMission(userMessage, brief, deps) {
63392
63530
  }
63393
63531
  const designFirst = brief.phases[0]?.mode === "design-phase";
63394
63532
  let noWriteStreak = 0;
63395
- let step = 0;
63396
- let implStep = 0;
63397
- let pendingDesign = designFirst;
63398
- let cumulativeCostUsd = 0;
63399
- let cumulativeTokens = 0;
63533
+ let step = resumed ? state3.iteration : 0;
63534
+ let implStep = resumed ? countImplementationSlices(state3) : 0;
63535
+ let pendingDesign = designFirst && !resumed;
63536
+ let cumulativeCostUsd = resumed ? state3.cumulativeCostUsd ?? 0 : 0;
63537
+ let cumulativeTokens = resumed ? state3.cumulativeTokens ?? 0 : 0;
63400
63538
  const repairHistory = Array.isArray(state3.repairHistory) ? [...state3.repairHistory] : [];
63401
63539
  let forcePivot = false;
63402
63540
  const missionStartMs = now().getTime();
@@ -63424,25 +63562,25 @@ async function runZelariMission(userMessage, brief, deps) {
63424
63562
  });
63425
63563
  const ragContext = formatMemoryHits(hits);
63426
63564
  const promptIter = runMode === "implementation" ? implStep : 1;
63427
- const slicePrompt = buildSlicePrompt(brief, userMessage, runMode, promptIter);
63565
+ const slicePrompt = buildSlicePrompt(brief, userMessage, runMode, promptIter, currentSlice());
63428
63566
  const implementerRetry = runMode === "implementation" && (implStep > 1 || forcePivot);
63429
63567
  const sliceStartedAt = now().toISOString();
63430
63568
  const sliceStartMs = now().getTime();
63431
63569
  if (runMode === "design-phase") {
63432
63570
  deps.emit(
63433
- `[zelari] design-phase (fuori budget) \xB7 step ${step} \xB7 slice ${brief.sliceMvp.id}`
63571
+ `[zelari] design-phase (fuori budget) \xB7 step ${step} \xB7 slice ${currentSlice().id}`
63434
63572
  );
63435
63573
  } else if (deps.buildViaAgent) {
63436
63574
  deps.emit(
63437
- `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 build@agent \xB7 slice ${brief.sliceMvp.id}`
63575
+ `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 build@agent \xB7 slice ${currentSlice().id}`
63438
63576
  );
63439
63577
  } else if (implementerRetry) {
63440
63578
  deps.emit(
63441
- `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 roster ridotto (Minosse+Lucifero) \xB7 slice ${brief.sliceMvp.id}`
63579
+ `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 roster ridotto (Minosse+Lucifero) \xB7 slice ${currentSlice().id}`
63442
63580
  );
63443
63581
  } else {
63444
63582
  deps.emit(
63445
- `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 council completo \xB7 slice ${brief.sliceMvp.id}`
63583
+ `[zelari] implementazione ${implStep}/${maxIter} \xB7 step ${step} \xB7 council completo \xB7 slice ${currentSlice().id}`
63446
63584
  );
63447
63585
  }
63448
63586
  let result;
@@ -63484,7 +63622,7 @@ async function runZelariMission(userMessage, brief, deps) {
63484
63622
  {
63485
63623
  projectRoot: deps.projectRoot,
63486
63624
  missionId,
63487
- sliceId: brief.sliceMvp.id,
63625
+ sliceId: currentSlice().id,
63488
63626
  source: "council",
63489
63627
  iteration: step,
63490
63628
  memoryKind: result.completionOk ? "outcome" : runMode === "design-phase" ? "decision" : "episode",
@@ -63508,7 +63646,7 @@ async function runZelariMission(userMessage, brief, deps) {
63508
63646
  state3.cumulativeTokens = cumulativeTokens;
63509
63647
  if (!state3.trace) state3.trace = [];
63510
63648
  state3.trace.push({
63511
- sliceId: brief.sliceMvp.id,
63649
+ sliceId: currentSlice().id,
63512
63650
  iteration: step,
63513
63651
  runMode,
63514
63652
  completionOk,
@@ -63533,7 +63671,7 @@ async function runZelariMission(userMessage, brief, deps) {
63533
63671
  env: deps.env,
63534
63672
  mode: "zelari",
63535
63673
  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}`,
63674
+ label: hard ? `zelari ${currentSlice().id} impl ${implStep} verified` : `zelari ${currentSlice().id} progress impl ${implStep}`,
63537
63675
  sessionId: missionId,
63538
63676
  verification: { ok: hard, ran: result.ran },
63539
63677
  force: !hard,
@@ -63572,12 +63710,24 @@ async function runZelariMission(userMessage, brief, deps) {
63572
63710
  budget: { iterationsUsed: implStep, iterationsMax: maxIter }
63573
63711
  });
63574
63712
  deps.onMissionProgress?.(advice, step);
63713
+ if (completionOk && sliceIndex < slices.length - 1) {
63714
+ const doneSlice = currentSlice();
63715
+ sliceIndex += 1;
63716
+ state3.currentSliceId = currentSlice().id;
63717
+ state3.updatedAt = now().toISOString();
63718
+ await persist();
63719
+ deps.emit(
63720
+ `[zelari] \u2713 incremento ${sliceIndex}/${slices.length} verde (${doneSlice.id}) \u2014 avvio ${currentSlice().id}`
63721
+ );
63722
+ continue;
63723
+ }
63575
63724
  if (completionOk) {
63576
63725
  state3.status = "success";
63577
63726
  deps.onMissionPhase?.("done", "mvp-green");
63578
63727
  await persist();
63728
+ const sliceLabel = slices.length === 1 ? "slice MVP" : `ultimo incremento (${currentSlice().id})`;
63579
63729
  deps.emit(
63580
- `[zelari] \u2713 missione completata \u2014 slice MVP verde all'implementazione ${implStep}/${maxIter} (step ${step}).`
63730
+ `[zelari] \u2713 missione completata \u2014 ${sliceLabel} verde all'implementazione ${implStep}/${maxIter} (step ${step}).`
63581
63731
  );
63582
63732
  return state3;
63583
63733
  }
@@ -63655,7 +63805,7 @@ async function runZelariMission(userMessage, brief, deps) {
63655
63805
  );
63656
63806
  return state3;
63657
63807
  }
63658
- var DEFAULT_MAX_ITER, DEFAULT_MAX_STALL;
63808
+ var DEFAULT_MAX_ITER, DEFAULT_MAX_STALL, MissionResumeError;
63659
63809
  var init_zelariMission = __esm({
63660
63810
  "src/cli/zelariMission.ts"() {
63661
63811
  "use strict";
@@ -63668,6 +63818,12 @@ var init_zelariMission = __esm({
63668
63818
  init_traceStore();
63669
63819
  DEFAULT_MAX_ITER = 6;
63670
63820
  DEFAULT_MAX_STALL = 2;
63821
+ MissionResumeError = class extends Error {
63822
+ constructor(message) {
63823
+ super(message);
63824
+ this.name = "MissionResumeError";
63825
+ }
63826
+ };
63671
63827
  }
63672
63828
  });
63673
63829
 
@@ -69125,6 +69281,76 @@ var init_run = __esm({
69125
69281
  }
69126
69282
  });
69127
69283
 
69284
+ // src/cli/evolution/runTelemetry.ts
69285
+ var runTelemetry_exports = {};
69286
+ __export(runTelemetry_exports, {
69287
+ RunTelemetryAccumulator: () => RunTelemetryAccumulator
69288
+ });
69289
+ var RunTelemetryAccumulator;
69290
+ var init_runTelemetry = __esm({
69291
+ "src/cli/evolution/runTelemetry.ts"() {
69292
+ "use strict";
69293
+ RunTelemetryAccumulator = class {
69294
+ constructor(meta3 = {}) {
69295
+ this.meta = meta3;
69296
+ }
69297
+ totals = {
69298
+ inputTokens: 0,
69299
+ outputTokens: 0,
69300
+ cacheHitTokens: 0,
69301
+ toolCalls: 0,
69302
+ usageReports: 0
69303
+ };
69304
+ /** Mirror one dispatch/spine event. Never throws on unknown shapes. */
69305
+ observe(ev) {
69306
+ if (!ev || typeof ev !== "object" || !("type" in ev)) return;
69307
+ const e = ev;
69308
+ if (e["type"] === "tool_execution_end") {
69309
+ this.totals.toolCalls += 1;
69310
+ return;
69311
+ }
69312
+ if (e["type"] !== "message_end") return;
69313
+ const usage = e["usage"];
69314
+ if (!usage || typeof usage !== "object") return;
69315
+ const u = usage;
69316
+ if (typeof u["promptTokens"] === "number") this.totals.inputTokens += u["promptTokens"];
69317
+ if (typeof u["completionTokens"] === "number") this.totals.outputTokens += u["completionTokens"];
69318
+ if (typeof u["cachedPromptTokens"] === "number") this.totals.cacheHitTokens += u["cachedPromptTokens"];
69319
+ this.totals.usageReports += 1;
69320
+ }
69321
+ /** Cumulative totals (defensive copy). */
69322
+ usage() {
69323
+ return { ...this.totals };
69324
+ }
69325
+ /**
69326
+ * Final NDJSON `usage` event for JSON hosts (Desktop, competitive bench,
69327
+ * anchor runner). Emitted once per run, after the dispatch stream ends —
69328
+ * `tools/eval/competitive/adapters.ts#parseZelariUsage` reads exactly this
69329
+ * flat `{ inputTokens, outputTokens, cacheHitTokens, model?, provider? }`
69330
+ * shape, so the bench stops recording `tokens: null` with no bench change.
69331
+ */
69332
+ usageEvent() {
69333
+ return {
69334
+ type: "usage",
69335
+ ...this.usage(),
69336
+ ...this.meta.model ? { model: this.meta.model } : {},
69337
+ ...this.meta.provider ? { provider: this.meta.provider } : {}
69338
+ };
69339
+ }
69340
+ /**
69341
+ * Ledger projection: toolCalls always (event-countable), token fields ONLY
69342
+ * when backed by ≥1 provider usage report (unknown ≠ estimated ≠ zero).
69343
+ */
69344
+ ledgerFields() {
69345
+ return {
69346
+ toolCalls: this.totals.toolCalls,
69347
+ ...this.totals.usageReports > 0 ? { inputTokens: this.totals.inputTokens, outputTokens: this.totals.outputTokens } : {}
69348
+ };
69349
+ }
69350
+ };
69351
+ }
69352
+ });
69353
+
69128
69354
  // src/cli/triggerLock.ts
69129
69355
  var triggerLock_exports = {};
69130
69356
  __export(triggerLock_exports, {
@@ -69729,6 +69955,9 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69729
69955
  const scrub = createStreamScrubber2({ stripQuestion: opts.output !== "json" });
69730
69956
  let lastAssistantText = "";
69731
69957
  let currentAssistantText = "";
69958
+ const { RunTelemetryAccumulator: RunTelemetryAccumulator2 } = await Promise.resolve().then(() => (init_runTelemetry(), runTelemetry_exports));
69959
+ const telemetry = new RunTelemetryAccumulator2({ model, provider });
69960
+ const councilStartedAt = Date.now();
69732
69961
  try {
69733
69962
  const { composeProjectContext: composeProjectContext2 } = await Promise.resolve().then(() => (init_composeContext(), composeContext_exports));
69734
69963
  const { loadDurableContext: loadDurableContext2 } = await Promise.resolve().then(() => (init_loadDurableContext(), loadDurableContext_exports));
@@ -69784,6 +70013,7 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69784
70013
  currentAssistantText = "";
69785
70014
  }
69786
70015
  spine.observe(event);
70016
+ telemetry.observe(event);
69787
70017
  if (event.type === "message_delta" && typeof event.delta === "string") {
69788
70018
  const cleanDelta = scrub.push(event.delta);
69789
70019
  if (cleanDelta.length > 0) currentAssistantText += cleanDelta;
@@ -69811,6 +70041,9 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69811
70041
  }
69812
70042
  }
69813
70043
  }
70044
+ if (opts.output === "json") {
70045
+ emitEvent(telemetry.usageEvent());
70046
+ }
69814
70047
  } catch (err) {
69815
70048
  process.stderr.write(
69816
70049
  `[zelari-code --headless] council error: ${err instanceof Error ? err.message : String(err)}
@@ -69834,6 +70067,12 @@ async function runHeadlessCouncilBody(opts, provider, model, providerStream, ext
69834
70067
  at: (/* @__PURE__ */ new Date()).toISOString(),
69835
70068
  mode: "shadow",
69836
70069
  taskClass: classifyTask2({ prompt: effectiveTask }).taskClass,
70070
+ // Steal #1/#2 wiring: real efficiency + attribution fields — the
70071
+ // ledger schema carried them since ADR-0036, this site never wrote them.
70072
+ latencyMs: Date.now() - councilStartedAt,
70073
+ model,
70074
+ provider,
70075
+ ...telemetry.ledgerFields(),
69837
70076
  verdict: signal.aborted ? "UNKNOWN" : exitCode === 0 ? "PASS" : exitCode === 3 ? "FAIL" : "UNKNOWN"
69838
70077
  });
69839
70078
  }
@@ -69901,14 +70140,17 @@ async function runHeadlessZelariBody(opts, provider, model, providerStream, extr
69901
70140
  spine.missionPhase("design", "mission-start");
69902
70141
  const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
69903
70142
  const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
70143
+ const { listOpenPlanTaskIds: listOpenPlanTaskIds2 } = await Promise.resolve().then(() => (init_planStore(), planStore_exports));
69904
70144
  const { getMemoryBackend: getMemoryBackend2 } = await Promise.resolve().then(() => (init_fileBackend(), fileBackend_exports));
69905
70145
  const { runZelariMission: runZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
69906
70146
  const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
69907
70147
  const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
69908
70148
  const { runPostCouncilHook: runPostCouncilHook2 } = await Promise.resolve().then(() => (init_postCouncilHook(), postCouncilHook_exports));
70149
+ const planTaskIds = await listOpenPlanTaskIds2(projectRoot);
69909
70150
  const brief = buildMissionBrief2({
69910
70151
  userMessage: opts.task,
69911
- hasPlan: hasWorkspacePlan2(projectRoot)
70152
+ hasPlan: hasWorkspacePlan2(projectRoot),
70153
+ planTaskIds
69912
70154
  });
69913
70155
  const memory = await getMemoryBackend2(
69914
70156
  projectRoot,
@@ -69993,7 +70235,9 @@ ${JSON.stringify({ deliverable: brief.deliverableThisMission, mvp: brief.sliceMv
69993
70235
  }
69994
70236
  }
69995
70237
  try {
69996
- const state3 = await runZelariMission2(missionTask, brief, {
70238
+ const { resumeZelariMission: resumeZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
70239
+ const runMission = (missionDeps) => opts.resumeMission ? resumeZelariMission2(missionDeps) : runZelariMission2(missionTask, brief, missionDeps);
70240
+ const state3 = await runMission({
69997
70241
  projectRoot,
69998
70242
  memory,
69999
70243
  emit,
@@ -79407,11 +79651,14 @@ async function dispatchZelariPromptImpl(text, deps, pendingRef) {
79407
79651
  }
79408
79652
  const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
79409
79653
  const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
79654
+ const { listOpenPlanTaskIds: listOpenPlanTaskIds2 } = await Promise.resolve().then(() => (init_planStore(), planStore_exports));
79410
79655
  const { formatBriefForChat: formatBriefForChat2, isMissionAutoStart: isMissionAutoStart2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
79411
79656
  const projectRoot = process.cwd();
79657
+ const planTaskIds = await listOpenPlanTaskIds2(projectRoot);
79412
79658
  const brief = buildMissionBrief2({
79413
79659
  userMessage: text,
79414
- hasPlan: hasWorkspacePlan2(projectRoot)
79660
+ hasPlan: hasWorkspacePlan2(projectRoot),
79661
+ planTaskIds
79415
79662
  });
79416
79663
  emit(formatBriefForChat2(brief));
79417
79664
  if (isMissionAutoStart2()) {
@@ -79437,11 +79684,14 @@ async function runZelariMissionInTui(userMessage, deps, emit) {
79437
79684
  const projectRoot = process.cwd();
79438
79685
  const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
79439
79686
  const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
79687
+ const { listOpenPlanTaskIds: listOpenPlanTaskIds2 } = await Promise.resolve().then(() => (init_planStore(), planStore_exports));
79440
79688
  const { getMemoryBackend: getMemoryBackend2 } = await Promise.resolve().then(() => (init_fileBackend(), fileBackend_exports));
79441
79689
  const { runZelariMission: runZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
79690
+ const planTaskIds = await listOpenPlanTaskIds2(projectRoot);
79442
79691
  const brief = buildMissionBrief2({
79443
79692
  userMessage,
79444
- hasPlan: hasWorkspacePlan2(projectRoot)
79693
+ hasPlan: hasWorkspacePlan2(projectRoot),
79694
+ planTaskIds
79445
79695
  });
79446
79696
  const missionSpineHolder = {
79447
79697
  get current() {
@@ -84733,7 +84983,7 @@ proposals: npm run evolve:propose \u2014 decisions in npm run evolve:decide (P1:
84733
84983
  }
84734
84984
  if (argv.includes("--help") || argv.includes("-h")) {
84735
84985
  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"
84986
+ "zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor [--json] Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --inspect [--json] Unified project inspection (config, skills, MCP,\n hooks, plugins, AGENTS.md, trust status)\n --trust [path] Trust the cwd (or path) so project MCP + hooks load\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --fix-budget Set recommended ZELARI_MAX_TOOL_LOOP_HARD=180,\n ZELARI_MAX_TOOL_LOOP_ITERATIONS=60, ZELARI_CONTEXT_LIMIT=400000\n at User scope (prevents the agent stopping mid-task)\n --permission-mcp <socket> MCP stdio server for external agent permission prompts\n (spawned by claude --permission-prompt-tool)\n --memory-mcp Optional MCP stdio server for project memory\n --cwd <path> Trusted project root (requires ZELARI_MEMORY_MCP=1)\n --client-id <id> Stable local owner identity for private memories\n --memory-json <json> Read-only project-memory bridge for Zelari Desktop\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)\n zelari/mission mode auto-scopes slices from open tasks in .zelari/plan.json\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --profile <id> Capability profile (minimal/v1|kraken/v1|council/v1|mission/v1)\n --resume <id> Continue a 2.0 spine session\n --resume-mission Resume .zelari/mission-state.json (not the spine)\n --export-session <path> Write zelari-session-export/1 after the run\n --strict-done Evidence-based BUILD completion gate\n --task-file <path> Read the task prompt from a file (Windows argv cap)\n --once Single-cycle run (cron/git-hook triggers, ADR-0014)\n --kraken-graph <goal> Plan + execute a Kraken task graph\n (variant: --kraken-graph-file <path>; kill-switch\n ZELARI_KRAKEN_GRAPH=0)\n --plan-only Serialize the graph plan to .zelari/radio/ and exit 0\n --run-plan <id> Execute a pre-built .zelari/radio/plan-<id>.json\n --gauntlet Host-driven gauntlet loop (builder/critic tentacles)\n --session-export <id> Print a portable 2.0 session export (no LLM)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --serve-harness Long-lived harness kernel for hosts (NDJSON JSON-RPC\n on stdin/stdout; Desktop/companion transport)\n --print-config Print provider/model config as JSON (no secrets)\n --print-settings Print zelari.config.json values + the origin of\n each (default < user < project < env)\n --permissions <p> Permission preset: strict | standard | yolo \u2014 changes\n category DEFAULTS only (env vars and policy files win)\n --evolve-status Evolution ledger stats (read-only; ADR-0036; the\n ledger is written only when ZELARI_EVOLUTION=shadow)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --thinking <spec> Thinking effort (auto|off|low|medium|high|budget:N)\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --login-oauth Start subscription OAuth (grok, chatgpt, anthropic)\n --provider <id> grok | chatgpt | anthropic\n --code <paste> Anthropic magic-link code (CODE#STATE)\n --no-browser Do not open the system browser\n --refresh-oauth Force-refresh an OAuth access token\n --provider <id> grok | chatgpt | anthropic\n --logout-oauth Clear stored OAuth credentials\n --provider <id> grok | chatgpt | anthropic\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable for stdio servers\n --url <endpoint> Streamable HTTP endpoint (e.g. UE 5.8 editor)\n --args <json> JSON array of args (stdio, optional)\n --timeout <ms> Per-server request timeout (http, optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --preset unreal-mcp Unreal Engine 5.8+ editor (MCP over HTTP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ZELARI_MEMORY_MCP=1 Enable the optional external memory MCP server\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
84737
84987
  );
84738
84988
  process.exit(0);
84739
84989
  }