zelari-code 1.14.3 → 1.15.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/dist/cli/app.js +1 -0
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/main.bundled.js +591 -196
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/mcp/mcpManager.js +16 -5
- package/dist/cli/mcp/mcpManager.js.map +1 -1
- package/dist/cli/toolRegistry.js +14 -0
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/workspace/worldModel.js +331 -0
- package/dist/cli/workspace/worldModel.js.map +1 -0
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -308,7 +308,7 @@ async function refreshGrokToken(options) {
|
|
|
308
308
|
return parseTokenResponseBody(obj, accessToken);
|
|
309
309
|
}
|
|
310
310
|
async function openBrowser(url2) {
|
|
311
|
-
const { spawn:
|
|
311
|
+
const { spawn: spawn11 } = await import("node:child_process");
|
|
312
312
|
const cmd = (() => {
|
|
313
313
|
switch (process.platform) {
|
|
314
314
|
case "darwin":
|
|
@@ -321,7 +321,7 @@ async function openBrowser(url2) {
|
|
|
321
321
|
})();
|
|
322
322
|
return new Promise((resolve, reject) => {
|
|
323
323
|
try {
|
|
324
|
-
const child =
|
|
324
|
+
const child = spawn11(cmd.bin, cmd.args, {
|
|
325
325
|
stdio: "ignore",
|
|
326
326
|
detached: true
|
|
327
327
|
});
|
|
@@ -1543,10 +1543,10 @@ function mergeDefs(...defs) {
|
|
|
1543
1543
|
function cloneDef(schema) {
|
|
1544
1544
|
return mergeDefs(schema._zod.def);
|
|
1545
1545
|
}
|
|
1546
|
-
function getElementAtPath(obj,
|
|
1547
|
-
if (!
|
|
1546
|
+
function getElementAtPath(obj, path37) {
|
|
1547
|
+
if (!path37)
|
|
1548
1548
|
return obj;
|
|
1549
|
-
return
|
|
1549
|
+
return path37.reduce((acc, key) => acc?.[key], obj);
|
|
1550
1550
|
}
|
|
1551
1551
|
function promiseAllObject(promisesObj) {
|
|
1552
1552
|
const keys = Object.keys(promisesObj);
|
|
@@ -1874,11 +1874,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
1874
1874
|
}
|
|
1875
1875
|
return false;
|
|
1876
1876
|
}
|
|
1877
|
-
function prefixIssues(
|
|
1877
|
+
function prefixIssues(path37, issues) {
|
|
1878
1878
|
return issues.map((iss) => {
|
|
1879
1879
|
var _a3;
|
|
1880
1880
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
1881
|
-
iss.path.unshift(
|
|
1881
|
+
iss.path.unshift(path37);
|
|
1882
1882
|
return iss;
|
|
1883
1883
|
});
|
|
1884
1884
|
}
|
|
@@ -2096,16 +2096,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2096
2096
|
}
|
|
2097
2097
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
2098
2098
|
const fieldErrors = { _errors: [] };
|
|
2099
|
-
const processError = (error52,
|
|
2099
|
+
const processError = (error52, path37 = []) => {
|
|
2100
2100
|
for (const issue2 of error52.issues) {
|
|
2101
2101
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2102
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2102
|
+
issue2.errors.map((issues) => processError({ issues }, [...path37, ...issue2.path]));
|
|
2103
2103
|
} else if (issue2.code === "invalid_key") {
|
|
2104
|
-
processError({ issues: issue2.issues }, [...
|
|
2104
|
+
processError({ issues: issue2.issues }, [...path37, ...issue2.path]);
|
|
2105
2105
|
} else if (issue2.code === "invalid_element") {
|
|
2106
|
-
processError({ issues: issue2.issues }, [...
|
|
2106
|
+
processError({ issues: issue2.issues }, [...path37, ...issue2.path]);
|
|
2107
2107
|
} else {
|
|
2108
|
-
const fullpath = [...
|
|
2108
|
+
const fullpath = [...path37, ...issue2.path];
|
|
2109
2109
|
if (fullpath.length === 0) {
|
|
2110
2110
|
fieldErrors._errors.push(mapper(issue2));
|
|
2111
2111
|
} else {
|
|
@@ -2132,17 +2132,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2132
2132
|
}
|
|
2133
2133
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
2134
2134
|
const result = { errors: [] };
|
|
2135
|
-
const processError = (error52,
|
|
2135
|
+
const processError = (error52, path37 = []) => {
|
|
2136
2136
|
var _a3, _b;
|
|
2137
2137
|
for (const issue2 of error52.issues) {
|
|
2138
2138
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2139
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2139
|
+
issue2.errors.map((issues) => processError({ issues }, [...path37, ...issue2.path]));
|
|
2140
2140
|
} else if (issue2.code === "invalid_key") {
|
|
2141
|
-
processError({ issues: issue2.issues }, [...
|
|
2141
|
+
processError({ issues: issue2.issues }, [...path37, ...issue2.path]);
|
|
2142
2142
|
} else if (issue2.code === "invalid_element") {
|
|
2143
|
-
processError({ issues: issue2.issues }, [...
|
|
2143
|
+
processError({ issues: issue2.issues }, [...path37, ...issue2.path]);
|
|
2144
2144
|
} else {
|
|
2145
|
-
const fullpath = [...
|
|
2145
|
+
const fullpath = [...path37, ...issue2.path];
|
|
2146
2146
|
if (fullpath.length === 0) {
|
|
2147
2147
|
result.errors.push(mapper(issue2));
|
|
2148
2148
|
continue;
|
|
@@ -2174,8 +2174,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2174
2174
|
}
|
|
2175
2175
|
function toDotPath(_path) {
|
|
2176
2176
|
const segs = [];
|
|
2177
|
-
const
|
|
2178
|
-
for (const seg of
|
|
2177
|
+
const path37 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
2178
|
+
for (const seg of path37) {
|
|
2179
2179
|
if (typeof seg === "number")
|
|
2180
2180
|
segs.push(`[${seg}]`);
|
|
2181
2181
|
else if (typeof seg === "symbol")
|
|
@@ -15678,13 +15678,13 @@ function resolveRef(ref, ctx) {
|
|
|
15678
15678
|
if (!ref.startsWith("#")) {
|
|
15679
15679
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
15680
15680
|
}
|
|
15681
|
-
const
|
|
15682
|
-
if (
|
|
15681
|
+
const path37 = ref.slice(1).split("/").filter(Boolean);
|
|
15682
|
+
if (path37.length === 0) {
|
|
15683
15683
|
return ctx.rootSchema;
|
|
15684
15684
|
}
|
|
15685
15685
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
15686
|
-
if (
|
|
15687
|
-
const key =
|
|
15686
|
+
if (path37[0] === defsKey) {
|
|
15687
|
+
const key = path37[1];
|
|
15688
15688
|
if (!key || !ctx.defs[key]) {
|
|
15689
15689
|
throw new Error(`Reference not found: ${ref}`);
|
|
15690
15690
|
}
|
|
@@ -17784,11 +17784,11 @@ var init_tools = __esm({
|
|
|
17784
17784
|
if (!ctx.addDocument)
|
|
17785
17785
|
return "Knowledge vault tool not available.";
|
|
17786
17786
|
const title = args["title"] || "New Document";
|
|
17787
|
-
const
|
|
17787
|
+
const path37 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
17788
17788
|
const content = args["content"] || "";
|
|
17789
17789
|
const tags = args["tags"] || [];
|
|
17790
17790
|
ctx.addDocument({
|
|
17791
|
-
path:
|
|
17791
|
+
path: path37,
|
|
17792
17792
|
title,
|
|
17793
17793
|
content,
|
|
17794
17794
|
format: "markdown",
|
|
@@ -17797,7 +17797,7 @@ var init_tools = __esm({
|
|
|
17797
17797
|
workspaceId: ctx.workspaceId
|
|
17798
17798
|
});
|
|
17799
17799
|
ctx.addActivity("vault", "created document", title);
|
|
17800
|
-
return `Document "${title}" created at "${
|
|
17800
|
+
return `Document "${title}" created at "${path37}".`;
|
|
17801
17801
|
}
|
|
17802
17802
|
}
|
|
17803
17803
|
];
|
|
@@ -22509,21 +22509,21 @@ function normalizeAuth(auth) {
|
|
|
22509
22509
|
return "agent";
|
|
22510
22510
|
}
|
|
22511
22511
|
function readSecrets() {
|
|
22512
|
-
const
|
|
22513
|
-
if (!existsSync9(
|
|
22512
|
+
const path37 = getSshSecretsPath();
|
|
22513
|
+
if (!existsSync9(path37)) return {};
|
|
22514
22514
|
try {
|
|
22515
|
-
return JSON.parse(readFileSync7(
|
|
22515
|
+
return JSON.parse(readFileSync7(path37, "utf8"));
|
|
22516
22516
|
} catch {
|
|
22517
22517
|
return {};
|
|
22518
22518
|
}
|
|
22519
22519
|
}
|
|
22520
22520
|
function writeSecrets(data) {
|
|
22521
|
-
const
|
|
22522
|
-
mkdirSync6(dirname2(
|
|
22523
|
-
writeFileSync5(
|
|
22521
|
+
const path37 = getSshSecretsPath();
|
|
22522
|
+
mkdirSync6(dirname2(path37), { recursive: true });
|
|
22523
|
+
writeFileSync5(path37, `${JSON.stringify(data, null, 2)}
|
|
22524
22524
|
`, "utf8");
|
|
22525
22525
|
try {
|
|
22526
|
-
chmodSync(
|
|
22526
|
+
chmodSync(path37, 384);
|
|
22527
22527
|
} catch {
|
|
22528
22528
|
}
|
|
22529
22529
|
}
|
|
@@ -22552,10 +22552,10 @@ function deleteSshPassword(id) {
|
|
|
22552
22552
|
writeSecrets({ passwords });
|
|
22553
22553
|
}
|
|
22554
22554
|
function readStore2() {
|
|
22555
|
-
const
|
|
22556
|
-
if (!existsSync9(
|
|
22555
|
+
const path37 = getSshTargetsPath();
|
|
22556
|
+
if (!existsSync9(path37)) return [];
|
|
22557
22557
|
try {
|
|
22558
|
-
const parsed = JSON.parse(readFileSync7(
|
|
22558
|
+
const parsed = JSON.parse(readFileSync7(path37, "utf8"));
|
|
22559
22559
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
22560
22560
|
return list.filter(
|
|
22561
22561
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -22570,11 +22570,11 @@ function readStore2() {
|
|
|
22570
22570
|
}
|
|
22571
22571
|
}
|
|
22572
22572
|
function writeStore2(targets) {
|
|
22573
|
-
const
|
|
22574
|
-
mkdirSync6(dirname2(
|
|
22573
|
+
const path37 = getSshTargetsPath();
|
|
22574
|
+
mkdirSync6(dirname2(path37), { recursive: true });
|
|
22575
22575
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
22576
22576
|
writeFileSync5(
|
|
22577
|
-
|
|
22577
|
+
path37,
|
|
22578
22578
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
22579
22579
|
`,
|
|
22580
22580
|
"utf8"
|
|
@@ -22820,11 +22820,11 @@ function formatSshTargetsForPrompt() {
|
|
|
22820
22820
|
];
|
|
22821
22821
|
for (const t of targets) {
|
|
22822
22822
|
const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
|
|
22823
|
-
const
|
|
22823
|
+
const path37 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
|
|
22824
22824
|
const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
|
|
22825
22825
|
const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
|
|
22826
22826
|
lines.push(
|
|
22827
|
-
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${
|
|
22827
|
+
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path37}${tags}${allow}`
|
|
22828
22828
|
);
|
|
22829
22829
|
}
|
|
22830
22830
|
return lines.join("\n");
|
|
@@ -22949,6 +22949,304 @@ var init_tools6 = __esm({
|
|
|
22949
22949
|
}
|
|
22950
22950
|
});
|
|
22951
22951
|
|
|
22952
|
+
// src/cli/workspace/worldModel.ts
|
|
22953
|
+
import { promises as fs13 } from "node:fs";
|
|
22954
|
+
import path23 from "node:path";
|
|
22955
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
22956
|
+
function worldDir(cwd) {
|
|
22957
|
+
return path23.join(cwd, WORLD_DIR_NAME);
|
|
22958
|
+
}
|
|
22959
|
+
async function ensureWorldDir(cwd) {
|
|
22960
|
+
const dir = worldDir(cwd);
|
|
22961
|
+
await fs13.mkdir(dir, { recursive: true });
|
|
22962
|
+
return dir;
|
|
22963
|
+
}
|
|
22964
|
+
async function appendTimeline(cwd, entry) {
|
|
22965
|
+
const dir = await ensureWorldDir(cwd);
|
|
22966
|
+
const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
|
|
22967
|
+
await fs13.appendFile(path23.join(dir, TIMELINE_FILE), line, "utf8");
|
|
22968
|
+
}
|
|
22969
|
+
async function readChecks(cwd) {
|
|
22970
|
+
const p3 = path23.join(worldDir(cwd), CHECKS_FILE);
|
|
22971
|
+
try {
|
|
22972
|
+
const raw = await fs13.readFile(p3, "utf8");
|
|
22973
|
+
const parsed = JSON.parse(raw);
|
|
22974
|
+
return Array.isArray(parsed.checks) ? parsed.checks : [];
|
|
22975
|
+
} catch {
|
|
22976
|
+
return [];
|
|
22977
|
+
}
|
|
22978
|
+
}
|
|
22979
|
+
function runShell(command, cwd, timeoutMs, signal) {
|
|
22980
|
+
return new Promise((resolve) => {
|
|
22981
|
+
const isWin = process.platform === "win32";
|
|
22982
|
+
const child = spawn5(isWin ? "cmd.exe" : "/bin/sh", isWin ? ["/c", command] : ["-c", command], {
|
|
22983
|
+
cwd,
|
|
22984
|
+
env: process.env,
|
|
22985
|
+
windowsHide: true,
|
|
22986
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
22987
|
+
});
|
|
22988
|
+
let stdout = "";
|
|
22989
|
+
let stderr = "";
|
|
22990
|
+
let settled = false;
|
|
22991
|
+
const finish = (exitCode) => {
|
|
22992
|
+
if (settled) return;
|
|
22993
|
+
settled = true;
|
|
22994
|
+
resolve({ exitCode, stdout, stderr });
|
|
22995
|
+
};
|
|
22996
|
+
const timer = setTimeout(() => {
|
|
22997
|
+
try {
|
|
22998
|
+
child.kill("SIGTERM");
|
|
22999
|
+
} catch {
|
|
23000
|
+
}
|
|
23001
|
+
finish(124);
|
|
23002
|
+
}, timeoutMs);
|
|
23003
|
+
if (signal) {
|
|
23004
|
+
if (signal.aborted) {
|
|
23005
|
+
try {
|
|
23006
|
+
child.kill("SIGTERM");
|
|
23007
|
+
} catch {
|
|
23008
|
+
}
|
|
23009
|
+
clearTimeout(timer);
|
|
23010
|
+
finish(130);
|
|
23011
|
+
return;
|
|
23012
|
+
}
|
|
23013
|
+
signal.addEventListener(
|
|
23014
|
+
"abort",
|
|
23015
|
+
() => {
|
|
23016
|
+
try {
|
|
23017
|
+
child.kill("SIGTERM");
|
|
23018
|
+
} catch {
|
|
23019
|
+
}
|
|
23020
|
+
clearTimeout(timer);
|
|
23021
|
+
finish(130);
|
|
23022
|
+
},
|
|
23023
|
+
{ once: true }
|
|
23024
|
+
);
|
|
23025
|
+
}
|
|
23026
|
+
child.stdout?.on("data", (d) => {
|
|
23027
|
+
stdout += d.toString("utf8");
|
|
23028
|
+
if (stdout.length > 32e3) stdout = stdout.slice(0, 32e3);
|
|
23029
|
+
});
|
|
23030
|
+
child.stderr?.on("data", (d) => {
|
|
23031
|
+
stderr += d.toString("utf8");
|
|
23032
|
+
if (stderr.length > 32e3) stderr = stderr.slice(0, 32e3);
|
|
23033
|
+
});
|
|
23034
|
+
child.on("error", () => {
|
|
23035
|
+
clearTimeout(timer);
|
|
23036
|
+
finish(1);
|
|
23037
|
+
});
|
|
23038
|
+
child.on("close", (code) => {
|
|
23039
|
+
clearTimeout(timer);
|
|
23040
|
+
finish(code ?? 1);
|
|
23041
|
+
});
|
|
23042
|
+
});
|
|
23043
|
+
}
|
|
23044
|
+
async function runBacktest(cwd, signal) {
|
|
23045
|
+
const checksPath = path23.join(worldDir(cwd), CHECKS_FILE);
|
|
23046
|
+
const hypothesisPath = path23.join(worldDir(cwd), HYPOTHESIS_FILE);
|
|
23047
|
+
const checks = await readChecks(cwd);
|
|
23048
|
+
if (checks.length === 0) {
|
|
23049
|
+
return {
|
|
23050
|
+
ok: false,
|
|
23051
|
+
passed: 0,
|
|
23052
|
+
failed: 0,
|
|
23053
|
+
total: 0,
|
|
23054
|
+
results: [],
|
|
23055
|
+
hypothesisPath,
|
|
23056
|
+
checksPath
|
|
23057
|
+
};
|
|
23058
|
+
}
|
|
23059
|
+
const results = [];
|
|
23060
|
+
for (const c of checks) {
|
|
23061
|
+
const expectExit = c.expectExit ?? 0;
|
|
23062
|
+
const timeoutMs = c.timeoutMs ?? 12e4;
|
|
23063
|
+
const start = Date.now();
|
|
23064
|
+
const { exitCode, stdout, stderr } = await runShell(c.command, cwd, timeoutMs, signal);
|
|
23065
|
+
const combined = `${stdout}${stderr}`;
|
|
23066
|
+
const preview = combined.slice(0, 400);
|
|
23067
|
+
let ok = exitCode === expectExit;
|
|
23068
|
+
let mismatch;
|
|
23069
|
+
if (!ok) {
|
|
23070
|
+
mismatch = `exit ${exitCode} (expected ${expectExit})`;
|
|
23071
|
+
} else if (c.expectStdoutIncludes && !combined.includes(c.expectStdoutIncludes)) {
|
|
23072
|
+
ok = false;
|
|
23073
|
+
mismatch = `stdout missing substring: ${c.expectStdoutIncludes}`;
|
|
23074
|
+
}
|
|
23075
|
+
results.push({
|
|
23076
|
+
id: c.id,
|
|
23077
|
+
command: c.command,
|
|
23078
|
+
ok,
|
|
23079
|
+
exitCode,
|
|
23080
|
+
expectExit,
|
|
23081
|
+
durationMs: Date.now() - start,
|
|
23082
|
+
stdoutPreview: preview,
|
|
23083
|
+
...mismatch ? { mismatch } : {}
|
|
23084
|
+
});
|
|
23085
|
+
}
|
|
23086
|
+
const passed = results.filter((r) => r.ok).length;
|
|
23087
|
+
const failed = results.length - passed;
|
|
23088
|
+
const summary = {
|
|
23089
|
+
ok: failed === 0 && results.length > 0,
|
|
23090
|
+
passed,
|
|
23091
|
+
failed,
|
|
23092
|
+
total: results.length,
|
|
23093
|
+
results,
|
|
23094
|
+
hypothesisPath,
|
|
23095
|
+
checksPath
|
|
23096
|
+
};
|
|
23097
|
+
await appendTimeline(cwd, { kind: "backtest", ok: summary.ok, passed, failed, total: results.length });
|
|
23098
|
+
return summary;
|
|
23099
|
+
}
|
|
23100
|
+
function createWorldModelTools() {
|
|
23101
|
+
if (process.env["ZELARI_SCHEMA_LOOP"] === "0") return [];
|
|
23102
|
+
return [
|
|
23103
|
+
updateWorldHypothesisTool,
|
|
23104
|
+
setWorldChecksTool,
|
|
23105
|
+
runBacktestTool,
|
|
23106
|
+
recordWorldObservationTool
|
|
23107
|
+
];
|
|
23108
|
+
}
|
|
23109
|
+
var WORLD_DIR_NAME, HYPOTHESIS_FILE, CHECKS_FILE, TIMELINE_FILE, UpdateHypothesisSchema, updateWorldHypothesisTool, WorldCheckSchema, SetChecksSchema, setWorldChecksTool, RunBacktestSchema, runBacktestTool, RecordObsSchema, recordWorldObservationTool;
|
|
23110
|
+
var init_worldModel = __esm({
|
|
23111
|
+
"src/cli/workspace/worldModel.ts"() {
|
|
23112
|
+
"use strict";
|
|
23113
|
+
init_zod();
|
|
23114
|
+
init_toolTypes();
|
|
23115
|
+
WORLD_DIR_NAME = path23.join(".zelari", "world");
|
|
23116
|
+
HYPOTHESIS_FILE = "hypothesis.md";
|
|
23117
|
+
CHECKS_FILE = "checks.json";
|
|
23118
|
+
TIMELINE_FILE = "timeline.jsonl";
|
|
23119
|
+
UpdateHypothesisSchema = external_exports.object({
|
|
23120
|
+
content: external_exports.string().min(1).describe("Full markdown hypothesis / working notes (replaces file)."),
|
|
23121
|
+
append: external_exports.boolean().optional().describe("If true, append content under a timestamp instead of replacing.")
|
|
23122
|
+
});
|
|
23123
|
+
updateWorldHypothesisTool = {
|
|
23124
|
+
name: "update_world_hypothesis",
|
|
23125
|
+
description: "Write or append the task world-model hypothesis (Schema-style notes.md) to .zelari/world/hypothesis.md. Use this to record what you believe is true about the bug/system, competing hypotheses, and what experiment would discriminate them. Do NOT claim work is done until run_backtest is green.",
|
|
23126
|
+
permissions: ["write"],
|
|
23127
|
+
timeoutMs: 1e4,
|
|
23128
|
+
inputSchema: UpdateHypothesisSchema,
|
|
23129
|
+
execute: async (args, ctx) => {
|
|
23130
|
+
try {
|
|
23131
|
+
const dir = await ensureWorldDir(ctx.cwd);
|
|
23132
|
+
const file2 = path23.join(dir, HYPOTHESIS_FILE);
|
|
23133
|
+
if (args.append) {
|
|
23134
|
+
const block = `
|
|
23135
|
+
|
|
23136
|
+
## ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
23137
|
+
|
|
23138
|
+
${args.content}
|
|
23139
|
+
`;
|
|
23140
|
+
await fs13.appendFile(file2, block, "utf8");
|
|
23141
|
+
} else {
|
|
23142
|
+
await fs13.writeFile(file2, args.content, "utf8");
|
|
23143
|
+
}
|
|
23144
|
+
const st = await fs13.stat(file2);
|
|
23145
|
+
await appendTimeline(ctx.cwd, { kind: "hypothesis_update", bytes: st.size, append: !!args.append });
|
|
23146
|
+
return typedOk({ path: file2, bytes: st.size });
|
|
23147
|
+
} catch (err) {
|
|
23148
|
+
return typedErr(err instanceof Error ? err.message : String(err));
|
|
23149
|
+
}
|
|
23150
|
+
}
|
|
23151
|
+
};
|
|
23152
|
+
WorldCheckSchema = external_exports.object({
|
|
23153
|
+
id: external_exports.string().min(1),
|
|
23154
|
+
command: external_exports.string().min(1),
|
|
23155
|
+
expectExit: external_exports.number().int().optional(),
|
|
23156
|
+
expectStdoutIncludes: external_exports.string().optional(),
|
|
23157
|
+
timeoutMs: external_exports.number().int().positive().max(6e5).optional()
|
|
23158
|
+
});
|
|
23159
|
+
SetChecksSchema = external_exports.object({
|
|
23160
|
+
checks: external_exports.array(WorldCheckSchema).min(1).describe("List of certifiable shell checks (typecheck, unit tests, smoke scripts).")
|
|
23161
|
+
});
|
|
23162
|
+
setWorldChecksTool = {
|
|
23163
|
+
name: "set_world_checks",
|
|
23164
|
+
description: "Replace .zelari/world/checks.json with certifiable checks used by run_backtest. Each check is a shell command + expected exit code (default 0). Prefer fast, deterministic commands (npm run typecheck, npx vitest run path/to/file).",
|
|
23165
|
+
permissions: ["write"],
|
|
23166
|
+
timeoutMs: 1e4,
|
|
23167
|
+
inputSchema: SetChecksSchema,
|
|
23168
|
+
execute: async (args, ctx) => {
|
|
23169
|
+
try {
|
|
23170
|
+
const dir = await ensureWorldDir(ctx.cwd);
|
|
23171
|
+
const file2 = path23.join(dir, CHECKS_FILE);
|
|
23172
|
+
const body = { checks: args.checks };
|
|
23173
|
+
await fs13.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
|
|
23174
|
+
await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
|
|
23175
|
+
return typedOk({ path: file2, count: args.checks.length });
|
|
23176
|
+
} catch (err) {
|
|
23177
|
+
return typedErr(err instanceof Error ? err.message : String(err));
|
|
23178
|
+
}
|
|
23179
|
+
}
|
|
23180
|
+
};
|
|
23181
|
+
RunBacktestSchema = external_exports.object({
|
|
23182
|
+
/** Reserved for future selective runs. */
|
|
23183
|
+
dryRun: external_exports.boolean().optional()
|
|
23184
|
+
});
|
|
23185
|
+
runBacktestTool = {
|
|
23186
|
+
name: "run_backtest",
|
|
23187
|
+
description: "Schema-style certify: run every check in .zelari/world/checks.json and report exact pass/fail (exit code + optional stdout substring). Appends a timeline entry. If total=0, call set_world_checks first. NEVER claim the task is done when ok=false. On mismatch, revise hypothesis (update_world_hypothesis) and the implementation, then re-run.",
|
|
23188
|
+
permissions: ["execute"],
|
|
23189
|
+
timeoutMs: 6e5,
|
|
23190
|
+
inputSchema: RunBacktestSchema,
|
|
23191
|
+
execute: async (args, ctx) => {
|
|
23192
|
+
try {
|
|
23193
|
+
if (args.dryRun) {
|
|
23194
|
+
const checks = await readChecks(ctx.cwd);
|
|
23195
|
+
return typedOk({
|
|
23196
|
+
ok: false,
|
|
23197
|
+
passed: 0,
|
|
23198
|
+
failed: 0,
|
|
23199
|
+
total: checks.length,
|
|
23200
|
+
results: checks.map((c) => ({
|
|
23201
|
+
id: c.id,
|
|
23202
|
+
command: c.command,
|
|
23203
|
+
ok: false,
|
|
23204
|
+
exitCode: -1,
|
|
23205
|
+
expectExit: c.expectExit ?? 0,
|
|
23206
|
+
durationMs: 0,
|
|
23207
|
+
stdoutPreview: "(dryRun)",
|
|
23208
|
+
mismatch: "dryRun"
|
|
23209
|
+
})),
|
|
23210
|
+
hypothesisPath: path23.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
|
|
23211
|
+
checksPath: path23.join(worldDir(ctx.cwd), CHECKS_FILE)
|
|
23212
|
+
});
|
|
23213
|
+
}
|
|
23214
|
+
const result = await runBacktest(ctx.cwd, ctx.signal);
|
|
23215
|
+
return typedOk(result);
|
|
23216
|
+
} catch (err) {
|
|
23217
|
+
return typedErr(err instanceof Error ? err.message : String(err));
|
|
23218
|
+
}
|
|
23219
|
+
}
|
|
23220
|
+
};
|
|
23221
|
+
RecordObsSchema = external_exports.object({
|
|
23222
|
+
kind: external_exports.string().min(1).describe("Observation kind, e.g. surprise, probe, prediction_mismatch."),
|
|
23223
|
+
summary: external_exports.string().min(1),
|
|
23224
|
+
data: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
|
|
23225
|
+
});
|
|
23226
|
+
recordWorldObservationTool = {
|
|
23227
|
+
name: "record_world_observation",
|
|
23228
|
+
description: "Append one ground-truth observation to .zelari/world/timeline.jsonl (Schema timeline). Use after a surprising tool result (prediction mismatch, unexpected exit code, wrong path) so later deliberation cannot rewrite history.",
|
|
23229
|
+
permissions: ["write"],
|
|
23230
|
+
timeoutMs: 5e3,
|
|
23231
|
+
inputSchema: RecordObsSchema,
|
|
23232
|
+
execute: async (args, ctx) => {
|
|
23233
|
+
try {
|
|
23234
|
+
const dir = await ensureWorldDir(ctx.cwd);
|
|
23235
|
+
const file2 = path23.join(dir, TIMELINE_FILE);
|
|
23236
|
+
await appendTimeline(ctx.cwd, {
|
|
23237
|
+
kind: args.kind,
|
|
23238
|
+
summary: args.summary,
|
|
23239
|
+
...args.data ? { data: args.data } : {}
|
|
23240
|
+
});
|
|
23241
|
+
return typedOk({ path: file2 });
|
|
23242
|
+
} catch (err) {
|
|
23243
|
+
return typedErr(err instanceof Error ? err.message : String(err));
|
|
23244
|
+
}
|
|
23245
|
+
}
|
|
23246
|
+
};
|
|
23247
|
+
}
|
|
23248
|
+
});
|
|
23249
|
+
|
|
22952
23250
|
// src/cli/toolRegistry.ts
|
|
22953
23251
|
var toolRegistry_exports = {};
|
|
22954
23252
|
__export(toolRegistry_exports, {
|
|
@@ -23037,6 +23335,17 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
23037
23335
|
});
|
|
23038
23336
|
}
|
|
23039
23337
|
}
|
|
23338
|
+
if (!readOnly) {
|
|
23339
|
+
for (const t of createWorldModelTools()) {
|
|
23340
|
+
const safe = wrapWithAudit(t, audit, sessionId);
|
|
23341
|
+
registry3.register(safe);
|
|
23342
|
+
tools.push({
|
|
23343
|
+
name: t.name,
|
|
23344
|
+
description: t.description,
|
|
23345
|
+
permissions: t.permissions ?? []
|
|
23346
|
+
});
|
|
23347
|
+
}
|
|
23348
|
+
}
|
|
23040
23349
|
if (!readOnly && options.enableTask !== false) {
|
|
23041
23350
|
const taskTool = createTaskTool({
|
|
23042
23351
|
createSubAgentContext: async () => {
|
|
@@ -23276,6 +23585,7 @@ var init_toolRegistry = __esm({
|
|
|
23276
23585
|
init_tools4();
|
|
23277
23586
|
init_tools5();
|
|
23278
23587
|
init_tools6();
|
|
23588
|
+
init_worldModel();
|
|
23279
23589
|
init_openai_compatible();
|
|
23280
23590
|
init_skills2();
|
|
23281
23591
|
HARNESS_BUILTIN_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -24069,11 +24379,11 @@ var init_synthesisAudit = __esm({
|
|
|
24069
24379
|
import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
24070
24380
|
import { join as join3 } from "node:path";
|
|
24071
24381
|
function loadNfrSpec(zelariRoot) {
|
|
24072
|
-
const
|
|
24073
|
-
if (!existsSync11(
|
|
24382
|
+
const path37 = join3(zelariRoot, "nfr-spec.json");
|
|
24383
|
+
if (!existsSync11(path37))
|
|
24074
24384
|
return null;
|
|
24075
24385
|
try {
|
|
24076
|
-
const raw = JSON.parse(readFileSync9(
|
|
24386
|
+
const raw = JSON.parse(readFileSync9(path37, "utf8"));
|
|
24077
24387
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
24078
24388
|
return null;
|
|
24079
24389
|
return raw;
|
|
@@ -26321,9 +26631,9 @@ var init_types2 = __esm({
|
|
|
26321
26631
|
import { readFileSync as readFileSync14 } from "node:fs";
|
|
26322
26632
|
import { join as join9 } from "node:path";
|
|
26323
26633
|
function readLessonsDeduped(zelariRoot) {
|
|
26324
|
-
const
|
|
26634
|
+
const path37 = join9(zelariRoot, LESSONS_FILE);
|
|
26325
26635
|
try {
|
|
26326
|
-
const raw = readFileSync14(
|
|
26636
|
+
const raw = readFileSync14(path37, "utf8");
|
|
26327
26637
|
const byId = /* @__PURE__ */ new Map();
|
|
26328
26638
|
for (const line of raw.split(/\r?\n/)) {
|
|
26329
26639
|
if (!line.trim())
|
|
@@ -26424,8 +26734,8 @@ function keywordsFrom(check2, signature) {
|
|
|
26424
26734
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
26425
26735
|
}
|
|
26426
26736
|
function writeLesson(zelariRoot, lesson) {
|
|
26427
|
-
const
|
|
26428
|
-
appendFileSync2(
|
|
26737
|
+
const path37 = join10(zelariRoot, LESSONS_FILE);
|
|
26738
|
+
appendFileSync2(path37, `${JSON.stringify(lesson)}
|
|
26429
26739
|
`, "utf8");
|
|
26430
26740
|
}
|
|
26431
26741
|
function findSimilar(lessons, signature) {
|
|
@@ -27933,28 +28243,28 @@ var init_storage = __esm({
|
|
|
27933
28243
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
27934
28244
|
Storage = class {
|
|
27935
28245
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
27936
|
-
read(
|
|
27937
|
-
if (!existsSync16(
|
|
27938
|
-
throw new Error(`File not found: ${
|
|
28246
|
+
read(path37) {
|
|
28247
|
+
if (!existsSync16(path37)) {
|
|
28248
|
+
throw new Error(`File not found: ${path37}`);
|
|
27939
28249
|
}
|
|
27940
|
-
const md = readFileSync16(
|
|
28250
|
+
const md = readFileSync16(path37, "utf8");
|
|
27941
28251
|
return parseFrontmatter(md);
|
|
27942
28252
|
}
|
|
27943
28253
|
/** Read a Markdown file; returns null if not found. */
|
|
27944
|
-
readIfExists(
|
|
27945
|
-
if (!existsSync16(
|
|
27946
|
-
return this.read(
|
|
28254
|
+
readIfExists(path37) {
|
|
28255
|
+
if (!existsSync16(path37)) return null;
|
|
28256
|
+
return this.read(path37);
|
|
27947
28257
|
}
|
|
27948
28258
|
/**
|
|
27949
28259
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
27950
28260
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
27951
28261
|
*/
|
|
27952
|
-
write(
|
|
27953
|
-
mkdirSync8(dirname3(
|
|
27954
|
-
const tmp =
|
|
28262
|
+
write(path37, meta3, body) {
|
|
28263
|
+
mkdirSync8(dirname3(path37), { recursive: true });
|
|
28264
|
+
const tmp = path37 + ".tmp-" + process.pid;
|
|
27955
28265
|
const md = serializeFrontmatter(meta3, body);
|
|
27956
28266
|
writeFileSync12(tmp, md, "utf8");
|
|
27957
|
-
renameSync2(tmp,
|
|
28267
|
+
renameSync2(tmp, path37);
|
|
27958
28268
|
}
|
|
27959
28269
|
/** List all .md files in a directory (non-recursive). */
|
|
27960
28270
|
listMarkdown(dir) {
|
|
@@ -28032,8 +28342,8 @@ function readPlan(ctx) {
|
|
|
28032
28342
|
} catch {
|
|
28033
28343
|
}
|
|
28034
28344
|
}
|
|
28035
|
-
const
|
|
28036
|
-
const doc = ctx.storage.readIfExists(
|
|
28345
|
+
const path37 = workspaceFile(ctx.rootDir, "plan");
|
|
28346
|
+
const doc = ctx.storage.readIfExists(path37);
|
|
28037
28347
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
28038
28348
|
const meta3 = doc.meta;
|
|
28039
28349
|
return {
|
|
@@ -28198,7 +28508,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
28198
28508
|
dueDate: input.dueDate,
|
|
28199
28509
|
targetVersion: version2
|
|
28200
28510
|
});
|
|
28201
|
-
const
|
|
28511
|
+
const path37 = join15(ctx.rootDir, "milestones", `${id}.md`);
|
|
28202
28512
|
const meta3 = {
|
|
28203
28513
|
kind: "milestone",
|
|
28204
28514
|
id,
|
|
@@ -28215,7 +28525,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
28215
28525
|
`Target version: ${version2}`,
|
|
28216
28526
|
""
|
|
28217
28527
|
].join("\n");
|
|
28218
|
-
ctx.storage.write(
|
|
28528
|
+
ctx.storage.write(path37, meta3, body);
|
|
28219
28529
|
return { id, created: true };
|
|
28220
28530
|
}
|
|
28221
28531
|
function readPlanSummary(ctx) {
|
|
@@ -28419,7 +28729,7 @@ function addIdeaStub(ctx) {
|
|
|
28419
28729
|
const tags = args["tags"] ?? [];
|
|
28420
28730
|
const category = args["category"] ?? "General";
|
|
28421
28731
|
const id = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
28422
|
-
const
|
|
28732
|
+
const path37 = workspaceArtifact(ctx.rootDir, "decisions", id);
|
|
28423
28733
|
const meta3 = {
|
|
28424
28734
|
kind: "adr",
|
|
28425
28735
|
status: "proposed",
|
|
@@ -28445,7 +28755,7 @@ function addIdeaStub(ctx) {
|
|
|
28445
28755
|
...consequences.map((c) => `- ${c}`),
|
|
28446
28756
|
""
|
|
28447
28757
|
].join("\n");
|
|
28448
|
-
ctx.storage.write(
|
|
28758
|
+
ctx.storage.write(path37, meta3, body);
|
|
28449
28759
|
return `ADR ${id} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
28450
28760
|
});
|
|
28451
28761
|
}
|
|
@@ -28527,14 +28837,14 @@ function createDocumentStub(ctx) {
|
|
|
28527
28837
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
28528
28838
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
28529
28839
|
}
|
|
28530
|
-
const
|
|
28840
|
+
const path37 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
28531
28841
|
const meta3 = {
|
|
28532
28842
|
kind: "doc",
|
|
28533
28843
|
id: slug,
|
|
28534
28844
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
28535
28845
|
tags
|
|
28536
28846
|
};
|
|
28537
|
-
ctx.storage.write(
|
|
28847
|
+
ctx.storage.write(path37, meta3, content);
|
|
28538
28848
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
28539
28849
|
});
|
|
28540
28850
|
}
|
|
@@ -28751,17 +29061,17 @@ __export(updater_exports, {
|
|
|
28751
29061
|
resolveBundledNpmCli: () => resolveBundledNpmCli
|
|
28752
29062
|
});
|
|
28753
29063
|
import { createRequire as createRequire2 } from "node:module";
|
|
28754
|
-
import { spawn as
|
|
29064
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
28755
29065
|
import { existsSync as existsSync18 } from "node:fs";
|
|
28756
|
-
import
|
|
29066
|
+
import path24 from "node:path";
|
|
28757
29067
|
import { fileURLToPath } from "node:url";
|
|
28758
29068
|
function resolveBundledNpmCli(execPath = process.execPath) {
|
|
28759
|
-
const dir =
|
|
29069
|
+
const dir = path24.dirname(execPath);
|
|
28760
29070
|
const candidates = [
|
|
28761
29071
|
// Windows: C:\...\node.exe → C:\...\node_modules\npm\bin\npm-cli.js
|
|
28762
|
-
|
|
29072
|
+
path24.join(dir, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
28763
29073
|
// POSIX: <prefix>/bin/node → <prefix>/lib/node_modules/npm/bin/npm-cli.js
|
|
28764
|
-
|
|
29074
|
+
path24.join(dir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
28765
29075
|
];
|
|
28766
29076
|
for (const candidate of candidates) {
|
|
28767
29077
|
try {
|
|
@@ -28778,7 +29088,7 @@ function looksLikeBrokenShim(exitCode, output) {
|
|
|
28778
29088
|
}
|
|
28779
29089
|
function getCurrentVersion() {
|
|
28780
29090
|
try {
|
|
28781
|
-
const pkgPath =
|
|
29091
|
+
const pkgPath = path24.resolve(__dirname2, "..", "..", "package.json");
|
|
28782
29092
|
const pkg = require2(pkgPath);
|
|
28783
29093
|
return pkg.version;
|
|
28784
29094
|
} catch {
|
|
@@ -28838,7 +29148,7 @@ async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
|
28838
29148
|
updateAvailable: cmp < 0
|
|
28839
29149
|
};
|
|
28840
29150
|
}
|
|
28841
|
-
async function performUpdate(packageName = "zelari-code", executor =
|
|
29151
|
+
async function performUpdate(packageName = "zelari-code", executor = spawn6, resolveNpmCli = resolveBundledNpmCli) {
|
|
28842
29152
|
const args = ["install", "-g", `${packageName}@latest`];
|
|
28843
29153
|
const primary = await runNpm(executor, args, "shim");
|
|
28844
29154
|
if (primary.ok) return primary;
|
|
@@ -28890,13 +29200,13 @@ var init_updater = __esm({
|
|
|
28890
29200
|
"use strict";
|
|
28891
29201
|
init_cmdline();
|
|
28892
29202
|
require2 = createRequire2(import.meta.url);
|
|
28893
|
-
__dirname2 =
|
|
29203
|
+
__dirname2 = path24.dirname(fileURLToPath(import.meta.url));
|
|
28894
29204
|
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
28895
29205
|
}
|
|
28896
29206
|
});
|
|
28897
29207
|
|
|
28898
29208
|
// src/cli/mcp/mcpClient.ts
|
|
28899
|
-
import { spawn as
|
|
29209
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
28900
29210
|
var DEFAULT_REQUEST_TIMEOUT_MS, INIT_TIMEOUT_MS, MCP_PROTOCOL_VERSION, McpClient;
|
|
28901
29211
|
var init_mcpClient = __esm({
|
|
28902
29212
|
"src/cli/mcp/mcpClient.ts"() {
|
|
@@ -28924,10 +29234,10 @@ var init_mcpClient = __esm({
|
|
|
28924
29234
|
env: { ...process.env, ...this.config.env ?? {} },
|
|
28925
29235
|
windowsHide: true
|
|
28926
29236
|
};
|
|
28927
|
-
const child = process.platform === "win32" ?
|
|
29237
|
+
const child = process.platform === "win32" ? spawn7(buildCmdLine(this.config.command, this.config.args ?? []), {
|
|
28928
29238
|
...spawnOpts,
|
|
28929
29239
|
shell: true
|
|
28930
|
-
}) :
|
|
29240
|
+
}) : spawn7(this.config.command, this.config.args ?? [], spawnOpts);
|
|
28931
29241
|
this.child = child;
|
|
28932
29242
|
child.stdout.setEncoding("utf8");
|
|
28933
29243
|
child.stdout.on("data", (chunk) => this.onStdout(chunk));
|
|
@@ -29076,11 +29386,11 @@ import { join as join16 } from "node:path";
|
|
|
29076
29386
|
import { homedir as homedir6 } from "node:os";
|
|
29077
29387
|
function readMcpConfig(projectRoot = process.cwd()) {
|
|
29078
29388
|
const merged = {};
|
|
29079
|
-
const paths = [
|
|
29080
|
-
|
|
29081
|
-
join16(
|
|
29082
|
-
|
|
29083
|
-
|
|
29389
|
+
const paths = [];
|
|
29390
|
+
if (process.env["ZELARI_MCP_USER"] !== "0") {
|
|
29391
|
+
paths.push(join16(homedir6(), ".zelari-code", "mcp.json"));
|
|
29392
|
+
}
|
|
29393
|
+
paths.push(join16(projectRoot, ".zelari", "mcp.json"));
|
|
29084
29394
|
for (const p3 of paths) {
|
|
29085
29395
|
if (!existsSync19(p3)) continue;
|
|
29086
29396
|
try {
|
|
@@ -29378,10 +29688,10 @@ import { createHash as createHash3 } from "node:crypto";
|
|
|
29378
29688
|
import { join as join19 } from "node:path";
|
|
29379
29689
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
29380
29690
|
async function readPackageJson2(projectRoot) {
|
|
29381
|
-
const
|
|
29382
|
-
if (!existsSync22(
|
|
29691
|
+
const path37 = join19(projectRoot, "package.json");
|
|
29692
|
+
if (!existsSync22(path37)) return null;
|
|
29383
29693
|
try {
|
|
29384
|
-
return JSON.parse(await readFile2(
|
|
29694
|
+
return JSON.parse(await readFile2(path37, "utf8"));
|
|
29385
29695
|
} catch {
|
|
29386
29696
|
return null;
|
|
29387
29697
|
}
|
|
@@ -29463,9 +29773,9 @@ async function genBuild(ctx) {
|
|
|
29463
29773
|
].join("\n");
|
|
29464
29774
|
}
|
|
29465
29775
|
async function genOpenQuestions(ctx) {
|
|
29466
|
-
const
|
|
29467
|
-
if (!existsSync22(
|
|
29468
|
-
const content = readFileSync21(
|
|
29776
|
+
const path37 = join19(ctx.rootDir, "risks.md");
|
|
29777
|
+
if (!existsSync22(path37)) return "_No open questions._";
|
|
29778
|
+
const content = readFileSync21(path37, "utf8");
|
|
29469
29779
|
const lines = content.split("\n");
|
|
29470
29780
|
const questions = [];
|
|
29471
29781
|
let currentTitle = "";
|
|
@@ -29710,7 +30020,7 @@ var init_completeDesign = __esm({
|
|
|
29710
30020
|
});
|
|
29711
30021
|
|
|
29712
30022
|
// src/cli/workspace/projectSmoke.ts
|
|
29713
|
-
import { spawn as
|
|
30023
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
29714
30024
|
import { existsSync as existsSync23, readFileSync as readFileSync22 } from "node:fs";
|
|
29715
30025
|
import { join as join20 } from "node:path";
|
|
29716
30026
|
function pickSmokeScript(scripts) {
|
|
@@ -29740,12 +30050,12 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
|
29740
30050
|
return { ran: false, reason: "no typecheck/test/build script (skipped)" };
|
|
29741
30051
|
}
|
|
29742
30052
|
return await new Promise((resolveRun) => {
|
|
29743
|
-
const child = process.platform === "win32" ?
|
|
30053
|
+
const child = process.platform === "win32" ? spawn8(buildCmdLine("npm.cmd", ["run", script]), {
|
|
29744
30054
|
cwd: projectRoot,
|
|
29745
30055
|
stdio: ["ignore", "pipe", "pipe"],
|
|
29746
30056
|
env: process.env,
|
|
29747
30057
|
shell: true
|
|
29748
|
-
}) :
|
|
30058
|
+
}) : spawn8("npm", ["run", script], {
|
|
29749
30059
|
cwd: projectRoot,
|
|
29750
30060
|
stdio: ["ignore", "pipe", "pipe"],
|
|
29751
30061
|
env: process.env
|
|
@@ -29817,7 +30127,7 @@ __export(postCouncilHook_exports, {
|
|
|
29817
30127
|
runImplementationVerificationHook: () => runImplementationVerificationHook,
|
|
29818
30128
|
runPostCouncilHook: () => runPostCouncilHook
|
|
29819
30129
|
});
|
|
29820
|
-
import { spawn as
|
|
30130
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
29821
30131
|
import { existsSync as existsSync24, readFileSync as readFileSync23 } from "node:fs";
|
|
29822
30132
|
import { join as join21 } from "node:path";
|
|
29823
30133
|
async function runCompleteDesignPostProcessor(ctx, options) {
|
|
@@ -29866,7 +30176,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
29866
30176
|
}
|
|
29867
30177
|
}
|
|
29868
30178
|
return await new Promise((resolveRun) => {
|
|
29869
|
-
const child =
|
|
30179
|
+
const child = spawn9(process.execPath, [scriptPath], {
|
|
29870
30180
|
cwd: ctx.projectRoot,
|
|
29871
30181
|
stdio: ["ignore", "pipe", "pipe"],
|
|
29872
30182
|
env: process.env
|
|
@@ -30032,8 +30342,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
30032
30342
|
sources: scope.sources
|
|
30033
30343
|
} : void 0
|
|
30034
30344
|
});
|
|
30035
|
-
const
|
|
30036
|
-
completionHook = { ran: true, path:
|
|
30345
|
+
const path37 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
30346
|
+
completionHook = { ran: true, path: path37, completion };
|
|
30037
30347
|
} catch (err) {
|
|
30038
30348
|
completionHook = {
|
|
30039
30349
|
ran: true,
|
|
@@ -30096,13 +30406,13 @@ __export(councilFeedback_exports, {
|
|
|
30096
30406
|
FeedbackStore: () => FeedbackStore
|
|
30097
30407
|
});
|
|
30098
30408
|
import {
|
|
30099
|
-
promises as
|
|
30409
|
+
promises as fs14,
|
|
30100
30410
|
existsSync as existsSync26,
|
|
30101
30411
|
readFileSync as readFileSync24,
|
|
30102
30412
|
writeFileSync as writeFileSync15,
|
|
30103
30413
|
mkdirSync as mkdirSync10
|
|
30104
30414
|
} from "node:fs";
|
|
30105
|
-
import
|
|
30415
|
+
import path25 from "node:path";
|
|
30106
30416
|
import os8 from "node:os";
|
|
30107
30417
|
var FeedbackStore;
|
|
30108
30418
|
var init_councilFeedback = __esm({
|
|
@@ -30113,7 +30423,7 @@ var init_councilFeedback = __esm({
|
|
|
30113
30423
|
now;
|
|
30114
30424
|
entries = [];
|
|
30115
30425
|
constructor(options = {}) {
|
|
30116
|
-
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ??
|
|
30426
|
+
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path25.join(os8.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
|
|
30117
30427
|
this.now = options.now ?? Date.now;
|
|
30118
30428
|
this.load();
|
|
30119
30429
|
}
|
|
@@ -30219,7 +30529,7 @@ var init_councilFeedback = __esm({
|
|
|
30219
30529
|
}
|
|
30220
30530
|
}
|
|
30221
30531
|
save() {
|
|
30222
|
-
mkdirSync10(
|
|
30532
|
+
mkdirSync10(path25.dirname(this.file), { recursive: true });
|
|
30223
30533
|
writeFileSync15(
|
|
30224
30534
|
this.file,
|
|
30225
30535
|
JSON.stringify({ entries: this.entries }, null, 2),
|
|
@@ -30229,7 +30539,7 @@ var init_councilFeedback = __esm({
|
|
|
30229
30539
|
/** Async variant of load for callers that prefer async IO. */
|
|
30230
30540
|
async loadAsync() {
|
|
30231
30541
|
try {
|
|
30232
|
-
const raw = await
|
|
30542
|
+
const raw = await fs14.readFile(this.file, "utf-8");
|
|
30233
30543
|
const parsed = JSON.parse(raw);
|
|
30234
30544
|
if (parsed && Array.isArray(parsed.entries)) {
|
|
30235
30545
|
this.entries = parsed.entries.filter(
|
|
@@ -30253,8 +30563,8 @@ __export(fileBackend_exports, {
|
|
|
30253
30563
|
isMemoryEnabled: () => isMemoryEnabled
|
|
30254
30564
|
});
|
|
30255
30565
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
30256
|
-
import { promises as
|
|
30257
|
-
import * as
|
|
30566
|
+
import { promises as fs15 } from "node:fs";
|
|
30567
|
+
import * as path26 from "node:path";
|
|
30258
30568
|
function tokenize(text) {
|
|
30259
30569
|
return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
|
|
30260
30570
|
}
|
|
@@ -30292,9 +30602,9 @@ var init_fileBackend = __esm({
|
|
|
30292
30602
|
logPath = "";
|
|
30293
30603
|
memoryDir = "";
|
|
30294
30604
|
async init(projectRoot) {
|
|
30295
|
-
this.memoryDir =
|
|
30296
|
-
this.logPath =
|
|
30297
|
-
await
|
|
30605
|
+
this.memoryDir = path26.join(projectRoot, ".zelari", "memory");
|
|
30606
|
+
this.logPath = path26.join(this.memoryDir, "log.jsonl");
|
|
30607
|
+
await fs15.mkdir(this.memoryDir, { recursive: true });
|
|
30298
30608
|
}
|
|
30299
30609
|
async add(content, metadata = {}, graph) {
|
|
30300
30610
|
const fact = {
|
|
@@ -30304,7 +30614,7 @@ var init_fileBackend = __esm({
|
|
|
30304
30614
|
...graph ? { graph } : {},
|
|
30305
30615
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
30306
30616
|
};
|
|
30307
|
-
await
|
|
30617
|
+
await fs15.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
|
|
30308
30618
|
return fact.id;
|
|
30309
30619
|
}
|
|
30310
30620
|
async search(query, options = {}) {
|
|
@@ -30332,7 +30642,7 @@ var init_fileBackend = __esm({
|
|
|
30332
30642
|
async readAll() {
|
|
30333
30643
|
let raw;
|
|
30334
30644
|
try {
|
|
30335
|
-
raw = await
|
|
30645
|
+
raw = await fs15.readFile(this.logPath, "utf8");
|
|
30336
30646
|
} catch {
|
|
30337
30647
|
return [];
|
|
30338
30648
|
}
|
|
@@ -30368,7 +30678,7 @@ import { execFile as execFile2 } from "node:child_process";
|
|
|
30368
30678
|
import { promisify } from "node:util";
|
|
30369
30679
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
30370
30680
|
import { tmpdir } from "node:os";
|
|
30371
|
-
import
|
|
30681
|
+
import path27 from "node:path";
|
|
30372
30682
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
30373
30683
|
async function git(cwd, args, env) {
|
|
30374
30684
|
const { stdout } = await execFileAsync("git", ["-C", cwd, ...args], {
|
|
@@ -30388,8 +30698,8 @@ async function isGitRepo(cwd) {
|
|
|
30388
30698
|
return await gitSafe(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true";
|
|
30389
30699
|
}
|
|
30390
30700
|
async function withTempIndex(fn) {
|
|
30391
|
-
const dir = mkdtempSync(
|
|
30392
|
-
const indexFile =
|
|
30701
|
+
const dir = mkdtempSync(path27.join(tmpdir(), "zelari-ckpt-"));
|
|
30702
|
+
const indexFile = path27.join(dir, "index");
|
|
30393
30703
|
try {
|
|
30394
30704
|
return await fn(indexFile);
|
|
30395
30705
|
} finally {
|
|
@@ -30480,7 +30790,7 @@ async function restoreCheckpoint(cwd, id) {
|
|
|
30480
30790
|
const deleted = [];
|
|
30481
30791
|
for (const rel2 of added) {
|
|
30482
30792
|
try {
|
|
30483
|
-
rmSync(
|
|
30793
|
+
rmSync(path27.join(cwd, rel2), { force: true });
|
|
30484
30794
|
deleted.push(rel2);
|
|
30485
30795
|
} catch {
|
|
30486
30796
|
}
|
|
@@ -30509,8 +30819,8 @@ __export(zelariMission_exports, {
|
|
|
30509
30819
|
runZelariMission: () => runZelariMission
|
|
30510
30820
|
});
|
|
30511
30821
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
30512
|
-
import { promises as
|
|
30513
|
-
import * as
|
|
30822
|
+
import { promises as fs16 } from "node:fs";
|
|
30823
|
+
import * as path28 from "node:path";
|
|
30514
30824
|
function resolveMaxIterations(env = process.env) {
|
|
30515
30825
|
const raw = env.ZELARI_MISSION_MAX_ITER;
|
|
30516
30826
|
const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
|
|
@@ -30526,10 +30836,10 @@ function isMissionAutoStart(env = process.env) {
|
|
|
30526
30836
|
return env.ZELARI_MISSION_AUTO === "1";
|
|
30527
30837
|
}
|
|
30528
30838
|
async function writeMissionState(projectRoot, state2) {
|
|
30529
|
-
const dir =
|
|
30530
|
-
await
|
|
30531
|
-
await
|
|
30532
|
-
|
|
30839
|
+
const dir = path28.join(projectRoot, ".zelari");
|
|
30840
|
+
await fs16.mkdir(dir, { recursive: true });
|
|
30841
|
+
await fs16.writeFile(
|
|
30842
|
+
path28.join(dir, "mission-state.json"),
|
|
30533
30843
|
JSON.stringify(state2, null, 2) + "\n",
|
|
30534
30844
|
"utf8"
|
|
30535
30845
|
);
|
|
@@ -30977,10 +31287,10 @@ var init_prereqChecks = __esm({
|
|
|
30977
31287
|
|
|
30978
31288
|
// src/cli/plugins/prefs.ts
|
|
30979
31289
|
import { existsSync as existsSync28, readFileSync as readFileSync25, writeFileSync as writeFileSync16, mkdirSync as mkdirSync11 } from "node:fs";
|
|
30980
|
-
import
|
|
31290
|
+
import path30 from "node:path";
|
|
30981
31291
|
import os9 from "node:os";
|
|
30982
31292
|
function getPluginPrefsPath() {
|
|
30983
|
-
return process.env.ZELARI_PLUGINS_PREFS_FILE ??
|
|
31293
|
+
return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path30.join(os9.homedir(), ".tmp", "zelari-code", "plugins.json");
|
|
30984
31294
|
}
|
|
30985
31295
|
function getPluginPrefs() {
|
|
30986
31296
|
const file2 = getPluginPrefsPath();
|
|
@@ -31001,7 +31311,7 @@ function getPluginPrefs() {
|
|
|
31001
31311
|
}
|
|
31002
31312
|
function writePluginPrefs(prefs) {
|
|
31003
31313
|
const file2 = getPluginPrefsPath();
|
|
31004
|
-
mkdirSync11(
|
|
31314
|
+
mkdirSync11(path30.dirname(file2), { recursive: true });
|
|
31005
31315
|
writeFileSync16(file2, JSON.stringify(prefs, null, 2), {
|
|
31006
31316
|
encoding: "utf-8",
|
|
31007
31317
|
mode: 384
|
|
@@ -31038,7 +31348,7 @@ __export(registry_exports, {
|
|
|
31038
31348
|
isBinaryOnPath: () => isBinaryOnPath
|
|
31039
31349
|
});
|
|
31040
31350
|
import { existsSync as existsSync29 } from "node:fs";
|
|
31041
|
-
import
|
|
31351
|
+
import path31 from "node:path";
|
|
31042
31352
|
function detectLocalBin(bin) {
|
|
31043
31353
|
return (cwd) => {
|
|
31044
31354
|
try {
|
|
@@ -31056,7 +31366,7 @@ function isBinaryOnPath(bin, opts = {}) {
|
|
|
31056
31366
|
const platform = opts.platform ?? process.platform;
|
|
31057
31367
|
const exists = opts.exists ?? existsSync29;
|
|
31058
31368
|
const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
|
|
31059
|
-
const pathMod = platform === "win32" ?
|
|
31369
|
+
const pathMod = platform === "win32" ? path31.win32 : path31.posix;
|
|
31060
31370
|
const sep = platform === "win32" ? ";" : ":";
|
|
31061
31371
|
const dirs = pathEnv.split(sep).filter((d) => d.length > 0);
|
|
31062
31372
|
const candidates = [bin];
|
|
@@ -31208,11 +31518,11 @@ import { execSync as execSync2 } from "node:child_process";
|
|
|
31208
31518
|
import { existsSync as existsSync35, readFileSync as readFileSync30, readlinkSync, statSync as statSync6 } from "node:fs";
|
|
31209
31519
|
import { createRequire as createRequire3 } from "node:module";
|
|
31210
31520
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
31211
|
-
import
|
|
31521
|
+
import path36 from "node:path";
|
|
31212
31522
|
function findPackageRoot(start) {
|
|
31213
31523
|
let dir = start;
|
|
31214
31524
|
for (let i = 0; i < 6; i += 1) {
|
|
31215
|
-
const candidate =
|
|
31525
|
+
const candidate = path36.join(dir, "package.json");
|
|
31216
31526
|
if (existsSync35(candidate)) {
|
|
31217
31527
|
try {
|
|
31218
31528
|
const pkg = JSON.parse(readFileSync30(candidate, "utf8"));
|
|
@@ -31220,11 +31530,11 @@ function findPackageRoot(start) {
|
|
|
31220
31530
|
} catch {
|
|
31221
31531
|
}
|
|
31222
31532
|
}
|
|
31223
|
-
const parent =
|
|
31533
|
+
const parent = path36.dirname(dir);
|
|
31224
31534
|
if (parent === dir) break;
|
|
31225
31535
|
dir = parent;
|
|
31226
31536
|
}
|
|
31227
|
-
return
|
|
31537
|
+
return path36.resolve(__dirname3, "..", "..", "..");
|
|
31228
31538
|
}
|
|
31229
31539
|
function tryExec(cmd) {
|
|
31230
31540
|
try {
|
|
@@ -31238,7 +31548,7 @@ function tryExec(cmd) {
|
|
|
31238
31548
|
}
|
|
31239
31549
|
function readPackageJson3() {
|
|
31240
31550
|
try {
|
|
31241
|
-
const pkgPath =
|
|
31551
|
+
const pkgPath = path36.join(packageRoot, "package.json");
|
|
31242
31552
|
return JSON.parse(readFileSync30(pkgPath, "utf8"));
|
|
31243
31553
|
} catch {
|
|
31244
31554
|
return null;
|
|
@@ -31254,7 +31564,7 @@ function checkShim(pkgName) {
|
|
|
31254
31564
|
}
|
|
31255
31565
|
const isWin = process.platform === "win32";
|
|
31256
31566
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
31257
|
-
const shimPath =
|
|
31567
|
+
const shimPath = path36.join(prefix, shimName);
|
|
31258
31568
|
if (!existsSync35(shimPath)) {
|
|
31259
31569
|
return FAIL(
|
|
31260
31570
|
`shim not found at ${shimPath}
|
|
@@ -31282,8 +31592,8 @@ function checkShim(pkgName) {
|
|
|
31282
31592
|
fix: npm install -g ${pkgName}@latest --force`
|
|
31283
31593
|
);
|
|
31284
31594
|
}
|
|
31285
|
-
const resolved =
|
|
31286
|
-
const expected =
|
|
31595
|
+
const resolved = path36.resolve(path36.dirname(shimPath), target);
|
|
31596
|
+
const expected = path36.join(
|
|
31287
31597
|
prefix,
|
|
31288
31598
|
"node_modules",
|
|
31289
31599
|
pkgName,
|
|
@@ -31322,7 +31632,7 @@ function checkNode(pkg) {
|
|
|
31322
31632
|
return OK(`node ${raw}`);
|
|
31323
31633
|
}
|
|
31324
31634
|
function checkBundle() {
|
|
31325
|
-
const bundle =
|
|
31635
|
+
const bundle = path36.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
31326
31636
|
if (!existsSync35(bundle)) {
|
|
31327
31637
|
return FAIL(
|
|
31328
31638
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
@@ -31343,7 +31653,7 @@ function checkRuntimeDeps() {
|
|
|
31343
31653
|
const missing = [];
|
|
31344
31654
|
for (const dep of required2) {
|
|
31345
31655
|
try {
|
|
31346
|
-
const localReq = createRequire3(
|
|
31656
|
+
const localReq = createRequire3(path36.join(packageRoot, "package.json"));
|
|
31347
31657
|
localReq.resolve(dep);
|
|
31348
31658
|
} catch {
|
|
31349
31659
|
missing.push(dep);
|
|
@@ -31464,7 +31774,7 @@ var init_doctor = __esm({
|
|
|
31464
31774
|
"use strict";
|
|
31465
31775
|
init_prereqChecks();
|
|
31466
31776
|
require3 = createRequire3(import.meta.url);
|
|
31467
|
-
__dirname3 =
|
|
31777
|
+
__dirname3 = path36.dirname(fileURLToPath2(import.meta.url));
|
|
31468
31778
|
packageRoot = findPackageRoot(__dirname3);
|
|
31469
31779
|
OK = (message) => ({
|
|
31470
31780
|
ok: true,
|
|
@@ -34512,6 +34822,91 @@ registerCodingSkill(writeUnitTests);
|
|
|
34512
34822
|
registerCodingSkill(writeIntegrationTests);
|
|
34513
34823
|
registerCodingSkill(regressionTest);
|
|
34514
34824
|
|
|
34825
|
+
// packages/core/dist/agents/skills/builtin/schemaLoop.js
|
|
34826
|
+
init_skills();
|
|
34827
|
+
var schemaLoop = {
|
|
34828
|
+
id: "schema-loop",
|
|
34829
|
+
version: "1.0.0",
|
|
34830
|
+
name: "Schema Loop (certify before done)",
|
|
34831
|
+
description: "Physicist-style coding harness: keep an explicit hypothesis, define certifiable checks, run_backtest before claiming done, and treat prediction mismatches as plan-voiding surprises. When \u22652 hypotheses remain, run one discriminating experiment first.",
|
|
34832
|
+
category: "debug",
|
|
34833
|
+
requiredRoles: [],
|
|
34834
|
+
requiredTools: [
|
|
34835
|
+
"update_world_hypothesis",
|
|
34836
|
+
"set_world_checks",
|
|
34837
|
+
"run_backtest",
|
|
34838
|
+
"record_world_observation",
|
|
34839
|
+
"bash",
|
|
34840
|
+
"read_file"
|
|
34841
|
+
],
|
|
34842
|
+
estimatedCost: "medium",
|
|
34843
|
+
enabledByDefault: true,
|
|
34844
|
+
builtin: true,
|
|
34845
|
+
triggers: [
|
|
34846
|
+
"Non-trivial bug or multi-step implementation",
|
|
34847
|
+
"You are about to claim the task is done",
|
|
34848
|
+
"Tests or typecheck failed after edits",
|
|
34849
|
+
"Two or more competing root-cause hypotheses",
|
|
34850
|
+
"Surprising tool result (wrong exit code, missing path, shell mismatch)"
|
|
34851
|
+
],
|
|
34852
|
+
antiPatterns: [
|
|
34853
|
+
"Trivial one-line typo fix with no uncertainty",
|
|
34854
|
+
"Pure documentation rewrite with no behavior change",
|
|
34855
|
+
"User explicitly asked for a draft-only answer without running tools"
|
|
34856
|
+
],
|
|
34857
|
+
requires: [],
|
|
34858
|
+
relatedSkills: ["debug-with-rag", "root-cause-five-whys", "reproduce-bug"],
|
|
34859
|
+
tags: ["schema", "backtest", "hypothesis", "verify", "world-model", "debug"],
|
|
34860
|
+
examples: [
|
|
34861
|
+
{
|
|
34862
|
+
input: "Fix the flaky headless test timeout",
|
|
34863
|
+
output: {
|
|
34864
|
+
hypothesis: "Test hangs because registerMcpTools spawns real MCP servers; default 5s timeout is too low.",
|
|
34865
|
+
checks: [
|
|
34866
|
+
{ id: "unit", command: "npx vitest run tests/unit/cli-useChatTurn.test.ts" }
|
|
34867
|
+
],
|
|
34868
|
+
next: "set_world_checks \u2192 implement isolation \u2192 run_backtest \u2192 only then claim done"
|
|
34869
|
+
}
|
|
34870
|
+
}
|
|
34871
|
+
],
|
|
34872
|
+
outputSchema: "{ hypothesis: string; checks: Array<{ id: string; command: string }>; backtestOk: boolean; surprises?: string[] }",
|
|
34873
|
+
systemPromptFragment: `You are running the **Schema Loop** adapted for software engineering
|
|
34874
|
+
(inspired by Schema harness / ARC world-models \u2014 but for repos, not grids).
|
|
34875
|
+
|
|
34876
|
+
## Core idea
|
|
34877
|
+
The latent model of the task is **explicit files under .zelari/world/**, not only chat context:
|
|
34878
|
+
- hypothesis.md \u2014 what you believe (objects = modules, mechanism = bug cause / design)
|
|
34879
|
+
- checks.json \u2014 certifiable shell checks (the "reality" oracle)
|
|
34880
|
+
- timeline.jsonl \u2014 append-only observations (do not rewrite history)
|
|
34881
|
+
|
|
34882
|
+
## Outer loop
|
|
34883
|
+
1. **observe** \u2014 read errors, failing tests, tool results
|
|
34884
|
+
2. **deliberate** \u2014 update_world_hypothesis; set_world_checks
|
|
34885
|
+
3. **execute** \u2014 edit/run tools to change the repo
|
|
34886
|
+
4. **record** \u2014 record_world_observation on surprises; run_backtest to certify
|
|
34887
|
+
|
|
34888
|
+
## Hard rules (reality outranks the model)
|
|
34889
|
+
1. **Never claim done** while the latest run_backtest has ok=false or total=0 without checks.
|
|
34890
|
+
2. After any batch of write/edit, prefer run_backtest (or set checks then backtest) before asserting success.
|
|
34891
|
+
3. **Surprise = void plan**: if a command exits unexpectedly, shell rejects POSIX on Windows, path missing, or tests fail differently than predicted \u2014 call record_world_observation (kind=surprise), revise hypothesis, do not keep patching blindly.
|
|
34892
|
+
4. **Discovery actions**: when \u22652 hypotheses remain consistent with evidence, design ONE discriminating experiment (read/grep/test) whose outcomes diverge; do not spray random edits.
|
|
34893
|
+
5. Prefer fast checks (single-file vitest, typecheck) over full suite until the model is stable.
|
|
34894
|
+
|
|
34895
|
+
## Predict-then-act (soft)
|
|
34896
|
+
Before a risky bash/edit, state a short prediction in hypothesis or observation
|
|
34897
|
+
(expect exit 0, files touched). After the tool, if reality mismatches, log surprise.
|
|
34898
|
+
|
|
34899
|
+
## Tools
|
|
34900
|
+
- update_world_hypothesis \u2014 write/append theory
|
|
34901
|
+
- set_world_checks \u2014 define certifiable commands
|
|
34902
|
+
- run_backtest \u2014 replay all checks; report exact pass/fail
|
|
34903
|
+
- record_world_observation \u2014 timeline ground truth
|
|
34904
|
+
|
|
34905
|
+
Kill switch for tools: ZELARI_SCHEMA_LOOP=0.
|
|
34906
|
+
${""}`
|
|
34907
|
+
};
|
|
34908
|
+
registerCodingSkill(schemaLoop);
|
|
34909
|
+
|
|
34515
34910
|
// src/cli/app.tsx
|
|
34516
34911
|
init_providerConfig();
|
|
34517
34912
|
init_harness();
|
|
@@ -36914,7 +37309,7 @@ ${formatSkillList(availableSkills)}`
|
|
|
36914
37309
|
// src/cli/gitOps.ts
|
|
36915
37310
|
import { execFile as execFile3 } from "node:child_process";
|
|
36916
37311
|
import { promisify as promisify2 } from "node:util";
|
|
36917
|
-
import
|
|
37312
|
+
import path29 from "node:path";
|
|
36918
37313
|
var execFileAsync2 = promisify2(execFile3);
|
|
36919
37314
|
async function git2(cwd, args) {
|
|
36920
37315
|
try {
|
|
@@ -36960,7 +37355,7 @@ async function undoWorkingChanges(opts = {}) {
|
|
|
36960
37355
|
};
|
|
36961
37356
|
}
|
|
36962
37357
|
function defaultProjectRoot() {
|
|
36963
|
-
return
|
|
37358
|
+
return path29.resolve(__dirname, "..", "..", "..");
|
|
36964
37359
|
}
|
|
36965
37360
|
|
|
36966
37361
|
// src/cli/slashHandlers/git.ts
|
|
@@ -37269,8 +37664,8 @@ init_registry2();
|
|
|
37269
37664
|
// src/cli/plugins/installer.ts
|
|
37270
37665
|
init_cmdline();
|
|
37271
37666
|
init_updater();
|
|
37272
|
-
import { spawn as
|
|
37273
|
-
async function installPlugin(spec, cwd, executor =
|
|
37667
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
37668
|
+
async function installPlugin(spec, cwd, executor = spawn10) {
|
|
37274
37669
|
const scopeFlag = spec.installScope === "global" ? "-g" : "-D";
|
|
37275
37670
|
const args = ["install", scopeFlag, spec.npmPackage];
|
|
37276
37671
|
const primary = await runNpm2(executor, args, cwd, "shim");
|
|
@@ -37371,17 +37766,17 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
|
|
|
37371
37766
|
}
|
|
37372
37767
|
|
|
37373
37768
|
// src/cli/slashHandlers/promoteMember.ts
|
|
37374
|
-
import { promises as
|
|
37375
|
-
import
|
|
37769
|
+
import { promises as fs17 } from "node:fs";
|
|
37770
|
+
import path32 from "node:path";
|
|
37376
37771
|
import os10 from "node:os";
|
|
37377
37772
|
async function handlePromoteMember(ctx, memberId) {
|
|
37378
37773
|
try {
|
|
37379
37774
|
const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
37380
37775
|
const { skill, markdown } = promoteMember2(memberId);
|
|
37381
|
-
const skillDir = process.env.ANATHEMA_SKILL_DIR ??
|
|
37382
|
-
await
|
|
37383
|
-
const filePath =
|
|
37384
|
-
await
|
|
37776
|
+
const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path32.join(os10.homedir(), ".tmp", "zelari-code", "skills");
|
|
37777
|
+
await fs17.mkdir(skillDir, { recursive: true });
|
|
37778
|
+
const filePath = path32.join(skillDir, `${skill.id}.md`);
|
|
37779
|
+
await fs17.writeFile(filePath, markdown, "utf8");
|
|
37385
37780
|
appendSystem(
|
|
37386
37781
|
ctx.setMessages,
|
|
37387
37782
|
`[promote-member] ${skill.name} (${memberId}) \u2192 ${filePath}
|
|
@@ -37397,25 +37792,25 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
37397
37792
|
}
|
|
37398
37793
|
|
|
37399
37794
|
// src/cli/branchManager.ts
|
|
37400
|
-
import { promises as
|
|
37401
|
-
import
|
|
37795
|
+
import { promises as fs18, existsSync as existsSync30, readFileSync as readFileSync26, writeFileSync as writeFileSync17, mkdirSync as mkdirSync12, statSync as statSync4, rmSync as rmSync2 } from "node:fs";
|
|
37796
|
+
import path33 from "node:path";
|
|
37402
37797
|
import os11 from "node:os";
|
|
37403
37798
|
var META_FILENAME = "meta.json";
|
|
37404
37799
|
var SESSIONS_SUBDIR = "sessions";
|
|
37405
37800
|
function getBranchesBaseDir() {
|
|
37406
|
-
return process.env.ANATHEMA_BRANCHES_DIR ??
|
|
37801
|
+
return process.env.ANATHEMA_BRANCHES_DIR ?? path33.join(os11.homedir(), ".tmp", "zelari-code", "branches");
|
|
37407
37802
|
}
|
|
37408
37803
|
function getSessionsBaseDir() {
|
|
37409
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
37804
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path33.join(os11.homedir(), ".tmp", "zelari-code", "sessions");
|
|
37410
37805
|
}
|
|
37411
37806
|
function branchPathFor(name, baseDir) {
|
|
37412
|
-
return
|
|
37807
|
+
return path33.join(baseDir, name);
|
|
37413
37808
|
}
|
|
37414
37809
|
function metaPathFor(name, baseDir) {
|
|
37415
|
-
return
|
|
37810
|
+
return path33.join(baseDir, name, META_FILENAME);
|
|
37416
37811
|
}
|
|
37417
37812
|
function sessionsPathFor(name, baseDir) {
|
|
37418
|
-
return
|
|
37813
|
+
return path33.join(baseDir, name, SESSIONS_SUBDIR);
|
|
37419
37814
|
}
|
|
37420
37815
|
function readBranchMeta(name, baseDir) {
|
|
37421
37816
|
const metaPath = metaPathFor(name, baseDir);
|
|
@@ -37440,13 +37835,13 @@ function readBranchMeta(name, baseDir) {
|
|
|
37440
37835
|
}
|
|
37441
37836
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
37442
37837
|
const metaPath = metaPathFor(name, baseDir);
|
|
37443
|
-
mkdirSync12(
|
|
37838
|
+
mkdirSync12(path33.dirname(metaPath), { recursive: true });
|
|
37444
37839
|
writeFileSync17(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
37445
37840
|
}
|
|
37446
37841
|
async function countSessions(name, baseDir) {
|
|
37447
37842
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
37448
37843
|
try {
|
|
37449
|
-
const entries = await
|
|
37844
|
+
const entries = await fs18.readdir(sessionsPath);
|
|
37450
37845
|
return entries.filter((e) => e.endsWith(".jsonl")).length;
|
|
37451
37846
|
} catch (err) {
|
|
37452
37847
|
if (err.code === "ENOENT") return 0;
|
|
@@ -37491,15 +37886,15 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
37491
37886
|
if (branchExists(name, baseDir)) {
|
|
37492
37887
|
throw new BranchAlreadyExistsError(name);
|
|
37493
37888
|
}
|
|
37494
|
-
const sourcePath =
|
|
37889
|
+
const sourcePath = path33.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
37495
37890
|
if (!existsSync30(sourcePath)) {
|
|
37496
37891
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
37497
37892
|
}
|
|
37498
37893
|
const branchPath = branchPathFor(name, baseDir);
|
|
37499
37894
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
37500
37895
|
mkdirSync12(branchSessionsPath, { recursive: true });
|
|
37501
|
-
const destPath =
|
|
37502
|
-
await
|
|
37896
|
+
const destPath = path33.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
37897
|
+
await fs18.copyFile(sourcePath, destPath);
|
|
37503
37898
|
const meta3 = {
|
|
37504
37899
|
name,
|
|
37505
37900
|
createdAt: Date.now(),
|
|
@@ -37517,7 +37912,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
37517
37912
|
async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
37518
37913
|
let entries;
|
|
37519
37914
|
try {
|
|
37520
|
-
entries = await
|
|
37915
|
+
entries = await fs18.readdir(baseDir);
|
|
37521
37916
|
} catch (err) {
|
|
37522
37917
|
if (err.code === "ENOENT") return [];
|
|
37523
37918
|
throw err;
|
|
@@ -37598,26 +37993,26 @@ async function handleBranchCheckout(ctx, branchName) {
|
|
|
37598
37993
|
}
|
|
37599
37994
|
|
|
37600
37995
|
// src/cli/slashHandlers/workspace.ts
|
|
37601
|
-
import { promises as
|
|
37602
|
-
import
|
|
37996
|
+
import { promises as fs19 } from "node:fs";
|
|
37997
|
+
import path34 from "node:path";
|
|
37603
37998
|
async function handleWorkspaceShow(ctx, what) {
|
|
37604
37999
|
try {
|
|
37605
|
-
const zelari =
|
|
38000
|
+
const zelari = path34.join(process.cwd(), ".zelari");
|
|
37606
38001
|
let content;
|
|
37607
38002
|
switch (what) {
|
|
37608
38003
|
case "plan": {
|
|
37609
|
-
const planPath =
|
|
38004
|
+
const planPath = path34.join(zelari, "plan.md");
|
|
37610
38005
|
try {
|
|
37611
|
-
content = await
|
|
38006
|
+
content = await fs19.readFile(planPath, "utf-8");
|
|
37612
38007
|
} catch {
|
|
37613
38008
|
content = "(no plan.md yet \u2014 run a council session first)";
|
|
37614
38009
|
}
|
|
37615
38010
|
break;
|
|
37616
38011
|
}
|
|
37617
38012
|
case "decisions": {
|
|
37618
|
-
const decisionsDir =
|
|
38013
|
+
const decisionsDir = path34.join(zelari, "decisions");
|
|
37619
38014
|
try {
|
|
37620
|
-
const files = (await
|
|
38015
|
+
const files = (await fs19.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
37621
38016
|
if (files.length === 0) {
|
|
37622
38017
|
content = "(no ADRs yet \u2014 invoke /council to generate some)";
|
|
37623
38018
|
} else {
|
|
@@ -37625,7 +38020,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
37625
38020
|
`];
|
|
37626
38021
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
37627
38022
|
for (const f of files) {
|
|
37628
|
-
const raw = await
|
|
38023
|
+
const raw = await fs19.readFile(path34.join(decisionsDir, f), "utf-8");
|
|
37629
38024
|
const { meta: meta3, body } = parseFrontmatter2(raw);
|
|
37630
38025
|
const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
|
|
37631
38026
|
lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
|
|
@@ -37638,27 +38033,27 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
37638
38033
|
break;
|
|
37639
38034
|
}
|
|
37640
38035
|
case "risks": {
|
|
37641
|
-
const risksPath =
|
|
38036
|
+
const risksPath = path34.join(zelari, "risks.md");
|
|
37642
38037
|
try {
|
|
37643
|
-
content = await
|
|
38038
|
+
content = await fs19.readFile(risksPath, "utf-8");
|
|
37644
38039
|
} catch {
|
|
37645
38040
|
content = "(no risks.md yet)";
|
|
37646
38041
|
}
|
|
37647
38042
|
break;
|
|
37648
38043
|
}
|
|
37649
38044
|
case "agents": {
|
|
37650
|
-
const agentsPath =
|
|
38045
|
+
const agentsPath = path34.join(process.cwd(), "AGENTS.MD");
|
|
37651
38046
|
try {
|
|
37652
|
-
content = await
|
|
38047
|
+
content = await fs19.readFile(agentsPath, "utf-8");
|
|
37653
38048
|
} catch {
|
|
37654
38049
|
content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
|
|
37655
38050
|
}
|
|
37656
38051
|
break;
|
|
37657
38052
|
}
|
|
37658
38053
|
case "docs": {
|
|
37659
|
-
const docsDir =
|
|
38054
|
+
const docsDir = path34.join(zelari, "docs");
|
|
37660
38055
|
try {
|
|
37661
|
-
const files = (await
|
|
38056
|
+
const files = (await fs19.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
37662
38057
|
content = files.length ? `# Docs (${files.length})
|
|
37663
38058
|
|
|
37664
38059
|
` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
|
|
@@ -37698,8 +38093,8 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
37698
38093
|
return;
|
|
37699
38094
|
}
|
|
37700
38095
|
try {
|
|
37701
|
-
const target =
|
|
37702
|
-
await
|
|
38096
|
+
const target = path34.join(process.cwd(), ".zelari");
|
|
38097
|
+
await fs19.rm(target, { recursive: true, force: true });
|
|
37703
38098
|
appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
|
|
37704
38099
|
} catch (err) {
|
|
37705
38100
|
appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -38057,16 +38452,16 @@ function handleModelsRefresh(ctx) {
|
|
|
38057
38452
|
}
|
|
38058
38453
|
|
|
38059
38454
|
// src/cli/slashHandlers/skills.ts
|
|
38060
|
-
import
|
|
38455
|
+
import path35 from "node:path";
|
|
38061
38456
|
import os12 from "node:os";
|
|
38062
38457
|
|
|
38063
38458
|
// src/cli/skillHistory.ts
|
|
38064
|
-
import { promises as
|
|
38459
|
+
import { promises as fs20, existsSync as existsSync31, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync13 } from "node:fs";
|
|
38065
38460
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
38066
38461
|
async function readSkillHistory(file2) {
|
|
38067
38462
|
let raw = "";
|
|
38068
38463
|
try {
|
|
38069
|
-
raw = await
|
|
38464
|
+
raw = await fs20.readFile(file2, "utf-8");
|
|
38070
38465
|
} catch {
|
|
38071
38466
|
return [];
|
|
38072
38467
|
}
|
|
@@ -38159,7 +38554,7 @@ async function applySteerInterrupt(options) {
|
|
|
38159
38554
|
|
|
38160
38555
|
// src/cli/slashHandlers/skills.ts
|
|
38161
38556
|
async function handleSkillStats(ctx, skillId) {
|
|
38162
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
38557
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path35.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
38163
38558
|
try {
|
|
38164
38559
|
const records = await readSkillHistory(historyFile);
|
|
38165
38560
|
const stats = getSkillStats(records, skillId);
|
|
@@ -38175,7 +38570,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
|
|
|
38175
38570
|
appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
|
|
38176
38571
|
return;
|
|
38177
38572
|
}
|
|
38178
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
38573
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path35.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
38179
38574
|
try {
|
|
38180
38575
|
const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
|
|
38181
38576
|
appendSystem(ctx.setMessages, formatted);
|
|
@@ -40757,10 +41152,10 @@ function getUserMcpPath() {
|
|
|
40757
41152
|
function getProjectMcpPath(projectRoot) {
|
|
40758
41153
|
return join26(projectRoot, ".zelari", "mcp.json");
|
|
40759
41154
|
}
|
|
40760
|
-
function readFile3(
|
|
40761
|
-
if (!existsSync34(
|
|
41155
|
+
function readFile3(path37) {
|
|
41156
|
+
if (!existsSync34(path37)) return {};
|
|
40762
41157
|
try {
|
|
40763
|
-
const parsed = JSON.parse(readFileSync29(
|
|
41158
|
+
const parsed = JSON.parse(readFileSync29(path37, "utf8"));
|
|
40764
41159
|
const out = {};
|
|
40765
41160
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
40766
41161
|
if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
|
|
@@ -40776,10 +41171,10 @@ function readFile3(path36) {
|
|
|
40776
41171
|
return {};
|
|
40777
41172
|
}
|
|
40778
41173
|
}
|
|
40779
|
-
function writeFile(
|
|
40780
|
-
mkdirSync14(dirname6(
|
|
41174
|
+
function writeFile(path37, servers) {
|
|
41175
|
+
mkdirSync14(dirname6(path37), { recursive: true });
|
|
40781
41176
|
const body = { mcpServers: servers };
|
|
40782
|
-
writeFileSync18(
|
|
41177
|
+
writeFileSync18(path37, `${JSON.stringify(body, null, 2)}
|
|
40783
41178
|
`, "utf8");
|
|
40784
41179
|
}
|
|
40785
41180
|
function listMcpServers(projectRoot) {
|
|
@@ -40812,9 +41207,9 @@ function upsertMcpServer(opts) {
|
|
|
40812
41207
|
if (!opts.config.command?.trim()) {
|
|
40813
41208
|
return { ok: false, error: "command is required" };
|
|
40814
41209
|
}
|
|
40815
|
-
let
|
|
41210
|
+
let path37;
|
|
40816
41211
|
if (opts.scope === "user") {
|
|
40817
|
-
|
|
41212
|
+
path37 = getUserMcpPath();
|
|
40818
41213
|
} else {
|
|
40819
41214
|
const root = opts.projectRoot?.trim();
|
|
40820
41215
|
if (!root) {
|
|
@@ -40823,30 +41218,30 @@ function upsertMcpServer(opts) {
|
|
|
40823
41218
|
error: "projectRoot required for project scope (Open Folder first)"
|
|
40824
41219
|
};
|
|
40825
41220
|
}
|
|
40826
|
-
|
|
41221
|
+
path37 = getProjectMcpPath(root);
|
|
40827
41222
|
}
|
|
40828
|
-
const current = readFile3(
|
|
41223
|
+
const current = readFile3(path37);
|
|
40829
41224
|
current[name] = {
|
|
40830
41225
|
command: opts.config.command.trim(),
|
|
40831
41226
|
args: opts.config.args,
|
|
40832
41227
|
env: opts.config.env,
|
|
40833
41228
|
enabled: opts.config.enabled !== false
|
|
40834
41229
|
};
|
|
40835
|
-
writeFile(
|
|
40836
|
-
return { ok: true, path:
|
|
41230
|
+
writeFile(path37, current);
|
|
41231
|
+
return { ok: true, path: path37 };
|
|
40837
41232
|
}
|
|
40838
41233
|
function removeMcpServer(opts) {
|
|
40839
|
-
const
|
|
40840
|
-
if (!
|
|
41234
|
+
const path37 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
|
|
41235
|
+
if (!path37) {
|
|
40841
41236
|
return { ok: false, error: "projectRoot required for project scope" };
|
|
40842
41237
|
}
|
|
40843
|
-
const current = readFile3(
|
|
41238
|
+
const current = readFile3(path37);
|
|
40844
41239
|
if (!(opts.name in current)) {
|
|
40845
|
-
return { ok: false, error: `Server "${opts.name}" not found in ${
|
|
41240
|
+
return { ok: false, error: `Server "${opts.name}" not found in ${path37}` };
|
|
40846
41241
|
}
|
|
40847
41242
|
delete current[opts.name];
|
|
40848
|
-
writeFile(
|
|
40849
|
-
return { ok: true, path:
|
|
41243
|
+
writeFile(path37, current);
|
|
41244
|
+
return { ok: true, path: path37 };
|
|
40850
41245
|
}
|
|
40851
41246
|
|
|
40852
41247
|
// src/cli/main.ts
|