zelari-code 2.41.0 → 2.43.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/headless.js.map +1 -1
- package/dist/cli/main.bundled.js +1208 -873
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +16 -4
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/mcpClient.js +9 -1
- package/dist/cli/mcp/mcpClient.js.map +1 -1
- package/dist/cli/mcp/mcpConfigIo.js +65 -1
- package/dist/cli/mcp/mcpConfigIo.js.map +1 -1
- package/dist/cli/mcp/mcpManager.js +1 -1
- package/dist/cli/mcp/mcpManager.js.map +1 -1
- package/dist/cli/runHeadless.js +20 -3
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/safety/toolPermissions.js +8 -2
- package/dist/cli/safety/toolPermissions.js.map +1 -1
- package/dist/cli/serve/harnessServer.js +42 -2
- package/dist/cli/serve/harnessServer.js.map +1 -1
- package/dist/cli/toolRegistry.js +77 -4
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/createSkillTool.js +156 -0
- package/dist/cli/tools/createSkillTool.js.map +1 -0
- package/dist/cli/tools/krakenRadio.js +26 -1
- package/dist/cli/tools/krakenRadio.js.map +1 -1
- package/dist/cli/tools/taskTool.js +25 -1
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/package.json +4 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -807,7 +807,7 @@ async function openBrowser(url2) {
|
|
|
807
807
|
return { bin: "xdg-open", args: [url2] };
|
|
808
808
|
}
|
|
809
809
|
})();
|
|
810
|
-
return new Promise((
|
|
810
|
+
return new Promise((resolve10, reject) => {
|
|
811
811
|
try {
|
|
812
812
|
const child = spawn19(cmd.bin, cmd.args, {
|
|
813
813
|
stdio: "ignore",
|
|
@@ -816,9 +816,9 @@ async function openBrowser(url2) {
|
|
|
816
816
|
child.on("error", (err) => reject(err));
|
|
817
817
|
child.on("spawn", () => {
|
|
818
818
|
child.unref();
|
|
819
|
-
|
|
819
|
+
resolve10();
|
|
820
820
|
});
|
|
821
|
-
setTimeout(() =>
|
|
821
|
+
setTimeout(() => resolve10(), 100);
|
|
822
822
|
} catch (err) {
|
|
823
823
|
reject(err);
|
|
824
824
|
}
|
|
@@ -867,7 +867,7 @@ async function waitForLoopbackCallback(options) {
|
|
|
867
867
|
const host = options.host ?? "127.0.0.1";
|
|
868
868
|
const timeoutMs2 = options.timeoutMs ?? 3e5;
|
|
869
869
|
const expectedPath = options.path.startsWith("/") ? options.path : `/${options.path}`;
|
|
870
|
-
return new Promise((
|
|
870
|
+
return new Promise((resolve10, reject) => {
|
|
871
871
|
let settled = false;
|
|
872
872
|
const server = createServer((req, res) => {
|
|
873
873
|
const url2 = new URL(req.url ?? "/", `http://${host}`);
|
|
@@ -896,7 +896,7 @@ async function waitForLoopbackCallback(options) {
|
|
|
896
896
|
clearTimeout(timer);
|
|
897
897
|
server.close(() => {
|
|
898
898
|
if (err) reject(err);
|
|
899
|
-
else
|
|
899
|
+
else resolve10(value ?? {});
|
|
900
900
|
});
|
|
901
901
|
};
|
|
902
902
|
server.on("error", (err) => finish2(void 0, err));
|
|
@@ -3482,10 +3482,10 @@ function mergeDefs(...defs) {
|
|
|
3482
3482
|
function cloneDef(schema) {
|
|
3483
3483
|
return mergeDefs(schema._zod.def);
|
|
3484
3484
|
}
|
|
3485
|
-
function getElementAtPath(obj,
|
|
3486
|
-
if (!
|
|
3485
|
+
function getElementAtPath(obj, path104) {
|
|
3486
|
+
if (!path104)
|
|
3487
3487
|
return obj;
|
|
3488
|
-
return
|
|
3488
|
+
return path104.reduce((acc, key) => acc?.[key], obj);
|
|
3489
3489
|
}
|
|
3490
3490
|
function promiseAllObject(promisesObj) {
|
|
3491
3491
|
const keys = Object.keys(promisesObj);
|
|
@@ -3813,11 +3813,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
3813
3813
|
}
|
|
3814
3814
|
return false;
|
|
3815
3815
|
}
|
|
3816
|
-
function prefixIssues(
|
|
3816
|
+
function prefixIssues(path104, issues) {
|
|
3817
3817
|
return issues.map((iss) => {
|
|
3818
3818
|
var _a3;
|
|
3819
3819
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
3820
|
-
iss.path.unshift(
|
|
3820
|
+
iss.path.unshift(path104);
|
|
3821
3821
|
return iss;
|
|
3822
3822
|
});
|
|
3823
3823
|
}
|
|
@@ -4035,16 +4035,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
4035
4035
|
}
|
|
4036
4036
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
4037
4037
|
const fieldErrors = { _errors: [] };
|
|
4038
|
-
const processError = (error52,
|
|
4038
|
+
const processError = (error52, path104 = []) => {
|
|
4039
4039
|
for (const issue2 of error52.issues) {
|
|
4040
4040
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
4041
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4041
|
+
issue2.errors.map((issues) => processError({ issues }, [...path104, ...issue2.path]));
|
|
4042
4042
|
} else if (issue2.code === "invalid_key") {
|
|
4043
|
-
processError({ issues: issue2.issues }, [...
|
|
4043
|
+
processError({ issues: issue2.issues }, [...path104, ...issue2.path]);
|
|
4044
4044
|
} else if (issue2.code === "invalid_element") {
|
|
4045
|
-
processError({ issues: issue2.issues }, [...
|
|
4045
|
+
processError({ issues: issue2.issues }, [...path104, ...issue2.path]);
|
|
4046
4046
|
} else {
|
|
4047
|
-
const fullpath = [...
|
|
4047
|
+
const fullpath = [...path104, ...issue2.path];
|
|
4048
4048
|
if (fullpath.length === 0) {
|
|
4049
4049
|
fieldErrors._errors.push(mapper(issue2));
|
|
4050
4050
|
} else {
|
|
@@ -4071,17 +4071,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
4071
4071
|
}
|
|
4072
4072
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
4073
4073
|
const result = { errors: [] };
|
|
4074
|
-
const processError = (error52,
|
|
4074
|
+
const processError = (error52, path104 = []) => {
|
|
4075
4075
|
var _a3, _b;
|
|
4076
4076
|
for (const issue2 of error52.issues) {
|
|
4077
4077
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
4078
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
4078
|
+
issue2.errors.map((issues) => processError({ issues }, [...path104, ...issue2.path]));
|
|
4079
4079
|
} else if (issue2.code === "invalid_key") {
|
|
4080
|
-
processError({ issues: issue2.issues }, [...
|
|
4080
|
+
processError({ issues: issue2.issues }, [...path104, ...issue2.path]);
|
|
4081
4081
|
} else if (issue2.code === "invalid_element") {
|
|
4082
|
-
processError({ issues: issue2.issues }, [...
|
|
4082
|
+
processError({ issues: issue2.issues }, [...path104, ...issue2.path]);
|
|
4083
4083
|
} else {
|
|
4084
|
-
const fullpath = [...
|
|
4084
|
+
const fullpath = [...path104, ...issue2.path];
|
|
4085
4085
|
if (fullpath.length === 0) {
|
|
4086
4086
|
result.errors.push(mapper(issue2));
|
|
4087
4087
|
continue;
|
|
@@ -4113,8 +4113,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
4113
4113
|
}
|
|
4114
4114
|
function toDotPath(_path) {
|
|
4115
4115
|
const segs = [];
|
|
4116
|
-
const
|
|
4117
|
-
for (const seg of
|
|
4116
|
+
const path104 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
4117
|
+
for (const seg of path104) {
|
|
4118
4118
|
if (typeof seg === "number")
|
|
4119
4119
|
segs.push(`[${seg}]`);
|
|
4120
4120
|
else if (typeof seg === "symbol")
|
|
@@ -17617,13 +17617,13 @@ function resolveRef(ref, ctx) {
|
|
|
17617
17617
|
if (!ref.startsWith("#")) {
|
|
17618
17618
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
17619
17619
|
}
|
|
17620
|
-
const
|
|
17621
|
-
if (
|
|
17620
|
+
const path104 = ref.slice(1).split("/").filter(Boolean);
|
|
17621
|
+
if (path104.length === 0) {
|
|
17622
17622
|
return ctx.rootSchema;
|
|
17623
17623
|
}
|
|
17624
17624
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
17625
|
-
if (
|
|
17626
|
-
const key =
|
|
17625
|
+
if (path104[0] === defsKey) {
|
|
17626
|
+
const key = path104[1];
|
|
17627
17627
|
if (!key || !ctx.defs[key]) {
|
|
17628
17628
|
throw new Error(`Reference not found: ${ref}`);
|
|
17629
17629
|
}
|
|
@@ -18457,17 +18457,17 @@ var init_newlines = __esm({
|
|
|
18457
18457
|
});
|
|
18458
18458
|
|
|
18459
18459
|
// packages/core/dist/core/tools/builtin/fileEvents.js
|
|
18460
|
-
function fileReadEvent(
|
|
18461
|
-
return { kind: "file.read", actor: { type: "tool" }, data: { path:
|
|
18460
|
+
function fileReadEvent(path104, snapshotId) {
|
|
18461
|
+
return { kind: "file.read", actor: { type: "tool" }, data: { path: path104, snapshotId } };
|
|
18462
18462
|
}
|
|
18463
|
-
function fileAppliedEvent(
|
|
18464
|
-
return { kind: "file.applied", actor: { type: "tool" }, data: { path:
|
|
18463
|
+
function fileAppliedEvent(path104, snapshotId, bytes) {
|
|
18464
|
+
return { kind: "file.applied", actor: { type: "tool" }, data: { path: path104, snapshotId, bytes } };
|
|
18465
18465
|
}
|
|
18466
|
-
function fileRejectedEvent(
|
|
18466
|
+
function fileRejectedEvent(path104, reason, hint) {
|
|
18467
18467
|
return {
|
|
18468
18468
|
kind: "file.rejected",
|
|
18469
18469
|
actor: { type: "tool" },
|
|
18470
|
-
data: hint === void 0 ? { path:
|
|
18470
|
+
data: hint === void 0 ? { path: path104, reason } : { path: path104, reason, hint }
|
|
18471
18471
|
};
|
|
18472
18472
|
}
|
|
18473
18473
|
function reReadHint(reject) {
|
|
@@ -19066,12 +19066,12 @@ function withNodeDirOnPath(base2) {
|
|
|
19066
19066
|
const nodeDir = dirname(process.execPath);
|
|
19067
19067
|
if (!nodeDir)
|
|
19068
19068
|
return env;
|
|
19069
|
-
const
|
|
19069
|
+
const sep5 = process.platform === "win32" ? ";" : ":";
|
|
19070
19070
|
const current = env.PATH ?? env.Path ?? "";
|
|
19071
|
-
const parts = current.split(
|
|
19071
|
+
const parts = current.split(sep5).filter((p3) => p3.length > 0);
|
|
19072
19072
|
const has = parts.some((p3) => p3.toLowerCase() === nodeDir.toLowerCase());
|
|
19073
19073
|
if (!has) {
|
|
19074
|
-
env.PATH = `${nodeDir}${
|
|
19074
|
+
env.PATH = `${nodeDir}${sep5}${current}`;
|
|
19075
19075
|
}
|
|
19076
19076
|
} catch {
|
|
19077
19077
|
}
|
|
@@ -19086,7 +19086,7 @@ function createBashTool(spawnSeam) {
|
|
|
19086
19086
|
timeoutMs: 6e4,
|
|
19087
19087
|
inputSchema: BashArgsSchema,
|
|
19088
19088
|
execute: async (args, ctx) => {
|
|
19089
|
-
return new Promise((
|
|
19089
|
+
return new Promise((resolve10) => {
|
|
19090
19090
|
const start = Date.now();
|
|
19091
19091
|
const cwd = args.cwd ?? ctx.cwd;
|
|
19092
19092
|
const resolved = resolveShell();
|
|
@@ -19113,7 +19113,7 @@ function createBashTool(spawnSeam) {
|
|
|
19113
19113
|
if (spawnSeam) {
|
|
19114
19114
|
const seamResult = spawnSeam({ program, argv, cwd, env, signal: ctx.signal });
|
|
19115
19115
|
if (seamResult.outcome !== "spawned") {
|
|
19116
|
-
|
|
19116
|
+
resolve10(typedErr(seamResult.reason));
|
|
19117
19117
|
return;
|
|
19118
19118
|
}
|
|
19119
19119
|
child = seamResult.child;
|
|
@@ -19140,14 +19140,14 @@ function createBashTool(spawnSeam) {
|
|
|
19140
19140
|
});
|
|
19141
19141
|
const timer = setTimeout(() => {
|
|
19142
19142
|
child.kill("SIGTERM");
|
|
19143
|
-
|
|
19143
|
+
resolve10(typedErr(`Bash command timed out after ${args.timeoutMs}ms. If it was waiting for interactive input: stdin is closed \u2014 pass non-interactive flags or create the files directly instead of retrying.`));
|
|
19144
19144
|
}, args.timeoutMs);
|
|
19145
19145
|
child.on("close", (code) => {
|
|
19146
19146
|
clearTimeout(timer);
|
|
19147
19147
|
const cappedStdout = stdout.slice(0, maxBuffer);
|
|
19148
19148
|
const cappedStderr = stderr.slice(0, maxBuffer);
|
|
19149
19149
|
const interactive = INTERACTIVE_CANCEL_RE.test(cappedStdout) || INTERACTIVE_CANCEL_RE.test(cappedStderr);
|
|
19150
|
-
|
|
19150
|
+
resolve10(typedOk({
|
|
19151
19151
|
stdout: cappedStdout,
|
|
19152
19152
|
stderr: cappedStderr,
|
|
19153
19153
|
exitCode: code ?? -1,
|
|
@@ -19159,7 +19159,7 @@ function createBashTool(spawnSeam) {
|
|
|
19159
19159
|
});
|
|
19160
19160
|
child.on("error", (err) => {
|
|
19161
19161
|
clearTimeout(timer);
|
|
19162
|
-
|
|
19162
|
+
resolve10(typedErr(err.message));
|
|
19163
19163
|
});
|
|
19164
19164
|
});
|
|
19165
19165
|
}
|
|
@@ -19304,22 +19304,54 @@ var init_walk = __esm({
|
|
|
19304
19304
|
// packages/core/dist/core/tools/builtin/search.js
|
|
19305
19305
|
import { promises as fs7 } from "node:fs";
|
|
19306
19306
|
import path10 from "node:path";
|
|
19307
|
+
function cleanGlobFragment(g) {
|
|
19308
|
+
let out = g.trim();
|
|
19309
|
+
if (out.startsWith("[") && out.charAt(1) === '"')
|
|
19310
|
+
out = out.slice(1);
|
|
19311
|
+
if (out.endsWith("]") && out.charAt(out.length - 2) === '"')
|
|
19312
|
+
out = out.slice(0, -1);
|
|
19313
|
+
if (out.length >= 2 && (out.charAt(0) === '"' && out.charAt(out.length - 1) === '"' || out.charAt(0) === "'" && out.charAt(out.length - 1) === "'")) {
|
|
19314
|
+
out = out.slice(1, -1).trim();
|
|
19315
|
+
}
|
|
19316
|
+
return out;
|
|
19317
|
+
}
|
|
19318
|
+
function isJsonArrayString(value) {
|
|
19319
|
+
if (typeof value !== "string")
|
|
19320
|
+
return false;
|
|
19321
|
+
const s = value.trim();
|
|
19322
|
+
if (!s.startsWith("[") || !s.endsWith("]"))
|
|
19323
|
+
return false;
|
|
19324
|
+
try {
|
|
19325
|
+
return Array.isArray(JSON.parse(s));
|
|
19326
|
+
} catch {
|
|
19327
|
+
return false;
|
|
19328
|
+
}
|
|
19329
|
+
}
|
|
19307
19330
|
function coerceStringList(value, fallback) {
|
|
19308
19331
|
if (value === void 0 || value === null)
|
|
19309
19332
|
return fallback;
|
|
19310
19333
|
if (Array.isArray(value)) {
|
|
19311
|
-
const cleaned = value.filter((x) => typeof x === "string" && x.trim().length > 0);
|
|
19334
|
+
const cleaned = value.map((x) => typeof x === "string" ? cleanGlobFragment(x) : x).filter((x) => typeof x === "string" && x.trim().length > 0);
|
|
19312
19335
|
return cleaned.length > 0 ? cleaned : fallback;
|
|
19313
19336
|
}
|
|
19314
19337
|
if (typeof value === "string") {
|
|
19315
19338
|
const s = value.trim();
|
|
19316
19339
|
if (!s)
|
|
19317
19340
|
return fallback;
|
|
19341
|
+
if (s.startsWith("[") && s.endsWith("]")) {
|
|
19342
|
+
try {
|
|
19343
|
+
const parsed = JSON.parse(s);
|
|
19344
|
+
if (Array.isArray(parsed))
|
|
19345
|
+
return coerceStringList(parsed, fallback);
|
|
19346
|
+
} catch {
|
|
19347
|
+
}
|
|
19348
|
+
}
|
|
19318
19349
|
if (s.includes(",") && !s.includes("{")) {
|
|
19319
|
-
const parts = s.split(",").map((x) => x
|
|
19350
|
+
const parts = s.split(",").map((x) => cleanGlobFragment(x)).filter(Boolean);
|
|
19320
19351
|
return parts.length > 0 ? parts : fallback;
|
|
19321
19352
|
}
|
|
19322
|
-
|
|
19353
|
+
const single = cleanGlobFragment(s);
|
|
19354
|
+
return single ? [single] : fallback;
|
|
19323
19355
|
}
|
|
19324
19356
|
return fallback;
|
|
19325
19357
|
}
|
|
@@ -19425,7 +19457,7 @@ var init_search = __esm({
|
|
|
19425
19457
|
});
|
|
19426
19458
|
grepContentTool = {
|
|
19427
19459
|
name: "grep_content",
|
|
19428
|
-
description: `Regex search for content in a file OR recursively in a directory. When path is a directory, include/exclude globs filter which files are searched (default: all files, excluding node_modules/dist/.git/etc.). Glob semantics (grep --include style): a glob without '/' (e.g. "*.md") matches the file basename at ANY depth; a glob with '/' (e.g. "src/*.ts") matches the relative path at exactly that level; "**" is explicit recursion ("**/*.ts" matches at any depth, same as the bare form). include/exclude accept a single glob string (e.g. "*.ts") OR an array of globs. Returns matches with line numbers and context, plus filesWalked/filesInTree counts and a warning when the include globs matched suspiciously few files.`,
|
|
19460
|
+
description: `Regex search for content in a file OR recursively in a directory. When path is a directory, include/exclude globs filter which files are searched (default: all files, excluding node_modules/dist/.git/etc.). Glob semantics (grep --include style): a glob without '/' (e.g. "*.md") matches the file basename at ANY depth; a glob with '/' (e.g. "src/*.ts") matches the relative path at exactly that level; "**" is explicit recursion ("**/*.ts" matches at any depth, same as the bare form). include/exclude accept a single glob string (e.g. "*.ts") OR an array of globs. Stringified-array ('["*.ts"]') or quote-wrapped forms are auto-repaired, with a warning. Returns matches with line numbers and context, plus filesWalked/filesInTree counts and a warning when the include globs matched suspiciously few files.`,
|
|
19429
19461
|
permissions: ["read"],
|
|
19430
19462
|
sideEffect: "none",
|
|
19431
19463
|
timeoutMs: 3e4,
|
|
@@ -19440,9 +19472,14 @@ var init_search = __esm({
|
|
|
19440
19472
|
const warnings = [];
|
|
19441
19473
|
if (Array.isArray(rawInclude) && rawInclude.length === 0) {
|
|
19442
19474
|
warnings.push('DEPRECATED_INPUT: empty include array \u2014 omit the field instead; this will become INVALID_ARGUMENT (planned v1.47). Fell back to ["*"]');
|
|
19475
|
+
} else if (isJsonArrayString(rawInclude)) {
|
|
19476
|
+
warnings.push(`include repaired from stringified-array form to ${JSON.stringify(include)}`);
|
|
19443
19477
|
} else if (typeof rawInclude === "string") {
|
|
19444
19478
|
warnings.push(`include coerced from bare string to ${JSON.stringify(include)}`);
|
|
19445
19479
|
}
|
|
19480
|
+
if (isJsonArrayString(args.exclude)) {
|
|
19481
|
+
warnings.push(`exclude repaired from stringified-array form to ${JSON.stringify(exclude)}`);
|
|
19482
|
+
}
|
|
19446
19483
|
if (!await isDirectory(absRoot)) {
|
|
19447
19484
|
let exists = true;
|
|
19448
19485
|
try {
|
|
@@ -20336,11 +20373,11 @@ var init_tools = __esm({
|
|
|
20336
20373
|
if (!ctx.addDocument)
|
|
20337
20374
|
return "Knowledge vault tool not available.";
|
|
20338
20375
|
const title = args["title"] || "New Document";
|
|
20339
|
-
const
|
|
20376
|
+
const path104 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
20340
20377
|
const content = args["content"] || "";
|
|
20341
20378
|
const tags = args["tags"] || [];
|
|
20342
20379
|
ctx.addDocument({
|
|
20343
|
-
path:
|
|
20380
|
+
path: path104,
|
|
20344
20381
|
title,
|
|
20345
20382
|
content,
|
|
20346
20383
|
format: "markdown",
|
|
@@ -20349,7 +20386,7 @@ var init_tools = __esm({
|
|
|
20349
20386
|
workspaceId: ctx.workspaceId
|
|
20350
20387
|
});
|
|
20351
20388
|
ctx.addActivity("vault", "created document", title);
|
|
20352
|
-
return `Document "${title}" created at "${
|
|
20389
|
+
return `Document "${title}" created at "${path104}".`;
|
|
20353
20390
|
}
|
|
20354
20391
|
}
|
|
20355
20392
|
];
|
|
@@ -22259,7 +22296,7 @@ var init_nodeProviders = __esm({
|
|
|
22259
22296
|
const isWindows = process.platform === "win32";
|
|
22260
22297
|
const file2 = isWindows ? "cmd.exe" : "/bin/sh";
|
|
22261
22298
|
const args = isWindows ? ["/d", "/s", "/c", command] : ["-c", command];
|
|
22262
|
-
return await new Promise((
|
|
22299
|
+
return await new Promise((resolve10) => {
|
|
22263
22300
|
const child = spawn2(file2, args, {
|
|
22264
22301
|
cwd,
|
|
22265
22302
|
shell: false,
|
|
@@ -22292,7 +22329,7 @@ var init_nodeProviders = __esm({
|
|
|
22292
22329
|
});
|
|
22293
22330
|
child.on("error", (err) => {
|
|
22294
22331
|
clearTimeout(timer);
|
|
22295
|
-
|
|
22332
|
+
resolve10({
|
|
22296
22333
|
exitCode: null,
|
|
22297
22334
|
stdout,
|
|
22298
22335
|
stderr: `${stderr}${err.message}`,
|
|
@@ -22302,7 +22339,7 @@ var init_nodeProviders = __esm({
|
|
|
22302
22339
|
});
|
|
22303
22340
|
child.on("close", (code) => {
|
|
22304
22341
|
clearTimeout(timer);
|
|
22305
|
-
|
|
22342
|
+
resolve10({ exitCode: code, stdout, stderr, durationMs: Date.now() - started, timedOut });
|
|
22306
22343
|
});
|
|
22307
22344
|
});
|
|
22308
22345
|
}
|
|
@@ -22380,7 +22417,7 @@ import path16 from "node:path";
|
|
|
22380
22417
|
import crypto2 from "node:crypto";
|
|
22381
22418
|
import { spawn as spawn3 } from "node:child_process";
|
|
22382
22419
|
async function git(cwd, args) {
|
|
22383
|
-
return await new Promise((
|
|
22420
|
+
return await new Promise((resolve10, reject) => {
|
|
22384
22421
|
const child = spawn3("git", args, { cwd, shell: false });
|
|
22385
22422
|
let stdout = "";
|
|
22386
22423
|
let stderr = "";
|
|
@@ -22389,7 +22426,7 @@ async function git(cwd, args) {
|
|
|
22389
22426
|
child.on("error", (err) => reject(err));
|
|
22390
22427
|
child.on("close", (code) => {
|
|
22391
22428
|
if (code === 0)
|
|
22392
|
-
|
|
22429
|
+
resolve10(stdout);
|
|
22393
22430
|
else
|
|
22394
22431
|
reject(new Error(`git ${args.join(" ")} failed (${code}): ${stderr.trim()}`));
|
|
22395
22432
|
});
|
|
@@ -25287,16 +25324,16 @@ function runRetentionFromEnv() {
|
|
|
25287
25324
|
maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
|
|
25288
25325
|
};
|
|
25289
25326
|
}
|
|
25290
|
-
async function dirSize(
|
|
25327
|
+
async function dirSize(path104) {
|
|
25291
25328
|
let total = 0;
|
|
25292
25329
|
let entries;
|
|
25293
25330
|
try {
|
|
25294
|
-
entries = await readdir(
|
|
25331
|
+
entries = await readdir(path104, { withFileTypes: true });
|
|
25295
25332
|
} catch {
|
|
25296
25333
|
return 0;
|
|
25297
25334
|
}
|
|
25298
25335
|
for (const entry of entries) {
|
|
25299
|
-
const child = join3(
|
|
25336
|
+
const child = join3(path104, entry.name);
|
|
25300
25337
|
if (entry.isDirectory())
|
|
25301
25338
|
total += await dirSize(child);
|
|
25302
25339
|
else {
|
|
@@ -25323,19 +25360,19 @@ async function enforceRunRetention(runsDir, options = {}) {
|
|
|
25323
25360
|
for (const entry of entries) {
|
|
25324
25361
|
if (!entry.isDirectory())
|
|
25325
25362
|
continue;
|
|
25326
|
-
const
|
|
25363
|
+
const path104 = join3(runsDir, entry.name);
|
|
25327
25364
|
let startedAt = 0;
|
|
25328
25365
|
let endedAt;
|
|
25329
25366
|
let completed = false;
|
|
25330
25367
|
try {
|
|
25331
|
-
const manifest = JSON.parse(await readFile(join3(
|
|
25368
|
+
const manifest = JSON.parse(await readFile(join3(path104, "manifest.json"), "utf8"));
|
|
25332
25369
|
startedAt = manifest.startedAt ?? 0;
|
|
25333
25370
|
endedAt = manifest.endedAt;
|
|
25334
25371
|
completed = Boolean(endedAt) && manifest.status !== "running";
|
|
25335
25372
|
} catch {
|
|
25336
25373
|
completed = false;
|
|
25337
25374
|
}
|
|
25338
|
-
infos.push({ name: entry.name, path:
|
|
25375
|
+
infos.push({ name: entry.name, path: path104, startedAt, endedAt, completed, bytes: await dirSize(path104) });
|
|
25339
25376
|
}
|
|
25340
25377
|
const remove = async (info) => {
|
|
25341
25378
|
await rm(info.path, { recursive: true, force: true });
|
|
@@ -25893,12 +25930,12 @@ var init_engine = __esm({
|
|
|
25893
25930
|
* content digest) and the returned ref carries the event seq when the
|
|
25894
25931
|
* emitter resolved one.
|
|
25895
25932
|
*/
|
|
25896
|
-
async fsEvidence(observation,
|
|
25933
|
+
async fsEvidence(observation, path104, sha2562, content, extra = {}) {
|
|
25897
25934
|
const digest = sha2562 && content !== void 0 ? sha2562(content) : void 0;
|
|
25898
|
-
const seq = await this.emitEvidence({ observation, path:
|
|
25935
|
+
const seq = await this.emitEvidence({ observation, path: path104, ...extra, ...digest ? { digest } : {} });
|
|
25899
25936
|
return {
|
|
25900
25937
|
tier: "fs-observation",
|
|
25901
|
-
ref:
|
|
25938
|
+
ref: path104,
|
|
25902
25939
|
capturedAt: Date.now(),
|
|
25903
25940
|
...digest ? { digest } : {},
|
|
25904
25941
|
...seq !== void 0 ? { seq } : {}
|
|
@@ -29044,22 +29081,32 @@ function parseMinimaxStyleToolCalls(text) {
|
|
|
29044
29081
|
}
|
|
29045
29082
|
function parseLooseArgs(body) {
|
|
29046
29083
|
const args = {};
|
|
29047
|
-
const
|
|
29084
|
+
const paramFull = /<parameter\s+name=["']([a-zA-Z_][\w]*)["']\s*>([\s\S]*?)<\/parameter>/gi;
|
|
29048
29085
|
let m;
|
|
29049
|
-
while ((m =
|
|
29086
|
+
while ((m = paramFull.exec(body)) !== null) {
|
|
29087
|
+
const key = m[1];
|
|
29088
|
+
if (["invoke", "minimax", "tool_call", "parameter"].includes(key))
|
|
29089
|
+
continue;
|
|
29090
|
+
args[key] = coerceJsonishValue(m[2]);
|
|
29091
|
+
}
|
|
29092
|
+
const rest = body.replace(/<parameter\s+name=["'][a-zA-Z_][\w]*["']\s*>[\s\S]*?<\/parameter>/gi, " ");
|
|
29093
|
+
const paramTag = /(?:parameter\s+name=|<\s*)["']?([a-zA-Z_][\w]*)["']?\s*(?:>|=\s*["']?)([^<\]\n]+)/gi;
|
|
29094
|
+
while ((m = paramTag.exec(rest)) !== null) {
|
|
29050
29095
|
const key = m[1];
|
|
29051
29096
|
if (key === "invoke" || key === "minimax" || key === "tool_call")
|
|
29052
29097
|
continue;
|
|
29053
|
-
args[key]
|
|
29098
|
+
if (args[key] !== void 0)
|
|
29099
|
+
continue;
|
|
29100
|
+
args[key] = coerceJsonishValue(m[2]);
|
|
29054
29101
|
}
|
|
29055
29102
|
const lineRe = /(?:^|[\s\[>])([a-zA-Z_][\w]*)\s*[>:=]\s*([^\n<\]]+)/g;
|
|
29056
|
-
while ((m = lineRe.exec(
|
|
29103
|
+
while ((m = lineRe.exec(rest)) !== null) {
|
|
29057
29104
|
const key = m[1];
|
|
29058
29105
|
if (args[key] !== void 0)
|
|
29059
29106
|
continue;
|
|
29060
29107
|
if (["invoke", "name", "minimax", "tool_call", "parameter"].includes(key))
|
|
29061
29108
|
continue;
|
|
29062
|
-
args[key] = m[2]
|
|
29109
|
+
args[key] = coerceJsonishValue(m[2]);
|
|
29063
29110
|
}
|
|
29064
29111
|
if (Object.keys(args).length === 0) {
|
|
29065
29112
|
const brace = body.indexOf("{");
|
|
@@ -29075,6 +29122,20 @@ function parseLooseArgs(body) {
|
|
|
29075
29122
|
}
|
|
29076
29123
|
return args;
|
|
29077
29124
|
}
|
|
29125
|
+
function coerceJsonishValue(raw) {
|
|
29126
|
+
const t = raw.trim();
|
|
29127
|
+
if (t.startsWith("[") || t.startsWith("{")) {
|
|
29128
|
+
try {
|
|
29129
|
+
return JSON.parse(t);
|
|
29130
|
+
} catch {
|
|
29131
|
+
}
|
|
29132
|
+
try {
|
|
29133
|
+
return JSON.parse(t + (t.startsWith("[") ? "]" : "}"));
|
|
29134
|
+
} catch {
|
|
29135
|
+
}
|
|
29136
|
+
}
|
|
29137
|
+
return t.replace(/^["']|["']$/g, "").trim();
|
|
29138
|
+
}
|
|
29078
29139
|
function tryParseToolArray(raw) {
|
|
29079
29140
|
let parsed;
|
|
29080
29141
|
try {
|
|
@@ -30504,8 +30565,8 @@ function wrapLegacyStream(legacyStream, params, _messages, _tools) {
|
|
|
30504
30565
|
}
|
|
30505
30566
|
if (done)
|
|
30506
30567
|
break;
|
|
30507
|
-
await new Promise((
|
|
30508
|
-
resolveNext =
|
|
30568
|
+
await new Promise((resolve10) => {
|
|
30569
|
+
resolveNext = resolve10;
|
|
30509
30570
|
});
|
|
30510
30571
|
}
|
|
30511
30572
|
await promise2;
|
|
@@ -30638,11 +30699,11 @@ var init_sessionJsonl = __esm({
|
|
|
30638
30699
|
*/
|
|
30639
30700
|
scheduleFlush() {
|
|
30640
30701
|
if (this.pending.length > 0 && !this.flushDeferred) {
|
|
30641
|
-
let
|
|
30702
|
+
let resolve10;
|
|
30642
30703
|
const promise2 = new Promise((r) => {
|
|
30643
|
-
|
|
30704
|
+
resolve10 = r;
|
|
30644
30705
|
});
|
|
30645
|
-
this.flushDeferred = { promise: promise2, resolve:
|
|
30706
|
+
this.flushDeferred = { promise: promise2, resolve: resolve10 };
|
|
30646
30707
|
}
|
|
30647
30708
|
if (this.flushTimer === null && this.pending.length > 0) {
|
|
30648
30709
|
this.flushTimer = setTimeout(() => {
|
|
@@ -30949,7 +31010,7 @@ var init_lifecycleHookRunner = __esm({
|
|
|
30949
31010
|
}
|
|
30950
31011
|
/** Spawn `command`, write JSON payload to stdin, read stdout until close. */
|
|
30951
31012
|
execCommand(command, payload, timeoutMs2, cwd) {
|
|
30952
|
-
return new Promise((
|
|
31013
|
+
return new Promise((resolve10, reject) => {
|
|
30953
31014
|
const argv = splitHookCommandLine(command);
|
|
30954
31015
|
if (argv.length === 0) {
|
|
30955
31016
|
reject(new Error("empty hook command"));
|
|
@@ -30983,7 +31044,7 @@ var init_lifecycleHookRunner = __esm({
|
|
|
30983
31044
|
reject(new Error(`exited ${code}: ${stderr.trim().slice(0, 200)}`));
|
|
30984
31045
|
return;
|
|
30985
31046
|
}
|
|
30986
|
-
|
|
31047
|
+
resolve10(stdout);
|
|
30987
31048
|
});
|
|
30988
31049
|
child.stdin?.on("error", () => {
|
|
30989
31050
|
});
|
|
@@ -31032,7 +31093,17 @@ var init_appServerTypes = __esm({
|
|
|
31032
31093
|
|
|
31033
31094
|
// packages/core/dist/harness/appServer.js
|
|
31034
31095
|
import { randomUUID } from "node:crypto";
|
|
31035
|
-
import { resolve } from "node:path";
|
|
31096
|
+
import { isAbsolute, resolve } from "node:path";
|
|
31097
|
+
function resolveSessionWorkspaceRoot(workspaceRoot) {
|
|
31098
|
+
if (typeof workspaceRoot !== "string" || workspaceRoot.trim() === "") {
|
|
31099
|
+
throw new Error("HarnessAppServer: createSession requires a non-empty `workspaceRoot` (it never falls back to process.cwd(): sessions on different workspaces must stay isolated)");
|
|
31100
|
+
}
|
|
31101
|
+
const raw = workspaceRoot.trim();
|
|
31102
|
+
if (!isAbsolute(raw)) {
|
|
31103
|
+
throw new Error(`HarnessAppServer: createSession workspaceRoot must be an absolute path (got '${raw}') \u2014 a relative root would resolve against the server process.cwd() and mix sessions (ADR-0016)`);
|
|
31104
|
+
}
|
|
31105
|
+
return resolve(raw);
|
|
31106
|
+
}
|
|
31036
31107
|
var HarnessAppServer;
|
|
31037
31108
|
var init_appServer = __esm({
|
|
31038
31109
|
"packages/core/dist/harness/appServer.js"() {
|
|
@@ -31053,7 +31124,7 @@ var init_appServer = __esm({
|
|
|
31053
31124
|
this.defaultServicesFactory = options.createWorkspaceServices;
|
|
31054
31125
|
}
|
|
31055
31126
|
createSession(options) {
|
|
31056
|
-
const root =
|
|
31127
|
+
const root = resolveSessionWorkspaceRoot(options.workspaceRoot);
|
|
31057
31128
|
const factory = options.createWorkspaceServices ?? this.defaultServicesFactory;
|
|
31058
31129
|
if (!factory) {
|
|
31059
31130
|
throw new Error("HarnessAppServer: createWorkspaceServices factory is required");
|
|
@@ -31289,6 +31360,7 @@ __export(harness_exports, {
|
|
|
31289
31360
|
recordToolResult: () => recordToolResult,
|
|
31290
31361
|
recordUsage: () => recordUsage,
|
|
31291
31362
|
resolveRequestSnapshotMode: () => resolveRequestSnapshotMode,
|
|
31363
|
+
resolveSessionWorkspaceRoot: () => resolveSessionWorkspaceRoot,
|
|
31292
31364
|
runExtensionPreToolUse: () => runExtensionPreToolUse,
|
|
31293
31365
|
sha256Hex: () => sha256Hex,
|
|
31294
31366
|
splitHookCommandLine: () => splitHookCommandLine,
|
|
@@ -32107,11 +32179,11 @@ var init_synthesisAudit = __esm({
|
|
|
32107
32179
|
import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
32108
32180
|
import { join as join5 } from "node:path";
|
|
32109
32181
|
function loadNfrSpec(zelariRoot) {
|
|
32110
|
-
const
|
|
32111
|
-
if (!existsSync10(
|
|
32182
|
+
const path104 = join5(zelariRoot, "nfr-spec.json");
|
|
32183
|
+
if (!existsSync10(path104))
|
|
32112
32184
|
return null;
|
|
32113
32185
|
try {
|
|
32114
|
-
const raw = JSON.parse(readFileSync9(
|
|
32186
|
+
const raw = JSON.parse(readFileSync9(path104, "utf8"));
|
|
32115
32187
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
32116
32188
|
return null;
|
|
32117
32189
|
return raw;
|
|
@@ -34512,9 +34584,9 @@ var init_types9 = __esm({
|
|
|
34512
34584
|
import { readFileSync as readFileSync14 } from "node:fs";
|
|
34513
34585
|
import { join as join11 } from "node:path";
|
|
34514
34586
|
function readLessonsDeduped(zelariRoot) {
|
|
34515
|
-
const
|
|
34587
|
+
const path104 = join11(zelariRoot, LESSONS_FILE);
|
|
34516
34588
|
try {
|
|
34517
|
-
const raw = readFileSync14(
|
|
34589
|
+
const raw = readFileSync14(path104, "utf8");
|
|
34518
34590
|
const byId = /* @__PURE__ */ new Map();
|
|
34519
34591
|
for (const line of raw.split(/\r?\n/)) {
|
|
34520
34592
|
if (!line.trim())
|
|
@@ -34615,8 +34687,8 @@ function keywordsFrom(check2, signature) {
|
|
|
34615
34687
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
34616
34688
|
}
|
|
34617
34689
|
function writeLesson(zelariRoot, lesson) {
|
|
34618
|
-
const
|
|
34619
|
-
appendFileSync(
|
|
34690
|
+
const path104 = join12(zelariRoot, LESSONS_FILE);
|
|
34691
|
+
appendFileSync(path104, `${JSON.stringify(lesson)}
|
|
34620
34692
|
`, "utf8");
|
|
34621
34693
|
}
|
|
34622
34694
|
function findSimilar(lessons, signature) {
|
|
@@ -36584,9 +36656,9 @@ function findCycle(nodes) {
|
|
|
36584
36656
|
if (color.get(start) !== WHITE)
|
|
36585
36657
|
continue;
|
|
36586
36658
|
const stack = [[start, 0]];
|
|
36587
|
-
const
|
|
36659
|
+
const path104 = [];
|
|
36588
36660
|
color.set(start, GRAY);
|
|
36589
|
-
|
|
36661
|
+
path104.push(start);
|
|
36590
36662
|
while (stack.length > 0) {
|
|
36591
36663
|
const top = stack[stack.length - 1];
|
|
36592
36664
|
const [id3, idx] = top;
|
|
@@ -36599,17 +36671,17 @@ function findCycle(nodes) {
|
|
|
36599
36671
|
continue;
|
|
36600
36672
|
const c = color.get(dep);
|
|
36601
36673
|
if (c === GRAY) {
|
|
36602
|
-
const at =
|
|
36603
|
-
return [...
|
|
36674
|
+
const at = path104.indexOf(dep);
|
|
36675
|
+
return [...path104.slice(at), dep];
|
|
36604
36676
|
}
|
|
36605
36677
|
if (c === WHITE) {
|
|
36606
36678
|
color.set(dep, GRAY);
|
|
36607
|
-
|
|
36679
|
+
path104.push(dep);
|
|
36608
36680
|
stack.push([dep, 0]);
|
|
36609
36681
|
}
|
|
36610
36682
|
} else {
|
|
36611
36683
|
color.set(id3, BLACK);
|
|
36612
|
-
|
|
36684
|
+
path104.pop();
|
|
36613
36685
|
stack.pop();
|
|
36614
36686
|
}
|
|
36615
36687
|
}
|
|
@@ -37529,8 +37601,8 @@ var init_runner = __esm({
|
|
|
37529
37601
|
failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
|
|
37530
37602
|
pending: []
|
|
37531
37603
|
};
|
|
37532
|
-
const
|
|
37533
|
-
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${
|
|
37604
|
+
const path104 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
|
|
37605
|
+
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path104}`);
|
|
37534
37606
|
return snapshot;
|
|
37535
37607
|
}
|
|
37536
37608
|
callLog(msg, data) {
|
|
@@ -38826,7 +38898,7 @@ var CORE_VERSION;
|
|
|
38826
38898
|
var init_version = __esm({
|
|
38827
38899
|
"packages/core/dist/version.js"() {
|
|
38828
38900
|
"use strict";
|
|
38829
|
-
CORE_VERSION = "2.
|
|
38901
|
+
CORE_VERSION = "2.43.0";
|
|
38830
38902
|
}
|
|
38831
38903
|
});
|
|
38832
38904
|
|
|
@@ -39309,6 +39381,7 @@ __export(dist_exports, {
|
|
|
39309
39381
|
resolveRequestSnapshotMode: () => resolveRequestSnapshotMode,
|
|
39310
39382
|
resolveResponseLanguage: () => resolveResponseLanguage,
|
|
39311
39383
|
resolveRoleSystemPrompt: () => resolveRoleSystemPrompt,
|
|
39384
|
+
resolveSessionWorkspaceRoot: () => resolveSessionWorkspaceRoot,
|
|
39312
39385
|
resolveSessionsDir: () => resolveSessionsDir,
|
|
39313
39386
|
resolveSkillDependencies: () => resolveSkillDependencies,
|
|
39314
39387
|
resolveVerifyRetryTool: () => resolveVerifyRetryTool,
|
|
@@ -40162,7 +40235,7 @@ ${fallback.output}`
|
|
|
40162
40235
|
return primary;
|
|
40163
40236
|
}
|
|
40164
40237
|
function runNpm(executor, args, mode, npmCliPath) {
|
|
40165
|
-
return new Promise((
|
|
40238
|
+
return new Promise((resolve10) => {
|
|
40166
40239
|
let stdout = "";
|
|
40167
40240
|
let stderr = "";
|
|
40168
40241
|
const stdio = ["ignore", "pipe", "pipe"];
|
|
@@ -40174,7 +40247,7 @@ function runNpm(executor, args, mode, npmCliPath) {
|
|
|
40174
40247
|
stderr += chunk.toString();
|
|
40175
40248
|
});
|
|
40176
40249
|
child.on("error", (err) => {
|
|
40177
|
-
|
|
40250
|
+
resolve10({
|
|
40178
40251
|
ok: false,
|
|
40179
40252
|
output: stdout + stderr,
|
|
40180
40253
|
error: err.message,
|
|
@@ -40183,7 +40256,7 @@ function runNpm(executor, args, mode, npmCliPath) {
|
|
|
40183
40256
|
});
|
|
40184
40257
|
child.on("close", (code) => {
|
|
40185
40258
|
const ok = code === 0;
|
|
40186
|
-
|
|
40259
|
+
resolve10({
|
|
40187
40260
|
ok,
|
|
40188
40261
|
output: stdout + stderr,
|
|
40189
40262
|
error: ok ? void 0 : `npm exited with code ${code}`,
|
|
@@ -41308,9 +41381,9 @@ function spillToolOutput(fullText, meta3) {
|
|
|
41308
41381
|
const rnd = randomBytes3(3).toString("hex");
|
|
41309
41382
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
41310
41383
|
const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
|
|
41311
|
-
const
|
|
41312
|
-
writeFileSync12(
|
|
41313
|
-
return
|
|
41384
|
+
const path104 = join14(dir, file2);
|
|
41385
|
+
writeFileSync12(path104, fullText, "utf8");
|
|
41386
|
+
return path104;
|
|
41314
41387
|
} catch {
|
|
41315
41388
|
return null;
|
|
41316
41389
|
}
|
|
@@ -41356,10 +41429,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
|
|
|
41356
41429
|
${tail2}`;
|
|
41357
41430
|
}
|
|
41358
41431
|
if (doSpill) {
|
|
41359
|
-
const
|
|
41360
|
-
if (
|
|
41432
|
+
const path104 = spillToolOutput(text, { toolName: opts.toolName });
|
|
41433
|
+
if (path104) {
|
|
41361
41434
|
const spillNote = `
|
|
41362
|
-
\u2026 [full output spilled to: ${
|
|
41435
|
+
\u2026 [full output spilled to: ${path104} \u2014 re-read with read_file if you need the complete text] \u2026`;
|
|
41363
41436
|
if (preview.includes("] \u2026\n")) {
|
|
41364
41437
|
preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
|
|
41365
41438
|
`);
|
|
@@ -41716,8 +41789,15 @@ import path36 from "node:path";
|
|
|
41716
41789
|
function radioDir(cwd) {
|
|
41717
41790
|
return path36.join(cwd, ".zelari", "radio");
|
|
41718
41791
|
}
|
|
41792
|
+
function processFallbackRadioId() {
|
|
41793
|
+
if (fallbackRadioId === null) {
|
|
41794
|
+
fallbackRadioId = `default-${process.pid}-${Date.now().toString(36)}`;
|
|
41795
|
+
}
|
|
41796
|
+
return fallbackRadioId;
|
|
41797
|
+
}
|
|
41719
41798
|
function radioPath(cwd, sessionId2) {
|
|
41720
|
-
const
|
|
41799
|
+
const id3 = sessionId2.trim() ? sessionId2 : processFallbackRadioId();
|
|
41800
|
+
const safe = id3.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
41721
41801
|
return path36.join(radioDir(cwd), `${safe}.jsonl`);
|
|
41722
41802
|
}
|
|
41723
41803
|
function appendRadioLine(file2, line) {
|
|
@@ -41812,10 +41892,11 @@ function formatKrakenRadioStatus(cwd, sessionId2, limit = 12) {
|
|
|
41812
41892
|
});
|
|
41813
41893
|
return [`Kraken radio (last ${events.length}) session=${sessionId2}:`, ...lines].join("\n");
|
|
41814
41894
|
}
|
|
41815
|
-
var MAX_CACHED_RADIO_FDS, radioFds;
|
|
41895
|
+
var fallbackRadioId, MAX_CACHED_RADIO_FDS, radioFds;
|
|
41816
41896
|
var init_krakenRadio = __esm({
|
|
41817
41897
|
"src/cli/tools/krakenRadio.ts"() {
|
|
41818
41898
|
"use strict";
|
|
41899
|
+
fallbackRadioId = null;
|
|
41819
41900
|
MAX_CACHED_RADIO_FDS = 32;
|
|
41820
41901
|
radioFds = /* @__PURE__ */ new Map();
|
|
41821
41902
|
}
|
|
@@ -42162,28 +42243,28 @@ var init_storage = __esm({
|
|
|
42162
42243
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
42163
42244
|
Storage = class {
|
|
42164
42245
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
42165
|
-
read(
|
|
42166
|
-
if (!existsSync19(
|
|
42167
|
-
throw new Error(`File not found: ${
|
|
42246
|
+
read(path104) {
|
|
42247
|
+
if (!existsSync19(path104)) {
|
|
42248
|
+
throw new Error(`File not found: ${path104}`);
|
|
42168
42249
|
}
|
|
42169
|
-
const md = readFileSync17(
|
|
42250
|
+
const md = readFileSync17(path104, "utf8");
|
|
42170
42251
|
return parseFrontmatter(md);
|
|
42171
42252
|
}
|
|
42172
42253
|
/** Read a Markdown file; returns null if not found. */
|
|
42173
|
-
readIfExists(
|
|
42174
|
-
if (!existsSync19(
|
|
42175
|
-
return this.read(
|
|
42254
|
+
readIfExists(path104) {
|
|
42255
|
+
if (!existsSync19(path104)) return null;
|
|
42256
|
+
return this.read(path104);
|
|
42176
42257
|
}
|
|
42177
42258
|
/**
|
|
42178
42259
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
42179
42260
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
42180
42261
|
*/
|
|
42181
|
-
write(
|
|
42182
|
-
mkdirSync10(dirname2(
|
|
42183
|
-
const tmp =
|
|
42262
|
+
write(path104, meta3, body) {
|
|
42263
|
+
mkdirSync10(dirname2(path104), { recursive: true });
|
|
42264
|
+
const tmp = path104 + ".tmp-" + process.pid;
|
|
42184
42265
|
const md = serializeFrontmatter(meta3, body);
|
|
42185
42266
|
writeFileSync14(tmp, md, "utf8");
|
|
42186
|
-
renameSync2(tmp,
|
|
42267
|
+
renameSync2(tmp, path104);
|
|
42187
42268
|
}
|
|
42188
42269
|
/** List all .md files in a directory (non-recursive). */
|
|
42189
42270
|
listMarkdown(dir) {
|
|
@@ -42197,8 +42278,8 @@ var init_storage = __esm({
|
|
|
42197
42278
|
const prev2 = this.chains.get(key) ?? Promise.resolve();
|
|
42198
42279
|
let release = () => {
|
|
42199
42280
|
};
|
|
42200
|
-
const next = new Promise((
|
|
42201
|
-
release =
|
|
42281
|
+
const next = new Promise((resolve10) => {
|
|
42282
|
+
release = resolve10;
|
|
42202
42283
|
});
|
|
42203
42284
|
const chained = prev2.then(() => next);
|
|
42204
42285
|
this.chains.set(key, chained);
|
|
@@ -42294,8 +42375,8 @@ function nextPlanTaskId(store6) {
|
|
|
42294
42375
|
return `t${store6.counter}`;
|
|
42295
42376
|
}
|
|
42296
42377
|
function writePlanTaskArtifact(rootDir, task) {
|
|
42297
|
-
const
|
|
42298
|
-
mkdirSync11(dirname3(
|
|
42378
|
+
const path104 = join17(rootDir, "plan-tasks", `${task.id}.md`);
|
|
42379
|
+
mkdirSync11(dirname3(path104), { recursive: true });
|
|
42299
42380
|
const meta3 = {
|
|
42300
42381
|
kind: "task",
|
|
42301
42382
|
id: task.id,
|
|
@@ -42316,7 +42397,7 @@ function writePlanTaskArtifact(rootDir, task) {
|
|
|
42316
42397
|
task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
|
|
42317
42398
|
""
|
|
42318
42399
|
].filter((l) => l !== null).join("\n");
|
|
42319
|
-
new Storage().write(
|
|
42400
|
+
new Storage().write(path104, meta3, body);
|
|
42320
42401
|
}
|
|
42321
42402
|
function loadHandle(rootDir) {
|
|
42322
42403
|
const jsonPath = join17(rootDir, "plan.json");
|
|
@@ -42994,14 +43075,14 @@ var init_engine2 = __esm({
|
|
|
42994
43075
|
parse: parseRuffJson
|
|
42995
43076
|
}
|
|
42996
43077
|
];
|
|
42997
|
-
defaultRunner = (cmd, args, opts) => new Promise((
|
|
43078
|
+
defaultRunner = (cmd, args, opts) => new Promise((resolve10) => {
|
|
42998
43079
|
let stdout = "";
|
|
42999
43080
|
let stderr = "";
|
|
43000
43081
|
let settled = false;
|
|
43001
43082
|
const done = (r) => {
|
|
43002
43083
|
if (settled) return;
|
|
43003
43084
|
settled = true;
|
|
43004
|
-
|
|
43085
|
+
resolve10(r);
|
|
43005
43086
|
};
|
|
43006
43087
|
let child;
|
|
43007
43088
|
try {
|
|
@@ -44056,7 +44137,7 @@ async function readChecks(cwd) {
|
|
|
44056
44137
|
}
|
|
44057
44138
|
}
|
|
44058
44139
|
function runShell(command, cwd, timeoutMs2, signal) {
|
|
44059
|
-
return new Promise((
|
|
44140
|
+
return new Promise((resolve10) => {
|
|
44060
44141
|
const isWin = process.platform === "win32";
|
|
44061
44142
|
const child = spawn8(isWin ? "cmd.exe" : "/bin/sh", isWin ? ["/c", command] : ["-c", command], {
|
|
44062
44143
|
cwd,
|
|
@@ -44070,7 +44151,7 @@ function runShell(command, cwd, timeoutMs2, signal) {
|
|
|
44070
44151
|
const finish2 = (exitCode) => {
|
|
44071
44152
|
if (settled) return;
|
|
44072
44153
|
settled = true;
|
|
44073
|
-
|
|
44154
|
+
resolve10({ exitCode, stdout, stderr });
|
|
44074
44155
|
};
|
|
44075
44156
|
const timer = setTimeout(() => {
|
|
44076
44157
|
try {
|
|
@@ -46781,8 +46862,8 @@ ${upstream}` : node.prompt,
|
|
|
46781
46862
|
if (ms <= 0) return promise2;
|
|
46782
46863
|
let timer;
|
|
46783
46864
|
const TIMED_OUT = Symbol("timeout");
|
|
46784
|
-
const timeout = new Promise((
|
|
46785
|
-
timer = setTimeout(() =>
|
|
46865
|
+
const timeout = new Promise((resolve10) => {
|
|
46866
|
+
timer = setTimeout(() => resolve10(TIMED_OUT), ms);
|
|
46786
46867
|
});
|
|
46787
46868
|
const raced = await Promise.race([promise2, timeout]).finally(() => {
|
|
46788
46869
|
if (timer) clearTimeout(timer);
|
|
@@ -46791,8 +46872,8 @@ ${upstream}` : node.prompt,
|
|
|
46791
46872
|
controller?.abort();
|
|
46792
46873
|
const graceMs = this.cancelGraceMs ?? resolveCancelGraceMs();
|
|
46793
46874
|
let graceTimer;
|
|
46794
|
-
const grace = new Promise((
|
|
46795
|
-
graceTimer = setTimeout(() =>
|
|
46875
|
+
const grace = new Promise((resolve10) => {
|
|
46876
|
+
graceTimer = setTimeout(() => resolve10(TIMED_OUT), graceMs);
|
|
46796
46877
|
});
|
|
46797
46878
|
const settled = await Promise.race([promise2, grace]).finally(() => {
|
|
46798
46879
|
if (graceTimer) clearTimeout(graceTimer);
|
|
@@ -47850,7 +47931,10 @@ async function runTentacle(opts) {
|
|
|
47850
47931
|
emitActivity({
|
|
47851
47932
|
type: "agent_ended",
|
|
47852
47933
|
agentId: id3,
|
|
47853
|
-
|
|
47934
|
+
// t102: `reason` feeds a failure-heuristic on the Desktop; free text in
|
|
47935
|
+
// it (result excerpt) could flip a SUCCESSFUL tentacle to "failed".
|
|
47936
|
+
// Only genuine failures carry detail; successes are enum-only.
|
|
47937
|
+
reason: info.ok === false ? info.detail ?? "failed" : "completed",
|
|
47854
47938
|
ok: info.ok !== false,
|
|
47855
47939
|
durationMs: info.durationMs ?? 0,
|
|
47856
47940
|
ts: Date.now()
|
|
@@ -47861,7 +47945,10 @@ async function runTentacle(opts) {
|
|
|
47861
47945
|
sub = await deps.createSubAgentContext({
|
|
47862
47946
|
agent,
|
|
47863
47947
|
thoroughness,
|
|
47864
|
-
cwd: effectiveCwd
|
|
47948
|
+
cwd: effectiveCwd,
|
|
47949
|
+
// Per-spawn thinking effort (ADR-0017): the factory applies arg > per-kind
|
|
47950
|
+
// env > inherited provider default and reports the winner back on `sub`.
|
|
47951
|
+
...args.thinkingEffort ? { thinkingEffort: args.thinkingEffort } : {}
|
|
47865
47952
|
});
|
|
47866
47953
|
} catch (err) {
|
|
47867
47954
|
if (worktree) await cleanupKrakenWorktree(worktree);
|
|
@@ -47897,6 +47984,8 @@ async function runTentacle(opts) {
|
|
|
47897
47984
|
error: "task: no provider configured for the sub-agent (set an API key / run /login)."
|
|
47898
47985
|
};
|
|
47899
47986
|
}
|
|
47987
|
+
const requestedThinking = args.thinkingEffort && args.thinkingEffort.toLowerCase() !== "inherit" ? args.thinkingEffort : void 0;
|
|
47988
|
+
const spawnThinking = sub.thinking ?? requestedThinking;
|
|
47900
47989
|
emitActivity({
|
|
47901
47990
|
type: "agent_spawned",
|
|
47902
47991
|
agentId: liveId,
|
|
@@ -47904,6 +47993,7 @@ async function runTentacle(opts) {
|
|
|
47904
47993
|
title: args.description,
|
|
47905
47994
|
...sub.model ? { model: sub.model } : {},
|
|
47906
47995
|
...sub.provider ? { provider: sub.provider } : {},
|
|
47996
|
+
...spawnThinking ? { thinking: spawnThinking } : {},
|
|
47907
47997
|
...args.scope && args.scope.length > 0 ? { scope: args.scope } : {},
|
|
47908
47998
|
...worktree ? { worktree: worktree.path } : {},
|
|
47909
47999
|
ts: Date.now()
|
|
@@ -48238,7 +48328,8 @@ RESTRICTED in this mode: only agent=${allowedAgents.join("|")} is allowed.` : ""
|
|
|
48238
48328
|
description: args.description,
|
|
48239
48329
|
prompt: args.prompt,
|
|
48240
48330
|
scope: args.scope,
|
|
48241
|
-
acceptance: args.acceptance
|
|
48331
|
+
acceptance: args.acceptance,
|
|
48332
|
+
...args.thinkingEffort ? { thinkingEffort: args.thinkingEffort } : {}
|
|
48242
48333
|
},
|
|
48243
48334
|
agent,
|
|
48244
48335
|
thoroughness,
|
|
@@ -48394,6 +48485,9 @@ var init_taskTool = __esm({
|
|
|
48394
48485
|
),
|
|
48395
48486
|
acceptance: external_exports.array(external_exports.string().min(1)).max(16).optional().describe(
|
|
48396
48487
|
"Optional acceptance checklist (contract). Appended to the prompt as Acceptance criteria."
|
|
48488
|
+
),
|
|
48489
|
+
thinkingEffort: external_exports.enum(["inherit", "auto", "off", "low", "medium", "high", "xhigh", "max"]).optional().describe(
|
|
48490
|
+
"Thinking effort for THIS tentacle only (ADR-0017), overriding the provider default used by the lead. 'inherit' (and omitting the field) defers to the per-kind default: ZELARI_KRAKEN_<EXPLORE|GENERAL|VERIFY>_THINKING, else the provider thinkingByProvider value. Token budgets are not accepted here \u2014 set ZELARI_KRAKEN_<KIND>_THINKING='budget:<n>' instead. Invalid values are ignored."
|
|
48397
48491
|
)
|
|
48398
48492
|
});
|
|
48399
48493
|
TaskPurposeSchema = external_exports.enum(["candidate"]).optional().describe(
|
|
@@ -49910,6 +50004,383 @@ var init_skillTool = __esm({
|
|
|
49910
50004
|
}
|
|
49911
50005
|
});
|
|
49912
50006
|
|
|
50007
|
+
// src/cli/skillCategories.ts
|
|
50008
|
+
var CODING_CATEGORIES_LIST, CODING_CATEGORIES2;
|
|
50009
|
+
var init_skillCategories = __esm({
|
|
50010
|
+
"src/cli/skillCategories.ts"() {
|
|
50011
|
+
"use strict";
|
|
50012
|
+
CODING_CATEGORIES_LIST = [
|
|
50013
|
+
"plan",
|
|
50014
|
+
"refactor",
|
|
50015
|
+
"debug",
|
|
50016
|
+
"review",
|
|
50017
|
+
"test",
|
|
50018
|
+
"docs",
|
|
50019
|
+
"ops",
|
|
50020
|
+
"git",
|
|
50021
|
+
"db",
|
|
50022
|
+
"maint"
|
|
50023
|
+
];
|
|
50024
|
+
CODING_CATEGORIES2 = new Set(CODING_CATEGORIES_LIST);
|
|
50025
|
+
}
|
|
50026
|
+
});
|
|
50027
|
+
|
|
50028
|
+
// src/cli/skillConfigIo.ts
|
|
50029
|
+
import {
|
|
50030
|
+
existsSync as existsSync28,
|
|
50031
|
+
mkdirSync as mkdirSync13,
|
|
50032
|
+
readdirSync as readdirSync6,
|
|
50033
|
+
readFileSync as readFileSync20,
|
|
50034
|
+
rmSync as rmSync3,
|
|
50035
|
+
writeFileSync as writeFileSync16
|
|
50036
|
+
} from "node:fs";
|
|
50037
|
+
import { dirname as dirname4, join as join20 } from "node:path";
|
|
50038
|
+
function ensureBuiltinSkillsLoadedSync() {
|
|
50039
|
+
if (builtinsLoaded) return;
|
|
50040
|
+
for (const spec of BUILTIN_SKILL_MODULES) {
|
|
50041
|
+
try {
|
|
50042
|
+
require?.(spec);
|
|
50043
|
+
} catch {
|
|
50044
|
+
}
|
|
50045
|
+
}
|
|
50046
|
+
}
|
|
50047
|
+
function getUserSkillsDir() {
|
|
50048
|
+
return join20(zelariHome(), "skills");
|
|
50049
|
+
}
|
|
50050
|
+
function getProjectSkillsDir(projectRoot) {
|
|
50051
|
+
return join20(projectRoot, ".zelari", "skills");
|
|
50052
|
+
}
|
|
50053
|
+
function skillFilePath(dir, name) {
|
|
50054
|
+
return join20(dir, name, "SKILL.md");
|
|
50055
|
+
}
|
|
50056
|
+
function classifyScope(skillPath, projectRoot) {
|
|
50057
|
+
const userDir = getUserSkillsDir().replace(/\\/g, "/");
|
|
50058
|
+
const norm = skillPath.replace(/\\/g, "/");
|
|
50059
|
+
if (norm.startsWith(userDir + "/") || norm === userDir) {
|
|
50060
|
+
return { scope: "user", writable: true };
|
|
50061
|
+
}
|
|
50062
|
+
if (projectRoot) {
|
|
50063
|
+
const projDir = getProjectSkillsDir(projectRoot).replace(/\\/g, "/");
|
|
50064
|
+
if (norm.startsWith(projDir + "/") || norm === projDir) {
|
|
50065
|
+
return { scope: "project", writable: true };
|
|
50066
|
+
}
|
|
50067
|
+
}
|
|
50068
|
+
return { scope: "compat", writable: false };
|
|
50069
|
+
}
|
|
50070
|
+
function entryFromParsed(parsed, projectRoot) {
|
|
50071
|
+
const { scope, writable } = classifyScope(parsed.sourcePath, projectRoot);
|
|
50072
|
+
return {
|
|
50073
|
+
id: parsed.name,
|
|
50074
|
+
name: parsed.name,
|
|
50075
|
+
description: parsed.description,
|
|
50076
|
+
category: parsed.category,
|
|
50077
|
+
estimatedCost: parsed.estimatedCost,
|
|
50078
|
+
requiredTools: parsed.requiredTools,
|
|
50079
|
+
scope,
|
|
50080
|
+
path: parsed.sourcePath,
|
|
50081
|
+
body: parsed.body,
|
|
50082
|
+
builtin: false,
|
|
50083
|
+
writable
|
|
50084
|
+
};
|
|
50085
|
+
}
|
|
50086
|
+
function entryFromBuiltin(skill) {
|
|
50087
|
+
return {
|
|
50088
|
+
id: skill.id,
|
|
50089
|
+
name: skill.name || skill.id,
|
|
50090
|
+
description: skill.description || "",
|
|
50091
|
+
category: skill.category,
|
|
50092
|
+
estimatedCost: skill.estimatedCost,
|
|
50093
|
+
requiredTools: skill.requiredTools,
|
|
50094
|
+
scope: "builtin",
|
|
50095
|
+
path: null,
|
|
50096
|
+
// Expose body so Desktop skill picker can expand like `/skill <id>`.
|
|
50097
|
+
body: skill.systemPromptFragment || void 0,
|
|
50098
|
+
builtin: true,
|
|
50099
|
+
writable: false
|
|
50100
|
+
};
|
|
50101
|
+
}
|
|
50102
|
+
function scanSkillsDir(dir, projectRoot, seen, out) {
|
|
50103
|
+
if (!existsSync28(dir)) return;
|
|
50104
|
+
let entries;
|
|
50105
|
+
try {
|
|
50106
|
+
entries = readdirSync6(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
50107
|
+
} catch {
|
|
50108
|
+
return;
|
|
50109
|
+
}
|
|
50110
|
+
for (const entry of entries) {
|
|
50111
|
+
const skillPath = skillFilePath(dir, entry);
|
|
50112
|
+
if (!existsSync28(skillPath)) continue;
|
|
50113
|
+
try {
|
|
50114
|
+
const parsed = parseSkillMd(readFileSync20(skillPath, "utf8"), skillPath);
|
|
50115
|
+
if (!parsed) continue;
|
|
50116
|
+
if (seen.has(parsed.name)) continue;
|
|
50117
|
+
seen.add(parsed.name);
|
|
50118
|
+
out.push(entryFromParsed(parsed, projectRoot));
|
|
50119
|
+
} catch {
|
|
50120
|
+
}
|
|
50121
|
+
}
|
|
50122
|
+
}
|
|
50123
|
+
function listSkillsSnapshot(projectRoot) {
|
|
50124
|
+
const root = projectRoot && projectRoot.trim() ? projectRoot.trim() : null;
|
|
50125
|
+
const userSkillsDir = getUserSkillsDir();
|
|
50126
|
+
const projectSkillsDir = root ? getProjectSkillsDir(root) : null;
|
|
50127
|
+
const skills = [];
|
|
50128
|
+
const seen = /* @__PURE__ */ new Set();
|
|
50129
|
+
if (root) {
|
|
50130
|
+
scanSkillsDir(join20(root, ".zelari", "skills"), root, seen, skills);
|
|
50131
|
+
scanSkillsDir(join20(root, ".claude", "skills"), root, seen, skills);
|
|
50132
|
+
scanSkillsDir(join20(root, ".opencode", "skills"), root, seen, skills);
|
|
50133
|
+
}
|
|
50134
|
+
scanSkillsDir(userSkillsDir, root, seen, skills);
|
|
50135
|
+
for (const s of listCodingSkills()) {
|
|
50136
|
+
if (seen.has(s.id)) continue;
|
|
50137
|
+
seen.add(s.id);
|
|
50138
|
+
if (s.builtin) {
|
|
50139
|
+
skills.push(entryFromBuiltin(s));
|
|
50140
|
+
}
|
|
50141
|
+
}
|
|
50142
|
+
skills.sort((a, b) => {
|
|
50143
|
+
const order = (s) => s === "project" ? 0 : s === "user" ? 1 : s === "compat" ? 2 : 3;
|
|
50144
|
+
const d = order(a.scope) - order(b.scope);
|
|
50145
|
+
if (d !== 0) return d;
|
|
50146
|
+
return a.id.localeCompare(b.id);
|
|
50147
|
+
});
|
|
50148
|
+
return { userSkillsDir, projectSkillsDir, skills };
|
|
50149
|
+
}
|
|
50150
|
+
function serializeSkillMd(opts) {
|
|
50151
|
+
const name = opts.name.trim().toLowerCase();
|
|
50152
|
+
const description = opts.description.trim();
|
|
50153
|
+
const body = opts.body.trim();
|
|
50154
|
+
const lines = ["---", `name: ${name}`, `description: ${description}`];
|
|
50155
|
+
const cat = (opts.category ?? "").trim().toLowerCase();
|
|
50156
|
+
if (cat && CODING_CATEGORIES2.has(cat)) {
|
|
50157
|
+
lines.push(`category: ${cat}`);
|
|
50158
|
+
}
|
|
50159
|
+
if (opts.tools && opts.tools.length > 0) {
|
|
50160
|
+
lines.push(`tools: [${opts.tools.map((t) => t.trim()).filter(Boolean).join(", ")}]`);
|
|
50161
|
+
}
|
|
50162
|
+
const cost = (opts.cost ?? "").trim().toLowerCase();
|
|
50163
|
+
if (cost === "low" || cost === "medium" || cost === "high") {
|
|
50164
|
+
lines.push(`cost: ${cost}`);
|
|
50165
|
+
}
|
|
50166
|
+
lines.push("---", "", body, "");
|
|
50167
|
+
return lines.join("\n");
|
|
50168
|
+
}
|
|
50169
|
+
function upsertSkill(opts) {
|
|
50170
|
+
const name = opts.name.trim().toLowerCase();
|
|
50171
|
+
if (!name || !NAME_RE.test(name)) {
|
|
50172
|
+
return {
|
|
50173
|
+
ok: false,
|
|
50174
|
+
error: "Invalid skill name (use lowercase letters, digits, hyphens; max 64 chars)"
|
|
50175
|
+
};
|
|
50176
|
+
}
|
|
50177
|
+
const description = opts.description.trim();
|
|
50178
|
+
if (!description) {
|
|
50179
|
+
return { ok: false, error: "description is required" };
|
|
50180
|
+
}
|
|
50181
|
+
const body = opts.body.trim();
|
|
50182
|
+
if (!body) {
|
|
50183
|
+
return { ok: false, error: "body is required" };
|
|
50184
|
+
}
|
|
50185
|
+
let dir;
|
|
50186
|
+
if (opts.scope === "user") {
|
|
50187
|
+
dir = getUserSkillsDir();
|
|
50188
|
+
} else {
|
|
50189
|
+
const root = opts.projectRoot?.trim();
|
|
50190
|
+
if (!root) {
|
|
50191
|
+
return {
|
|
50192
|
+
ok: false,
|
|
50193
|
+
error: "projectRoot required for project scope (Open Folder first)"
|
|
50194
|
+
};
|
|
50195
|
+
}
|
|
50196
|
+
dir = getProjectSkillsDir(root);
|
|
50197
|
+
}
|
|
50198
|
+
const path104 = skillFilePath(dir, name);
|
|
50199
|
+
const content = serializeSkillMd({
|
|
50200
|
+
name,
|
|
50201
|
+
description,
|
|
50202
|
+
body,
|
|
50203
|
+
category: opts.category,
|
|
50204
|
+
tools: opts.tools,
|
|
50205
|
+
cost: opts.cost
|
|
50206
|
+
});
|
|
50207
|
+
const parsed = parseSkillMd(content, path104);
|
|
50208
|
+
if (!parsed) {
|
|
50209
|
+
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
50210
|
+
}
|
|
50211
|
+
mkdirSync13(dirname4(path104), { recursive: true });
|
|
50212
|
+
writeFileSync16(path104, content, "utf8");
|
|
50213
|
+
return { ok: true, path: path104 };
|
|
50214
|
+
}
|
|
50215
|
+
function removeSkill(opts) {
|
|
50216
|
+
const name = opts.name.trim().toLowerCase();
|
|
50217
|
+
if (!name) {
|
|
50218
|
+
return { ok: false, error: "name is required" };
|
|
50219
|
+
}
|
|
50220
|
+
let dir;
|
|
50221
|
+
if (opts.scope === "user") {
|
|
50222
|
+
dir = getUserSkillsDir();
|
|
50223
|
+
} else {
|
|
50224
|
+
const root = opts.projectRoot?.trim();
|
|
50225
|
+
if (!root) {
|
|
50226
|
+
return { ok: false, error: "projectRoot required for project scope" };
|
|
50227
|
+
}
|
|
50228
|
+
dir = getProjectSkillsDir(root);
|
|
50229
|
+
}
|
|
50230
|
+
const skillDir = join20(dir, name);
|
|
50231
|
+
const path104 = skillFilePath(dir, name);
|
|
50232
|
+
if (!existsSync28(path104) && !existsSync28(skillDir)) {
|
|
50233
|
+
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
50234
|
+
}
|
|
50235
|
+
try {
|
|
50236
|
+
rmSync3(skillDir, { recursive: true, force: true });
|
|
50237
|
+
} catch (err) {
|
|
50238
|
+
return {
|
|
50239
|
+
ok: false,
|
|
50240
|
+
error: err instanceof Error ? err.message : String(err)
|
|
50241
|
+
};
|
|
50242
|
+
}
|
|
50243
|
+
return { ok: true, path: path104 };
|
|
50244
|
+
}
|
|
50245
|
+
var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
|
|
50246
|
+
var init_skillConfigIo = __esm({
|
|
50247
|
+
"src/cli/skillConfigIo.ts"() {
|
|
50248
|
+
"use strict";
|
|
50249
|
+
init_skills2();
|
|
50250
|
+
init_skillsMd();
|
|
50251
|
+
init_skillCategories();
|
|
50252
|
+
init_paths();
|
|
50253
|
+
NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
50254
|
+
BUILTIN_SKILL_MODULES = [
|
|
50255
|
+
"@zelari/core/skills/builtin/debugging",
|
|
50256
|
+
"@zelari/core/skills/builtin/docs",
|
|
50257
|
+
"@zelari/core/skills/builtin/git-ops",
|
|
50258
|
+
"@zelari/core/skills/builtin/planning",
|
|
50259
|
+
"@zelari/core/skills/builtin/refactoring",
|
|
50260
|
+
"@zelari/core/skills/builtin/review",
|
|
50261
|
+
"@zelari/core/skills/builtin/unrealEditor",
|
|
50262
|
+
"@zelari/core/skills/builtin/testing",
|
|
50263
|
+
"@zelari/core/skills/builtin/schema-loop",
|
|
50264
|
+
"@zelari/core/skills/builtin/computer-use-cua",
|
|
50265
|
+
"@zelari/core/skills/builtin/qwen-mm-plugins"
|
|
50266
|
+
];
|
|
50267
|
+
builtinsLoaded = false;
|
|
50268
|
+
}
|
|
50269
|
+
});
|
|
50270
|
+
|
|
50271
|
+
// src/cli/tools/createSkillTool.ts
|
|
50272
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
50273
|
+
import { resolve as resolve3, sep } from "node:path";
|
|
50274
|
+
function createCreateSkillTool(opts) {
|
|
50275
|
+
const root = opts?.cwd ?? process.cwd();
|
|
50276
|
+
return {
|
|
50277
|
+
name: "create_skill",
|
|
50278
|
+
description: 'Create a NEW reusable skill (a SKILL.md procedure) that you can invoke in later turns with the `skill` tool or `/skill <name>`. Use it when the user asks to save a procedure as a skill ("salva questa procedura come skill", "crea una skill per X", "make this reusable"), or when you just worked out a repeatable workflow worth persisting. Write `instructions` as a COMPLETE, self-contained markdown procedure (goal, ordered steps, exact commands, verification, pitfalls): it becomes the skill body verbatim. scope=project (default) saves to <cwd>/.zelari/skills and is shared with the repo; scope=user saves to ~/.zelari-code/skills for every project. Creating an existing name fails unless overwrite=true. Does not edit built-in skills.',
|
|
50279
|
+
permissions: ["write"],
|
|
50280
|
+
timeoutMs: 1e4,
|
|
50281
|
+
inputSchema: CreateSkillArgsSchema,
|
|
50282
|
+
execute: async (args) => {
|
|
50283
|
+
const name = typeof args?.name === "string" ? args.name.trim() : "";
|
|
50284
|
+
if (!NAME_RE2.test(name)) {
|
|
50285
|
+
return typedErr(
|
|
50286
|
+
`Invalid skill name ${JSON.stringify(name)}. Use a slug of 2-40 chars: lowercase letters, digits and hyphens, starting with a letter or digit (e.g. "release-checklist").`
|
|
50287
|
+
);
|
|
50288
|
+
}
|
|
50289
|
+
const description = (args?.description ?? "").replace(/\s+/g, " ").trim();
|
|
50290
|
+
if (!description) {
|
|
50291
|
+
return typedErr("description is required: one line explaining when to use this skill.");
|
|
50292
|
+
}
|
|
50293
|
+
const instructions = (args?.instructions ?? "").trim();
|
|
50294
|
+
if (!instructions) {
|
|
50295
|
+
return typedErr(
|
|
50296
|
+
"instructions is required: the markdown body of the skill (goal, steps, commands, pitfalls)."
|
|
50297
|
+
);
|
|
50298
|
+
}
|
|
50299
|
+
const scope = args?.scope === "user" ? "user" : "project";
|
|
50300
|
+
const overwrite = args?.overwrite === true;
|
|
50301
|
+
const dir = scope === "user" ? getUserSkillsDir() : getProjectSkillsDir(root);
|
|
50302
|
+
const skillDir = resolve3(dir, name);
|
|
50303
|
+
const path104 = resolve3(skillDir, "SKILL.md");
|
|
50304
|
+
if (!path104.startsWith(resolve3(dir) + sep)) {
|
|
50305
|
+
return typedErr(
|
|
50306
|
+
`Refused: "${name}" would resolve outside the ${scope} skills directory (${resolve3(dir)}).`
|
|
50307
|
+
);
|
|
50308
|
+
}
|
|
50309
|
+
const existed = existsSync29(path104);
|
|
50310
|
+
if (existed && !overwrite) {
|
|
50311
|
+
return typedErr(
|
|
50312
|
+
`Skill "${name}" already exists at ${path104} \u2014 nothing was written. Call create_skill again with overwrite: true to replace it, or pick another name.`
|
|
50313
|
+
);
|
|
50314
|
+
}
|
|
50315
|
+
const written = upsertSkill({
|
|
50316
|
+
scope,
|
|
50317
|
+
name,
|
|
50318
|
+
description,
|
|
50319
|
+
body: instructions,
|
|
50320
|
+
projectRoot: root
|
|
50321
|
+
});
|
|
50322
|
+
if (!written.ok) {
|
|
50323
|
+
return typedErr(`Could not write SKILL.md for "${name}": ${written.error}`);
|
|
50324
|
+
}
|
|
50325
|
+
let loadable = false;
|
|
50326
|
+
try {
|
|
50327
|
+
loadSkillMdSkills(root);
|
|
50328
|
+
const registered = getCodingSkillById(name);
|
|
50329
|
+
loadable = (registered?.systemPromptFragment ?? "").trim() === instructions;
|
|
50330
|
+
} catch {
|
|
50331
|
+
}
|
|
50332
|
+
const verb = existed ? "Replaced existing skill" : "Created skill";
|
|
50333
|
+
const lines = [
|
|
50334
|
+
`${verb} "${name}" (${scope} scope).`,
|
|
50335
|
+
`Saved to: ${written.path}`
|
|
50336
|
+
];
|
|
50337
|
+
if (!loadable) {
|
|
50338
|
+
lines.push(
|
|
50339
|
+
`Note: \`${name}\` currently resolves to a DIFFERENT skill already registered from another root (a built-in or an earlier search dir wins), so \`/skill ${name}\` may load that one instead. The file on disk is unchanged.`
|
|
50340
|
+
);
|
|
50341
|
+
}
|
|
50342
|
+
lines.push(
|
|
50343
|
+
`Use it now: \`/skill ${name}\` \u2014 or call the \`skill\` tool with name "${name}". Skills are discovered on demand, so no restart is needed.`
|
|
50344
|
+
);
|
|
50345
|
+
return typedOk({
|
|
50346
|
+
name,
|
|
50347
|
+
scope,
|
|
50348
|
+
path: written.path,
|
|
50349
|
+
overwritten: existed,
|
|
50350
|
+
loadable,
|
|
50351
|
+
message: lines.join("\n")
|
|
50352
|
+
});
|
|
50353
|
+
}
|
|
50354
|
+
};
|
|
50355
|
+
}
|
|
50356
|
+
var NAME_RE2, CreateSkillArgsSchema;
|
|
50357
|
+
var init_createSkillTool = __esm({
|
|
50358
|
+
"src/cli/tools/createSkillTool.ts"() {
|
|
50359
|
+
"use strict";
|
|
50360
|
+
init_zod();
|
|
50361
|
+
init_skills2();
|
|
50362
|
+
init_toolTypes();
|
|
50363
|
+
init_skillConfigIo();
|
|
50364
|
+
init_skillsMd();
|
|
50365
|
+
NAME_RE2 = /^[a-z0-9][a-z0-9-]{1,39}$/;
|
|
50366
|
+
CreateSkillArgsSchema = external_exports.object({
|
|
50367
|
+
name: external_exports.string().regex(NAME_RE2).describe(
|
|
50368
|
+
"Skill id/slug: 2-40 chars, lowercase letters/digits/hyphens, must start with a letter or digit."
|
|
50369
|
+
),
|
|
50370
|
+
description: external_exports.string().min(1).describe(
|
|
50371
|
+
"One-line description shown in the skill catalog (when to use it). Collapsed to a single line."
|
|
50372
|
+
),
|
|
50373
|
+
instructions: external_exports.string().min(1).describe(
|
|
50374
|
+
"The skill body, in markdown: goal, step-by-step procedure, exact commands, pitfalls. Becomes the loaded instructions verbatim."
|
|
50375
|
+
),
|
|
50376
|
+
scope: external_exports.enum(["project", "user"]).optional().describe(
|
|
50377
|
+
"Where to save: 'project' (default) = <cwd>/.zelari/skills (repo-shared); 'user' = ~/.zelari-code/skills (every project)."
|
|
50378
|
+
),
|
|
50379
|
+
overwrite: external_exports.boolean().optional().describe("Default false: fail if a SKILL.md for that name already exists. Pass true to replace it.")
|
|
50380
|
+
});
|
|
50381
|
+
}
|
|
50382
|
+
});
|
|
50383
|
+
|
|
49913
50384
|
// src/cli/tools/todoTools.ts
|
|
49914
50385
|
function createTodoWriteTool() {
|
|
49915
50386
|
return {
|
|
@@ -50301,13 +50772,13 @@ async function scanTsbuildinfo(root) {
|
|
|
50301
50772
|
return found;
|
|
50302
50773
|
}
|
|
50303
50774
|
async function gitStatusPorcelain(root) {
|
|
50304
|
-
return new Promise((
|
|
50775
|
+
return new Promise((resolve10) => {
|
|
50305
50776
|
const child = spawn9("git", ["status", "--porcelain"], { cwd: root, shell: false });
|
|
50306
50777
|
let out = "";
|
|
50307
50778
|
child.stdout.on("data", (d) => out += d.toString());
|
|
50308
50779
|
child.stderr.on("data", (d) => out += d.toString());
|
|
50309
|
-
child.on("error", () =>
|
|
50310
|
-
child.on("close", (code) =>
|
|
50780
|
+
child.on("error", () => resolve10("<git-unavailable>"));
|
|
50781
|
+
child.on("close", (code) => resolve10(code === 0 ? out : `<git-exit-${code ?? "none"}>`));
|
|
50311
50782
|
});
|
|
50312
50783
|
}
|
|
50313
50784
|
async function fingerprintWorkspace(root) {
|
|
@@ -50354,14 +50825,14 @@ var init_inspectTypecheckSafety = __esm({
|
|
|
50354
50825
|
// src/cli/tools/inspectCommand.ts
|
|
50355
50826
|
import { spawn as spawn10 } from "node:child_process";
|
|
50356
50827
|
import { createHash as createHash14 } from "node:crypto";
|
|
50357
|
-
import { existsSync as
|
|
50828
|
+
import { existsSync as existsSync30, promises as fs23 } from "node:fs";
|
|
50358
50829
|
import os2 from "node:os";
|
|
50359
50830
|
import path52 from "node:path";
|
|
50360
50831
|
function resolveNodeModuleBin(start, rel2) {
|
|
50361
50832
|
let dir = path52.resolve(start);
|
|
50362
50833
|
for (; ; ) {
|
|
50363
50834
|
const candidate = path52.join(dir, "node_modules", rel2);
|
|
50364
|
-
if (
|
|
50835
|
+
if (existsSync30(candidate)) return candidate;
|
|
50365
50836
|
const parent = path52.dirname(dir);
|
|
50366
50837
|
if (parent === dir) return void 0;
|
|
50367
50838
|
dir = parent;
|
|
@@ -50465,12 +50936,12 @@ function buildInspectCommand(op, ctx) {
|
|
|
50465
50936
|
}
|
|
50466
50937
|
}
|
|
50467
50938
|
function runSpawn(command, argv, opts) {
|
|
50468
|
-
return new Promise((
|
|
50939
|
+
return new Promise((resolve10) => {
|
|
50469
50940
|
let child;
|
|
50470
50941
|
try {
|
|
50471
50942
|
child = spawn10(command, argv, { cwd: opts.cwd, shell: false });
|
|
50472
50943
|
} catch (err) {
|
|
50473
|
-
|
|
50944
|
+
resolve10({ code: null, stdout: "", stderr: String(err), timedOut: false, spawnError: String(err) });
|
|
50474
50945
|
return;
|
|
50475
50946
|
}
|
|
50476
50947
|
let stdout = "";
|
|
@@ -50492,14 +50963,14 @@ function runSpawn(command, argv, opts) {
|
|
|
50492
50963
|
if (settled) return;
|
|
50493
50964
|
settled = true;
|
|
50494
50965
|
clearTimeout(timer);
|
|
50495
|
-
|
|
50966
|
+
resolve10({ code: null, stdout, stderr, timedOut, spawnError: err.message });
|
|
50496
50967
|
});
|
|
50497
50968
|
child.on("close", (code) => {
|
|
50498
50969
|
if (settled) return;
|
|
50499
50970
|
settled = true;
|
|
50500
50971
|
clearTimeout(timer);
|
|
50501
50972
|
opts.signal?.removeEventListener("abort", onAbort);
|
|
50502
|
-
|
|
50973
|
+
resolve10({ code, stdout, stderr, timedOut });
|
|
50503
50974
|
});
|
|
50504
50975
|
});
|
|
50505
50976
|
}
|
|
@@ -50784,7 +51255,7 @@ function createExecProcessTool(root, opts = {}) {
|
|
|
50784
51255
|
const msg = err instanceof SandboxViolationError ? err.message : String(err);
|
|
50785
51256
|
return typedErr(`[sandbox] ${msg}`);
|
|
50786
51257
|
}
|
|
50787
|
-
return new Promise((
|
|
51258
|
+
return new Promise((resolve10) => {
|
|
50788
51259
|
const start = Date.now();
|
|
50789
51260
|
const spec = { ...baseSpec, network: opts.resolveNetwork?.(input) ?? baseSpec.network };
|
|
50790
51261
|
const res = spawnJailed(spec, {
|
|
@@ -50796,11 +51267,11 @@ function createExecProcessTool(root, opts = {}) {
|
|
|
50796
51267
|
envExtras: { CI: process.env.CI ?? "1" }
|
|
50797
51268
|
});
|
|
50798
51269
|
if (res.outcome === "denied") {
|
|
50799
|
-
|
|
51270
|
+
resolve10(typedErr(res.reason));
|
|
50800
51271
|
return;
|
|
50801
51272
|
}
|
|
50802
51273
|
if (res.outcome === "failed") {
|
|
50803
|
-
|
|
51274
|
+
resolve10(typedErr(`exec_process could not launch ${input.program}: ${res.reason}`));
|
|
50804
51275
|
return;
|
|
50805
51276
|
}
|
|
50806
51277
|
const meta3 = res.notice ? { status: "complete", warnings: [`os-jail: ${res.notice}`] } : void 0;
|
|
@@ -50816,7 +51287,7 @@ function createExecProcessTool(root, opts = {}) {
|
|
|
50816
51287
|
const timeoutMs2 = typeof input.timeoutMs === "number" && input.timeoutMs > 0 ? input.timeoutMs : 3e4;
|
|
50817
51288
|
const timer = setTimeout(() => {
|
|
50818
51289
|
child.kill("SIGTERM");
|
|
50819
|
-
|
|
51290
|
+
resolve10(
|
|
50820
51291
|
typedErr(
|
|
50821
51292
|
`exec_process timed out after ${timeoutMs2}ms running: ${[input.program, ...argv].join(" ")}`
|
|
50822
51293
|
)
|
|
@@ -50824,11 +51295,11 @@ function createExecProcessTool(root, opts = {}) {
|
|
|
50824
51295
|
}, timeoutMs2);
|
|
50825
51296
|
child.on("error", (err) => {
|
|
50826
51297
|
clearTimeout(timer);
|
|
50827
|
-
|
|
51298
|
+
resolve10(typedErr(`exec_process could not launch ${input.program}: ${err.message}`));
|
|
50828
51299
|
});
|
|
50829
51300
|
child.on("close", (code) => {
|
|
50830
51301
|
clearTimeout(timer);
|
|
50831
|
-
|
|
51302
|
+
resolve10(
|
|
50832
51303
|
typedOk(
|
|
50833
51304
|
{
|
|
50834
51305
|
exitCode: code ?? -1,
|
|
@@ -51357,12 +51828,12 @@ var init_client = __esm({
|
|
|
51357
51828
|
if (this.closed) return Promise.reject(new Error("LSP transport is closed"));
|
|
51358
51829
|
const id3 = this.nextId++;
|
|
51359
51830
|
const msg = { jsonrpc: "2.0", id: id3, method, ...params !== void 0 ? { params } : {} };
|
|
51360
|
-
return new Promise((
|
|
51831
|
+
return new Promise((resolve10, reject) => {
|
|
51361
51832
|
const timer = setTimeout(() => {
|
|
51362
51833
|
this.pending.delete(id3);
|
|
51363
51834
|
reject(new Error(`LSP request "${method}" timed out after ${this.timeoutMs}ms`));
|
|
51364
51835
|
}, this.timeoutMs);
|
|
51365
|
-
this.pending.set(id3, { resolve:
|
|
51836
|
+
this.pending.set(id3, { resolve: resolve10, reject, timer });
|
|
51366
51837
|
this.transport.send(encodeMessage(msg));
|
|
51367
51838
|
});
|
|
51368
51839
|
}
|
|
@@ -51481,7 +51952,7 @@ var init_servers = __esm({
|
|
|
51481
51952
|
|
|
51482
51953
|
// src/cli/lsp/manager.ts
|
|
51483
51954
|
import { spawn as spawn11 } from "node:child_process";
|
|
51484
|
-
import { readFileSync as
|
|
51955
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
51485
51956
|
import path54 from "node:path";
|
|
51486
51957
|
function processTransport(child) {
|
|
51487
51958
|
return {
|
|
@@ -51639,8 +52110,8 @@ var init_manager = __esm({
|
|
|
51639
52110
|
if (cached2 !== void 0) return cached2;
|
|
51640
52111
|
let resolveInit;
|
|
51641
52112
|
let rejectInit;
|
|
51642
|
-
const initialized = new Promise((
|
|
51643
|
-
resolveInit =
|
|
52113
|
+
const initialized = new Promise((resolve10, reject) => {
|
|
52114
|
+
resolveInit = resolve10;
|
|
51644
52115
|
rejectInit = reject;
|
|
51645
52116
|
});
|
|
51646
52117
|
let entry = null;
|
|
@@ -51695,7 +52166,7 @@ var init_manager = __esm({
|
|
|
51695
52166
|
const uri = pathToUri(file2);
|
|
51696
52167
|
let text;
|
|
51697
52168
|
try {
|
|
51698
|
-
text =
|
|
52169
|
+
text = readFileSync21(file2, "utf8");
|
|
51699
52170
|
} catch {
|
|
51700
52171
|
text = "";
|
|
51701
52172
|
}
|
|
@@ -51975,7 +52446,7 @@ var init_store2 = __esm({
|
|
|
51975
52446
|
});
|
|
51976
52447
|
|
|
51977
52448
|
// src/cli/semantic/index.ts
|
|
51978
|
-
import { promises as fs24, existsSync as
|
|
52449
|
+
import { promises as fs24, existsSync as existsSync31, readFileSync as readFileSync22 } from "node:fs";
|
|
51979
52450
|
import path55 from "node:path";
|
|
51980
52451
|
import { createHash as createHash15 } from "node:crypto";
|
|
51981
52452
|
function getIndexPath(root) {
|
|
@@ -52058,9 +52529,9 @@ async function saveIndex(root, data) {
|
|
|
52058
52529
|
}
|
|
52059
52530
|
function loadIndex(root) {
|
|
52060
52531
|
const file2 = getIndexPath(root);
|
|
52061
|
-
if (!
|
|
52532
|
+
if (!existsSync31(file2)) return null;
|
|
52062
52533
|
try {
|
|
52063
|
-
const parsed = JSON.parse(
|
|
52534
|
+
const parsed = JSON.parse(readFileSync22(file2, "utf8"));
|
|
52064
52535
|
if (parsed && Array.isArray(parsed.chunks)) return parsed;
|
|
52065
52536
|
} catch {
|
|
52066
52537
|
}
|
|
@@ -52165,14 +52636,14 @@ function resolveStreamTimeouts(capabilities) {
|
|
|
52165
52636
|
};
|
|
52166
52637
|
}
|
|
52167
52638
|
function abortableSleep(ms, signal) {
|
|
52168
|
-
return new Promise((
|
|
52169
|
-
if (signal?.aborted) return
|
|
52170
|
-
const t = setTimeout(
|
|
52639
|
+
return new Promise((resolve10) => {
|
|
52640
|
+
if (signal?.aborted) return resolve10();
|
|
52641
|
+
const t = setTimeout(resolve10, ms);
|
|
52171
52642
|
signal?.addEventListener(
|
|
52172
52643
|
"abort",
|
|
52173
52644
|
() => {
|
|
52174
52645
|
clearTimeout(t);
|
|
52175
|
-
|
|
52646
|
+
resolve10();
|
|
52176
52647
|
},
|
|
52177
52648
|
{ once: true }
|
|
52178
52649
|
);
|
|
@@ -53046,8 +53517,8 @@ async function runBrowserCheck(options, loader) {
|
|
|
53046
53517
|
const failedRequests = [];
|
|
53047
53518
|
const evaluateResults = [];
|
|
53048
53519
|
const base2 = { ok: false, consoleErrors, pageErrors, failedRequests };
|
|
53049
|
-
const
|
|
53050
|
-
const pw = await
|
|
53520
|
+
const resolve10 = loader ?? (() => loadPlaywright(options.cwd ?? process.cwd()));
|
|
53521
|
+
const pw = await resolve10();
|
|
53051
53522
|
if (!pw) {
|
|
53052
53523
|
return {
|
|
53053
53524
|
...base2,
|
|
@@ -53422,18 +53893,18 @@ __export(targets_exports, {
|
|
|
53422
53893
|
});
|
|
53423
53894
|
import {
|
|
53424
53895
|
chmodSync,
|
|
53425
|
-
existsSync as
|
|
53426
|
-
mkdirSync as
|
|
53427
|
-
readFileSync as
|
|
53428
|
-
writeFileSync as
|
|
53896
|
+
existsSync as existsSync32,
|
|
53897
|
+
mkdirSync as mkdirSync14,
|
|
53898
|
+
readFileSync as readFileSync23,
|
|
53899
|
+
writeFileSync as writeFileSync17
|
|
53429
53900
|
} from "node:fs";
|
|
53430
|
-
import { dirname as
|
|
53901
|
+
import { dirname as dirname5, join as join21 } from "node:path";
|
|
53431
53902
|
import { spawn as spawn12 } from "node:child_process";
|
|
53432
53903
|
function getSshTargetsPath() {
|
|
53433
|
-
return
|
|
53904
|
+
return join21(zelariHome(), "ssh-targets.json");
|
|
53434
53905
|
}
|
|
53435
53906
|
function getSshSecretsPath() {
|
|
53436
|
-
return
|
|
53907
|
+
return join21(zelariHome(), "ssh-secrets.json");
|
|
53437
53908
|
}
|
|
53438
53909
|
function normalizeAuth(auth) {
|
|
53439
53910
|
if (auth === "keyPath") return "keyPath";
|
|
@@ -53441,21 +53912,21 @@ function normalizeAuth(auth) {
|
|
|
53441
53912
|
return "agent";
|
|
53442
53913
|
}
|
|
53443
53914
|
function readSecrets() {
|
|
53444
|
-
const
|
|
53445
|
-
if (!
|
|
53915
|
+
const path104 = getSshSecretsPath();
|
|
53916
|
+
if (!existsSync32(path104)) return {};
|
|
53446
53917
|
try {
|
|
53447
|
-
return JSON.parse(
|
|
53918
|
+
return JSON.parse(readFileSync23(path104, "utf8"));
|
|
53448
53919
|
} catch {
|
|
53449
53920
|
return {};
|
|
53450
53921
|
}
|
|
53451
53922
|
}
|
|
53452
53923
|
function writeSecrets(data) {
|
|
53453
|
-
const
|
|
53454
|
-
|
|
53455
|
-
|
|
53924
|
+
const path104 = getSshSecretsPath();
|
|
53925
|
+
mkdirSync14(dirname5(path104), { recursive: true });
|
|
53926
|
+
writeFileSync17(path104, `${JSON.stringify(data, null, 2)}
|
|
53456
53927
|
`, "utf8");
|
|
53457
53928
|
try {
|
|
53458
|
-
chmodSync(
|
|
53929
|
+
chmodSync(path104, 384);
|
|
53459
53930
|
} catch {
|
|
53460
53931
|
}
|
|
53461
53932
|
}
|
|
@@ -53484,10 +53955,10 @@ function deleteSshPassword(id3) {
|
|
|
53484
53955
|
writeSecrets({ passwords });
|
|
53485
53956
|
}
|
|
53486
53957
|
function readStore2() {
|
|
53487
|
-
const
|
|
53488
|
-
if (!
|
|
53958
|
+
const path104 = getSshTargetsPath();
|
|
53959
|
+
if (!existsSync32(path104)) return [];
|
|
53489
53960
|
try {
|
|
53490
|
-
const parsed = JSON.parse(
|
|
53961
|
+
const parsed = JSON.parse(readFileSync23(path104, "utf8"));
|
|
53491
53962
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
53492
53963
|
return list.filter(
|
|
53493
53964
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -53502,11 +53973,11 @@ function readStore2() {
|
|
|
53502
53973
|
}
|
|
53503
53974
|
}
|
|
53504
53975
|
function writeStore2(targets) {
|
|
53505
|
-
const
|
|
53506
|
-
|
|
53976
|
+
const path104 = getSshTargetsPath();
|
|
53977
|
+
mkdirSync14(dirname5(path104), { recursive: true });
|
|
53507
53978
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
53508
|
-
|
|
53509
|
-
|
|
53979
|
+
writeFileSync17(
|
|
53980
|
+
path104,
|
|
53510
53981
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
53511
53982
|
`,
|
|
53512
53983
|
"utf8"
|
|
@@ -53606,17 +54077,17 @@ function buildSshBaseArgs(target) {
|
|
|
53606
54077
|
return args;
|
|
53607
54078
|
}
|
|
53608
54079
|
function ensureAskpassHelper() {
|
|
53609
|
-
const dir =
|
|
53610
|
-
|
|
53611
|
-
const cjs =
|
|
53612
|
-
|
|
54080
|
+
const dir = join21(zelariHome(), "ssh-helpers");
|
|
54081
|
+
mkdirSync14(dir, { recursive: true });
|
|
54082
|
+
const cjs = join21(dir, "askpass.cjs");
|
|
54083
|
+
writeFileSync17(
|
|
53613
54084
|
cjs,
|
|
53614
54085
|
"process.stdout.write(process.env.ZELARI_SSH_ASKPASS_PASS || '');\n",
|
|
53615
54086
|
"utf8"
|
|
53616
54087
|
);
|
|
53617
54088
|
if (process.platform === "win32") {
|
|
53618
|
-
const cmd =
|
|
53619
|
-
|
|
54089
|
+
const cmd = join21(dir, "askpass.cmd");
|
|
54090
|
+
writeFileSync17(
|
|
53620
54091
|
cmd,
|
|
53621
54092
|
`@echo off\r
|
|
53622
54093
|
node "%~dp0askpass.cjs"\r
|
|
@@ -53625,8 +54096,8 @@ node "%~dp0askpass.cjs"\r
|
|
|
53625
54096
|
);
|
|
53626
54097
|
return cmd;
|
|
53627
54098
|
}
|
|
53628
|
-
const sh =
|
|
53629
|
-
|
|
54099
|
+
const sh = join21(dir, "askpass.sh");
|
|
54100
|
+
writeFileSync17(
|
|
53630
54101
|
sh,
|
|
53631
54102
|
`#!/bin/sh
|
|
53632
54103
|
exec node "$(dirname "$0")/askpass.cjs"
|
|
@@ -53640,9 +54111,9 @@ exec node "$(dirname "$0")/askpass.cjs"
|
|
|
53640
54111
|
return sh;
|
|
53641
54112
|
}
|
|
53642
54113
|
function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
53643
|
-
return new Promise((
|
|
54114
|
+
return new Promise((resolve10) => {
|
|
53644
54115
|
if (target.auth === "password" && !getSshPassword(target.id)) {
|
|
53645
|
-
|
|
54116
|
+
resolve10({
|
|
53646
54117
|
code: 1,
|
|
53647
54118
|
stdout: "",
|
|
53648
54119
|
stderr: "No password stored for this target \u2014 edit target and set password"
|
|
@@ -53674,7 +54145,7 @@ function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
|
53674
54145
|
});
|
|
53675
54146
|
const timer = setTimeout(() => {
|
|
53676
54147
|
child.kill("SIGTERM");
|
|
53677
|
-
|
|
54148
|
+
resolve10({
|
|
53678
54149
|
code: 124,
|
|
53679
54150
|
stdout,
|
|
53680
54151
|
stderr: stderr + "\n[ssh] timeout"
|
|
@@ -53682,7 +54153,7 @@ function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
|
53682
54153
|
}, timeoutMs2);
|
|
53683
54154
|
child.on("error", (err) => {
|
|
53684
54155
|
clearTimeout(timer);
|
|
53685
|
-
|
|
54156
|
+
resolve10({
|
|
53686
54157
|
code: 127,
|
|
53687
54158
|
stdout,
|
|
53688
54159
|
stderr: err.message.includes("ENOENT") ? "ssh not found on PATH \u2014 install OpenSSH client" : err.message
|
|
@@ -53690,7 +54161,7 @@ function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
|
53690
54161
|
});
|
|
53691
54162
|
child.on("close", (code) => {
|
|
53692
54163
|
clearTimeout(timer);
|
|
53693
|
-
|
|
54164
|
+
resolve10({ code: code ?? 1, stdout, stderr });
|
|
53694
54165
|
});
|
|
53695
54166
|
});
|
|
53696
54167
|
}
|
|
@@ -53699,9 +54170,9 @@ function readSshPublicKey(keyOrPubPath) {
|
|
|
53699
54170
|
if (!raw) return { ok: false, error: "Empty path" };
|
|
53700
54171
|
const candidates = raw.endsWith(".pub") ? [raw] : [`${raw}.pub`, raw];
|
|
53701
54172
|
for (const p3 of candidates) {
|
|
53702
|
-
if (!
|
|
54173
|
+
if (!existsSync32(p3)) continue;
|
|
53703
54174
|
try {
|
|
53704
|
-
const content =
|
|
54175
|
+
const content = readFileSync23(p3, "utf8").trim();
|
|
53705
54176
|
if (!content) continue;
|
|
53706
54177
|
if (/BEGIN .*PRIVATE KEY/i.test(content)) {
|
|
53707
54178
|
return {
|
|
@@ -53752,11 +54223,11 @@ function formatSshTargetsForPrompt() {
|
|
|
53752
54223
|
];
|
|
53753
54224
|
for (const t of targets) {
|
|
53754
54225
|
const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
|
|
53755
|
-
const
|
|
54226
|
+
const path104 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
|
|
53756
54227
|
const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
|
|
53757
54228
|
const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
|
|
53758
54229
|
lines.push(
|
|
53759
|
-
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${
|
|
54230
|
+
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path104}${tags}${allow}`
|
|
53760
54231
|
);
|
|
53761
54232
|
}
|
|
53762
54233
|
return lines.join("\n");
|
|
@@ -54467,14 +54938,14 @@ function backoffDelay2(attempt, retryAfterHeader) {
|
|
|
54467
54938
|
return Math.min(BACKOFF_BASE_MS2 * 2 ** attempt, BACKOFF_CAP_MS2);
|
|
54468
54939
|
}
|
|
54469
54940
|
function abortableSleep2(ms, signal) {
|
|
54470
|
-
return new Promise((
|
|
54471
|
-
if (signal?.aborted) return
|
|
54472
|
-
const t = setTimeout(
|
|
54941
|
+
return new Promise((resolve10) => {
|
|
54942
|
+
if (signal?.aborted) return resolve10();
|
|
54943
|
+
const t = setTimeout(resolve10, ms);
|
|
54473
54944
|
signal?.addEventListener(
|
|
54474
54945
|
"abort",
|
|
54475
54946
|
() => {
|
|
54476
54947
|
clearTimeout(t);
|
|
54477
|
-
|
|
54948
|
+
resolve10();
|
|
54478
54949
|
},
|
|
54479
54950
|
{ once: true }
|
|
54480
54951
|
);
|
|
@@ -54930,14 +55401,18 @@ function activePermissionPreset() {
|
|
|
54930
55401
|
return parsePermissionPreset(process.env.ZELARI_PERMISSION_PRESET) ?? "standard";
|
|
54931
55402
|
}
|
|
54932
55403
|
function defaultPermissionPolicy(overrides) {
|
|
54933
|
-
const
|
|
55404
|
+
const presetName = activePermissionPreset();
|
|
55405
|
+
const preset = PERMISSION_PRESETS[presetName];
|
|
54934
55406
|
return {
|
|
54935
55407
|
read: parseAction(process.env.ZELARI_PERMISSION_READ, preset.read),
|
|
54936
55408
|
write: parseAction(process.env.ZELARI_PERMISSION_WRITE, preset.write),
|
|
54937
55409
|
execute: parseAction(process.env.ZELARI_PERMISSION_EXECUTE, preset.execute),
|
|
54938
55410
|
network: parseAction(process.env.ZELARI_PERMISSION_NETWORK, preset.network),
|
|
54939
55411
|
ui: "allow",
|
|
54940
|
-
|
|
55412
|
+
// yolo means "go alone": residual asks auto-approve without a UI handler
|
|
55413
|
+
// (no more "denied timed out" piles on unattended builds). Explicit
|
|
55414
|
+
// ZELARI_AUTO=1 keeps working for every preset; deny is never promoted.
|
|
55415
|
+
auto: isAutoPermissions() || presetName === "yolo",
|
|
54941
55416
|
...overrides
|
|
54942
55417
|
};
|
|
54943
55418
|
}
|
|
@@ -55141,7 +55616,7 @@ __export(folderTrust_exports, {
|
|
|
55141
55616
|
trustFolder: () => trustFolder,
|
|
55142
55617
|
untrustFolder: () => untrustFolder
|
|
55143
55618
|
});
|
|
55144
|
-
import { existsSync as
|
|
55619
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync15, readFileSync as readFileSync24, writeFileSync as writeFileSync18 } from "node:fs";
|
|
55145
55620
|
import path60 from "node:path";
|
|
55146
55621
|
function trustStorePath() {
|
|
55147
55622
|
return _overrideStorePath ?? trustConfigPath();
|
|
@@ -55152,7 +55627,7 @@ function normalize6(p3) {
|
|
|
55152
55627
|
}
|
|
55153
55628
|
function readStore3() {
|
|
55154
55629
|
try {
|
|
55155
|
-
const raw =
|
|
55630
|
+
const raw = readFileSync24(trustStorePath(), "utf8");
|
|
55156
55631
|
const parsed = JSON.parse(raw);
|
|
55157
55632
|
if (parsed && Array.isArray(parsed.folders)) return parsed;
|
|
55158
55633
|
return DEFAULT_STORE;
|
|
@@ -55163,8 +55638,8 @@ function readStore3() {
|
|
|
55163
55638
|
function writeStore3(store6) {
|
|
55164
55639
|
const p3 = trustStorePath();
|
|
55165
55640
|
try {
|
|
55166
|
-
|
|
55167
|
-
|
|
55641
|
+
mkdirSync15(path60.dirname(p3), { recursive: true });
|
|
55642
|
+
writeFileSync18(p3, JSON.stringify(store6, null, 2), "utf8");
|
|
55168
55643
|
} catch (err) {
|
|
55169
55644
|
throw new Error(
|
|
55170
55645
|
`failed to persist trust store ${p3}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -55219,7 +55694,7 @@ function getTrustStorePath() {
|
|
|
55219
55694
|
return trustStorePath();
|
|
55220
55695
|
}
|
|
55221
55696
|
function hasTrustStore() {
|
|
55222
|
-
return
|
|
55697
|
+
return existsSync33(trustStorePath());
|
|
55223
55698
|
}
|
|
55224
55699
|
function _setTrustStorePathForTests(p3) {
|
|
55225
55700
|
_overrideStorePath = p3;
|
|
@@ -55235,13 +55710,13 @@ var init_folderTrust = __esm({
|
|
|
55235
55710
|
});
|
|
55236
55711
|
|
|
55237
55712
|
// src/cli/safety/lifecycleHooks.ts
|
|
55238
|
-
import { join as
|
|
55239
|
-
import { readdirSync as
|
|
55713
|
+
import { join as join22 } from "node:path";
|
|
55714
|
+
import { readdirSync as readdirSync7, statSync as statSync3 } from "node:fs";
|
|
55240
55715
|
function globalHooksDir() {
|
|
55241
|
-
return
|
|
55716
|
+
return join22(zelariHome(), "hooks");
|
|
55242
55717
|
}
|
|
55243
55718
|
function projectHooksDir(projectRoot) {
|
|
55244
|
-
return
|
|
55719
|
+
return join22(projectRoot, ".zelari", "hooks");
|
|
55245
55720
|
}
|
|
55246
55721
|
function resolveHookFailureMode(override, env = process.env) {
|
|
55247
55722
|
const v = override?.trim().toLowerCase();
|
|
@@ -55254,7 +55729,7 @@ function fingerprintHookDirs(dirs) {
|
|
|
55254
55729
|
for (const dir of dirs) {
|
|
55255
55730
|
let names;
|
|
55256
55731
|
try {
|
|
55257
|
-
names =
|
|
55732
|
+
names = readdirSync7(dir).filter((f) => f.endsWith(".json")).sort();
|
|
55258
55733
|
} catch {
|
|
55259
55734
|
parts.push(`${dir}:missing`);
|
|
55260
55735
|
continue;
|
|
@@ -55268,7 +55743,7 @@ function fingerprintHookDirs(dirs) {
|
|
|
55268
55743
|
continue;
|
|
55269
55744
|
}
|
|
55270
55745
|
for (const name of names) {
|
|
55271
|
-
const full =
|
|
55746
|
+
const full = join22(dir, name);
|
|
55272
55747
|
try {
|
|
55273
55748
|
const st = statSync3(full);
|
|
55274
55749
|
parts.push(`${full}:${st.mtimeMs}:${st.size}`);
|
|
@@ -55553,8 +56028,8 @@ function networkClaimsForUrls(urls) {
|
|
|
55553
56028
|
}
|
|
55554
56029
|
function mcpClaimFromName(registryName) {
|
|
55555
56030
|
const rest = registryName.startsWith("mcp_") ? registryName.slice("mcp_".length) : "";
|
|
55556
|
-
const
|
|
55557
|
-
return
|
|
56031
|
+
const sep5 = rest.indexOf("_");
|
|
56032
|
+
return sep5 <= 0 || sep5 === rest.length - 1 ? null : { kind: "mcp", server: rest.slice(0, sep5), tool: rest.slice(sep5 + 1) };
|
|
55558
56033
|
}
|
|
55559
56034
|
function browserActionUrls(a) {
|
|
55560
56035
|
const actions = Array.isArray(a["actions"]) ? a["actions"] : [];
|
|
@@ -55968,9 +56443,11 @@ __export(toolRegistry_exports, {
|
|
|
55968
56443
|
createKrakenSubAgentContextFactory: () => createKrakenSubAgentContextFactory,
|
|
55969
56444
|
getCliToolCatalogEntries: () => getCliToolCatalogEntries,
|
|
55970
56445
|
registerCliToolsIntoCouncilCatalog: () => registerCliToolsIntoCouncilCatalog,
|
|
56446
|
+
resolveTentacleThinkingInput: () => resolveTentacleThinkingInput,
|
|
56447
|
+
tentacleThinkingEnvKey: () => tentacleThinkingEnvKey,
|
|
55971
56448
|
wrapWithSandbox: () => wrapWithSandbox
|
|
55972
56449
|
});
|
|
55973
|
-
import { existsSync as
|
|
56450
|
+
import { existsSync as existsSync34 } from "node:fs";
|
|
55974
56451
|
import path63 from "node:path";
|
|
55975
56452
|
function createBuiltinToolRegistry(options = {}) {
|
|
55976
56453
|
const root = options.root ?? process.cwd();
|
|
@@ -56059,9 +56536,11 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
56059
56536
|
const gauntletParent = options.gauntletParent === true;
|
|
56060
56537
|
const allowMutators = !readOnly && !verifyMode && !gauntletParent;
|
|
56061
56538
|
const allowBash = (allowMutators || verifyMode) && !gauntletParent;
|
|
56062
|
-
if (isParent && allowMutators &&
|
|
56063
|
-
registry4.setToolResultListener(
|
|
56064
|
-
|
|
56539
|
+
if (isParent && allowMutators && options.sessionId) {
|
|
56540
|
+
registry4.setToolResultListener(
|
|
56541
|
+
createTaskTouchGuard({ projectRoot: root, sessionId: options.sessionId })
|
|
56542
|
+
);
|
|
56543
|
+
void runTaskStalenessCheck({ projectRoot: root, sessionId: options.sessionId });
|
|
56065
56544
|
}
|
|
56066
56545
|
const permPolicy = options.permissionPolicy ?? defaultPermissionPolicy();
|
|
56067
56546
|
const agentPolicySet = (() => {
|
|
@@ -56127,6 +56606,10 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
56127
56606
|
if (skillTool) {
|
|
56128
56607
|
registry4.register(skillTool);
|
|
56129
56608
|
}
|
|
56609
|
+
const skillCreateTool = enableSkill ? withPerm(createCreateSkillTool({ cwd: root })) : null;
|
|
56610
|
+
if (skillCreateTool) {
|
|
56611
|
+
registry4.register(skillCreateTool);
|
|
56612
|
+
}
|
|
56130
56613
|
const enableTodos = options.enableTodos !== false && options.readOnly !== true && !gauntletParent && profile === "full";
|
|
56131
56614
|
const todoWrite = enableTodos ? withPerm(createTodoWriteTool()) : null;
|
|
56132
56615
|
const todoRead = enableTodos ? withPerm(createTodoReadTool()) : null;
|
|
@@ -56154,6 +56637,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
56154
56637
|
...allowBash ? [safeBash, safeExecProcess] : [],
|
|
56155
56638
|
...askUserTool ? [askUserTool] : [],
|
|
56156
56639
|
...skillTool ? [skillTool] : [],
|
|
56640
|
+
...skillCreateTool ? [skillCreateTool] : [],
|
|
56157
56641
|
...todoWrite ? [todoWrite] : [],
|
|
56158
56642
|
...todoRead ? [todoRead] : [],
|
|
56159
56643
|
...planTaskToolsWrapped.length > 0 ? planTaskToolsWrapped : []
|
|
@@ -56337,9 +56821,29 @@ function taskAgentToProfile(agent) {
|
|
|
56337
56821
|
if (agent === "verify") return "verify";
|
|
56338
56822
|
return "explore";
|
|
56339
56823
|
}
|
|
56824
|
+
function tentacleThinkingEnvKey(agent) {
|
|
56825
|
+
if (agent === "explore") return "ZELARI_KRAKEN_EXPLORE_THINKING";
|
|
56826
|
+
if (agent === "verify") return "ZELARI_KRAKEN_VERIFY_THINKING";
|
|
56827
|
+
return "ZELARI_KRAKEN_GENERAL_THINKING";
|
|
56828
|
+
}
|
|
56829
|
+
function resolveTentacleThinkingInput(agent, taskArg, env = process.env) {
|
|
56830
|
+
const fromArg = typeof taskArg === "string" ? taskArg.trim() : "";
|
|
56831
|
+
const argWins = fromArg.length > 0 && fromArg.toLowerCase() !== "inherit";
|
|
56832
|
+
const key = tentacleThinkingEnvKey(agent);
|
|
56833
|
+
const raw = (argWins ? fromArg : (env[key] ?? "").trim()).trim();
|
|
56834
|
+
if (!raw) return void 0;
|
|
56835
|
+
if (isValidThinkingInput(raw)) return raw.toLowerCase();
|
|
56836
|
+
if (!warnedThinkingInputs.has(raw)) {
|
|
56837
|
+
warnedThinkingInputs.add(raw);
|
|
56838
|
+
console.warn(
|
|
56839
|
+
`[kraken] ignoring invalid thinking effort "${raw}" for the ${agent} tentacle (${key}); using the provider default.`
|
|
56840
|
+
);
|
|
56841
|
+
}
|
|
56842
|
+
return void 0;
|
|
56843
|
+
}
|
|
56340
56844
|
function createKrakenSubAgentContextFactory(opts) {
|
|
56341
56845
|
const { root, audit, sessionId: sessionId2, provider: providerOverride, model: modelOverride, parentPolicy, onPermissionAsk } = opts;
|
|
56342
|
-
return async ({ agent, cwd: subCwd }) => {
|
|
56846
|
+
return async ({ agent, cwd: subCwd, thinkingEffort }) => {
|
|
56343
56847
|
const cfg = providerOverride ? await providerConfigFor(providerOverride) : await providerFromEnv();
|
|
56344
56848
|
if (!cfg) return null;
|
|
56345
56849
|
const { resolveKrakenSubModelAsync: resolveKrakenSubModelAsync2, parseQualifiedModelRef: parseQualifiedModelRef2 } = await Promise.resolve().then(() => (init_krakenModel(), krakenModel_exports));
|
|
@@ -56358,6 +56862,8 @@ function createKrakenSubAgentContextFactory(opts) {
|
|
|
56358
56862
|
}
|
|
56359
56863
|
}
|
|
56360
56864
|
const subCfg = { ...effCfg, model };
|
|
56865
|
+
const thinkingInput = resolveTentacleThinkingInput(agent, thinkingEffort, process.env);
|
|
56866
|
+
if (thinkingInput) subCfg.thinking = parseThinkingSpec(thinkingInput);
|
|
56361
56867
|
const subProfile = taskAgentToProfile(agent);
|
|
56362
56868
|
const subRoot = subCwd || root;
|
|
56363
56869
|
const agentPolicyForSubProfile = defaultPermissionPolicy({ auto: true });
|
|
@@ -56394,6 +56900,9 @@ function createKrakenSubAgentContextFactory(opts) {
|
|
|
56394
56900
|
providerStream,
|
|
56395
56901
|
model,
|
|
56396
56902
|
provider: subCfg.providerId,
|
|
56903
|
+
// E (thinking): report the spec actually applied so the parent's
|
|
56904
|
+
// `agent_spawned` event can surface it (arg > kind env > inherited).
|
|
56905
|
+
...subCfg.thinking !== void 0 ? { thinking: stringifyThinkingSpec(subCfg.thinking) } : {},
|
|
56397
56906
|
...model !== parentModel ? {
|
|
56398
56907
|
fallback: {
|
|
56399
56908
|
model: parentModel,
|
|
@@ -56617,7 +57126,7 @@ function claimedSourcePath(token, args, root) {
|
|
|
56617
57126
|
const candidate = path63.isAbsolute(cleaned) ? path63.normalize(cleaned) : path63.resolve(base2, cleaned);
|
|
56618
57127
|
try {
|
|
56619
57128
|
const contained = resolveSandboxedPath(candidate, { root });
|
|
56620
|
-
if (
|
|
57129
|
+
if (existsSync34(contained)) return contained;
|
|
56621
57130
|
} catch {
|
|
56622
57131
|
}
|
|
56623
57132
|
}
|
|
@@ -56851,7 +57360,7 @@ function redactForAudit(args) {
|
|
|
56851
57360
|
}
|
|
56852
57361
|
return out;
|
|
56853
57362
|
}
|
|
56854
|
-
var HARNESS_BUILTIN_NAMES, DIAG_SOURCE_EXTENSIONS, EXEC_DIAGNOSTICS_MAX_FILES;
|
|
57363
|
+
var HARNESS_BUILTIN_NAMES, warnedThinkingInputs, DIAG_SOURCE_EXTENSIONS, EXEC_DIAGNOSTICS_MAX_FILES;
|
|
56855
57364
|
var init_toolRegistry = __esm({
|
|
56856
57365
|
"src/cli/toolRegistry.ts"() {
|
|
56857
57366
|
"use strict";
|
|
@@ -56873,6 +57382,7 @@ var init_toolRegistry = __esm({
|
|
|
56873
57382
|
init_krakenSelectTool();
|
|
56874
57383
|
init_askUser();
|
|
56875
57384
|
init_skillTool();
|
|
57385
|
+
init_createSkillTool();
|
|
56876
57386
|
init_todoTools();
|
|
56877
57387
|
init_planTaskTools();
|
|
56878
57388
|
init_inspectCommand();
|
|
@@ -56890,6 +57400,7 @@ var init_toolRegistry = __esm({
|
|
|
56890
57400
|
init_openai_compatible();
|
|
56891
57401
|
init_resolveStream();
|
|
56892
57402
|
init_providerConfig();
|
|
57403
|
+
init_thinking();
|
|
56893
57404
|
init_crossProviderFailover();
|
|
56894
57405
|
init_keyStore();
|
|
56895
57406
|
init_toolPermissions();
|
|
@@ -56924,6 +57435,7 @@ var init_toolRegistry = __esm({
|
|
|
56924
57435
|
"fetch_url",
|
|
56925
57436
|
"web_search"
|
|
56926
57437
|
]);
|
|
57438
|
+
warnedThinkingInputs = /* @__PURE__ */ new Set();
|
|
56927
57439
|
DIAG_SOURCE_EXTENSIONS = new Set(
|
|
56928
57440
|
DEFAULT_PROVIDERS.flatMap((p3) => p3.extensions)
|
|
56929
57441
|
);
|
|
@@ -56932,7 +57444,7 @@ var init_toolRegistry = __esm({
|
|
|
56932
57444
|
});
|
|
56933
57445
|
|
|
56934
57446
|
// src/cli/metrics.ts
|
|
56935
|
-
import { promises as fs27, existsSync as
|
|
57447
|
+
import { promises as fs27, existsSync as existsSync35, statSync as statSync4, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync16 } from "node:fs";
|
|
56936
57448
|
import path64 from "node:path";
|
|
56937
57449
|
async function readMetrics(file2) {
|
|
56938
57450
|
let raw = "";
|
|
@@ -56983,7 +57495,7 @@ var init_metrics3 = __esm({
|
|
|
56983
57495
|
writeQueue = Promise.resolve();
|
|
56984
57496
|
constructor(file2) {
|
|
56985
57497
|
this.file = file2 ?? metricsPath();
|
|
56986
|
-
|
|
57498
|
+
mkdirSync16(path64.dirname(this.file), { recursive: true });
|
|
56987
57499
|
}
|
|
56988
57500
|
/** Metrics file path — doctor/summary readers use this. */
|
|
56989
57501
|
get filePath() {
|
|
@@ -56998,12 +57510,12 @@ var init_metrics3 = __esm({
|
|
|
56998
57510
|
}
|
|
56999
57511
|
/** Append a single record synchronously (file I/O). */
|
|
57000
57512
|
append(rec) {
|
|
57001
|
-
return new Promise((
|
|
57513
|
+
return new Promise((resolve10, reject) => {
|
|
57002
57514
|
try {
|
|
57003
57515
|
this.maybeRotate();
|
|
57004
57516
|
const line = JSON.stringify(rec) + "\n";
|
|
57005
57517
|
appendFileSync3(this.file, line, { encoding: "utf-8" });
|
|
57006
|
-
|
|
57518
|
+
resolve10();
|
|
57007
57519
|
} catch (err) {
|
|
57008
57520
|
reject(err);
|
|
57009
57521
|
}
|
|
@@ -57018,7 +57530,7 @@ var init_metrics3 = __esm({
|
|
|
57018
57530
|
}
|
|
57019
57531
|
/** If the file is over the rotation threshold, rotate it. */
|
|
57020
57532
|
maybeRotate() {
|
|
57021
|
-
if (!
|
|
57533
|
+
if (!existsSync35(this.file)) return;
|
|
57022
57534
|
try {
|
|
57023
57535
|
const stat8 = statSync4(this.file);
|
|
57024
57536
|
if (stat8.size >= METRICS_ROTATE_BYTES) {
|
|
@@ -58300,7 +58812,7 @@ var init_sqliteCodec = __esm({
|
|
|
58300
58812
|
});
|
|
58301
58813
|
|
|
58302
58814
|
// src/cli/memory/sqliteRpc.ts
|
|
58303
|
-
import { existsSync as
|
|
58815
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
58304
58816
|
import { fileURLToPath as fileURLToPath2, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
58305
58817
|
import * as path69 from "node:path";
|
|
58306
58818
|
import { Worker } from "node:worker_threads";
|
|
@@ -58313,7 +58825,7 @@ function isBusy(error51) {
|
|
|
58313
58825
|
function resolveWorkerUrl() {
|
|
58314
58826
|
const here = path69.dirname(fileURLToPath2(import.meta.url));
|
|
58315
58827
|
const direct = path69.join(here, "sqliteWorker.mjs");
|
|
58316
|
-
if (
|
|
58828
|
+
if (existsSync36(direct)) return pathToFileURL2(direct);
|
|
58317
58829
|
return pathToFileURL2(path69.join(here, "memory", "sqliteWorker.mjs"));
|
|
58318
58830
|
}
|
|
58319
58831
|
var SqliteWorkerRpc;
|
|
@@ -58388,8 +58900,8 @@ var init_sqliteRpc = __esm({
|
|
|
58388
58900
|
const worker = this.worker;
|
|
58389
58901
|
if (!worker) return Promise.reject(new Error("SQLite worker is not open."));
|
|
58390
58902
|
const id3 = this.nextId++;
|
|
58391
|
-
return new Promise((
|
|
58392
|
-
this.pending.set(id3, { resolve:
|
|
58903
|
+
return new Promise((resolve10, reject) => {
|
|
58904
|
+
this.pending.set(id3, { resolve: resolve10, reject });
|
|
58393
58905
|
worker.postMessage({ id: id3, operation, args });
|
|
58394
58906
|
});
|
|
58395
58907
|
}
|
|
@@ -58400,7 +58912,7 @@ var init_sqliteRpc = __esm({
|
|
|
58400
58912
|
return await this.request(operation, args);
|
|
58401
58913
|
} catch (error51) {
|
|
58402
58914
|
if (!isBusy(error51) || attempt >= 3) throw error51;
|
|
58403
|
-
await new Promise((
|
|
58915
|
+
await new Promise((resolve10) => setTimeout(resolve10, 25 * 2 ** attempt));
|
|
58404
58916
|
attempt += 1;
|
|
58405
58917
|
}
|
|
58406
58918
|
}
|
|
@@ -60024,8 +60536,8 @@ __export(conversationContext_exports, {
|
|
|
60024
60536
|
setHistory: () => setHistory,
|
|
60025
60537
|
setLastClarification: () => setLastClarification
|
|
60026
60538
|
});
|
|
60027
|
-
import { existsSync as
|
|
60028
|
-
import { join as
|
|
60539
|
+
import { existsSync as existsSync37 } from "node:fs";
|
|
60540
|
+
import { join as join28 } from "node:path";
|
|
60029
60541
|
function getHistory() {
|
|
60030
60542
|
return history;
|
|
60031
60543
|
}
|
|
@@ -60034,7 +60546,7 @@ function setHistory(messages) {
|
|
|
60034
60546
|
history = projected === messages ? [...messages] : projected;
|
|
60035
60547
|
}
|
|
60036
60548
|
function compactInPlace(cwd = process.cwd()) {
|
|
60037
|
-
const durableStatePresent =
|
|
60549
|
+
const durableStatePresent = existsSync37(join28(cwd, ".zelari", "state", "HEAD.json"));
|
|
60038
60550
|
history = applySessionSurface(compactHistory(history, { durableStatePresent }));
|
|
60039
60551
|
}
|
|
60040
60552
|
function appendMessages(msgs) {
|
|
@@ -60416,7 +60928,7 @@ var init_mode = __esm({
|
|
|
60416
60928
|
});
|
|
60417
60929
|
|
|
60418
60930
|
// src/cli/headless.ts
|
|
60419
|
-
import { readFileSync as
|
|
60931
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
60420
60932
|
import path73 from "node:path";
|
|
60421
60933
|
function resolveHeadlessCwd(opts) {
|
|
60422
60934
|
const raw = typeof opts.cwd === "string" ? opts.cwd.trim() : "";
|
|
@@ -60479,7 +60991,7 @@ function parseHeadlessFlags(argv) {
|
|
|
60479
60991
|
const next = argv[i + 1];
|
|
60480
60992
|
if (next) {
|
|
60481
60993
|
try {
|
|
60482
|
-
const fromFile =
|
|
60994
|
+
const fromFile = readFileSync25(next, "utf-8");
|
|
60483
60995
|
if (fromFile.trim()) task = fromFile;
|
|
60484
60996
|
} catch {
|
|
60485
60997
|
}
|
|
@@ -60528,7 +61040,7 @@ function parseHeadlessFlags(argv) {
|
|
|
60528
61040
|
let raw = null;
|
|
60529
61041
|
if (arg === "--history-file") {
|
|
60530
61042
|
try {
|
|
60531
|
-
raw =
|
|
61043
|
+
raw = readFileSync25(next, "utf-8");
|
|
60532
61044
|
} catch {
|
|
60533
61045
|
raw = null;
|
|
60534
61046
|
}
|
|
@@ -60630,7 +61142,7 @@ function parseHeadlessFlags(argv) {
|
|
|
60630
61142
|
const next = argv[i + 1];
|
|
60631
61143
|
if (next) {
|
|
60632
61144
|
try {
|
|
60633
|
-
const fromFile =
|
|
61145
|
+
const fromFile = readFileSync25(next, "utf-8");
|
|
60634
61146
|
if (fromFile.trim()) krakenGraph = fromFile;
|
|
60635
61147
|
} catch {
|
|
60636
61148
|
}
|
|
@@ -61319,13 +61831,13 @@ __export(claudeProvider_exports, {
|
|
|
61319
61831
|
});
|
|
61320
61832
|
import { spawn as spawn13 } from "node:child_process";
|
|
61321
61833
|
function waitForExit(child, timeoutMs2 = 2e3) {
|
|
61322
|
-
return new Promise((
|
|
61323
|
-
if (child.exitCode != null) return
|
|
61324
|
-
const timer = setTimeout(() =>
|
|
61834
|
+
return new Promise((resolve10) => {
|
|
61835
|
+
if (child.exitCode != null) return resolve10(child.exitCode);
|
|
61836
|
+
const timer = setTimeout(() => resolve10(child.exitCode ?? null), timeoutMs2);
|
|
61325
61837
|
timer.unref?.();
|
|
61326
61838
|
child.once("exit", (code) => {
|
|
61327
61839
|
clearTimeout(timer);
|
|
61328
|
-
|
|
61840
|
+
resolve10(code ?? null);
|
|
61329
61841
|
});
|
|
61330
61842
|
});
|
|
61331
61843
|
}
|
|
@@ -61528,13 +62040,13 @@ var planDetect_exports = {};
|
|
|
61528
62040
|
__export(planDetect_exports, {
|
|
61529
62041
|
hasWorkspacePlan: () => hasWorkspacePlan
|
|
61530
62042
|
});
|
|
61531
|
-
import { existsSync as
|
|
61532
|
-
import { join as
|
|
62043
|
+
import { existsSync as existsSync38, readFileSync as readFileSync26 } from "node:fs";
|
|
62044
|
+
import { join as join29 } from "node:path";
|
|
61533
62045
|
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
61534
|
-
const planPath =
|
|
61535
|
-
if (!
|
|
62046
|
+
const planPath = join29(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
62047
|
+
if (!existsSync38(planPath)) return false;
|
|
61536
62048
|
try {
|
|
61537
|
-
const parsed = JSON.parse(
|
|
62049
|
+
const parsed = JSON.parse(readFileSync26(planPath, "utf8"));
|
|
61538
62050
|
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
61539
62051
|
} catch {
|
|
61540
62052
|
return false;
|
|
@@ -61548,14 +62060,14 @@ var init_planDetect = __esm({
|
|
|
61548
62060
|
});
|
|
61549
62061
|
|
|
61550
62062
|
// src/cli/workspace/projectInstructions.ts
|
|
61551
|
-
import { existsSync as
|
|
61552
|
-
import { join as
|
|
62063
|
+
import { existsSync as existsSync39, readFileSync as readFileSync27 } from "node:fs";
|
|
62064
|
+
import { join as join30 } from "node:path";
|
|
61553
62065
|
function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
|
|
61554
62066
|
for (const name of CANDIDATES) {
|
|
61555
|
-
const full =
|
|
61556
|
-
if (!
|
|
62067
|
+
const full = join30(projectRoot, name);
|
|
62068
|
+
if (!existsSync39(full)) continue;
|
|
61557
62069
|
try {
|
|
61558
|
-
let raw =
|
|
62070
|
+
let raw = readFileSync27(full, "utf8");
|
|
61559
62071
|
raw = raw.replace(/\r\n/g, "\n").trim();
|
|
61560
62072
|
if (!raw) continue;
|
|
61561
62073
|
if (raw.length <= maxChars) {
|
|
@@ -61599,8 +62111,8 @@ __export(workspaceSummary_exports, {
|
|
|
61599
62111
|
buildWorkspaceSummary: () => buildWorkspaceSummary,
|
|
61600
62112
|
buildZelariReadHint: () => buildZelariReadHint
|
|
61601
62113
|
});
|
|
61602
|
-
import { existsSync as
|
|
61603
|
-
import { join as
|
|
62114
|
+
import { existsSync as existsSync40, readFileSync as readFileSync28, readdirSync as readdirSync8, statSync as statSync5 } from "node:fs";
|
|
62115
|
+
import { join as join31, relative as relative2 } from "node:path";
|
|
61604
62116
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
61605
62117
|
const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
|
|
61606
62118
|
const name = safeProjectName(projectRoot);
|
|
@@ -61633,11 +62145,11 @@ function formatTaskLine(t) {
|
|
|
61633
62145
|
}
|
|
61634
62146
|
function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
61635
62147
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
61636
|
-
const planPath =
|
|
61637
|
-
if (!
|
|
62148
|
+
const planPath = join31(zelariRoot, "plan.json");
|
|
62149
|
+
if (!existsSync40(planPath)) return null;
|
|
61638
62150
|
let plan;
|
|
61639
62151
|
try {
|
|
61640
|
-
plan = JSON.parse(
|
|
62152
|
+
plan = JSON.parse(readFileSync28(planPath, "utf8"));
|
|
61641
62153
|
} catch {
|
|
61642
62154
|
return null;
|
|
61643
62155
|
}
|
|
@@ -61776,8 +62288,8 @@ function pickNextTask(open2) {
|
|
|
61776
62288
|
)[0];
|
|
61777
62289
|
}
|
|
61778
62290
|
function buildZelariReadHint(projectRoot = process.cwd()) {
|
|
61779
|
-
const planPath =
|
|
61780
|
-
if (!
|
|
62291
|
+
const planPath = join31(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
62292
|
+
if (!existsSync40(planPath)) return "";
|
|
61781
62293
|
return [
|
|
61782
62294
|
"# Council workspace detected (.zelari/) \u2014 DRAFT vault",
|
|
61783
62295
|
"`.zelari/plan.json` and `.zelari/docs/` hold **design hypotheses**, not verified product state.",
|
|
@@ -61792,10 +62304,10 @@ function safeProjectName(root) {
|
|
|
61792
62304
|
}
|
|
61793
62305
|
}
|
|
61794
62306
|
function readPackageJson2(projectRoot) {
|
|
61795
|
-
const p3 =
|
|
61796
|
-
if (!
|
|
62307
|
+
const p3 = join31(projectRoot, "package.json");
|
|
62308
|
+
if (!existsSync40(p3)) return null;
|
|
61797
62309
|
try {
|
|
61798
|
-
return JSON.parse(
|
|
62310
|
+
return JSON.parse(readFileSync28(p3, "utf8"));
|
|
61799
62311
|
} catch {
|
|
61800
62312
|
return null;
|
|
61801
62313
|
}
|
|
@@ -61836,7 +62348,7 @@ function readBuildScripts(projectRoot, maxScripts = 16) {
|
|
|
61836
62348
|
function listShallow(projectRoot, maxEntries) {
|
|
61837
62349
|
const out = [];
|
|
61838
62350
|
try {
|
|
61839
|
-
const top =
|
|
62351
|
+
const top = readdirSync8(projectRoot, { withFileTypes: true }).filter(
|
|
61840
62352
|
(e) => !e.name.startsWith(".") && e.name !== "node_modules" && e.name !== "dist"
|
|
61841
62353
|
).sort((a, b) => a.name.localeCompare(b.name));
|
|
61842
62354
|
let count = 0;
|
|
@@ -61845,11 +62357,11 @@ function listShallow(projectRoot, maxEntries) {
|
|
|
61845
62357
|
out.push(`\u2026 (+${top.length - count} more)`);
|
|
61846
62358
|
break;
|
|
61847
62359
|
}
|
|
61848
|
-
const rel2 = relative2(projectRoot,
|
|
62360
|
+
const rel2 = relative2(projectRoot, join31(projectRoot, entry.name));
|
|
61849
62361
|
if (entry.isDirectory()) {
|
|
61850
62362
|
let inner = "";
|
|
61851
62363
|
try {
|
|
61852
|
-
const sub =
|
|
62364
|
+
const sub = readdirSync8(join31(projectRoot, entry.name), {
|
|
61853
62365
|
withFileTypes: true
|
|
61854
62366
|
}).filter((e) => !e.name.startsWith(".")).slice(0, 4).map((e) => e.name);
|
|
61855
62367
|
if (sub.length > 0)
|
|
@@ -61897,12 +62409,12 @@ var init_workspaceSummary = __esm({
|
|
|
61897
62409
|
});
|
|
61898
62410
|
|
|
61899
62411
|
// src/cli/workspace/buildLessonsSummary.ts
|
|
61900
|
-
import { existsSync as
|
|
61901
|
-
import { join as
|
|
62412
|
+
import { existsSync as existsSync41 } from "node:fs";
|
|
62413
|
+
import { join as join32 } from "node:path";
|
|
61902
62414
|
function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
|
|
61903
62415
|
if (process.env["ZELARI_LESSONS"] === "0") return null;
|
|
61904
62416
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
61905
|
-
if (!
|
|
62417
|
+
if (!existsSync41(join32(zelariRoot, "lessons.jsonl"))) return null;
|
|
61906
62418
|
const lessons = recallLessons(zelariRoot, {
|
|
61907
62419
|
maxLessons: 5,
|
|
61908
62420
|
maxBytes: 2048,
|
|
@@ -61923,8 +62435,8 @@ var composeContext_exports = {};
|
|
|
61923
62435
|
__export(composeContext_exports, {
|
|
61924
62436
|
composeProjectContext: () => composeProjectContext
|
|
61925
62437
|
});
|
|
61926
|
-
import { existsSync as
|
|
61927
|
-
import { join as
|
|
62438
|
+
import { existsSync as existsSync42, readdirSync as readdirSync9, readFileSync as readFileSync29 } from "node:fs";
|
|
62439
|
+
import { join as join33 } from "node:path";
|
|
61928
62440
|
function cap2(text, max, label) {
|
|
61929
62441
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
61930
62442
|
return {
|
|
@@ -61936,19 +62448,19 @@ function cap2(text, max, label) {
|
|
|
61936
62448
|
}
|
|
61937
62449
|
function buildDesignIndex(projectRoot, maxChars) {
|
|
61938
62450
|
const root = resolveWorkspaceRoot(projectRoot);
|
|
61939
|
-
if (!
|
|
62451
|
+
if (!existsSync42(root)) return "";
|
|
61940
62452
|
const lines = [
|
|
61941
62453
|
"# Design vault index (.zelari/) \u2014 HYPOTHESES only",
|
|
61942
62454
|
"Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
|
|
61943
62455
|
];
|
|
61944
|
-
const docsDir =
|
|
61945
|
-
if (
|
|
62456
|
+
const docsDir = join33(root, "docs");
|
|
62457
|
+
if (existsSync42(docsDir)) {
|
|
61946
62458
|
try {
|
|
61947
|
-
const docs =
|
|
62459
|
+
const docs = readdirSync9(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
|
|
61948
62460
|
if (docs.length > 0) {
|
|
61949
62461
|
lines.push("", "## docs/ (titles only)");
|
|
61950
62462
|
for (const d of docs) lines.push(`- .zelari/docs/${d}`);
|
|
61951
|
-
if (
|
|
62463
|
+
if (readdirSync9(docsDir).filter((n) => n.endsWith(".md")).length > 12) {
|
|
61952
62464
|
lines.push("- \u2026 (more under .zelari/docs/)");
|
|
61953
62465
|
}
|
|
61954
62466
|
}
|
|
@@ -61956,14 +62468,14 @@ function buildDesignIndex(projectRoot, maxChars) {
|
|
|
61956
62468
|
}
|
|
61957
62469
|
}
|
|
61958
62470
|
for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
|
|
61959
|
-
if (
|
|
62471
|
+
if (existsSync42(join33(root, name))) {
|
|
61960
62472
|
lines.push(`- .zelari/${name} present`);
|
|
61961
62473
|
}
|
|
61962
62474
|
}
|
|
61963
|
-
const decisionsDir =
|
|
61964
|
-
if (
|
|
62475
|
+
const decisionsDir = join33(root, "decisions");
|
|
62476
|
+
if (existsSync42(decisionsDir)) {
|
|
61965
62477
|
try {
|
|
61966
|
-
const n =
|
|
62478
|
+
const n = readdirSync9(decisionsDir).filter((f) => f.endsWith(".md")).length;
|
|
61967
62479
|
if (n > 0) lines.push(`- .zelari/decisions/ (${n} ADR file(s) \u2014 treat proposed as non-binding)`);
|
|
61968
62480
|
} catch {
|
|
61969
62481
|
}
|
|
@@ -62062,17 +62574,17 @@ function composeProjectContext(input) {
|
|
|
62062
62574
|
}
|
|
62063
62575
|
function readDurableHeadSync(projectRoot) {
|
|
62064
62576
|
try {
|
|
62065
|
-
const headPath =
|
|
62066
|
-
if (!
|
|
62067
|
-
const head = JSON.parse(
|
|
62577
|
+
const headPath = join33(projectRoot, ".zelari", "state", "HEAD.json");
|
|
62578
|
+
if (!existsSync42(headPath)) return "";
|
|
62579
|
+
const head = JSON.parse(readFileSync29(headPath, "utf8"));
|
|
62068
62580
|
if (!head?.id) return "";
|
|
62069
|
-
const metaPath =
|
|
62070
|
-
if (!
|
|
62071
|
-
const meta3 = JSON.parse(
|
|
62072
|
-
const discPath = meta3.artifactDir ?
|
|
62581
|
+
const metaPath = join33(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
|
|
62582
|
+
if (!existsSync42(metaPath)) return "";
|
|
62583
|
+
const meta3 = JSON.parse(readFileSync29(metaPath, "utf8"));
|
|
62584
|
+
const discPath = meta3.artifactDir ? join33(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join33(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
|
|
62073
62585
|
let discoveries = [];
|
|
62074
|
-
if (
|
|
62075
|
-
discoveries = JSON.parse(
|
|
62586
|
+
if (existsSync42(discPath)) {
|
|
62587
|
+
discoveries = JSON.parse(readFileSync29(discPath, "utf8"));
|
|
62076
62588
|
}
|
|
62077
62589
|
const reusable = discoveries.filter((d) => d.reusable !== false);
|
|
62078
62590
|
const lines = [
|
|
@@ -62146,14 +62658,14 @@ __export(stubs_exports, {
|
|
|
62146
62658
|
resolveWorkspaceRoot: () => resolveWorkspaceRoot
|
|
62147
62659
|
});
|
|
62148
62660
|
import {
|
|
62149
|
-
existsSync as
|
|
62150
|
-
readdirSync as
|
|
62151
|
-
writeFileSync as
|
|
62152
|
-
readFileSync as
|
|
62153
|
-
mkdirSync as
|
|
62661
|
+
existsSync as existsSync43,
|
|
62662
|
+
readdirSync as readdirSync10,
|
|
62663
|
+
writeFileSync as writeFileSync19,
|
|
62664
|
+
readFileSync as readFileSync30,
|
|
62665
|
+
mkdirSync as mkdirSync17,
|
|
62154
62666
|
renameSync as renameSync5
|
|
62155
62667
|
} from "node:fs";
|
|
62156
|
-
import { join as
|
|
62668
|
+
import { join as join34, basename as basename4, dirname as dirname10, relative as relative3 } from "node:path";
|
|
62157
62669
|
function createWorkspaceContext(projectRoot = process.cwd()) {
|
|
62158
62670
|
const rootDir = resolveWorkspaceRoot(projectRoot);
|
|
62159
62671
|
return {
|
|
@@ -62163,14 +62675,14 @@ function createWorkspaceContext(projectRoot = process.cwd()) {
|
|
|
62163
62675
|
};
|
|
62164
62676
|
}
|
|
62165
62677
|
function planJsonPath(ctx) {
|
|
62166
|
-
return
|
|
62678
|
+
return join34(ctx.rootDir, "plan.json");
|
|
62167
62679
|
}
|
|
62168
62680
|
function readPlan(ctx) {
|
|
62169
62681
|
const jsonPath = planJsonPath(ctx);
|
|
62170
|
-
if (
|
|
62682
|
+
if (existsSync43(jsonPath)) {
|
|
62171
62683
|
try {
|
|
62172
62684
|
const parsed = JSON.parse(
|
|
62173
|
-
|
|
62685
|
+
readFileSync30(jsonPath, "utf8")
|
|
62174
62686
|
);
|
|
62175
62687
|
const { phases, tasks, milestones, ...root } = parsed;
|
|
62176
62688
|
return {
|
|
@@ -62182,8 +62694,8 @@ function readPlan(ctx) {
|
|
|
62182
62694
|
} catch {
|
|
62183
62695
|
}
|
|
62184
62696
|
}
|
|
62185
|
-
const
|
|
62186
|
-
const doc = ctx.storage.readIfExists(
|
|
62697
|
+
const path104 = workspaceFile(ctx.rootDir, "plan");
|
|
62698
|
+
const doc = ctx.storage.readIfExists(path104);
|
|
62187
62699
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
62188
62700
|
const meta3 = doc.meta;
|
|
62189
62701
|
return {
|
|
@@ -62194,9 +62706,9 @@ function readPlan(ctx) {
|
|
|
62194
62706
|
}
|
|
62195
62707
|
function writePlan(ctx, summary) {
|
|
62196
62708
|
const jsonPath = planJsonPath(ctx);
|
|
62197
|
-
|
|
62709
|
+
mkdirSync17(dirname10(jsonPath), { recursive: true });
|
|
62198
62710
|
const tmp = jsonPath + ".tmp-" + process.pid;
|
|
62199
|
-
|
|
62711
|
+
writeFileSync19(
|
|
62200
62712
|
tmp,
|
|
62201
62713
|
JSON.stringify(
|
|
62202
62714
|
{
|
|
@@ -62276,9 +62788,9 @@ function renderPlanBody(summary) {
|
|
|
62276
62788
|
return lines.join("\n");
|
|
62277
62789
|
}
|
|
62278
62790
|
function nextAdrId(ctx) {
|
|
62279
|
-
const decisionsDir =
|
|
62280
|
-
if (!
|
|
62281
|
-
const existing =
|
|
62791
|
+
const decisionsDir = join34(ctx.rootDir, "decisions");
|
|
62792
|
+
if (!existsSync43(decisionsDir)) return "001";
|
|
62793
|
+
const existing = readdirSync10(decisionsDir).filter((f) => f.endsWith(".md")).map((f) => f.match(/^(\d+)-/)).filter((m) => !!m).map((m) => parseInt(m[1], 10));
|
|
62282
62794
|
const max = existing.length === 0 ? 0 : Math.max(...existing);
|
|
62283
62795
|
return String(max + 1).padStart(3, "0");
|
|
62284
62796
|
}
|
|
@@ -62322,7 +62834,7 @@ function addTaskRecord(ctx, summary, phaseId, t, options) {
|
|
|
62322
62834
|
// plan.json record (they already live in tags + the artifact body md).
|
|
62323
62835
|
files: t.fileRefs
|
|
62324
62836
|
});
|
|
62325
|
-
const taskPath =
|
|
62837
|
+
const taskPath = join34(ctx.rootDir, "plan-tasks", `${id3}.md`);
|
|
62326
62838
|
const meta3 = {
|
|
62327
62839
|
kind: "task",
|
|
62328
62840
|
id: id3,
|
|
@@ -62364,7 +62876,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
62364
62876
|
dueDate: input.dueDate,
|
|
62365
62877
|
targetVersion: version2
|
|
62366
62878
|
});
|
|
62367
|
-
const
|
|
62879
|
+
const path104 = join34(ctx.rootDir, "milestones", `${id3}.md`);
|
|
62368
62880
|
const meta3 = {
|
|
62369
62881
|
kind: "milestone",
|
|
62370
62882
|
id: id3,
|
|
@@ -62381,7 +62893,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
62381
62893
|
`Target version: ${version2}`,
|
|
62382
62894
|
""
|
|
62383
62895
|
].join("\n");
|
|
62384
|
-
ctx.storage.write(
|
|
62896
|
+
ctx.storage.write(path104, meta3, body);
|
|
62385
62897
|
return { id: id3, created: true };
|
|
62386
62898
|
}
|
|
62387
62899
|
function readPlanSummary(ctx) {
|
|
@@ -62585,7 +63097,7 @@ function addIdeaStub(ctx) {
|
|
|
62585
63097
|
const tags = args["tags"] ?? [];
|
|
62586
63098
|
const category = args["category"] ?? "General";
|
|
62587
63099
|
const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
62588
|
-
const
|
|
63100
|
+
const path104 = workspaceArtifact(ctx.rootDir, "decisions", id3);
|
|
62589
63101
|
const meta3 = {
|
|
62590
63102
|
kind: "adr",
|
|
62591
63103
|
status: "proposed",
|
|
@@ -62611,7 +63123,7 @@ function addIdeaStub(ctx) {
|
|
|
62611
63123
|
...consequences.map((c) => `- ${c}`),
|
|
62612
63124
|
""
|
|
62613
63125
|
].join("\n");
|
|
62614
|
-
ctx.storage.write(
|
|
63126
|
+
ctx.storage.write(path104, meta3, body);
|
|
62615
63127
|
return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
62616
63128
|
});
|
|
62617
63129
|
}
|
|
@@ -62662,8 +63174,8 @@ function createNfrSpecStub(ctx) {
|
|
|
62662
63174
|
},
|
|
62663
63175
|
planFeatureKeywords: Array.isArray(args["planFeatureKeywords"]) ? args["planFeatureKeywords"] : void 0
|
|
62664
63176
|
};
|
|
62665
|
-
const outPath =
|
|
62666
|
-
|
|
63177
|
+
const outPath = join34(ctx.rootDir, "nfr-spec.json");
|
|
63178
|
+
writeFileSync19(outPath, JSON.stringify(spec, null, 2), "utf8");
|
|
62667
63179
|
return `NFR spec written to nfr-spec.json (${targets.length} target(s)).`;
|
|
62668
63180
|
});
|
|
62669
63181
|
}
|
|
@@ -62693,14 +63205,14 @@ function createDocumentStub(ctx) {
|
|
|
62693
63205
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
62694
63206
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
62695
63207
|
}
|
|
62696
|
-
const
|
|
63208
|
+
const path104 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
62697
63209
|
const meta3 = {
|
|
62698
63210
|
kind: "doc",
|
|
62699
63211
|
id: slug,
|
|
62700
63212
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
62701
63213
|
tags
|
|
62702
63214
|
};
|
|
62703
|
-
ctx.storage.write(
|
|
63215
|
+
ctx.storage.write(path104, meta3, content);
|
|
62704
63216
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
62705
63217
|
});
|
|
62706
63218
|
}
|
|
@@ -62726,18 +63238,18 @@ function searchDocumentsStub(ctx) {
|
|
|
62726
63238
|
(w) => w.length >= 3 && w !== "or" && w !== "and" && w !== "the"
|
|
62727
63239
|
);
|
|
62728
63240
|
const files = [
|
|
62729
|
-
...ctx.storage.listMarkdown(
|
|
62730
|
-
...ctx.storage.listMarkdown(
|
|
62731
|
-
...ctx.storage.listMarkdown(
|
|
62732
|
-
...ctx.storage.listMarkdown(
|
|
62733
|
-
...ctx.storage.listMarkdown(
|
|
63241
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "decisions")),
|
|
63242
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "docs")),
|
|
63243
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "reviews")),
|
|
63244
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "plan-tasks")),
|
|
63245
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "milestones")),
|
|
62734
63246
|
workspaceFile(ctx.rootDir, "plan"),
|
|
62735
63247
|
workspaceFile(ctx.rootDir, "risks")
|
|
62736
63248
|
];
|
|
62737
63249
|
const results = [];
|
|
62738
63250
|
for (const file2 of files) {
|
|
62739
|
-
if (!
|
|
62740
|
-
const raw =
|
|
63251
|
+
if (!existsSync43(file2)) continue;
|
|
63252
|
+
const raw = readFileSync30(file2, "utf8");
|
|
62741
63253
|
const content = raw.toLowerCase();
|
|
62742
63254
|
let idx = -1;
|
|
62743
63255
|
let matchLen = 0;
|
|
@@ -62788,9 +63300,9 @@ function linkDocumentsStub(ctx) {
|
|
|
62788
63300
|
const toId = args["toId"] ?? args["targetId"] ?? args["targetPathOrTitle"];
|
|
62789
63301
|
if (!fromId || !toId) return "linkDocuments requires fromId and toId.";
|
|
62790
63302
|
const allFiles = [
|
|
62791
|
-
...ctx.storage.listMarkdown(
|
|
62792
|
-
...ctx.storage.listMarkdown(
|
|
62793
|
-
...ctx.storage.listMarkdown(
|
|
63303
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "decisions")),
|
|
63304
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "docs")),
|
|
63305
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "reviews"))
|
|
62794
63306
|
];
|
|
62795
63307
|
const source2 = allFiles.find((f) => {
|
|
62796
63308
|
try {
|
|
@@ -62821,9 +63333,9 @@ function getDocumentBacklinksStub(ctx) {
|
|
|
62821
63333
|
const targetId = args["targetId"] ?? args["id"];
|
|
62822
63334
|
if (!targetId) return "getDocumentBacklinks requires targetId.";
|
|
62823
63335
|
const allFiles = [
|
|
62824
|
-
...ctx.storage.listMarkdown(
|
|
62825
|
-
...ctx.storage.listMarkdown(
|
|
62826
|
-
...ctx.storage.listMarkdown(
|
|
63336
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "decisions")),
|
|
63337
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "docs")),
|
|
63338
|
+
...ctx.storage.listMarkdown(join34(ctx.rootDir, "reviews"))
|
|
62827
63339
|
];
|
|
62828
63340
|
const backlinks = [];
|
|
62829
63341
|
for (const file2 of allFiles) {
|
|
@@ -63067,9 +63579,10 @@ var init_mcpClient = __esm({
|
|
|
63067
63579
|
MAX_LIST_PAGES = 50;
|
|
63068
63580
|
MCP_PROTOCOL_VERSION = "2025-03-26";
|
|
63069
63581
|
McpClient = class {
|
|
63070
|
-
constructor(serverName, config2) {
|
|
63582
|
+
constructor(serverName, config2, spawnCwd) {
|
|
63071
63583
|
this.serverName = serverName;
|
|
63072
63584
|
this.config = config2;
|
|
63585
|
+
this.spawnCwd = spawnCwd;
|
|
63073
63586
|
this.defaultTimeoutMs = config2.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
63074
63587
|
this.serial = config2.serial ?? this.transportKind() === "http";
|
|
63075
63588
|
}
|
|
@@ -63116,7 +63629,11 @@ var init_mcpClient = __esm({
|
|
|
63116
63629
|
const spawnOpts = {
|
|
63117
63630
|
stdio: ["pipe", "pipe", "pipe"],
|
|
63118
63631
|
env: { ...process.env, ...this.config.env ?? {} },
|
|
63119
|
-
windowsHide: true
|
|
63632
|
+
windowsHide: true,
|
|
63633
|
+
// MCP servers are project-scoped: their cwd is the session project
|
|
63634
|
+
// root, not the CLI process cwd (the Desktop launches the CLI from its
|
|
63635
|
+
// install dir, so "." entries would jail themselves to the app folder).
|
|
63636
|
+
cwd: this.spawnCwd
|
|
63120
63637
|
};
|
|
63121
63638
|
const child = process.platform === "win32" ? spawn14(buildCmdLine(command, this.config.args ?? []), {
|
|
63122
63639
|
...spawnOpts,
|
|
@@ -63235,7 +63752,7 @@ var init_mcpClient = __esm({
|
|
|
63235
63752
|
if (!transport && !child)
|
|
63236
63753
|
return Promise.reject(new Error(`[mcp:${this.serverName}] not started`));
|
|
63237
63754
|
const id3 = this.nextId++;
|
|
63238
|
-
return new Promise((
|
|
63755
|
+
return new Promise((resolve10, reject) => {
|
|
63239
63756
|
const timer = setTimeout(() => {
|
|
63240
63757
|
this.pending.delete(id3);
|
|
63241
63758
|
reject(
|
|
@@ -63244,7 +63761,7 @@ var init_mcpClient = __esm({
|
|
|
63244
63761
|
)
|
|
63245
63762
|
);
|
|
63246
63763
|
}, timeoutMs2);
|
|
63247
|
-
this.pending.set(id3, { resolve:
|
|
63764
|
+
this.pending.set(id3, { resolve: resolve10, reject, timer });
|
|
63248
63765
|
if (transport) {
|
|
63249
63766
|
void transport.send({ id: id3, method, params }, timeoutMs2);
|
|
63250
63767
|
} else {
|
|
@@ -63313,22 +63830,22 @@ var init_mcpClient = __esm({
|
|
|
63313
63830
|
|
|
63314
63831
|
// src/cli/mcp/mcpConfigIo.ts
|
|
63315
63832
|
import {
|
|
63316
|
-
existsSync as
|
|
63317
|
-
mkdirSync as
|
|
63318
|
-
readFileSync as
|
|
63319
|
-
writeFileSync as
|
|
63833
|
+
existsSync as existsSync44,
|
|
63834
|
+
mkdirSync as mkdirSync18,
|
|
63835
|
+
readFileSync as readFileSync31,
|
|
63836
|
+
writeFileSync as writeFileSync20
|
|
63320
63837
|
} from "node:fs";
|
|
63321
|
-
import { dirname as
|
|
63838
|
+
import { dirname as dirname11, join as join35 } from "node:path";
|
|
63322
63839
|
function getUserMcpPath() {
|
|
63323
|
-
return
|
|
63840
|
+
return join35(zelariHome(), "mcp.json");
|
|
63324
63841
|
}
|
|
63325
63842
|
function getProjectMcpPath(projectRoot) {
|
|
63326
|
-
return
|
|
63843
|
+
return join35(projectRoot, ".zelari", "mcp.json");
|
|
63327
63844
|
}
|
|
63328
|
-
function readFile10(
|
|
63329
|
-
if (!
|
|
63845
|
+
function readFile10(path104) {
|
|
63846
|
+
if (!existsSync44(path104)) return {};
|
|
63330
63847
|
try {
|
|
63331
|
-
const parsed = JSON.parse(
|
|
63848
|
+
const parsed = JSON.parse(readFileSync31(path104, "utf8"));
|
|
63332
63849
|
const out = {};
|
|
63333
63850
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
63334
63851
|
const hasCommand = !!cfg && typeof cfg.command === "string" && !!cfg.command.trim();
|
|
@@ -63350,10 +63867,10 @@ function readFile10(path103) {
|
|
|
63350
63867
|
return {};
|
|
63351
63868
|
}
|
|
63352
63869
|
}
|
|
63353
|
-
function writeFile4(
|
|
63354
|
-
|
|
63870
|
+
function writeFile4(path104, servers) {
|
|
63871
|
+
mkdirSync18(dirname11(path104), { recursive: true });
|
|
63355
63872
|
const body = { mcpServers: servers };
|
|
63356
|
-
|
|
63873
|
+
writeFileSync20(path104, `${JSON.stringify(body, null, 2)}
|
|
63357
63874
|
`, "utf8");
|
|
63358
63875
|
}
|
|
63359
63876
|
function listMcpServers(projectRoot) {
|
|
@@ -63375,6 +63892,46 @@ function listMcpServers(projectRoot) {
|
|
|
63375
63892
|
};
|
|
63376
63893
|
return { userPath, projectPath, servers, merged };
|
|
63377
63894
|
}
|
|
63895
|
+
function requireEnvKey(key) {
|
|
63896
|
+
if (!ENV_KEY_RE.test(key)) {
|
|
63897
|
+
throw new Error(
|
|
63898
|
+
`Invalid env key "${key}" \u2014 use letters, digits, _ (no leading digit)`
|
|
63899
|
+
);
|
|
63900
|
+
}
|
|
63901
|
+
return key;
|
|
63902
|
+
}
|
|
63903
|
+
function parseMcpEnvFlag(raw) {
|
|
63904
|
+
if (raw.length === 0) return void 0;
|
|
63905
|
+
const env = {};
|
|
63906
|
+
for (const value of raw) {
|
|
63907
|
+
const text = value.trim();
|
|
63908
|
+
if (text.startsWith("{") || text.startsWith("[")) {
|
|
63909
|
+
let parsed;
|
|
63910
|
+
try {
|
|
63911
|
+
parsed = JSON.parse(text);
|
|
63912
|
+
} catch {
|
|
63913
|
+
throw new Error(`--env is not valid JSON: ${text}`);
|
|
63914
|
+
}
|
|
63915
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
63916
|
+
throw new Error('--env JSON must be an object of "KEY": "VALUE" pairs');
|
|
63917
|
+
}
|
|
63918
|
+
for (const [key2, val] of Object.entries(parsed)) {
|
|
63919
|
+
if (typeof val !== "string") {
|
|
63920
|
+
throw new Error(`--env "${key2}" must map to a string value`);
|
|
63921
|
+
}
|
|
63922
|
+
env[requireEnvKey(key2)] = val;
|
|
63923
|
+
}
|
|
63924
|
+
continue;
|
|
63925
|
+
}
|
|
63926
|
+
const eq = text.indexOf("=");
|
|
63927
|
+
const key = eq > 0 ? text.slice(0, eq).trim() : "";
|
|
63928
|
+
if (!key) {
|
|
63929
|
+
throw new Error(`Invalid --env "${text}" \u2014 use KEY=VALUE or a JSON object`);
|
|
63930
|
+
}
|
|
63931
|
+
env[requireEnvKey(key)] = text.slice(eq + 1);
|
|
63932
|
+
}
|
|
63933
|
+
return env;
|
|
63934
|
+
}
|
|
63378
63935
|
function upsertMcpServer(opts) {
|
|
63379
63936
|
const name = opts.name.trim();
|
|
63380
63937
|
if (!name || !/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
@@ -63391,9 +63948,9 @@ function upsertMcpServer(opts) {
|
|
|
63391
63948
|
error: "either command (stdio) or url (http) is required"
|
|
63392
63949
|
};
|
|
63393
63950
|
}
|
|
63394
|
-
let
|
|
63951
|
+
let path104;
|
|
63395
63952
|
if (opts.scope === "user") {
|
|
63396
|
-
|
|
63953
|
+
path104 = getUserMcpPath();
|
|
63397
63954
|
} else {
|
|
63398
63955
|
const root = opts.projectRoot?.trim();
|
|
63399
63956
|
if (!root) {
|
|
@@ -63402,39 +63959,46 @@ function upsertMcpServer(opts) {
|
|
|
63402
63959
|
error: "projectRoot required for project scope (Open Folder first)"
|
|
63403
63960
|
};
|
|
63404
63961
|
}
|
|
63405
|
-
|
|
63962
|
+
path104 = getProjectMcpPath(root);
|
|
63406
63963
|
}
|
|
63407
|
-
const current = readFile10(
|
|
63964
|
+
const current = readFile10(path104);
|
|
63965
|
+
const previous = current[name];
|
|
63408
63966
|
current[name] = {
|
|
63409
63967
|
command: hasCommand ? opts.config.command.trim() : void 0,
|
|
63410
63968
|
args: opts.config.args,
|
|
63411
|
-
|
|
63969
|
+
// Back-compat: callers that only flip `enabled` (Desktop toggle) or that
|
|
63970
|
+
// have no env channel at all (`--set-mcp` without `--env`) must not wipe
|
|
63971
|
+
// env written by hand or by another tool. An explicit env always wins —
|
|
63972
|
+
// including `{}`, which clears it.
|
|
63973
|
+
env: opts.config.env ?? previous?.env,
|
|
63412
63974
|
type: hasUrl ? "http" : opts.config.type === "http" ? "http" : "stdio",
|
|
63413
63975
|
url: hasUrl ? opts.config.url.trim() : void 0,
|
|
63414
63976
|
timeoutMs: opts.config.timeoutMs,
|
|
63415
63977
|
serial: opts.config.serial,
|
|
63416
63978
|
enabled: opts.config.enabled !== false
|
|
63417
63979
|
};
|
|
63418
|
-
writeFile4(
|
|
63419
|
-
return { ok: true, path:
|
|
63980
|
+
writeFile4(path104, current);
|
|
63981
|
+
return { ok: true, path: path104 };
|
|
63420
63982
|
}
|
|
63421
63983
|
function removeMcpServer(opts) {
|
|
63422
|
-
const
|
|
63423
|
-
if (!
|
|
63984
|
+
const path104 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
|
|
63985
|
+
if (!path104) {
|
|
63424
63986
|
return { ok: false, error: "projectRoot required for project scope" };
|
|
63425
63987
|
}
|
|
63426
|
-
const current = readFile10(
|
|
63988
|
+
const current = readFile10(path104);
|
|
63427
63989
|
if (!(opts.name in current)) {
|
|
63428
|
-
return { ok: false, error: `Server "${opts.name}" not found in ${
|
|
63990
|
+
return { ok: false, error: `Server "${opts.name}" not found in ${path104}` };
|
|
63429
63991
|
}
|
|
63430
63992
|
delete current[opts.name];
|
|
63431
|
-
writeFile4(
|
|
63432
|
-
return { ok: true, path:
|
|
63993
|
+
writeFile4(path104, current);
|
|
63994
|
+
return { ok: true, path: path104 };
|
|
63433
63995
|
}
|
|
63996
|
+
var ENV_KEY_RE;
|
|
63434
63997
|
var init_mcpConfigIo = __esm({
|
|
63435
63998
|
"src/cli/mcp/mcpConfigIo.ts"() {
|
|
63436
63999
|
"use strict";
|
|
63437
64000
|
init_paths();
|
|
64001
|
+
ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
63438
64002
|
}
|
|
63439
64003
|
});
|
|
63440
64004
|
|
|
@@ -63601,21 +64165,21 @@ __export(mcpManager_exports, {
|
|
|
63601
64165
|
readMcpConfig: () => readMcpConfig,
|
|
63602
64166
|
registerMcpTools: () => registerMcpTools
|
|
63603
64167
|
});
|
|
63604
|
-
import { existsSync as
|
|
63605
|
-
import { join as
|
|
64168
|
+
import { existsSync as existsSync45, readFileSync as readFileSync32 } from "node:fs";
|
|
64169
|
+
import { join as join36 } from "node:path";
|
|
63606
64170
|
function readMcpConfig(projectRoot = process.cwd(), opts) {
|
|
63607
64171
|
const merged = {};
|
|
63608
64172
|
const paths = [];
|
|
63609
64173
|
if (process.env["ZELARI_MCP_USER"] !== "0") {
|
|
63610
|
-
paths.push(
|
|
64174
|
+
paths.push(join36(zelariHome(), "mcp.json"));
|
|
63611
64175
|
}
|
|
63612
64176
|
if (!opts?.skipProjectMcp) {
|
|
63613
|
-
paths.push(
|
|
64177
|
+
paths.push(join36(projectRoot, ".zelari", "mcp.json"));
|
|
63614
64178
|
}
|
|
63615
64179
|
for (const p3 of paths) {
|
|
63616
|
-
if (!
|
|
64180
|
+
if (!existsSync45(p3)) continue;
|
|
63617
64181
|
try {
|
|
63618
|
-
const parsed = JSON.parse(
|
|
64182
|
+
const parsed = JSON.parse(readFileSync32(p3, "utf8"));
|
|
63619
64183
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
63620
64184
|
const hasCommand = !!cfg && typeof cfg.command === "string" && cfg.command.length > 0;
|
|
63621
64185
|
const hasUrl = !!cfg && typeof cfg.url === "string" && /^https?:\/\//i.test(cfg.url);
|
|
@@ -63631,7 +64195,7 @@ async function ensureLoaded(projectRoot) {
|
|
|
63631
64195
|
if (state2.loaded) return;
|
|
63632
64196
|
state2.loaded = true;
|
|
63633
64197
|
const trusted = isFolderTrusted(projectRoot);
|
|
63634
|
-
if (!trusted &&
|
|
64198
|
+
if (!trusted && existsSync45(join36(projectRoot, ".zelari", "mcp.json"))) {
|
|
63635
64199
|
state2.warnings.push(
|
|
63636
64200
|
"[mcp] project .zelari/mcp.json ignored \u2014 folder not trusted (run /trust or `zelari-code --trust` to enable project MCP)"
|
|
63637
64201
|
);
|
|
@@ -63645,7 +64209,7 @@ async function ensureLoaded(projectRoot) {
|
|
|
63645
64209
|
);
|
|
63646
64210
|
continue;
|
|
63647
64211
|
}
|
|
63648
|
-
const client = new McpClient(name, cfg);
|
|
64212
|
+
const client = new McpClient(name, cfg, projectRoot);
|
|
63649
64213
|
try {
|
|
63650
64214
|
await client.start();
|
|
63651
64215
|
const tools = await client.listTools();
|
|
@@ -63895,15 +64459,15 @@ __export(agentsMd_exports, {
|
|
|
63895
64459
|
serializeAgentsMd: () => serializeAgentsMd,
|
|
63896
64460
|
updateAgentsMd: () => updateAgentsMd
|
|
63897
64461
|
});
|
|
63898
|
-
import { existsSync as
|
|
64462
|
+
import { existsSync as existsSync46, readFileSync as readFileSync33, writeFileSync as writeFileSync21 } from "node:fs";
|
|
63899
64463
|
import { createHash as createHash24 } from "node:crypto";
|
|
63900
|
-
import { join as
|
|
64464
|
+
import { join as join37 } from "node:path";
|
|
63901
64465
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
63902
64466
|
async function readPackageJson3(projectRoot) {
|
|
63903
|
-
const
|
|
63904
|
-
if (!
|
|
64467
|
+
const path104 = join37(projectRoot, "package.json");
|
|
64468
|
+
if (!existsSync46(path104)) return null;
|
|
63905
64469
|
try {
|
|
63906
|
-
return JSON.parse(await readFile11(
|
|
64470
|
+
return JSON.parse(await readFile11(path104, "utf8"));
|
|
63907
64471
|
} catch {
|
|
63908
64472
|
return null;
|
|
63909
64473
|
}
|
|
@@ -63925,8 +64489,8 @@ async function genTechStack(ctx) {
|
|
|
63925
64489
|
].join("\n");
|
|
63926
64490
|
}
|
|
63927
64491
|
async function genDecisions(ctx) {
|
|
63928
|
-
const decisionsDir =
|
|
63929
|
-
if (!
|
|
64492
|
+
const decisionsDir = join37(ctx.rootDir, "decisions");
|
|
64493
|
+
if (!existsSync46(decisionsDir)) return "_No ADRs yet._";
|
|
63930
64494
|
const files = ctx.storage.listMarkdown(decisionsDir).sort();
|
|
63931
64495
|
const accepted = [];
|
|
63932
64496
|
const proposed = [];
|
|
@@ -63951,9 +64515,9 @@ async function genDecisions(ctx) {
|
|
|
63951
64515
|
}
|
|
63952
64516
|
async function genConventions(ctx) {
|
|
63953
64517
|
const lines = [];
|
|
63954
|
-
const claudeMd =
|
|
63955
|
-
if (
|
|
63956
|
-
const content =
|
|
64518
|
+
const claudeMd = join37(ctx.projectRoot, "CLAUDE.MD");
|
|
64519
|
+
if (existsSync46(claudeMd)) {
|
|
64520
|
+
const content = readFileSync33(claudeMd, "utf8");
|
|
63957
64521
|
const match = content.match(/## Architecture rules[\s\S]+?(?=\n## |\n*$)/);
|
|
63958
64522
|
if (match) {
|
|
63959
64523
|
lines.push('<!-- Extracted from CLAUDE.MD "Architecture rules" -->');
|
|
@@ -63985,9 +64549,9 @@ async function genBuild(ctx) {
|
|
|
63985
64549
|
].join("\n");
|
|
63986
64550
|
}
|
|
63987
64551
|
async function genOpenQuestions(ctx) {
|
|
63988
|
-
const
|
|
63989
|
-
if (!
|
|
63990
|
-
const content =
|
|
64552
|
+
const path104 = join37(ctx.rootDir, "risks.md");
|
|
64553
|
+
if (!existsSync46(path104)) return "_No open questions._";
|
|
64554
|
+
const content = readFileSync33(path104, "utf8");
|
|
63991
64555
|
const lines = content.split("\n");
|
|
63992
64556
|
const questions = [];
|
|
63993
64557
|
let currentTitle = "";
|
|
@@ -64061,9 +64625,9 @@ function titleCase(id3) {
|
|
|
64061
64625
|
return id3.split("-").map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
|
|
64062
64626
|
}
|
|
64063
64627
|
async function updateAgentsMd(ctx, projectRoot) {
|
|
64064
|
-
const agentsPath =
|
|
64065
|
-
if (
|
|
64066
|
-
const content =
|
|
64628
|
+
const agentsPath = join37(projectRoot, "AGENTS.MD");
|
|
64629
|
+
if (existsSync46(agentsPath)) {
|
|
64630
|
+
const content = readFileSync33(agentsPath, "utf8");
|
|
64067
64631
|
const hasAnyMarker = AUTO_SECTIONS.some((id3) => content.includes(MARKER_OPEN(id3)));
|
|
64068
64632
|
if (!hasAnyMarker) {
|
|
64069
64633
|
return {
|
|
@@ -64078,8 +64642,8 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
64078
64642
|
newSections.set(id3, await GENERATORS[id3](ctx));
|
|
64079
64643
|
}
|
|
64080
64644
|
let manualContent = "";
|
|
64081
|
-
if (
|
|
64082
|
-
const { manualBlocks } = parseAgentsMd(
|
|
64645
|
+
if (existsSync46(agentsPath)) {
|
|
64646
|
+
const { manualBlocks } = parseAgentsMd(readFileSync33(agentsPath, "utf8"));
|
|
64083
64647
|
manualContent = manualBlocks.after;
|
|
64084
64648
|
} else {
|
|
64085
64649
|
const projectName2 = projectName(projectRoot);
|
|
@@ -64095,7 +64659,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
64095
64659
|
""
|
|
64096
64660
|
].join("\n");
|
|
64097
64661
|
}
|
|
64098
|
-
const oldContent =
|
|
64662
|
+
const oldContent = existsSync46(agentsPath) ? readFileSync33(agentsPath, "utf8") : "";
|
|
64099
64663
|
const { sections: oldSections } = parseAgentsMd(oldContent);
|
|
64100
64664
|
const changedSections = [];
|
|
64101
64665
|
for (const id3 of AUTO_SECTIONS) {
|
|
@@ -64107,7 +64671,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
64107
64671
|
return { changed: false, sections: [] };
|
|
64108
64672
|
}
|
|
64109
64673
|
const newContent = serializeAgentsMd(manualContent, newSections);
|
|
64110
|
-
|
|
64674
|
+
writeFileSync21(agentsPath, newContent, "utf8");
|
|
64111
64675
|
return { changed: true, sections: changedSections };
|
|
64112
64676
|
}
|
|
64113
64677
|
function hash2(s) {
|
|
@@ -64232,12 +64796,12 @@ var init_completeDesign = __esm({
|
|
|
64232
64796
|
});
|
|
64233
64797
|
|
|
64234
64798
|
// src/cli/workspace/planDriftCheck.ts
|
|
64235
|
-
import { existsSync as
|
|
64236
|
-
import { join as
|
|
64799
|
+
import { existsSync as existsSync47, readFileSync as readFileSync34, readdirSync as readdirSync11, statSync as statSync6, writeFileSync as writeFileSync22 } from "node:fs";
|
|
64800
|
+
import { join as join38 } from "node:path";
|
|
64237
64801
|
function findCanonicalDoc(rootDir) {
|
|
64238
|
-
const docsDir =
|
|
64239
|
-
if (!
|
|
64240
|
-
const candidates =
|
|
64802
|
+
const docsDir = join38(rootDir, "docs");
|
|
64803
|
+
if (!existsSync47(docsDir)) return null;
|
|
64804
|
+
const candidates = readdirSync11(docsDir).filter((f) => /^plan-canonical.*\.md$/i.test(f)).map((f) => ({ f, mtime: statSync6(join38(docsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
64241
64805
|
return candidates.length > 0 ? candidates[0].f : null;
|
|
64242
64806
|
}
|
|
64243
64807
|
function parseCanonicalDoc(text) {
|
|
@@ -64261,9 +64825,9 @@ function versionKey(value) {
|
|
|
64261
64825
|
function firstString2(v) {
|
|
64262
64826
|
return typeof v === "string" && v.trim().length > 0 ? v : null;
|
|
64263
64827
|
}
|
|
64264
|
-
function readFileSyncSafe(
|
|
64828
|
+
function readFileSyncSafe(path104) {
|
|
64265
64829
|
try {
|
|
64266
|
-
return
|
|
64830
|
+
return readFileSync34(path104, "utf8");
|
|
64267
64831
|
} catch {
|
|
64268
64832
|
return null;
|
|
64269
64833
|
}
|
|
@@ -64272,13 +64836,13 @@ async function runPlanDriftCheck(rootDir) {
|
|
|
64272
64836
|
if (process.env["ZELARI_DRIFT_CHECK"] === "0") {
|
|
64273
64837
|
return { ran: false, reason: "ZELARI_DRIFT_CHECK=0 (disabled)" };
|
|
64274
64838
|
}
|
|
64275
|
-
const planPath =
|
|
64276
|
-
if (!
|
|
64839
|
+
const planPath = join38(rootDir, "plan.json");
|
|
64840
|
+
if (!existsSync47(planPath)) {
|
|
64277
64841
|
return { ran: false, reason: ".zelari/plan.json missing (not design-phase)" };
|
|
64278
64842
|
}
|
|
64279
64843
|
let plan;
|
|
64280
64844
|
try {
|
|
64281
|
-
plan = JSON.parse(
|
|
64845
|
+
plan = JSON.parse(readFileSync34(planPath, "utf8"));
|
|
64282
64846
|
} catch {
|
|
64283
64847
|
return { ran: false, reason: ".zelari/plan.json corrupt" };
|
|
64284
64848
|
}
|
|
@@ -64288,7 +64852,7 @@ async function runPlanDriftCheck(rootDir) {
|
|
|
64288
64852
|
const milestones = Array.isArray(plan.milestones) ? plan.milestones : [];
|
|
64289
64853
|
const phaseIds = new Set(phases.map((p3) => typeof p3.id === "string" ? p3.id : "").filter(Boolean));
|
|
64290
64854
|
const canonicalName = findCanonicalDoc(rootDir);
|
|
64291
|
-
const canonicalText = canonicalName ? readFileSyncSafe(
|
|
64855
|
+
const canonicalText = canonicalName ? readFileSyncSafe(join38(rootDir, "docs", canonicalName)) : null;
|
|
64292
64856
|
if (canonicalText !== null) {
|
|
64293
64857
|
const { activePhases, blockedPrefixes } = parseCanonicalDoc(canonicalText);
|
|
64294
64858
|
for (const id3 of activePhases) {
|
|
@@ -64367,8 +64931,8 @@ async function runPlanDriftCheck(rootDir) {
|
|
|
64367
64931
|
const canonicalParsed = canonicalName !== null && canonicalText !== null;
|
|
64368
64932
|
let reportPath;
|
|
64369
64933
|
try {
|
|
64370
|
-
reportPath =
|
|
64371
|
-
|
|
64934
|
+
reportPath = join38(rootDir, "drift-report.json");
|
|
64935
|
+
writeFileSync22(
|
|
64372
64936
|
reportPath,
|
|
64373
64937
|
JSON.stringify(
|
|
64374
64938
|
{
|
|
@@ -64404,8 +64968,8 @@ var init_planDriftCheck = __esm({
|
|
|
64404
64968
|
|
|
64405
64969
|
// src/cli/workspace/projectSmoke.ts
|
|
64406
64970
|
import { spawn as spawn15 } from "node:child_process";
|
|
64407
|
-
import { existsSync as
|
|
64408
|
-
import { join as
|
|
64971
|
+
import { existsSync as existsSync48, readFileSync as readFileSync35 } from "node:fs";
|
|
64972
|
+
import { join as join39 } from "node:path";
|
|
64409
64973
|
function pickSmokeScript(scripts) {
|
|
64410
64974
|
if (!scripts) return null;
|
|
64411
64975
|
for (const name of SMOKE_SCRIPT_PRIORITY) {
|
|
@@ -64417,13 +64981,13 @@ async function runProjectSmoke(projectRoot, timeoutMs2 = DEFAULT_TIMEOUT_MS3) {
|
|
|
64417
64981
|
if (process.env["ZELARI_SMOKE"] === "0") {
|
|
64418
64982
|
return { ran: false, reason: "ZELARI_SMOKE=0 (disabled)" };
|
|
64419
64983
|
}
|
|
64420
|
-
const pkgPath =
|
|
64421
|
-
if (!
|
|
64984
|
+
const pkgPath = join39(projectRoot, "package.json");
|
|
64985
|
+
if (!existsSync48(pkgPath)) {
|
|
64422
64986
|
return { ran: false, reason: "no package.json (skipped)" };
|
|
64423
64987
|
}
|
|
64424
64988
|
let scripts = {};
|
|
64425
64989
|
try {
|
|
64426
|
-
const pkg = JSON.parse(
|
|
64990
|
+
const pkg = JSON.parse(readFileSync35(pkgPath, "utf8"));
|
|
64427
64991
|
scripts = pkg.scripts ?? {};
|
|
64428
64992
|
} catch {
|
|
64429
64993
|
return { ran: false, reason: "package.json unreadable (skipped)" };
|
|
@@ -64510,7 +65074,7 @@ __export(evidenceFromSpine_exports, {
|
|
|
64510
65074
|
collectSessionEvidenceRefs: () => collectSessionEvidenceRefs,
|
|
64511
65075
|
evidenceRefsFromEventLines: () => evidenceRefsFromEventLines
|
|
64512
65076
|
});
|
|
64513
|
-
import { existsSync as
|
|
65077
|
+
import { existsSync as existsSync49, readFileSync as readFileSync36 } from "node:fs";
|
|
64514
65078
|
import path75 from "node:path";
|
|
64515
65079
|
function asRecord2(v) {
|
|
64516
65080
|
return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
@@ -64550,8 +65114,8 @@ function evidenceRefsFromEventLines(lines) {
|
|
|
64550
65114
|
function collectSessionEvidenceRefs(sessionId2) {
|
|
64551
65115
|
try {
|
|
64552
65116
|
const file2 = path75.join(sessionsDir(), sessionId2, "events.jsonl");
|
|
64553
|
-
if (!
|
|
64554
|
-
return evidenceRefsFromEventLines(
|
|
65117
|
+
if (!existsSync49(file2)) return [];
|
|
65118
|
+
return evidenceRefsFromEventLines(readFileSync36(file2, "utf8").split("\n"));
|
|
64555
65119
|
} catch {
|
|
64556
65120
|
return [];
|
|
64557
65121
|
}
|
|
@@ -64574,8 +65138,8 @@ __export(postCouncilHook_exports, {
|
|
|
64574
65138
|
runPostCouncilHook: () => runPostCouncilHook
|
|
64575
65139
|
});
|
|
64576
65140
|
import { spawn as spawn16 } from "node:child_process";
|
|
64577
|
-
import { existsSync as
|
|
64578
|
-
import { join as
|
|
65141
|
+
import { existsSync as existsSync50, readFileSync as readFileSync37 } from "node:fs";
|
|
65142
|
+
import { join as join40 } from "node:path";
|
|
64579
65143
|
async function runCompleteDesignPostProcessor(ctx, options) {
|
|
64580
65144
|
if (options?.runMode === "implementation") {
|
|
64581
65145
|
return {
|
|
@@ -64586,9 +65150,9 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
64586
65150
|
if (process.env["ZELARI_COMPLETE_DESIGN"] === "0") {
|
|
64587
65151
|
return { ran: false, reason: "ZELARI_COMPLETE_DESIGN=0 (disabled)" };
|
|
64588
65152
|
}
|
|
64589
|
-
const planJsonPath2 =
|
|
64590
|
-
const scriptPath =
|
|
64591
|
-
if (!
|
|
65153
|
+
const planJsonPath2 = join40(ctx.rootDir, "plan.json");
|
|
65154
|
+
const scriptPath = join40(ctx.projectRoot, "complete-design.mjs");
|
|
65155
|
+
if (!existsSync50(planJsonPath2)) {
|
|
64592
65156
|
return {
|
|
64593
65157
|
ran: false,
|
|
64594
65158
|
reason: ".zelari/plan.json missing (not design-phase)"
|
|
@@ -64596,7 +65160,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
64596
65160
|
}
|
|
64597
65161
|
let phaseCount = 0;
|
|
64598
65162
|
try {
|
|
64599
|
-
const parsed = JSON.parse(
|
|
65163
|
+
const parsed = JSON.parse(readFileSync37(planJsonPath2, "utf8"));
|
|
64600
65164
|
phaseCount = Array.isArray(parsed.phases) ? parsed.phases.length : 0;
|
|
64601
65165
|
} catch {
|
|
64602
65166
|
return { ran: false, reason: ".zelari/plan.json corrupt" };
|
|
@@ -64604,7 +65168,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
64604
65168
|
if (phaseCount === 0) {
|
|
64605
65169
|
return { ran: false, reason: ".zelari/plan.json has no phases" };
|
|
64606
65170
|
}
|
|
64607
|
-
if (!
|
|
65171
|
+
if (!existsSync50(scriptPath)) {
|
|
64608
65172
|
try {
|
|
64609
65173
|
const builtin = await runBuiltinCompleteDesign(ctx);
|
|
64610
65174
|
return {
|
|
@@ -64799,8 +65363,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
64799
65363
|
sources: scope.sources
|
|
64800
65364
|
} : void 0
|
|
64801
65365
|
});
|
|
64802
|
-
const
|
|
64803
|
-
completionHook = { ran: true, path:
|
|
65366
|
+
const path104 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
65367
|
+
completionHook = { ran: true, path: path104, completion };
|
|
64804
65368
|
} catch (err) {
|
|
64805
65369
|
completionHook = {
|
|
64806
65370
|
ran: true,
|
|
@@ -64840,10 +65404,10 @@ __export(councilFeedback_exports, {
|
|
|
64840
65404
|
});
|
|
64841
65405
|
import {
|
|
64842
65406
|
promises as fs33,
|
|
64843
|
-
existsSync as
|
|
64844
|
-
readFileSync as
|
|
64845
|
-
writeFileSync as
|
|
64846
|
-
mkdirSync as
|
|
65407
|
+
existsSync as existsSync51,
|
|
65408
|
+
readFileSync as readFileSync38,
|
|
65409
|
+
writeFileSync as writeFileSync23,
|
|
65410
|
+
mkdirSync as mkdirSync19
|
|
64847
65411
|
} from "node:fs";
|
|
64848
65412
|
import path76 from "node:path";
|
|
64849
65413
|
var FeedbackStore;
|
|
@@ -64949,9 +65513,9 @@ var init_councilFeedback = __esm({
|
|
|
64949
65513
|
}
|
|
64950
65514
|
// --- persistence ---------------------------------------------------------
|
|
64951
65515
|
load() {
|
|
64952
|
-
if (!
|
|
65516
|
+
if (!existsSync51(this.file)) return;
|
|
64953
65517
|
try {
|
|
64954
|
-
const raw =
|
|
65518
|
+
const raw = readFileSync38(this.file, "utf-8");
|
|
64955
65519
|
const parsed = JSON.parse(raw);
|
|
64956
65520
|
if (parsed && Array.isArray(parsed.entries)) {
|
|
64957
65521
|
this.entries = parsed.entries.filter(
|
|
@@ -64962,8 +65526,8 @@ var init_councilFeedback = __esm({
|
|
|
64962
65526
|
}
|
|
64963
65527
|
}
|
|
64964
65528
|
save() {
|
|
64965
|
-
|
|
64966
|
-
|
|
65529
|
+
mkdirSync19(path76.dirname(this.file), { recursive: true });
|
|
65530
|
+
writeFileSync23(
|
|
64967
65531
|
this.file,
|
|
64968
65532
|
JSON.stringify({ entries: this.entries }, null, 2),
|
|
64969
65533
|
{ encoding: "utf-8", mode: 384 }
|
|
@@ -65036,7 +65600,7 @@ __export(ledger_exports, {
|
|
|
65036
65600
|
ledgerStats: () => ledgerStats,
|
|
65037
65601
|
readLedger: () => readLedger
|
|
65038
65602
|
});
|
|
65039
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
65603
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync52, mkdirSync as mkdirSync20, readFileSync as readFileSync39 } from "node:fs";
|
|
65040
65604
|
import path77 from "node:path";
|
|
65041
65605
|
function evolutionMode(env = process.env) {
|
|
65042
65606
|
return env[EVOLUTION_ENV] === "shadow" ? "shadow" : "0";
|
|
@@ -65050,7 +65614,7 @@ function appendLedgerEntry(cwd, entry) {
|
|
|
65050
65614
|
}
|
|
65051
65615
|
try {
|
|
65052
65616
|
const file2 = ledgerPath(cwd);
|
|
65053
|
-
|
|
65617
|
+
mkdirSync20(path77.dirname(file2), { recursive: true });
|
|
65054
65618
|
appendFileSync4(file2, `${JSON.stringify(entry)}
|
|
65055
65619
|
`, "utf8");
|
|
65056
65620
|
return { written: true, path: file2 };
|
|
@@ -65063,10 +65627,10 @@ function appendLedgerEntry(cwd, entry) {
|
|
|
65063
65627
|
}
|
|
65064
65628
|
function readLedger(cwd) {
|
|
65065
65629
|
const file2 = ledgerPath(cwd);
|
|
65066
|
-
if (!
|
|
65630
|
+
if (!existsSync52(file2)) return [];
|
|
65067
65631
|
let raw;
|
|
65068
65632
|
try {
|
|
65069
|
-
raw =
|
|
65633
|
+
raw = readFileSync39(file2, "utf8");
|
|
65070
65634
|
} catch {
|
|
65071
65635
|
return [];
|
|
65072
65636
|
}
|
|
@@ -66286,7 +66850,7 @@ function safeSocketPath(socketPath) {
|
|
|
66286
66850
|
return socketPath.trim();
|
|
66287
66851
|
}
|
|
66288
66852
|
function startPermissionBroker(socketPath, handlers, opts) {
|
|
66289
|
-
const
|
|
66853
|
+
const path104 = safeSocketPath(socketPath);
|
|
66290
66854
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
66291
66855
|
const sockets = /* @__PURE__ */ new Set();
|
|
66292
66856
|
const server = createServer2((socket) => {
|
|
@@ -66383,13 +66947,13 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
66383
66947
|
});
|
|
66384
66948
|
}
|
|
66385
66949
|
}
|
|
66386
|
-
return new Promise((
|
|
66950
|
+
return new Promise((resolve10, reject) => {
|
|
66387
66951
|
const onError = (err) => reject(err);
|
|
66388
66952
|
server.once("error", onError);
|
|
66389
|
-
server.listen(
|
|
66953
|
+
server.listen(path104, () => {
|
|
66390
66954
|
server.removeListener("error", onError);
|
|
66391
|
-
|
|
66392
|
-
socketPath:
|
|
66955
|
+
resolve10({
|
|
66956
|
+
socketPath: path104,
|
|
66393
66957
|
stop: () => new Promise((res) => {
|
|
66394
66958
|
for (const s of sockets) s.destroy();
|
|
66395
66959
|
sockets.clear();
|
|
@@ -66400,7 +66964,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
66400
66964
|
if (done) return;
|
|
66401
66965
|
done = true;
|
|
66402
66966
|
if (process.platform !== "win32") {
|
|
66403
|
-
unlink(
|
|
66967
|
+
unlink(path104, () => res());
|
|
66404
66968
|
} else {
|
|
66405
66969
|
res();
|
|
66406
66970
|
}
|
|
@@ -66413,11 +66977,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
66413
66977
|
});
|
|
66414
66978
|
}
|
|
66415
66979
|
function requestBrokerAsk(socketPath, ask, opts) {
|
|
66416
|
-
const
|
|
66980
|
+
const path104 = safeSocketPath(socketPath);
|
|
66417
66981
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
66418
66982
|
const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
|
|
66419
|
-
return new Promise((
|
|
66420
|
-
const socket = connect(
|
|
66983
|
+
return new Promise((resolve10, reject) => {
|
|
66984
|
+
const socket = connect(path104);
|
|
66421
66985
|
let buffer = "";
|
|
66422
66986
|
let settled = false;
|
|
66423
66987
|
const settle = (fn) => {
|
|
@@ -66432,7 +66996,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
|
|
|
66432
66996
|
settle(
|
|
66433
66997
|
() => reject(
|
|
66434
66998
|
new Error(
|
|
66435
|
-
`permission broker unavailable at "${
|
|
66999
|
+
`permission broker unavailable at "${path104}" (connect timed out after ${connectTimeoutMs}ms)`
|
|
66436
67000
|
)
|
|
66437
67001
|
)
|
|
66438
67002
|
);
|
|
@@ -66469,7 +67033,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
|
|
|
66469
67033
|
}
|
|
66470
67034
|
if (msg?.t === "answer" && msg.id === ask.id) {
|
|
66471
67035
|
const { t: _t, id: _id, ...answer } = msg;
|
|
66472
|
-
settle(() =>
|
|
67036
|
+
settle(() => resolve10(answer));
|
|
66473
67037
|
return;
|
|
66474
67038
|
}
|
|
66475
67039
|
}
|
|
@@ -67249,8 +67813,8 @@ __export(prereqChecks_exports, {
|
|
|
67249
67813
|
runPrereqChecks: () => runPrereqChecks
|
|
67250
67814
|
});
|
|
67251
67815
|
import { execSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
67252
|
-
import { existsSync as
|
|
67253
|
-
import { dirname as
|
|
67816
|
+
import { existsSync as existsSync54 } from "node:fs";
|
|
67817
|
+
import { dirname as dirname13 } from "node:path";
|
|
67254
67818
|
function isWslBashPath2(p3) {
|
|
67255
67819
|
if (!p3 || typeof p3 !== "string") return false;
|
|
67256
67820
|
const n = p3.replace(/\//g, "\\").toLowerCase();
|
|
@@ -67356,16 +67920,16 @@ function resolveAgentShellSync() {
|
|
|
67356
67920
|
function agentProbeEnv() {
|
|
67357
67921
|
const env = { ...process.env };
|
|
67358
67922
|
try {
|
|
67359
|
-
const nodeDir =
|
|
67923
|
+
const nodeDir = dirname13(process.execPath);
|
|
67360
67924
|
if (!nodeDir) return env;
|
|
67361
|
-
const
|
|
67925
|
+
const sep5 = process.platform === "win32" ? ";" : ":";
|
|
67362
67926
|
const current = env.PATH ?? env.Path ?? "";
|
|
67363
|
-
const parts = current.split(
|
|
67927
|
+
const parts = current.split(sep5).filter((p3) => p3.length > 0);
|
|
67364
67928
|
const has = parts.some(
|
|
67365
67929
|
(p3) => p3.toLowerCase() === nodeDir.toLowerCase()
|
|
67366
67930
|
);
|
|
67367
67931
|
if (!has) {
|
|
67368
|
-
env.PATH = `${nodeDir}${
|
|
67932
|
+
env.PATH = `${nodeDir}${sep5}${current}`;
|
|
67369
67933
|
}
|
|
67370
67934
|
} catch {
|
|
67371
67935
|
}
|
|
@@ -67373,7 +67937,7 @@ function agentProbeEnv() {
|
|
|
67373
67937
|
}
|
|
67374
67938
|
function existsSyncSafe2(p3) {
|
|
67375
67939
|
try {
|
|
67376
|
-
return
|
|
67940
|
+
return existsSync54(p3);
|
|
67377
67941
|
} catch {
|
|
67378
67942
|
return false;
|
|
67379
67943
|
}
|
|
@@ -67620,7 +68184,7 @@ var init_prereqChecks = __esm({
|
|
|
67620
68184
|
});
|
|
67621
68185
|
|
|
67622
68186
|
// src/cli/plugins/prefs.ts
|
|
67623
|
-
import { existsSync as
|
|
68187
|
+
import { existsSync as existsSync55, readFileSync as readFileSync41, writeFileSync as writeFileSync24, mkdirSync as mkdirSync21 } from "node:fs";
|
|
67624
68188
|
import path85 from "node:path";
|
|
67625
68189
|
function getPluginPrefsPath() {
|
|
67626
68190
|
return pluginsPrefsPath();
|
|
@@ -67628,8 +68192,8 @@ function getPluginPrefsPath() {
|
|
|
67628
68192
|
function getPluginPrefs() {
|
|
67629
68193
|
const file2 = getPluginPrefsPath();
|
|
67630
68194
|
try {
|
|
67631
|
-
if (!
|
|
67632
|
-
const raw =
|
|
68195
|
+
if (!existsSync55(file2)) return { ...DEFAULTS2, dontAskAgain: {} };
|
|
68196
|
+
const raw = readFileSync41(file2, "utf-8");
|
|
67633
68197
|
const parsed = JSON.parse(raw);
|
|
67634
68198
|
if (parsed && typeof parsed === "object" && parsed.dontAskAgain && typeof parsed.dontAskAgain === "object") {
|
|
67635
68199
|
const clean = {};
|
|
@@ -67644,8 +68208,8 @@ function getPluginPrefs() {
|
|
|
67644
68208
|
}
|
|
67645
68209
|
function writePluginPrefs(prefs) {
|
|
67646
68210
|
const file2 = getPluginPrefsPath();
|
|
67647
|
-
|
|
67648
|
-
|
|
68211
|
+
mkdirSync21(path85.dirname(file2), { recursive: true });
|
|
68212
|
+
writeFileSync24(file2, JSON.stringify(prefs, null, 2), {
|
|
67649
68213
|
encoding: "utf-8",
|
|
67650
68214
|
mode: 384
|
|
67651
68215
|
});
|
|
@@ -67681,7 +68245,7 @@ __export(registry_exports, {
|
|
|
67681
68245
|
findPlugin: () => findPlugin,
|
|
67682
68246
|
isBinaryOnPath: () => isBinaryOnPath
|
|
67683
68247
|
});
|
|
67684
|
-
import { existsSync as
|
|
68248
|
+
import { existsSync as existsSync56 } from "node:fs";
|
|
67685
68249
|
import path86 from "node:path";
|
|
67686
68250
|
function detectLocalBin(bin) {
|
|
67687
68251
|
return (cwd) => {
|
|
@@ -67698,11 +68262,11 @@ function isBinaryOnPath(bin, opts = {}) {
|
|
|
67698
68262
|
return false;
|
|
67699
68263
|
}
|
|
67700
68264
|
const platform = opts.platform ?? process.platform;
|
|
67701
|
-
const exists = opts.exists ??
|
|
68265
|
+
const exists = opts.exists ?? existsSync56;
|
|
67702
68266
|
const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
|
|
67703
68267
|
const pathMod = platform === "win32" ? path86.win32 : path86.posix;
|
|
67704
|
-
const
|
|
67705
|
-
const dirs = pathEnv.split(
|
|
68268
|
+
const sep5 = platform === "win32" ? ";" : ":";
|
|
68269
|
+
const dirs = pathEnv.split(sep5).filter((d) => d.length > 0);
|
|
67706
68270
|
const candidates = [bin];
|
|
67707
68271
|
if (platform === "win32") {
|
|
67708
68272
|
const pathExt = opts.pathExt ?? process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM";
|
|
@@ -68442,8 +69006,8 @@ __export(atMentions_exports, {
|
|
|
68442
69006
|
extractAtMentions: () => extractAtMentions,
|
|
68443
69007
|
hasAtMentions: () => hasAtMentions
|
|
68444
69008
|
});
|
|
68445
|
-
import { existsSync as
|
|
68446
|
-
import { basename as basename5, isAbsolute as
|
|
69009
|
+
import { existsSync as existsSync59, readFileSync as readFileSync43, statSync as statSync9 } from "node:fs";
|
|
69010
|
+
import { basename as basename5, isAbsolute as isAbsolute5, relative as relative5, resolve as resolve7, sep as sep3 } from "node:path";
|
|
68447
69011
|
function isImagePath(abs) {
|
|
68448
69012
|
const ext = abs.split(".").pop()?.toLowerCase() ?? "";
|
|
68449
69013
|
return ext in IMAGE_MIME_BY_EXT;
|
|
@@ -68457,9 +69021,9 @@ function isProbablyText(name, head) {
|
|
|
68457
69021
|
return !head.includes("\0") && /[\x09\x0a\x0d\x20-\x7e]/.test(head.slice(0, 200));
|
|
68458
69022
|
}
|
|
68459
69023
|
function underRoot(abs, root) {
|
|
68460
|
-
const a =
|
|
68461
|
-
const r =
|
|
68462
|
-
const prefix = r.endsWith(
|
|
69024
|
+
const a = resolve7(abs);
|
|
69025
|
+
const r = resolve7(root);
|
|
69026
|
+
const prefix = r.endsWith(sep3) ? r : r + sep3;
|
|
68463
69027
|
return a === r || a.startsWith(prefix);
|
|
68464
69028
|
}
|
|
68465
69029
|
function extractAtMentions(text) {
|
|
@@ -68486,7 +69050,7 @@ function extractAtMentions(text) {
|
|
|
68486
69050
|
return out;
|
|
68487
69051
|
}
|
|
68488
69052
|
function resolveMention(token, cwd) {
|
|
68489
|
-
const abs =
|
|
69053
|
+
const abs = isAbsolute5(token) ? resolve7(token) : resolve7(cwd, token);
|
|
68490
69054
|
if (!underRoot(abs, cwd) && !isImagePath(abs)) {
|
|
68491
69055
|
return {
|
|
68492
69056
|
raw: token,
|
|
@@ -68496,7 +69060,7 @@ function resolveMention(token, cwd) {
|
|
|
68496
69060
|
note: "outside project root \u2014 skipped"
|
|
68497
69061
|
};
|
|
68498
69062
|
}
|
|
68499
|
-
if (!
|
|
69063
|
+
if (!existsSync59(abs)) {
|
|
68500
69064
|
return {
|
|
68501
69065
|
raw: token,
|
|
68502
69066
|
path: token,
|
|
@@ -68548,7 +69112,7 @@ function resolveMention(token, cwd) {
|
|
|
68548
69112
|
note: `image too large (${Math.round(st.size / 1024)} KB) \u2014 path only`
|
|
68549
69113
|
};
|
|
68550
69114
|
}
|
|
68551
|
-
const dataBase64 =
|
|
69115
|
+
const dataBase64 = readFileSync43(abs).toString("base64");
|
|
68552
69116
|
return {
|
|
68553
69117
|
raw: token,
|
|
68554
69118
|
path: rel2,
|
|
@@ -68559,7 +69123,7 @@ function resolveMention(token, cwd) {
|
|
|
68559
69123
|
};
|
|
68560
69124
|
}
|
|
68561
69125
|
try {
|
|
68562
|
-
const buf =
|
|
69126
|
+
const buf = readFileSync43(abs);
|
|
68563
69127
|
const head = buf.subarray(0, 800).toString("utf8");
|
|
68564
69128
|
if (!isProbablyText(abs, head)) {
|
|
68565
69129
|
return {
|
|
@@ -69458,7 +70022,7 @@ var init_liveTurnAbort = __esm({
|
|
|
69458
70022
|
});
|
|
69459
70023
|
|
|
69460
70024
|
// src/cli/headless/policyGate.ts
|
|
69461
|
-
import { isAbsolute as
|
|
70025
|
+
import { isAbsolute as isAbsolute6, resolve as resolve8 } from "node:path";
|
|
69462
70026
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
69463
70027
|
function checkStrictPolicyLoad(root, opts) {
|
|
69464
70028
|
if (isPolicyEngineDisabled()) return { blocked: false, warnings: [] };
|
|
@@ -69467,7 +70031,7 @@ function checkStrictPolicyLoad(root, opts) {
|
|
|
69467
70031
|
return { blocked: false, warnings: set2.warnings };
|
|
69468
70032
|
} catch (err) {
|
|
69469
70033
|
if (!(err instanceof PolicyLoadError)) throw err;
|
|
69470
|
-
const file2 =
|
|
70034
|
+
const file2 = isAbsolute6(err.file) ? err.file : resolve8(root, err.file);
|
|
69471
70035
|
return {
|
|
69472
70036
|
blocked: true,
|
|
69473
70037
|
warnings: [],
|
|
@@ -69720,27 +70284,27 @@ var init_sandboxedFs = __esm({
|
|
|
69720
70284
|
});
|
|
69721
70285
|
|
|
69722
70286
|
// src/cli/extensions/loader.ts
|
|
69723
|
-
import { join as
|
|
69724
|
-
import { readdirSync as
|
|
70287
|
+
import { join as join46 } from "node:path";
|
|
70288
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync44 } from "node:fs";
|
|
69725
70289
|
import { createHash as createHash25 } from "node:crypto";
|
|
69726
70290
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
69727
70291
|
function globalExtensionsDir() {
|
|
69728
|
-
return
|
|
70292
|
+
return join46(zelariHome(), "extensions");
|
|
69729
70293
|
}
|
|
69730
70294
|
function projectExtensionsDir(projectRoot) {
|
|
69731
|
-
return
|
|
70295
|
+
return join46(projectRoot, ".zelari", "extensions");
|
|
69732
70296
|
}
|
|
69733
70297
|
function sha256File(file2) {
|
|
69734
|
-
return createHash25("sha256").update(
|
|
70298
|
+
return createHash25("sha256").update(readFileSync44(file2)).digest("hex");
|
|
69735
70299
|
}
|
|
69736
70300
|
function candidateFiles(dir) {
|
|
69737
70301
|
let names;
|
|
69738
70302
|
try {
|
|
69739
|
-
names =
|
|
70303
|
+
names = readdirSync12(dir);
|
|
69740
70304
|
} catch {
|
|
69741
70305
|
return [];
|
|
69742
70306
|
}
|
|
69743
|
-
return names.filter((n) => EXTENSION_FILE_EXTS.has(n.slice(n.lastIndexOf(".")).toLowerCase())).sort().map((n) =>
|
|
70307
|
+
return names.filter((n) => EXTENSION_FILE_EXTS.has(n.slice(n.lastIndexOf(".")).toLowerCase())).sort().map((n) => join46(dir, n));
|
|
69744
70308
|
}
|
|
69745
70309
|
function extractExtension(mod) {
|
|
69746
70310
|
const m = mod;
|
|
@@ -69769,7 +70333,7 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
|
|
|
69769
70333
|
if (files.length === 0) continue;
|
|
69770
70334
|
let lock = null;
|
|
69771
70335
|
try {
|
|
69772
|
-
lock = JSON.parse(
|
|
70336
|
+
lock = JSON.parse(readFileSync44(join46(dir.path, EXTENSIONS_LOCK_FILE), "utf8"));
|
|
69773
70337
|
} catch {
|
|
69774
70338
|
lock = null;
|
|
69775
70339
|
if (dirHasLockFile(dir.path)) {
|
|
@@ -69836,7 +70400,7 @@ function basenameOf(file2) {
|
|
|
69836
70400
|
}
|
|
69837
70401
|
function dirHasLockFile(dir) {
|
|
69838
70402
|
try {
|
|
69839
|
-
|
|
70403
|
+
readFileSync44(join46(dir, EXTENSIONS_LOCK_FILE));
|
|
69840
70404
|
return true;
|
|
69841
70405
|
} catch {
|
|
69842
70406
|
return false;
|
|
@@ -72692,7 +73256,10 @@ ${ragContext}` : slicePrompt;
|
|
|
72692
73256
|
if (opts.output === "json") {
|
|
72693
73257
|
emitEvent({ type: "verification_run", ...missionVerificationPayload });
|
|
72694
73258
|
}
|
|
72695
|
-
|
|
73259
|
+
surfaceOpsKnowledgeNotices(
|
|
73260
|
+
await writeProofSafe(missionGate, { surface: "mission", sessionId: spine.sessionId }, projectRoot),
|
|
73261
|
+
opts
|
|
73262
|
+
);
|
|
72696
73263
|
if (missionGate.blocked) {
|
|
72697
73264
|
exitCode = strictGateExitCode(missionGate);
|
|
72698
73265
|
spine.missionPhase("verification", "mission-strict-blocked");
|
|
@@ -72789,6 +73356,11 @@ var init_runHeadless = __esm({
|
|
|
72789
73356
|
["krakenExploreModel", "ZELARI_KRAKEN_EXPLORE_MODEL"],
|
|
72790
73357
|
["krakenGeneralModel", "ZELARI_KRAKEN_GENERAL_MODEL"],
|
|
72791
73358
|
["krakenVerifyModel", "ZELARI_KRAKEN_VERIFY_MODEL"],
|
|
73359
|
+
// Per-tentacle thinking effort (ADR-0017) — same per-kind mapping as the
|
|
73360
|
+
// models above; the spawn factory reads them to override thinkingByProvider.
|
|
73361
|
+
["krakenExploreThinking", "ZELARI_KRAKEN_EXPLORE_THINKING"],
|
|
73362
|
+
["krakenGeneralThinking", "ZELARI_KRAKEN_GENERAL_THINKING"],
|
|
73363
|
+
["krakenVerifyThinking", "ZELARI_KRAKEN_VERIFY_THINKING"],
|
|
72792
73364
|
["krakenPlannerModel", "ZELARI_KRAKEN_PLANNER_MODEL"],
|
|
72793
73365
|
["krakenDelegation", "ZELARI_KRAKEN_DELEGATION"]
|
|
72794
73366
|
];
|
|
@@ -73179,270 +73751,6 @@ var init_desktopConfig = __esm({
|
|
|
73179
73751
|
}
|
|
73180
73752
|
});
|
|
73181
73753
|
|
|
73182
|
-
// src/cli/skillCategories.ts
|
|
73183
|
-
var CODING_CATEGORIES_LIST, CODING_CATEGORIES2;
|
|
73184
|
-
var init_skillCategories = __esm({
|
|
73185
|
-
"src/cli/skillCategories.ts"() {
|
|
73186
|
-
"use strict";
|
|
73187
|
-
CODING_CATEGORIES_LIST = [
|
|
73188
|
-
"plan",
|
|
73189
|
-
"refactor",
|
|
73190
|
-
"debug",
|
|
73191
|
-
"review",
|
|
73192
|
-
"test",
|
|
73193
|
-
"docs",
|
|
73194
|
-
"ops",
|
|
73195
|
-
"git",
|
|
73196
|
-
"db",
|
|
73197
|
-
"maint"
|
|
73198
|
-
];
|
|
73199
|
-
CODING_CATEGORIES2 = new Set(CODING_CATEGORIES_LIST);
|
|
73200
|
-
}
|
|
73201
|
-
});
|
|
73202
|
-
|
|
73203
|
-
// src/cli/skillConfigIo.ts
|
|
73204
|
-
import {
|
|
73205
|
-
existsSync as existsSync59,
|
|
73206
|
-
mkdirSync as mkdirSync23,
|
|
73207
|
-
readdirSync as readdirSync12,
|
|
73208
|
-
readFileSync as readFileSync44,
|
|
73209
|
-
rmSync as rmSync4,
|
|
73210
|
-
writeFileSync as writeFileSync25
|
|
73211
|
-
} from "node:fs";
|
|
73212
|
-
import { dirname as dirname14, join as join47 } from "node:path";
|
|
73213
|
-
function ensureBuiltinSkillsLoadedSync() {
|
|
73214
|
-
if (builtinsLoaded) return;
|
|
73215
|
-
for (const spec of BUILTIN_SKILL_MODULES) {
|
|
73216
|
-
try {
|
|
73217
|
-
require?.(spec);
|
|
73218
|
-
} catch {
|
|
73219
|
-
}
|
|
73220
|
-
}
|
|
73221
|
-
}
|
|
73222
|
-
function getUserSkillsDir() {
|
|
73223
|
-
return join47(zelariHome(), "skills");
|
|
73224
|
-
}
|
|
73225
|
-
function getProjectSkillsDir(projectRoot) {
|
|
73226
|
-
return join47(projectRoot, ".zelari", "skills");
|
|
73227
|
-
}
|
|
73228
|
-
function skillFilePath(dir, name) {
|
|
73229
|
-
return join47(dir, name, "SKILL.md");
|
|
73230
|
-
}
|
|
73231
|
-
function classifyScope(skillPath, projectRoot) {
|
|
73232
|
-
const userDir = getUserSkillsDir().replace(/\\/g, "/");
|
|
73233
|
-
const norm = skillPath.replace(/\\/g, "/");
|
|
73234
|
-
if (norm.startsWith(userDir + "/") || norm === userDir) {
|
|
73235
|
-
return { scope: "user", writable: true };
|
|
73236
|
-
}
|
|
73237
|
-
if (projectRoot) {
|
|
73238
|
-
const projDir = getProjectSkillsDir(projectRoot).replace(/\\/g, "/");
|
|
73239
|
-
if (norm.startsWith(projDir + "/") || norm === projDir) {
|
|
73240
|
-
return { scope: "project", writable: true };
|
|
73241
|
-
}
|
|
73242
|
-
}
|
|
73243
|
-
return { scope: "compat", writable: false };
|
|
73244
|
-
}
|
|
73245
|
-
function entryFromParsed(parsed, projectRoot) {
|
|
73246
|
-
const { scope, writable } = classifyScope(parsed.sourcePath, projectRoot);
|
|
73247
|
-
return {
|
|
73248
|
-
id: parsed.name,
|
|
73249
|
-
name: parsed.name,
|
|
73250
|
-
description: parsed.description,
|
|
73251
|
-
category: parsed.category,
|
|
73252
|
-
estimatedCost: parsed.estimatedCost,
|
|
73253
|
-
requiredTools: parsed.requiredTools,
|
|
73254
|
-
scope,
|
|
73255
|
-
path: parsed.sourcePath,
|
|
73256
|
-
body: parsed.body,
|
|
73257
|
-
builtin: false,
|
|
73258
|
-
writable
|
|
73259
|
-
};
|
|
73260
|
-
}
|
|
73261
|
-
function entryFromBuiltin(skill) {
|
|
73262
|
-
return {
|
|
73263
|
-
id: skill.id,
|
|
73264
|
-
name: skill.name || skill.id,
|
|
73265
|
-
description: skill.description || "",
|
|
73266
|
-
category: skill.category,
|
|
73267
|
-
estimatedCost: skill.estimatedCost,
|
|
73268
|
-
requiredTools: skill.requiredTools,
|
|
73269
|
-
scope: "builtin",
|
|
73270
|
-
path: null,
|
|
73271
|
-
// Expose body so Desktop skill picker can expand like `/skill <id>`.
|
|
73272
|
-
body: skill.systemPromptFragment || void 0,
|
|
73273
|
-
builtin: true,
|
|
73274
|
-
writable: false
|
|
73275
|
-
};
|
|
73276
|
-
}
|
|
73277
|
-
function scanSkillsDir(dir, projectRoot, seen, out) {
|
|
73278
|
-
if (!existsSync59(dir)) return;
|
|
73279
|
-
let entries;
|
|
73280
|
-
try {
|
|
73281
|
-
entries = readdirSync12(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
73282
|
-
} catch {
|
|
73283
|
-
return;
|
|
73284
|
-
}
|
|
73285
|
-
for (const entry of entries) {
|
|
73286
|
-
const skillPath = skillFilePath(dir, entry);
|
|
73287
|
-
if (!existsSync59(skillPath)) continue;
|
|
73288
|
-
try {
|
|
73289
|
-
const parsed = parseSkillMd(readFileSync44(skillPath, "utf8"), skillPath);
|
|
73290
|
-
if (!parsed) continue;
|
|
73291
|
-
if (seen.has(parsed.name)) continue;
|
|
73292
|
-
seen.add(parsed.name);
|
|
73293
|
-
out.push(entryFromParsed(parsed, projectRoot));
|
|
73294
|
-
} catch {
|
|
73295
|
-
}
|
|
73296
|
-
}
|
|
73297
|
-
}
|
|
73298
|
-
function listSkillsSnapshot(projectRoot) {
|
|
73299
|
-
const root = projectRoot && projectRoot.trim() ? projectRoot.trim() : null;
|
|
73300
|
-
const userSkillsDir = getUserSkillsDir();
|
|
73301
|
-
const projectSkillsDir = root ? getProjectSkillsDir(root) : null;
|
|
73302
|
-
const skills = [];
|
|
73303
|
-
const seen = /* @__PURE__ */ new Set();
|
|
73304
|
-
if (root) {
|
|
73305
|
-
scanSkillsDir(join47(root, ".zelari", "skills"), root, seen, skills);
|
|
73306
|
-
scanSkillsDir(join47(root, ".claude", "skills"), root, seen, skills);
|
|
73307
|
-
scanSkillsDir(join47(root, ".opencode", "skills"), root, seen, skills);
|
|
73308
|
-
}
|
|
73309
|
-
scanSkillsDir(userSkillsDir, root, seen, skills);
|
|
73310
|
-
for (const s of listCodingSkills()) {
|
|
73311
|
-
if (seen.has(s.id)) continue;
|
|
73312
|
-
seen.add(s.id);
|
|
73313
|
-
if (s.builtin) {
|
|
73314
|
-
skills.push(entryFromBuiltin(s));
|
|
73315
|
-
}
|
|
73316
|
-
}
|
|
73317
|
-
skills.sort((a, b) => {
|
|
73318
|
-
const order = (s) => s === "project" ? 0 : s === "user" ? 1 : s === "compat" ? 2 : 3;
|
|
73319
|
-
const d = order(a.scope) - order(b.scope);
|
|
73320
|
-
if (d !== 0) return d;
|
|
73321
|
-
return a.id.localeCompare(b.id);
|
|
73322
|
-
});
|
|
73323
|
-
return { userSkillsDir, projectSkillsDir, skills };
|
|
73324
|
-
}
|
|
73325
|
-
function serializeSkillMd(opts) {
|
|
73326
|
-
const name = opts.name.trim().toLowerCase();
|
|
73327
|
-
const description = opts.description.trim();
|
|
73328
|
-
const body = opts.body.trim();
|
|
73329
|
-
const lines = ["---", `name: ${name}`, `description: ${description}`];
|
|
73330
|
-
const cat = (opts.category ?? "").trim().toLowerCase();
|
|
73331
|
-
if (cat && CODING_CATEGORIES2.has(cat)) {
|
|
73332
|
-
lines.push(`category: ${cat}`);
|
|
73333
|
-
}
|
|
73334
|
-
if (opts.tools && opts.tools.length > 0) {
|
|
73335
|
-
lines.push(`tools: [${opts.tools.map((t) => t.trim()).filter(Boolean).join(", ")}]`);
|
|
73336
|
-
}
|
|
73337
|
-
const cost = (opts.cost ?? "").trim().toLowerCase();
|
|
73338
|
-
if (cost === "low" || cost === "medium" || cost === "high") {
|
|
73339
|
-
lines.push(`cost: ${cost}`);
|
|
73340
|
-
}
|
|
73341
|
-
lines.push("---", "", body, "");
|
|
73342
|
-
return lines.join("\n");
|
|
73343
|
-
}
|
|
73344
|
-
function upsertSkill(opts) {
|
|
73345
|
-
const name = opts.name.trim().toLowerCase();
|
|
73346
|
-
if (!name || !NAME_RE.test(name)) {
|
|
73347
|
-
return {
|
|
73348
|
-
ok: false,
|
|
73349
|
-
error: "Invalid skill name (use lowercase letters, digits, hyphens; max 64 chars)"
|
|
73350
|
-
};
|
|
73351
|
-
}
|
|
73352
|
-
const description = opts.description.trim();
|
|
73353
|
-
if (!description) {
|
|
73354
|
-
return { ok: false, error: "description is required" };
|
|
73355
|
-
}
|
|
73356
|
-
const body = opts.body.trim();
|
|
73357
|
-
if (!body) {
|
|
73358
|
-
return { ok: false, error: "body is required" };
|
|
73359
|
-
}
|
|
73360
|
-
let dir;
|
|
73361
|
-
if (opts.scope === "user") {
|
|
73362
|
-
dir = getUserSkillsDir();
|
|
73363
|
-
} else {
|
|
73364
|
-
const root = opts.projectRoot?.trim();
|
|
73365
|
-
if (!root) {
|
|
73366
|
-
return {
|
|
73367
|
-
ok: false,
|
|
73368
|
-
error: "projectRoot required for project scope (Open Folder first)"
|
|
73369
|
-
};
|
|
73370
|
-
}
|
|
73371
|
-
dir = getProjectSkillsDir(root);
|
|
73372
|
-
}
|
|
73373
|
-
const path103 = skillFilePath(dir, name);
|
|
73374
|
-
const content = serializeSkillMd({
|
|
73375
|
-
name,
|
|
73376
|
-
description,
|
|
73377
|
-
body,
|
|
73378
|
-
category: opts.category,
|
|
73379
|
-
tools: opts.tools,
|
|
73380
|
-
cost: opts.cost
|
|
73381
|
-
});
|
|
73382
|
-
const parsed = parseSkillMd(content, path103);
|
|
73383
|
-
if (!parsed) {
|
|
73384
|
-
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
73385
|
-
}
|
|
73386
|
-
mkdirSync23(dirname14(path103), { recursive: true });
|
|
73387
|
-
writeFileSync25(path103, content, "utf8");
|
|
73388
|
-
return { ok: true, path: path103 };
|
|
73389
|
-
}
|
|
73390
|
-
function removeSkill(opts) {
|
|
73391
|
-
const name = opts.name.trim().toLowerCase();
|
|
73392
|
-
if (!name) {
|
|
73393
|
-
return { ok: false, error: "name is required" };
|
|
73394
|
-
}
|
|
73395
|
-
let dir;
|
|
73396
|
-
if (opts.scope === "user") {
|
|
73397
|
-
dir = getUserSkillsDir();
|
|
73398
|
-
} else {
|
|
73399
|
-
const root = opts.projectRoot?.trim();
|
|
73400
|
-
if (!root) {
|
|
73401
|
-
return { ok: false, error: "projectRoot required for project scope" };
|
|
73402
|
-
}
|
|
73403
|
-
dir = getProjectSkillsDir(root);
|
|
73404
|
-
}
|
|
73405
|
-
const skillDir = join47(dir, name);
|
|
73406
|
-
const path103 = skillFilePath(dir, name);
|
|
73407
|
-
if (!existsSync59(path103) && !existsSync59(skillDir)) {
|
|
73408
|
-
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
73409
|
-
}
|
|
73410
|
-
try {
|
|
73411
|
-
rmSync4(skillDir, { recursive: true, force: true });
|
|
73412
|
-
} catch (err) {
|
|
73413
|
-
return {
|
|
73414
|
-
ok: false,
|
|
73415
|
-
error: err instanceof Error ? err.message : String(err)
|
|
73416
|
-
};
|
|
73417
|
-
}
|
|
73418
|
-
return { ok: true, path: path103 };
|
|
73419
|
-
}
|
|
73420
|
-
var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
|
|
73421
|
-
var init_skillConfigIo = __esm({
|
|
73422
|
-
"src/cli/skillConfigIo.ts"() {
|
|
73423
|
-
"use strict";
|
|
73424
|
-
init_skills2();
|
|
73425
|
-
init_skillsMd();
|
|
73426
|
-
init_skillCategories();
|
|
73427
|
-
init_paths();
|
|
73428
|
-
NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
73429
|
-
BUILTIN_SKILL_MODULES = [
|
|
73430
|
-
"@zelari/core/skills/builtin/debugging",
|
|
73431
|
-
"@zelari/core/skills/builtin/docs",
|
|
73432
|
-
"@zelari/core/skills/builtin/git-ops",
|
|
73433
|
-
"@zelari/core/skills/builtin/planning",
|
|
73434
|
-
"@zelari/core/skills/builtin/refactoring",
|
|
73435
|
-
"@zelari/core/skills/builtin/review",
|
|
73436
|
-
"@zelari/core/skills/builtin/unrealEditor",
|
|
73437
|
-
"@zelari/core/skills/builtin/testing",
|
|
73438
|
-
"@zelari/core/skills/builtin/schema-loop",
|
|
73439
|
-
"@zelari/core/skills/builtin/computer-use-cua",
|
|
73440
|
-
"@zelari/core/skills/builtin/qwen-mm-plugins"
|
|
73441
|
-
];
|
|
73442
|
-
builtinsLoaded = false;
|
|
73443
|
-
}
|
|
73444
|
-
});
|
|
73445
|
-
|
|
73446
73754
|
// src/cli/memory/jsonApi.ts
|
|
73447
73755
|
var jsonApi_exports = {};
|
|
73448
73756
|
__export(jsonApi_exports, {
|
|
@@ -73809,8 +74117,8 @@ async function startMemoryMcpServer(options) {
|
|
|
73809
74117
|
let stopped = false;
|
|
73810
74118
|
let finalizePromise;
|
|
73811
74119
|
let resolveClosed = () => void 0;
|
|
73812
|
-
const closed = new Promise((
|
|
73813
|
-
resolveClosed =
|
|
74120
|
+
const closed = new Promise((resolve10) => {
|
|
74121
|
+
resolveClosed = resolve10;
|
|
73814
74122
|
});
|
|
73815
74123
|
const adapter = new MemoryMcpAdapter({
|
|
73816
74124
|
service,
|
|
@@ -73957,8 +74265,8 @@ function startPermissionMcpServer(opts) {
|
|
|
73957
74265
|
});
|
|
73958
74266
|
let closedResolve = () => {
|
|
73959
74267
|
};
|
|
73960
|
-
const closed = new Promise((
|
|
73961
|
-
closedResolve =
|
|
74268
|
+
const closed = new Promise((resolve10) => {
|
|
74269
|
+
closedResolve = resolve10;
|
|
73962
74270
|
});
|
|
73963
74271
|
let stopped = false;
|
|
73964
74272
|
const send = (obj) => {
|
|
@@ -74211,7 +74519,7 @@ var init_permissionCli = __esm({
|
|
|
74211
74519
|
|
|
74212
74520
|
// src/cli/companion/config.ts
|
|
74213
74521
|
import {
|
|
74214
|
-
existsSync as
|
|
74522
|
+
existsSync as existsSync61,
|
|
74215
74523
|
mkdirSync as mkdirSync24,
|
|
74216
74524
|
readFileSync as readFileSync45,
|
|
74217
74525
|
writeFileSync as writeFileSync26
|
|
@@ -74229,17 +74537,17 @@ function getCompanionTokenPath() {
|
|
|
74229
74537
|
}
|
|
74230
74538
|
function ensureHome() {
|
|
74231
74539
|
const home = getZelariHome();
|
|
74232
|
-
if (!
|
|
74540
|
+
if (!existsSync61(home)) {
|
|
74233
74541
|
mkdirSync24(home, { recursive: true });
|
|
74234
74542
|
}
|
|
74235
74543
|
}
|
|
74236
74544
|
function loadCompanionConfig() {
|
|
74237
|
-
const
|
|
74238
|
-
if (!
|
|
74545
|
+
const path104 = getCompanionConfigPath();
|
|
74546
|
+
if (!existsSync61(path104)) {
|
|
74239
74547
|
return { projects: [] };
|
|
74240
74548
|
}
|
|
74241
74549
|
try {
|
|
74242
|
-
const raw = JSON.parse(readFileSync45(
|
|
74550
|
+
const raw = JSON.parse(readFileSync45(path104, "utf8"));
|
|
74243
74551
|
const projects = Array.isArray(raw.projects) ? raw.projects.filter(
|
|
74244
74552
|
(p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
|
|
74245
74553
|
).map((p3) => ({
|
|
@@ -74277,16 +74585,16 @@ function loadOrCreateToken(explicit) {
|
|
|
74277
74585
|
return { token: explicit.trim(), created: false };
|
|
74278
74586
|
}
|
|
74279
74587
|
ensureHome();
|
|
74280
|
-
const
|
|
74281
|
-
if (
|
|
74282
|
-
const t = readFileSync45(
|
|
74588
|
+
const path104 = getCompanionTokenPath();
|
|
74589
|
+
if (existsSync61(path104)) {
|
|
74590
|
+
const t = readFileSync45(path104, "utf8").trim();
|
|
74283
74591
|
if (t) return { token: t, created: false };
|
|
74284
74592
|
}
|
|
74285
74593
|
const token = randomBytes7(24).toString("base64url");
|
|
74286
|
-
writeFileSync26(
|
|
74594
|
+
writeFileSync26(path104, token + "\n", "utf8");
|
|
74287
74595
|
try {
|
|
74288
74596
|
const fs50 = __require("node:fs");
|
|
74289
|
-
fs50.chmodSync?.(
|
|
74597
|
+
fs50.chmodSync?.(path104, 384);
|
|
74290
74598
|
} catch {
|
|
74291
74599
|
}
|
|
74292
74600
|
return { token, created: true };
|
|
@@ -74311,17 +74619,17 @@ function mergeProjects(cfg, extraPaths) {
|
|
|
74311
74619
|
byId.set(p3.id, p3);
|
|
74312
74620
|
}
|
|
74313
74621
|
for (const raw of extraPaths) {
|
|
74314
|
-
const
|
|
74315
|
-
if (!
|
|
74316
|
-
let id3 = slugFromPath(
|
|
74622
|
+
const path104 = raw.trim();
|
|
74623
|
+
if (!path104) continue;
|
|
74624
|
+
let id3 = slugFromPath(path104);
|
|
74317
74625
|
let n = 2;
|
|
74318
|
-
while (byId.has(id3) && byId.get(id3).path !==
|
|
74319
|
-
id3 = `${slugFromPath(
|
|
74626
|
+
while (byId.has(id3) && byId.get(id3).path !== path104) {
|
|
74627
|
+
id3 = `${slugFromPath(path104)}-${n++}`;
|
|
74320
74628
|
}
|
|
74321
74629
|
byId.set(id3, {
|
|
74322
74630
|
id: id3,
|
|
74323
|
-
name: slugFromPath(
|
|
74324
|
-
path:
|
|
74631
|
+
name: slugFromPath(path104),
|
|
74632
|
+
path: path104
|
|
74325
74633
|
});
|
|
74326
74634
|
}
|
|
74327
74635
|
return [...byId.values()];
|
|
@@ -74407,11 +74715,11 @@ function createServePermissionBridge(write, timeoutMs2 = 12e4) {
|
|
|
74407
74715
|
onPermissionAsk(payload) {
|
|
74408
74716
|
const requestId = `perm-${Date.now()}-${++seq}`;
|
|
74409
74717
|
const categories = payload.categories && payload.categories.length > 0 ? payload.categories : payload.category ? payload.category.split(",").map((c) => c.trim()).filter(Boolean) : [];
|
|
74410
|
-
return new Promise((
|
|
74718
|
+
return new Promise((resolve10) => {
|
|
74411
74719
|
const timer = setTimeout(() => {
|
|
74412
74720
|
settle(requestId, "deny", true);
|
|
74413
74721
|
}, timeoutMs2);
|
|
74414
|
-
pending.set(requestId, { resolve:
|
|
74722
|
+
pending.set(requestId, { resolve: resolve10, timer, payload });
|
|
74415
74723
|
write(
|
|
74416
74724
|
JSON.stringify({
|
|
74417
74725
|
type: "permission.request",
|
|
@@ -74521,11 +74829,11 @@ function createServeAskUserBridge(write, timeoutMs2 = askUserTimeoutMs()) {
|
|
|
74521
74829
|
const choices = req.choices.map((c) => c.trim()).filter(Boolean);
|
|
74522
74830
|
if (choices.length < 2) return Promise.resolve(null);
|
|
74523
74831
|
const requestId = `ask-${Date.now()}-${++seq}`;
|
|
74524
|
-
return new Promise((
|
|
74832
|
+
return new Promise((resolve10) => {
|
|
74525
74833
|
const timer = setTimeout(() => {
|
|
74526
74834
|
settle(requestId, null, true);
|
|
74527
74835
|
}, timeoutMs2);
|
|
74528
|
-
pending.set(requestId, { resolve:
|
|
74836
|
+
pending.set(requestId, { resolve: resolve10, timer });
|
|
74529
74837
|
write(
|
|
74530
74838
|
JSON.stringify({
|
|
74531
74839
|
type: "ask_user.request",
|
|
@@ -74625,11 +74933,13 @@ __export(harnessServer_exports, {
|
|
|
74625
74933
|
bindHarnessTurnOptions: () => bindHarnessTurnOptions,
|
|
74626
74934
|
createCliRunTurn: () => createCliRunTurn,
|
|
74627
74935
|
createCliWorkspaceServices: () => createCliWorkspaceServices,
|
|
74936
|
+
resolveSessionCreateRoot: () => resolveSessionCreateRoot,
|
|
74628
74937
|
resolveTurnLspProvider: () => resolveTurnLspProvider,
|
|
74629
74938
|
runHarnessServer: () => runHarnessServer,
|
|
74630
74939
|
startHarnessServer: () => startHarnessServer
|
|
74631
74940
|
});
|
|
74632
74941
|
import { createInterface as createInterface3 } from "node:readline";
|
|
74942
|
+
import path99 from "node:path";
|
|
74633
74943
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
74634
74944
|
function createCliWorkspaceServices(workspaceRoot) {
|
|
74635
74945
|
const mode = activePolicyLoadMode();
|
|
@@ -74655,6 +74965,23 @@ function createCliWorkspaceServices(workspaceRoot) {
|
|
|
74655
74965
|
}
|
|
74656
74966
|
};
|
|
74657
74967
|
}
|
|
74968
|
+
function resolveSessionCreateRoot(params, cwd = process.cwd()) {
|
|
74969
|
+
const raw = params.workspaceRoot;
|
|
74970
|
+
if (typeof raw !== "string" || raw.trim() === "") {
|
|
74971
|
+
return {
|
|
74972
|
+
ok: false,
|
|
74973
|
+
message: "session.create requires a non-empty string `workspaceRoot` (the sidecar never substitutes its own cwd: sessions on different workspaces must stay isolated)"
|
|
74974
|
+
};
|
|
74975
|
+
}
|
|
74976
|
+
const root = raw.trim();
|
|
74977
|
+
if (!path99.isAbsolute(root)) {
|
|
74978
|
+
return {
|
|
74979
|
+
ok: false,
|
|
74980
|
+
message: `session.create workspaceRoot must be an absolute path (got '${root}') \u2014 a relative root would resolve against the sidecar cwd (${cwd}) and mix conversations (ADR-0016)`
|
|
74981
|
+
};
|
|
74982
|
+
}
|
|
74983
|
+
return { ok: true, root };
|
|
74984
|
+
}
|
|
74658
74985
|
function bindHarnessTurnOptions(input, workspaceRoot) {
|
|
74659
74986
|
const turnInput = input;
|
|
74660
74987
|
if (typeof turnInput.task !== "string" || turnInput.task.length === 0) {
|
|
@@ -74760,9 +75087,12 @@ function startHarnessServer(options = {}) {
|
|
|
74760
75087
|
};
|
|
74761
75088
|
}
|
|
74762
75089
|
case "session.create": {
|
|
74763
|
-
const
|
|
75090
|
+
const resolved = resolveSessionCreateRoot(params);
|
|
75091
|
+
if (!resolved.ok) {
|
|
75092
|
+
return { id: req.id ?? null, ok: false, error: { code: "bad_request", message: resolved.message } };
|
|
75093
|
+
}
|
|
74764
75094
|
const session = server.createSession({
|
|
74765
|
-
workspaceRoot: root,
|
|
75095
|
+
workspaceRoot: resolved.root,
|
|
74766
75096
|
runTurn: options.runTurn ?? createCliRunTurn(
|
|
74767
75097
|
asRegistryAskHandler(permissionBridge),
|
|
74768
75098
|
askUserBridge.onAskUser
|
|
@@ -74984,8 +75314,8 @@ var init_harnessClient = __esm({
|
|
|
74984
75314
|
);
|
|
74985
75315
|
}
|
|
74986
75316
|
const id3 = this.nextId++;
|
|
74987
|
-
return new Promise((
|
|
74988
|
-
this.pending.set(id3, { resolve:
|
|
75317
|
+
return new Promise((resolve10, reject) => {
|
|
75318
|
+
this.pending.set(id3, { resolve: resolve10, reject });
|
|
74989
75319
|
this.transport.write(JSON.stringify({ id: id3, method, params }));
|
|
74990
75320
|
});
|
|
74991
75321
|
}
|
|
@@ -75480,8 +75810,8 @@ __export(serve_exports, {
|
|
|
75480
75810
|
runCompanionServe: () => runCompanionServe
|
|
75481
75811
|
});
|
|
75482
75812
|
import { createServer as createServer3 } from "node:http";
|
|
75483
|
-
import { existsSync as
|
|
75484
|
-
import { resolve as
|
|
75813
|
+
import { existsSync as existsSync62 } from "node:fs";
|
|
75814
|
+
import { resolve as resolve9 } from "node:path";
|
|
75485
75815
|
function readBody(req, max = 2e6) {
|
|
75486
75816
|
return new Promise((resolveBody, reject) => {
|
|
75487
75817
|
const chunks = [];
|
|
@@ -75528,8 +75858,8 @@ async function runCompanionServe(opts = {}) {
|
|
|
75528
75858
|
const { token, created } = loadOrCreateToken(opts.token);
|
|
75529
75859
|
let projects = mergeProjects(fileCfg, opts.projects ?? []);
|
|
75530
75860
|
projects = projects.filter((p3) => {
|
|
75531
|
-
const abs =
|
|
75532
|
-
if (!
|
|
75861
|
+
const abs = resolve9(p3.path);
|
|
75862
|
+
if (!existsSync62(abs)) {
|
|
75533
75863
|
process.stderr.write(
|
|
75534
75864
|
`[zelari-code serve] skip missing project path: ${p3.path}
|
|
75535
75865
|
`
|
|
@@ -75548,7 +75878,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
75548
75878
|
});
|
|
75549
75879
|
}
|
|
75550
75880
|
if (projects.length === 0) {
|
|
75551
|
-
const cwd =
|
|
75881
|
+
const cwd = resolve9(process.cwd());
|
|
75552
75882
|
projects = [
|
|
75553
75883
|
{
|
|
75554
75884
|
id: "default",
|
|
@@ -75580,9 +75910,9 @@ async function runCompanionServe(opts = {}) {
|
|
|
75580
75910
|
return;
|
|
75581
75911
|
}
|
|
75582
75912
|
const url2 = parseUrl(req);
|
|
75583
|
-
const
|
|
75913
|
+
const path104 = url2.pathname.replace(/\/+$/, "") || "/";
|
|
75584
75914
|
try {
|
|
75585
|
-
if (req.method === "GET" && (
|
|
75915
|
+
if (req.method === "GET" && (path104 === "/health" || path104 === "/v1/health")) {
|
|
75586
75916
|
sendJson2(res, 200, {
|
|
75587
75917
|
ok: true,
|
|
75588
75918
|
service: "zelari-companion",
|
|
@@ -75594,18 +75924,18 @@ async function runCompanionServe(opts = {}) {
|
|
|
75594
75924
|
});
|
|
75595
75925
|
return;
|
|
75596
75926
|
}
|
|
75597
|
-
if (
|
|
75927
|
+
if (path104.startsWith("/v1")) {
|
|
75598
75928
|
if (!tokenMatches(token, getBearer(req))) {
|
|
75599
75929
|
sendJson2(res, 401, { ok: false, error: "unauthorized" });
|
|
75600
75930
|
return;
|
|
75601
75931
|
}
|
|
75602
75932
|
}
|
|
75603
|
-
if (req.method === "GET" &&
|
|
75933
|
+
if (req.method === "GET" && path104 === "/v1/config") {
|
|
75604
75934
|
const snap = buildDesktopConfigSnapshot();
|
|
75605
75935
|
sendJson2(res, 200, { ok: true, ...snap });
|
|
75606
75936
|
return;
|
|
75607
75937
|
}
|
|
75608
|
-
if (req.method === "GET" &&
|
|
75938
|
+
if (req.method === "GET" && path104 === "/v1/projects") {
|
|
75609
75939
|
sendJson2(res, 200, {
|
|
75610
75940
|
ok: true,
|
|
75611
75941
|
projects: projects.map((p3) => ({
|
|
@@ -75616,7 +75946,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
75616
75946
|
});
|
|
75617
75947
|
return;
|
|
75618
75948
|
}
|
|
75619
|
-
if (req.method === "GET" &&
|
|
75949
|
+
if (req.method === "GET" && path104 === "/v1/runs") {
|
|
75620
75950
|
sendJson2(res, 200, {
|
|
75621
75951
|
ok: true,
|
|
75622
75952
|
active: runs.getActive(),
|
|
@@ -75634,7 +75964,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
75634
75964
|
});
|
|
75635
75965
|
return;
|
|
75636
75966
|
}
|
|
75637
|
-
if (req.method === "POST" &&
|
|
75967
|
+
if (req.method === "POST" && path104 === "/v1/runs") {
|
|
75638
75968
|
const raw = await readBody(req);
|
|
75639
75969
|
let body = {};
|
|
75640
75970
|
try {
|
|
@@ -75682,7 +76012,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
75682
76012
|
});
|
|
75683
76013
|
return;
|
|
75684
76014
|
}
|
|
75685
|
-
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(
|
|
76015
|
+
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path104);
|
|
75686
76016
|
if (req.method === "GET" && eventsMatch) {
|
|
75687
76017
|
const runId = eventsMatch[1];
|
|
75688
76018
|
const run = runs.getRun(runId);
|
|
@@ -75747,7 +76077,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
75747
76077
|
}, 500);
|
|
75748
76078
|
return;
|
|
75749
76079
|
}
|
|
75750
|
-
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(
|
|
76080
|
+
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path104);
|
|
75751
76081
|
if (req.method === "POST" && cancelMatch) {
|
|
75752
76082
|
const runId = cancelMatch[1];
|
|
75753
76083
|
const result = runs.cancel(runId);
|
|
@@ -75758,7 +76088,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
75758
76088
|
sendJson2(res, 200, { ok: true, cancelled: runId });
|
|
75759
76089
|
return;
|
|
75760
76090
|
}
|
|
75761
|
-
const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(
|
|
76091
|
+
const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path104);
|
|
75762
76092
|
if (req.method === "POST" && steerMatch) {
|
|
75763
76093
|
const runId = steerMatch[1];
|
|
75764
76094
|
const raw = await readBody(req);
|
|
@@ -75924,26 +76254,26 @@ __export(doctor_exports, {
|
|
|
75924
76254
|
runDoctor: () => runDoctor
|
|
75925
76255
|
});
|
|
75926
76256
|
import { execSync as execSync2 } from "node:child_process";
|
|
75927
|
-
import { existsSync as
|
|
76257
|
+
import { existsSync as existsSync63, readFileSync as readFileSync46, readlinkSync, statSync as statSync10 } from "node:fs";
|
|
75928
76258
|
import { createRequire as createRequire3 } from "node:module";
|
|
75929
76259
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
75930
|
-
import
|
|
76260
|
+
import path100 from "node:path";
|
|
75931
76261
|
function findPackageRoot(start) {
|
|
75932
76262
|
let dir = start;
|
|
75933
76263
|
for (let i = 0; i < 6; i += 1) {
|
|
75934
|
-
const candidate =
|
|
75935
|
-
if (
|
|
76264
|
+
const candidate = path100.join(dir, "package.json");
|
|
76265
|
+
if (existsSync63(candidate)) {
|
|
75936
76266
|
try {
|
|
75937
76267
|
const pkg = JSON.parse(readFileSync46(candidate, "utf8"));
|
|
75938
76268
|
if (pkg.name === "zelari-code") return dir;
|
|
75939
76269
|
} catch {
|
|
75940
76270
|
}
|
|
75941
76271
|
}
|
|
75942
|
-
const parent =
|
|
76272
|
+
const parent = path100.dirname(dir);
|
|
75943
76273
|
if (parent === dir) break;
|
|
75944
76274
|
dir = parent;
|
|
75945
76275
|
}
|
|
75946
|
-
return
|
|
76276
|
+
return path100.resolve(__dirname3, "..", "..", "..");
|
|
75947
76277
|
}
|
|
75948
76278
|
function tryExec(cmd) {
|
|
75949
76279
|
try {
|
|
@@ -75957,7 +76287,7 @@ function tryExec(cmd) {
|
|
|
75957
76287
|
}
|
|
75958
76288
|
function readPackageJson4() {
|
|
75959
76289
|
try {
|
|
75960
|
-
const pkgPath =
|
|
76290
|
+
const pkgPath = path100.join(packageRoot, "package.json");
|
|
75961
76291
|
return JSON.parse(readFileSync46(pkgPath, "utf8"));
|
|
75962
76292
|
} catch {
|
|
75963
76293
|
return null;
|
|
@@ -75969,7 +76299,7 @@ function getGlobalPrefix() {
|
|
|
75969
76299
|
return (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || "").trim();
|
|
75970
76300
|
}
|
|
75971
76301
|
function isSourceCheckout() {
|
|
75972
|
-
return
|
|
76302
|
+
return existsSync63(path100.join(packageRoot, "src", "cli", "main.ts")) && existsSync63(path100.join(packageRoot, "apps", "desktop", "package.json"));
|
|
75973
76303
|
}
|
|
75974
76304
|
function checkShim(pkgName) {
|
|
75975
76305
|
const prefix = getGlobalPrefix();
|
|
@@ -75978,10 +76308,10 @@ function checkShim(pkgName) {
|
|
|
75978
76308
|
}
|
|
75979
76309
|
const isWin = process.platform === "win32";
|
|
75980
76310
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
75981
|
-
const shimPath =
|
|
75982
|
-
if (!
|
|
75983
|
-
const localBin =
|
|
75984
|
-
if (isSourceCheckout() &&
|
|
76311
|
+
const shimPath = path100.join(prefix, shimName);
|
|
76312
|
+
if (!existsSync63(shimPath)) {
|
|
76313
|
+
const localBin = path100.join(packageRoot, "bin", "zelari-code.js");
|
|
76314
|
+
if (isSourceCheckout() && existsSync63(localBin)) {
|
|
75985
76315
|
return WARN(
|
|
75986
76316
|
`global shim not found at ${shimPath}
|
|
75987
76317
|
source checkout \u2014 using ${localBin}
|
|
@@ -76014,8 +76344,8 @@ function checkShim(pkgName) {
|
|
|
76014
76344
|
fix: npm install -g ${pkgName}@latest --force`
|
|
76015
76345
|
);
|
|
76016
76346
|
}
|
|
76017
|
-
const resolved =
|
|
76018
|
-
const expected =
|
|
76347
|
+
const resolved = path100.resolve(path100.dirname(shimPath), target);
|
|
76348
|
+
const expected = path100.join(
|
|
76019
76349
|
prefix,
|
|
76020
76350
|
"node_modules",
|
|
76021
76351
|
pkgName,
|
|
@@ -76057,8 +76387,8 @@ function checkNode(pkg) {
|
|
|
76057
76387
|
return OK(`node ${raw} (engines.node ${enginesNode ?? ">= 20.0.0"})`);
|
|
76058
76388
|
}
|
|
76059
76389
|
function checkBundle() {
|
|
76060
|
-
const bundle =
|
|
76061
|
-
if (!
|
|
76390
|
+
const bundle = path100.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
76391
|
+
if (!existsSync63(bundle)) {
|
|
76062
76392
|
return FAIL(
|
|
76063
76393
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
76064
76394
|
fix: npm run build:cli (then reinstall or run via tsx)`
|
|
@@ -76078,7 +76408,7 @@ function checkRuntimeDeps() {
|
|
|
76078
76408
|
const missing = [];
|
|
76079
76409
|
for (const dep of required2) {
|
|
76080
76410
|
try {
|
|
76081
|
-
const localReq = createRequire3(
|
|
76411
|
+
const localReq = createRequire3(path100.join(packageRoot, "package.json"));
|
|
76082
76412
|
localReq.resolve(dep);
|
|
76083
76413
|
} catch {
|
|
76084
76414
|
missing.push(dep);
|
|
@@ -76355,7 +76685,7 @@ var init_doctor = __esm({
|
|
|
76355
76685
|
init_metrics3();
|
|
76356
76686
|
init_contextGrowthSummary();
|
|
76357
76687
|
require3 = createRequire3(import.meta.url);
|
|
76358
|
-
__dirname3 =
|
|
76688
|
+
__dirname3 = path100.dirname(fileURLToPath3(import.meta.url));
|
|
76359
76689
|
packageRoot = findPackageRoot(__dirname3);
|
|
76360
76690
|
OK = (message) => ({
|
|
76361
76691
|
ok: true,
|
|
@@ -76463,8 +76793,8 @@ __export(userSettings_exports, {
|
|
|
76463
76793
|
resolveUserSettings: () => resolveUserSettings,
|
|
76464
76794
|
settingsOverrides: () => settingsOverrides
|
|
76465
76795
|
});
|
|
76466
|
-
import { existsSync as
|
|
76467
|
-
import
|
|
76796
|
+
import { existsSync as existsSync64, readFileSync as readFileSync47 } from "node:fs";
|
|
76797
|
+
import path101 from "node:path";
|
|
76468
76798
|
function parseBool(raw) {
|
|
76469
76799
|
const v = raw.trim().toLowerCase();
|
|
76470
76800
|
if (["1", "true", "yes", "on"].includes(v)) return true;
|
|
@@ -76479,7 +76809,7 @@ function parseEnum(values, raw) {
|
|
|
76479
76809
|
return values.includes(v) ? v : void 0;
|
|
76480
76810
|
}
|
|
76481
76811
|
function loadFileLayer(file2, origin, warnings) {
|
|
76482
|
-
if (!
|
|
76812
|
+
if (!existsSync64(file2)) return {};
|
|
76483
76813
|
let raw;
|
|
76484
76814
|
try {
|
|
76485
76815
|
raw = readFileSync47(file2, "utf8");
|
|
@@ -76531,8 +76861,8 @@ function envValueFor(key, env) {
|
|
|
76531
76861
|
function resolveUserSettings(opts = {}) {
|
|
76532
76862
|
const cwd = opts.cwd ?? process.cwd();
|
|
76533
76863
|
const env = opts.env ?? process.env;
|
|
76534
|
-
const userPath =
|
|
76535
|
-
const projectPath =
|
|
76864
|
+
const userPath = path101.join(zelariHome(), SETTINGS_FILE_NAME);
|
|
76865
|
+
const projectPath = path101.join(cwd, ".zelari", SETTINGS_FILE_NAME);
|
|
76536
76866
|
const warnings = [];
|
|
76537
76867
|
const userLayer = loadFileLayer(userPath, "user", warnings);
|
|
76538
76868
|
const projectLayer = loadFileLayer(projectPath, "project", warnings);
|
|
@@ -76590,8 +76920,8 @@ function printSettingsReport(opts = {}) {
|
|
|
76590
76920
|
}
|
|
76591
76921
|
lines.push("");
|
|
76592
76922
|
lines.push("layers:");
|
|
76593
|
-
lines.push(` user: ${r.userPath} (${
|
|
76594
|
-
lines.push(` project: ${r.projectPath} (${
|
|
76923
|
+
lines.push(` user: ${r.userPath} (${existsSync64(r.userPath) ? "loaded" : "not found"})`);
|
|
76924
|
+
lines.push(` project: ${r.projectPath} (${existsSync64(r.projectPath) ? "loaded" : "not found"})`);
|
|
76595
76925
|
if (r.warnings.length > 0) {
|
|
76596
76926
|
lines.push("");
|
|
76597
76927
|
lines.push("warnings:");
|
|
@@ -76746,8 +77076,8 @@ __export(inspectSession_exports, {
|
|
|
76746
77076
|
renderInspectReport: () => renderInspectReport,
|
|
76747
77077
|
runInspectSession: () => runInspectSession
|
|
76748
77078
|
});
|
|
76749
|
-
import
|
|
76750
|
-
import { existsSync as
|
|
77079
|
+
import path102 from "node:path";
|
|
77080
|
+
import { existsSync as existsSync65 } from "node:fs";
|
|
76751
77081
|
function formatLimit(limit) {
|
|
76752
77082
|
return `${Math.round(limit / 1e3)}k`;
|
|
76753
77083
|
}
|
|
@@ -76780,13 +77110,13 @@ function renderInspectReport(state3) {
|
|
|
76780
77110
|
}
|
|
76781
77111
|
async function runInspectSession(opts) {
|
|
76782
77112
|
const sessionsDir2 = resolveSessionsDir({ workspaceRoot: opts.cwd ?? process.cwd() });
|
|
76783
|
-
const sessionDir =
|
|
76784
|
-
const eventsPath =
|
|
76785
|
-
if (!
|
|
77113
|
+
const sessionDir = path102.join(sessionsDir2, opts.sessionId);
|
|
77114
|
+
const eventsPath = path102.join(sessionDir, "events.jsonl");
|
|
77115
|
+
if (!existsSync65(sessionDir)) {
|
|
76786
77116
|
console.error(`zelari-code inspect: no session directory at ${sessionDir}`);
|
|
76787
77117
|
return 1;
|
|
76788
77118
|
}
|
|
76789
|
-
if (!
|
|
77119
|
+
if (!existsSync65(eventsPath)) {
|
|
76790
77120
|
console.error(`zelari-code inspect: session directory has no events.jsonl at ${eventsPath}`);
|
|
76791
77121
|
return 1;
|
|
76792
77122
|
}
|
|
@@ -76815,14 +77145,14 @@ __export(inspect_exports, {
|
|
|
76815
77145
|
collectInspectReport: () => collectInspectReport,
|
|
76816
77146
|
runInspect: () => runInspect
|
|
76817
77147
|
});
|
|
76818
|
-
import
|
|
76819
|
-
import { existsSync as
|
|
77148
|
+
import path103 from "node:path";
|
|
77149
|
+
import { existsSync as existsSync66, readFileSync as readFileSync48, readdirSync as readdirSync13 } from "node:fs";
|
|
76820
77150
|
async function collectInspectReport(cwd = process.cwd()) {
|
|
76821
77151
|
ensureBuiltinSkillsLoadedSync();
|
|
76822
77152
|
const snap = listSkillsSnapshot(cwd);
|
|
76823
77153
|
const mcp = listMcpServers(cwd);
|
|
76824
|
-
const userMcpPath =
|
|
76825
|
-
const projectMcpPath =
|
|
77154
|
+
const userMcpPath = path103.join(zelariHome(), "mcp.json");
|
|
77155
|
+
const projectMcpPath = path103.join(cwd, ".zelari", "mcp.json");
|
|
76826
77156
|
const globalHooks = globalHooksDir();
|
|
76827
77157
|
const projectHooks = projectHooksDir(cwd);
|
|
76828
77158
|
const projectTrusted = isFolderTrusted(cwd);
|
|
@@ -76848,11 +77178,11 @@ async function collectInspectReport(cwd = process.cwd()) {
|
|
|
76848
77178
|
folders: listTrustedFolders()
|
|
76849
77179
|
},
|
|
76850
77180
|
configSources: [
|
|
76851
|
-
{ path: userMcpPath, exists:
|
|
76852
|
-
{ path: projectMcpPath, exists:
|
|
76853
|
-
{ path:
|
|
76854
|
-
{ path:
|
|
76855
|
-
{ path:
|
|
77181
|
+
{ path: userMcpPath, exists: existsSync66(userMcpPath) },
|
|
77182
|
+
{ path: projectMcpPath, exists: existsSync66(projectMcpPath) },
|
|
77183
|
+
{ path: path103.join(zelariHome(), "provider.json"), exists: existsSync66(path103.join(zelariHome(), "provider.json")) },
|
|
77184
|
+
{ path: path103.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync66(path103.join(cwd, ".zelari", "AGENTS.md")) },
|
|
77185
|
+
{ path: path103.join(cwd, "AGENTS.md"), exists: existsSync66(path103.join(cwd, "AGENTS.md")) }
|
|
76856
77186
|
],
|
|
76857
77187
|
skills: {
|
|
76858
77188
|
total: snap.skills.length,
|
|
@@ -76865,7 +77195,7 @@ async function collectInspectReport(cwd = process.cwd()) {
|
|
|
76865
77195
|
user: mcp.servers.filter((s) => s.scope === "user").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
|
|
76866
77196
|
project: mcp.servers.filter((s) => s.scope === "project").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
|
|
76867
77197
|
projectTrusted,
|
|
76868
|
-
projectConfigExists:
|
|
77198
|
+
projectConfigExists: existsSync66(projectMcpPath)
|
|
76869
77199
|
},
|
|
76870
77200
|
hooks: {
|
|
76871
77201
|
global: {
|
|
@@ -76892,12 +77222,12 @@ function listJsonFiles(dir) {
|
|
|
76892
77222
|
}
|
|
76893
77223
|
function findAgentsMd(cwd) {
|
|
76894
77224
|
const candidates = [
|
|
76895
|
-
|
|
76896
|
-
|
|
77225
|
+
path103.join(cwd, "AGENTS.md"),
|
|
77226
|
+
path103.join(cwd, ".zelari", "AGENTS.md")
|
|
76897
77227
|
];
|
|
76898
77228
|
const found = [];
|
|
76899
77229
|
for (const c of candidates) {
|
|
76900
|
-
if (
|
|
77230
|
+
if (existsSync66(c)) {
|
|
76901
77231
|
try {
|
|
76902
77232
|
const text = readFileSync48(c, "utf8");
|
|
76903
77233
|
found.push(`${c} (${text.length} bytes)`);
|
|
@@ -77352,12 +77682,12 @@ function mergeChanges(unstaged, staged, untrackedPaths) {
|
|
|
77352
77682
|
return [...byPath.values()].sort((a, b) => churn(b) - churn(a));
|
|
77353
77683
|
}
|
|
77354
77684
|
function runGit(args, cwd) {
|
|
77355
|
-
return new Promise((
|
|
77685
|
+
return new Promise((resolve10, reject) => {
|
|
77356
77686
|
execFile(
|
|
77357
77687
|
"git",
|
|
77358
77688
|
args,
|
|
77359
77689
|
{ cwd, timeout: 5e3, windowsHide: true, maxBuffer: 4 * 1024 * 1024 },
|
|
77360
|
-
(err, stdout) => err ? reject(err) :
|
|
77690
|
+
(err, stdout) => err ? reject(err) : resolve10(stdout)
|
|
77361
77691
|
);
|
|
77362
77692
|
});
|
|
77363
77693
|
}
|
|
@@ -79936,7 +80266,7 @@ init_toolPermissions();
|
|
|
79936
80266
|
init_askUserTimeout();
|
|
79937
80267
|
function createPermissionAskHandler(opts) {
|
|
79938
80268
|
const { setPicker: setPicker2, appendSystem: appendSystem2 } = opts;
|
|
79939
|
-
return (req) => new Promise((
|
|
80269
|
+
return (req) => new Promise((resolve10) => {
|
|
79940
80270
|
const cats = req.categories;
|
|
79941
80271
|
const catLabel = cats.length === 1 ? cats[0] : cats.join("+") || "action";
|
|
79942
80272
|
const title = `Allow tool "${req.toolName}"?`;
|
|
@@ -79962,7 +80292,7 @@ ${detail}${note}${claimsBlock}
|
|
|
79962
80292
|
cancelAskTimeout();
|
|
79963
80293
|
setPicker2(null);
|
|
79964
80294
|
if (note2) appendSystem2?.(note2, Date.now());
|
|
79965
|
-
|
|
80295
|
+
resolve10(ok);
|
|
79966
80296
|
};
|
|
79967
80297
|
cancelAskTimeout = armPickerTimeout(
|
|
79968
80298
|
() => finish2(
|
|
@@ -80161,10 +80491,10 @@ function useChatTurn(params) {
|
|
|
80161
80491
|
}
|
|
80162
80492
|
} catch {
|
|
80163
80493
|
}
|
|
80164
|
-
const onAskUser = setPicker2 ? (req) => new Promise((
|
|
80494
|
+
const onAskUser = setPicker2 ? (req) => new Promise((resolve10) => {
|
|
80165
80495
|
const choices = req.choices ?? [];
|
|
80166
80496
|
if (choices.length < 2) {
|
|
80167
|
-
|
|
80497
|
+
resolve10(null);
|
|
80168
80498
|
return;
|
|
80169
80499
|
}
|
|
80170
80500
|
setLastClarification({
|
|
@@ -80188,7 +80518,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
80188
80518
|
settled = true;
|
|
80189
80519
|
cancelAskTimeout();
|
|
80190
80520
|
setPicker2(null);
|
|
80191
|
-
|
|
80521
|
+
resolve10(value);
|
|
80192
80522
|
};
|
|
80193
80523
|
cancelAskTimeout = armPickerTimeout(
|
|
80194
80524
|
() => {
|
|
@@ -81134,10 +81464,10 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
81134
81464
|
const { composeProjectContext: composeProjectContext2 } = await Promise.resolve().then(() => (init_composeContext(), composeContext_exports));
|
|
81135
81465
|
const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
|
|
81136
81466
|
const workPhase = getPhase();
|
|
81137
|
-
const onAskUserCouncil = setPicker2 ? (req) => new Promise((
|
|
81467
|
+
const onAskUserCouncil = setPicker2 ? (req) => new Promise((resolve10) => {
|
|
81138
81468
|
const choices = req.choices ?? [];
|
|
81139
81469
|
if (choices.length < 2) {
|
|
81140
|
-
|
|
81470
|
+
resolve10(null);
|
|
81141
81471
|
return;
|
|
81142
81472
|
}
|
|
81143
81473
|
setLastClarification({
|
|
@@ -81161,7 +81491,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
81161
81491
|
settled = true;
|
|
81162
81492
|
cancelAskTimeout();
|
|
81163
81493
|
setPicker2(null);
|
|
81164
|
-
|
|
81494
|
+
resolve10(value);
|
|
81165
81495
|
};
|
|
81166
81496
|
cancelAskTimeout = armPickerTimeout(
|
|
81167
81497
|
() => {
|
|
@@ -81343,10 +81673,10 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
81343
81673
|
appendSystem(setMessages, message, Date.now());
|
|
81344
81674
|
},
|
|
81345
81675
|
// v1.8.0: pause council when a member asks a structured question.
|
|
81346
|
-
onClarification: setPicker2 ? (req) => new Promise((
|
|
81676
|
+
onClarification: setPicker2 ? (req) => new Promise((resolve10) => {
|
|
81347
81677
|
const choices = req.choices ?? [];
|
|
81348
81678
|
if (choices.length < 2) {
|
|
81349
|
-
|
|
81679
|
+
resolve10(null);
|
|
81350
81680
|
return;
|
|
81351
81681
|
}
|
|
81352
81682
|
setLastClarification({
|
|
@@ -81367,7 +81697,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
81367
81697
|
if (settled) return;
|
|
81368
81698
|
settled = true;
|
|
81369
81699
|
setPicker2(null);
|
|
81370
|
-
|
|
81700
|
+
resolve10(value);
|
|
81371
81701
|
};
|
|
81372
81702
|
setPicker2({
|
|
81373
81703
|
kind: "clarification",
|
|
@@ -82025,10 +82355,10 @@ function usePermissionBroker(opts) {
|
|
|
82025
82355
|
setPicker: setPicker2,
|
|
82026
82356
|
appendSystem: (msg, at) => appendSystem(setMessages, msg, at ?? Date.now())
|
|
82027
82357
|
});
|
|
82028
|
-
const onQuestion = (req) => new Promise((
|
|
82358
|
+
const onQuestion = (req) => new Promise((resolve10) => {
|
|
82029
82359
|
const choices = (req.choices ?? []).map((c) => String(c).trim()).filter((c) => c.length > 0);
|
|
82030
82360
|
if (choices.length < 2) {
|
|
82031
|
-
|
|
82361
|
+
resolve10(null);
|
|
82032
82362
|
return;
|
|
82033
82363
|
}
|
|
82034
82364
|
let settled = false;
|
|
@@ -82038,7 +82368,7 @@ function usePermissionBroker(opts) {
|
|
|
82038
82368
|
settled = true;
|
|
82039
82369
|
cancelWaitTimeout?.();
|
|
82040
82370
|
setPicker2(null);
|
|
82041
|
-
|
|
82371
|
+
resolve10(value);
|
|
82042
82372
|
};
|
|
82043
82373
|
const waitTimeoutMs = askUserTimeoutMs();
|
|
82044
82374
|
cancelWaitTimeout = armPickerTimeout(() => {
|
|
@@ -82107,7 +82437,7 @@ init_mode();
|
|
|
82107
82437
|
init_ledger();
|
|
82108
82438
|
|
|
82109
82439
|
// src/cli/evolution/proposals.ts
|
|
82110
|
-
import { existsSync as
|
|
82440
|
+
import { existsSync as existsSync53, readFileSync as readFileSync40 } from "node:fs";
|
|
82111
82441
|
import path81 from "node:path";
|
|
82112
82442
|
var PROPOSALS_REL = path81.join(".zelari", "evolution", "proposals.jsonl");
|
|
82113
82443
|
function proposalsPath(cwd) {
|
|
@@ -82115,10 +82445,10 @@ function proposalsPath(cwd) {
|
|
|
82115
82445
|
}
|
|
82116
82446
|
function readProposalStore(cwd) {
|
|
82117
82447
|
const file2 = proposalsPath(cwd);
|
|
82118
|
-
if (!
|
|
82448
|
+
if (!existsSync53(file2)) return [];
|
|
82119
82449
|
let raw;
|
|
82120
82450
|
try {
|
|
82121
|
-
raw =
|
|
82451
|
+
raw = readFileSync40(file2, "utf8");
|
|
82122
82452
|
} catch {
|
|
82123
82453
|
return [];
|
|
82124
82454
|
}
|
|
@@ -84008,7 +84338,7 @@ async function handleKrakenFanout(ctx, raw) {
|
|
|
84008
84338
|
}
|
|
84009
84339
|
return;
|
|
84010
84340
|
}
|
|
84011
|
-
const absCsv =
|
|
84341
|
+
const absCsv = isAbsolute4(parsed.args.csv_path) ? parsed.args.csv_path : joinPath(ctx.cwd, parsed.args.csv_path);
|
|
84012
84342
|
try {
|
|
84013
84343
|
await fs39.access(absCsv);
|
|
84014
84344
|
} catch {
|
|
@@ -84044,7 +84374,7 @@ async function handleKrakenFanout(ctx, raw) {
|
|
|
84044
84374
|
);
|
|
84045
84375
|
}
|
|
84046
84376
|
}
|
|
84047
|
-
function
|
|
84377
|
+
function isAbsolute4(p3) {
|
|
84048
84378
|
return /^([A-Za-z]:[\\/]|[\\/])/.test(p3);
|
|
84049
84379
|
}
|
|
84050
84380
|
function joinPath(a, b) {
|
|
@@ -84416,7 +84746,7 @@ ${browsers.output}` : "") + (browsers.ok ? "" : `
|
|
|
84416
84746
|
return result;
|
|
84417
84747
|
}
|
|
84418
84748
|
function runPlaywrightInstallChromium(cwd, executor) {
|
|
84419
|
-
return new Promise((
|
|
84749
|
+
return new Promise((resolve10) => {
|
|
84420
84750
|
let stdout = "";
|
|
84421
84751
|
let stderr = "";
|
|
84422
84752
|
const stdio = ["ignore", "pipe", "pipe"];
|
|
@@ -84429,7 +84759,7 @@ function runPlaywrightInstallChromium(cwd, executor) {
|
|
|
84429
84759
|
stderr += chunk.toString();
|
|
84430
84760
|
});
|
|
84431
84761
|
child.on("error", (err) => {
|
|
84432
|
-
|
|
84762
|
+
resolve10({
|
|
84433
84763
|
ok: false,
|
|
84434
84764
|
output: stdout + stderr,
|
|
84435
84765
|
error: err.message,
|
|
@@ -84438,7 +84768,7 @@ function runPlaywrightInstallChromium(cwd, executor) {
|
|
|
84438
84768
|
});
|
|
84439
84769
|
child.on("close", (code) => {
|
|
84440
84770
|
const ok = code === 0;
|
|
84441
|
-
|
|
84771
|
+
resolve10({
|
|
84442
84772
|
ok,
|
|
84443
84773
|
output: stdout + stderr,
|
|
84444
84774
|
exitCode: code,
|
|
@@ -84448,7 +84778,7 @@ function runPlaywrightInstallChromium(cwd, executor) {
|
|
|
84448
84778
|
});
|
|
84449
84779
|
}
|
|
84450
84780
|
function runNpm2(executor, args, cwd, mode, npmCliPath) {
|
|
84451
|
-
return new Promise((
|
|
84781
|
+
return new Promise((resolve10) => {
|
|
84452
84782
|
let stdout = "";
|
|
84453
84783
|
let stderr = "";
|
|
84454
84784
|
const stdio = ["ignore", "pipe", "pipe"];
|
|
@@ -84460,7 +84790,7 @@ function runNpm2(executor, args, cwd, mode, npmCliPath) {
|
|
|
84460
84790
|
stderr += chunk.toString();
|
|
84461
84791
|
});
|
|
84462
84792
|
child.on("error", (err) => {
|
|
84463
|
-
|
|
84793
|
+
resolve10({
|
|
84464
84794
|
ok: false,
|
|
84465
84795
|
output: stdout + stderr,
|
|
84466
84796
|
error: err.message,
|
|
@@ -84469,7 +84799,7 @@ function runNpm2(executor, args, cwd, mode, npmCliPath) {
|
|
|
84469
84799
|
});
|
|
84470
84800
|
child.on("close", (code) => {
|
|
84471
84801
|
const ok = code === 0;
|
|
84472
|
-
|
|
84802
|
+
resolve10({
|
|
84473
84803
|
ok,
|
|
84474
84804
|
output: stdout + stderr,
|
|
84475
84805
|
exitCode: code,
|
|
@@ -84568,7 +84898,7 @@ ${lineage}
|
|
|
84568
84898
|
|
|
84569
84899
|
// src/cli/branchManager.ts
|
|
84570
84900
|
init_paths();
|
|
84571
|
-
import { promises as fs42, existsSync as
|
|
84901
|
+
import { promises as fs42, existsSync as existsSync57, readFileSync as readFileSync42, writeFileSync as writeFileSync25, mkdirSync as mkdirSync22, statSync as statSync7, rmSync as rmSync4 } from "node:fs";
|
|
84572
84902
|
import path88 from "node:path";
|
|
84573
84903
|
var META_FILENAME = "meta.json";
|
|
84574
84904
|
var SESSIONS_SUBDIR = "sessions";
|
|
@@ -84589,11 +84919,11 @@ function sessionsPathFor(name, baseDir) {
|
|
|
84589
84919
|
}
|
|
84590
84920
|
function readBranchMeta(name, baseDir) {
|
|
84591
84921
|
const metaPath = metaPathFor(name, baseDir);
|
|
84592
|
-
if (!
|
|
84922
|
+
if (!existsSync57(metaPath)) {
|
|
84593
84923
|
throw new BranchNotFoundError(`Branch "${name}" not found`);
|
|
84594
84924
|
}
|
|
84595
84925
|
try {
|
|
84596
|
-
const raw =
|
|
84926
|
+
const raw = readFileSync42(metaPath, "utf-8");
|
|
84597
84927
|
const parsed = JSON.parse(raw);
|
|
84598
84928
|
if (!parsed || typeof parsed !== "object" || typeof parsed.name !== "string" || typeof parsed.createdAt !== "number" || typeof parsed.fromSessionId !== "string") {
|
|
84599
84929
|
throw new BranchCorruptError(`Branch "${name}" meta.json is malformed`);
|
|
@@ -84610,8 +84940,8 @@ function readBranchMeta(name, baseDir) {
|
|
|
84610
84940
|
}
|
|
84611
84941
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
84612
84942
|
const metaPath = metaPathFor(name, baseDir);
|
|
84613
|
-
|
|
84614
|
-
|
|
84943
|
+
mkdirSync22(path88.dirname(metaPath), { recursive: true });
|
|
84944
|
+
writeFileSync25(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
84615
84945
|
}
|
|
84616
84946
|
async function countSessions(name, baseDir) {
|
|
84617
84947
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
@@ -84649,7 +84979,7 @@ var SessionNotFoundError = class extends Error {
|
|
|
84649
84979
|
};
|
|
84650
84980
|
function branchExists(name, baseDir = getBranchesBaseDir()) {
|
|
84651
84981
|
const bp = branchPathFor(name, baseDir);
|
|
84652
|
-
return
|
|
84982
|
+
return existsSync57(bp) && existsSync57(metaPathFor(name, baseDir));
|
|
84653
84983
|
}
|
|
84654
84984
|
async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(), sessionsBaseDir = getSessionsBaseDir()) {
|
|
84655
84985
|
if (!name || name.trim().length === 0) {
|
|
@@ -84662,12 +84992,12 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
84662
84992
|
throw new BranchAlreadyExistsError(name);
|
|
84663
84993
|
}
|
|
84664
84994
|
const sourcePath = path88.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
84665
|
-
if (!
|
|
84995
|
+
if (!existsSync57(sourcePath)) {
|
|
84666
84996
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
84667
84997
|
}
|
|
84668
84998
|
const branchPath = branchPathFor(name, baseDir);
|
|
84669
84999
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
84670
|
-
|
|
85000
|
+
mkdirSync22(branchSessionsPath, { recursive: true });
|
|
84671
85001
|
const destPath = path88.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
84672
85002
|
await fs42.copyFile(sourcePath, destPath);
|
|
84673
85003
|
const meta3 = {
|
|
@@ -84695,7 +85025,7 @@ async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
|
84695
85025
|
const results = [];
|
|
84696
85026
|
for (const entry of entries) {
|
|
84697
85027
|
const metaPath = metaPathFor(entry, baseDir);
|
|
84698
|
-
if (!
|
|
85028
|
+
if (!existsSync57(metaPath)) continue;
|
|
84699
85029
|
try {
|
|
84700
85030
|
const meta3 = readBranchMeta(entry, baseDir);
|
|
84701
85031
|
const sessionCount = await countSessions(entry, baseDir);
|
|
@@ -84883,7 +85213,7 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
84883
85213
|
init_provider2();
|
|
84884
85214
|
|
|
84885
85215
|
// src/cli/skillHistory.ts
|
|
84886
|
-
import { promises as fs44, existsSync as
|
|
85216
|
+
import { promises as fs44, existsSync as existsSync58, statSync as statSync8, renameSync as renameSync6, appendFileSync as appendFileSync5, mkdirSync as mkdirSync23 } from "node:fs";
|
|
84887
85217
|
init_paths();
|
|
84888
85218
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
84889
85219
|
async function readSkillHistory(file2) {
|
|
@@ -86294,9 +86624,9 @@ init_metrics3();
|
|
|
86294
86624
|
init_providerConfig();
|
|
86295
86625
|
|
|
86296
86626
|
// src/cli/wizard/firstRun.ts
|
|
86297
|
-
import { existsSync as
|
|
86627
|
+
import { existsSync as existsSync60 } from "node:fs";
|
|
86298
86628
|
function shouldRunWizard(input) {
|
|
86299
|
-
const exists = input.exists ??
|
|
86629
|
+
const exists = input.exists ?? existsSync60;
|
|
86300
86630
|
if (input.hasResetConfigFlag) {
|
|
86301
86631
|
return { shouldRun: true, reason: "--reset-config flag forced wizard" };
|
|
86302
86632
|
}
|
|
@@ -86769,8 +87099,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
|
|
|
86769
87099
|
let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
86770
87100
|
if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
|
|
86771
87101
|
try {
|
|
86772
|
-
const
|
|
86773
|
-
name =
|
|
87102
|
+
const path104 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
87103
|
+
name = path104 && /^[a-z0-9]/.test(path104) ? path104 : "imported-skill";
|
|
86774
87104
|
} catch {
|
|
86775
87105
|
name = "imported-skill";
|
|
86776
87106
|
}
|
|
@@ -86933,7 +87263,7 @@ function runPreflight() {
|
|
|
86933
87263
|
}
|
|
86934
87264
|
async function backgroundUpdateCheck() {
|
|
86935
87265
|
if (process.env.ANATHEMA_DEV === "1") return;
|
|
86936
|
-
await new Promise((
|
|
87266
|
+
await new Promise((resolve10) => setTimeout(resolve10, 3e3));
|
|
86937
87267
|
try {
|
|
86938
87268
|
const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_updater(), updater_exports));
|
|
86939
87269
|
const info = await checkForUpdate2();
|
|
@@ -87183,7 +87513,7 @@ proposals: npm run evolve:propose \u2014 decisions in npm run evolve:decide (P1:
|
|
|
87183
87513
|
}
|
|
87184
87514
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
87185
87515
|
console.log(
|
|
87186
|
-
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor [--json] Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --inspect [--json] Unified project inspection (config, skills, MCP,\n hooks, plugins, AGENTS.md, trust status)\n --trust [path] Trust the cwd (or path) so project MCP + hooks load\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --fix-budget Set recommended ZELARI_MAX_TOOL_LOOP_HARD=180,\n ZELARI_MAX_TOOL_LOOP_ITERATIONS=60, ZELARI_CONTEXT_LIMIT=400000\n at User scope (prevents the agent stopping mid-task)\n --permission-mcp <socket> MCP stdio server for external agent permission prompts\n (spawned by claude --permission-prompt-tool)\n --memory-mcp Optional MCP stdio server for project memory\n --cwd <path> Trusted project root (requires ZELARI_MEMORY_MCP=1)\n --client-id <id> Stable local owner identity for private memories\n --memory-json <json> Read-only project-memory bridge for Zelari Desktop\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)\n zelari/mission mode auto-scopes slices from open tasks in .zelari/plan.json\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --profile <id> Capability profile (minimal/v1|kraken/v1|council/v1|mission/v1)\n --resume <id> Continue a 2.0 spine session\n --resume-mission Resume .zelari/mission-state.json (not the spine)\n --export-session <path> Write zelari-session-export/1 after the run\n --strict-done Evidence-based BUILD completion gate\n --allow-unverified Exit 0 when strict is ON but nothing could be verified (M1.2)\n --task-file <path> Read the task prompt from a file (Windows argv cap)\n --once Single-cycle run (cron/git-hook triggers, ADR-0014)\n --kraken-graph <goal> Plan + execute a Kraken task graph\n (variant: --kraken-graph-file <path>; kill-switch\n ZELARI_KRAKEN_GRAPH=0)\n --plan-only Serialize the graph plan to .zelari/radio/ and exit 0\n --run-plan <id> Execute a pre-built .zelari/radio/plan-<id>.json\n --gauntlet Host-driven gauntlet loop (builder/critic tentacles)\n --session-export <id> Print a portable 2.0 session export (no LLM)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --serve-harness Long-lived harness kernel for hosts (NDJSON JSON-RPC\n on stdin/stdout; Desktop/companion transport)\n --print-config Print provider/model config as JSON (no secrets)\n --print-settings Print zelari.config.json values + the origin of\n each (default < user < project < env)\n --permissions <p> Permission preset: strict | standard | yolo \u2014 changes\n category DEFAULTS only (env vars and policy files win)\n --evolve-status Evolution ledger stats (read-only; ADR-0036; the\n ledger is written only when ZELARI_EVOLUTION=shadow)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --thinking <spec> Thinking effort (auto|off|low|medium|high|budget:N)\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --login-oauth Start subscription OAuth (grok, chatgpt, anthropic)\n --provider <id> grok | chatgpt | anthropic\n --code <paste> Anthropic magic-link code (CODE#STATE)\n --no-browser Do not open the system browser\n --refresh-oauth Force-refresh an OAuth access token\n --provider <id> grok | chatgpt | anthropic\n --logout-oauth Clear stored OAuth credentials\n --provider <id> grok | chatgpt | anthropic\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable for stdio servers\n --url <endpoint> Streamable HTTP endpoint (e.g. UE 5.8 editor)\n --args <json> JSON array of args (stdio, optional)\n --timeout <ms> Per-server request timeout (http, optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --preset unreal-mcp Unreal Engine 5.8+ editor (MCP over HTTP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ZELARI_MEMORY_MCP=1 Enable the optional external memory MCP server\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
|
|
87516
|
+
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor [--json] Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --inspect [--json] Unified project inspection (config, skills, MCP,\n hooks, plugins, AGENTS.md, trust status)\n --trust [path] Trust the cwd (or path) so project MCP + hooks load\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --fix-budget Set recommended ZELARI_MAX_TOOL_LOOP_HARD=180,\n ZELARI_MAX_TOOL_LOOP_ITERATIONS=60, ZELARI_CONTEXT_LIMIT=400000\n at User scope (prevents the agent stopping mid-task)\n --permission-mcp <socket> MCP stdio server for external agent permission prompts\n (spawned by claude --permission-prompt-tool)\n --memory-mcp Optional MCP stdio server for project memory\n --cwd <path> Trusted project root (requires ZELARI_MEMORY_MCP=1)\n --client-id <id> Stable local owner identity for private memories\n --memory-json <json> Read-only project-memory bridge for Zelari Desktop\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)\n zelari/mission mode auto-scopes slices from open tasks in .zelari/plan.json\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n --profile <id> Capability profile (minimal/v1|kraken/v1|council/v1|mission/v1)\n --resume <id> Continue a 2.0 spine session\n --resume-mission Resume .zelari/mission-state.json (not the spine)\n --export-session <path> Write zelari-session-export/1 after the run\n --strict-done Evidence-based BUILD completion gate\n --allow-unverified Exit 0 when strict is ON but nothing could be verified (M1.2)\n --task-file <path> Read the task prompt from a file (Windows argv cap)\n --once Single-cycle run (cron/git-hook triggers, ADR-0014)\n --kraken-graph <goal> Plan + execute a Kraken task graph\n (variant: --kraken-graph-file <path>; kill-switch\n ZELARI_KRAKEN_GRAPH=0)\n --plan-only Serialize the graph plan to .zelari/radio/ and exit 0\n --run-plan <id> Execute a pre-built .zelari/radio/plan-<id>.json\n --gauntlet Host-driven gauntlet loop (builder/critic tentacles)\n --session-export <id> Print a portable 2.0 session export (no LLM)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --serve-harness Long-lived harness kernel for hosts (NDJSON JSON-RPC\n on stdin/stdout; Desktop/companion transport)\n --print-config Print provider/model config as JSON (no secrets)\n --print-settings Print zelari.config.json values + the origin of\n each (default < user < project < env)\n --permissions <p> Permission preset: strict | standard | yolo \u2014 changes\n category DEFAULTS only (env vars and policy files win);\n yolo also auto-approves residual asks (unattended runs)\n --evolve-status Evolution ledger stats (read-only; ADR-0036; the\n ledger is written only when ZELARI_EVOLUTION=shadow)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --thinking <spec> Thinking effort (auto|off|low|medium|high|budget:N)\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --login-oauth Start subscription OAuth (grok, chatgpt, anthropic)\n --provider <id> grok | chatgpt | anthropic\n --code <paste> Anthropic magic-link code (CODE#STATE)\n --no-browser Do not open the system browser\n --refresh-oauth Force-refresh an OAuth access token\n --provider <id> grok | chatgpt | anthropic\n --logout-oauth Clear stored OAuth credentials\n --provider <id> grok | chatgpt | anthropic\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable for stdio servers\n --url <endpoint> Streamable HTTP endpoint (e.g. UE 5.8 editor)\n --args <json> JSON array of args (stdio, optional)\n --env <json|K=V> Env for the server: JSON object or KEY=VALUE,\n repeatable (omit to keep the stored env)\n --timeout <ms> Per-server request timeout (http, optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --preset unreal-mcp Unreal Engine 5.8+ editor (MCP over HTTP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ZELARI_MEMORY_MCP=1 Enable the optional external memory MCP server\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
|
|
87187
87517
|
);
|
|
87188
87518
|
process.exit(0);
|
|
87189
87519
|
}
|
|
@@ -87223,6 +87553,11 @@ proposals: npm run evolve:propose \u2014 decisions in npm run evolve:decide (P1:
|
|
|
87223
87553
|
if (!Array.isArray(parsed)) throw new Error("--args must be a JSON array");
|
|
87224
87554
|
args = parsed.map(String);
|
|
87225
87555
|
}
|
|
87556
|
+
const envValues = [];
|
|
87557
|
+
for (let i = 0; i < argv.length - 1; i++) {
|
|
87558
|
+
if (argv[i] === "--env") envValues.push(argv[i + 1]);
|
|
87559
|
+
}
|
|
87560
|
+
const env = parseMcpEnvFlag(envValues);
|
|
87226
87561
|
const timeoutMs2 = timeoutRaw !== void 0 ? Number(timeoutRaw) : void 0;
|
|
87227
87562
|
if (timeoutMs2 !== void 0 && (!Number.isFinite(timeoutMs2) || timeoutMs2 <= 0)) {
|
|
87228
87563
|
throw new Error("--timeout must be a positive number of milliseconds");
|
|
@@ -87238,7 +87573,7 @@ proposals: npm run evolve:propose \u2014 decisions in npm run evolve:decide (P1:
|
|
|
87238
87573
|
scope,
|
|
87239
87574
|
name,
|
|
87240
87575
|
projectRoot: cwd,
|
|
87241
|
-
config: url2 ? { type: "http", url: url2, timeoutMs: timeoutMs2, serial: true, enabled } : { command, args, enabled }
|
|
87576
|
+
config: url2 ? { type: "http", url: url2, timeoutMs: timeoutMs2, serial: true, enabled, env } : { command, args, env, enabled }
|
|
87242
87577
|
});
|
|
87243
87578
|
if (!result.ok) throw new Error(result.error);
|
|
87244
87579
|
console.log(JSON.stringify({ ok: true, path: result.path, name, scope }));
|
|
@@ -87729,7 +88064,7 @@ function main() {
|
|
|
87729
88064
|
closeMcpClients2();
|
|
87730
88065
|
} catch {
|
|
87731
88066
|
}
|
|
87732
|
-
await new Promise((
|
|
88067
|
+
await new Promise((resolve10) => setImmediate(resolve10));
|
|
87733
88068
|
process.exit(code);
|
|
87734
88069
|
}).catch(async (err) => {
|
|
87735
88070
|
console.error(
|