zelari-code 0.7.14 → 1.0.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.
@@ -1522,10 +1522,10 @@ function mergeDefs(...defs) {
1522
1522
  function cloneDef(schema) {
1523
1523
  return mergeDefs(schema._zod.def);
1524
1524
  }
1525
- function getElementAtPath(obj, path22) {
1526
- if (!path22)
1525
+ function getElementAtPath(obj, path24) {
1526
+ if (!path24)
1527
1527
  return obj;
1528
- return path22.reduce((acc, key) => acc?.[key], obj);
1528
+ return path24.reduce((acc, key) => acc?.[key], obj);
1529
1529
  }
1530
1530
  function promiseAllObject(promisesObj) {
1531
1531
  const keys = Object.keys(promisesObj);
@@ -1853,11 +1853,11 @@ function explicitlyAborted(x, startIndex = 0) {
1853
1853
  }
1854
1854
  return false;
1855
1855
  }
1856
- function prefixIssues(path22, issues) {
1856
+ function prefixIssues(path24, issues) {
1857
1857
  return issues.map((iss) => {
1858
1858
  var _a3;
1859
1859
  (_a3 = iss).path ?? (_a3.path = []);
1860
- iss.path.unshift(path22);
1860
+ iss.path.unshift(path24);
1861
1861
  return iss;
1862
1862
  });
1863
1863
  }
@@ -2075,16 +2075,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
2075
2075
  }
2076
2076
  function formatError(error51, mapper = (issue2) => issue2.message) {
2077
2077
  const fieldErrors = { _errors: [] };
2078
- const processError = (error52, path22 = []) => {
2078
+ const processError = (error52, path24 = []) => {
2079
2079
  for (const issue2 of error52.issues) {
2080
2080
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2081
- issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
2081
+ issue2.errors.map((issues) => processError({ issues }, [...path24, ...issue2.path]));
2082
2082
  } else if (issue2.code === "invalid_key") {
2083
- processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
2083
+ processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
2084
2084
  } else if (issue2.code === "invalid_element") {
2085
- processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
2085
+ processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
2086
2086
  } else {
2087
- const fullpath = [...path22, ...issue2.path];
2087
+ const fullpath = [...path24, ...issue2.path];
2088
2088
  if (fullpath.length === 0) {
2089
2089
  fieldErrors._errors.push(mapper(issue2));
2090
2090
  } else {
@@ -2111,17 +2111,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
2111
2111
  }
2112
2112
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
2113
2113
  const result = { errors: [] };
2114
- const processError = (error52, path22 = []) => {
2114
+ const processError = (error52, path24 = []) => {
2115
2115
  var _a3, _b;
2116
2116
  for (const issue2 of error52.issues) {
2117
2117
  if (issue2.code === "invalid_union" && issue2.errors.length) {
2118
- issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
2118
+ issue2.errors.map((issues) => processError({ issues }, [...path24, ...issue2.path]));
2119
2119
  } else if (issue2.code === "invalid_key") {
2120
- processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
2120
+ processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
2121
2121
  } else if (issue2.code === "invalid_element") {
2122
- processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
2122
+ processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
2123
2123
  } else {
2124
- const fullpath = [...path22, ...issue2.path];
2124
+ const fullpath = [...path24, ...issue2.path];
2125
2125
  if (fullpath.length === 0) {
2126
2126
  result.errors.push(mapper(issue2));
2127
2127
  continue;
@@ -2153,8 +2153,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
2153
2153
  }
2154
2154
  function toDotPath(_path) {
2155
2155
  const segs = [];
2156
- const path22 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2157
- for (const seg of path22) {
2156
+ const path24 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2157
+ for (const seg of path24) {
2158
2158
  if (typeof seg === "number")
2159
2159
  segs.push(`[${seg}]`);
2160
2160
  else if (typeof seg === "symbol")
@@ -12600,7 +12600,7 @@ function _stringbool(Classes, _params) {
12600
12600
  type: "pipe",
12601
12601
  in: stringSchema,
12602
12602
  out: booleanSchema,
12603
- transform: (input, payload) => {
12603
+ transform: ((input, payload) => {
12604
12604
  let data = input;
12605
12605
  if (params.case !== "sensitive")
12606
12606
  data = data.toLowerCase();
@@ -12619,14 +12619,14 @@ function _stringbool(Classes, _params) {
12619
12619
  });
12620
12620
  return {};
12621
12621
  }
12622
- },
12623
- reverseTransform: (input, _payload) => {
12622
+ }),
12623
+ reverseTransform: ((input, _payload) => {
12624
12624
  if (input === true) {
12625
12625
  return truthyArray[0] || "true";
12626
12626
  } else {
12627
12627
  return falsyArray[0] || "false";
12628
12628
  }
12629
- },
12629
+ }),
12630
12630
  error: params.error
12631
12631
  });
12632
12632
  return codec2;
@@ -15657,13 +15657,13 @@ function resolveRef(ref, ctx) {
15657
15657
  if (!ref.startsWith("#")) {
15658
15658
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
15659
15659
  }
15660
- const path22 = ref.slice(1).split("/").filter(Boolean);
15661
- if (path22.length === 0) {
15660
+ const path24 = ref.slice(1).split("/").filter(Boolean);
15661
+ if (path24.length === 0) {
15662
15662
  return ctx.rootSchema;
15663
15663
  }
15664
15664
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
15665
- if (path22[0] === defsKey) {
15666
- const key = path22[1];
15665
+ if (path24[0] === defsKey) {
15666
+ const key = path24[1];
15667
15667
  if (!key || !ctx.defs[key]) {
15668
15668
  throw new Error(`Reference not found: ${ref}`);
15669
15669
  }
@@ -17693,11 +17693,11 @@ var init_tools = __esm({
17693
17693
  if (!ctx.addDocument)
17694
17694
  return "Knowledge vault tool not available.";
17695
17695
  const title = args["title"] || "New Document";
17696
- const path22 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
17696
+ const path24 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
17697
17697
  const content = args["content"] || "";
17698
17698
  const tags = args["tags"] || [];
17699
17699
  ctx.addDocument({
17700
- path: path22,
17700
+ path: path24,
17701
17701
  title,
17702
17702
  content,
17703
17703
  format: "markdown",
@@ -17706,7 +17706,7 @@ var init_tools = __esm({
17706
17706
  workspaceId: ctx.workspaceId
17707
17707
  });
17708
17708
  ctx.addActivity("vault", "created document", title);
17709
- return `Document "${title}" created at "${path22}".`;
17709
+ return `Document "${title}" created at "${path24}".`;
17710
17710
  }
17711
17711
  }
17712
17712
  ];
@@ -19750,9 +19750,9 @@ var DESIGN_KEYWORDS, IMPLEMENTATION_KEYWORDS, PLAN_CONTINUE;
19750
19750
  var init_runMode = __esm({
19751
19751
  "packages/core/dist/council/runMode.js"() {
19752
19752
  "use strict";
19753
- DESIGN_KEYWORDS = /\b(design|architect|architecture|spec|blueprint|mockup|wireframe|greenfield|from scratch)\b/i;
19754
- IMPLEMENTATION_KEYWORDS = /\b(fix|refactor|bug|implement|patch|migrate|add tests|debug|repair|hotfix)\b/i;
19755
- PLAN_CONTINUE = /\b(continue|extend|update|refine)\b[\s\S]{0,40}\b(plan|phase|milestone)\b/i;
19753
+ DESIGN_KEYWORDS = /\b(design|architect|architecture|spec|blueprint|mockup|wireframe|greenfield|from scratch|costruisci|crea|progetta|progettazione|architettura|nuovo progetto|da zero|sviluppa|realizza|vetrina|pannello|gestionale)\b/i;
19754
+ IMPLEMENTATION_KEYWORDS = /\b(fix|refactor|bug|implement|patch|migrate|add tests|debug|repair|hotfix|correggi|correzione|rifattorizza|refactoring|implementa|aggiungi test|migra)\b/i;
19755
+ PLAN_CONTINUE = /\b(continue|extend|update|refine|continua|estendi|aggiorna|rifinisci)\b[\s\S]{0,40}\b(plan|phase|milestone|piano|fase|milestone)\b/i;
19756
19756
  }
19757
19757
  });
19758
19758
 
@@ -20212,11 +20212,11 @@ var init_synthesisAudit = __esm({
20212
20212
  import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
20213
20213
  import { join as join2 } from "node:path";
20214
20214
  function loadNfrSpec(zelariRoot) {
20215
- const path22 = join2(zelariRoot, "nfr-spec.json");
20216
- if (!existsSync8(path22))
20215
+ const path24 = join2(zelariRoot, "nfr-spec.json");
20216
+ if (!existsSync8(path24))
20217
20217
  return null;
20218
20218
  try {
20219
- const raw = JSON.parse(readFileSync6(path22, "utf8"));
20219
+ const raw = JSON.parse(readFileSync6(path24, "utf8"));
20220
20220
  if (raw.version !== 1 || !Array.isArray(raw.targets))
20221
20221
  return null;
20222
20222
  return raw;
@@ -21338,7 +21338,9 @@ async function* runCouncilPure(userMessage, config2, callbacks = {}) {
21338
21338
  tools: chairmanTools,
21339
21339
  eventBus: config2.eventBus,
21340
21340
  toolRegistry: config2.tools,
21341
- maxToolCallsPerTurn: config2.maxToolCallsPerTurn ?? 5,
21341
+ // Chairman-only budget (zelari-mode raises this); specialists/oracle
21342
+ // keep the shared default.
21343
+ maxToolCallsPerTurn: config2.maxToolCallsChairman ?? config2.maxToolCallsPerTurn ?? 5,
21342
21344
  // v0.5.0 visible-reasoning wiring: stamp every event with
21343
21345
  // the chairman identity so the UI renders `· Lucifero` in
21344
21346
  // purple. Same pattern as the specialist loop above.
@@ -22038,6 +22040,138 @@ var init_councilApi = __esm({
22038
22040
  }
22039
22041
  });
22040
22042
 
22043
+ // packages/core/dist/council/mission.js
22044
+ function classifyMission(input) {
22045
+ const msg = input.userMessage;
22046
+ if (input.hasPlan && EXTEND_KEYWORDS.test(msg))
22047
+ return "extend";
22048
+ if (REDESIGN_KEYWORDS.test(msg))
22049
+ return "redesign";
22050
+ if (GREENFIELD_KEYWORDS.test(msg))
22051
+ return "greenfield";
22052
+ if (FIX_KEYWORDS.test(msg))
22053
+ return "fix";
22054
+ return input.hasPlan ? "extend" : "greenfield";
22055
+ }
22056
+ var REDESIGN_KEYWORDS, FIX_KEYWORDS, GREENFIELD_KEYWORDS, EXTEND_KEYWORDS;
22057
+ var init_mission = __esm({
22058
+ "packages/core/dist/council/mission.js"() {
22059
+ "use strict";
22060
+ REDESIGN_KEYWORDS = /\b(redesign|restyle|restyling|revamp|ridisegna|ridisegnare|nuovo look|rifai la ui|rinnova (?:la )?ui)\b/i;
22061
+ FIX_KEYWORDS = /\b(fix|bug|hotfix|debug|repair|refactor|patch|correggi|correzione|rifattorizza|refactoring|migra|migrate)\b/i;
22062
+ GREENFIELD_KEYWORDS = /\b(greenfield|from scratch|scaffold|costruisci|crea|realizza|sviluppa|nuovo progetto|da zero|build (?:a|an|the)? ?(?:new )?)\b/i;
22063
+ EXTEND_KEYWORDS = /\b(continue|extend|add (?:a )?(?:new )?(?:feature|phase|module)|continua|estendi|aggiungi (?:una )?(?:fase|feature|funzionalit[àa]|modulo))\b/i;
22064
+ }
22065
+ });
22066
+
22067
+ // packages/core/dist/council/missionBrief.js
22068
+ function inferStack(msg) {
22069
+ const found = /* @__PURE__ */ new Set();
22070
+ for (const [re, name] of STACK_SIGNALS) {
22071
+ if (re.test(msg))
22072
+ found.add(name);
22073
+ }
22074
+ return [...found];
22075
+ }
22076
+ function firstSentence(msg, max = 160) {
22077
+ const oneLine = msg.replace(/\s+/g, " ").trim();
22078
+ return oneLine.length <= max ? oneLine : oneLine.slice(0, max - 1).trimEnd() + "\u2026";
22079
+ }
22080
+ function deliverableFor(intent, msg) {
22081
+ const s = firstSentence(msg);
22082
+ switch (intent) {
22083
+ case "greenfield":
22084
+ return `Design and scaffold a working MVP for: ${s}`;
22085
+ case "redesign":
22086
+ return `Redesign the UI/UX while preserving behaviour for: ${s}`;
22087
+ case "extend":
22088
+ return `Extend the existing project with: ${s}`;
22089
+ case "fix":
22090
+ return `Diagnose and resolve: ${s}`;
22091
+ }
22092
+ }
22093
+ function assumptionsFor(intent, stack, msg) {
22094
+ const out = [];
22095
+ if (intent === "greenfield" && stack.length === 0) {
22096
+ out.push("Stack not specified \u2014 a sensible default will be chosen and stated in the plan.");
22097
+ }
22098
+ if (/\b(pagament|payment|checkout|stripe)\b/i.test(msg)) {
22099
+ out.push("Payments are stubbed (no live gateway credentials).");
22100
+ }
22101
+ if (/\b(auth|login|accesso|autenticazione)\b/i.test(msg)) {
22102
+ out.push("Authentication uses a minimal local scheme unless specified otherwise.");
22103
+ }
22104
+ if (out.length === 0) {
22105
+ out.push("Scope is limited to the MVP slice defined below.");
22106
+ }
22107
+ return out;
22108
+ }
22109
+ function buildMissionBrief(input) {
22110
+ const { userMessage, hasPlan = false } = input;
22111
+ const maxTasks = input.maxSliceTasks ?? 8;
22112
+ const intent = classifyMission({ userMessage, hasPlan });
22113
+ const runModeHint = resolveCouncilRunMode({
22114
+ userMessage,
22115
+ hasExistingPlan: hasPlan,
22116
+ env: input.env
22117
+ });
22118
+ const stackInferred = inferStack(userMessage);
22119
+ const isGreenfield = intent === "greenfield" && !hasPlan;
22120
+ const phases = isGreenfield ? [
22121
+ { name: "design", mode: "design-phase" },
22122
+ { name: "implementation", mode: "implementation" }
22123
+ ] : [{ name: runModeHint === "design-phase" ? "design" : "implementation", mode: runModeHint }];
22124
+ const sliceMvp = {
22125
+ id: "slice-mvp",
22126
+ title: `MVP \u2014 ${firstSentence(userMessage, 60)}`,
22127
+ maxTasks
22128
+ };
22129
+ return {
22130
+ intent,
22131
+ runModeHint,
22132
+ stackInferred,
22133
+ deliverableThisMission: deliverableFor(intent, userMessage),
22134
+ assumptions: assumptionsFor(intent, stackInferred, userMessage),
22135
+ outOfScope: [
22136
+ "Production deployment and CI/CD pipelines",
22137
+ "Real credentials, secrets, and third-party account setup"
22138
+ ],
22139
+ phases,
22140
+ sliceMvp,
22141
+ slices: [sliceMvp],
22142
+ userPromptOriginal: userMessage
22143
+ };
22144
+ }
22145
+ var STACK_SIGNALS;
22146
+ var init_missionBrief = __esm({
22147
+ "packages/core/dist/council/missionBrief.js"() {
22148
+ "use strict";
22149
+ init_mission();
22150
+ init_runMode();
22151
+ STACK_SIGNALS = [
22152
+ [/\breact\b/i, "react"],
22153
+ [/\bnext\.?js\b/i, "nextjs"],
22154
+ [/\bvue\b/i, "vue"],
22155
+ [/\bsvelte\b/i, "svelte"],
22156
+ [/\bangular\b/i, "angular"],
22157
+ [/\bnode(\.js)?\b/i, "node"],
22158
+ [/\bexpress\b/i, "express"],
22159
+ [/\blaravel\b/i, "laravel"],
22160
+ [/\bphp\b/i, "php"],
22161
+ [/\bpython\b/i, "python"],
22162
+ [/\bdjango\b/i, "django"],
22163
+ [/\bflask\b/i, "flask"],
22164
+ [/\btypescript\b|\bts\b/i, "typescript"],
22165
+ [/\btailwind\b/i, "tailwind"],
22166
+ [/\bpostgres(ql)?\b/i, "postgres"],
22167
+ [/\bmysql\b/i, "mysql"],
22168
+ [/\bsqlite\b/i, "sqlite"],
22169
+ [/\bmongo(db)?\b/i, "mongodb"],
22170
+ [/\bstripe\b/i, "stripe"]
22171
+ ];
22172
+ }
22173
+ });
22174
+
22041
22175
  // packages/core/dist/council/verification/types.js
22042
22176
  var init_types = __esm({
22043
22177
  "packages/core/dist/council/verification/types.js"() {
@@ -22271,9 +22405,9 @@ var init_types2 = __esm({
22271
22405
  import { readFileSync as readFileSync11 } from "node:fs";
22272
22406
  import { join as join8 } from "node:path";
22273
22407
  function readLessonsDeduped(zelariRoot) {
22274
- const path22 = join8(zelariRoot, LESSONS_FILE);
22408
+ const path24 = join8(zelariRoot, LESSONS_FILE);
22275
22409
  try {
22276
- const raw = readFileSync11(path22, "utf8");
22410
+ const raw = readFileSync11(path24, "utf8");
22277
22411
  const byId = /* @__PURE__ */ new Map();
22278
22412
  for (const line of raw.split(/\r?\n/)) {
22279
22413
  if (!line.trim())
@@ -22374,8 +22508,8 @@ function keywordsFrom(check2, signature) {
22374
22508
  return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
22375
22509
  }
22376
22510
  function writeLesson(zelariRoot, lesson) {
22377
- const path22 = join9(zelariRoot, LESSONS_FILE);
22378
- appendFileSync2(path22, `${JSON.stringify(lesson)}
22511
+ const path24 = join9(zelariRoot, LESSONS_FILE);
22512
+ appendFileSync2(path24, `${JSON.stringify(lesson)}
22379
22513
  `, "utf8");
22380
22514
  }
22381
22515
  function findSimilar(lessons, signature) {
@@ -22817,6 +22951,7 @@ __export(council_exports, {
22817
22951
  buildDeliveryFixPrompt: () => buildDeliveryFixPrompt,
22818
22952
  buildImplementationVerifyRetryPrompt: () => buildImplementationVerifyRetryPrompt,
22819
22953
  buildImplementationWriteRetryPrompt: () => buildImplementationWriteRetryPrompt,
22954
+ buildMissionBrief: () => buildMissionBrief,
22820
22955
  buildMotionFixPrompt: () => buildMotionFixPrompt,
22821
22956
  buildRetryPrompt: () => buildRetryPrompt,
22822
22957
  buildSkillDefinition: () => buildSkillDefinition,
@@ -22826,6 +22961,7 @@ __export(council_exports, {
22826
22961
  checkImplementationDelivery: () => checkImplementationDelivery,
22827
22962
  checkMemberToolEmissionSets: () => checkMemberToolEmissionSets,
22828
22963
  checkMemberToolEmissions: () => checkMemberToolEmissions,
22964
+ classifyMission: () => classifyMission,
22829
22965
  classifyTaskScope: () => classifyTaskScope,
22830
22966
  cleanAgentContent: () => cleanAgentContent,
22831
22967
  computeAgentSkills: () => computeAgentSkills,
@@ -22891,6 +23027,8 @@ var init_council = __esm({
22891
23027
  "use strict";
22892
23028
  init_councilApi();
22893
23029
  init_runMode();
23030
+ init_mission();
23031
+ init_missionBrief();
22894
23032
  init_modeBanners();
22895
23033
  init_verification();
22896
23034
  init_lessons();
@@ -23511,28 +23649,28 @@ var init_storage = __esm({
23511
23649
  VALID_SCALARS = /^(true|false|null|~)$/i;
23512
23650
  Storage = class {
23513
23651
  /** Read a Markdown file with frontmatter. Throws if not found. */
23514
- read(path22) {
23515
- if (!existsSync13(path22)) {
23516
- throw new Error(`File not found: ${path22}`);
23652
+ read(path24) {
23653
+ if (!existsSync13(path24)) {
23654
+ throw new Error(`File not found: ${path24}`);
23517
23655
  }
23518
- const md = readFileSync13(path22, "utf8");
23656
+ const md = readFileSync13(path24, "utf8");
23519
23657
  return parseFrontmatter(md);
23520
23658
  }
23521
23659
  /** Read a Markdown file; returns null if not found. */
23522
- readIfExists(path22) {
23523
- if (!existsSync13(path22)) return null;
23524
- return this.read(path22);
23660
+ readIfExists(path24) {
23661
+ if (!existsSync13(path24)) return null;
23662
+ return this.read(path24);
23525
23663
  }
23526
23664
  /**
23527
23665
  * Write a Markdown file atomically (tmp + rename). Creates parent dirs.
23528
23666
  * The meta object is serialized as YAML frontmatter; body as Markdown.
23529
23667
  */
23530
- write(path22, meta3, body) {
23531
- mkdirSync7(dirname(path22), { recursive: true });
23532
- const tmp = path22 + ".tmp-" + process.pid;
23668
+ write(path24, meta3, body) {
23669
+ mkdirSync7(dirname(path24), { recursive: true });
23670
+ const tmp = path24 + ".tmp-" + process.pid;
23533
23671
  const md = serializeFrontmatter(meta3, body);
23534
23672
  writeFileSync11(tmp, md, "utf8");
23535
- renameSync2(tmp, path22);
23673
+ renameSync2(tmp, path24);
23536
23674
  }
23537
23675
  /** List all .md files in a directory (non-recursive). */
23538
23676
  listMarkdown(dir) {
@@ -23610,8 +23748,8 @@ function readPlan(ctx) {
23610
23748
  } catch {
23611
23749
  }
23612
23750
  }
23613
- const path22 = workspaceFile(ctx.rootDir, "plan");
23614
- const doc = ctx.storage.readIfExists(path22);
23751
+ const path24 = workspaceFile(ctx.rootDir, "plan");
23752
+ const doc = ctx.storage.readIfExists(path24);
23615
23753
  if (!doc) return { phases: [], tasks: [], milestones: [] };
23616
23754
  const meta3 = doc.meta;
23617
23755
  return {
@@ -23776,7 +23914,7 @@ function addMilestoneRecord(ctx, summary, input) {
23776
23914
  dueDate: input.dueDate,
23777
23915
  targetVersion: version2
23778
23916
  });
23779
- const path22 = join14(ctx.rootDir, "milestones", `${id}.md`);
23917
+ const path24 = join14(ctx.rootDir, "milestones", `${id}.md`);
23780
23918
  const meta3 = {
23781
23919
  kind: "milestone",
23782
23920
  id,
@@ -23793,7 +23931,7 @@ function addMilestoneRecord(ctx, summary, input) {
23793
23931
  `Target version: ${version2}`,
23794
23932
  ""
23795
23933
  ].join("\n");
23796
- ctx.storage.write(path22, meta3, body);
23934
+ ctx.storage.write(path24, meta3, body);
23797
23935
  return { id, created: true };
23798
23936
  }
23799
23937
  function readPlanSummary(ctx) {
@@ -23997,7 +24135,7 @@ function addIdeaStub(ctx) {
23997
24135
  const tags = args["tags"] ?? [];
23998
24136
  const category = args["category"] ?? "General";
23999
24137
  const id = `${nextAdrId(ctx)}-${slugify3(title)}`;
24000
- const path22 = workspaceArtifact(ctx.rootDir, "decisions", id);
24138
+ const path24 = workspaceArtifact(ctx.rootDir, "decisions", id);
24001
24139
  const meta3 = {
24002
24140
  kind: "adr",
24003
24141
  status: "proposed",
@@ -24023,7 +24161,7 @@ function addIdeaStub(ctx) {
24023
24161
  ...consequences.map((c) => `- ${c}`),
24024
24162
  ""
24025
24163
  ].join("\n");
24026
- ctx.storage.write(path22, meta3, body);
24164
+ ctx.storage.write(path24, meta3, body);
24027
24165
  return `ADR ${id} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
24028
24166
  });
24029
24167
  }
@@ -24105,14 +24243,14 @@ function createDocumentStub(ctx) {
24105
24243
  ctx.storage.write(risksPath, riskMeta, content);
24106
24244
  return `Document "${title}" created at risks.md (workspace root).`;
24107
24245
  }
24108
- const path22 = workspaceArtifact(ctx.rootDir, "docs", slug);
24246
+ const path24 = workspaceArtifact(ctx.rootDir, "docs", slug);
24109
24247
  const meta3 = {
24110
24248
  kind: "doc",
24111
24249
  id: slug,
24112
24250
  date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
24113
24251
  tags
24114
24252
  };
24115
- ctx.storage.write(path22, meta3, content);
24253
+ ctx.storage.write(path24, meta3, content);
24116
24254
  return `Document "${title}" created at docs/${slug}.md.`;
24117
24255
  });
24118
24256
  }
@@ -24618,6 +24756,10 @@ var init_councilConfig = __esm({
24618
24756
  });
24619
24757
 
24620
24758
  // src/cli/workspace/planDetect.ts
24759
+ var planDetect_exports = {};
24760
+ __export(planDetect_exports, {
24761
+ hasWorkspacePlan: () => hasWorkspacePlan
24762
+ });
24621
24763
  import { existsSync as existsSync16, readFileSync as readFileSync16 } from "node:fs";
24622
24764
  import { join as join16 } from "node:path";
24623
24765
  function hasWorkspacePlan(projectRoot = process.cwd()) {
@@ -24677,6 +24819,7 @@ async function* dispatchCouncil(userMessage, options) {
24677
24819
  sessionId: options.sessionId,
24678
24820
  tools: options.tools ?? (options.disableWorkspaceTools ? void 0 : createWorkspaceToolRegistry(createWorkspaceContext(projectRoot))),
24679
24821
  maxToolCallsPerTurn: options.maxToolCallsPerTurn,
24822
+ maxToolCallsChairman: options.maxToolCallsChairman,
24680
24823
  feedbackStore: options.feedbackStore
24681
24824
  };
24682
24825
  if (!options.disableWorkspaceTools) {
@@ -24725,10 +24868,10 @@ import { createHash as createHash2 } from "node:crypto";
24725
24868
  import { join as join17 } from "node:path";
24726
24869
  import { readFile } from "node:fs/promises";
24727
24870
  async function readPackageJson2(projectRoot) {
24728
- const path22 = join17(projectRoot, "package.json");
24729
- if (!existsSync17(path22)) return null;
24871
+ const path24 = join17(projectRoot, "package.json");
24872
+ if (!existsSync17(path24)) return null;
24730
24873
  try {
24731
- return JSON.parse(await readFile(path22, "utf8"));
24874
+ return JSON.parse(await readFile(path24, "utf8"));
24732
24875
  } catch {
24733
24876
  return null;
24734
24877
  }
@@ -24810,9 +24953,9 @@ async function genBuild(ctx) {
24810
24953
  ].join("\n");
24811
24954
  }
24812
24955
  async function genOpenQuestions(ctx) {
24813
- const path22 = join17(ctx.rootDir, "risks.md");
24814
- if (!existsSync17(path22)) return "_No open questions._";
24815
- const content = readFileSync17(path22, "utf8");
24956
+ const path24 = join17(ctx.rootDir, "risks.md");
24957
+ if (!existsSync17(path24)) return "_No open questions._";
24958
+ const content = readFileSync17(path24, "utf8");
24816
24959
  const lines = content.split("\n");
24817
24960
  const questions = [];
24818
24961
  let currentTitle = "";
@@ -25375,8 +25518,8 @@ async function runPostCouncilHook(ctx, options) {
25375
25518
  sources: scope.sources
25376
25519
  } : void 0
25377
25520
  });
25378
- const path22 = writeCouncilCompletion(ctx.rootDir, completion);
25379
- completionHook = { ran: true, path: path22, completion };
25521
+ const path24 = writeCouncilCompletion(ctx.rootDir, completion);
25522
+ completionHook = { ran: true, path: path24, completion };
25380
25523
  } catch (err) {
25381
25524
  completionHook = {
25382
25525
  ran: true,
@@ -25586,6 +25729,284 @@ var init_councilFeedback = __esm({
25586
25729
  }
25587
25730
  });
25588
25731
 
25732
+ // src/cli/memory/fileBackend.ts
25733
+ var fileBackend_exports = {};
25734
+ __export(fileBackend_exports, {
25735
+ FileMemoryBackend: () => FileMemoryBackend,
25736
+ NoopMemoryBackend: () => NoopMemoryBackend,
25737
+ formatMemoryHits: () => formatMemoryHits,
25738
+ getMemoryBackend: () => getMemoryBackend,
25739
+ isMemoryEnabled: () => isMemoryEnabled
25740
+ });
25741
+ import { randomUUID as randomUUID2 } from "node:crypto";
25742
+ import { promises as fs13 } from "node:fs";
25743
+ import * as path16 from "node:path";
25744
+ function tokenize(text) {
25745
+ return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
25746
+ }
25747
+ function matchesFilter(metadata, filter) {
25748
+ if (!filter) return true;
25749
+ for (const [k, v] of Object.entries(filter)) {
25750
+ if (metadata[k] !== v) return false;
25751
+ }
25752
+ return true;
25753
+ }
25754
+ function isMemoryEnabled(env = process.env) {
25755
+ return env.ZELARI_MEMORY !== "0";
25756
+ }
25757
+ async function getMemoryBackend(projectRoot, env = process.env) {
25758
+ if (!isMemoryEnabled(env)) return new NoopMemoryBackend();
25759
+ const backend = new FileMemoryBackend();
25760
+ try {
25761
+ await backend.init(projectRoot);
25762
+ return backend;
25763
+ } catch {
25764
+ return new NoopMemoryBackend();
25765
+ }
25766
+ }
25767
+ function formatMemoryHits(hits) {
25768
+ if (hits.length === 0) return "";
25769
+ const lines = hits.map((h, i) => `${i + 1}. ${h.text.replace(/\s+/g, " ").trim()}`);
25770
+ return `## Recalled from project memory
25771
+ ${lines.join("\n")}`;
25772
+ }
25773
+ var FileMemoryBackend, NoopMemoryBackend;
25774
+ var init_fileBackend = __esm({
25775
+ "src/cli/memory/fileBackend.ts"() {
25776
+ "use strict";
25777
+ FileMemoryBackend = class {
25778
+ logPath = "";
25779
+ memoryDir = "";
25780
+ async init(projectRoot) {
25781
+ this.memoryDir = path16.join(projectRoot, ".zelari", "memory");
25782
+ this.logPath = path16.join(this.memoryDir, "log.jsonl");
25783
+ await fs13.mkdir(this.memoryDir, { recursive: true });
25784
+ }
25785
+ async add(content, metadata = {}, graph) {
25786
+ const fact = {
25787
+ id: randomUUID2(),
25788
+ content,
25789
+ metadata,
25790
+ ...graph ? { graph } : {},
25791
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
25792
+ };
25793
+ await fs13.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
25794
+ return fact.id;
25795
+ }
25796
+ async search(query, options = {}) {
25797
+ const limit = options.limit ?? 8;
25798
+ const facts = await this.readAll();
25799
+ const queryTokens = new Set(tokenize(query));
25800
+ if (queryTokens.size === 0) return [];
25801
+ const scored = [];
25802
+ for (const fact of facts) {
25803
+ if (!matchesFilter(fact.metadata, options.metadataFilter)) continue;
25804
+ const contentTokens = new Set(tokenize(fact.content));
25805
+ let score = 0;
25806
+ for (const t of queryTokens) {
25807
+ if (contentTokens.has(t)) score += 1;
25808
+ }
25809
+ if (score > 0) {
25810
+ scored.push({ id: fact.id, text: fact.content, score, metadata: fact.metadata });
25811
+ }
25812
+ }
25813
+ scored.sort((a, b) => b.score - a.score);
25814
+ return scored.slice(0, limit);
25815
+ }
25816
+ async close() {
25817
+ }
25818
+ async readAll() {
25819
+ let raw;
25820
+ try {
25821
+ raw = await fs13.readFile(this.logPath, "utf8");
25822
+ } catch {
25823
+ return [];
25824
+ }
25825
+ const facts = [];
25826
+ for (const line of raw.split("\n")) {
25827
+ const trimmed = line.trim();
25828
+ if (!trimmed) continue;
25829
+ try {
25830
+ facts.push(JSON.parse(trimmed));
25831
+ } catch {
25832
+ }
25833
+ }
25834
+ return facts;
25835
+ }
25836
+ };
25837
+ NoopMemoryBackend = class {
25838
+ async init() {
25839
+ }
25840
+ async add() {
25841
+ return "";
25842
+ }
25843
+ async search() {
25844
+ return [];
25845
+ }
25846
+ async close() {
25847
+ }
25848
+ };
25849
+ }
25850
+ });
25851
+
25852
+ // src/cli/zelariMission.ts
25853
+ var zelariMission_exports = {};
25854
+ __export(zelariMission_exports, {
25855
+ formatBriefForChat: () => formatBriefForChat,
25856
+ isMissionAutoStart: () => isMissionAutoStart,
25857
+ resolveMaxIterations: () => resolveMaxIterations,
25858
+ resolveMaxStall: () => resolveMaxStall,
25859
+ runZelariMission: () => runZelariMission
25860
+ });
25861
+ import { randomUUID as randomUUID3 } from "node:crypto";
25862
+ import { promises as fs14 } from "node:fs";
25863
+ import * as path17 from "node:path";
25864
+ function resolveMaxIterations(env = process.env) {
25865
+ const raw = env.ZELARI_MISSION_MAX_ITER;
25866
+ const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
25867
+ return Number.isFinite(n) && n > 0 ? n : DEFAULT_MAX_ITER;
25868
+ }
25869
+ function resolveMaxStall(env = process.env) {
25870
+ const raw = env.ZELARI_MISSION_MAX_STALL;
25871
+ if (raw === void 0) return DEFAULT_MAX_STALL;
25872
+ const n = Number.parseInt(raw, 10);
25873
+ return Number.isFinite(n) && n >= 0 ? n : DEFAULT_MAX_STALL;
25874
+ }
25875
+ function isMissionAutoStart(env = process.env) {
25876
+ return env.ZELARI_MISSION_AUTO === "1";
25877
+ }
25878
+ async function writeMissionState(projectRoot, state2) {
25879
+ const dir = path17.join(projectRoot, ".zelari");
25880
+ await fs14.mkdir(dir, { recursive: true });
25881
+ await fs14.writeFile(
25882
+ path17.join(dir, "mission-state.json"),
25883
+ JSON.stringify(state2, null, 2) + "\n",
25884
+ "utf8"
25885
+ );
25886
+ }
25887
+ function buildSlicePrompt(brief, userMessage, runMode, iteration) {
25888
+ if (runMode === "design-phase") {
25889
+ return `${userMessage}
25890
+
25891
+ [Zelari mission] Produce the design-phase plan for the MVP: ${brief.deliverableThisMission}. Keep the first slice to at most ${brief.sliceMvp.maxTasks ?? 8} tasks.`;
25892
+ }
25893
+ const fix = iteration > 1 ? " Address any remaining verification failures recorded in .zelari/completion.json." : "";
25894
+ return `${userMessage}
25895
+
25896
+ [Zelari mission] Implement the MVP slice: ${brief.deliverableThisMission}.${fix} You MUST create or modify the real project files with write_file / edit_file \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.`;
25897
+ }
25898
+ function formatBriefForChat(brief) {
25899
+ const lines = [
25900
+ "[zelari] Mission brief",
25901
+ ` intent: ${brief.intent}`,
25902
+ ` first run: ${brief.runModeHint}`,
25903
+ ` deliverable: ${brief.deliverableThisMission}`
25904
+ ];
25905
+ if (brief.stackInferred.length) {
25906
+ lines.push(` stack: ${brief.stackInferred.join(", ")}`);
25907
+ }
25908
+ if (brief.assumptions.length) {
25909
+ lines.push(" assumptions:");
25910
+ for (const a of brief.assumptions) lines.push(` - ${a}`);
25911
+ }
25912
+ if (brief.outOfScope.length) {
25913
+ lines.push(" out of scope:");
25914
+ for (const o of brief.outOfScope) lines.push(` - ${o}`);
25915
+ }
25916
+ lines.push(` MVP slice: ${brief.sliceMvp.title} (\u2264 ${brief.sliceMvp.maxTasks} tasks)`);
25917
+ return lines.join("\n");
25918
+ }
25919
+ async function runZelariMission(userMessage, brief, deps) {
25920
+ const now = deps.now ?? (() => /* @__PURE__ */ new Date());
25921
+ const maxIter = deps.maxIterations ?? resolveMaxIterations(deps.env);
25922
+ const maxStall = resolveMaxStall(deps.env);
25923
+ const missionId = deps.missionId ?? `m_${randomUUID3().slice(0, 8)}`;
25924
+ const startedAt = now().toISOString();
25925
+ const state2 = {
25926
+ missionId,
25927
+ userPrompt: userMessage,
25928
+ brief,
25929
+ iteration: 0,
25930
+ currentSliceId: brief.sliceMvp.id,
25931
+ status: "running",
25932
+ lastCompletionOk: false,
25933
+ startedAt,
25934
+ updatedAt: startedAt
25935
+ };
25936
+ await deps.memory.init(deps.projectRoot);
25937
+ await writeMissionState(deps.projectRoot, state2);
25938
+ const designFirst = brief.phases[0]?.mode === "design-phase";
25939
+ let noWriteStreak = 0;
25940
+ for (let i = 1; i <= maxIter; i++) {
25941
+ state2.iteration = i;
25942
+ const runMode = i === 1 && designFirst ? "design-phase" : "implementation";
25943
+ const hits = await deps.memory.search(`${brief.deliverableThisMission} ${userMessage}`, {
25944
+ limit: 8,
25945
+ metadataFilter: { projectRoot: deps.projectRoot }
25946
+ });
25947
+ const ragContext = formatMemoryHits(hits);
25948
+ const slicePrompt = buildSlicePrompt(brief, userMessage, runMode, i);
25949
+ deps.emit(`[zelari] iterazione ${i}/${maxIter} \xB7 ${runMode} \xB7 slice ${brief.sliceMvp.id}`);
25950
+ let result;
25951
+ try {
25952
+ result = await deps.runSlice({ userMessage: slicePrompt, runMode, ragContext, iteration: i });
25953
+ } catch (err) {
25954
+ state2.status = "error";
25955
+ state2.updatedAt = now().toISOString();
25956
+ await writeMissionState(deps.projectRoot, state2);
25957
+ deps.emit(`[zelari] errore all'iterazione ${i}: ${err instanceof Error ? err.message : String(err)}`);
25958
+ return state2;
25959
+ }
25960
+ await deps.memory.add(
25961
+ JSON.stringify({
25962
+ iteration: i,
25963
+ runMode,
25964
+ completionOk: result.completionOk,
25965
+ synthesis: result.synthesisText?.slice(0, 2e3) ?? ""
25966
+ }),
25967
+ { projectRoot: deps.projectRoot, missionId, sliceId: brief.sliceMvp.id, source: "council", iteration: i }
25968
+ );
25969
+ state2.lastCompletionOk = result.completionOk;
25970
+ state2.updatedAt = now().toISOString();
25971
+ if (result.completionOk && runMode === "implementation") {
25972
+ state2.status = "success";
25973
+ await writeMissionState(deps.projectRoot, state2);
25974
+ deps.emit(`[zelari] \u2713 missione completata \u2014 slice MVP verde all'iterazione ${i}.`);
25975
+ return state2;
25976
+ }
25977
+ if (runMode === "implementation" && typeof result.writeCount === "number") {
25978
+ if (result.writeCount === 0) noWriteStreak++;
25979
+ else noWriteStreak = 0;
25980
+ if (maxStall > 0 && noWriteStreak >= maxStall) {
25981
+ state2.status = "stalled";
25982
+ state2.updatedAt = now().toISOString();
25983
+ await writeMissionState(deps.projectRoot, state2);
25984
+ deps.emit(
25985
+ `[zelari] fermata: ${noWriteStreak} iterazioni di implementation senza scrivere alcun file (il modello dichiara "fatto" ma non produce il deliverable). Prova un modello pi\xF9 capace o verifica provider/chiave. Stato salvato in .zelari/mission-state.json`
25986
+ );
25987
+ return state2;
25988
+ }
25989
+ }
25990
+ await writeMissionState(deps.projectRoot, state2);
25991
+ }
25992
+ state2.status = "stopped";
25993
+ state2.updatedAt = now().toISOString();
25994
+ await writeMissionState(deps.projectRoot, state2);
25995
+ deps.emit(
25996
+ `[zelari] fermata dopo ${maxIter} iterazioni senza completamento verde. Stato salvato in .zelari/mission-state.json`
25997
+ );
25998
+ return state2;
25999
+ }
26000
+ var DEFAULT_MAX_ITER, DEFAULT_MAX_STALL;
26001
+ var init_zelariMission = __esm({
26002
+ "src/cli/zelariMission.ts"() {
26003
+ "use strict";
26004
+ init_fileBackend();
26005
+ DEFAULT_MAX_ITER = 10;
26006
+ DEFAULT_MAX_STALL = 2;
26007
+ }
26008
+ });
26009
+
25589
26010
  // src/cli/updater.ts
25590
26011
  var updater_exports = {};
25591
26012
  __export(updater_exports, {
@@ -25598,11 +26019,11 @@ __export(updater_exports, {
25598
26019
  });
25599
26020
  import { createRequire } from "node:module";
25600
26021
  import { spawn as spawn5 } from "node:child_process";
25601
- import path17 from "node:path";
26022
+ import path19 from "node:path";
25602
26023
  import { fileURLToPath } from "node:url";
25603
26024
  function getCurrentVersion() {
25604
26025
  try {
25605
- const pkgPath = path17.resolve(__dirname2, "..", "..", "package.json");
26026
+ const pkgPath = path19.resolve(__dirname2, "..", "..", "package.json");
25606
26027
  const pkg = require2(pkgPath);
25607
26028
  return pkg.version;
25608
26029
  } catch {
@@ -25700,7 +26121,7 @@ var init_updater = __esm({
25700
26121
  "use strict";
25701
26122
  init_cmdline();
25702
26123
  require2 = createRequire(import.meta.url);
25703
- __dirname2 = path17.dirname(fileURLToPath(import.meta.url));
26124
+ __dirname2 = path19.dirname(fileURLToPath(import.meta.url));
25704
26125
  REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
25705
26126
  }
25706
26127
  });
@@ -26144,7 +26565,14 @@ function StatusBar({
26144
26565
  elapsedMs = null,
26145
26566
  lastMs = null
26146
26567
  }) {
26147
- return /* @__PURE__ */ React6.createElement(Box5, { paddingX: 1, width: "100%", justifyContent: "space-between", gap: 2 }, /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 2 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, /* @__PURE__ */ React6.createElement(Text6, { color: sessionActive ? "green" : "gray" }, sessionActive ? "\u25CF" : "\u25CB"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: mode === "council" ? "magenta" : "cyan" }, mode === "council" ? "\u26EC council" : "\u23F5 agent"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (shift+tab)"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, provider), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, model), cwd ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, cwd)) : null)), /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 1 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, busy && elapsedMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Spinner, { color: "yellow" }), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, " ", formatDuration(elapsedMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : lastMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "last ", formatDuration(lastMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, queueCount > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "queue ", queueCount), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "session ", sessionId))));
26568
+ return /* @__PURE__ */ React6.createElement(Box5, { paddingX: 1, width: "100%", justifyContent: "space-between", gap: 2 }, /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 2 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, /* @__PURE__ */ React6.createElement(Text6, { color: sessionActive ? "green" : "gray" }, sessionActive ? "\u25CF" : "\u25CB"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " "), /* @__PURE__ */ React6.createElement(
26569
+ Text6,
26570
+ {
26571
+ bold: true,
26572
+ color: mode === "council" ? "magenta" : mode === "zelari" ? "green" : "cyan"
26573
+ },
26574
+ mode === "council" ? "\u26EC council" : mode === "zelari" ? "\u26A1 zelari" : "\u23F5 agent"
26575
+ ), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (shift+tab)"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: "cyan" }, provider), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, model), cwd ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, cwd)) : null)), /* @__PURE__ */ React6.createElement(Box5, { flexShrink: 1 }, /* @__PURE__ */ React6.createElement(Text6, { wrap: "truncate" }, busy && elapsedMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Spinner, { color: "yellow" }), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, " ", formatDuration(elapsedMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : lastMs !== null ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "last ", formatDuration(lastMs)), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, queueCount > 0 ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "queue ", queueCount), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \xB7 ")) : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "session ", sessionId))));
26148
26576
  }
26149
26577
 
26150
26578
  // src/cli/components/SelectList.tsx
@@ -30026,15 +30454,47 @@ function useChatTurn(params) {
30026
30454
  liveRef
30027
30455
  ]
30028
30456
  );
30457
+ const pendingZelariRef = useRef4(null);
30458
+ const dispatchZelariPrompt = useCallback2(
30459
+ async (text) => {
30460
+ await dispatchZelariPromptImpl(
30461
+ text,
30462
+ {
30463
+ sessionId,
30464
+ writerRef,
30465
+ setMessages,
30466
+ commitStreaming,
30467
+ flushStreaming,
30468
+ setBusy,
30469
+ setQueueCount,
30470
+ setLive,
30471
+ liveRef
30472
+ },
30473
+ pendingZelariRef
30474
+ );
30475
+ },
30476
+ [
30477
+ sessionId,
30478
+ writerRef,
30479
+ setMessages,
30480
+ commitStreaming,
30481
+ flushStreaming,
30482
+ setBusy,
30483
+ setQueueCount,
30484
+ setLive,
30485
+ liveRef
30486
+ ]
30487
+ );
30029
30488
  return {
30030
30489
  dispatchPrompt,
30031
30490
  dispatchCouncilPrompt,
30491
+ dispatchZelariPrompt,
30032
30492
  harnessRef,
30033
30493
  queueCount,
30034
30494
  setQueueCount
30035
30495
  };
30036
30496
  }
30037
- async function dispatchCouncilPromptImpl(text, deps) {
30497
+ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
30038
30498
  const {
30039
30499
  sessionId,
30040
30500
  writerRef,
@@ -30054,7 +30514,7 @@ async function dispatchCouncilPromptImpl(text, deps) {
30054
30514
  setMessages,
30055
30515
  `No API key for the active provider "${active}". Set ${spec?.envVar ?? "the provider API key env var"} or run /login ${active} before invoking /council.`
30056
30516
  );
30057
- return;
30517
+ return { completionOk: false, ran: false };
30058
30518
  }
30059
30519
  setBusy(true);
30060
30520
  const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
@@ -30096,6 +30556,9 @@ async function dispatchCouncilPromptImpl(text, deps) {
30096
30556
  let chairmanErrored = false;
30097
30557
  let luciferWriteCount = 0;
30098
30558
  let councilRunMode = "implementation";
30559
+ let sliceCompletionOk = false;
30560
+ let sliceRan = false;
30561
+ let sliceDegraded = false;
30099
30562
  const PROVIDER_ERROR_ABORT_THRESHOLD = 2;
30100
30563
  try {
30101
30564
  for await (const event of dispatchCouncil2(text, {
@@ -30118,6 +30581,11 @@ async function dispatchCouncilPromptImpl(text, deps) {
30118
30581
  buildLessonsSummary2(process.cwd(), text)
30119
30582
  ].filter(Boolean).join("\n\n"),
30120
30583
  maxToolCallsPerTurn: councilMaxToolCalls,
30584
+ // v1.0: Zelari-mode per-slice overrides (memory RAG, forced run mode,
30585
+ // raised chairman budget). No-ops for a normal /council run.
30586
+ ...overrides.ragContext ? { ragContext: overrides.ragContext } : {},
30587
+ ...overrides.runMode ? { runMode: overrides.runMode } : {},
30588
+ ...overrides.maxToolCallsChairman ? { maxToolCallsChairman: overrides.maxToolCallsChairman } : {},
30121
30589
  onCouncilStatus: (message) => {
30122
30590
  appendSystem(setMessages, message, Date.now());
30123
30591
  }
@@ -30272,6 +30740,7 @@ async function dispatchCouncilPromptImpl(text, deps) {
30272
30740
  if (useLiveModel) finalizeStreaming(setMessages, setLive);
30273
30741
  else finalizeStreamingAssistant(setMessages);
30274
30742
  const hookShouldRun = membersCompleted > 0 || chairmanProducedOutput;
30743
+ sliceRan = hookShouldRun;
30275
30744
  if (hookShouldRun) {
30276
30745
  try {
30277
30746
  const { detectDegradedRun: detectDegradedRun2 } = await Promise.resolve().then(() => (init_council(), council_exports));
@@ -30282,6 +30751,7 @@ async function dispatchCouncilPromptImpl(text, deps) {
30282
30751
  synthesisText: chairmanSynthesisText,
30283
30752
  runMode: councilRunMode
30284
30753
  });
30754
+ sliceDegraded = degraded.degraded;
30285
30755
  if (degraded.degraded) {
30286
30756
  appendSystem(
30287
30757
  setMessages,
@@ -30296,6 +30766,7 @@ async function dispatchCouncilPromptImpl(text, deps) {
30296
30766
  degradedRun: degraded.degraded,
30297
30767
  degradedReasons: degraded.reasons
30298
30768
  });
30769
+ sliceCompletionOk = hook.completion?.completion?.ok ?? false;
30299
30770
  if (hook.ran && hook.changed) {
30300
30771
  appendSystem(
30301
30772
  setMessages,
@@ -30389,6 +30860,101 @@ ${lines}${fails.length > 8 ? "\n \xB7 \u2026" : ""}`,
30389
30860
  }
30390
30861
  setBusy(false);
30391
30862
  }
30863
+ return {
30864
+ completionOk: sliceCompletionOk,
30865
+ ran: sliceRan,
30866
+ synthesisText: chairmanSynthesisText || void 0,
30867
+ writeCount: luciferWriteCount,
30868
+ degraded: sliceDegraded
30869
+ };
30870
+ }
30871
+ async function dispatchZelariPromptImpl(text, deps, pendingRef) {
30872
+ const { setMessages } = deps;
30873
+ const emit = (m) => appendSystem(setMessages, m, Date.now());
30874
+ if (pendingRef.current) {
30875
+ const pending = pendingRef.current;
30876
+ pendingRef.current = null;
30877
+ const affirmative = /^(ok|okay|s[iì]|yes|y|procedi|vai|conferma|go)\b/i.test(
30878
+ text.trim()
30879
+ );
30880
+ if (!affirmative) {
30881
+ emit("[zelari] missione annullata.");
30882
+ return;
30883
+ }
30884
+ await runZelariMissionInTui(pending.userMessage, deps, emit);
30885
+ return;
30886
+ }
30887
+ const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
30888
+ const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
30889
+ const { formatBriefForChat: formatBriefForChat2, isMissionAutoStart: isMissionAutoStart2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
30890
+ const projectRoot = process.cwd();
30891
+ const brief = buildMissionBrief2({
30892
+ userMessage: text,
30893
+ hasPlan: hasWorkspacePlan2(projectRoot)
30894
+ });
30895
+ emit(formatBriefForChat2(brief));
30896
+ if (isMissionAutoStart2()) {
30897
+ await runZelariMissionInTui(text, deps, emit);
30898
+ return;
30899
+ }
30900
+ pendingRef.current = { userMessage: text };
30901
+ emit(
30902
+ "[zelari] Confermi l'avvio della missione? invia 'ok' per procedere, qualsiasi altra cosa per annullare."
30903
+ );
30904
+ }
30905
+ async function runZelariMissionInTui(userMessage, deps, emit) {
30906
+ const { setMessages } = deps;
30907
+ const envConfig = await providerFromEnv();
30908
+ if (!envConfig) {
30909
+ const active = resolveActiveProvider();
30910
+ const spec = PROVIDERS.find((p3) => p3.id === active);
30911
+ emit(
30912
+ `No API key for the active provider "${active}". Set ${spec?.envVar ?? "the provider API key env var"} or run /login ${active} before starting a Zelari mission.`
30913
+ );
30914
+ return;
30915
+ }
30916
+ const projectRoot = process.cwd();
30917
+ const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
30918
+ const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
30919
+ const { getMemoryBackend: getMemoryBackend2 } = await Promise.resolve().then(() => (init_fileBackend(), fileBackend_exports));
30920
+ const { runZelariMission: runZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
30921
+ const brief = buildMissionBrief2({
30922
+ userMessage,
30923
+ hasPlan: hasWorkspacePlan2(projectRoot)
30924
+ });
30925
+ const memory = await getMemoryBackend2(projectRoot);
30926
+ const chairmanBudget = (() => {
30927
+ const raw = process.env.ZELARI_MODE_MAX_TOOLS_LUCIFER;
30928
+ const n = raw ? Number.parseInt(raw, 10) : 30;
30929
+ return Number.isFinite(n) && n > 0 ? n : 30;
30930
+ })();
30931
+ try {
30932
+ await runZelariMission2(userMessage, brief, {
30933
+ projectRoot,
30934
+ memory,
30935
+ emit,
30936
+ runSlice: async ({ userMessage: slicePrompt, runMode, ragContext }) => {
30937
+ const r = await dispatchCouncilPromptImpl(slicePrompt, deps, {
30938
+ ragContext,
30939
+ runMode,
30940
+ maxToolCallsChairman: chairmanBudget
30941
+ });
30942
+ return {
30943
+ completionOk: r.completionOk,
30944
+ ran: r.ran,
30945
+ synthesisText: r.synthesisText,
30946
+ writeCount: r.writeCount,
30947
+ degraded: r.degraded
30948
+ };
30949
+ }
30950
+ });
30951
+ } catch (err) {
30952
+ emit(
30953
+ `[zelari] errore missione: ${err instanceof Error ? err.message : String(err)}`
30954
+ );
30955
+ } finally {
30956
+ await memory.close();
30957
+ }
30392
30958
  }
30393
30959
 
30394
30960
  // src/cli/hooks/useSlashDispatch.ts
@@ -30464,6 +31030,7 @@ function handleSlashCommand(text, availableSkills) {
30464
31030
  /skill <name> [input] \u2014 invoke a skill (autocomplete with /skill <TAB>)
30465
31031
  /skill-stats [name] \u2014 show invocation stats (success rate, avg duration, total tokens)
30466
31032
  /council <input> \u2014 invoke the multi-agent council on input
31033
+ /zelari <input> \u2014 run an autonomous mission (multi-run council until the MVP slice is complete)
30467
31034
  /council-feedback <memberId> <1-5> [note] \u2014 rate a council member for future ranking (Task I.2)
30468
31035
  /promote-member <memberId> \u2014 promote a council member to a standalone skill (v3-K)
30469
31036
  /update [--yes|-y] \u2014 check for zelari-code updates; --yes performs the update (v3-N)
@@ -30659,6 +31226,17 @@ ${formatSkillList(availableSkills)}`
30659
31226
  }
30660
31227
  return { handled: true, kind: "council", councilInput: input };
30661
31228
  }
31229
+ case "zelari": {
31230
+ const input = args.join(" ").trim();
31231
+ if (!input) {
31232
+ return {
31233
+ handled: true,
31234
+ kind: "zelari",
31235
+ message: "Usage: /zelari <prompt> \u2014 runs an autonomous Zelari mission (multi-run council until the MVP slice is complete)"
31236
+ };
31237
+ }
31238
+ return { handled: true, kind: "zelari", zelariInput: input };
31239
+ }
30662
31240
  case "council-feedback": {
30663
31241
  const memberId = args[0];
30664
31242
  const scoreStr = args[1];
@@ -30870,7 +31448,7 @@ ${formatSkillList(availableSkills)}`
30870
31448
  // src/cli/gitOps.ts
30871
31449
  import { execFile as execFile2 } from "node:child_process";
30872
31450
  import { promisify } from "node:util";
30873
- import path16 from "node:path";
31451
+ import path18 from "node:path";
30874
31452
  var execFileAsync = promisify(execFile2);
30875
31453
  async function git(cwd, args) {
30876
31454
  try {
@@ -30916,7 +31494,7 @@ async function undoWorkingChanges(opts = {}) {
30916
31494
  };
30917
31495
  }
30918
31496
  function defaultProjectRoot() {
30919
- return path16.resolve(__dirname, "..", "..", "..");
31497
+ return path18.resolve(__dirname, "..", "..", "..");
30920
31498
  }
30921
31499
 
30922
31500
  // src/cli/slashHandlers/git.ts
@@ -31055,17 +31633,17 @@ ${res.output || "(empty)"}`
31055
31633
  }
31056
31634
 
31057
31635
  // src/cli/slashHandlers/promoteMember.ts
31058
- import { promises as fs13 } from "node:fs";
31059
- import path18 from "node:path";
31636
+ import { promises as fs15 } from "node:fs";
31637
+ import path20 from "node:path";
31060
31638
  import os8 from "node:os";
31061
31639
  async function handlePromoteMember(ctx, memberId) {
31062
31640
  try {
31063
31641
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
31064
31642
  const { skill, markdown } = promoteMember2(memberId);
31065
- const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path18.join(os8.homedir(), ".tmp", "zelari-code", "skills");
31066
- await fs13.mkdir(skillDir, { recursive: true });
31067
- const filePath = path18.join(skillDir, `${skill.id}.md`);
31068
- await fs13.writeFile(filePath, markdown, "utf8");
31643
+ const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path20.join(os8.homedir(), ".tmp", "zelari-code", "skills");
31644
+ await fs15.mkdir(skillDir, { recursive: true });
31645
+ const filePath = path20.join(skillDir, `${skill.id}.md`);
31646
+ await fs15.writeFile(filePath, markdown, "utf8");
31069
31647
  appendSystem(
31070
31648
  ctx.setMessages,
31071
31649
  `[promote-member] ${skill.name} (${memberId}) \u2192 ${filePath}
@@ -31081,25 +31659,25 @@ async function handlePromoteMember(ctx, memberId) {
31081
31659
  }
31082
31660
 
31083
31661
  // src/cli/branchManager.ts
31084
- import { promises as fs14, existsSync as existsSync22, readFileSync as readFileSync21, writeFileSync as writeFileSync15, mkdirSync as mkdirSync10, statSync as statSync4, rmSync } from "node:fs";
31085
- import path19 from "node:path";
31662
+ import { promises as fs16, existsSync as existsSync22, readFileSync as readFileSync21, writeFileSync as writeFileSync15, mkdirSync as mkdirSync10, statSync as statSync4, rmSync } from "node:fs";
31663
+ import path21 from "node:path";
31086
31664
  import os9 from "node:os";
31087
31665
  var META_FILENAME = "meta.json";
31088
31666
  var SESSIONS_SUBDIR = "sessions";
31089
31667
  function getBranchesBaseDir() {
31090
- return process.env.ANATHEMA_BRANCHES_DIR ?? path19.join(os9.homedir(), ".tmp", "zelari-code", "branches");
31668
+ return process.env.ANATHEMA_BRANCHES_DIR ?? path21.join(os9.homedir(), ".tmp", "zelari-code", "branches");
31091
31669
  }
31092
31670
  function getSessionsBaseDir() {
31093
- return process.env.ANATHEMA_SESSIONS_DIR ?? path19.join(os9.homedir(), ".tmp", "zelari-code", "sessions");
31671
+ return process.env.ANATHEMA_SESSIONS_DIR ?? path21.join(os9.homedir(), ".tmp", "zelari-code", "sessions");
31094
31672
  }
31095
31673
  function branchPathFor(name, baseDir) {
31096
- return path19.join(baseDir, name);
31674
+ return path21.join(baseDir, name);
31097
31675
  }
31098
31676
  function metaPathFor(name, baseDir) {
31099
- return path19.join(baseDir, name, META_FILENAME);
31677
+ return path21.join(baseDir, name, META_FILENAME);
31100
31678
  }
31101
31679
  function sessionsPathFor(name, baseDir) {
31102
- return path19.join(baseDir, name, SESSIONS_SUBDIR);
31680
+ return path21.join(baseDir, name, SESSIONS_SUBDIR);
31103
31681
  }
31104
31682
  function readBranchMeta(name, baseDir) {
31105
31683
  const metaPath = metaPathFor(name, baseDir);
@@ -31124,13 +31702,13 @@ function readBranchMeta(name, baseDir) {
31124
31702
  }
31125
31703
  function writeBranchMeta(name, baseDir, meta3) {
31126
31704
  const metaPath = metaPathFor(name, baseDir);
31127
- mkdirSync10(path19.dirname(metaPath), { recursive: true });
31705
+ mkdirSync10(path21.dirname(metaPath), { recursive: true });
31128
31706
  writeFileSync15(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
31129
31707
  }
31130
31708
  async function countSessions(name, baseDir) {
31131
31709
  const sessionsPath = sessionsPathFor(name, baseDir);
31132
31710
  try {
31133
- const entries = await fs14.readdir(sessionsPath);
31711
+ const entries = await fs16.readdir(sessionsPath);
31134
31712
  return entries.filter((e) => e.endsWith(".jsonl")).length;
31135
31713
  } catch (err) {
31136
31714
  if (err.code === "ENOENT") return 0;
@@ -31175,15 +31753,15 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
31175
31753
  if (branchExists(name, baseDir)) {
31176
31754
  throw new BranchAlreadyExistsError(name);
31177
31755
  }
31178
- const sourcePath = path19.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
31756
+ const sourcePath = path21.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
31179
31757
  if (!existsSync22(sourcePath)) {
31180
31758
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
31181
31759
  }
31182
31760
  const branchPath = branchPathFor(name, baseDir);
31183
31761
  const branchSessionsPath = sessionsPathFor(name, baseDir);
31184
31762
  mkdirSync10(branchSessionsPath, { recursive: true });
31185
- const destPath = path19.join(branchSessionsPath, `${fromSessionId}.jsonl`);
31186
- await fs14.copyFile(sourcePath, destPath);
31763
+ const destPath = path21.join(branchSessionsPath, `${fromSessionId}.jsonl`);
31764
+ await fs16.copyFile(sourcePath, destPath);
31187
31765
  const meta3 = {
31188
31766
  name,
31189
31767
  createdAt: Date.now(),
@@ -31201,7 +31779,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
31201
31779
  async function listBranches(baseDir = getBranchesBaseDir()) {
31202
31780
  let entries;
31203
31781
  try {
31204
- entries = await fs14.readdir(baseDir);
31782
+ entries = await fs16.readdir(baseDir);
31205
31783
  } catch (err) {
31206
31784
  if (err.code === "ENOENT") return [];
31207
31785
  throw err;
@@ -31282,26 +31860,26 @@ async function handleBranchCheckout(ctx, branchName) {
31282
31860
  }
31283
31861
 
31284
31862
  // src/cli/slashHandlers/workspace.ts
31285
- import { promises as fs15 } from "node:fs";
31286
- import path20 from "node:path";
31863
+ import { promises as fs17 } from "node:fs";
31864
+ import path22 from "node:path";
31287
31865
  async function handleWorkspaceShow(ctx, what) {
31288
31866
  try {
31289
- const zelari = path20.join(process.cwd(), ".zelari");
31867
+ const zelari = path22.join(process.cwd(), ".zelari");
31290
31868
  let content;
31291
31869
  switch (what) {
31292
31870
  case "plan": {
31293
- const planPath = path20.join(zelari, "plan.md");
31871
+ const planPath = path22.join(zelari, "plan.md");
31294
31872
  try {
31295
- content = await fs15.readFile(planPath, "utf-8");
31873
+ content = await fs17.readFile(planPath, "utf-8");
31296
31874
  } catch {
31297
31875
  content = "(no plan.md yet \u2014 run a council session first)";
31298
31876
  }
31299
31877
  break;
31300
31878
  }
31301
31879
  case "decisions": {
31302
- const decisionsDir = path20.join(zelari, "decisions");
31880
+ const decisionsDir = path22.join(zelari, "decisions");
31303
31881
  try {
31304
- const files = (await fs15.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
31882
+ const files = (await fs17.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
31305
31883
  if (files.length === 0) {
31306
31884
  content = "(no ADRs yet \u2014 invoke /council to generate some)";
31307
31885
  } else {
@@ -31309,7 +31887,7 @@ async function handleWorkspaceShow(ctx, what) {
31309
31887
  `];
31310
31888
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
31311
31889
  for (const f of files) {
31312
- const raw = await fs15.readFile(path20.join(decisionsDir, f), "utf-8");
31890
+ const raw = await fs17.readFile(path22.join(decisionsDir, f), "utf-8");
31313
31891
  const { meta: meta3, body } = parseFrontmatter2(raw);
31314
31892
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
31315
31893
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -31322,27 +31900,27 @@ async function handleWorkspaceShow(ctx, what) {
31322
31900
  break;
31323
31901
  }
31324
31902
  case "risks": {
31325
- const risksPath = path20.join(zelari, "risks.md");
31903
+ const risksPath = path22.join(zelari, "risks.md");
31326
31904
  try {
31327
- content = await fs15.readFile(risksPath, "utf-8");
31905
+ content = await fs17.readFile(risksPath, "utf-8");
31328
31906
  } catch {
31329
31907
  content = "(no risks.md yet)";
31330
31908
  }
31331
31909
  break;
31332
31910
  }
31333
31911
  case "agents": {
31334
- const agentsPath = path20.join(process.cwd(), "AGENTS.MD");
31912
+ const agentsPath = path22.join(process.cwd(), "AGENTS.MD");
31335
31913
  try {
31336
- content = await fs15.readFile(agentsPath, "utf-8");
31914
+ content = await fs17.readFile(agentsPath, "utf-8");
31337
31915
  } catch {
31338
31916
  content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
31339
31917
  }
31340
31918
  break;
31341
31919
  }
31342
31920
  case "docs": {
31343
- const docsDir = path20.join(zelari, "docs");
31921
+ const docsDir = path22.join(zelari, "docs");
31344
31922
  try {
31345
- const files = (await fs15.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
31923
+ const files = (await fs17.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
31346
31924
  content = files.length ? `# Docs (${files.length})
31347
31925
 
31348
31926
  ` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
@@ -31382,8 +31960,8 @@ async function handleWorkspaceReset(ctx, force) {
31382
31960
  return;
31383
31961
  }
31384
31962
  try {
31385
- const target = path20.join(process.cwd(), ".zelari");
31386
- await fs15.rm(target, { recursive: true, force: true });
31963
+ const target = path22.join(process.cwd(), ".zelari");
31964
+ await fs17.rm(target, { recursive: true, force: true });
31387
31965
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
31388
31966
  } catch (err) {
31389
31967
  appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
@@ -31741,16 +32319,16 @@ function handleModelsRefresh(ctx) {
31741
32319
  }
31742
32320
 
31743
32321
  // src/cli/slashHandlers/skills.ts
31744
- import path21 from "node:path";
32322
+ import path23 from "node:path";
31745
32323
  import os10 from "node:os";
31746
32324
 
31747
32325
  // src/cli/skillHistory.ts
31748
- import { promises as fs16, existsSync as existsSync23, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync11 } from "node:fs";
32326
+ import { promises as fs18, existsSync as existsSync23, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync11 } from "node:fs";
31749
32327
  var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
31750
32328
  async function readSkillHistory(file2) {
31751
32329
  let raw = "";
31752
32330
  try {
31753
- raw = await fs16.readFile(file2, "utf-8");
32331
+ raw = await fs18.readFile(file2, "utf-8");
31754
32332
  } catch {
31755
32333
  return [];
31756
32334
  }
@@ -31843,7 +32421,7 @@ async function applySteerInterrupt(options) {
31843
32421
 
31844
32422
  // src/cli/slashHandlers/skills.ts
31845
32423
  async function handleSkillStats(ctx, skillId) {
31846
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path21.join(os10.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
32424
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path23.join(os10.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
31847
32425
  try {
31848
32426
  const records = await readSkillHistory(historyFile);
31849
32427
  const stats = getSkillStats(records, skillId);
@@ -31859,7 +32437,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
31859
32437
  appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
31860
32438
  return;
31861
32439
  }
31862
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path21.join(os10.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
32440
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path23.join(os10.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
31863
32441
  try {
31864
32442
  const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
31865
32443
  appendSystem(ctx.setMessages, formatted);
@@ -31933,6 +32511,7 @@ function useSlashDispatch(params) {
31933
32511
  setQueueCount,
31934
32512
  dispatchPrompt,
31935
32513
  dispatchCouncilPrompt,
32514
+ dispatchZelariPrompt,
31936
32515
  mode = "agent"
31937
32516
  } = params;
31938
32517
  return useCallback3(async (value) => {
@@ -31955,6 +32534,11 @@ function useSlashDispatch(params) {
31955
32534
  if (!result.handled) {
31956
32535
  appendUser(setMessages, value);
31957
32536
  setSessionActive(true);
32537
+ if (mode === "zelari") {
32538
+ setInput("");
32539
+ await dispatchZelariPrompt(value);
32540
+ return;
32541
+ }
31958
32542
  if (mode === "council") {
31959
32543
  setInput("");
31960
32544
  await dispatchCouncilPrompt(value);
@@ -31990,6 +32574,13 @@ function useSlashDispatch(params) {
31990
32574
  await dispatchCouncilPrompt(result.councilInput);
31991
32575
  return;
31992
32576
  }
32577
+ if (result.kind === "zelari" && result.zelariInput) {
32578
+ appendUser(setMessages, `/zelari ${result.zelariInput}`);
32579
+ setSessionActive(true);
32580
+ setInput("");
32581
+ await dispatchZelariPrompt(result.zelariInput);
32582
+ return;
32583
+ }
31993
32584
  if (result.kind === "council_feedback" && result.feedbackMemberId && typeof result.feedbackScore === "number") {
31994
32585
  handleCouncilFeedback(skillCtx, result.feedbackMemberId, result.feedbackScore, result.feedbackNote);
31995
32586
  setInput("");
@@ -32211,6 +32802,7 @@ function useSlashDispatch(params) {
32211
32802
  setQueueCount,
32212
32803
  dispatchPrompt,
32213
32804
  dispatchCouncilPrompt,
32805
+ dispatchZelariPrompt,
32214
32806
  mode,
32215
32807
  params
32216
32808
  ]);
@@ -32339,7 +32931,9 @@ function App() {
32339
32931
  useInput2(
32340
32932
  (_input, key) => {
32341
32933
  if (key.tab && key.shift) {
32342
- setMode((m) => m === "agent" ? "council" : "agent");
32934
+ setMode(
32935
+ (m) => m === "agent" ? "council" : m === "council" ? "zelari" : "agent"
32936
+ );
32343
32937
  }
32344
32938
  },
32345
32939
  { isActive: isRawModeSupported === true }
@@ -32395,6 +32989,7 @@ function App() {
32395
32989
  setQueueCount: chatTurn.setQueueCount,
32396
32990
  dispatchPrompt: chatTurn.dispatchPrompt,
32397
32991
  dispatchCouncilPrompt: chatTurn.dispatchCouncilPrompt,
32992
+ dispatchZelariPrompt: chatTurn.dispatchZelariPrompt,
32398
32993
  mode,
32399
32994
  openPicker: setPicker,
32400
32995
  onNewSession,
@@ -33122,7 +33717,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
33122
33717
  // src/cli/skillsMd.ts
33123
33718
  init_skills2();
33124
33719
  import { existsSync as existsSync25, readdirSync as readdirSync4, readFileSync as readFileSync22 } from "node:fs";
33125
- import { join as join21 } from "node:path";
33720
+ import { join as join23 } from "node:path";
33126
33721
  import { homedir as homedir5 } from "node:os";
33127
33722
  var CODING_CATEGORIES = /* @__PURE__ */ new Set([
33128
33723
  "plan",
@@ -33138,10 +33733,10 @@ var CODING_CATEGORIES = /* @__PURE__ */ new Set([
33138
33733
  ]);
33139
33734
  function skillMdSearchDirs(projectRoot = process.cwd()) {
33140
33735
  return [
33141
- join21(projectRoot, ".zelari", "skills"),
33142
- join21(projectRoot, ".claude", "skills"),
33143
- join21(projectRoot, ".opencode", "skills"),
33144
- join21(homedir5(), ".zelari-code", "skills")
33736
+ join23(projectRoot, ".zelari", "skills"),
33737
+ join23(projectRoot, ".claude", "skills"),
33738
+ join23(projectRoot, ".opencode", "skills"),
33739
+ join23(homedir5(), ".zelari-code", "skills")
33145
33740
  ];
33146
33741
  }
33147
33742
  function parseSkillMd(content, sourcePath) {
@@ -33207,7 +33802,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
33207
33802
  continue;
33208
33803
  }
33209
33804
  for (const entry of entries) {
33210
- const skillPath = join21(dir, entry, "SKILL.md");
33805
+ const skillPath = join23(dir, entry, "SKILL.md");
33211
33806
  if (!existsSync25(skillPath)) continue;
33212
33807
  try {
33213
33808
  const parsed = parseSkillMd(readFileSync22(skillPath, "utf8"), skillPath);
@@ -33232,7 +33827,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
33232
33827
 
33233
33828
  // src/cli/main.ts
33234
33829
  init_skills2();
33235
- var VERSION = "0.7.12";
33830
+ var VERSION = "1.0.0";
33236
33831
  async function backgroundUpdateCheck() {
33237
33832
  if (process.env.ANATHEMA_DEV === "1") return;
33238
33833
  await new Promise((resolve) => setTimeout(resolve, 3e3));