zelari-code 0.7.14 → 1.0.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.
@@ -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,261 @@ 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
+ runZelariMission: () => runZelariMission
25859
+ });
25860
+ import { randomUUID as randomUUID3 } from "node:crypto";
25861
+ import { promises as fs14 } from "node:fs";
25862
+ import * as path17 from "node:path";
25863
+ function resolveMaxIterations(env = process.env) {
25864
+ const raw = env.ZELARI_MISSION_MAX_ITER;
25865
+ const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
25866
+ return Number.isFinite(n) && n > 0 ? n : DEFAULT_MAX_ITER;
25867
+ }
25868
+ function isMissionAutoStart(env = process.env) {
25869
+ return env.ZELARI_MISSION_AUTO === "1";
25870
+ }
25871
+ async function writeMissionState(projectRoot, state2) {
25872
+ const dir = path17.join(projectRoot, ".zelari");
25873
+ await fs14.mkdir(dir, { recursive: true });
25874
+ await fs14.writeFile(
25875
+ path17.join(dir, "mission-state.json"),
25876
+ JSON.stringify(state2, null, 2) + "\n",
25877
+ "utf8"
25878
+ );
25879
+ }
25880
+ function buildSlicePrompt(brief, userMessage, runMode, iteration) {
25881
+ if (runMode === "design-phase") {
25882
+ return `${userMessage}
25883
+
25884
+ [Zelari mission] Produce the design-phase plan for the MVP: ${brief.deliverableThisMission}. Keep the first slice to at most ${brief.sliceMvp.maxTasks ?? 8} tasks.`;
25885
+ }
25886
+ const fix = iteration > 1 ? " Address any remaining verification failures recorded in .zelari/completion.json." : "";
25887
+ return `${userMessage}
25888
+
25889
+ [Zelari mission] Implement the MVP slice: ${brief.deliverableThisMission}.${fix}`;
25890
+ }
25891
+ function formatBriefForChat(brief) {
25892
+ const lines = [
25893
+ "[zelari] Mission brief",
25894
+ ` intent: ${brief.intent}`,
25895
+ ` first run: ${brief.runModeHint}`,
25896
+ ` deliverable: ${brief.deliverableThisMission}`
25897
+ ];
25898
+ if (brief.stackInferred.length) {
25899
+ lines.push(` stack: ${brief.stackInferred.join(", ")}`);
25900
+ }
25901
+ if (brief.assumptions.length) {
25902
+ lines.push(" assumptions:");
25903
+ for (const a of brief.assumptions) lines.push(` - ${a}`);
25904
+ }
25905
+ if (brief.outOfScope.length) {
25906
+ lines.push(" out of scope:");
25907
+ for (const o of brief.outOfScope) lines.push(` - ${o}`);
25908
+ }
25909
+ lines.push(` MVP slice: ${brief.sliceMvp.title} (\u2264 ${brief.sliceMvp.maxTasks} tasks)`);
25910
+ return lines.join("\n");
25911
+ }
25912
+ async function runZelariMission(userMessage, brief, deps) {
25913
+ const now = deps.now ?? (() => /* @__PURE__ */ new Date());
25914
+ const maxIter = deps.maxIterations ?? resolveMaxIterations(deps.env);
25915
+ const missionId = deps.missionId ?? `m_${randomUUID3().slice(0, 8)}`;
25916
+ const startedAt = now().toISOString();
25917
+ const state2 = {
25918
+ missionId,
25919
+ userPrompt: userMessage,
25920
+ brief,
25921
+ iteration: 0,
25922
+ currentSliceId: brief.sliceMvp.id,
25923
+ status: "running",
25924
+ lastCompletionOk: false,
25925
+ startedAt,
25926
+ updatedAt: startedAt
25927
+ };
25928
+ await deps.memory.init(deps.projectRoot);
25929
+ await writeMissionState(deps.projectRoot, state2);
25930
+ const designFirst = brief.phases[0]?.mode === "design-phase";
25931
+ for (let i = 1; i <= maxIter; i++) {
25932
+ state2.iteration = i;
25933
+ const runMode = i === 1 && designFirst ? "design-phase" : "implementation";
25934
+ const hits = await deps.memory.search(`${brief.deliverableThisMission} ${userMessage}`, {
25935
+ limit: 8,
25936
+ metadataFilter: { projectRoot: deps.projectRoot }
25937
+ });
25938
+ const ragContext = formatMemoryHits(hits);
25939
+ const slicePrompt = buildSlicePrompt(brief, userMessage, runMode, i);
25940
+ deps.emit(`[zelari] iterazione ${i}/${maxIter} \xB7 ${runMode} \xB7 slice ${brief.sliceMvp.id}`);
25941
+ let result;
25942
+ try {
25943
+ result = await deps.runSlice({ userMessage: slicePrompt, runMode, ragContext, iteration: i });
25944
+ } catch (err) {
25945
+ state2.status = "error";
25946
+ state2.updatedAt = now().toISOString();
25947
+ await writeMissionState(deps.projectRoot, state2);
25948
+ deps.emit(`[zelari] errore all'iterazione ${i}: ${err instanceof Error ? err.message : String(err)}`);
25949
+ return state2;
25950
+ }
25951
+ await deps.memory.add(
25952
+ JSON.stringify({
25953
+ iteration: i,
25954
+ runMode,
25955
+ completionOk: result.completionOk,
25956
+ synthesis: result.synthesisText?.slice(0, 2e3) ?? ""
25957
+ }),
25958
+ { projectRoot: deps.projectRoot, missionId, sliceId: brief.sliceMvp.id, source: "council", iteration: i }
25959
+ );
25960
+ state2.lastCompletionOk = result.completionOk;
25961
+ state2.updatedAt = now().toISOString();
25962
+ if (result.completionOk && runMode === "implementation") {
25963
+ state2.status = "success";
25964
+ await writeMissionState(deps.projectRoot, state2);
25965
+ deps.emit(`[zelari] \u2713 missione completata \u2014 slice MVP verde all'iterazione ${i}.`);
25966
+ return state2;
25967
+ }
25968
+ await writeMissionState(deps.projectRoot, state2);
25969
+ }
25970
+ state2.status = "stopped";
25971
+ state2.updatedAt = now().toISOString();
25972
+ await writeMissionState(deps.projectRoot, state2);
25973
+ deps.emit(
25974
+ `[zelari] fermata dopo ${maxIter} iterazioni senza completamento verde. Stato salvato in .zelari/mission-state.json`
25975
+ );
25976
+ return state2;
25977
+ }
25978
+ var DEFAULT_MAX_ITER;
25979
+ var init_zelariMission = __esm({
25980
+ "src/cli/zelariMission.ts"() {
25981
+ "use strict";
25982
+ init_fileBackend();
25983
+ DEFAULT_MAX_ITER = 10;
25984
+ }
25985
+ });
25986
+
25589
25987
  // src/cli/updater.ts
