zelari-code 1.0.0 → 1.0.2
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/dist/cli/hooks/useChatTurn.js +6 -0
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/main.bundled.js +221 -155
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +57 -46
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/mcpClient.js +29 -26
- package/dist/cli/mcp/mcpClient.js.map +1 -1
- package/dist/cli/zelariMission.js +44 -1
- package/dist/cli/zelariMission.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -24469,13 +24469,133 @@ var init_cmdline = __esm({
|
|
|
24469
24469
|
}
|
|
24470
24470
|
});
|
|
24471
24471
|
|
|
24472
|
-
// src/cli/
|
|
24472
|
+
// src/cli/updater.ts
|
|
24473
|
+
var updater_exports = {};
|
|
24474
|
+
__export(updater_exports, {
|
|
24475
|
+
REGISTRY_URL: () => REGISTRY_URL,
|
|
24476
|
+
checkForUpdate: () => checkForUpdate,
|
|
24477
|
+
compareSemver: () => compareSemver,
|
|
24478
|
+
fetchLatestVersion: () => fetchLatestVersion,
|
|
24479
|
+
getCurrentVersion: () => getCurrentVersion,
|
|
24480
|
+
performUpdate: () => performUpdate
|
|
24481
|
+
});
|
|
24482
|
+
import { createRequire } from "node:module";
|
|
24473
24483
|
import { spawn as spawn2 } from "node:child_process";
|
|
24484
|
+
import path15 from "node:path";
|
|
24485
|
+
import { fileURLToPath } from "node:url";
|
|
24486
|
+
function getCurrentVersion() {
|
|
24487
|
+
try {
|
|
24488
|
+
const pkgPath = path15.resolve(__dirname2, "..", "..", "package.json");
|
|
24489
|
+
const pkg = require2(pkgPath);
|
|
24490
|
+
return pkg.version;
|
|
24491
|
+
} catch {
|
|
24492
|
+
return "0.0.0";
|
|
24493
|
+
}
|
|
24494
|
+
}
|
|
24495
|
+
function compareSemver(a, b) {
|
|
24496
|
+
const parse3 = (v) => {
|
|
24497
|
+
const m = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
|
|
24498
|
+
if (!m) return [0, 0, 0, null];
|
|
24499
|
+
return [Number(m[1]), Number(m[2]), Number(m[3]), m[4] ?? null];
|
|
24500
|
+
};
|
|
24501
|
+
const [a1, a2, a3, aPre] = parse3(a);
|
|
24502
|
+
const [b1, b2, b3, bPre] = parse3(b);
|
|
24503
|
+
if (a1 !== b1) return a1 < b1 ? -1 : 1;
|
|
24504
|
+
if (a2 !== b2) return a2 < b2 ? -1 : 1;
|
|
24505
|
+
if (a3 !== b3) return a3 < b3 ? -1 : 1;
|
|
24506
|
+
if (aPre === bPre) return 0;
|
|
24507
|
+
if (aPre === null) return 1;
|
|
24508
|
+
if (bPre === null) return -1;
|
|
24509
|
+
return aPre < bPre ? -1 : 1;
|
|
24510
|
+
}
|
|
24511
|
+
async function fetchLatestVersion(fetcher = fetch, registryUrl = REGISTRY_URL, timeoutMs = 5e3) {
|
|
24512
|
+
try {
|
|
24513
|
+
const controller = new AbortController();
|
|
24514
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
24515
|
+
const response = await fetcher(registryUrl, { signal: controller.signal });
|
|
24516
|
+
clearTimeout(timer);
|
|
24517
|
+
if (!response.ok) {
|
|
24518
|
+
return { error: `Registry responded ${response.status}` };
|
|
24519
|
+
}
|
|
24520
|
+
const data = await response.json();
|
|
24521
|
+
if (!data.version || typeof data.version !== "string") {
|
|
24522
|
+
return { error: "Registry response missing version field" };
|
|
24523
|
+
}
|
|
24524
|
+
return { version: data.version };
|
|
24525
|
+
} catch (err) {
|
|
24526
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
24527
|
+
return { error: message };
|
|
24528
|
+
}
|
|
24529
|
+
}
|
|
24530
|
+
async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
24531
|
+
const currentVersion = getCurrentVersion();
|
|
24532
|
+
const latest = await fetchLatestVersion(fetcher, registryUrl);
|
|
24533
|
+
if ("error" in latest) {
|
|
24534
|
+
return {
|
|
24535
|
+
currentVersion,
|
|
24536
|
+
latestVersion: currentVersion,
|
|
24537
|
+
updateAvailable: false,
|
|
24538
|
+
error: latest.error
|
|
24539
|
+
};
|
|
24540
|
+
}
|
|
24541
|
+
const cmp = compareSemver(currentVersion, latest.version);
|
|
24542
|
+
return {
|
|
24543
|
+
currentVersion,
|
|
24544
|
+
latestVersion: latest.version,
|
|
24545
|
+
updateAvailable: cmp < 0
|
|
24546
|
+
};
|
|
24547
|
+
}
|
|
24548
|
+
async function performUpdate(packageName = "zelari-code", executor = spawn2) {
|
|
24549
|
+
return new Promise((resolve) => {
|
|
24550
|
+
const args = ["install", "-g", `${packageName}@latest`];
|
|
24551
|
+
let stdout = "";
|
|
24552
|
+
let stderr = "";
|
|
24553
|
+
const stdio = ["ignore", "pipe", "pipe"];
|
|
24554
|
+
const child = process.platform === "win32" ? executor(buildCmdLine("npm", args), { stdio, shell: true }) : executor("npm", args, { stdio });
|
|
24555
|
+
child.stdout?.on("data", (chunk) => {
|
|
24556
|
+
stdout += chunk.toString();
|
|
24557
|
+
});
|
|
24558
|
+
child.stderr?.on("data", (chunk) => {
|
|
24559
|
+
stderr += chunk.toString();
|
|
24560
|
+
});
|
|
24561
|
+
child.on("error", (err) => {
|
|
24562
|
+
resolve({
|
|
24563
|
+
ok: false,
|
|
24564
|
+
output: stdout + stderr,
|
|
24565
|
+
error: err.message,
|
|
24566
|
+
exitCode: null
|
|
24567
|
+
});
|
|
24568
|
+
});
|
|
24569
|
+
child.on("close", (code) => {
|
|
24570
|
+
const ok = code === 0;
|
|
24571
|
+
resolve({
|
|
24572
|
+
ok,
|
|
24573
|
+
output: stdout + stderr,
|
|
24574
|
+
error: ok ? void 0 : `npm exited with code ${code}`,
|
|
24575
|
+
exitCode: code
|
|
24576
|
+
});
|
|
24577
|
+
});
|
|
24578
|
+
});
|
|
24579
|
+
}
|
|
24580
|
+
var require2, __dirname2, REGISTRY_URL;
|
|
24581
|
+
var init_updater = __esm({
|
|
24582
|
+
"src/cli/updater.ts"() {
|
|
24583
|
+
"use strict";
|
|
24584
|
+
init_cmdline();
|
|
24585
|
+
require2 = createRequire(import.meta.url);
|
|
24586
|
+
__dirname2 = path15.dirname(fileURLToPath(import.meta.url));
|
|
24587
|
+
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
24588
|
+
}
|
|
24589
|
+
});
|
|
24590
|
+
|
|
24591
|
+
// src/cli/mcp/mcpClient.ts
|
|
24592
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
24474
24593
|
var DEFAULT_REQUEST_TIMEOUT_MS, INIT_TIMEOUT_MS, MCP_PROTOCOL_VERSION, McpClient;
|
|
24475
24594
|
var init_mcpClient = __esm({
|
|
24476
24595
|
"src/cli/mcp/mcpClient.ts"() {
|
|
24477
24596
|
"use strict";
|
|
24478
24597
|
init_cmdline();
|
|
24598
|
+
init_updater();
|
|
24479
24599
|
DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
24480
24600
|
INIT_TIMEOUT_MS = 15e3;
|
|
24481
24601
|
MCP_PROTOCOL_VERSION = "2025-03-26";
|
|
@@ -24497,17 +24617,26 @@ var init_mcpClient = __esm({
|
|
|
24497
24617
|
env: { ...process.env, ...this.config.env ?? {} },
|
|
24498
24618
|
windowsHide: true
|
|
24499
24619
|
};
|
|
24500
|
-
const child = process.platform === "win32" ?
|
|
24620
|
+
const child = process.platform === "win32" ? spawn3(buildCmdLine(this.config.command, this.config.args ?? []), {
|
|
24501
24621
|
...spawnOpts,
|
|
24502
24622
|
shell: true
|
|
24503
|
-
}) :
|
|
24623
|
+
}) : spawn3(this.config.command, this.config.args ?? [], spawnOpts);
|
|
24504
24624
|
this.child = child;
|
|
24505
24625
|
child.stdout.setEncoding("utf8");
|
|
24506
24626
|
child.stdout.on("data", (chunk) => this.onStdout(chunk));
|
|
24507
|
-
child.on(
|
|
24627
|
+
child.on(
|
|
24628
|
+
"error",
|
|
24629
|
+
(err) => this.failAll(
|
|
24630
|
+
new Error(`[mcp:${this.serverName}] spawn failed: ${err.message}`)
|
|
24631
|
+
)
|
|
24632
|
+
);
|
|
24508
24633
|
child.on("exit", (code) => {
|
|
24509
24634
|
if (!this.closed) {
|
|
24510
|
-
this.failAll(
|
|
24635
|
+
this.failAll(
|
|
24636
|
+
new Error(
|
|
24637
|
+
`[mcp:${this.serverName}] server exited (code ${code ?? "null"})`
|
|
24638
|
+
)
|
|
24639
|
+
);
|
|
24511
24640
|
}
|
|
24512
24641
|
});
|
|
24513
24642
|
await this.request(
|
|
@@ -24515,7 +24644,7 @@ var init_mcpClient = __esm({
|
|
|
24515
24644
|
{
|
|
24516
24645
|
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
24517
24646
|
capabilities: {},
|
|
24518
|
-
clientInfo: { name: "zelari-code", version:
|
|
24647
|
+
clientInfo: { name: "zelari-code", version: getCurrentVersion() }
|
|
24519
24648
|
},
|
|
24520
24649
|
INIT_TIMEOUT_MS
|
|
24521
24650
|
);
|
|
@@ -24524,7 +24653,9 @@ var init_mcpClient = __esm({
|
|
|
24524
24653
|
/** Discover the server's tools. */
|
|
24525
24654
|
async listTools() {
|
|
24526
24655
|
const res = await this.request("tools/list", {});
|
|
24527
|
-
return (res.tools ?? []).filter(
|
|
24656
|
+
return (res.tools ?? []).filter(
|
|
24657
|
+
(t) => !!t.name
|
|
24658
|
+
).map((t) => ({
|
|
24528
24659
|
name: t.name,
|
|
24529
24660
|
description: t.description ?? "",
|
|
24530
24661
|
inputSchema: t.inputSchema ?? { type: "object", properties: {} }
|
|
@@ -24535,9 +24666,16 @@ var init_mcpClient = __esm({
|
|
|
24535
24666
|
* items are summarized by type. Throws when the server flags isError.
|
|
24536
24667
|
*/
|
|
24537
24668
|
async callTool(name, args, timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {
|
|
24538
|
-
const res = await this.request(
|
|
24539
|
-
|
|
24540
|
-
|
|
24669
|
+
const res = await this.request(
|
|
24670
|
+
"tools/call",
|
|
24671
|
+
{ name, arguments: args },
|
|
24672
|
+
timeoutMs
|
|
24673
|
+
);
|
|
24674
|
+
const text = (res.content ?? []).map(
|
|
24675
|
+
(c) => c.type === "text" && typeof c.text === "string" ? c.text : `[${c.type ?? "unknown"} content]`
|
|
24676
|
+
).join("\n");
|
|
24677
|
+
if (res.isError)
|
|
24678
|
+
throw new Error(text || `tool "${name}" reported an error`);
|
|
24541
24679
|
return text;
|
|
24542
24680
|
}
|
|
24543
24681
|
/** Terminate the server process and reject all in-flight requests. */
|
|
@@ -24550,13 +24688,18 @@ var init_mcpClient = __esm({
|
|
|
24550
24688
|
// ── JSON-RPC plumbing ────────────────────────────────────────────────
|
|
24551
24689
|
request(method, params, timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {
|
|
24552
24690
|
const child = this.child;
|
|
24553
|
-
if (!child)
|
|
24691
|
+
if (!child)
|
|
24692
|
+
return Promise.reject(new Error(`[mcp:${this.serverName}] not started`));
|
|
24554
24693
|
const id = this.nextId++;
|
|
24555
24694
|
const payload = JSON.stringify({ jsonrpc: "2.0", id, method, params });
|
|
24556
24695
|
return new Promise((resolve, reject) => {
|
|
24557
24696
|
const timer = setTimeout(() => {
|
|
24558
24697
|
this.pending.delete(id);
|
|
24559
|
-
reject(
|
|
24698
|
+
reject(
|
|
24699
|
+
new Error(
|
|
24700
|
+
`[mcp:${this.serverName}] ${method} timed out after ${timeoutMs}ms`
|
|
24701
|
+
)
|
|
24702
|
+
);
|
|
24560
24703
|
}, timeoutMs);
|
|
24561
24704
|
this.pending.set(id, { resolve, reject, timer });
|
|
24562
24705
|
child.stdin.write(payload + "\n", (err) => {
|
|
@@ -24569,7 +24712,9 @@ var init_mcpClient = __esm({
|
|
|
24569
24712
|
});
|
|
24570
24713
|
}
|
|
24571
24714
|
notify(method, params) {
|
|
24572
|
-
this.child?.stdin.write(
|
|
24715
|
+
this.child?.stdin.write(
|
|
24716
|
+
JSON.stringify({ jsonrpc: "2.0", method, params }) + "\n"
|
|
24717
|
+
);
|
|
24573
24718
|
}
|
|
24574
24719
|
onStdout(chunk) {
|
|
24575
24720
|
this.stdoutBuffer += chunk;
|
|
@@ -24590,7 +24735,11 @@ var init_mcpClient = __esm({
|
|
|
24590
24735
|
this.pending.delete(msg.id);
|
|
24591
24736
|
clearTimeout(pending.timer);
|
|
24592
24737
|
if (msg.error) {
|
|
24593
|
-
pending.reject(
|
|
24738
|
+
pending.reject(
|
|
24739
|
+
new Error(
|
|
24740
|
+
`[mcp:${this.serverName}] ${msg.error.message ?? "JSON-RPC error"} (code ${msg.error.code ?? "?"})`
|
|
24741
|
+
)
|
|
24742
|
+
);
|
|
24594
24743
|
} else {
|
|
24595
24744
|
pending.resolve(msg.result);
|
|
24596
24745
|
}
|
|
@@ -25200,7 +25349,7 @@ var init_completeDesign = __esm({
|
|
|
25200
25349
|
});
|
|
25201
25350
|
|
|
25202
25351
|
// src/cli/workspace/projectSmoke.ts
|
|
25203
|
-
import { spawn as
|
|
25352
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
25204
25353
|
import { existsSync as existsSync18, readFileSync as readFileSync18 } from "node:fs";
|
|
25205
25354
|
import { join as join18 } from "node:path";
|
|
25206
25355
|
function pickSmokeScript(scripts) {
|
|
@@ -25231,7 +25380,7 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
|
25231
25380
|
}
|
|
25232
25381
|
return await new Promise((resolveRun) => {
|
|
25233
25382
|
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
25234
|
-
const child =
|
|
25383
|
+
const child = spawn4(npmCmd, ["run", script], {
|
|
25235
25384
|
cwd: projectRoot,
|
|
25236
25385
|
stdio: ["ignore", "pipe", "pipe"],
|
|
25237
25386
|
env: process.env,
|
|
@@ -25303,7 +25452,7 @@ __export(postCouncilHook_exports, {
|
|
|
25303
25452
|
runImplementationVerificationHook: () => runImplementationVerificationHook,
|
|
25304
25453
|
runPostCouncilHook: () => runPostCouncilHook
|
|
25305
25454
|
});
|
|
25306
|
-
import { spawn as
|
|
25455
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
25307
25456
|
import { existsSync as existsSync19, readFileSync as readFileSync19 } from "node:fs";
|
|
25308
25457
|
import { join as join19 } from "node:path";
|
|
25309
25458
|
async function runCompleteDesignPostProcessor(ctx, options) {
|
|
@@ -25352,7 +25501,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
25352
25501
|
}
|
|
25353
25502
|
}
|
|
25354
25503
|
return await new Promise((resolveRun) => {
|
|
25355
|
-
const child =
|
|
25504
|
+
const child = spawn5(process.execPath, [scriptPath], {
|
|
25356
25505
|
cwd: ctx.projectRoot,
|
|
25357
25506
|
stdio: ["ignore", "pipe", "pipe"],
|
|
25358
25507
|
env: process.env
|
|
@@ -25588,7 +25737,7 @@ import {
|
|
|
25588
25737
|
writeFileSync as writeFileSync14,
|
|
25589
25738
|
mkdirSync as mkdirSync9
|
|
25590
25739
|
} from "node:fs";
|
|
25591
|
-
import
|
|
25740
|
+
import path16 from "node:path";
|
|
25592
25741
|
import os7 from "node:os";
|
|
25593
25742
|
var FeedbackStore;
|
|
25594
25743
|
var init_councilFeedback = __esm({
|
|
@@ -25599,7 +25748,7 @@ var init_councilFeedback = __esm({
|
|
|
25599
25748
|
now;
|
|
25600
25749
|
entries = [];
|
|
25601
25750
|
constructor(options = {}) {
|
|
25602
|
-
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ??
|
|
25751
|
+
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path16.join(os7.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
|
|
25603
25752
|
this.now = options.now ?? Date.now;
|
|
25604
25753
|
this.load();
|
|
25605
25754
|
}
|
|
@@ -25705,7 +25854,7 @@ var init_councilFeedback = __esm({
|
|
|
25705
25854
|
}
|
|
25706
25855
|
}
|
|
25707
25856
|
save() {
|
|
25708
|
-
mkdirSync9(
|
|
25857
|
+
mkdirSync9(path16.dirname(this.file), { recursive: true });
|
|
25709
25858
|
writeFileSync14(
|
|
25710
25859
|
this.file,
|
|
25711
25860
|
JSON.stringify({ entries: this.entries }, null, 2),
|
|
@@ -25740,7 +25889,7 @@ __export(fileBackend_exports, {
|
|
|
25740
25889
|
});
|
|
25741
25890
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
25742
25891
|
import { promises as fs13 } from "node:fs";
|
|
25743
|
-
import * as
|
|
25892
|
+
import * as path17 from "node:path";
|
|
25744
25893
|
function tokenize(text) {
|
|
25745
25894
|
return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
|
|
25746
25895
|
}
|
|
@@ -25778,8 +25927,8 @@ var init_fileBackend = __esm({
|
|
|
25778
25927
|
logPath = "";
|
|
25779
25928
|
memoryDir = "";
|
|
25780
25929
|
async init(projectRoot) {
|
|
25781
|
-
this.memoryDir =
|
|
25782
|
-
this.logPath =
|
|
25930
|
+
this.memoryDir = path17.join(projectRoot, ".zelari", "memory");
|
|
25931
|
+
this.logPath = path17.join(this.memoryDir, "log.jsonl");
|
|
25783
25932
|
await fs13.mkdir(this.memoryDir, { recursive: true });
|
|
25784
25933
|
}
|
|
25785
25934
|
async add(content, metadata = {}, graph) {
|
|
@@ -25855,24 +26004,31 @@ __export(zelariMission_exports, {
|
|
|
25855
26004
|
formatBriefForChat: () => formatBriefForChat,
|
|
25856
26005
|
isMissionAutoStart: () => isMissionAutoStart,
|
|
25857
26006
|
resolveMaxIterations: () => resolveMaxIterations,
|
|
26007
|
+
resolveMaxStall: () => resolveMaxStall,
|
|
25858
26008
|
runZelariMission: () => runZelariMission
|
|
25859
26009
|
});
|
|
25860
26010
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
25861
26011
|
import { promises as fs14 } from "node:fs";
|
|
25862
|
-
import * as
|
|
26012
|
+
import * as path18 from "node:path";
|
|
25863
26013
|
function resolveMaxIterations(env = process.env) {
|
|
25864
26014
|
const raw = env.ZELARI_MISSION_MAX_ITER;
|
|
25865
26015
|
const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
|
|
25866
26016
|
return Number.isFinite(n) && n > 0 ? n : DEFAULT_MAX_ITER;
|
|
25867
26017
|
}
|
|
26018
|
+
function resolveMaxStall(env = process.env) {
|
|
26019
|
+
const raw = env.ZELARI_MISSION_MAX_STALL;
|
|
26020
|
+
if (raw === void 0) return DEFAULT_MAX_STALL;
|
|
26021
|
+
const n = Number.parseInt(raw, 10);
|
|
26022
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_MAX_STALL;
|
|
26023
|
+
}
|
|
25868
26024
|
function isMissionAutoStart(env = process.env) {
|
|
25869
26025
|
return env.ZELARI_MISSION_AUTO === "1";
|
|
25870
26026
|
}
|
|
25871
26027
|
async function writeMissionState(projectRoot, state2) {
|
|
25872
|
-
const dir =
|
|
26028
|
+
const dir = path18.join(projectRoot, ".zelari");
|
|
25873
26029
|
await fs14.mkdir(dir, { recursive: true });
|
|
25874
26030
|
await fs14.writeFile(
|
|
25875
|
-
|
|
26031
|
+
path18.join(dir, "mission-state.json"),
|
|
25876
26032
|
JSON.stringify(state2, null, 2) + "\n",
|
|
25877
26033
|
"utf8"
|
|
25878
26034
|
);
|
|
@@ -25886,7 +26042,7 @@ function buildSlicePrompt(brief, userMessage, runMode, iteration) {
|
|
|
25886
26042
|
const fix = iteration > 1 ? " Address any remaining verification failures recorded in .zelari/completion.json." : "";
|
|
25887
26043
|
return `${userMessage}
|
|
25888
26044
|
|
|
25889
|
-
[Zelari mission] Implement the MVP slice: ${brief.deliverableThisMission}.${fix}
|
|
26045
|
+
[Zelari mission] Implement the MVP slice: ${brief.deliverableThisMission}.${fix} You MUST create or modify the real project files with write_file / edit_file \u2014 not just describe them in prose. A run that claims completion without writing any file is a failed run and will not be accepted.`;
|
|
25890
26046
|
}
|
|
25891
26047
|
function formatBriefForChat(brief) {
|
|
25892
26048
|
const lines = [
|
|
@@ -25912,6 +26068,7 @@ function formatBriefForChat(brief) {
|
|
|
25912
26068
|
async function runZelariMission(userMessage, brief, deps) {
|
|
25913
26069
|
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
25914
26070
|
const maxIter = deps.maxIterations ?? resolveMaxIterations(deps.env);
|
|
26071
|
+
const maxStall = resolveMaxStall(deps.env);
|
|
25915
26072
|
const missionId = deps.missionId ?? `m_${randomUUID3().slice(0, 8)}`;
|
|
25916
26073
|
const startedAt = now().toISOString();
|
|
25917
26074
|
const state2 = {
|
|
@@ -25928,6 +26085,7 @@ async function runZelariMission(userMessage, brief, deps) {
|
|
|
25928
26085
|
await deps.memory.init(deps.projectRoot);
|
|
25929
26086
|
await writeMissionState(deps.projectRoot, state2);
|
|
25930
26087
|
const designFirst = brief.phases[0]?.mode === "design-phase";
|
|
26088
|
+
let noWriteStreak = 0;
|
|
25931
26089
|
for (let i = 1; i <= maxIter; i++) {
|
|
25932
26090
|
state2.iteration = i;
|
|
25933
26091
|
const runMode = i === 1 && designFirst ? "design-phase" : "implementation";
|
|
@@ -25965,6 +26123,19 @@ async function runZelariMission(userMessage, brief, deps) {
|
|
|
25965
26123
|
deps.emit(`[zelari] \u2713 missione completata \u2014 slice MVP verde all'iterazione ${i}.`);
|
|
25966
26124
|
return state2;
|
|
25967
26125
|
}
|
|
26126
|
+
if (runMode === "implementation" && typeof result.writeCount === "number") {
|
|
26127
|
+
if (result.writeCount === 0) noWriteStreak++;
|
|
26128
|
+
else noWriteStreak = 0;
|
|
26129
|
+
if (maxStall > 0 && noWriteStreak >= maxStall) {
|
|
26130
|
+
state2.status = "stalled";
|
|
26131
|
+
state2.updatedAt = now().toISOString();
|
|
26132
|
+
await writeMissionState(deps.projectRoot, state2);
|
|
26133
|
+
deps.emit(
|
|
26134
|
+
`[zelari] fermata: ${noWriteStreak} iterazioni di implementation senza scrivere alcun file (il modello dichiara "fatto" ma non produce il deliverable). Prova un modello pi\xF9 capace o verifica provider/chiave. Stato salvato in .zelari/mission-state.json`
|
|
26135
|
+
);
|
|
26136
|
+
return state2;
|
|
26137
|
+
}
|
|
26138
|
+
}
|
|
25968
26139
|
await writeMissionState(deps.projectRoot, state2);
|
|
25969
26140
|
}
|
|
25970
26141
|
state2.status = "stopped";
|
|
@@ -25975,131 +26146,13 @@ async function runZelariMission(userMessage, brief, deps) {
|
|
|
25975
26146
|
);
|
|
25976
26147
|
return state2;
|
|
25977
26148
|
}
|
|
25978
|
-
var DEFAULT_MAX_ITER;
|
|
26149
|
+
var DEFAULT_MAX_ITER, DEFAULT_MAX_STALL;
|
|
25979
26150
|
var init_zelariMission = __esm({
|
|
25980
26151
|
"src/cli/zelariMission.ts"() {
|
|
25981
26152
|
"use strict";
|
|
25982
26153
|
init_fileBackend();
|
|
25983
26154
|
DEFAULT_MAX_ITER = 10;
|
|
25984
|
-
|
|
25985
|
-
});
|
|
25986
|
-
|
|
25987
|
-
// src/cli/updater.ts
|
|
25988
|
-
var updater_exports = {};
|
|
25989
|
-
__export(updater_exports, {
|
|
25990
|
-
REGISTRY_URL: () => REGISTRY_URL,
|
|
25991
|
-
checkForUpdate: () => checkForUpdate,
|
|
25992
|
-
compareSemver: () => compareSemver,
|
|
25993
|
-
fetchLatestVersion: () => fetchLatestVersion,
|
|
25994
|
-
getCurrentVersion: () => getCurrentVersion,
|
|
25995
|
-
performUpdate: () => performUpdate
|
|
25996
|
-
});
|
|
25997
|
-
import { createRequire } from "node:module";
|
|
25998
|
-
import { spawn as spawn5 } from "node:child_process";
|
|
25999
|
-
import path19 from "node:path";
|
|
26000
|
-
import { fileURLToPath } from "node:url";
|
|
26001
|
-
function getCurrentVersion() {
|
|
26002
|
-
try {
|
|
26003
|
-
const pkgPath = path19.resolve(__dirname2, "..", "..", "package.json");
|
|
26004
|
-
const pkg = require2(pkgPath);
|
|
26005
|
-
return pkg.version;
|
|
26006
|
-
} catch {
|
|
26007
|
-
return "0.0.0";
|
|
26008
|
-
}
|
|
26009
|
-
}
|
|
26010
|
-
function compareSemver(a, b) {
|
|
26011
|
-
const parse3 = (v) => {
|
|
26012
|
-
const m = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
|
|
26013
|
-
if (!m) return [0, 0, 0, null];
|
|
26014
|
-
return [Number(m[1]), Number(m[2]), Number(m[3]), m[4] ?? null];
|
|
26015
|
-
};
|
|
26016
|
-
const [a1, a2, a3, aPre] = parse3(a);
|
|
26017
|
-
const [b1, b2, b3, bPre] = parse3(b);
|
|
26018
|
-
if (a1 !== b1) return a1 < b1 ? -1 : 1;
|
|
26019
|
-
if (a2 !== b2) return a2 < b2 ? -1 : 1;
|
|
26020
|
-
if (a3 !== b3) return a3 < b3 ? -1 : 1;
|
|
26021
|
-
if (aPre === bPre) return 0;
|
|
26022
|
-
if (aPre === null) return 1;
|
|
26023
|
-
if (bPre === null) return -1;
|
|
26024
|
-
return aPre < bPre ? -1 : 1;
|
|
26025
|
-
}
|
|
26026
|
-
async function fetchLatestVersion(fetcher = fetch, registryUrl = REGISTRY_URL, timeoutMs = 5e3) {
|
|
26027
|
-
try {
|
|
26028
|
-
const controller = new AbortController();
|
|
26029
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
26030
|
-
const response = await fetcher(registryUrl, { signal: controller.signal });
|
|
26031
|
-
clearTimeout(timer);
|
|
26032
|
-
if (!response.ok) {
|
|
26033
|
-
return { error: `Registry responded ${response.status}` };
|
|
26034
|
-
}
|
|
26035
|
-
const data = await response.json();
|
|
26036
|
-
if (!data.version || typeof data.version !== "string") {
|
|
26037
|
-
return { error: "Registry response missing version field" };
|
|
26038
|
-
}
|
|
26039
|
-
return { version: data.version };
|
|
26040
|
-
} catch (err) {
|
|
26041
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
26042
|
-
return { error: message };
|
|
26043
|
-
}
|
|
26044
|
-
}
|
|
26045
|
-
async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
26046
|
-
const currentVersion = getCurrentVersion();
|
|
26047
|
-
const latest = await fetchLatestVersion(fetcher, registryUrl);
|
|
26048
|
-
if ("error" in latest) {
|
|
26049
|
-
return {
|
|
26050
|
-
currentVersion,
|
|
26051
|
-
latestVersion: currentVersion,
|
|
26052
|
-
updateAvailable: false,
|
|
26053
|
-
error: latest.error
|
|
26054
|
-
};
|
|
26055
|
-
}
|
|
26056
|
-
const cmp = compareSemver(currentVersion, latest.version);
|
|
26057
|
-
return {
|
|
26058
|
-
currentVersion,
|
|
26059
|
-
latestVersion: latest.version,
|
|
26060
|
-
updateAvailable: cmp < 0
|
|
26061
|
-
};
|
|
26062
|
-
}
|
|
26063
|
-
async function performUpdate(packageName = "zelari-code", executor = spawn5) {
|
|
26064
|
-
return new Promise((resolve) => {
|
|
26065
|
-
const args = ["install", "-g", `${packageName}@latest`];
|
|
26066
|
-
let stdout = "";
|
|
26067
|
-
let stderr = "";
|
|
26068
|
-
const stdio = ["ignore", "pipe", "pipe"];
|
|
26069
|
-
const child = process.platform === "win32" ? executor(buildCmdLine("npm", args), { stdio, shell: true }) : executor("npm", args, { stdio });
|
|
26070
|
-
child.stdout?.on("data", (chunk) => {
|
|
26071
|
-
stdout += chunk.toString();
|
|
26072
|
-
});
|
|
26073
|
-
child.stderr?.on("data", (chunk) => {
|
|
26074
|
-
stderr += chunk.toString();
|
|
26075
|
-
});
|
|
26076
|
-
child.on("error", (err) => {
|
|
26077
|
-
resolve({
|
|
26078
|
-
ok: false,
|
|
26079
|
-
output: stdout + stderr,
|
|
26080
|
-
error: err.message,
|
|
26081
|
-
exitCode: null
|
|
26082
|
-
});
|
|
26083
|
-
});
|
|
26084
|
-
child.on("close", (code) => {
|
|
26085
|
-
const ok = code === 0;
|
|
26086
|
-
resolve({
|
|
26087
|
-
ok,
|
|
26088
|
-
output: stdout + stderr,
|
|
26089
|
-
error: ok ? void 0 : `npm exited with code ${code}`,
|
|
26090
|
-
exitCode: code
|
|
26091
|
-
});
|
|
26092
|
-
});
|
|
26093
|
-
});
|
|
26094
|
-
}
|
|
26095
|
-
var require2, __dirname2, REGISTRY_URL;
|
|
26096
|
-
var init_updater = __esm({
|
|
26097
|
-
"src/cli/updater.ts"() {
|
|
26098
|
-
"use strict";
|
|
26099
|
-
init_cmdline();
|
|
26100
|
-
require2 = createRequire(import.meta.url);
|
|
26101
|
-
__dirname2 = path19.dirname(fileURLToPath(import.meta.url));
|
|
26102
|
-
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
26155
|
+
DEFAULT_MAX_STALL = 2;
|
|
26103
26156
|
}
|
|
26104
26157
|
});
|
|
26105
26158
|
|
|
@@ -30535,6 +30588,7 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
30535
30588
|
let councilRunMode = "implementation";
|
|
30536
30589
|
let sliceCompletionOk = false;
|
|
30537
30590
|
let sliceRan = false;
|
|
30591
|
+
let sliceDegraded = false;
|
|
30538
30592
|
const PROVIDER_ERROR_ABORT_THRESHOLD = 2;
|
|
30539
30593
|
try {
|
|
30540
30594
|
for await (const event of dispatchCouncil2(text, {
|
|
@@ -30727,6 +30781,7 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
30727
30781
|
synthesisText: chairmanSynthesisText,
|
|
30728
30782
|
runMode: councilRunMode
|
|
30729
30783
|
});
|
|
30784
|
+
sliceDegraded = degraded.degraded;
|
|
30730
30785
|
if (degraded.degraded) {
|
|
30731
30786
|
appendSystem(
|
|
30732
30787
|
setMessages,
|
|
@@ -30838,7 +30893,9 @@ ${lines}${fails.length > 8 ? "\n \xB7 \u2026" : ""}`,
|
|
|
30838
30893
|
return {
|
|
30839
30894
|
completionOk: sliceCompletionOk,
|
|
30840
30895
|
ran: sliceRan,
|
|
30841
|
-
synthesisText: chairmanSynthesisText || void 0
|
|
30896
|
+
synthesisText: chairmanSynthesisText || void 0,
|
|
30897
|
+
writeCount: luciferWriteCount,
|
|
30898
|
+
degraded: sliceDegraded
|
|
30842
30899
|
};
|
|
30843
30900
|
}
|
|
30844
30901
|
async function dispatchZelariPromptImpl(text, deps, pendingRef) {
|
|
@@ -30915,7 +30972,9 @@ async function runZelariMissionInTui(userMessage, deps, emit) {
|
|
|
30915
30972
|
return {
|
|
30916
30973
|
completionOk: r.completionOk,
|
|
30917
30974
|
ran: r.ran,
|
|
30918
|
-
synthesisText: r.synthesisText
|
|
30975
|
+
synthesisText: r.synthesisText,
|
|
30976
|
+
writeCount: r.writeCount,
|
|
30977
|
+
degraded: r.degraded
|
|
30919
30978
|
};
|
|
30920
30979
|
}
|
|
30921
30980
|
});
|
|
@@ -31419,7 +31478,7 @@ ${formatSkillList(availableSkills)}`
|
|
|
31419
31478
|
// src/cli/gitOps.ts
|
|
31420
31479
|
import { execFile as execFile2 } from "node:child_process";
|
|
31421
31480
|
import { promisify } from "node:util";
|
|
31422
|
-
import
|
|
31481
|
+
import path19 from "node:path";
|
|
31423
31482
|
var execFileAsync = promisify(execFile2);
|
|
31424
31483
|
async function git(cwd, args) {
|
|
31425
31484
|
try {
|
|
@@ -31465,7 +31524,7 @@ async function undoWorkingChanges(opts = {}) {
|
|
|
31465
31524
|
};
|
|
31466
31525
|
}
|
|
31467
31526
|
function defaultProjectRoot() {
|
|
31468
|
-
return
|
|
31527
|
+
return path19.resolve(__dirname, "..", "..", "..");
|
|
31469
31528
|
}
|
|
31470
31529
|
|
|
31471
31530
|
// src/cli/slashHandlers/git.ts
|
|
@@ -33798,7 +33857,8 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
33798
33857
|
|
|
33799
33858
|
// src/cli/main.ts
|
|
33800
33859
|
init_skills2();
|
|
33801
|
-
|
|
33860
|
+
init_updater();
|
|
33861
|
+
var VERSION = getCurrentVersion();
|
|
33802
33862
|
async function backgroundUpdateCheck() {
|
|
33803
33863
|
if (process.env.ANATHEMA_DEV === "1") return;
|
|
33804
33864
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
@@ -33858,7 +33918,11 @@ function pickRootComponent() {
|
|
|
33858
33918
|
}
|
|
33859
33919
|
return {
|
|
33860
33920
|
kind: "app",
|
|
33861
|
-
element: React13.createElement(
|
|
33921
|
+
element: React13.createElement(
|
|
33922
|
+
SplashGate,
|
|
33923
|
+
{ version: VERSION },
|
|
33924
|
+
React13.createElement(App)
|
|
33925
|
+
)
|
|
33862
33926
|
};
|
|
33863
33927
|
}
|
|
33864
33928
|
function loadUserSkills() {
|
|
@@ -33866,7 +33930,9 @@ function loadUserSkills() {
|
|
|
33866
33930
|
const existing = new Set(listCodingSkills().map((s) => s.id));
|
|
33867
33931
|
const summary = loadSkillMdSkills(process.cwd(), { existingIds: existing });
|
|
33868
33932
|
if (summary.loaded.length > 0) {
|
|
33869
|
-
console.error(
|
|
33933
|
+
console.error(
|
|
33934
|
+
`[zelari-code] loaded ${summary.loaded.length} SKILL.md skill(s): ${summary.loaded.join(", ")}`
|
|
33935
|
+
);
|
|
33870
33936
|
}
|
|
33871
33937
|
for (const s of summary.skipped) {
|
|
33872
33938
|
console.error(`[zelari-code] skipped SKILL.md at ${s.path}: ${s.reason}`);
|