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.
- package/README.md +9 -2
- package/dist/cli/app.js +4 -3
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/components/StatusBar.js +1 -1
- package/dist/cli/components/StatusBar.js.map +1 -1
- package/dist/cli/councilDispatcher.js +1 -0
- package/dist/cli/councilDispatcher.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +136 -13
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useSlashDispatch.js +15 -2
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/main.bundled.js +688 -122
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +1 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/memory/fileBackend.js +140 -0
- package/dist/cli/memory/fileBackend.js.map +1 -0
- package/dist/cli/slashCommands.js +12 -1
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/zelariMission.js +136 -0
- package/dist/cli/zelariMission.js.map +1 -0
- package/package.json +4 -4
package/dist/cli/main.bundled.js
CHANGED
|
@@ -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,
|
|
1526
|
-
if (!
|
|
1525
|
+
function getElementAtPath(obj, path24) {
|
|
1526
|
+
if (!path24)
|
|
1527
1527
|
return obj;
|
|
1528
|
-
return
|
|
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(
|
|
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(
|
|
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,
|
|
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 }, [...
|
|
2081
|
+
issue2.errors.map((issues) => processError({ issues }, [...path24, ...issue2.path]));
|
|
2082
2082
|
} else if (issue2.code === "invalid_key") {
|
|
2083
|
-
processError({ issues: issue2.issues }, [...
|
|
2083
|
+
processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
|
|
2084
2084
|
} else if (issue2.code === "invalid_element") {
|
|
2085
|
-
processError({ issues: issue2.issues }, [...
|
|
2085
|
+
processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
|
|
2086
2086
|
} else {
|
|
2087
|
-
const fullpath = [...
|
|
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,
|
|
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 }, [...
|
|
2118
|
+
issue2.errors.map((issues) => processError({ issues }, [...path24, ...issue2.path]));
|
|
2119
2119
|
} else if (issue2.code === "invalid_key") {
|
|
2120
|
-
processError({ issues: issue2.issues }, [...
|
|
2120
|
+
processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
|
|
2121
2121
|
} else if (issue2.code === "invalid_element") {
|
|
2122
|
-
processError({ issues: issue2.issues }, [...
|
|
2122
|
+
processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
|
|
2123
2123
|
} else {
|
|
2124
|
-
const fullpath = [...
|
|
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
|
|
2157
|
-
for (const seg of
|
|
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
|
|
15661
|
-
if (
|
|
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 (
|
|
15666
|
-
const key =
|
|
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
|
|
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:
|
|
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 "${
|
|
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
|
|
20216
|
-
if (!existsSync8(
|
|
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(
|
|
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
|
-
|
|
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
|
|
22408
|
+
const path24 = join8(zelariRoot, LESSONS_FILE);
|
|
22275
22409
|
try {
|
|
22276
|
-
const raw = readFileSync11(
|
|
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
|
|
22378
|
-
appendFileSync2(
|
|
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(
|
|
23515
|
-
if (!existsSync13(
|
|
23516
|
-
throw new Error(`File not found: ${
|
|
23652
|
+
read(path24) {
|
|
23653
|
+
if (!existsSync13(path24)) {
|
|
23654
|
+
throw new Error(`File not found: ${path24}`);
|
|
23517
23655
|
}
|
|
23518
|
-
const md = readFileSync13(
|
|
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(
|
|
23523
|
-
if (!existsSync13(
|
|
23524
|
-
return this.read(
|
|
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(
|
|
23531
|
-
mkdirSync7(dirname(
|
|
23532
|
-
const tmp =
|
|
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,
|
|
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
|
|
23614
|
-
const doc = ctx.storage.readIfExists(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
24729
|
-
if (!existsSync17(
|
|
24871
|
+
const path24 = join17(projectRoot, "package.json");
|
|
24872
|
+
if (!existsSync17(path24)) return null;
|
|
24730
24873
|
try {
|
|
24731
|
-
return JSON.parse(await readFile(
|
|
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
|
|
24814
|
-
if (!existsSync17(
|
|
24815
|
-
const content = readFileSync17(
|
|
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
|
|
25379
|
-
completionHook = { ran: true, path:
|
|
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
|
|
25999
|
+
import path19 from "node:path";
|
|
25602
26000
|
import { fileURLToPath } from "node:url";
|
|
25603
26001
|
function getCurrentVersion() {
|
|
25604
26002
|
try {
|
|
25605
|
-
const pkgPath =
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
31059
|
-
import
|
|
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 ??
|
|
31066
|
-
await
|
|
31067
|
-
const filePath =
|
|
31068
|
-
await
|
|
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
|
|
31085
|
-
import
|
|
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 ??
|
|
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 ??
|
|
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
|
|
31645
|
+
return path21.join(baseDir, name);
|
|
31097
31646
|
}
|
|
31098
31647
|
function metaPathFor(name, baseDir) {
|
|
31099
|
-
return
|
|
31648
|
+
return path21.join(baseDir, name, META_FILENAME);
|
|
31100
31649
|
}
|
|
31101
31650
|
function sessionsPathFor(name, baseDir) {
|
|
31102
|
-
return
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
31186
|
-
await
|
|
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
|
|
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
|
|
31286
|
-
import
|
|
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 =
|
|
31838
|
+
const zelari = path22.join(process.cwd(), ".zelari");
|
|
31290
31839
|
let content;
|
|
31291
31840
|
switch (what) {
|
|
31292
31841
|
case "plan": {
|
|
31293
|
-
const planPath =
|
|
31842
|
+
const planPath = path22.join(zelari, "plan.md");
|
|
31294
31843
|
try {
|
|
31295
|
-
content = await
|
|
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 =
|
|
31851
|
+
const decisionsDir = path22.join(zelari, "decisions");
|
|
31303
31852
|
try {
|
|
31304
|
-
const files = (await
|
|
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
|
|
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 =
|
|
31874
|
+
const risksPath = path22.join(zelari, "risks.md");
|
|
31326
31875
|
try {
|
|
31327
|
-
content = await
|
|
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 =
|
|
31883
|
+
const agentsPath = path22.join(process.cwd(), "AGENTS.MD");
|
|
31335
31884
|
try {
|
|
31336
|
-
content = await
|
|
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 =
|
|
31892
|
+
const docsDir = path22.join(zelari, "docs");
|
|
31344
31893
|
try {
|
|
31345
|
-
const files = (await
|
|
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 =
|
|
31386
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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 ??
|
|
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 ??
|
|
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(
|
|
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
|
|
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
|
-
|
|
33142
|
-
|
|
33143
|
-
|
|
33144
|
-
|
|
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 =
|
|
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.
|
|
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));
|