25590
25988
  var updater_exports = {};
25591
25989
  __export(updater_exports, {
@@ -25598,11 +25996,11 @@ __export(updater_exports, {
25598
25996
  });
25599
25997
  import { createRequire } from "node:module";
25600
25998
  import { spawn as spawn5 } from "node:child_process";
25601
- import path17 from "node:path";
25999
+ import path19 from "node:path";
25602
26000
  import { fileURLToPath } from "node:url";
25603
26001
  function getCurrentVersion() {
25604
26002
  try {
25605
- const pkgPath = path17.resolve(__dirname2, "..", "..", "package.json");
26003
+ const pkgPath = path19.resolve(__dirname2, "..", "..", "package.json");
25606
26004
  const pkg = require2(pkgPath);
25607
26005
  return pkg.version;
25608
26006
  } catch {
@@ -25700,7 +26098,7 @@ var init_updater = __esm({
25700
26098
  "use strict";
25701
26099
  init_cmdline();
25702
26100
  require2 = createRequire(import.meta.url);
25703
- __dirname2 = path17.dirname(fileURLToPath(import.meta.url));
26101
+ __dirname2 = path19.dirname(fileURLToPath(import.meta.url));
25704
26102
  REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
25705
26103
  }
25706
26104
  });
@@ -26144,7 +26542,14 @@ function StatusBar({
26144
26542
  elapsedMs = null,
26145
26543
  lastMs = null
26146
26544
  }) {
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))));
26545
+ 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(
26546
+ Text6,
26547
+ {
26548
+ bold: true,
26549
+ color: mode === "council" ? "magenta" : mode === "zelari" ? "green" : "cyan"
26550
+ },
26551
+ mode === "council" ? "\u26EC council" : mode === "zelari" ? "\u26A1 zelari" : "\u23F5 agent"
26552
+ ), /* @__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
26553
  }
26149
26554
 
26150
26555
  // src/cli/components/SelectList.tsx
@@ -30026,15 +30431,47 @@ function useChatTurn(params) {
30026
30431
  liveRef
30027
30432
  ]
30028
30433
  );
30434
+ const pendingZelariRef = useRef4(null);
30435
+ const dispatchZelariPrompt = useCallback2(
30436
+ async (text) => {
30437
+ await dispatchZelariPromptImpl(
30438
+ text,
30439
+ {
30440
+ sessionId,
30441
+ writerRef,
30442
+ setMessages,
30443
+ commitStreaming,
30444
+ flushStreaming,
30445
+ setBusy,
30446
+ setQueueCount,
30447
+ setLive,
30448
+ liveRef
30449
+ },
30450
+ pendingZelariRef
30451
+ );
30452
+ },
30453
+ [
30454
+ sessionId,
30455
+ writerRef,
30456
+ setMessages,
30457
+ commitStreaming,
30458
+ flushStreaming,
30459
+ setBusy,
30460
+ setQueueCount,
30461
+ setLive,
30462
+ liveRef
30463
+ ]
30464
+ );
30029
30465
  return {
30030
30466
  dispatchPrompt,
30031
30467
  dispatchCouncilPrompt,
30468
+ dispatchZelariPrompt,
30032
30469
  harnessRef,
30033
30470
  queueCount,
30034
30471
  setQueueCount
30035
30472
  };
30036
30473
  }
30037
- async function dispatchCouncilPromptImpl(text, deps) {
30474
+ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
30038
30475
  const {
30039
30476
  sessionId,
30040
30477
  writerRef,
@@ -30054,7 +30491,7 @@ async function dispatchCouncilPromptImpl(text, deps) {
30054
30491
  setMessages,
30055
30492
  `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
30493
  );
30057
- return;
30494
+ return { completionOk: false, ran: false };
30058
30495
  }
30059
30496
  setBusy(true);
30060
30497
  const { dispatchCouncil: dispatchCouncil2 } = await Promise.resolve().then(() => (init_councilDispatcher(), councilDispatcher_exports));
@@ -30096,6 +30533,8 @@ async function dispatchCouncilPromptImpl(text, deps) {
30096
30533
  let chairmanErrored = false;
30097
30534
  let luciferWriteCount = 0;
30098
30535
  let councilRunMode = "implementation";
30536
+ let sliceCompletionOk = false;
30537
+ let sliceRan = false;
30099
30538
  const PROVIDER_ERROR_ABORT_THRESHOLD = 2;
30100
30539
  try {
30101
30540
  for await (const event of dispatchCouncil2(text, {
@@ -30118,6 +30557,11 @@ async function dispatchCouncilPromptImpl(text, deps) {
30118
30557
  buildLessonsSummary2(process.cwd(), text)
30119
30558
  ].filter(Boolean).join("\n\n"),
30120
30559
  maxToolCallsPerTurn: councilMaxToolCalls,
30560
+ // v1.0: Zelari-mode per-slice overrides (memory RAG, forced run mode,
30561
+ // raised chairman budget). No-ops for a normal /council run.
30562
+ ...overrides.ragContext ? { ragContext: overrides.ragContext } : {},
30563
+ ...overrides.runMode ? { runMode: overrides.runMode } : {},
30564
+ ...overrides.maxToolCallsChairman ? { maxToolCallsChairman: overrides.maxToolCallsChairman } : {},
30121
30565
  onCouncilStatus: (message) => {
30122
30566
  appendSystem(setMessages, message, Date.now());
30123
30567
  }
@@ -30272,6 +30716,7 @@ async function dispatchCouncilPromptImpl(text, deps) {
30272
30716
  if (useLiveModel) finalizeStreaming(setMessages, setLive);
30273
30717
  else finalizeStreamingAssistant(setMessages);
30274
30718
  const hookShouldRun = membersCompleted > 0 || chairmanProducedOutput;
30719
+ sliceRan = hookShouldRun;
30275
30720
  if (hookShouldRun) {
30276
30721
  try {
30277
30722
  const { detectDegradedRun: detectDegradedRun2 } = await Promise.resolve().then(() => (init_council(), council_exports));
@@ -30296,6 +30741,7 @@ async function dispatchCouncilPromptImpl(text, deps) {
30296
30741
  degradedRun: degraded.degraded,
30297
30742
  degradedReasons: degraded.reasons
30298
30743
  });
30744
+ sliceCompletionOk = hook.completion?.completion?.ok ?? false;
30299
30745
  if (hook.ran && hook.changed) {
30300
30746
  appendSystem(
30301
30747
  setMessages,
@@ -30389,6 +30835,97 @@ ${lines}${fails.length > 8 ? "\n \xB7 \u2026" : ""}`,
30389
30835
  }
30390
30836
  setBusy(false);
30391
30837
  }
30838
+ return {
30839
+ completionOk: sliceCompletionOk,
30840
+ ran: sliceRan,
30841
+ synthesisText: chairmanSynthesisText || void 0
30842
+ };
30843
+ }
30844
+ async function dispatchZelariPromptImpl(text, deps, pendingRef) {
30845
+ const { setMessages } = deps;
30846
+ const emit = (m) => appendSystem(setMessages, m, Date.now());
30847
+ if (pendingRef.current) {
30848
+ const pending = pendingRef.current;
30849
+ pendingRef.current = null;
30850
+ const affirmative = /^(ok|okay|s[iì]|yes|y|procedi|vai|conferma|go)\b/i.test(
30851
+ text.trim()
30852
+ );
30853
+ if (!affirmative) {
30854
+ emit("[zelari] missione annullata.");
30855
+ return;
30856
+ }
30857
+ await runZelariMissionInTui(pending.userMessage, deps, emit);
30858
+ return;
30859
+ }
30860
+ const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
30861
+ const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
30862
+ const { formatBriefForChat: formatBriefForChat2, isMissionAutoStart: isMissionAutoStart2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
30863
+ const projectRoot = process.cwd();
30864
+ const brief = buildMissionBrief2({
30865
+ userMessage: text,
30866
+ hasPlan: hasWorkspacePlan2(projectRoot)
30867
+ });
30868
+ emit(formatBriefForChat2(brief));
30869
+ if (isMissionAutoStart2()) {
30870
+ await runZelariMissionInTui(text, deps, emit);
30871
+ return;
30872
+ }
30873
+ pendingRef.current = { userMessage: text };
30874
+ emit(
30875
+ "[zelari] Confermi l'avvio della missione? invia 'ok' per procedere, qualsiasi altra cosa per annullare."
30876
+ );
30877
+ }
30878
+ async function runZelariMissionInTui(userMessage, deps, emit) {
30879
+ const { setMessages } = deps;
30880
+ const envConfig = await providerFromEnv();
30881
+ if (!envConfig) {
30882
+ const active = resolveActiveProvider();
30883
+ const spec = PROVIDERS.find((p3) => p3.id === active);
30884
+ emit(
30885
+ `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.`
30886
+ );
30887
+ return;
30888
+ }
30889
+ const projectRoot = process.cwd();
30890
+ const { buildMissionBrief: buildMissionBrief2 } = await Promise.resolve().then(() => (init_council(), council_exports));
30891
+ const { hasWorkspacePlan: hasWorkspacePlan2 } = await Promise.resolve().then(() => (init_planDetect(), planDetect_exports));
30892
+ const { getMemoryBackend: getMemoryBackend2 } = await Promise.resolve().then(() => (init_fileBackend(), fileBackend_exports));
30893
+ const { runZelariMission: runZelariMission2 } = await Promise.resolve().then(() => (init_zelariMission(), zelariMission_exports));
30894
+ const brief = buildMissionBrief2({
30895
+ userMessage,
30896
+ hasPlan: hasWorkspacePlan2(projectRoot)
30897
+ });
30898
+ const memory = await getMemoryBackend2(projectRoot);
30899
+ const chairmanBudget = (() => {
30900
+ const raw = process.env.ZELARI_MODE_MAX_TOOLS_LUCIFER;
30901
+ const n = raw ? Number.parseInt(raw, 10) : 30;
30902
+ return Number.isFinite(n) && n > 0 ? n : 30;
30903
+ })();
30904
+ try {
30905
+ await runZelariMission2(userMessage, brief, {
30906
+ projectRoot,
30907
+ memory,
30908
+ emit,
30909
+ runSlice: async ({ userMessage: slicePrompt, runMode, ragContext }) => {
30910
+ const r = await dispatchCouncilPromptImpl(slicePrompt, deps, {
30911
+ ragContext,
30912
+ runMode,
30913
+ maxToolCallsChairman: chairmanBudget
30914
+ });
30915
+ return {
30916
+ completionOk: r.completionOk,
30917
+ ran: r.ran,
30918
+ synthesisText: r.synthesisText
30919
+ };
30920
+ }
30921
+ });
30922
+ } catch (err) {
30923
+ emit(
30924
+ `[zelari] errore missione: ${err instanceof Error ? err.message : String(err)}`
30925
+ );
30926
+ } finally {
30927
+ await memory.close();
30928
+ }
30392
30929
  }
30393
30930
 
30394
30931
  // src/cli/hooks/useSlashDispatch.ts
@@ -30464,6 +31001,7 @@ function handleSlashCommand(text, availableSkills) {
30464
31001
  /skill <name> [input] \u2014 invoke a skill (autocomplete with /skill <TAB>)
30465
31002
  /skill-stats [name] \u2014 show invocation stats (success rate, avg duration, total tokens)
30466
31003
  /council <input> \u2014 invoke the multi-agent council on input
31004
+ /zelari <input> \u2014 run an autonomous mission (multi-run council until the MVP slice is complete)
30467
31005
  /council-feedback <memberId> <1-5> [note] \u2014 rate a council member for future ranking (Task I.2)
30468
31006
  /promote-member <memberId> \u2014 promote a council member to a standalone skill (v3-K)
30469
31007
  /update [--yes|-y] \u2014 check for zelari-code updates; --yes performs the update (v3-N)
@@ -30659,6 +31197,17 @@ ${formatSkillList(availableSkills)}`
30659
31197
  }
30660
31198
  return { handled: true, kind: "council", councilInput: input };
30661
31199
  }
31200
+ case "zelari": {
31201
+ const input = args.join(" ").trim();
31202
+ if (!input) {
31203
+ return {
31204
+ handled: true,
31205
+ kind: "zelari",
31206
+ message: "Usage: /zelari <prompt> \u2014 runs an autonomous Zelari mission (multi-run council until the MVP slice is complete)"
31207
+ };
31208
+ }
31209
+ return { handled: true, kind: "zelari", zelariInput: input };
31210
+ }
30662
31211
  case "council-feedback": {
30663
31212
  const memberId = args[0];
30664
31213
  const scoreStr = args[1];
@@ -30870,7 +31419,7 @@ ${formatSkillList(availableSkills)}`
30870
31419
  // src/cli/gitOps.ts
30871
31420
  import { execFile as execFile2 } from "node:child_process";
30872
31421
  import { promisify } from "node:util";
30873
- import path16 from "node:path";
31422
+ import path18 from "node:path";
30874
31423
  var execFileAsync = promisify(execFile2);
30875
31424
  async function git(cwd, args) {
30876
31425
  try {
@@ -30916,7 +31465,7 @@ async function undoWorkingChanges(opts = {}) {
30916
31465
  };
30917
31466
  }
30918
31467
  function defaultProjectRoot() {
30919
- return path16.resolve(__dirname, "..", "..", "..");
31468
+ return path18.resolve(__dirname, "..", "..", "..");
30920
31469
  }
30921
31470
 
30922
31471
  // src/cli/slashHandlers/git.ts
@@ -31055,17 +31604,17 @@ ${res.output || "(empty)"}`
31055
31604
  }
31056
31605
 
31057
31606
  // src/cli/slashHandlers/promoteMember.ts
31058
- import { promises as fs13 } from "node:fs";
31059
- import path18 from "node:path";
31607
+ import { promises as fs15 } from "node:fs";
31608
+ import path20 from "node:path";
31060
31609
  import os8 from "node:os";
31061
31610
  async function handlePromoteMember(ctx, memberId) {
31062
31611
  try {
31063
31612
  const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
31064
31613
  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");
31614
+ const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path20.join(os8.homedir(), ".tmp", "zelari-code", "skills");
31615
+ await fs15.mkdir(skillDir, { recursive: true });
31616
+ const filePath = path20.join(skillDir, `${skill.id}.md`);
31617
+ await fs15.writeFile(filePath, markdown, "utf8");
31069
31618
  appendSystem(
31070
31619
  ctx.setMessages,
31071
31620
  `[promote-member] ${skill.name} (${memberId}) \u2192 ${filePath}
@@ -31081,25 +31630,25 @@ async function handlePromoteMember(ctx, memberId) {
31081
31630
  }
31082
31631
 
31083
31632
  // 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";
31633
+ import { promises as fs16, existsSync as existsSync22, readFileSync as readFileSync21, writeFileSync as writeFileSync15, mkdirSync as mkdirSync10, statSync as statSync4, rmSync } from "node:fs";
31634
+ import path21 from "node:path";
31086
31635
  import os9 from "node:os";
31087
31636
  var META_FILENAME = "meta.json";
31088
31637
  var SESSIONS_SUBDIR = "sessions";
31089
31638
  function getBranchesBaseDir() {
31090
- return process.env.ANATHEMA_BRANCHES_DIR ?? path19.join(os9.homedir(), ".tmp", "zelari-code", "branches");
31639
+ return process.env.ANATHEMA_BRANCHES_DIR ?? path21.join(os9.homedir(), ".tmp", "zelari-code", "branches");
31091
31640
  }
31092
31641
  function getSessionsBaseDir() {
31093
- return process.env.ANATHEMA_SESSIONS_DIR ?? path19.join(os9.homedir(), ".tmp", "zelari-code", "sessions");
31642
+ return process.env.ANATHEMA_SESSIONS_DIR ?? path21.join(os9.homedir(), ".tmp", "zelari-code", "sessions");
31094
31643
  }
31095
31644
  function branchPathFor(name, baseDir) {
31096
- return path19.join(baseDir, name);
31645
+ return path21.join(baseDir, name);
31097
31646
  }
31098
31647
  function metaPathFor(name, baseDir) {
31099
- return path19.join(baseDir, name, META_FILENAME);
31648
+ return path21.join(baseDir, name, META_FILENAME);
31100
31649
  }
31101
31650
  function sessionsPathFor(name, baseDir) {
31102
- return path19.join(baseDir, name, SESSIONS_SUBDIR);
31651
+ return path21.join(baseDir, name, SESSIONS_SUBDIR);
31103
31652
  }
31104
31653
  function readBranchMeta(name, baseDir) {
31105
31654
  const metaPath = metaPathFor(name, baseDir);
@@ -31124,13 +31673,13 @@ function readBranchMeta(name, baseDir) {
31124
31673
  }
31125
31674
  function writeBranchMeta(name, baseDir, meta3) {
31126
31675
  const metaPath = metaPathFor(name, baseDir);
31127
- mkdirSync10(path19.dirname(metaPath), { recursive: true });
31676
+ mkdirSync10(path21.dirname(metaPath), { recursive: true });
31128
31677
  writeFileSync15(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
31129
31678
  }
31130
31679
  async function countSessions(name, baseDir) {
31131
31680
  const sessionsPath = sessionsPathFor(name, baseDir);
31132
31681
  try {
31133
- const entries = await fs14.readdir(sessionsPath);
31682
+ const entries = await fs16.readdir(sessionsPath);
31134
31683
  return entries.filter((e) => e.endsWith(".jsonl")).length;
31135
31684
  } catch (err) {
31136
31685
  if (err.code === "ENOENT") return 0;
@@ -31175,15 +31724,15 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
31175
31724
  if (branchExists(name, baseDir)) {
31176
31725
  throw new BranchAlreadyExistsError(name);
31177
31726
  }
31178
- const sourcePath = path19.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
31727
+ const sourcePath = path21.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
31179
31728
  if (!existsSync22(sourcePath)) {
31180
31729
  throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
31181
31730
  }
31182
31731
  const branchPath = branchPathFor(name, baseDir);
31183
31732
  const branchSessionsPath = sessionsPathFor(name, baseDir);
31184
31733
  mkdirSync10(branchSessionsPath, { recursive: true });
31185
- const destPath = path19.join(branchSessionsPath, `${fromSessionId}.jsonl`);
31186
- await fs14.copyFile(sourcePath, destPath);
31734
+ const destPath = path21.join(branchSessionsPath, `${fromSessionId}.jsonl`);
31735
+ await fs16.copyFile(sourcePath, destPath);
31187
31736
  const meta3 = {
31188
31737
  name,
31189
31738
  createdAt: Date.now(),
@@ -31201,7 +31750,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
31201
31750
  async function listBranches(baseDir = getBranchesBaseDir()) {
31202
31751
  let entries;
31203
31752
  try {
31204
- entries = await fs14.readdir(baseDir);
31753
+ entries = await fs16.readdir(baseDir);
31205
31754
  } catch (err) {
31206
31755
  if (err.code === "ENOENT") return [];
31207
31756
  throw err;
@@ -31282,26 +31831,26 @@ async function handleBranchCheckout(ctx, branchName) {
31282
31831
  }
31283
31832
 
31284
31833
  // src/cli/slashHandlers/workspace.ts
31285
- import { promises as fs15 } from "node:fs";
31286
- import path20 from "node:path";
31834
+ import { promises as fs17 } from "node:fs";
31835
+ import path22 from "node:path";
31287
31836
  async function handleWorkspaceShow(ctx, what) {
31288
31837
  try {
31289
- const zelari = path20.join(process.cwd(), ".zelari");
31838
+ const zelari = path22.join(process.cwd(), ".zelari");
31290
31839
  let content;
31291
31840
  switch (what) {
31292
31841
  case "plan": {
31293
- const planPath = path20.join(zelari, "plan.md");
31842
+ const planPath = path22.join(zelari, "plan.md");
31294
31843
  try {
31295
- content = await fs15.readFile(planPath, "utf-8");
31844
+ content = await fs17.readFile(planPath, "utf-8");
31296
31845
  } catch {
31297
31846
  content = "(no plan.md yet \u2014 run a council session first)";
31298
31847
  }
31299
31848
  break;
31300
31849
  }
31301
31850
  case "decisions": {
31302
- const decisionsDir = path20.join(zelari, "decisions");
31851
+ const decisionsDir = path22.join(zelari, "decisions");
31303
31852
  try {
31304
- const files = (await fs15.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
31853
+ const files = (await fs17.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
31305
31854
  if (files.length === 0) {
31306
31855
  content = "(no ADRs yet \u2014 invoke /council to generate some)";
31307
31856
  } else {
@@ -31309,7 +31858,7 @@ async function handleWorkspaceShow(ctx, what) {
31309
31858
  `];
31310
31859
  const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
31311
31860
  for (const f of files) {
31312
- const raw = await fs15.readFile(path20.join(decisionsDir, f), "utf-8");
31861
+ const raw = await fs17.readFile(path22.join(decisionsDir, f), "utf-8");
31313
31862
  const { meta: meta3, body } = parseFrontmatter2(raw);
31314
31863
  const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
31315
31864
  lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
@@ -31322,27 +31871,27 @@ async function handleWorkspaceShow(ctx, what) {
31322
31871
  break;
31323
31872
  }
31324
31873
  case "risks": {
31325
- const risksPath = path20.join(zelari, "risks.md");
31874
+ const risksPath = path22.join(zelari, "risks.md");
31326
31875
  try {
31327
- content = await fs15.readFile(risksPath, "utf-8");
31876
+ content = await fs17.readFile(risksPath, "utf-8");
31328
31877
  } catch {
31329
31878
  content = "(no risks.md yet)";
31330
31879
  }
31331
31880
  break;
31332
31881
  }
31333
31882
  case "agents": {
31334
- const agentsPath = path20.join(process.cwd(), "AGENTS.MD");
31883
+ const agentsPath = path22.join(process.cwd(), "AGENTS.MD");
31335
31884
  try {
31336
- content = await fs15.readFile(agentsPath, "utf-8");
31885
+ content = await fs17.readFile(agentsPath, "utf-8");
31337
31886
  } catch {
31338
31887
  content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
31339
31888
  }
31340
31889
  break;
31341
31890
  }
31342
31891
  case "docs": {
31343
- const docsDir = path20.join(zelari, "docs");
31892
+ const docsDir = path22.join(zelari, "docs");
31344
31893
  try {
31345
- const files = (await fs15.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
31894
+ const files = (await fs17.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
31346
31895
  content = files.length ? `# Docs (${files.length})
31347
31896
 
31348
31897
  ` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
@@ -31382,8 +31931,8 @@ async function handleWorkspaceReset(ctx, force) {
31382
31931
  return;
31383
31932
  }
31384
31933
  try {
31385
- const target = path20.join(process.cwd(), ".zelari");
31386
- await fs15.rm(target, { recursive: true, force: true });
31934
+ const target = path22.join(process.cwd(), ".zelari");
31935
+ await fs17.rm(target, { recursive: true, force: true });
31387
31936
  appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
31388
31937
  } catch (err) {
31389
31938
  appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
@@ -31741,16 +32290,16 @@ function handleModelsRefresh(ctx) {
31741
32290
  }
31742
32291
 
31743
32292
  // src/cli/slashHandlers/skills.ts
31744
- import path21 from "node:path";
32293
+ import path23 from "node:path";
31745
32294
  import os10 from "node:os";
31746
32295
 
31747
32296
  // 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";
32297
+ import { promises as fs18, existsSync as existsSync23, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync11 } from "node:fs";
31749
32298
  var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
31750
32299
  async function readSkillHistory(file2) {
31751
32300
  let raw = "";
31752
32301
  try {
31753
- raw = await fs16.readFile(file2, "utf-8");
32302
+ raw = await fs18.readFile(file2, "utf-8");
31754
32303
  } catch {
31755
32304
  return [];
31756
32305
  }
@@ -31843,7 +32392,7 @@ async function applySteerInterrupt(options) {
31843
32392
 
31844
32393
  // src/cli/slashHandlers/skills.ts
31845
32394
  async function handleSkillStats(ctx, skillId) {
31846
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path21.join(os10.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
32395
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path23.join(os10.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
31847
32396
  try {
31848
32397
  const records = await readSkillHistory(historyFile);
31849
32398
  const stats = getSkillStats(records, skillId);
@@ -31859,7 +32408,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
31859
32408
  appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
31860
32409
  return;
31861
32410
  }
31862
- const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path21.join(os10.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
32411
+ const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path23.join(os10.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
31863
32412
  try {
31864
32413
  const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
31865
32414
  appendSystem(ctx.setMessages, formatted);
@@ -31933,6 +32482,7 @@ function useSlashDispatch(params) {
31933
32482
  setQueueCount,
31934
32483
  dispatchPrompt,
31935
32484
  dispatchCouncilPrompt,
32485
+ dispatchZelariPrompt,
31936
32486
  mode = "agent"
31937
32487
  } = params;
31938
32488
  return useCallback3(async (value) => {
@@ -31955,6 +32505,11 @@ function useSlashDispatch(params) {
31955
32505
  if (!result.handled) {
31956
32506
  appendUser(setMessages, value);
31957
32507
  setSessionActive(true);
32508
+ if (mode === "zelari") {
32509
+ setInput("");
32510
+ await dispatchZelariPrompt(value);
32511
+ return;
32512
+ }
31958
32513
  if (mode === "council") {
31959
32514
  setInput("");
31960
32515
  await dispatchCouncilPrompt(value);
@@ -31990,6 +32545,13 @@ function useSlashDispatch(params) {
31990
32545
  await dispatchCouncilPrompt(result.councilInput);
31991
32546
  return;
31992
32547
  }
32548
+ if (result.kind === "zelari" && result.zelariInput) {
32549
+ appendUser(setMessages, `/zelari ${result.zelariInput}`);
32550
+ setSessionActive(true);
32551
+ setInput("");
32552
+ await dispatchZelariPrompt(result.zelariInput);
32553
+ return;
32554
+ }
31993
32555
  if (result.kind === "council_feedback" && result.feedbackMemberId && typeof result.feedbackScore === "number") {
31994
32556
  handleCouncilFeedback(skillCtx, result.feedbackMemberId, result.feedbackScore, result.feedbackNote);
31995
32557
  setInput("");
@@ -32211,6 +32773,7 @@ function useSlashDispatch(params) {
32211
32773
  setQueueCount,
32212
32774
  dispatchPrompt,
32213
32775
  dispatchCouncilPrompt,
32776
+ dispatchZelariPrompt,
32214
32777
  mode,
32215
32778
  params
32216
32779
  ]);
@@ -32339,7 +32902,9 @@ function App() {
32339
32902
  useInput2(
32340
32903
  (_input, key) => {
32341
32904
  if (key.tab && key.shift) {
32342
- setMode((m) => m === "agent" ? "council" : "agent");
32905
+ setMode(
32906
+ (m) => m === "agent" ? "council" : m === "council" ? "zelari" : "agent"
32907
+ );
32343
32908
  }
32344
32909
  },
32345
32910
  { isActive: isRawModeSupported === true }
@@ -32395,6 +32960,7 @@ function App() {
32395
32960
  setQueueCount: chatTurn.setQueueCount,
32396
32961
  dispatchPrompt: chatTurn.dispatchPrompt,
32397
32962
  dispatchCouncilPrompt: chatTurn.dispatchCouncilPrompt,
32963
+ dispatchZelariPrompt: chatTurn.dispatchZelariPrompt,
32398
32964
  mode,
32399
32965
  openPicker: setPicker,
32400
32966
  onNewSession,
@@ -33122,7 +33688,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
33122
33688
  // src/cli/skillsMd.ts
33123
33689
  init_skills2();
33124
33690
  import { existsSync as existsSync25, readdirSync as readdirSync4, readFileSync as readFileSync22 } from "node:fs";
33125
- import { join as join21 } from "node:path";
33691
+ import { join as join23 } from "node:path";
33126
33692
  import { homedir as homedir5 } from "node:os";
33127
33693
  var CODING_CATEGORIES = /* @__PURE__ */ new Set([
33128
33694
  "plan",
@@ -33138,10 +33704,10 @@ var CODING_CATEGORIES = /* @__PURE__ */ new Set([
33138
33704
  ]);
33139
33705
  function skillMdSearchDirs(projectRoot = process.cwd()) {
33140
33706
  return [
33141
- join21(projectRoot, ".zelari", "skills"),
33142
- join21(projectRoot, ".claude", "skills"),
33143
- join21(projectRoot, ".opencode", "skills"),
33144
- join21(homedir5(), ".zelari-code", "skills")
33707
+ join23(projectRoot, ".zelari", "skills"),
33708
+ join23(projectRoot, ".claude", "skills"),
33709
+ join23(projectRoot, ".opencode", "skills"),
33710
+ join23(homedir5(), ".zelari-code", "skills")
33145
33711
  ];
33146
33712
  }
33147
33713
  function parseSkillMd(content, sourcePath) {
@@ -33207,7 +33773,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
33207
33773
  continue;
33208
33774
  }
33209
33775
  for (const entry of entries) {
33210
- const skillPath = join21(dir, entry, "SKILL.md");
33776
+ const skillPath = join23(dir, entry, "SKILL.md");
33211
33777
  if (!existsSync25(skillPath)) continue;
33212
33778
  try {
33213
33779
  const parsed = parseSkillMd(readFileSync22(skillPath, "utf8"), skillPath);
@@ -33232,7 +33798,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
33232
33798
 
33233
33799
  // src/cli/main.ts
33234
33800
  init_skills2();
33235
- var VERSION = "0.7.12";
33801
+ var VERSION = "1.0.0";
33236
33802
  async function backgroundUpdateCheck() {
33237
33803
  if (process.env.ANATHEMA_DEV === "1") return;
33238
33804
  await new Promise((resolve) => setTimeout(resolve, 3e3));