zelari-code 1.44.0 → 1.46.1
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/ast/engine.js +86 -23
- package/dist/cli/ast/engine.js.map +1 -1
- package/dist/cli/ast/engine.test.js +101 -0
- package/dist/cli/ast/engine.test.js.map +1 -0
- package/dist/cli/ast/tools.js +77 -15
- package/dist/cli/ast/tools.js.map +1 -1
- package/dist/cli/ast/tools.test.js +124 -0
- package/dist/cli/ast/tools.test.js.map +1 -0
- package/dist/cli/headless.js +37 -0
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/headless.test.js +107 -0
- package/dist/cli/headless.test.js.map +1 -0
- package/dist/cli/hooks/useChatTurn.js +2 -0
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/lsp/manager.js +10 -0
- package/dist/cli/lsp/manager.js.map +1 -1
- package/dist/cli/lsp/tools.js +37 -2
- package/dist/cli/lsp/tools.js.map +1 -1
- package/dist/cli/lsp/tools.test.js +90 -0
- package/dist/cli/lsp/tools.test.js.map +1 -0
- package/dist/cli/main.bundled.js +1082 -547
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/toolRegistry.js +22 -5
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/inspectCommand.js +346 -0
- package/dist/cli/tools/inspectCommand.js.map +1 -0
- package/dist/cli/tools/inspectCommand.test.js +311 -0
- package/dist/cli/tools/inspectCommand.test.js.map +1 -0
- package/dist/cli/tools/inspectTypecheckSafety.js +104 -0
- package/dist/cli/tools/inspectTypecheckSafety.js.map +1 -0
- package/dist/cli/tools/taskTool.js +4 -0
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -665,7 +665,7 @@ async function refreshGrokToken(options) {
|
|
|
665
665
|
return parseTokenResponseBody(obj, accessToken);
|
|
666
666
|
}
|
|
667
667
|
async function openBrowser(url2) {
|
|
668
|
-
const { spawn:
|
|
668
|
+
const { spawn: spawn16 } = await import("node:child_process");
|
|
669
669
|
const cmd = (() => {
|
|
670
670
|
switch (process.platform) {
|
|
671
671
|
case "darwin":
|
|
@@ -678,7 +678,7 @@ async function openBrowser(url2) {
|
|
|
678
678
|
})();
|
|
679
679
|
return new Promise((resolve3, reject) => {
|
|
680
680
|
try {
|
|
681
|
-
const child =
|
|
681
|
+
const child = spawn16(cmd.bin, cmd.args, {
|
|
682
682
|
stdio: "ignore",
|
|
683
683
|
detached: true
|
|
684
684
|
});
|
|
@@ -3181,10 +3181,10 @@ function mergeDefs(...defs) {
|
|
|
3181
3181
|
function cloneDef(schema) {
|
|
3182
3182
|
return mergeDefs(schema._zod.def);
|
|
3183
3183
|
}
|
|
3184
|
-
function getElementAtPath(obj,
|
|
3185
|
-
if (!
|
|
3184
|
+
function getElementAtPath(obj, path55) {
|
|
3185
|
+
if (!path55)
|
|
3186
3186
|
return obj;
|
|
3187
|
-
return
|
|
3187
|
+
return path55.reduce((acc, key) => acc?.[key], obj);
|
|
3188
3188
|
}
|
|
3189
3189
|
function promiseAllObject(promisesObj) {
|
|
3190
3190
|
const keys = Object.keys(promisesObj);
|
|
@@ -3512,11 +3512,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
3512
3512
|
}
|
|
3513
3513
|
return false;
|
|
3514
3514
|
}
|
|
3515
|
-
function prefixIssues(
|
|
3515
|
+
function prefixIssues(path55, issues) {
|
|
3516
3516
|
return issues.map((iss) => {
|
|
3517
3517
|
var _a3;
|
|
3518
3518
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
3519
|
-
iss.path.unshift(
|
|
3519
|
+
iss.path.unshift(path55);
|
|
3520
3520
|
return iss;
|
|
3521
3521
|
});
|
|
3522
3522
|
}
|
|
@@ -3734,16 +3734,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3734
3734
|
}
|
|
3735
3735
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
3736
3736
|
const fieldErrors = { _errors: [] };
|
|
3737
|
-
const processError = (error52,
|
|
3737
|
+
const processError = (error52, path55 = []) => {
|
|
3738
3738
|
for (const issue2 of error52.issues) {
|
|
3739
3739
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3740
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3740
|
+
issue2.errors.map((issues) => processError({ issues }, [...path55, ...issue2.path]));
|
|
3741
3741
|
} else if (issue2.code === "invalid_key") {
|
|
3742
|
-
processError({ issues: issue2.issues }, [...
|
|
3742
|
+
processError({ issues: issue2.issues }, [...path55, ...issue2.path]);
|
|
3743
3743
|
} else if (issue2.code === "invalid_element") {
|
|
3744
|
-
processError({ issues: issue2.issues }, [...
|
|
3744
|
+
processError({ issues: issue2.issues }, [...path55, ...issue2.path]);
|
|
3745
3745
|
} else {
|
|
3746
|
-
const fullpath = [...
|
|
3746
|
+
const fullpath = [...path55, ...issue2.path];
|
|
3747
3747
|
if (fullpath.length === 0) {
|
|
3748
3748
|
fieldErrors._errors.push(mapper(issue2));
|
|
3749
3749
|
} else {
|
|
@@ -3770,17 +3770,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3770
3770
|
}
|
|
3771
3771
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
3772
3772
|
const result = { errors: [] };
|
|
3773
|
-
const processError = (error52,
|
|
3773
|
+
const processError = (error52, path55 = []) => {
|
|
3774
3774
|
var _a3, _b;
|
|
3775
3775
|
for (const issue2 of error52.issues) {
|
|
3776
3776
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3777
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3777
|
+
issue2.errors.map((issues) => processError({ issues }, [...path55, ...issue2.path]));
|
|
3778
3778
|
} else if (issue2.code === "invalid_key") {
|
|
3779
|
-
processError({ issues: issue2.issues }, [...
|
|
3779
|
+
processError({ issues: issue2.issues }, [...path55, ...issue2.path]);
|
|
3780
3780
|
} else if (issue2.code === "invalid_element") {
|
|
3781
|
-
processError({ issues: issue2.issues }, [...
|
|
3781
|
+
processError({ issues: issue2.issues }, [...path55, ...issue2.path]);
|
|
3782
3782
|
} else {
|
|
3783
|
-
const fullpath = [...
|
|
3783
|
+
const fullpath = [...path55, ...issue2.path];
|
|
3784
3784
|
if (fullpath.length === 0) {
|
|
3785
3785
|
result.errors.push(mapper(issue2));
|
|
3786
3786
|
continue;
|
|
@@ -3812,8 +3812,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3812
3812
|
}
|
|
3813
3813
|
function toDotPath(_path) {
|
|
3814
3814
|
const segs = [];
|
|
3815
|
-
const
|
|
3816
|
-
for (const seg of
|
|
3815
|
+
const path55 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
3816
|
+
for (const seg of path55) {
|
|
3817
3817
|
if (typeof seg === "number")
|
|
3818
3818
|
segs.push(`[${seg}]`);
|
|
3819
3819
|
else if (typeof seg === "symbol")
|
|
@@ -17316,13 +17316,13 @@ function resolveRef(ref, ctx) {
|
|
|
17316
17316
|
if (!ref.startsWith("#")) {
|
|
17317
17317
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
17318
17318
|
}
|
|
17319
|
-
const
|
|
17320
|
-
if (
|
|
17319
|
+
const path55 = ref.slice(1).split("/").filter(Boolean);
|
|
17320
|
+
if (path55.length === 0) {
|
|
17321
17321
|
return ctx.rootSchema;
|
|
17322
17322
|
}
|
|
17323
17323
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
17324
|
-
if (
|
|
17325
|
-
const key =
|
|
17324
|
+
if (path55[0] === defsKey) {
|
|
17325
|
+
const key = path55[1];
|
|
17326
17326
|
if (!key || !ctx.defs[key]) {
|
|
17327
17327
|
throw new Error(`Reference not found: ${ref}`);
|
|
17328
17328
|
}
|
|
@@ -18625,6 +18625,27 @@ function coerceStringList(value, fallback) {
|
|
|
18625
18625
|
}
|
|
18626
18626
|
return fallback;
|
|
18627
18627
|
}
|
|
18628
|
+
function hasRecursiveGlob(include) {
|
|
18629
|
+
return include.some((g) => g.includes("**"));
|
|
18630
|
+
}
|
|
18631
|
+
function scopeWarnings(allEntries, include, matched) {
|
|
18632
|
+
const warnings = [];
|
|
18633
|
+
const filesWalked = allEntries.filter((e) => e.type === "file").length;
|
|
18634
|
+
if (filesWalked === 0)
|
|
18635
|
+
return warnings;
|
|
18636
|
+
if (matched === 0) {
|
|
18637
|
+
warnings.push(`SEARCH_EMPTY_SCOPE: include globs matched 0 of ${filesWalked} files walked \u2014 '*' matches only one path segment; use '**/<glob>' for recursive matching. Do not interpret this result as "pattern not found".`);
|
|
18638
|
+
return warnings;
|
|
18639
|
+
}
|
|
18640
|
+
if (hasRecursiveGlob(include) || matched >= filesWalked)
|
|
18641
|
+
return warnings;
|
|
18642
|
+
const recursiveRegexes = compileGlobs(include.map((g) => `**/${g}`));
|
|
18643
|
+
const wouldMatch = allEntries.filter((e) => e.type === "file" && matchesAnyCompiled(e.name, recursiveRegexes)).length;
|
|
18644
|
+
if (wouldMatch > matched) {
|
|
18645
|
+
warnings.push(`include globs matched ${matched} of ${filesWalked} files walked \u2014 '*' matches only one path segment; a '**/*.ts'-style recursive glob would have matched ${wouldMatch - matched} more file(s) in subdirectories`);
|
|
18646
|
+
}
|
|
18647
|
+
return warnings;
|
|
18648
|
+
}
|
|
18628
18649
|
async function searchFile(absPath, relPath, regex, contextLines, remainingSlots) {
|
|
18629
18650
|
let buf;
|
|
18630
18651
|
try {
|
|
@@ -18701,7 +18722,7 @@ var init_search = __esm({
|
|
|
18701
18722
|
});
|
|
18702
18723
|
grepContentTool = {
|
|
18703
18724
|
name: "grep_content",
|
|
18704
|
-
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.). include/exclude accept a single glob string (e.g. "*.ts") OR an array of globs. Returns matches with line numbers and
|
|
18725
|
+
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: "*" matches ONE path segment only ("*.ts" does NOT match "sub/file.ts"); use "**" for recursive matching ("**/*.ts" matches at any depth). 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.',
|
|
18705
18726
|
permissions: ["read"],
|
|
18706
18727
|
timeoutMs: 3e4,
|
|
18707
18728
|
inputSchema: GrepContentArgsSchema,
|
|
@@ -18709,8 +18730,15 @@ var init_search = __esm({
|
|
|
18709
18730
|
try {
|
|
18710
18731
|
const absRoot = path8.isAbsolute(args.path) ? args.path : path8.join(ctx.cwd, args.path);
|
|
18711
18732
|
const regex = new RegExp(args.pattern, "gm");
|
|
18712
|
-
const
|
|
18733
|
+
const rawInclude = args.include;
|
|
18734
|
+
const include = coerceStringList(rawInclude, ["*"]);
|
|
18713
18735
|
const exclude = coerceStringList(args.exclude, DEFAULT_EXCLUDES);
|
|
18736
|
+
const warnings = [];
|
|
18737
|
+
if (Array.isArray(rawInclude) && rawInclude.length === 0) {
|
|
18738
|
+
warnings.push('DEPRECATED_INPUT: empty include array \u2014 omit the field instead; this will become INVALID_ARGUMENT (planned v1.47). Fell back to ["*"]');
|
|
18739
|
+
} else if (typeof rawInclude === "string") {
|
|
18740
|
+
warnings.push(`include coerced from bare string to ${JSON.stringify(include)}`);
|
|
18741
|
+
}
|
|
18714
18742
|
if (!await isDirectory(absRoot)) {
|
|
18715
18743
|
const single = await searchFile(absRoot, args.path, regex, args.contextLines, args.maxMatches);
|
|
18716
18744
|
return typedOk({
|
|
@@ -18718,12 +18746,18 @@ var init_search = __esm({
|
|
|
18718
18746
|
totalMatches: single.total,
|
|
18719
18747
|
truncated: single.truncated,
|
|
18720
18748
|
filesSearched: 1,
|
|
18721
|
-
filesInTree: 1
|
|
18749
|
+
filesInTree: 1,
|
|
18750
|
+
filesWalked: 1,
|
|
18751
|
+
effectiveInclude: include,
|
|
18752
|
+
effectiveExclude: exclude,
|
|
18753
|
+
...warnings.length > 0 ? { warning: warnings.join("; ") } : {}
|
|
18722
18754
|
});
|
|
18723
18755
|
}
|
|
18724
18756
|
const allEntries = [];
|
|
18725
18757
|
await walk(absRoot, "", 0, args.maxDepth, exclude, allEntries, ctx.signal);
|
|
18726
18758
|
const matchedFiles = filterByInclude(allEntries, include);
|
|
18759
|
+
const filesWalked = allEntries.filter((e) => e.type === "file").length;
|
|
18760
|
+
warnings.push(...scopeWarnings(allEntries, include, matchedFiles.length));
|
|
18727
18761
|
const allMatches = [];
|
|
18728
18762
|
let totalMatches = 0;
|
|
18729
18763
|
let truncated = false;
|
|
@@ -18748,7 +18782,11 @@ var init_search = __esm({
|
|
|
18748
18782
|
totalMatches,
|
|
18749
18783
|
truncated,
|
|
18750
18784
|
filesSearched,
|
|
18751
|
-
filesInTree: matchedFiles.length
|
|
18785
|
+
filesInTree: matchedFiles.length,
|
|
18786
|
+
filesWalked,
|
|
18787
|
+
effectiveInclude: include,
|
|
18788
|
+
effectiveExclude: exclude,
|
|
18789
|
+
...warnings.length > 0 ? { warning: warnings.join("; ") } : {}
|
|
18752
18790
|
});
|
|
18753
18791
|
} catch (err) {
|
|
18754
18792
|
return typedErr(err instanceof Error ? err.message : String(err));
|
|
@@ -19535,11 +19573,11 @@ var init_tools = __esm({
|
|
|
19535
19573
|
if (!ctx.addDocument)
|
|
19536
19574
|
return "Knowledge vault tool not available.";
|
|
19537
19575
|
const title = args["title"] || "New Document";
|
|
19538
|
-
const
|
|
19576
|
+
const path55 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
19539
19577
|
const content = args["content"] || "";
|
|
19540
19578
|
const tags = args["tags"] || [];
|
|
19541
19579
|
ctx.addDocument({
|
|
19542
|
-
path:
|
|
19580
|
+
path: path55,
|
|
19543
19581
|
title,
|
|
19544
19582
|
content,
|
|
19545
19583
|
format: "markdown",
|
|
@@ -19548,7 +19586,7 @@ var init_tools = __esm({
|
|
|
19548
19586
|
workspaceId: ctx.workspaceId
|
|
19549
19587
|
});
|
|
19550
19588
|
ctx.addActivity("vault", "created document", title);
|
|
19551
|
-
return `Document "${title}" created at "${
|
|
19589
|
+
return `Document "${title}" created at "${path55}".`;
|
|
19552
19590
|
}
|
|
19553
19591
|
}
|
|
19554
19592
|
];
|
|
@@ -23877,11 +23915,11 @@ var init_synthesisAudit = __esm({
|
|
|
23877
23915
|
import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
|
|
23878
23916
|
import { join as join2 } from "node:path";
|
|
23879
23917
|
function loadNfrSpec(zelariRoot) {
|
|
23880
|
-
const
|
|
23881
|
-
if (!existsSync7(
|
|
23918
|
+
const path55 = join2(zelariRoot, "nfr-spec.json");
|
|
23919
|
+
if (!existsSync7(path55))
|
|
23882
23920
|
return null;
|
|
23883
23921
|
try {
|
|
23884
|
-
const raw = JSON.parse(readFileSync7(
|
|
23922
|
+
const raw = JSON.parse(readFileSync7(path55, "utf8"));
|
|
23885
23923
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
23886
23924
|
return null;
|
|
23887
23925
|
return raw;
|
|
@@ -26187,9 +26225,9 @@ var init_types4 = __esm({
|
|
|
26187
26225
|
import { readFileSync as readFileSync12 } from "node:fs";
|
|
26188
26226
|
import { join as join8 } from "node:path";
|
|
26189
26227
|
function readLessonsDeduped(zelariRoot) {
|
|
26190
|
-
const
|
|
26228
|
+
const path55 = join8(zelariRoot, LESSONS_FILE);
|
|
26191
26229
|
try {
|
|
26192
|
-
const raw = readFileSync12(
|
|
26230
|
+
const raw = readFileSync12(path55, "utf8");
|
|
26193
26231
|
const byId = /* @__PURE__ */ new Map();
|
|
26194
26232
|
for (const line of raw.split(/\r?\n/)) {
|
|
26195
26233
|
if (!line.trim())
|
|
@@ -26290,8 +26328,8 @@ function keywordsFrom(check2, signature) {
|
|
|
26290
26328
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
26291
26329
|
}
|
|
26292
26330
|
function writeLesson(zelariRoot, lesson) {
|
|
26293
|
-
const
|
|
26294
|
-
appendFileSync(
|
|
26331
|
+
const path55 = join9(zelariRoot, LESSONS_FILE);
|
|
26332
|
+
appendFileSync(path55, `${JSON.stringify(lesson)}
|
|
26295
26333
|
`, "utf8");
|
|
26296
26334
|
}
|
|
26297
26335
|
function findSimilar(lessons, signature) {
|
|
@@ -26904,9 +26942,9 @@ function findCycle(nodes) {
|
|
|
26904
26942
|
if (color.get(start) !== WHITE)
|
|
26905
26943
|
continue;
|
|
26906
26944
|
const stack = [[start, 0]];
|
|
26907
|
-
const
|
|
26945
|
+
const path55 = [];
|
|
26908
26946
|
color.set(start, GRAY);
|
|
26909
|
-
|
|
26947
|
+
path55.push(start);
|
|
26910
26948
|
while (stack.length > 0) {
|
|
26911
26949
|
const top = stack[stack.length - 1];
|
|
26912
26950
|
const [id, idx] = top;
|
|
@@ -26919,17 +26957,17 @@ function findCycle(nodes) {
|
|
|
26919
26957
|
continue;
|
|
26920
26958
|
const c = color.get(dep);
|
|
26921
26959
|
if (c === GRAY) {
|
|
26922
|
-
const at =
|
|
26923
|
-
return [...
|
|
26960
|
+
const at = path55.indexOf(dep);
|
|
26961
|
+
return [...path55.slice(at), dep];
|
|
26924
26962
|
}
|
|
26925
26963
|
if (c === WHITE) {
|
|
26926
26964
|
color.set(dep, GRAY);
|
|
26927
|
-
|
|
26965
|
+
path55.push(dep);
|
|
26928
26966
|
stack.push([dep, 0]);
|
|
26929
26967
|
}
|
|
26930
26968
|
} else {
|
|
26931
26969
|
color.set(id, BLACK);
|
|
26932
|
-
|
|
26970
|
+
path55.pop();
|
|
26933
26971
|
stack.pop();
|
|
26934
26972
|
}
|
|
26935
26973
|
}
|
|
@@ -27849,8 +27887,8 @@ var init_runner = __esm({
|
|
|
27849
27887
|
failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
|
|
27850
27888
|
pending: []
|
|
27851
27889
|
};
|
|
27852
|
-
const
|
|
27853
|
-
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${
|
|
27890
|
+
const path55 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
|
|
27891
|
+
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path55}`);
|
|
27854
27892
|
return snapshot;
|
|
27855
27893
|
}
|
|
27856
27894
|
callLog(msg, data) {
|
|
@@ -29463,9 +29501,9 @@ function spillToolOutput(fullText, meta3) {
|
|
|
29463
29501
|
const rnd = randomBytes2(3).toString("hex");
|
|
29464
29502
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
29465
29503
|
const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
|
|
29466
|
-
const
|
|
29467
|
-
writeFileSync11(
|
|
29468
|
-
return
|
|
29504
|
+
const path55 = join11(dir, file2);
|
|
29505
|
+
writeFileSync11(path55, fullText, "utf8");
|
|
29506
|
+
return path55;
|
|
29469
29507
|
} catch {
|
|
29470
29508
|
return null;
|
|
29471
29509
|
}
|
|
@@ -29511,10 +29549,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
|
|
|
29511
29549
|
${tail}`;
|
|
29512
29550
|
}
|
|
29513
29551
|
if (doSpill) {
|
|
29514
|
-
const
|
|
29515
|
-
if (
|
|
29552
|
+
const path55 = spillToolOutput(text, { toolName: opts.toolName });
|
|
29553
|
+
if (path55) {
|
|
29516
29554
|
const spillNote = `
|
|
29517
|
-
\u2026 [full output spilled to: ${
|
|
29555
|
+
\u2026 [full output spilled to: ${path55} \u2014 re-read with read_file if you need the complete text] \u2026`;
|
|
29518
29556
|
if (preview.includes("] \u2026\n")) {
|
|
29519
29557
|
preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
|
|
29520
29558
|
`);
|
|
@@ -30689,6 +30727,10 @@ var init_taskTool = __esm({
|
|
|
30689
30727
|
EXPLORE_PROMPT = [
|
|
30690
30728
|
"You are a focused EXPLORE tentacle of Kraken (parent super-agent).",
|
|
30691
30729
|
"READ-ONLY tools only (read, list, grep, fetch). No edits, no shell.",
|
|
30730
|
+
"OBSERVATION INTEGRITY: negative evidence is valid only from a completed",
|
|
30731
|
+
"observation. Never conclude that code/symbols/files do not exist from",
|
|
30732
|
+
"degraded results, zero files examined, or unavailable backends - report",
|
|
30733
|
+
"the degraded status instead and widen the observation.",
|
|
30692
30734
|
"Gather only what you need, then STOP with a concise conclusion:",
|
|
30693
30735
|
"file paths, symbols, line refs, and how things connect. No large dumps.",
|
|
30694
30736
|
"Respect any Scope / Acceptance sections in the user prompt.",
|
|
@@ -31375,28 +31417,28 @@ var init_storage = __esm({
|
|
|
31375
31417
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
31376
31418
|
Storage = class {
|
|
31377
31419
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
31378
|
-
read(
|
|
31379
|
-
if (!existsSync18(
|
|
31380
|
-
throw new Error(`File not found: ${
|
|
31420
|
+
read(path55) {
|
|
31421
|
+
if (!existsSync18(path55)) {
|
|
31422
|
+
throw new Error(`File not found: ${path55}`);
|
|
31381
31423
|
}
|
|
31382
|
-
const md = readFileSync16(
|
|
31424
|
+
const md = readFileSync16(path55, "utf8");
|
|
31383
31425
|
return parseFrontmatter(md);
|
|
31384
31426
|
}
|
|
31385
31427
|
/** Read a Markdown file; returns null if not found. */
|
|
31386
|
-
readIfExists(
|
|
31387
|
-
if (!existsSync18(
|
|
31388
|
-
return this.read(
|
|
31428
|
+
readIfExists(path55) {
|
|
31429
|
+
if (!existsSync18(path55)) return null;
|
|
31430
|
+
return this.read(path55);
|
|
31389
31431
|
}
|
|
31390
31432
|
/**
|
|
31391
31433
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
31392
31434
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
31393
31435
|
*/
|
|
31394
|
-
write(
|
|
31395
|
-
mkdirSync11(dirname2(
|
|
31396
|
-
const tmp =
|
|
31436
|
+
write(path55, meta3, body) {
|
|
31437
|
+
mkdirSync11(dirname2(path55), { recursive: true });
|
|
31438
|
+
const tmp = path55 + ".tmp-" + process.pid;
|
|
31397
31439
|
const md = serializeFrontmatter(meta3, body);
|
|
31398
31440
|
writeFileSync13(tmp, md, "utf8");
|
|
31399
|
-
renameSync2(tmp,
|
|
31441
|
+
renameSync2(tmp, path55);
|
|
31400
31442
|
}
|
|
31401
31443
|
/** List all .md files in a directory (non-recursive). */
|
|
31402
31444
|
listMarkdown(dir) {
|
|
@@ -31458,8 +31500,8 @@ function nextPlanTaskId(store4) {
|
|
|
31458
31500
|
return `t${store4.counter}`;
|
|
31459
31501
|
}
|
|
31460
31502
|
function writePlanTaskArtifact(rootDir, task) {
|
|
31461
|
-
const
|
|
31462
|
-
mkdirSync12(dirname3(
|
|
31503
|
+
const path55 = join15(rootDir, "plan-tasks", `${task.id}.md`);
|
|
31504
|
+
mkdirSync12(dirname3(path55), { recursive: true });
|
|
31463
31505
|
const meta3 = {
|
|
31464
31506
|
kind: "task",
|
|
31465
31507
|
id: task.id,
|
|
@@ -31480,7 +31522,7 @@ function writePlanTaskArtifact(rootDir, task) {
|
|
|
31480
31522
|
task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
|
|
31481
31523
|
""
|
|
31482
31524
|
].filter((l) => l !== null).join("\n");
|
|
31483
|
-
new Storage().write(
|
|
31525
|
+
new Storage().write(path55, meta3, body);
|
|
31484
31526
|
}
|
|
31485
31527
|
function loadHandle(rootDir) {
|
|
31486
31528
|
const jsonPath = join15(rootDir, "plan.json");
|
|
@@ -31799,6 +31841,369 @@ var init_planTaskTools = __esm({
|
|
|
31799
31841
|
}
|
|
31800
31842
|
});
|
|
31801
31843
|
|
|
31844
|
+
// src/cli/tools/inspectTypecheckSafety.ts
|
|
31845
|
+
import { promises as fs12 } from "node:fs";
|
|
31846
|
+
import path21 from "node:path";
|
|
31847
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
31848
|
+
async function scanTsbuildinfo(root) {
|
|
31849
|
+
const found = [];
|
|
31850
|
+
const stack = [root];
|
|
31851
|
+
while (stack.length > 0) {
|
|
31852
|
+
const dir = stack.pop();
|
|
31853
|
+
let entries;
|
|
31854
|
+
try {
|
|
31855
|
+
entries = await fs12.readdir(dir, { withFileTypes: true });
|
|
31856
|
+
} catch {
|
|
31857
|
+
continue;
|
|
31858
|
+
}
|
|
31859
|
+
for (const entry of entries) {
|
|
31860
|
+
const p3 = path21.join(dir, entry.name);
|
|
31861
|
+
if (entry.isDirectory()) {
|
|
31862
|
+
if (!SCAN_SKIP.has(entry.name)) stack.push(p3);
|
|
31863
|
+
} else if (entry.name.endsWith(".tsbuildinfo")) {
|
|
31864
|
+
found.push(path21.relative(root, p3).split(path21.sep).join("/"));
|
|
31865
|
+
}
|
|
31866
|
+
}
|
|
31867
|
+
}
|
|
31868
|
+
found.sort();
|
|
31869
|
+
return found;
|
|
31870
|
+
}
|
|
31871
|
+
async function gitStatusPorcelain(root) {
|
|
31872
|
+
return new Promise((resolve3) => {
|
|
31873
|
+
const child = spawn4("git", ["status", "--porcelain"], { cwd: root, shell: false });
|
|
31874
|
+
let out = "";
|
|
31875
|
+
child.stdout.on("data", (d) => out += d.toString());
|
|
31876
|
+
child.stderr.on("data", (d) => out += d.toString());
|
|
31877
|
+
child.on("error", () => resolve3("<git-unavailable>"));
|
|
31878
|
+
child.on("close", (code) => resolve3(code === 0 ? out : `<git-exit-${code ?? "none"}>`));
|
|
31879
|
+
});
|
|
31880
|
+
}
|
|
31881
|
+
async function fingerprintWorkspace(root) {
|
|
31882
|
+
const [gitStatus, tsbuildinfoFiles] = await Promise.all([
|
|
31883
|
+
gitStatusPorcelain(root),
|
|
31884
|
+
scanTsbuildinfo(root)
|
|
31885
|
+
]);
|
|
31886
|
+
return { gitStatus, tsbuildinfoFiles };
|
|
31887
|
+
}
|
|
31888
|
+
function diffFingerprints(pre, post) {
|
|
31889
|
+
const preSet = new Set(pre.tsbuildinfoFiles);
|
|
31890
|
+
return {
|
|
31891
|
+
newTsbuildinfo: post.tsbuildinfoFiles.filter((f) => !preSet.has(f)),
|
|
31892
|
+
gitStatusChanged: post.gitStatus !== pre.gitStatus
|
|
31893
|
+
};
|
|
31894
|
+
}
|
|
31895
|
+
async function cleanupArtifacts(root, relPaths) {
|
|
31896
|
+
const cleaned = [];
|
|
31897
|
+
const failed = [];
|
|
31898
|
+
for (const rel2 of relPaths) {
|
|
31899
|
+
try {
|
|
31900
|
+
await fs12.unlink(path21.join(root, rel2));
|
|
31901
|
+
cleaned.push(rel2);
|
|
31902
|
+
} catch {
|
|
31903
|
+
failed.push(rel2);
|
|
31904
|
+
}
|
|
31905
|
+
}
|
|
31906
|
+
return { cleaned, failed };
|
|
31907
|
+
}
|
|
31908
|
+
function classifyTypecheckRefusal(output) {
|
|
31909
|
+
if (/composite/i.test(output) && /(may not|cannot|disallow|disable)/i.test(output)) {
|
|
31910
|
+
return "the TypeScript compiler refused to run on this composite/incremental project shape (tsc-level error about the build setup, not a type error) \u2014 inspect_command will not fake an empty result; run the project typecheck script directly if you need it";
|
|
31911
|
+
}
|
|
31912
|
+
return null;
|
|
31913
|
+
}
|
|
31914
|
+
var SCAN_SKIP;
|
|
31915
|
+
var init_inspectTypecheckSafety = __esm({
|
|
31916
|
+
"src/cli/tools/inspectTypecheckSafety.ts"() {
|
|
31917
|
+
"use strict";
|
|
31918
|
+
SCAN_SKIP = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
31919
|
+
}
|
|
31920
|
+
});
|
|
31921
|
+
|
|
31922
|
+
// src/cli/tools/inspectCommand.ts
|
|
31923
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
31924
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
31925
|
+
import { existsSync as existsSync20, promises as fs13 } from "node:fs";
|
|
31926
|
+
import os8 from "node:os";
|
|
31927
|
+
import path22 from "node:path";
|
|
31928
|
+
function resolveNodeModuleBin(start, rel2) {
|
|
31929
|
+
let dir = path22.resolve(start);
|
|
31930
|
+
for (; ; ) {
|
|
31931
|
+
const candidate = path22.join(dir, "node_modules", rel2);
|
|
31932
|
+
if (existsSync20(candidate)) return candidate;
|
|
31933
|
+
const parent = path22.dirname(dir);
|
|
31934
|
+
if (parent === dir) return void 0;
|
|
31935
|
+
dir = parent;
|
|
31936
|
+
}
|
|
31937
|
+
}
|
|
31938
|
+
function rejectFlagLike(kind, value) {
|
|
31939
|
+
if (value.startsWith("-")) {
|
|
31940
|
+
return `${kind} must not start with "-" (got ${JSON.stringify(value)}) \u2014 pass a value, not a flag`;
|
|
31941
|
+
}
|
|
31942
|
+
return null;
|
|
31943
|
+
}
|
|
31944
|
+
function buildInspectCommand(op, ctx) {
|
|
31945
|
+
switch (op.operation) {
|
|
31946
|
+
case "git_status":
|
|
31947
|
+
return {
|
|
31948
|
+
ok: true,
|
|
31949
|
+
command: "git",
|
|
31950
|
+
argv: ["status", ...op.short ? ["--short"] : []],
|
|
31951
|
+
inspectionClass: "git-inspection"
|
|
31952
|
+
};
|
|
31953
|
+
case "git_log":
|
|
31954
|
+
return {
|
|
31955
|
+
ok: true,
|
|
31956
|
+
command: "git",
|
|
31957
|
+
argv: [
|
|
31958
|
+
"log",
|
|
31959
|
+
...op.oneline ? ["--oneline"] : [],
|
|
31960
|
+
...op.limit !== void 0 ? ["-n", String(op.limit)] : []
|
|
31961
|
+
],
|
|
31962
|
+
inspectionClass: "git-inspection"
|
|
31963
|
+
};
|
|
31964
|
+
case "git_diff": {
|
|
31965
|
+
if (op.path !== void 0) {
|
|
31966
|
+
const err = rejectFlagLike("path", op.path);
|
|
31967
|
+
if (err) return { ok: false, reason: err };
|
|
31968
|
+
}
|
|
31969
|
+
return {
|
|
31970
|
+
ok: true,
|
|
31971
|
+
command: "git",
|
|
31972
|
+
argv: [
|
|
31973
|
+
"diff",
|
|
31974
|
+
"--no-ext-diff",
|
|
31975
|
+
"--no-textconv",
|
|
31976
|
+
...op.staged ? ["--staged"] : [],
|
|
31977
|
+
...op.path !== void 0 ? ["--", op.path] : []
|
|
31978
|
+
],
|
|
31979
|
+
inspectionClass: "git-inspection"
|
|
31980
|
+
};
|
|
31981
|
+
}
|
|
31982
|
+
case "git_show": {
|
|
31983
|
+
const err = rejectFlagLike("ref", op.ref);
|
|
31984
|
+
if (err) return { ok: false, reason: err };
|
|
31985
|
+
return {
|
|
31986
|
+
ok: true,
|
|
31987
|
+
command: "git",
|
|
31988
|
+
argv: ["show", "--no-ext-diff", "--no-textconv", op.ref],
|
|
31989
|
+
inspectionClass: "git-inspection"
|
|
31990
|
+
};
|
|
31991
|
+
}
|
|
31992
|
+
case "git_branch_current":
|
|
31993
|
+
return { ok: true, command: "git", argv: ["branch", "--show-current"], inspectionClass: "git-inspection" };
|
|
31994
|
+
case "git_ls_files":
|
|
31995
|
+
return { ok: true, command: "git", argv: ["ls-files"], inspectionClass: "git-inspection" };
|
|
31996
|
+
case "node_version":
|
|
31997
|
+
return { ok: true, command: process.execPath, argv: ["--version"], inspectionClass: "env-info" };
|
|
31998
|
+
case "npm_ls":
|
|
31999
|
+
case "npm_outdated":
|
|
32000
|
+
case "npm_view": {
|
|
32001
|
+
const npmCli = ctx.npmCliPath ?? resolveNodeModuleBin(ctx.root, path22.join("npm", "bin", "npm-cli.js")) ?? path22.join(ctx.root, "node_modules", "npm", "bin", "npm-cli.js");
|
|
32002
|
+
if (op.operation === "npm_view") {
|
|
32003
|
+
const err = rejectFlagLike("package", op.package);
|
|
32004
|
+
if (err) return { ok: false, reason: err };
|
|
32005
|
+
}
|
|
32006
|
+
const sub = op.operation === "npm_ls" ? ["ls", "--depth=0"] : op.operation === "npm_outdated" ? ["outdated"] : ["view", op.package];
|
|
32007
|
+
return { ok: true, command: process.execPath, argv: [npmCli, ...sub], inspectionClass: "env-info" };
|
|
32008
|
+
}
|
|
32009
|
+
case "typecheck": {
|
|
32010
|
+
const project = path22.resolve(ctx.cwd, op.project ?? "tsconfig.json");
|
|
32011
|
+
const hash3 = createHash5("sha256").update(project).digest("hex").slice(0, 16);
|
|
32012
|
+
const tsBuildInfoFile = path22.join(os8.tmpdir(), "zelari-inspect", `${hash3}.tsbuildinfo`);
|
|
32013
|
+
return {
|
|
32014
|
+
ok: true,
|
|
32015
|
+
command: process.execPath,
|
|
32016
|
+
argv: [
|
|
32017
|
+
ctx.tscPath ?? resolveNodeModuleBin(ctx.root, path22.join("typescript", "bin", "tsc")) ?? resolveNodeModuleBin(ctx.cwd, path22.join("typescript", "bin", "tsc")) ?? path22.join(ctx.root, "node_modules", "typescript", "bin", "tsc"),
|
|
32018
|
+
"--noEmit",
|
|
32019
|
+
// S3.5 primary mechanism: redirect, never disable — composite forces
|
|
32020
|
+
// incremental (TS#30661), so --incremental false would break on the
|
|
32021
|
+
// very fixture it must support. The CLI override wins over any
|
|
32022
|
+
// tsBuildInfoFile written into the tsconfig.
|
|
32023
|
+
"--incremental",
|
|
32024
|
+
"--tsBuildInfoFile",
|
|
32025
|
+
tsBuildInfoFile,
|
|
32026
|
+
"-p",
|
|
32027
|
+
project
|
|
32028
|
+
],
|
|
32029
|
+
inspectionClass: "project-code-execution",
|
|
32030
|
+
tsBuildInfoFile
|
|
32031
|
+
};
|
|
32032
|
+
}
|
|
32033
|
+
}
|
|
32034
|
+
}
|
|
32035
|
+
function runSpawn(command, argv, opts) {
|
|
32036
|
+
return new Promise((resolve3) => {
|
|
32037
|
+
let child;
|
|
32038
|
+
try {
|
|
32039
|
+
child = spawn5(command, argv, { cwd: opts.cwd, shell: false });
|
|
32040
|
+
} catch (err) {
|
|
32041
|
+
resolve3({ code: null, stdout: "", stderr: String(err), timedOut: false, spawnError: String(err) });
|
|
32042
|
+
return;
|
|
32043
|
+
}
|
|
32044
|
+
let stdout = "";
|
|
32045
|
+
let stderr = "";
|
|
32046
|
+
let timedOut = false;
|
|
32047
|
+
let settled = false;
|
|
32048
|
+
const timer = setTimeout(() => {
|
|
32049
|
+
timedOut = true;
|
|
32050
|
+
child.kill();
|
|
32051
|
+
}, opts.timeoutMs);
|
|
32052
|
+
const onAbort = () => {
|
|
32053
|
+
timedOut = true;
|
|
32054
|
+
child.kill();
|
|
32055
|
+
};
|
|
32056
|
+
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
32057
|
+
child.stdout?.on("data", (d) => stdout += d.toString());
|
|
32058
|
+
child.stderr?.on("data", (d) => stderr += d.toString());
|
|
32059
|
+
child.on("error", (err) => {
|
|
32060
|
+
if (settled) return;
|
|
32061
|
+
settled = true;
|
|
32062
|
+
clearTimeout(timer);
|
|
32063
|
+
resolve3({ code: null, stdout, stderr, timedOut, spawnError: err.message });
|
|
32064
|
+
});
|
|
32065
|
+
child.on("close", (code) => {
|
|
32066
|
+
if (settled) return;
|
|
32067
|
+
settled = true;
|
|
32068
|
+
clearTimeout(timer);
|
|
32069
|
+
opts.signal?.removeEventListener("abort", onAbort);
|
|
32070
|
+
resolve3({ code, stdout, stderr, timedOut });
|
|
32071
|
+
});
|
|
32072
|
+
});
|
|
32073
|
+
}
|
|
32074
|
+
function capOutput(stdout, stderr) {
|
|
32075
|
+
const combined = stderr ? `${stdout}
|
|
32076
|
+
[stderr]
|
|
32077
|
+
${stderr}` : stdout;
|
|
32078
|
+
if (combined.length <= MAX_OUTPUT_CHARS) return { output: combined, truncated: false };
|
|
32079
|
+
return {
|
|
32080
|
+
output: `${combined.slice(0, MAX_OUTPUT_CHARS)}
|
|
32081
|
+
\u2026 (truncated, ${combined.length} chars total)`,
|
|
32082
|
+
truncated: true
|
|
32083
|
+
};
|
|
32084
|
+
}
|
|
32085
|
+
async function typecheckGuarded(built, root, signal) {
|
|
32086
|
+
const pre = await fingerprintWorkspace(root);
|
|
32087
|
+
const r = await runSpawn(built.command, built.argv, { cwd: root, timeoutMs: TYPECHECK_TIMEOUT_MS, signal });
|
|
32088
|
+
if (r.spawnError) {
|
|
32089
|
+
return typedErr(`SPAWN_ERROR: typecheck could not launch: ${r.spawnError}`);
|
|
32090
|
+
}
|
|
32091
|
+
const { output, truncated } = capOutput(r.stdout, r.stderr);
|
|
32092
|
+
const refusal = r.code !== 0 ? classifyTypecheckRefusal(`${r.stdout}
|
|
32093
|
+
${r.stderr}`) : null;
|
|
32094
|
+
if (refusal) {
|
|
32095
|
+
return typedOk({
|
|
32096
|
+
status: "unsupported_project_shape",
|
|
32097
|
+
operation: "typecheck",
|
|
32098
|
+
inspectionClass: built.inspectionClass,
|
|
32099
|
+
reason: refusal,
|
|
32100
|
+
exitCode: r.code,
|
|
32101
|
+
output,
|
|
32102
|
+
truncated
|
|
32103
|
+
});
|
|
32104
|
+
}
|
|
32105
|
+
const post = await fingerprintWorkspace(root);
|
|
32106
|
+
const delta = diffFingerprints(pre, post);
|
|
32107
|
+
if (delta.newTsbuildinfo.length > 0 || delta.gitStatusChanged) {
|
|
32108
|
+
const cleanup = await cleanupArtifacts(root, delta.newTsbuildinfo);
|
|
32109
|
+
return typedOk({
|
|
32110
|
+
status: "degraded",
|
|
32111
|
+
operation: "typecheck",
|
|
32112
|
+
inspectionClass: built.inspectionClass,
|
|
32113
|
+
exitCode: r.code,
|
|
32114
|
+
output,
|
|
32115
|
+
truncated,
|
|
32116
|
+
artifactsWritten: delta.newTsbuildinfo,
|
|
32117
|
+
gitStatusChanged: delta.gitStatusChanged,
|
|
32118
|
+
cleanedUp: cleanup.cleaned,
|
|
32119
|
+
cleanupFailed: cleanup.failed,
|
|
32120
|
+
note: `UNEXPECTED WORKSPACE ARTIFACTS: the typecheck wrote build artifacts into the workspace despite the tsbuildinfo redirect. This result is NOT a clean observation \u2014 treat the typecheck verdict as unreliable until the artifact leak is understood. ${cleanup.cleaned.length} artifact(s) removed, ${cleanup.failed.length} could not be removed.`
|
|
32121
|
+
});
|
|
32122
|
+
}
|
|
32123
|
+
return typedOk({
|
|
32124
|
+
status: "ok",
|
|
32125
|
+
operation: "typecheck",
|
|
32126
|
+
inspectionClass: built.inspectionClass,
|
|
32127
|
+
exitCode: r.code,
|
|
32128
|
+
output,
|
|
32129
|
+
truncated,
|
|
32130
|
+
note: r.code === 0 ? "compiler completed with no diagnostics; tsbuildinfo was redirected to the OS temp dir \u2014 the workspace is untouched (verified by pre/post fingerprint)" : `compiler exited ${r.code} \u2014 diagnostics above are real type errors (a successful, scoped observation: the run itself worked and wrote nothing to the workspace)`
|
|
32131
|
+
});
|
|
32132
|
+
}
|
|
32133
|
+
function createInspectCommandTool(rootOrDeps) {
|
|
32134
|
+
const deps = typeof rootOrDeps === "string" ? { root: rootOrDeps } : rootOrDeps;
|
|
32135
|
+
const tool = {
|
|
32136
|
+
name: "inspect_command",
|
|
32137
|
+
description: "Allowlisted read-only command inspector for plan/read-only sessions (no shell, no mutations). Pick an operation instead of writing a command: git_status, git_log, git_diff, git_show, git_branch_current, git_ls_files, typecheck, node_version, npm_ls, npm_outdated, npm_view. typecheck runs the project TypeScript compiler with --noEmit and a temp-dir tsbuildinfo redirect, verified by a pre/post workspace fingerprint (inspectionClass: 'project-code-execution' \u2014 you are executing the project's own toolchain, not reading git).",
|
|
32138
|
+
permissions: ["read"],
|
|
32139
|
+
timeoutMs: 9e4,
|
|
32140
|
+
inputSchema: inspectInputSchema,
|
|
32141
|
+
execute: async (input, ctx) => {
|
|
32142
|
+
const op = input;
|
|
32143
|
+
const cwd = ctx?.cwd ?? deps.root;
|
|
32144
|
+
const built = buildInspectCommand(op, { root: deps.root, cwd, tscPath: deps.tscPath, npmCliPath: deps.npmCliPath });
|
|
32145
|
+
if (!built.ok) return typedErr(`INVALID_ARGUMENT: ${built.reason}`);
|
|
32146
|
+
if (op.operation === "typecheck") {
|
|
32147
|
+
const tsc = built.argv[0];
|
|
32148
|
+
try {
|
|
32149
|
+
await fs13.access(tsc);
|
|
32150
|
+
} catch {
|
|
32151
|
+
return typedErr(
|
|
32152
|
+
`TYPESCRIPT_UNAVAILABLE: no TypeScript compiler at ${tsc} \u2014 inspect_command typecheck uses the project toolchain (walk-up to node_modules/typescript/bin/tsc) and refuses to guess. Install dependencies or fall back to read_file/grep_content.`
|
|
32153
|
+
);
|
|
32154
|
+
}
|
|
32155
|
+
return typecheckGuarded(built, deps.root, ctx?.signal);
|
|
32156
|
+
}
|
|
32157
|
+
const r = await runSpawn(built.command, built.argv, { cwd, timeoutMs: SPAWN_TIMEOUT_MS, signal: ctx?.signal });
|
|
32158
|
+
if (r.spawnError) return typedErr(`SPAWN_ERROR: ${op.operation} could not launch: ${r.spawnError}`);
|
|
32159
|
+
const { output, truncated } = capOutput(r.stdout, r.stderr);
|
|
32160
|
+
return typedOk({
|
|
32161
|
+
status: r.timedOut ? "timeout" : "ok",
|
|
32162
|
+
operation: op.operation,
|
|
32163
|
+
inspectionClass: built.inspectionClass,
|
|
32164
|
+
exitCode: r.code,
|
|
32165
|
+
output,
|
|
32166
|
+
truncated,
|
|
32167
|
+
...r.timedOut ? { note: `command timed out after ${SPAWN_TIMEOUT_MS} ms` } : {}
|
|
32168
|
+
});
|
|
32169
|
+
}
|
|
32170
|
+
};
|
|
32171
|
+
return tool;
|
|
32172
|
+
}
|
|
32173
|
+
var MAX_OUTPUT_CHARS, SPAWN_TIMEOUT_MS, TYPECHECK_TIMEOUT_MS, inspectInputSchema;
|
|
32174
|
+
var init_inspectCommand = __esm({
|
|
32175
|
+
"src/cli/tools/inspectCommand.ts"() {
|
|
32176
|
+
"use strict";
|
|
32177
|
+
init_zod();
|
|
32178
|
+
init_toolTypes();
|
|
32179
|
+
init_inspectTypecheckSafety();
|
|
32180
|
+
MAX_OUTPUT_CHARS = 8 * 1024;
|
|
32181
|
+
SPAWN_TIMEOUT_MS = 85e3;
|
|
32182
|
+
TYPECHECK_TIMEOUT_MS = 85e3;
|
|
32183
|
+
inspectInputSchema = external_exports.discriminatedUnion("operation", [
|
|
32184
|
+
external_exports.object({ operation: external_exports.literal("git_status"), short: external_exports.boolean().optional() }),
|
|
32185
|
+
external_exports.object({
|
|
32186
|
+
operation: external_exports.literal("git_log"),
|
|
32187
|
+
limit: external_exports.number().int().min(1).max(200).optional(),
|
|
32188
|
+
oneline: external_exports.boolean().optional()
|
|
32189
|
+
}),
|
|
32190
|
+
external_exports.object({
|
|
32191
|
+
operation: external_exports.literal("git_diff"),
|
|
32192
|
+
staged: external_exports.boolean().optional(),
|
|
32193
|
+
path: external_exports.string().optional()
|
|
32194
|
+
}),
|
|
32195
|
+
external_exports.object({ operation: external_exports.literal("git_show"), ref: external_exports.string().min(1) }),
|
|
32196
|
+
external_exports.object({ operation: external_exports.literal("git_branch_current") }),
|
|
32197
|
+
external_exports.object({ operation: external_exports.literal("git_ls_files") }),
|
|
32198
|
+
external_exports.object({ operation: external_exports.literal("typecheck"), project: external_exports.string().optional() }),
|
|
32199
|
+
external_exports.object({ operation: external_exports.literal("node_version") }),
|
|
32200
|
+
external_exports.object({ operation: external_exports.literal("npm_ls") }),
|
|
32201
|
+
external_exports.object({ operation: external_exports.literal("npm_outdated") }),
|
|
32202
|
+
external_exports.object({ operation: external_exports.literal("npm_view"), package: external_exports.string().min(1) })
|
|
32203
|
+
]);
|
|
32204
|
+
}
|
|
32205
|
+
});
|
|
32206
|
+
|
|
31802
32207
|
// src/cli/lsp/protocol.ts
|
|
31803
32208
|
function encodeMessage(message) {
|
|
31804
32209
|
const json2 = JSON.stringify(message);
|
|
@@ -31862,6 +32267,10 @@ function fmtLocation(loc, relativeTo) {
|
|
|
31862
32267
|
const col = (loc.range?.start?.character ?? 0) + 1;
|
|
31863
32268
|
return `${rel2}:${line}:${col}`;
|
|
31864
32269
|
}
|
|
32270
|
+
function degradedNote(provider, file2) {
|
|
32271
|
+
if (provider.serverStatusFor?.(file2) !== "unavailable") return void 0;
|
|
32272
|
+
return "LSP_PROVIDER_DEGRADED: no language server is available for this file (server not installed or failed to start) \u2014 an empty result here is NOT evidence about the symbol; fall back to ast_outline/find_symbol, grep_content or read_file.";
|
|
32273
|
+
}
|
|
31865
32274
|
function createLspTools(provider, root = process.cwd()) {
|
|
31866
32275
|
const goToDefinition = {
|
|
31867
32276
|
name: "go_to_definition",
|
|
@@ -31871,9 +32280,11 @@ function createLspTools(provider, root = process.cwd()) {
|
|
|
31871
32280
|
execute: async (args) => {
|
|
31872
32281
|
const a = args;
|
|
31873
32282
|
const locs = await provider.definition(a.path, a.line - 1, a.column - 1);
|
|
32283
|
+
const degraded = degradedNote(provider, a.path);
|
|
31874
32284
|
return typedOk({
|
|
31875
32285
|
definitions: locs.map((l) => fmtLocation(l, root)),
|
|
31876
|
-
count: locs.length
|
|
32286
|
+
count: locs.length,
|
|
32287
|
+
...degraded ? { degraded } : {}
|
|
31877
32288
|
});
|
|
31878
32289
|
}
|
|
31879
32290
|
};
|
|
@@ -31885,9 +32296,11 @@ function createLspTools(provider, root = process.cwd()) {
|
|
|
31885
32296
|
execute: async (args) => {
|
|
31886
32297
|
const a = args;
|
|
31887
32298
|
const locs = await provider.references(a.path, a.line - 1, a.column - 1);
|
|
32299
|
+
const degraded = degradedNote(provider, a.path);
|
|
31888
32300
|
return typedOk({
|
|
31889
32301
|
references: locs.map((l) => fmtLocation(l, root)),
|
|
31890
|
-
count: locs.length
|
|
32302
|
+
count: locs.length,
|
|
32303
|
+
...degraded ? { degraded } : {}
|
|
31891
32304
|
});
|
|
31892
32305
|
}
|
|
31893
32306
|
};
|
|
@@ -31899,7 +32312,13 @@ function createLspTools(provider, root = process.cwd()) {
|
|
|
31899
32312
|
execute: async (args) => {
|
|
31900
32313
|
const a = args;
|
|
31901
32314
|
const text = await provider.hover(a.path, a.line - 1, a.column - 1);
|
|
31902
|
-
|
|
32315
|
+
const degraded = degradedNote(provider, a.path);
|
|
32316
|
+
return typedOk({
|
|
32317
|
+
// Degraded + no text → the note replaces the neutral message:
|
|
32318
|
+
// "(no hover information)" would be a fake-empty under a dead server.
|
|
32319
|
+
hover: text ?? degraded ?? "(no hover information)",
|
|
32320
|
+
...degraded ? { degraded } : {}
|
|
32321
|
+
});
|
|
31903
32322
|
}
|
|
31904
32323
|
};
|
|
31905
32324
|
const documentSymbols = {
|
|
@@ -31912,9 +32331,11 @@ function createLspTools(provider, root = process.cwd()) {
|
|
|
31912
32331
|
execute: async (args) => {
|
|
31913
32332
|
const a = args;
|
|
31914
32333
|
const symbols = await provider.documentSymbols(a.path);
|
|
32334
|
+
const degraded = degradedNote(provider, a.path);
|
|
31915
32335
|
return typedOk({
|
|
31916
32336
|
symbols: symbols.map((s) => `${s.kind} ${s.name} (line ${s.line})`),
|
|
31917
|
-
count: symbols.length
|
|
32337
|
+
count: symbols.length,
|
|
32338
|
+
...degraded ? { degraded } : {}
|
|
31918
32339
|
});
|
|
31919
32340
|
}
|
|
31920
32341
|
};
|
|
@@ -31928,12 +32349,16 @@ function createLspTools(provider, root = process.cwd()) {
|
|
|
31928
32349
|
execute: async (args) => {
|
|
31929
32350
|
const a = args;
|
|
31930
32351
|
const result = await provider.rename(a.path, a.line - 1, a.column - 1, a.newName);
|
|
32352
|
+
const degraded = degradedNote(provider, a.path);
|
|
31931
32353
|
if (!result) {
|
|
31932
|
-
return typedOk({
|
|
32354
|
+
return typedOk({
|
|
32355
|
+
preview: degraded ?? "no rename available at this position (symbol not found or not renameable)"
|
|
32356
|
+
});
|
|
31933
32357
|
}
|
|
31934
32358
|
return typedOk({
|
|
31935
32359
|
totalEdits: result.totalEdits,
|
|
31936
|
-
files: result.files.map((f) => `${relativePosix(root, f.file)} (${f.count} edit${f.count === 1 ? "" : "s"})`)
|
|
32360
|
+
files: result.files.map((f) => `${relativePosix(root, f.file)} (${f.count} edit${f.count === 1 ? "" : "s"})`),
|
|
32361
|
+
...degraded ? { degraded } : {}
|
|
31937
32362
|
});
|
|
31938
32363
|
}
|
|
31939
32364
|
};
|
|
@@ -32035,9 +32460,9 @@ var init_client = __esm({
|
|
|
32035
32460
|
});
|
|
32036
32461
|
|
|
32037
32462
|
// src/cli/lsp/servers.ts
|
|
32038
|
-
import
|
|
32463
|
+
import path23 from "node:path";
|
|
32039
32464
|
function languageIdForFile(file2) {
|
|
32040
|
-
const ext =
|
|
32465
|
+
const ext = path23.extname(file2).toLowerCase();
|
|
32041
32466
|
const map2 = {
|
|
32042
32467
|
".ts": "typescript",
|
|
32043
32468
|
".tsx": "typescriptreact",
|
|
@@ -32052,7 +32477,7 @@ function languageIdForFile(file2) {
|
|
|
32052
32477
|
return map2[ext] ?? "plaintext";
|
|
32053
32478
|
}
|
|
32054
32479
|
function serverForFile(file2, servers = LSP_SERVERS) {
|
|
32055
|
-
const ext =
|
|
32480
|
+
const ext = path23.extname(file2).toLowerCase();
|
|
32056
32481
|
return servers.find((s) => s.extensions.includes(ext)) ?? null;
|
|
32057
32482
|
}
|
|
32058
32483
|
function resolveServerCommand(file2, cwd, servers = LSP_SERVERS) {
|
|
@@ -32101,7 +32526,7 @@ var init_servers = __esm({
|
|
|
32101
32526
|
});
|
|
32102
32527
|
|
|
32103
32528
|
// src/cli/lsp/manager.ts
|
|
32104
|
-
import { spawn as
|
|
32529
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
32105
32530
|
import { readFileSync as readFileSync18 } from "node:fs";
|
|
32106
32531
|
function processTransport(child) {
|
|
32107
32532
|
return {
|
|
@@ -32237,7 +32662,7 @@ var init_manager = __esm({
|
|
|
32237
32662
|
// languages already flagged as unavailable
|
|
32238
32663
|
constructor(options = {}) {
|
|
32239
32664
|
this.cwd = options.cwd ?? process.cwd();
|
|
32240
|
-
this.spawnImpl = options.spawnImpl ??
|
|
32665
|
+
this.spawnImpl = options.spawnImpl ?? spawn6;
|
|
32241
32666
|
this.timeoutMs = options.timeoutMs ?? 15e3;
|
|
32242
32667
|
this.onWarn = options.onWarn ?? ((m) => console.error(m));
|
|
32243
32668
|
}
|
|
@@ -32401,6 +32826,14 @@ var init_manager = __esm({
|
|
|
32401
32826
|
null
|
|
32402
32827
|
);
|
|
32403
32828
|
}
|
|
32829
|
+
/** See LspProvider.serverStatusFor (WS4). Call AFTER a provider method:
|
|
32830
|
+
* the server entry is lazily created on first use, so the status is only
|
|
32831
|
+
* meaningful once the manager has served that language once. */
|
|
32832
|
+
serverStatusFor(file2) {
|
|
32833
|
+
const cmd = resolveServerCommand(file2, this.cwd);
|
|
32834
|
+
if (!cmd) return "unavailable";
|
|
32835
|
+
return this.servers.get(cmd.language) === null ? "unavailable" : "available";
|
|
32836
|
+
}
|
|
32404
32837
|
dispose() {
|
|
32405
32838
|
for (const entry of this.servers.values()) entry?.dispose();
|
|
32406
32839
|
this.servers.clear();
|
|
@@ -32420,31 +32853,69 @@ var init_manager = __esm({
|
|
|
32420
32853
|
|
|
32421
32854
|
// src/cli/ast/engine.ts
|
|
32422
32855
|
import { readFile } from "node:fs/promises";
|
|
32423
|
-
import
|
|
32424
|
-
function isAstSupported(file2) {
|
|
32425
|
-
return TS_EXTENSIONS.has(path22.extname(file2).toLowerCase());
|
|
32426
|
-
}
|
|
32856
|
+
import path24 from "node:path";
|
|
32427
32857
|
function loadTs() {
|
|
32428
32858
|
if (!tsPromise) {
|
|
32429
32859
|
tsPromise = import("typescript").then((m) => m.default ?? m).catch(() => null);
|
|
32430
32860
|
}
|
|
32431
32861
|
return tsPromise;
|
|
32432
32862
|
}
|
|
32433
|
-
|
|
32434
|
-
|
|
32863
|
+
function errMessage(err) {
|
|
32864
|
+
return err instanceof Error ? err.message : String(err);
|
|
32865
|
+
}
|
|
32866
|
+
async function parseFileSymbolsDiag(file2, cwd) {
|
|
32867
|
+
const resolvedPath = path24.isAbsolute(file2) ? file2 : path24.join(cwd ?? process.cwd(), file2);
|
|
32868
|
+
const extension = path24.extname(resolvedPath).toLowerCase();
|
|
32869
|
+
if (!TS_EXTENSIONS.has(extension)) {
|
|
32870
|
+
return {
|
|
32871
|
+
status: "unsupported-extension",
|
|
32872
|
+
extension: extension || "(none)",
|
|
32873
|
+
resolvedPath,
|
|
32874
|
+
recoverable: false,
|
|
32875
|
+
recommendedFallback: "read_file"
|
|
32876
|
+
};
|
|
32877
|
+
}
|
|
32435
32878
|
const ts = await loadTs();
|
|
32436
|
-
if (!ts)
|
|
32879
|
+
if (!ts) {
|
|
32880
|
+
return {
|
|
32881
|
+
status: "typescript-unavailable",
|
|
32882
|
+
resolvedPath,
|
|
32883
|
+
recoverable: true,
|
|
32884
|
+
recommendedFallback: "read_file"
|
|
32885
|
+
};
|
|
32886
|
+
}
|
|
32437
32887
|
let text;
|
|
32438
32888
|
try {
|
|
32439
|
-
text = await readFile(
|
|
32440
|
-
} catch {
|
|
32441
|
-
|
|
32889
|
+
text = await readFile(resolvedPath, "utf8");
|
|
32890
|
+
} catch (err) {
|
|
32891
|
+
const code = err?.code;
|
|
32892
|
+
if (code === "ENOENT") {
|
|
32893
|
+
return {
|
|
32894
|
+
status: "file-not-found",
|
|
32895
|
+
resolvedPath,
|
|
32896
|
+
recoverable: false,
|
|
32897
|
+
recommendedFallback: "grep_content"
|
|
32898
|
+
};
|
|
32899
|
+
}
|
|
32900
|
+
return {
|
|
32901
|
+
status: "read-error",
|
|
32902
|
+
resolvedPath,
|
|
32903
|
+
message: errMessage(err),
|
|
32904
|
+
recoverable: true,
|
|
32905
|
+
recommendedFallback: "read_file"
|
|
32906
|
+
};
|
|
32442
32907
|
}
|
|
32443
32908
|
let source;
|
|
32444
32909
|
try {
|
|
32445
|
-
source = ts.createSourceFile(
|
|
32446
|
-
} catch {
|
|
32447
|
-
return
|
|
32910
|
+
source = ts.createSourceFile(path24.basename(resolvedPath), text, ts.ScriptTarget.Latest, true);
|
|
32911
|
+
} catch (err) {
|
|
32912
|
+
return {
|
|
32913
|
+
status: "parse-error",
|
|
32914
|
+
resolvedPath,
|
|
32915
|
+
message: errMessage(err),
|
|
32916
|
+
recoverable: false,
|
|
32917
|
+
recommendedFallback: "read_file"
|
|
32918
|
+
};
|
|
32448
32919
|
}
|
|
32449
32920
|
const out = [];
|
|
32450
32921
|
const lineOf = (pos) => source.getLineAndCharacterOfPosition(pos).line + 1;
|
|
@@ -32490,15 +32961,7 @@ async function parseFileSymbols(file2) {
|
|
|
32490
32961
|
ts.forEachChild(node, visit);
|
|
32491
32962
|
};
|
|
32492
32963
|
visit(source);
|
|
32493
|
-
return out;
|
|
32494
|
-
}
|
|
32495
|
-
async function astOutline(file2) {
|
|
32496
|
-
const symbols = await parseFileSymbols(file2);
|
|
32497
|
-
return symbols.map(({ text: _text, ...rest }) => rest);
|
|
32498
|
-
}
|
|
32499
|
-
async function findSymbol(file2, name) {
|
|
32500
|
-
const symbols = await parseFileSymbols(file2);
|
|
32501
|
-
return symbols.find((s) => s.name === name) ?? null;
|
|
32964
|
+
return { status: "ok", symbols: out };
|
|
32502
32965
|
}
|
|
32503
32966
|
var TS_EXTENSIONS, tsPromise;
|
|
32504
32967
|
var init_engine2 = __esm({
|
|
@@ -32509,23 +32972,54 @@ var init_engine2 = __esm({
|
|
|
32509
32972
|
});
|
|
32510
32973
|
|
|
32511
32974
|
// src/cli/ast/tools.ts
|
|
32512
|
-
function
|
|
32975
|
+
function degradedPayload(r) {
|
|
32976
|
+
return {
|
|
32977
|
+
status: r.status,
|
|
32978
|
+
resolvedPath: r.resolvedPath,
|
|
32979
|
+
recoverable: r.recoverable,
|
|
32980
|
+
recommendedFallback: r.recommendedFallback
|
|
32981
|
+
};
|
|
32982
|
+
}
|
|
32983
|
+
function degradedNote2(r) {
|
|
32984
|
+
switch (r.status) {
|
|
32985
|
+
case "file-not-found":
|
|
32986
|
+
return `file not found \u2014 looked at ${r.resolvedPath} (relative paths resolve against the workspace root)`;
|
|
32987
|
+
case "typescript-unavailable":
|
|
32988
|
+
return 'TypeScript compiler API unavailable \u2014 the "typescript" package could not be loaded. AST tools need it; disable them with ZELARI_AST=0 or fall back to read_file/grep_content.';
|
|
32989
|
+
case "unsupported-extension":
|
|
32990
|
+
return `unsupported file extension "${r.extension}" \u2014 ast_outline/find_symbol only parse TS/JS files (.ts/.tsx/.js/.jsx/.mjs/.cjs)`;
|
|
32991
|
+
case "read-error":
|
|
32992
|
+
return `could not read ${r.resolvedPath}: ${r.message}`;
|
|
32993
|
+
case "parse-error":
|
|
32994
|
+
return `TypeScript failed to parse ${r.resolvedPath}: ${r.message}`;
|
|
32995
|
+
}
|
|
32996
|
+
}
|
|
32997
|
+
function createAstTools(root) {
|
|
32513
32998
|
const outline = {
|
|
32514
32999
|
name: "ast_outline",
|
|
32515
|
-
description: "Structural outline of a TS/JS file: every declaration (function, class, method, interface, type, enum, variable) with its line range and whether it's exported. Faster and more precise than reading the whole file to find where things are. TS/JS only.",
|
|
33000
|
+
description: "Structural outline of a TS/JS file: every declaration (function, class, method, interface, type, enum, variable) with its line range and whether it's exported. Faster and more precise than reading the whole file to find where things are. Relative paths resolve against the working directory. TS/JS only.",
|
|
32516
33001
|
permissions: ["read"],
|
|
32517
33002
|
inputSchema: external_exports.object({
|
|
32518
33003
|
path: external_exports.string().min(1).describe("Path to the TS/JS file to outline.")
|
|
32519
33004
|
}),
|
|
32520
|
-
execute: async (args) => {
|
|
33005
|
+
execute: async (args, ctx) => {
|
|
32521
33006
|
const { path: file2 } = args;
|
|
32522
|
-
const
|
|
32523
|
-
if (
|
|
32524
|
-
return typedOk({ symbols: [], note:
|
|
33007
|
+
const r = await parseFileSymbolsDiag(file2, ctx?.cwd ?? root);
|
|
33008
|
+
if (r.status !== "ok") {
|
|
33009
|
+
return typedOk({ symbols: [], note: degradedNote2(r), ...degradedPayload(r) });
|
|
33010
|
+
}
|
|
33011
|
+
if (r.symbols.length === 0) {
|
|
33012
|
+
return typedOk({
|
|
33013
|
+
status: "ok",
|
|
33014
|
+
count: 0,
|
|
33015
|
+
symbols: [],
|
|
33016
|
+
note: "file parsed successfully but contains no declarations"
|
|
33017
|
+
});
|
|
32525
33018
|
}
|
|
32526
33019
|
return typedOk({
|
|
32527
|
-
|
|
32528
|
-
|
|
33020
|
+
status: "ok",
|
|
33021
|
+
count: r.symbols.length,
|
|
33022
|
+
symbols: r.symbols.map(
|
|
32529
33023
|
(s) => `${s.exported ? "export " : ""}${s.kind} ${s.name} (lines ${s.line}-${s.endLine})`
|
|
32530
33024
|
)
|
|
32531
33025
|
});
|
|
@@ -32533,21 +33027,30 @@ function createAstTools() {
|
|
|
32533
33027
|
};
|
|
32534
33028
|
const findSymbolTool = {
|
|
32535
33029
|
name: "find_symbol",
|
|
32536
|
-
description: "Locate a named declaration in a TS/JS file and return its EXACT source text and line range. Use this to grab a function/class/method verbatim so you can edit_file it reliably (node-accurate) instead of guessing the surrounding text. TS/JS only.",
|
|
33030
|
+
description: "Locate a named declaration in a TS/JS file and return its EXACT source text and line range. Use this to grab a function/class/method verbatim so you can edit_file it reliably (node-accurate) instead of guessing the surrounding text. Relative paths resolve against the working directory. TS/JS only.",
|
|
32537
33031
|
permissions: ["read"],
|
|
32538
33032
|
inputSchema: external_exports.object({
|
|
32539
33033
|
path: external_exports.string().min(1).describe("Path to the TS/JS file."),
|
|
32540
33034
|
name: external_exports.string().min(1).describe("The declaration name to find (function/class/method/etc).")
|
|
32541
33035
|
}),
|
|
32542
|
-
execute: async (args) => {
|
|
33036
|
+
execute: async (args, ctx) => {
|
|
32543
33037
|
const { path: file2, name } = args;
|
|
32544
|
-
const
|
|
33038
|
+
const r = await parseFileSymbolsDiag(file2, ctx?.cwd ?? root);
|
|
33039
|
+
if (r.status !== "ok") {
|
|
33040
|
+
return typedOk({ found: false, note: degradedNote2(r), ...degradedPayload(r) });
|
|
33041
|
+
}
|
|
33042
|
+
const sym = r.symbols.find((s) => s.name === name);
|
|
32545
33043
|
if (!sym) {
|
|
32546
|
-
return typedOk({
|
|
33044
|
+
return typedOk({
|
|
33045
|
+
found: false,
|
|
33046
|
+
status: "ok",
|
|
33047
|
+
note: `no declaration named "${name}" found in ${r.symbols.length > 0 ? `${file2} (declarations present: ${[...new Set(r.symbols.map((s) => s.name))].slice(0, 12).join(", ")})` : file2}`
|
|
33048
|
+
});
|
|
32547
33049
|
}
|
|
32548
33050
|
const truncated = sym.text.length > MAX_TEXT_CHARS;
|
|
32549
33051
|
return typedOk({
|
|
32550
33052
|
found: true,
|
|
33053
|
+
status: "ok",
|
|
32551
33054
|
kind: sym.kind,
|
|
32552
33055
|
exported: sym.exported,
|
|
32553
33056
|
line: sym.line,
|
|
@@ -32627,13 +33130,13 @@ var init_store = __esm({
|
|
|
32627
33130
|
});
|
|
32628
33131
|
|
|
32629
33132
|
// src/cli/semantic/index.ts
|
|
32630
|
-
import { promises as
|
|
33133
|
+
import { promises as fs14, existsSync as existsSync21, readFileSync as readFileSync19 } from "node:fs";
|
|
32631
33134
|
import { homedir as homedir6 } from "node:os";
|
|
32632
|
-
import
|
|
32633
|
-
import { createHash as
|
|
33135
|
+
import path25 from "node:path";
|
|
33136
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
32634
33137
|
function getIndexPath(root) {
|
|
32635
|
-
const hash3 =
|
|
32636
|
-
return process.env.ZELARI_SEMANTIC_FILE ??
|
|
33138
|
+
const hash3 = createHash6("sha1").update(path25.resolve(root)).digest("hex").slice(0, 16);
|
|
33139
|
+
return process.env.ZELARI_SEMANTIC_FILE ?? path25.join(homedir6(), ".tmp", "zelari-code", "semantic", `${hash3}.json`);
|
|
32637
33140
|
}
|
|
32638
33141
|
async function collectSourceFiles(root, maxFiles = 1500) {
|
|
32639
33142
|
const out = [];
|
|
@@ -32641,7 +33144,7 @@ async function collectSourceFiles(root, maxFiles = 1500) {
|
|
|
32641
33144
|
if (out.length >= maxFiles) return;
|
|
32642
33145
|
let entries;
|
|
32643
33146
|
try {
|
|
32644
|
-
entries = await
|
|
33147
|
+
entries = await fs14.readdir(dir, { withFileTypes: true });
|
|
32645
33148
|
} catch {
|
|
32646
33149
|
return;
|
|
32647
33150
|
}
|
|
@@ -32651,11 +33154,11 @@ async function collectSourceFiles(root, maxFiles = 1500) {
|
|
|
32651
33154
|
if (entry.isDirectory() && IGNORE_DIRS.has(entry.name)) continue;
|
|
32652
33155
|
if (entry.isDirectory()) continue;
|
|
32653
33156
|
}
|
|
32654
|
-
const full =
|
|
33157
|
+
const full = path25.join(dir, entry.name);
|
|
32655
33158
|
if (entry.isDirectory()) {
|
|
32656
33159
|
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
32657
33160
|
await walk2(full);
|
|
32658
|
-
} else if (SOURCE_EXTENSIONS.has(
|
|
33161
|
+
} else if (SOURCE_EXTENSIONS.has(path25.extname(entry.name).toLowerCase())) {
|
|
32659
33162
|
out.push(full);
|
|
32660
33163
|
}
|
|
32661
33164
|
}
|
|
@@ -32671,7 +33174,7 @@ async function buildIndex(files, embed, options) {
|
|
|
32671
33174
|
for (const file2 of files) {
|
|
32672
33175
|
let text;
|
|
32673
33176
|
try {
|
|
32674
|
-
text = await
|
|
33177
|
+
text = await fs14.readFile(file2, "utf8");
|
|
32675
33178
|
} catch {
|
|
32676
33179
|
continue;
|
|
32677
33180
|
}
|
|
@@ -32704,14 +33207,14 @@ async function buildIndex(files, embed, options) {
|
|
|
32704
33207
|
}
|
|
32705
33208
|
async function saveIndex(root, data) {
|
|
32706
33209
|
const file2 = getIndexPath(root);
|
|
32707
|
-
await
|
|
33210
|
+
await fs14.mkdir(path25.dirname(file2), { recursive: true });
|
|
32708
33211
|
const tmp = `${file2}.tmp-${process.pid}`;
|
|
32709
|
-
await
|
|
32710
|
-
await
|
|
33212
|
+
await fs14.writeFile(tmp, JSON.stringify(data), "utf8");
|
|
33213
|
+
await fs14.rename(tmp, file2);
|
|
32711
33214
|
}
|
|
32712
33215
|
function loadIndex(root) {
|
|
32713
33216
|
const file2 = getIndexPath(root);
|
|
32714
|
-
if (!
|
|
33217
|
+
if (!existsSync21(file2)) return null;
|
|
32715
33218
|
try {
|
|
32716
33219
|
const parsed = JSON.parse(readFileSync19(file2, "utf8"));
|
|
32717
33220
|
if (parsed && Array.isArray(parsed.chunks)) return parsed;
|
|
@@ -32856,7 +33359,7 @@ var init_provider = __esm({
|
|
|
32856
33359
|
});
|
|
32857
33360
|
|
|
32858
33361
|
// src/cli/semantic/tools.ts
|
|
32859
|
-
import
|
|
33362
|
+
import path26 from "node:path";
|
|
32860
33363
|
function createSemanticTool(deps) {
|
|
32861
33364
|
const buildEmbedFn = deps.buildEmbedFn ?? buildProviderEmbedFn;
|
|
32862
33365
|
return {
|
|
@@ -32883,7 +33386,7 @@ function createSemanticTool(deps) {
|
|
|
32883
33386
|
return typedOk({
|
|
32884
33387
|
count: res.hits.length,
|
|
32885
33388
|
results: res.hits.map((h) => ({
|
|
32886
|
-
location: `${
|
|
33389
|
+
location: `${path26.relative(deps.root, h.file) || h.file}:${h.startLine}-${h.endLine}`,
|
|
32887
33390
|
score: Number(h.score.toFixed(3)),
|
|
32888
33391
|
preview: h.text.length > 400 ? `${h.text.slice(0, 400)}\u2026` : h.text
|
|
32889
33392
|
}))
|
|
@@ -32903,7 +33406,7 @@ var init_tools4 = __esm({
|
|
|
32903
33406
|
|
|
32904
33407
|
// src/cli/browser/driver.ts
|
|
32905
33408
|
import { createRequire } from "node:module";
|
|
32906
|
-
import
|
|
33409
|
+
import path27 from "node:path";
|
|
32907
33410
|
import { pathToFileURL } from "node:url";
|
|
32908
33411
|
function asPlaywright(mod) {
|
|
32909
33412
|
if (!mod || typeof mod !== "object") return null;
|
|
@@ -32914,10 +33417,10 @@ function asPlaywright(mod) {
|
|
|
32914
33417
|
return null;
|
|
32915
33418
|
}
|
|
32916
33419
|
async function loadPlaywright(cwd) {
|
|
32917
|
-
const base = cwd && cwd.length > 0 ?
|
|
33420
|
+
const base = cwd && cwd.length > 0 ? path27.resolve(cwd) : void 0;
|
|
32918
33421
|
if (base) {
|
|
32919
33422
|
try {
|
|
32920
|
-
const req = createRequire(
|
|
33423
|
+
const req = createRequire(path27.join(base, "package.json"));
|
|
32921
33424
|
const resolved = req.resolve("playwright");
|
|
32922
33425
|
const mod = await import(pathToFileURL(resolved).href);
|
|
32923
33426
|
const pw = asPlaywright(mod);
|
|
@@ -33132,8 +33635,8 @@ var init_driver = __esm({
|
|
|
33132
33635
|
});
|
|
33133
33636
|
|
|
33134
33637
|
// src/cli/browser/tools.ts
|
|
33135
|
-
import
|
|
33136
|
-
import
|
|
33638
|
+
import path28 from "node:path";
|
|
33639
|
+
import os9 from "node:os";
|
|
33137
33640
|
function createBrowserTool(deps = {}) {
|
|
33138
33641
|
return {
|
|
33139
33642
|
name: "browser_check",
|
|
@@ -33150,8 +33653,8 @@ function createBrowserTool(deps = {}) {
|
|
|
33150
33653
|
}),
|
|
33151
33654
|
execute: async (args, ctx) => {
|
|
33152
33655
|
const a = args;
|
|
33153
|
-
const dir = deps.screenshotDir ??
|
|
33154
|
-
const screenshotPath = a.screenshot === false ? void 0 :
|
|
33656
|
+
const dir = deps.screenshotDir ?? os9.tmpdir();
|
|
33657
|
+
const screenshotPath = a.screenshot === false ? void 0 : path28.join(dir, `zelari-browser-${Date.now()}.png`);
|
|
33155
33658
|
const result = await runBrowserCheck(
|
|
33156
33659
|
{
|
|
33157
33660
|
url: a.url,
|
|
@@ -33243,14 +33746,14 @@ __export(targets_exports, {
|
|
|
33243
33746
|
});
|
|
33244
33747
|
import {
|
|
33245
33748
|
chmodSync,
|
|
33246
|
-
existsSync as
|
|
33749
|
+
existsSync as existsSync22,
|
|
33247
33750
|
mkdirSync as mkdirSync13,
|
|
33248
33751
|
readFileSync as readFileSync20,
|
|
33249
33752
|
writeFileSync as writeFileSync15
|
|
33250
33753
|
} from "node:fs";
|
|
33251
33754
|
import { dirname as dirname4, join as join16 } from "node:path";
|
|
33252
33755
|
import { homedir as homedir7 } from "node:os";
|
|
33253
|
-
import { spawn as
|
|
33756
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
33254
33757
|
function getSshTargetsPath() {
|
|
33255
33758
|
return join16(homedir7(), ".zelari-code", "ssh-targets.json");
|
|
33256
33759
|
}
|
|
@@ -33263,21 +33766,21 @@ function normalizeAuth(auth) {
|
|
|
33263
33766
|
return "agent";
|
|
33264
33767
|
}
|
|
33265
33768
|
function readSecrets() {
|
|
33266
|
-
const
|
|
33267
|
-
if (!
|
|
33769
|
+
const path55 = getSshSecretsPath();
|
|
33770
|
+
if (!existsSync22(path55)) return {};
|
|
33268
33771
|
try {
|
|
33269
|
-
return JSON.parse(readFileSync20(
|
|
33772
|
+
return JSON.parse(readFileSync20(path55, "utf8"));
|
|
33270
33773
|
} catch {
|
|
33271
33774
|
return {};
|
|
33272
33775
|
}
|
|
33273
33776
|
}
|
|
33274
33777
|
function writeSecrets(data) {
|
|
33275
|
-
const
|
|
33276
|
-
mkdirSync13(dirname4(
|
|
33277
|
-
writeFileSync15(
|
|
33778
|
+
const path55 = getSshSecretsPath();
|
|
33779
|
+
mkdirSync13(dirname4(path55), { recursive: true });
|
|
33780
|
+
writeFileSync15(path55, `${JSON.stringify(data, null, 2)}
|
|
33278
33781
|
`, "utf8");
|
|
33279
33782
|
try {
|
|
33280
|
-
chmodSync(
|
|
33783
|
+
chmodSync(path55, 384);
|
|
33281
33784
|
} catch {
|
|
33282
33785
|
}
|
|
33283
33786
|
}
|
|
@@ -33306,10 +33809,10 @@ function deleteSshPassword(id) {
|
|
|
33306
33809
|
writeSecrets({ passwords });
|
|
33307
33810
|
}
|
|
33308
33811
|
function readStore2() {
|
|
33309
|
-
const
|
|
33310
|
-
if (!
|
|
33812
|
+
const path55 = getSshTargetsPath();
|
|
33813
|
+
if (!existsSync22(path55)) return [];
|
|
33311
33814
|
try {
|
|
33312
|
-
const parsed = JSON.parse(readFileSync20(
|
|
33815
|
+
const parsed = JSON.parse(readFileSync20(path55, "utf8"));
|
|
33313
33816
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
33314
33817
|
return list.filter(
|
|
33315
33818
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -33324,11 +33827,11 @@ function readStore2() {
|
|
|
33324
33827
|
}
|
|
33325
33828
|
}
|
|
33326
33829
|
function writeStore2(targets) {
|
|
33327
|
-
const
|
|
33328
|
-
mkdirSync13(dirname4(
|
|
33830
|
+
const path55 = getSshTargetsPath();
|
|
33831
|
+
mkdirSync13(dirname4(path55), { recursive: true });
|
|
33329
33832
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
33330
33833
|
writeFileSync15(
|
|
33331
|
-
|
|
33834
|
+
path55,
|
|
33332
33835
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
33333
33836
|
`,
|
|
33334
33837
|
"utf8"
|
|
@@ -33480,7 +33983,7 @@ function runSsh(target, remoteCommand, timeoutMs = 6e4) {
|
|
|
33480
33983
|
if (!env.DISPLAY) env.DISPLAY = "1";
|
|
33481
33984
|
env.ZELARI_SSH_ASKPASS_PASS = pass;
|
|
33482
33985
|
}
|
|
33483
|
-
const child =
|
|
33986
|
+
const child = spawn7("ssh", args, {
|
|
33484
33987
|
windowsHide: true,
|
|
33485
33988
|
env,
|
|
33486
33989
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -33521,7 +34024,7 @@ function readSshPublicKey(keyOrPubPath) {
|
|
|
33521
34024
|
if (!raw) return { ok: false, error: "Empty path" };
|
|
33522
34025
|
const candidates = raw.endsWith(".pub") ? [raw] : [`${raw}.pub`, raw];
|
|
33523
34026
|
for (const p3 of candidates) {
|
|
33524
|
-
if (!
|
|
34027
|
+
if (!existsSync22(p3)) continue;
|
|
33525
34028
|
try {
|
|
33526
34029
|
const content = readFileSync20(p3, "utf8").trim();
|
|
33527
34030
|
if (!content) continue;
|
|
@@ -33574,11 +34077,11 @@ function formatSshTargetsForPrompt() {
|
|
|
33574
34077
|
];
|
|
33575
34078
|
for (const t of targets) {
|
|
33576
34079
|
const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
|
|
33577
|
-
const
|
|
34080
|
+
const path55 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
|
|
33578
34081
|
const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
|
|
33579
34082
|
const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
|
|
33580
34083
|
lines.push(
|
|
33581
|
-
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${
|
|
34084
|
+
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path55}${tags}${allow}`
|
|
33582
34085
|
);
|
|
33583
34086
|
}
|
|
33584
34087
|
return lines.join("\n");
|
|
@@ -33704,26 +34207,26 @@ var init_tools6 = __esm({
|
|
|
33704
34207
|
});
|
|
33705
34208
|
|
|
33706
34209
|
// src/cli/workspace/worldModel.ts
|
|
33707
|
-
import { promises as
|
|
33708
|
-
import
|
|
33709
|
-
import { spawn as
|
|
34210
|
+
import { promises as fs15 } from "node:fs";
|
|
34211
|
+
import path29 from "node:path";
|
|
34212
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
33710
34213
|
function worldDir(cwd) {
|
|
33711
|
-
return
|
|
34214
|
+
return path29.join(cwd, WORLD_DIR_NAME);
|
|
33712
34215
|
}
|
|
33713
34216
|
async function ensureWorldDir(cwd) {
|
|
33714
34217
|
const dir = worldDir(cwd);
|
|
33715
|
-
await
|
|
34218
|
+
await fs15.mkdir(dir, { recursive: true });
|
|
33716
34219
|
return dir;
|
|
33717
34220
|
}
|
|
33718
34221
|
async function appendTimeline(cwd, entry) {
|
|
33719
34222
|
const dir = await ensureWorldDir(cwd);
|
|
33720
34223
|
const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
|
|
33721
|
-
await
|
|
34224
|
+
await fs15.appendFile(path29.join(dir, TIMELINE_FILE), line, "utf8");
|
|
33722
34225
|
}
|
|
33723
34226
|
async function readChecks(cwd) {
|
|
33724
|
-
const p3 =
|
|
34227
|
+
const p3 = path29.join(worldDir(cwd), CHECKS_FILE);
|
|
33725
34228
|
try {
|
|
33726
|
-
const raw = await
|
|
34229
|
+
const raw = await fs15.readFile(p3, "utf8");
|
|
33727
34230
|
const parsed = JSON.parse(raw);
|
|
33728
34231
|
return Array.isArray(parsed.checks) ? parsed.checks : [];
|
|
33729
34232
|
} catch {
|
|
@@ -33733,7 +34236,7 @@ async function readChecks(cwd) {
|
|
|
33733
34236
|
function runShell(command, cwd, timeoutMs, signal) {
|
|
33734
34237
|
return new Promise((resolve3) => {
|
|
33735
34238
|
const isWin = process.platform === "win32";
|
|
33736
|
-
const child =
|
|
34239
|
+
const child = spawn8(isWin ? "cmd.exe" : "/bin/sh", isWin ? ["/c", command] : ["-c", command], {
|
|
33737
34240
|
cwd,
|
|
33738
34241
|
env: process.env,
|
|
33739
34242
|
windowsHide: true,
|
|
@@ -33796,8 +34299,8 @@ function runShell(command, cwd, timeoutMs, signal) {
|
|
|
33796
34299
|
});
|
|
33797
34300
|
}
|
|
33798
34301
|
async function runBacktest(cwd, signal) {
|
|
33799
|
-
const checksPath =
|
|
33800
|
-
const hypothesisPath =
|
|
34302
|
+
const checksPath = path29.join(worldDir(cwd), CHECKS_FILE);
|
|
34303
|
+
const hypothesisPath = path29.join(worldDir(cwd), HYPOTHESIS_FILE);
|
|
33801
34304
|
const checks = await readChecks(cwd);
|
|
33802
34305
|
if (checks.length === 0) {
|
|
33803
34306
|
return {
|
|
@@ -33866,7 +34369,7 @@ var init_worldModel = __esm({
|
|
|
33866
34369
|
"use strict";
|
|
33867
34370
|
init_zod();
|
|
33868
34371
|
init_toolTypes();
|
|
33869
|
-
WORLD_DIR_NAME =
|
|
34372
|
+
WORLD_DIR_NAME = path29.join(".zelari", "world");
|
|
33870
34373
|
HYPOTHESIS_FILE = "hypothesis.md";
|
|
33871
34374
|
CHECKS_FILE = "checks.json";
|
|
33872
34375
|
TIMELINE_FILE = "timeline.jsonl";
|
|
@@ -33883,7 +34386,7 @@ var init_worldModel = __esm({
|
|
|
33883
34386
|
execute: async (args, ctx) => {
|
|
33884
34387
|
try {
|
|
33885
34388
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
33886
|
-
const file2 =
|
|
34389
|
+
const file2 = path29.join(dir, HYPOTHESIS_FILE);
|
|
33887
34390
|
if (args.append) {
|
|
33888
34391
|
const block = `
|
|
33889
34392
|
|
|
@@ -33891,11 +34394,11 @@ var init_worldModel = __esm({
|
|
|
33891
34394
|
|
|
33892
34395
|
${args.content}
|
|
33893
34396
|
`;
|
|
33894
|
-
await
|
|
34397
|
+
await fs15.appendFile(file2, block, "utf8");
|
|
33895
34398
|
} else {
|
|
33896
|
-
await
|
|
34399
|
+
await fs15.writeFile(file2, args.content, "utf8");
|
|
33897
34400
|
}
|
|
33898
|
-
const st = await
|
|
34401
|
+
const st = await fs15.stat(file2);
|
|
33899
34402
|
await appendTimeline(ctx.cwd, { kind: "hypothesis_update", bytes: st.size, append: !!args.append });
|
|
33900
34403
|
return typedOk({ path: file2, bytes: st.size });
|
|
33901
34404
|
} catch (err) {
|
|
@@ -33922,9 +34425,9 @@ ${args.content}
|
|
|
33922
34425
|
execute: async (args, ctx) => {
|
|
33923
34426
|
try {
|
|
33924
34427
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
33925
|
-
const file2 =
|
|
34428
|
+
const file2 = path29.join(dir, CHECKS_FILE);
|
|
33926
34429
|
const body = { checks: args.checks };
|
|
33927
|
-
await
|
|
34430
|
+
await fs15.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
|
|
33928
34431
|
await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
|
|
33929
34432
|
return typedOk({ path: file2, count: args.checks.length });
|
|
33930
34433
|
} catch (err) {
|
|
@@ -33961,8 +34464,8 @@ ${args.content}
|
|
|
33961
34464
|
stdoutPreview: "(dryRun)",
|
|
33962
34465
|
mismatch: "dryRun"
|
|
33963
34466
|
})),
|
|
33964
|
-
hypothesisPath:
|
|
33965
|
-
checksPath:
|
|
34467
|
+
hypothesisPath: path29.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
|
|
34468
|
+
checksPath: path29.join(worldDir(ctx.cwd), CHECKS_FILE)
|
|
33966
34469
|
});
|
|
33967
34470
|
}
|
|
33968
34471
|
const result = await runBacktest(ctx.cwd, ctx.signal);
|
|
@@ -33986,7 +34489,7 @@ ${args.content}
|
|
|
33986
34489
|
execute: async (args, ctx) => {
|
|
33987
34490
|
try {
|
|
33988
34491
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
33989
|
-
const file2 =
|
|
34492
|
+
const file2 = path29.join(dir, TIMELINE_FILE);
|
|
33990
34493
|
await appendTimeline(ctx.cwd, {
|
|
33991
34494
|
kind: args.kind,
|
|
33992
34495
|
summary: args.summary,
|
|
@@ -34094,13 +34597,13 @@ __export(folderTrust_exports, {
|
|
|
34094
34597
|
untrustFolder: () => untrustFolder
|
|
34095
34598
|
});
|
|
34096
34599
|
import { homedir as homedir8 } from "node:os";
|
|
34097
|
-
import { existsSync as
|
|
34098
|
-
import
|
|
34600
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync14, readFileSync as readFileSync21, writeFileSync as writeFileSync16 } from "node:fs";
|
|
34601
|
+
import path30 from "node:path";
|
|
34099
34602
|
function trustStorePath() {
|
|
34100
|
-
return _overrideStorePath ??
|
|
34603
|
+
return _overrideStorePath ?? path30.join(homedir8(), ".zelari-code", "trust.json");
|
|
34101
34604
|
}
|
|
34102
34605
|
function normalize(p3) {
|
|
34103
|
-
const resolved =
|
|
34606
|
+
const resolved = path30.resolve(p3);
|
|
34104
34607
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
34105
34608
|
}
|
|
34106
34609
|
function readStore3() {
|
|
@@ -34116,7 +34619,7 @@ function readStore3() {
|
|
|
34116
34619
|
function writeStore3(store4) {
|
|
34117
34620
|
const p3 = trustStorePath();
|
|
34118
34621
|
try {
|
|
34119
|
-
mkdirSync14(
|
|
34622
|
+
mkdirSync14(path30.dirname(p3), { recursive: true });
|
|
34120
34623
|
writeFileSync16(p3, JSON.stringify(store4, null, 2), "utf8");
|
|
34121
34624
|
} catch (err) {
|
|
34122
34625
|
throw new Error(
|
|
@@ -34142,7 +34645,7 @@ function isFolderTrusted(folderPath) {
|
|
|
34142
34645
|
}
|
|
34143
34646
|
function trustFolder(folderPath) {
|
|
34144
34647
|
const store4 = readStore3();
|
|
34145
|
-
const normalized =
|
|
34648
|
+
const normalized = path30.resolve(folderPath);
|
|
34146
34649
|
if (!store4.folders.some((f) => normalize(f.path) === normalize(normalized))) {
|
|
34147
34650
|
store4.folders.push({ path: normalized, trustedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
34148
34651
|
writeStore3(store4);
|
|
@@ -34172,7 +34675,7 @@ function getTrustStorePath() {
|
|
|
34172
34675
|
return trustStorePath();
|
|
34173
34676
|
}
|
|
34174
34677
|
function hasTrustStore() {
|
|
34175
|
-
return
|
|
34678
|
+
return existsSync23(trustStorePath());
|
|
34176
34679
|
}
|
|
34177
34680
|
function _setTrustStorePathForTests(p3) {
|
|
34178
34681
|
_overrideStorePath = p3;
|
|
@@ -34256,9 +34759,9 @@ var init_lifecycleHooks = __esm({
|
|
|
34256
34759
|
});
|
|
34257
34760
|
|
|
34258
34761
|
// src/cli/toolResultCache.ts
|
|
34259
|
-
import { createHash as
|
|
34260
|
-
import { promises as
|
|
34261
|
-
import
|
|
34762
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
34763
|
+
import { promises as fs16 } from "node:fs";
|
|
34764
|
+
import path31 from "node:path";
|
|
34262
34765
|
function isToolCacheEnabled() {
|
|
34263
34766
|
const raw = process.env.ZELARI_TOOL_CACHE;
|
|
34264
34767
|
return raw !== "0" && raw !== "false" && raw !== "off";
|
|
@@ -34269,7 +34772,7 @@ function resolveToolCacheTtlMs() {
|
|
|
34269
34772
|
return Number.isFinite(n) && n >= 0 ? n : TOOL_CACHE_DEFAULT_TTL_MS;
|
|
34270
34773
|
}
|
|
34271
34774
|
function hashKey(parts) {
|
|
34272
|
-
return
|
|
34775
|
+
return createHash7("sha256").update(JSON.stringify(parts), "utf8").digest("hex");
|
|
34273
34776
|
}
|
|
34274
34777
|
function resultBytes(result) {
|
|
34275
34778
|
try {
|
|
@@ -34343,9 +34846,9 @@ async function statKey(toolName, input, ctx) {
|
|
|
34343
34846
|
if (!input || typeof input !== "object") return null;
|
|
34344
34847
|
const rawPath = input.path;
|
|
34345
34848
|
if (typeof rawPath !== "string" || rawPath.length === 0) return null;
|
|
34346
|
-
const abs =
|
|
34849
|
+
const abs = path31.isAbsolute(rawPath) ? rawPath : path31.join(ctx.cwd, rawPath);
|
|
34347
34850
|
try {
|
|
34348
|
-
const st = await
|
|
34851
|
+
const st = await fs16.stat(abs);
|
|
34349
34852
|
return hashKey({
|
|
34350
34853
|
tool: toolName,
|
|
34351
34854
|
args: input,
|
|
@@ -34584,8 +35087,17 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
34584
35087
|
description: t.description,
|
|
34585
35088
|
permissions: t.permissions ?? []
|
|
34586
35089
|
}));
|
|
35090
|
+
if (readOnly && process.env.ZELARI_INSPECT_COMMAND !== "0") {
|
|
35091
|
+
const inspectTool = createInspectCommandTool(root);
|
|
35092
|
+
registry4.register(withPerm(inspectTool));
|
|
35093
|
+
tools.push({
|
|
35094
|
+
name: inspectTool.name,
|
|
35095
|
+
description: inspectTool.description,
|
|
35096
|
+
permissions: inspectTool.permissions ?? []
|
|
35097
|
+
});
|
|
35098
|
+
}
|
|
34587
35099
|
if (process.env.ZELARI_AST !== "0") {
|
|
34588
|
-
for (const t of createAstTools()) {
|
|
35100
|
+
for (const t of createAstTools(root)) {
|
|
34589
35101
|
registry4.register(t);
|
|
34590
35102
|
tools.push({ name: t.name, description: t.description, permissions: t.permissions ?? [] });
|
|
34591
35103
|
}
|
|
@@ -34641,7 +35153,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
34641
35153
|
permissions: taskTool.permissions ?? []
|
|
34642
35154
|
});
|
|
34643
35155
|
}
|
|
34644
|
-
if (
|
|
35156
|
+
if (process.env.ZELARI_LSP !== "0" && options.lspProvider !== null) {
|
|
34645
35157
|
const lspTools = options.lspProvider ? createLspTools(options.lspProvider, root) : createLspTools(getSharedLspManager(root), root);
|
|
34646
35158
|
for (const t of lspTools) {
|
|
34647
35159
|
registry4.register(t);
|
|
@@ -34927,6 +35439,7 @@ var init_toolRegistry = __esm({
|
|
|
34927
35439
|
init_skillTool();
|
|
34928
35440
|
init_todoTools();
|
|
34929
35441
|
init_planTaskTools();
|
|
35442
|
+
init_inspectCommand();
|
|
34930
35443
|
init_tools2();
|
|
34931
35444
|
init_manager();
|
|
34932
35445
|
init_tools3();
|
|
@@ -34957,21 +35470,21 @@ var init_toolRegistry = __esm({
|
|
|
34957
35470
|
});
|
|
34958
35471
|
|
|
34959
35472
|
// src/cli/state/fileStateStore.ts
|
|
34960
|
-
import { createHash as
|
|
34961
|
-
import { promises as
|
|
34962
|
-
import * as
|
|
35473
|
+
import { createHash as createHash8, randomUUID as randomUUID2 } from "node:crypto";
|
|
35474
|
+
import { promises as fs17 } from "node:fs";
|
|
35475
|
+
import * as path32 from "node:path";
|
|
34963
35476
|
function shortId() {
|
|
34964
35477
|
return randomUUID2().replace(/-/g, "").slice(0, 12);
|
|
34965
35478
|
}
|
|
34966
35479
|
async function writeJsonAtomic(filePath, data) {
|
|
34967
|
-
await
|
|
35480
|
+
await fs17.mkdir(path32.dirname(filePath), { recursive: true });
|
|
34968
35481
|
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
34969
|
-
await
|
|
34970
|
-
await
|
|
35482
|
+
await fs17.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
35483
|
+
await fs17.rename(tmp, filePath);
|
|
34971
35484
|
}
|
|
34972
35485
|
async function readJsonFile(filePath) {
|
|
34973
35486
|
try {
|
|
34974
|
-
const raw = await
|
|
35487
|
+
const raw = await fs17.readFile(filePath, "utf8");
|
|
34975
35488
|
return JSON.parse(raw);
|
|
34976
35489
|
} catch {
|
|
34977
35490
|
return null;
|
|
@@ -35009,7 +35522,7 @@ async function getStateStore(projectRoot, env = process.env) {
|
|
|
35009
35522
|
}
|
|
35010
35523
|
}
|
|
35011
35524
|
function hashStablePrompt(stable) {
|
|
35012
|
-
return
|
|
35525
|
+
return createHash8("sha256").update(stable, "utf8").digest("hex").slice(0, 16);
|
|
35013
35526
|
}
|
|
35014
35527
|
var DEFAULT_MATERIALIZE_CHARS, FileDurableStateStore, NoopDurableStateStore;
|
|
35015
35528
|
var init_fileStateStore = __esm({
|
|
@@ -35025,13 +35538,13 @@ var init_fileStateStore = __esm({
|
|
|
35025
35538
|
indexPath = "";
|
|
35026
35539
|
async init(projectRoot) {
|
|
35027
35540
|
this.root = projectRoot;
|
|
35028
|
-
this.stateDir =
|
|
35029
|
-
this.commitsDir =
|
|
35030
|
-
this.artifactsDir =
|
|
35031
|
-
this.headPath =
|
|
35032
|
-
this.indexPath =
|
|
35033
|
-
await
|
|
35034
|
-
await
|
|
35541
|
+
this.stateDir = path32.join(projectRoot, ".zelari", "state");
|
|
35542
|
+
this.commitsDir = path32.join(this.stateDir, "commits");
|
|
35543
|
+
this.artifactsDir = path32.join(this.stateDir, "artifacts");
|
|
35544
|
+
this.headPath = path32.join(this.stateDir, "HEAD.json");
|
|
35545
|
+
this.indexPath = path32.join(this.stateDir, "index.jsonl");
|
|
35546
|
+
await fs17.mkdir(this.commitsDir, { recursive: true });
|
|
35547
|
+
await fs17.mkdir(this.artifactsDir, { recursive: true });
|
|
35035
35548
|
}
|
|
35036
35549
|
async commit(input) {
|
|
35037
35550
|
if (!input.force && input.verification.ran && !input.verification.ok) {
|
|
@@ -35042,13 +35555,13 @@ var init_fileStateStore = __esm({
|
|
|
35042
35555
|
const discoveries = input.discoveries ?? [];
|
|
35043
35556
|
const parent = await this.head();
|
|
35044
35557
|
const id = shortId();
|
|
35045
|
-
const artifactRel =
|
|
35046
|
-
const artifactAbs =
|
|
35047
|
-
await
|
|
35558
|
+
const artifactRel = path32.join("artifacts", id);
|
|
35559
|
+
const artifactAbs = path32.join(this.artifactsDir, id);
|
|
35560
|
+
await fs17.mkdir(artifactAbs, { recursive: true });
|
|
35048
35561
|
const summary = defaultSummary(input, discoveries);
|
|
35049
|
-
await
|
|
35050
|
-
await writeJsonAtomic(
|
|
35051
|
-
await writeJsonAtomic(
|
|
35562
|
+
await fs17.writeFile(path32.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
|
|
35563
|
+
await writeJsonAtomic(path32.join(artifactAbs, "discoveries.json"), discoveries);
|
|
35564
|
+
await writeJsonAtomic(path32.join(artifactAbs, "verification.json"), input.verification);
|
|
35052
35565
|
const meta3 = {
|
|
35053
35566
|
id,
|
|
35054
35567
|
parentId: parent?.id ?? null,
|
|
@@ -35060,16 +35573,16 @@ var init_fileStateStore = __esm({
|
|
|
35060
35573
|
workspaceCheckpointId: input.workspaceCheckpointId,
|
|
35061
35574
|
verification: {
|
|
35062
35575
|
...input.verification,
|
|
35063
|
-
reportPath: input.verification.reportPath ??
|
|
35576
|
+
reportPath: input.verification.reportPath ?? path32.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
|
|
35064
35577
|
},
|
|
35065
35578
|
changedPaths: input.changedPaths ?? [],
|
|
35066
35579
|
stablePromptHash: input.stablePromptHash,
|
|
35067
35580
|
discoveryCount: discoveries.length,
|
|
35068
35581
|
artifactDir: artifactRel.replace(/\\/g, "/")
|
|
35069
35582
|
};
|
|
35070
|
-
await writeJsonAtomic(
|
|
35583
|
+
await writeJsonAtomic(path32.join(this.commitsDir, `${id}.json`), meta3);
|
|
35071
35584
|
await writeJsonAtomic(this.headPath, { id, updatedAt: meta3.createdAt });
|
|
35072
|
-
await
|
|
35585
|
+
await fs17.appendFile(this.indexPath, JSON.stringify({ id, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
|
|
35073
35586
|
return stripStored(meta3);
|
|
35074
35587
|
}
|
|
35075
35588
|
async head() {
|
|
@@ -35078,13 +35591,13 @@ var init_fileStateStore = __esm({
|
|
|
35078
35591
|
return this.get(head.id);
|
|
35079
35592
|
}
|
|
35080
35593
|
async get(id) {
|
|
35081
|
-
const stored = await readJsonFile(
|
|
35594
|
+
const stored = await readJsonFile(path32.join(this.commitsDir, `${id}.json`));
|
|
35082
35595
|
return stored ? stripStored(stored) : null;
|
|
35083
35596
|
}
|
|
35084
35597
|
async list(limit = 20) {
|
|
35085
35598
|
let raw;
|
|
35086
35599
|
try {
|
|
35087
|
-
raw = await
|
|
35600
|
+
raw = await fs17.readFile(this.indexPath, "utf8");
|
|
35088
35601
|
} catch {
|
|
35089
35602
|
return [];
|
|
35090
35603
|
}
|
|
@@ -35117,9 +35630,9 @@ var init_fileStateStore = __esm({
|
|
|
35117
35630
|
async loadDiscoveries(id) {
|
|
35118
35631
|
const meta3 = id ? await this.get(id) : await this.head();
|
|
35119
35632
|
if (!meta3) return [];
|
|
35120
|
-
const stored = await readJsonFile(
|
|
35633
|
+
const stored = await readJsonFile(path32.join(this.commitsDir, `${meta3.id}.json`));
|
|
35121
35634
|
if (!stored?.artifactDir) return [];
|
|
35122
|
-
const discPath =
|
|
35635
|
+
const discPath = path32.join(this.stateDir, stored.artifactDir, "discoveries.json");
|
|
35123
35636
|
return await readJsonFile(discPath) ?? [];
|
|
35124
35637
|
}
|
|
35125
35638
|
async materializeContext(id, maxChars = DEFAULT_MATERIALIZE_CHARS) {
|
|
@@ -35722,7 +36235,7 @@ __export(conversationContext_exports, {
|
|
|
35722
36235
|
setHistory: () => setHistory,
|
|
35723
36236
|
setLastClarification: () => setLastClarification
|
|
35724
36237
|
});
|
|
35725
|
-
import { existsSync as
|
|
36238
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
35726
36239
|
import { join as join19 } from "node:path";
|
|
35727
36240
|
function getHistory() {
|
|
35728
36241
|
return history;
|
|
@@ -35731,7 +36244,7 @@ function setHistory(messages) {
|
|
|
35731
36244
|
history = [...messages];
|
|
35732
36245
|
}
|
|
35733
36246
|
function compactInPlace(cwd = process.cwd()) {
|
|
35734
|
-
const durableStatePresent =
|
|
36247
|
+
const durableStatePresent = existsSync24(join19(cwd, ".zelari", "state", "HEAD.json"));
|
|
35735
36248
|
history = compactHistory(history, { durableStatePresent });
|
|
35736
36249
|
}
|
|
35737
36250
|
function appendMessages(msgs) {
|
|
@@ -36122,7 +36635,7 @@ var claudeProvider_exports = {};
|
|
|
36122
36635
|
__export(claudeProvider_exports, {
|
|
36123
36636
|
createLocalCliProvider: () => createLocalCliProvider
|
|
36124
36637
|
});
|
|
36125
|
-
import { spawn as
|
|
36638
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
36126
36639
|
function waitForExit(child, timeoutMs = 2e3) {
|
|
36127
36640
|
return new Promise((resolve3) => {
|
|
36128
36641
|
if (child.exitCode != null) return resolve3(child.exitCode);
|
|
@@ -36151,7 +36664,7 @@ function createLocalCliProvider(opts = {}) {
|
|
|
36151
36664
|
);
|
|
36152
36665
|
}
|
|
36153
36666
|
}
|
|
36154
|
-
const spawnFn = opts.spawnFn ??
|
|
36667
|
+
const spawnFn = opts.spawnFn ?? spawn9;
|
|
36155
36668
|
let child;
|
|
36156
36669
|
try {
|
|
36157
36670
|
child = spawnFn(cli, args, {
|
|
@@ -36246,12 +36759,12 @@ var init_claudeProvider = __esm({
|
|
|
36246
36759
|
});
|
|
36247
36760
|
|
|
36248
36761
|
// src/cli/workspace/projectInstructions.ts
|
|
36249
|
-
import { existsSync as
|
|
36762
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22 } from "node:fs";
|
|
36250
36763
|
import { join as join20 } from "node:path";
|
|
36251
36764
|
function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
|
|
36252
36765
|
for (const name of CANDIDATES) {
|
|
36253
36766
|
const full = join20(projectRoot, name);
|
|
36254
|
-
if (!
|
|
36767
|
+
if (!existsSync25(full)) continue;
|
|
36255
36768
|
try {
|
|
36256
36769
|
let raw = readFileSync22(full, "utf8");
|
|
36257
36770
|
raw = raw.replace(/\r\n/g, "\n").trim();
|
|
@@ -36297,7 +36810,7 @@ __export(workspaceSummary_exports, {
|
|
|
36297
36810
|
buildWorkspaceSummary: () => buildWorkspaceSummary,
|
|
36298
36811
|
buildZelariReadHint: () => buildZelariReadHint
|
|
36299
36812
|
});
|
|
36300
|
-
import { existsSync as
|
|
36813
|
+
import { existsSync as existsSync26, readFileSync as readFileSync23, readdirSync as readdirSync6, statSync as statSync4 } from "node:fs";
|
|
36301
36814
|
import { join as join21, relative } from "node:path";
|
|
36302
36815
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
36303
36816
|
const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
|
|
@@ -36332,7 +36845,7 @@ function formatTaskLine(t) {
|
|
|
36332
36845
|
function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
36333
36846
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
36334
36847
|
const planPath = join21(zelariRoot, "plan.json");
|
|
36335
|
-
if (!
|
|
36848
|
+
if (!existsSync26(planPath)) return null;
|
|
36336
36849
|
let plan;
|
|
36337
36850
|
try {
|
|
36338
36851
|
plan = JSON.parse(readFileSync23(planPath, "utf8"));
|
|
@@ -36475,7 +36988,7 @@ function pickNextTask(open) {
|
|
|
36475
36988
|
}
|
|
36476
36989
|
function buildZelariReadHint(projectRoot = process.cwd()) {
|
|
36477
36990
|
const planPath = join21(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
36478
|
-
if (!
|
|
36991
|
+
if (!existsSync26(planPath)) return "";
|
|
36479
36992
|
return [
|
|
36480
36993
|
"# Council workspace detected (.zelari/) \u2014 DRAFT vault",
|
|
36481
36994
|
"`.zelari/plan.json` and `.zelari/docs/` hold **design hypotheses**, not verified product state.",
|
|
@@ -36491,7 +37004,7 @@ function safeProjectName(root) {
|
|
|
36491
37004
|
}
|
|
36492
37005
|
function readPackageJson(projectRoot) {
|
|
36493
37006
|
const p3 = join21(projectRoot, "package.json");
|
|
36494
|
-
if (!
|
|
37007
|
+
if (!existsSync26(p3)) return null;
|
|
36495
37008
|
try {
|
|
36496
37009
|
return JSON.parse(readFileSync23(p3, "utf8"));
|
|
36497
37010
|
} catch {
|
|
@@ -36595,12 +37108,12 @@ var init_workspaceSummary = __esm({
|
|
|
36595
37108
|
});
|
|
36596
37109
|
|
|
36597
37110
|
// src/cli/workspace/buildLessonsSummary.ts
|
|
36598
|
-
import { existsSync as
|
|
37111
|
+
import { existsSync as existsSync27 } from "node:fs";
|
|
36599
37112
|
import { join as join22 } from "node:path";
|
|
36600
37113
|
function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
|
|
36601
37114
|
if (process.env["ZELARI_LESSONS"] === "0") return null;
|
|
36602
37115
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
36603
|
-
if (!
|
|
37116
|
+
if (!existsSync27(join22(zelariRoot, "lessons.jsonl"))) return null;
|
|
36604
37117
|
const lessons = recallLessons(zelariRoot, {
|
|
36605
37118
|
maxLessons: 5,
|
|
36606
37119
|
maxBytes: 2048,
|
|
@@ -36621,7 +37134,7 @@ var composeContext_exports = {};
|
|
|
36621
37134
|
__export(composeContext_exports, {
|
|
36622
37135
|
composeProjectContext: () => composeProjectContext
|
|
36623
37136
|
});
|
|
36624
|
-
import { existsSync as
|
|
37137
|
+
import { existsSync as existsSync28, readdirSync as readdirSync7, readFileSync as readFileSync24 } from "node:fs";
|
|
36625
37138
|
import { join as join23 } from "node:path";
|
|
36626
37139
|
function cap2(text, max, label) {
|
|
36627
37140
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
@@ -36634,13 +37147,13 @@ function cap2(text, max, label) {
|
|
|
36634
37147
|
}
|
|
36635
37148
|
function buildDesignIndex(projectRoot, maxChars) {
|
|
36636
37149
|
const root = resolveWorkspaceRoot(projectRoot);
|
|
36637
|
-
if (!
|
|
37150
|
+
if (!existsSync28(root)) return "";
|
|
36638
37151
|
const lines = [
|
|
36639
37152
|
"# Design vault index (.zelari/) \u2014 HYPOTHESES only",
|
|
36640
37153
|
"Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
|
|
36641
37154
|
];
|
|
36642
37155
|
const docsDir = join23(root, "docs");
|
|
36643
|
-
if (
|
|
37156
|
+
if (existsSync28(docsDir)) {
|
|
36644
37157
|
try {
|
|
36645
37158
|
const docs = readdirSync7(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
|
|
36646
37159
|
if (docs.length > 0) {
|
|
@@ -36654,12 +37167,12 @@ function buildDesignIndex(projectRoot, maxChars) {
|
|
|
36654
37167
|
}
|
|
36655
37168
|
}
|
|
36656
37169
|
for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
|
|
36657
|
-
if (
|
|
37170
|
+
if (existsSync28(join23(root, name))) {
|
|
36658
37171
|
lines.push(`- .zelari/${name} present`);
|
|
36659
37172
|
}
|
|
36660
37173
|
}
|
|
36661
37174
|
const decisionsDir = join23(root, "decisions");
|
|
36662
|
-
if (
|
|
37175
|
+
if (existsSync28(decisionsDir)) {
|
|
36663
37176
|
try {
|
|
36664
37177
|
const n = readdirSync7(decisionsDir).filter((f) => f.endsWith(".md")).length;
|
|
36665
37178
|
if (n > 0) lines.push(`- .zelari/decisions/ (${n} ADR file(s) \u2014 treat proposed as non-binding)`);
|
|
@@ -36761,15 +37274,15 @@ function composeProjectContext(input) {
|
|
|
36761
37274
|
function readDurableHeadSync(projectRoot) {
|
|
36762
37275
|
try {
|
|
36763
37276
|
const headPath = join23(projectRoot, ".zelari", "state", "HEAD.json");
|
|
36764
|
-
if (!
|
|
37277
|
+
if (!existsSync28(headPath)) return "";
|
|
36765
37278
|
const head = JSON.parse(readFileSync24(headPath, "utf8"));
|
|
36766
37279
|
if (!head?.id) return "";
|
|
36767
37280
|
const metaPath = join23(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
|
|
36768
|
-
if (!
|
|
37281
|
+
if (!existsSync28(metaPath)) return "";
|
|
36769
37282
|
const meta3 = JSON.parse(readFileSync24(metaPath, "utf8"));
|
|
36770
37283
|
const discPath = meta3.artifactDir ? join23(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join23(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
|
|
36771
37284
|
let discoveries = [];
|
|
36772
|
-
if (
|
|
37285
|
+
if (existsSync28(discPath)) {
|
|
36773
37286
|
discoveries = JSON.parse(readFileSync24(discPath, "utf8"));
|
|
36774
37287
|
}
|
|
36775
37288
|
const reusable = discoveries.filter((d) => d.reusable !== false);
|
|
@@ -36803,11 +37316,11 @@ var planDetect_exports = {};
|
|
|
36803
37316
|
__export(planDetect_exports, {
|
|
36804
37317
|
hasWorkspacePlan: () => hasWorkspacePlan
|
|
36805
37318
|
});
|
|
36806
|
-
import { existsSync as
|
|
37319
|
+
import { existsSync as existsSync29, readFileSync as readFileSync25 } from "node:fs";
|
|
36807
37320
|
import { join as join24 } from "node:path";
|
|
36808
37321
|
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
36809
37322
|
const planPath = join24(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
36810
|
-
if (!
|
|
37323
|
+
if (!existsSync29(planPath)) return false;
|
|
36811
37324
|
try {
|
|
36812
37325
|
const parsed = JSON.parse(readFileSync25(planPath, "utf8"));
|
|
36813
37326
|
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
@@ -36868,7 +37381,7 @@ __export(stubs_exports, {
|
|
|
36868
37381
|
resolveWorkspaceRoot: () => resolveWorkspaceRoot
|
|
36869
37382
|
});
|
|
36870
37383
|
import {
|
|
36871
|
-
existsSync as
|
|
37384
|
+
existsSync as existsSync30,
|
|
36872
37385
|
readdirSync as readdirSync8,
|
|
36873
37386
|
writeFileSync as writeFileSync17,
|
|
36874
37387
|
readFileSync as readFileSync26,
|
|
@@ -36889,7 +37402,7 @@ function planJsonPath(ctx) {
|
|
|
36889
37402
|
}
|
|
36890
37403
|
function readPlan(ctx) {
|
|
36891
37404
|
const jsonPath = planJsonPath(ctx);
|
|
36892
|
-
if (
|
|
37405
|
+
if (existsSync30(jsonPath)) {
|
|
36893
37406
|
try {
|
|
36894
37407
|
const parsed = JSON.parse(
|
|
36895
37408
|
readFileSync26(jsonPath, "utf8")
|
|
@@ -36904,8 +37417,8 @@ function readPlan(ctx) {
|
|
|
36904
37417
|
} catch {
|
|
36905
37418
|
}
|
|
36906
37419
|
}
|
|
36907
|
-
const
|
|
36908
|
-
const doc = ctx.storage.readIfExists(
|
|
37420
|
+
const path55 = workspaceFile(ctx.rootDir, "plan");
|
|
37421
|
+
const doc = ctx.storage.readIfExists(path55);
|
|
36909
37422
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
36910
37423
|
const meta3 = doc.meta;
|
|
36911
37424
|
return {
|
|
@@ -36999,7 +37512,7 @@ function renderPlanBody(summary) {
|
|
|
36999
37512
|
}
|
|
37000
37513
|
function nextAdrId(ctx) {
|
|
37001
37514
|
const decisionsDir = join25(ctx.rootDir, "decisions");
|
|
37002
|
-
if (!
|
|
37515
|
+
if (!existsSync30(decisionsDir)) return "001";
|
|
37003
37516
|
const existing = readdirSync8(decisionsDir).filter((f) => f.endsWith(".md")).map((f) => f.match(/^(\d+)-/)).filter((m) => !!m).map((m) => parseInt(m[1], 10));
|
|
37004
37517
|
const max = existing.length === 0 ? 0 : Math.max(...existing);
|
|
37005
37518
|
return String(max + 1).padStart(3, "0");
|
|
@@ -37083,7 +37596,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
37083
37596
|
dueDate: input.dueDate,
|
|
37084
37597
|
targetVersion: version2
|
|
37085
37598
|
});
|
|
37086
|
-
const
|
|
37599
|
+
const path55 = join25(ctx.rootDir, "milestones", `${id}.md`);
|
|
37087
37600
|
const meta3 = {
|
|
37088
37601
|
kind: "milestone",
|
|
37089
37602
|
id,
|
|
@@ -37100,7 +37613,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
37100
37613
|
`Target version: ${version2}`,
|
|
37101
37614
|
""
|
|
37102
37615
|
].join("\n");
|
|
37103
|
-
ctx.storage.write(
|
|
37616
|
+
ctx.storage.write(path55, meta3, body);
|
|
37104
37617
|
return { id, created: true };
|
|
37105
37618
|
}
|
|
37106
37619
|
function readPlanSummary(ctx) {
|
|
@@ -37304,7 +37817,7 @@ function addIdeaStub(ctx) {
|
|
|
37304
37817
|
const tags = args["tags"] ?? [];
|
|
37305
37818
|
const category = args["category"] ?? "General";
|
|
37306
37819
|
const id = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
37307
|
-
const
|
|
37820
|
+
const path55 = workspaceArtifact(ctx.rootDir, "decisions", id);
|
|
37308
37821
|
const meta3 = {
|
|
37309
37822
|
kind: "adr",
|
|
37310
37823
|
status: "proposed",
|
|
@@ -37330,7 +37843,7 @@ function addIdeaStub(ctx) {
|
|
|
37330
37843
|
...consequences.map((c) => `- ${c}`),
|
|
37331
37844
|
""
|
|
37332
37845
|
].join("\n");
|
|
37333
|
-
ctx.storage.write(
|
|
37846
|
+
ctx.storage.write(path55, meta3, body);
|
|
37334
37847
|
return `ADR ${id} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
37335
37848
|
});
|
|
37336
37849
|
}
|
|
@@ -37412,14 +37925,14 @@ function createDocumentStub(ctx) {
|
|
|
37412
37925
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
37413
37926
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
37414
37927
|
}
|
|
37415
|
-
const
|
|
37928
|
+
const path55 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
37416
37929
|
const meta3 = {
|
|
37417
37930
|
kind: "doc",
|
|
37418
37931
|
id: slug,
|
|
37419
37932
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
37420
37933
|
tags
|
|
37421
37934
|
};
|
|
37422
|
-
ctx.storage.write(
|
|
37935
|
+
ctx.storage.write(path55, meta3, content);
|
|
37423
37936
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
37424
37937
|
});
|
|
37425
37938
|
}
|
|
@@ -37455,7 +37968,7 @@ function searchDocumentsStub(ctx) {
|
|
|
37455
37968
|
];
|
|
37456
37969
|
const results = [];
|
|
37457
37970
|
for (const file2 of files) {
|
|
37458
|
-
if (!
|
|
37971
|
+
if (!existsSync30(file2)) continue;
|
|
37459
37972
|
const raw = readFileSync26(file2, "utf8");
|
|
37460
37973
|
const content = raw.toLowerCase();
|
|
37461
37974
|
let idx = -1;
|
|
@@ -37636,21 +38149,21 @@ __export(updater_exports, {
|
|
|
37636
38149
|
resolveBundledNpmCli: () => resolveBundledNpmCli
|
|
37637
38150
|
});
|
|
37638
38151
|
import { createRequire as createRequire2 } from "node:module";
|
|
37639
|
-
import { spawn as
|
|
37640
|
-
import { existsSync as
|
|
37641
|
-
import
|
|
38152
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
38153
|
+
import { existsSync as existsSync31 } from "node:fs";
|
|
38154
|
+
import path33 from "node:path";
|
|
37642
38155
|
import { fileURLToPath } from "node:url";
|
|
37643
38156
|
function resolveBundledNpmCli(execPath = process.execPath) {
|
|
37644
|
-
const dir =
|
|
38157
|
+
const dir = path33.dirname(execPath);
|
|
37645
38158
|
const candidates = [
|
|
37646
38159
|
// Windows: C:\...\node.exe → C:\...\node_modules\npm\bin\npm-cli.js
|
|
37647
|
-
|
|
38160
|
+
path33.join(dir, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
37648
38161
|
// POSIX: <prefix>/bin/node → <prefix>/lib/node_modules/npm/bin/npm-cli.js
|
|
37649
|
-
|
|
38162
|
+
path33.join(dir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
37650
38163
|
];
|
|
37651
38164
|
for (const candidate of candidates) {
|
|
37652
38165
|
try {
|
|
37653
|
-
if (
|
|
38166
|
+
if (existsSync31(candidate)) return candidate;
|
|
37654
38167
|
} catch {
|
|
37655
38168
|
}
|
|
37656
38169
|
}
|
|
@@ -37663,7 +38176,7 @@ function looksLikeBrokenShim(exitCode, output) {
|
|
|
37663
38176
|
}
|
|
37664
38177
|
function getCurrentVersion() {
|
|
37665
38178
|
try {
|
|
37666
|
-
const pkgPath =
|
|
38179
|
+
const pkgPath = path33.resolve(__dirname2, "..", "..", "package.json");
|
|
37667
38180
|
const pkg = require2(pkgPath);
|
|
37668
38181
|
return pkg.version;
|
|
37669
38182
|
} catch {
|
|
@@ -37723,7 +38236,7 @@ async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
|
37723
38236
|
updateAvailable: cmp < 0
|
|
37724
38237
|
};
|
|
37725
38238
|
}
|
|
37726
|
-
async function performUpdate(packageName = "zelari-code", executor =
|
|
38239
|
+
async function performUpdate(packageName = "zelari-code", executor = spawn10, resolveNpmCli = resolveBundledNpmCli) {
|
|
37727
38240
|
const args = ["install", "-g", `${packageName}@latest`];
|
|
37728
38241
|
const primary = await runNpm(executor, args, "shim");
|
|
37729
38242
|
if (primary.ok) return primary;
|
|
@@ -37775,13 +38288,13 @@ var init_updater = __esm({
|
|
|
37775
38288
|
"use strict";
|
|
37776
38289
|
init_cmdline();
|
|
37777
38290
|
require2 = createRequire2(import.meta.url);
|
|
37778
|
-
__dirname2 =
|
|
38291
|
+
__dirname2 = path33.dirname(fileURLToPath(import.meta.url));
|
|
37779
38292
|
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
37780
38293
|
}
|
|
37781
38294
|
});
|
|
37782
38295
|
|
|
37783
38296
|
// src/cli/mcp/mcpClient.ts
|
|
37784
|
-
import { spawn as
|
|
38297
|
+
import { spawn as spawn11 } from "node:child_process";
|
|
37785
38298
|
var DEFAULT_REQUEST_TIMEOUT_MS, INIT_TIMEOUT_MS, MCP_PROTOCOL_VERSION, McpClient;
|
|
37786
38299
|
var init_mcpClient = __esm({
|
|
37787
38300
|
"src/cli/mcp/mcpClient.ts"() {
|
|
@@ -37809,10 +38322,10 @@ var init_mcpClient = __esm({
|
|
|
37809
38322
|
env: { ...process.env, ...this.config.env ?? {} },
|
|
37810
38323
|
windowsHide: true
|
|
37811
38324
|
};
|
|
37812
|
-
const child = process.platform === "win32" ?
|
|
38325
|
+
const child = process.platform === "win32" ? spawn11(buildCmdLine(this.config.command, this.config.args ?? []), {
|
|
37813
38326
|
...spawnOpts,
|
|
37814
38327
|
shell: true
|
|
37815
|
-
}) :
|
|
38328
|
+
}) : spawn11(this.config.command, this.config.args ?? [], spawnOpts);
|
|
37816
38329
|
this.child = child;
|
|
37817
38330
|
child.stdout.setEncoding("utf8");
|
|
37818
38331
|
child.stdout.on("data", (chunk) => this.onStdout(chunk));
|
|
@@ -37950,7 +38463,7 @@ var init_mcpClient = __esm({
|
|
|
37950
38463
|
|
|
37951
38464
|
// src/cli/mcp/mcpConfigIo.ts
|
|
37952
38465
|
import {
|
|
37953
|
-
existsSync as
|
|
38466
|
+
existsSync as existsSync32,
|
|
37954
38467
|
mkdirSync as mkdirSync16,
|
|
37955
38468
|
readFileSync as readFileSync27,
|
|
37956
38469
|
writeFileSync as writeFileSync18
|
|
@@ -37963,10 +38476,10 @@ function getUserMcpPath() {
|
|
|
37963
38476
|
function getProjectMcpPath(projectRoot) {
|
|
37964
38477
|
return join26(projectRoot, ".zelari", "mcp.json");
|
|
37965
38478
|
}
|
|
37966
|
-
function readFile2(
|
|
37967
|
-
if (!
|
|
38479
|
+
function readFile2(path55) {
|
|
38480
|
+
if (!existsSync32(path55)) return {};
|
|
37968
38481
|
try {
|
|
37969
|
-
const parsed = JSON.parse(readFileSync27(
|
|
38482
|
+
const parsed = JSON.parse(readFileSync27(path55, "utf8"));
|
|
37970
38483
|
const out = {};
|
|
37971
38484
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
37972
38485
|
if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
|
|
@@ -37982,10 +38495,10 @@ function readFile2(path53) {
|
|
|
37982
38495
|
return {};
|
|
37983
38496
|
}
|
|
37984
38497
|
}
|
|
37985
|
-
function writeFile(
|
|
37986
|
-
mkdirSync16(dirname7(
|
|
38498
|
+
function writeFile(path55, servers) {
|
|
38499
|
+
mkdirSync16(dirname7(path55), { recursive: true });
|
|
37987
38500
|
const body = { mcpServers: servers };
|
|
37988
|
-
writeFileSync18(
|
|
38501
|
+
writeFileSync18(path55, `${JSON.stringify(body, null, 2)}
|
|
37989
38502
|
`, "utf8");
|
|
37990
38503
|
}
|
|
37991
38504
|
function listMcpServers(projectRoot) {
|
|
@@ -38018,9 +38531,9 @@ function upsertMcpServer(opts) {
|
|
|
38018
38531
|
if (!opts.config.command?.trim()) {
|
|
38019
38532
|
return { ok: false, error: "command is required" };
|
|
38020
38533
|
}
|
|
38021
|
-
let
|
|
38534
|
+
let path55;
|
|
38022
38535
|
if (opts.scope === "user") {
|
|
38023
|
-
|
|
38536
|
+
path55 = getUserMcpPath();
|
|
38024
38537
|
} else {
|
|
38025
38538
|
const root = opts.projectRoot?.trim();
|
|
38026
38539
|
if (!root) {
|
|
@@ -38029,30 +38542,30 @@ function upsertMcpServer(opts) {
|
|
|
38029
38542
|
error: "projectRoot required for project scope (Open Folder first)"
|
|
38030
38543
|
};
|
|
38031
38544
|
}
|
|
38032
|
-
|
|
38545
|
+
path55 = getProjectMcpPath(root);
|
|
38033
38546
|
}
|
|
38034
|
-
const current = readFile2(
|
|
38547
|
+
const current = readFile2(path55);
|
|
38035
38548
|
current[name] = {
|
|
38036
38549
|
command: opts.config.command.trim(),
|
|
38037
38550
|
args: opts.config.args,
|
|
38038
38551
|
env: opts.config.env,
|
|
38039
38552
|
enabled: opts.config.enabled !== false
|
|
38040
38553
|
};
|
|
38041
|
-
writeFile(
|
|
38042
|
-
return { ok: true, path:
|
|
38554
|
+
writeFile(path55, current);
|
|
38555
|
+
return { ok: true, path: path55 };
|
|
38043
38556
|
}
|
|
38044
38557
|
function removeMcpServer(opts) {
|
|
38045
|
-
const
|
|
38046
|
-
if (!
|
|
38558
|
+
const path55 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
|
|
38559
|
+
if (!path55) {
|
|
38047
38560
|
return { ok: false, error: "projectRoot required for project scope" };
|
|
38048
38561
|
}
|
|
38049
|
-
const current = readFile2(
|
|
38562
|
+
const current = readFile2(path55);
|
|
38050
38563
|
if (!(opts.name in current)) {
|
|
38051
|
-
return { ok: false, error: `Server "${opts.name}" not found in ${
|
|
38564
|
+
return { ok: false, error: `Server "${opts.name}" not found in ${path55}` };
|
|
38052
38565
|
}
|
|
38053
38566
|
delete current[opts.name];
|
|
38054
|
-
writeFile(
|
|
38055
|
-
return { ok: true, path:
|
|
38567
|
+
writeFile(path55, current);
|
|
38568
|
+
return { ok: true, path: path55 };
|
|
38056
38569
|
}
|
|
38057
38570
|
var init_mcpConfigIo = __esm({
|
|
38058
38571
|
"src/cli/mcp/mcpConfigIo.ts"() {
|
|
@@ -38194,7 +38707,7 @@ __export(mcpManager_exports, {
|
|
|
38194
38707
|
readMcpConfig: () => readMcpConfig,
|
|
38195
38708
|
registerMcpTools: () => registerMcpTools
|
|
38196
38709
|
});
|
|
38197
|
-
import { existsSync as
|
|
38710
|
+
import { existsSync as existsSync33, readFileSync as readFileSync28 } from "node:fs";
|
|
38198
38711
|
import { join as join27 } from "node:path";
|
|
38199
38712
|
import { homedir as homedir11 } from "node:os";
|
|
38200
38713
|
function readMcpConfig(projectRoot = process.cwd(), opts) {
|
|
@@ -38207,7 +38720,7 @@ function readMcpConfig(projectRoot = process.cwd(), opts) {
|
|
|
38207
38720
|
paths.push(join27(projectRoot, ".zelari", "mcp.json"));
|
|
38208
38721
|
}
|
|
38209
38722
|
for (const p3 of paths) {
|
|
38210
|
-
if (!
|
|
38723
|
+
if (!existsSync33(p3)) continue;
|
|
38211
38724
|
try {
|
|
38212
38725
|
const parsed = JSON.parse(readFileSync28(p3, "utf8"));
|
|
38213
38726
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
@@ -38223,7 +38736,7 @@ async function ensureLoaded(projectRoot) {
|
|
|
38223
38736
|
if (state2.loaded) return;
|
|
38224
38737
|
state2.loaded = true;
|
|
38225
38738
|
const trusted = isFolderTrusted(projectRoot);
|
|
38226
|
-
if (!trusted &&
|
|
38739
|
+
if (!trusted && existsSync33(join27(projectRoot, ".zelari", "mcp.json"))) {
|
|
38227
38740
|
state2.warnings.push(
|
|
38228
38741
|
"[mcp] project .zelari/mcp.json ignored \u2014 folder not trusted (run /trust or `zelari-code --trust` to enable project MCP)"
|
|
38229
38742
|
);
|
|
@@ -38448,15 +38961,15 @@ __export(agentsMd_exports, {
|
|
|
38448
38961
|
serializeAgentsMd: () => serializeAgentsMd,
|
|
38449
38962
|
updateAgentsMd: () => updateAgentsMd
|
|
38450
38963
|
});
|
|
38451
|
-
import { existsSync as
|
|
38452
|
-
import { createHash as
|
|
38964
|
+
import { existsSync as existsSync34, readFileSync as readFileSync29, writeFileSync as writeFileSync19 } from "node:fs";
|
|
38965
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
38453
38966
|
import { join as join28 } from "node:path";
|
|
38454
38967
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
38455
38968
|
async function readPackageJson2(projectRoot) {
|
|
38456
|
-
const
|
|
38457
|
-
if (!
|
|
38969
|
+
const path55 = join28(projectRoot, "package.json");
|
|
38970
|
+
if (!existsSync34(path55)) return null;
|
|
38458
38971
|
try {
|
|
38459
|
-
return JSON.parse(await readFile3(
|
|
38972
|
+
return JSON.parse(await readFile3(path55, "utf8"));
|
|
38460
38973
|
} catch {
|
|
38461
38974
|
return null;
|
|
38462
38975
|
}
|
|
@@ -38479,7 +38992,7 @@ async function genTechStack(ctx) {
|
|
|
38479
38992
|
}
|
|
38480
38993
|
async function genDecisions(ctx) {
|
|
38481
38994
|
const decisionsDir = join28(ctx.rootDir, "decisions");
|
|
38482
|
-
if (!
|
|
38995
|
+
if (!existsSync34(decisionsDir)) return "_No ADRs yet._";
|
|
38483
38996
|
const files = ctx.storage.listMarkdown(decisionsDir).sort();
|
|
38484
38997
|
const accepted = [];
|
|
38485
38998
|
const proposed = [];
|
|
@@ -38505,7 +39018,7 @@ async function genDecisions(ctx) {
|
|
|
38505
39018
|
async function genConventions(ctx) {
|
|
38506
39019
|
const lines = [];
|
|
38507
39020
|
const claudeMd = join28(ctx.projectRoot, "CLAUDE.MD");
|
|
38508
|
-
if (
|
|
39021
|
+
if (existsSync34(claudeMd)) {
|
|
38509
39022
|
const content = readFileSync29(claudeMd, "utf8");
|
|
38510
39023
|
const match = content.match(/## Architecture rules[\s\S]+?(?=\n## |\n*$)/);
|
|
38511
39024
|
if (match) {
|
|
@@ -38538,9 +39051,9 @@ async function genBuild(ctx) {
|
|
|
38538
39051
|
].join("\n");
|
|
38539
39052
|
}
|
|
38540
39053
|
async function genOpenQuestions(ctx) {
|
|
38541
|
-
const
|
|
38542
|
-
if (!
|
|
38543
|
-
const content = readFileSync29(
|
|
39054
|
+
const path55 = join28(ctx.rootDir, "risks.md");
|
|
39055
|
+
if (!existsSync34(path55)) return "_No open questions._";
|
|
39056
|
+
const content = readFileSync29(path55, "utf8");
|
|
38544
39057
|
const lines = content.split("\n");
|
|
38545
39058
|
const questions = [];
|
|
38546
39059
|
let currentTitle = "";
|
|
@@ -38615,7 +39128,7 @@ function titleCase(id) {
|
|
|
38615
39128
|
}
|
|
38616
39129
|
async function updateAgentsMd(ctx, projectRoot) {
|
|
38617
39130
|
const agentsPath = join28(projectRoot, "AGENTS.MD");
|
|
38618
|
-
if (
|
|
39131
|
+
if (existsSync34(agentsPath)) {
|
|
38619
39132
|
const content = readFileSync29(agentsPath, "utf8");
|
|
38620
39133
|
const hasAnyMarker = AUTO_SECTIONS.some((id) => content.includes(MARKER_OPEN(id)));
|
|
38621
39134
|
if (!hasAnyMarker) {
|
|
@@ -38631,7 +39144,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
38631
39144
|
newSections.set(id, await GENERATORS[id](ctx));
|
|
38632
39145
|
}
|
|
38633
39146
|
let manualContent = "";
|
|
38634
|
-
if (
|
|
39147
|
+
if (existsSync34(agentsPath)) {
|
|
38635
39148
|
const { manualBlocks } = parseAgentsMd(readFileSync29(agentsPath, "utf8"));
|
|
38636
39149
|
manualContent = manualBlocks.after;
|
|
38637
39150
|
} else {
|
|
@@ -38648,7 +39161,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
38648
39161
|
""
|
|
38649
39162
|
].join("\n");
|
|
38650
39163
|
}
|
|
38651
|
-
const oldContent =
|
|
39164
|
+
const oldContent = existsSync34(agentsPath) ? readFileSync29(agentsPath, "utf8") : "";
|
|
38652
39165
|
const { sections: oldSections } = parseAgentsMd(oldContent);
|
|
38653
39166
|
const changedSections = [];
|
|
38654
39167
|
for (const id of AUTO_SECTIONS) {
|
|
@@ -38664,7 +39177,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
38664
39177
|
return { changed: true, sections: changedSections };
|
|
38665
39178
|
}
|
|
38666
39179
|
function hash2(s) {
|
|
38667
|
-
return
|
|
39180
|
+
return createHash9("sha256").update(s).digest("hex").slice(0, 16);
|
|
38668
39181
|
}
|
|
38669
39182
|
var AUTO_SECTIONS, MARKER_OPEN, MARKER_CLOSE, GENERATORS;
|
|
38670
39183
|
var init_agentsMd = __esm({
|
|
@@ -38785,11 +39298,11 @@ var init_completeDesign = __esm({
|
|
|
38785
39298
|
});
|
|
38786
39299
|
|
|
38787
39300
|
// src/cli/workspace/planDriftCheck.ts
|
|
38788
|
-
import { existsSync as
|
|
39301
|
+
import { existsSync as existsSync35, readFileSync as readFileSync30, readdirSync as readdirSync9, statSync as statSync5, writeFileSync as writeFileSync20 } from "node:fs";
|
|
38789
39302
|
import { join as join29 } from "node:path";
|
|
38790
39303
|
function findCanonicalDoc(rootDir) {
|
|
38791
39304
|
const docsDir = join29(rootDir, "docs");
|
|
38792
|
-
if (!
|
|
39305
|
+
if (!existsSync35(docsDir)) return null;
|
|
38793
39306
|
const candidates = readdirSync9(docsDir).filter((f) => /^plan-canonical.*\.md$/i.test(f)).map((f) => ({ f, mtime: statSync5(join29(docsDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
38794
39307
|
return candidates.length > 0 ? candidates[0].f : null;
|
|
38795
39308
|
}
|
|
@@ -38814,9 +39327,9 @@ function versionKey(value) {
|
|
|
38814
39327
|
function firstString2(v) {
|
|
38815
39328
|
return typeof v === "string" && v.trim().length > 0 ? v : null;
|
|
38816
39329
|
}
|
|
38817
|
-
function readFileSyncSafe(
|
|
39330
|
+
function readFileSyncSafe(path55) {
|
|
38818
39331
|
try {
|
|
38819
|
-
return readFileSync30(
|
|
39332
|
+
return readFileSync30(path55, "utf8");
|
|
38820
39333
|
} catch {
|
|
38821
39334
|
return null;
|
|
38822
39335
|
}
|
|
@@ -38826,7 +39339,7 @@ async function runPlanDriftCheck(rootDir) {
|
|
|
38826
39339
|
return { ran: false, reason: "ZELARI_DRIFT_CHECK=0 (disabled)" };
|
|
38827
39340
|
}
|
|
38828
39341
|
const planPath = join29(rootDir, "plan.json");
|
|
38829
|
-
if (!
|
|
39342
|
+
if (!existsSync35(planPath)) {
|
|
38830
39343
|
return { ran: false, reason: ".zelari/plan.json missing (not design-phase)" };
|
|
38831
39344
|
}
|
|
38832
39345
|
let plan;
|
|
@@ -38956,8 +39469,8 @@ var init_planDriftCheck = __esm({
|
|
|
38956
39469
|
});
|
|
38957
39470
|
|
|
38958
39471
|
// src/cli/workspace/projectSmoke.ts
|
|
38959
|
-
import { spawn as
|
|
38960
|
-
import { existsSync as
|
|
39472
|
+
import { spawn as spawn12 } from "node:child_process";
|
|
39473
|
+
import { existsSync as existsSync36, readFileSync as readFileSync31 } from "node:fs";
|
|
38961
39474
|
import { join as join30 } from "node:path";
|
|
38962
39475
|
function pickSmokeScript(scripts) {
|
|
38963
39476
|
if (!scripts) return null;
|
|
@@ -38971,7 +39484,7 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS2) {
|
|
|
38971
39484
|
return { ran: false, reason: "ZELARI_SMOKE=0 (disabled)" };
|
|
38972
39485
|
}
|
|
38973
39486
|
const pkgPath = join30(projectRoot, "package.json");
|
|
38974
|
-
if (!
|
|
39487
|
+
if (!existsSync36(pkgPath)) {
|
|
38975
39488
|
return { ran: false, reason: "no package.json (skipped)" };
|
|
38976
39489
|
}
|
|
38977
39490
|
let scripts = {};
|
|
@@ -38986,12 +39499,12 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS2) {
|
|
|
38986
39499
|
return { ran: false, reason: "no typecheck/test/build script (skipped)" };
|
|
38987
39500
|
}
|
|
38988
39501
|
return await new Promise((resolveRun) => {
|
|
38989
|
-
const child = process.platform === "win32" ?
|
|
39502
|
+
const child = process.platform === "win32" ? spawn12(buildCmdLine("npm.cmd", ["run", script]), {
|
|
38990
39503
|
cwd: projectRoot,
|
|
38991
39504
|
stdio: ["ignore", "pipe", "pipe"],
|
|
38992
39505
|
env: process.env,
|
|
38993
39506
|
shell: true
|
|
38994
|
-
}) :
|
|
39507
|
+
}) : spawn12("npm", ["run", script], {
|
|
38995
39508
|
cwd: projectRoot,
|
|
38996
39509
|
stdio: ["ignore", "pipe", "pipe"],
|
|
38997
39510
|
env: process.env
|
|
@@ -39063,8 +39576,8 @@ __export(postCouncilHook_exports, {
|
|
|
39063
39576
|
runImplementationVerificationHook: () => runImplementationVerificationHook,
|
|
39064
39577
|
runPostCouncilHook: () => runPostCouncilHook
|
|
39065
39578
|
});
|
|
39066
|
-
import { spawn as
|
|
39067
|
-
import { existsSync as
|
|
39579
|
+
import { spawn as spawn13 } from "node:child_process";
|
|
39580
|
+
import { existsSync as existsSync37, readFileSync as readFileSync32 } from "node:fs";
|
|
39068
39581
|
import { join as join31 } from "node:path";
|
|
39069
39582
|
async function runCompleteDesignPostProcessor(ctx, options) {
|
|
39070
39583
|
if (options?.runMode === "implementation") {
|
|
@@ -39078,7 +39591,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
39078
39591
|
}
|
|
39079
39592
|
const planJsonPath2 = join31(ctx.rootDir, "plan.json");
|
|
39080
39593
|
const scriptPath = join31(ctx.projectRoot, "complete-design.mjs");
|
|
39081
|
-
if (!
|
|
39594
|
+
if (!existsSync37(planJsonPath2)) {
|
|
39082
39595
|
return {
|
|
39083
39596
|
ran: false,
|
|
39084
39597
|
reason: ".zelari/plan.json missing (not design-phase)"
|
|
@@ -39094,7 +39607,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
39094
39607
|
if (phaseCount === 0) {
|
|
39095
39608
|
return { ran: false, reason: ".zelari/plan.json has no phases" };
|
|
39096
39609
|
}
|
|
39097
|
-
if (!
|
|
39610
|
+
if (!existsSync37(scriptPath)) {
|
|
39098
39611
|
try {
|
|
39099
39612
|
const builtin = await runBuiltinCompleteDesign(ctx);
|
|
39100
39613
|
return {
|
|
@@ -39112,7 +39625,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
39112
39625
|
}
|
|
39113
39626
|
}
|
|
39114
39627
|
return await new Promise((resolveRun) => {
|
|
39115
|
-
const child =
|
|
39628
|
+
const child = spawn13(process.execPath, [scriptPath], {
|
|
39116
39629
|
cwd: ctx.projectRoot,
|
|
39117
39630
|
stdio: ["ignore", "pipe", "pipe"],
|
|
39118
39631
|
env: process.env
|
|
@@ -39279,8 +39792,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
39279
39792
|
sources: scope.sources
|
|
39280
39793
|
} : void 0
|
|
39281
39794
|
});
|
|
39282
|
-
const
|
|
39283
|
-
completionHook = { ran: true, path:
|
|
39795
|
+
const path55 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
39796
|
+
completionHook = { ran: true, path: path55, completion };
|
|
39284
39797
|
} catch (err) {
|
|
39285
39798
|
completionHook = {
|
|
39286
39799
|
ran: true,
|
|
@@ -39319,14 +39832,14 @@ __export(councilFeedback_exports, {
|
|
|
39319
39832
|
FeedbackStore: () => FeedbackStore
|
|
39320
39833
|
});
|
|
39321
39834
|
import {
|
|
39322
|
-
promises as
|
|
39323
|
-
existsSync as
|
|
39835
|
+
promises as fs18,
|
|
39836
|
+
existsSync as existsSync38,
|
|
39324
39837
|
readFileSync as readFileSync33,
|
|
39325
39838
|
writeFileSync as writeFileSync21,
|
|
39326
39839
|
mkdirSync as mkdirSync17
|
|
39327
39840
|
} from "node:fs";
|
|
39328
|
-
import
|
|
39329
|
-
import
|
|
39841
|
+
import path34 from "node:path";
|
|
39842
|
+
import os10 from "node:os";
|
|
39330
39843
|
var FeedbackStore;
|
|
39331
39844
|
var init_councilFeedback = __esm({
|
|
39332
39845
|
"src/cli/councilFeedback.ts"() {
|
|
@@ -39336,7 +39849,7 @@ var init_councilFeedback = __esm({
|
|
|
39336
39849
|
now;
|
|
39337
39850
|
entries = [];
|
|
39338
39851
|
constructor(options = {}) {
|
|
39339
|
-
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ??
|
|
39852
|
+
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path34.join(os10.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
|
|
39340
39853
|
this.now = options.now ?? Date.now;
|
|
39341
39854
|
this.load();
|
|
39342
39855
|
}
|
|
@@ -39429,7 +39942,7 @@ var init_councilFeedback = __esm({
|
|
|
39429
39942
|
}
|
|
39430
39943
|
// --- persistence ---------------------------------------------------------
|
|
39431
39944
|
load() {
|
|
39432
|
-
if (!
|
|
39945
|
+
if (!existsSync38(this.file)) return;
|
|
39433
39946
|
try {
|
|
39434
39947
|
const raw = readFileSync33(this.file, "utf-8");
|
|
39435
39948
|
const parsed = JSON.parse(raw);
|
|
@@ -39442,7 +39955,7 @@ var init_councilFeedback = __esm({
|
|
|
39442
39955
|
}
|
|
39443
39956
|
}
|
|
39444
39957
|
save() {
|
|
39445
|
-
mkdirSync17(
|
|
39958
|
+
mkdirSync17(path34.dirname(this.file), { recursive: true });
|
|
39446
39959
|
writeFileSync21(
|
|
39447
39960
|
this.file,
|
|
39448
39961
|
JSON.stringify({ entries: this.entries }, null, 2),
|
|
@@ -39452,7 +39965,7 @@ var init_councilFeedback = __esm({
|
|
|
39452
39965
|
/** Async variant of load for callers that prefer async IO. */
|
|
39453
39966
|
async loadAsync() {
|
|
39454
39967
|
try {
|
|
39455
|
-
const raw = await
|
|
39968
|
+
const raw = await fs18.readFile(this.file, "utf-8");
|
|
39456
39969
|
const parsed = JSON.parse(raw);
|
|
39457
39970
|
if (parsed && Array.isArray(parsed.entries)) {
|
|
39458
39971
|
this.entries = parsed.entries.filter(
|
|
@@ -39510,7 +40023,7 @@ import { execFile as execFile3 } from "node:child_process";
|
|
|
39510
40023
|
import { promisify as promisify2 } from "node:util";
|
|
39511
40024
|
import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
|
|
39512
40025
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
39513
|
-
import
|
|
40026
|
+
import path35 from "node:path";
|
|
39514
40027
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
39515
40028
|
async function git2(cwd, args, env) {
|
|
39516
40029
|
const { stdout } = await execFileAsync2("git", ["-C", cwd, ...args], {
|
|
@@ -39530,8 +40043,8 @@ async function isGitRepo(cwd) {
|
|
|
39530
40043
|
return await gitSafe(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true";
|
|
39531
40044
|
}
|
|
39532
40045
|
async function withTempIndex(fn) {
|
|
39533
|
-
const dir = mkdtempSync(
|
|
39534
|
-
const indexFile =
|
|
40046
|
+
const dir = mkdtempSync(path35.join(tmpdir2(), "zelari-ckpt-"));
|
|
40047
|
+
const indexFile = path35.join(dir, "index");
|
|
39535
40048
|
try {
|
|
39536
40049
|
return await fn(indexFile);
|
|
39537
40050
|
} finally {
|
|
@@ -39622,7 +40135,7 @@ async function restoreCheckpoint(cwd, id) {
|
|
|
39622
40135
|
const deleted = [];
|
|
39623
40136
|
for (const rel2 of added) {
|
|
39624
40137
|
try {
|
|
39625
|
-
rmSync2(
|
|
40138
|
+
rmSync2(path35.join(cwd, rel2), { force: true });
|
|
39626
40139
|
deleted.push(rel2);
|
|
39627
40140
|
} catch {
|
|
39628
40141
|
}
|
|
@@ -39722,8 +40235,8 @@ __export(fileBackend_exports, {
|
|
|
39722
40235
|
isMemoryEnabled: () => isMemoryEnabled
|
|
39723
40236
|
});
|
|
39724
40237
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
39725
|
-
import { promises as
|
|
39726
|
-
import * as
|
|
40238
|
+
import { promises as fs19 } from "node:fs";
|
|
40239
|
+
import * as path36 from "node:path";
|
|
39727
40240
|
function tokenize(text) {
|
|
39728
40241
|
return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
|
|
39729
40242
|
}
|
|
@@ -39767,9 +40280,9 @@ var init_fileBackend = __esm({
|
|
|
39767
40280
|
logPath = "";
|
|
39768
40281
|
memoryDir = "";
|
|
39769
40282
|
async init(projectRoot) {
|
|
39770
|
-
this.memoryDir =
|
|
39771
|
-
this.logPath =
|
|
39772
|
-
await
|
|
40283
|
+
this.memoryDir = path36.join(projectRoot, ".zelari", "memory");
|
|
40284
|
+
this.logPath = path36.join(this.memoryDir, "log.jsonl");
|
|
40285
|
+
await fs19.mkdir(this.memoryDir, { recursive: true });
|
|
39773
40286
|
}
|
|
39774
40287
|
async add(content, metadata = {}, graph) {
|
|
39775
40288
|
const fact = {
|
|
@@ -39779,7 +40292,7 @@ var init_fileBackend = __esm({
|
|
|
39779
40292
|
...graph ? { graph } : {},
|
|
39780
40293
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
39781
40294
|
};
|
|
39782
|
-
await
|
|
40295
|
+
await fs19.appendFile(this.logPath, JSON.stringify(fact) + "\n", "utf8");
|
|
39783
40296
|
return fact.id;
|
|
39784
40297
|
}
|
|
39785
40298
|
async search(query, options = {}) {
|
|
@@ -39807,7 +40320,7 @@ var init_fileBackend = __esm({
|
|
|
39807
40320
|
async readAll() {
|
|
39808
40321
|
let raw;
|
|
39809
40322
|
try {
|
|
39810
|
-
raw = await
|
|
40323
|
+
raw = await fs19.readFile(this.logPath, "utf8");
|
|
39811
40324
|
} catch {
|
|
39812
40325
|
return [];
|
|
39813
40326
|
}
|
|
@@ -39840,23 +40353,23 @@ var init_fileBackend = __esm({
|
|
|
39840
40353
|
});
|
|
39841
40354
|
|
|
39842
40355
|
// src/cli/traceStore.ts
|
|
39843
|
-
import { promises as
|
|
39844
|
-
import * as
|
|
40356
|
+
import { promises as fs20 } from "node:fs";
|
|
40357
|
+
import * as path37 from "node:path";
|
|
39845
40358
|
function traceDir(projectRoot) {
|
|
39846
|
-
return
|
|
40359
|
+
return path37.join(projectRoot, ".zelari", "trace");
|
|
39847
40360
|
}
|
|
39848
40361
|
function tracePath(projectRoot, missionId) {
|
|
39849
|
-
return
|
|
40362
|
+
return path37.join(traceDir(projectRoot), `${missionId}.json`);
|
|
39850
40363
|
}
|
|
39851
40364
|
async function saveTrace(projectRoot, missionId, entries) {
|
|
39852
40365
|
const dir = traceDir(projectRoot);
|
|
39853
|
-
await
|
|
40366
|
+
await fs20.mkdir(dir, { recursive: true });
|
|
39854
40367
|
const payload = {
|
|
39855
40368
|
missionId,
|
|
39856
40369
|
ts: Date.now(),
|
|
39857
40370
|
entries
|
|
39858
40371
|
};
|
|
39859
|
-
await
|
|
40372
|
+
await fs20.writeFile(
|
|
39860
40373
|
tracePath(projectRoot, missionId),
|
|
39861
40374
|
JSON.stringify(payload, null, 2) + "\n",
|
|
39862
40375
|
"utf8"
|
|
@@ -39880,8 +40393,8 @@ __export(zelariMission_exports, {
|
|
|
39880
40393
|
runZelariMission: () => runZelariMission
|
|
39881
40394
|
});
|
|
39882
40395
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
39883
|
-
import { promises as
|
|
39884
|
-
import * as
|
|
40396
|
+
import { promises as fs21 } from "node:fs";
|
|
40397
|
+
import * as path38 from "node:path";
|
|
39885
40398
|
function resolveMaxIterations(env = process.env) {
|
|
39886
40399
|
const raw = env.ZELARI_MISSION_MAX_ITER;
|
|
39887
40400
|
const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
|
|
@@ -39909,10 +40422,10 @@ function isMissionAutoStart(env = process.env) {
|
|
|
39909
40422
|
return env.ZELARI_MISSION_AUTO === "1";
|
|
39910
40423
|
}
|
|
39911
40424
|
async function writeMissionState(projectRoot, state3) {
|
|
39912
|
-
const dir =
|
|
39913
|
-
await
|
|
39914
|
-
await
|
|
39915
|
-
|
|
40425
|
+
const dir = path38.join(projectRoot, ".zelari");
|
|
40426
|
+
await fs21.mkdir(dir, { recursive: true });
|
|
40427
|
+
await fs21.writeFile(
|
|
40428
|
+
path38.join(dir, "mission-state.json"),
|
|
39916
40429
|
JSON.stringify(state3, null, 2) + "\n",
|
|
39917
40430
|
"utf8"
|
|
39918
40431
|
);
|
|
@@ -40512,7 +41025,7 @@ function safeSocketPath(socketPath) {
|
|
|
40512
41025
|
return socketPath.trim();
|
|
40513
41026
|
}
|
|
40514
41027
|
function startPermissionBroker(socketPath, handlers, opts) {
|
|
40515
|
-
const
|
|
41028
|
+
const path55 = safeSocketPath(socketPath);
|
|
40516
41029
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
40517
41030
|
const sockets = /* @__PURE__ */ new Set();
|
|
40518
41031
|
const server = createServer2((socket) => {
|
|
@@ -40612,10 +41125,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
40612
41125
|
return new Promise((resolve3, reject) => {
|
|
40613
41126
|
const onError = (err) => reject(err);
|
|
40614
41127
|
server.once("error", onError);
|
|
40615
|
-
server.listen(
|
|
41128
|
+
server.listen(path55, () => {
|
|
40616
41129
|
server.removeListener("error", onError);
|
|
40617
41130
|
resolve3({
|
|
40618
|
-
socketPath:
|
|
41131
|
+
socketPath: path55,
|
|
40619
41132
|
stop: () => new Promise((res) => {
|
|
40620
41133
|
for (const s of sockets) s.destroy();
|
|
40621
41134
|
sockets.clear();
|
|
@@ -40626,7 +41139,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
40626
41139
|
if (done) return;
|
|
40627
41140
|
done = true;
|
|
40628
41141
|
if (process.platform !== "win32") {
|
|
40629
|
-
unlink(
|
|
41142
|
+
unlink(path55, () => res());
|
|
40630
41143
|
} else {
|
|
40631
41144
|
res();
|
|
40632
41145
|
}
|
|
@@ -40639,11 +41152,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
40639
41152
|
});
|
|
40640
41153
|
}
|
|
40641
41154
|
function requestBrokerAsk(socketPath, ask, opts) {
|
|
40642
|
-
const
|
|
41155
|
+
const path55 = safeSocketPath(socketPath);
|
|
40643
41156
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
40644
41157
|
const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
|
|
40645
41158
|
return new Promise((resolve3, reject) => {
|
|
40646
|
-
const socket = connect(
|
|
41159
|
+
const socket = connect(path55);
|
|
40647
41160
|
let buffer = "";
|
|
40648
41161
|
let settled = false;
|
|
40649
41162
|
const settle = (fn) => {
|
|
@@ -40658,7 +41171,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
|
|
|
40658
41171
|
settle(
|
|
40659
41172
|
() => reject(
|
|
40660
41173
|
new Error(
|
|
40661
|
-
`permission broker unavailable at "${
|
|
41174
|
+
`permission broker unavailable at "${path55}" (connect timed out after ${connectTimeoutMs}ms)`
|
|
40662
41175
|
)
|
|
40663
41176
|
)
|
|
40664
41177
|
);
|
|
@@ -41390,10 +41903,10 @@ __export(graphMemory_exports, {
|
|
|
41390
41903
|
saveGraphSnapshot: () => saveGraphSnapshot,
|
|
41391
41904
|
toGraphSnapshot: () => toGraphSnapshot
|
|
41392
41905
|
});
|
|
41393
|
-
import { promises as
|
|
41394
|
-
import
|
|
41906
|
+
import { promises as fs22 } from "node:fs";
|
|
41907
|
+
import path40 from "node:path";
|
|
41395
41908
|
function snapshotPath(cwd) {
|
|
41396
|
-
return
|
|
41909
|
+
return path40.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
|
|
41397
41910
|
}
|
|
41398
41911
|
function toGraphSnapshot(graph, opts) {
|
|
41399
41912
|
const unresolved = (opts.unresolvedFindings ?? []).map((u) => ({
|
|
@@ -41418,16 +41931,16 @@ function toGraphSnapshot(graph, opts) {
|
|
|
41418
41931
|
}
|
|
41419
41932
|
async function saveGraphSnapshot(cwd, snapshot) {
|
|
41420
41933
|
try {
|
|
41421
|
-
await
|
|
41934
|
+
await fs22.access(cwd);
|
|
41422
41935
|
const file2 = snapshotPath(cwd);
|
|
41423
|
-
await
|
|
41424
|
-
await
|
|
41936
|
+
await fs22.mkdir(path40.dirname(file2), { recursive: true });
|
|
41937
|
+
await fs22.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
41425
41938
|
} catch {
|
|
41426
41939
|
}
|
|
41427
41940
|
}
|
|
41428
41941
|
async function loadGraphSnapshot(cwd) {
|
|
41429
41942
|
try {
|
|
41430
|
-
const raw = await
|
|
41943
|
+
const raw = await fs22.readFile(snapshotPath(cwd), "utf8");
|
|
41431
41944
|
const parsed = JSON.parse(raw);
|
|
41432
41945
|
if (!parsed || !Array.isArray(parsed.nodes)) return null;
|
|
41433
41946
|
return parsed;
|
|
@@ -41487,7 +42000,7 @@ var SNAPSHOT_DIR, SNAPSHOT_FILE, MAX_SNAPSHOT_FINDINGS_CHARS;
|
|
|
41487
42000
|
var init_graphMemory = __esm({
|
|
41488
42001
|
"src/cli/kraken/graphMemory.ts"() {
|
|
41489
42002
|
"use strict";
|
|
41490
|
-
SNAPSHOT_DIR =
|
|
42003
|
+
SNAPSHOT_DIR = path40.join(".zelari", "kraken");
|
|
41491
42004
|
SNAPSHOT_FILE = "last-graph.json";
|
|
41492
42005
|
MAX_SNAPSHOT_FINDINGS_CHARS = 400;
|
|
41493
42006
|
}
|
|
@@ -41502,15 +42015,15 @@ var init_tentacle = __esm({
|
|
|
41502
42015
|
});
|
|
41503
42016
|
|
|
41504
42017
|
// src/cli/kraken/workbench.ts
|
|
41505
|
-
import { promises as
|
|
41506
|
-
import
|
|
42018
|
+
import { promises as fs23 } from "node:fs";
|
|
42019
|
+
import path41 from "node:path";
|
|
41507
42020
|
function isWorkbenchEnabled(env = process.env) {
|
|
41508
42021
|
const v = (env.ZELARI_KRAKEN_WORKBENCH ?? "1").trim().toLowerCase();
|
|
41509
42022
|
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
41510
42023
|
return true;
|
|
41511
42024
|
}
|
|
41512
42025
|
function workbenchPath(cwd, graphId) {
|
|
41513
|
-
return
|
|
42026
|
+
return path41.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
|
|
41514
42027
|
}
|
|
41515
42028
|
function countByStatus2(nodes) {
|
|
41516
42029
|
const out = { pending: 0, running: 0, done: 0, error: 0, skipped: 0 };
|
|
@@ -41673,11 +42186,11 @@ var init_workbench = __esm({
|
|
|
41673
42186
|
if (!this.enabled) return null;
|
|
41674
42187
|
if (!this.dirty && this.lastWrite) return this.lastWrite;
|
|
41675
42188
|
const out = workbenchPath(this.cwd, this.graphId);
|
|
41676
|
-
await
|
|
42189
|
+
await fs23.mkdir(path41.dirname(out), { recursive: true });
|
|
41677
42190
|
const body = this.render();
|
|
41678
42191
|
const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
|
|
41679
|
-
await
|
|
41680
|
-
await
|
|
42192
|
+
await fs23.writeFile(tmp, body, "utf8");
|
|
42193
|
+
await fs23.rename(tmp, out);
|
|
41681
42194
|
this.dirty = false;
|
|
41682
42195
|
this.lastWrite = Promise.resolve(out);
|
|
41683
42196
|
return out;
|
|
@@ -41869,8 +42382,8 @@ __export(executor_exports, {
|
|
|
41869
42382
|
resolveNodeTimeoutMs: () => resolveNodeTimeoutMs,
|
|
41870
42383
|
thoroughnessForKind: () => thoroughnessForKind
|
|
41871
42384
|
});
|
|
41872
|
-
import { existsSync as
|
|
41873
|
-
import
|
|
42385
|
+
import { existsSync as existsSync39 } from "node:fs";
|
|
42386
|
+
import path42 from "node:path";
|
|
41874
42387
|
function resolveMaxParallel(env = process.env) {
|
|
41875
42388
|
const raw = env.ZELARI_KRAKEN_MAX_PARALLEL;
|
|
41876
42389
|
if (raw === void 0 || raw === "") return DEFAULT_MAX_PARALLEL;
|
|
@@ -41928,7 +42441,7 @@ function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultC
|
|
|
41928
42441
|
}
|
|
41929
42442
|
function defaultChecksExists(cwd) {
|
|
41930
42443
|
try {
|
|
41931
|
-
return
|
|
42444
|
+
return existsSync39(path42.join(cwd, ".zelari", "world", "checks.json"));
|
|
41932
42445
|
} catch {
|
|
41933
42446
|
return false;
|
|
41934
42447
|
}
|
|
@@ -42895,7 +43408,7 @@ __export(prereqChecks_exports, {
|
|
|
42895
43408
|
runPrereqChecks: () => runPrereqChecks
|
|
42896
43409
|
});
|
|
42897
43410
|
import { execSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
42898
|
-
import { existsSync as
|
|
43411
|
+
import { existsSync as existsSync40 } from "node:fs";
|
|
42899
43412
|
import { dirname as dirname8 } from "node:path";
|
|
42900
43413
|
function isWslBashPath2(p3) {
|
|
42901
43414
|
if (!p3 || typeof p3 !== "string") return false;
|
|
@@ -43019,7 +43532,7 @@ function agentProbeEnv() {
|
|
|
43019
43532
|
}
|
|
43020
43533
|
function existsSyncSafe2(p3) {
|
|
43021
43534
|
try {
|
|
43022
|
-
return
|
|
43535
|
+
return existsSync40(p3);
|
|
43023
43536
|
} catch {
|
|
43024
43537
|
return false;
|
|
43025
43538
|
}
|
|
@@ -43266,16 +43779,16 @@ var init_prereqChecks = __esm({
|
|
|
43266
43779
|
});
|
|
43267
43780
|
|
|
43268
43781
|
// src/cli/plugins/prefs.ts
|
|
43269
|
-
import { existsSync as
|
|
43270
|
-
import
|
|
43271
|
-
import
|
|
43782
|
+
import { existsSync as existsSync41, readFileSync as readFileSync34, writeFileSync as writeFileSync22, mkdirSync as mkdirSync18 } from "node:fs";
|
|
43783
|
+
import path45 from "node:path";
|
|
43784
|
+
import os11 from "node:os";
|
|
43272
43785
|
function getPluginPrefsPath() {
|
|
43273
|
-
return process.env.ZELARI_PLUGINS_PREFS_FILE ??
|
|
43786
|
+
return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path45.join(os11.homedir(), ".tmp", "zelari-code", "plugins.json");
|
|
43274
43787
|
}
|
|
43275
43788
|
function getPluginPrefs() {
|
|
43276
43789
|
const file2 = getPluginPrefsPath();
|
|
43277
43790
|
try {
|
|
43278
|
-
if (!
|
|
43791
|
+
if (!existsSync41(file2)) return { ...DEFAULTS2, dontAskAgain: {} };
|
|
43279
43792
|
const raw = readFileSync34(file2, "utf-8");
|
|
43280
43793
|
const parsed = JSON.parse(raw);
|
|
43281
43794
|
if (parsed && typeof parsed === "object" && parsed.dontAskAgain && typeof parsed.dontAskAgain === "object") {
|
|
@@ -43291,7 +43804,7 @@ function getPluginPrefs() {
|
|
|
43291
43804
|
}
|
|
43292
43805
|
function writePluginPrefs(prefs) {
|
|
43293
43806
|
const file2 = getPluginPrefsPath();
|
|
43294
|
-
mkdirSync18(
|
|
43807
|
+
mkdirSync18(path45.dirname(file2), { recursive: true });
|
|
43295
43808
|
writeFileSync22(file2, JSON.stringify(prefs, null, 2), {
|
|
43296
43809
|
encoding: "utf-8",
|
|
43297
43810
|
mode: 384
|
|
@@ -43327,8 +43840,8 @@ __export(registry_exports, {
|
|
|
43327
43840
|
findPlugin: () => findPlugin,
|
|
43328
43841
|
isBinaryOnPath: () => isBinaryOnPath
|
|
43329
43842
|
});
|
|
43330
|
-
import { existsSync as
|
|
43331
|
-
import
|
|
43843
|
+
import { existsSync as existsSync42 } from "node:fs";
|
|
43844
|
+
import path46 from "node:path";
|
|
43332
43845
|
function detectLocalBin(bin) {
|
|
43333
43846
|
return (cwd) => {
|
|
43334
43847
|
try {
|
|
@@ -43344,9 +43857,9 @@ function isBinaryOnPath(bin, opts = {}) {
|
|
|
43344
43857
|
return false;
|
|
43345
43858
|
}
|
|
43346
43859
|
const platform = opts.platform ?? process.platform;
|
|
43347
|
-
const exists = opts.exists ??
|
|
43860
|
+
const exists = opts.exists ?? existsSync42;
|
|
43348
43861
|
const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
|
|
43349
|
-
const pathMod = platform === "win32" ?
|
|
43862
|
+
const pathMod = platform === "win32" ? path46.win32 : path46.posix;
|
|
43350
43863
|
const sep2 = platform === "win32" ? ";" : ":";
|
|
43351
43864
|
const dirs = pathEnv.split(sep2).filter((d) => d.length > 0);
|
|
43352
43865
|
const candidates = [bin];
|
|
@@ -44078,7 +44591,7 @@ __export(atMentions_exports, {
|
|
|
44078
44591
|
extractAtMentions: () => extractAtMentions,
|
|
44079
44592
|
hasAtMentions: () => hasAtMentions
|
|
44080
44593
|
});
|
|
44081
|
-
import { existsSync as
|
|
44594
|
+
import { existsSync as existsSync45, readFileSync as readFileSync36, statSync as statSync8 } from "node:fs";
|
|
44082
44595
|
import { basename as basename3, isAbsolute as isAbsolute2, relative as relative3, resolve, sep } from "node:path";
|
|
44083
44596
|
function isImagePath(abs) {
|
|
44084
44597
|
const ext = abs.split(".").pop()?.toLowerCase() ?? "";
|
|
@@ -44132,7 +44645,7 @@ function resolveMention(token, cwd) {
|
|
|
44132
44645
|
note: "outside project root \u2014 skipped"
|
|
44133
44646
|
};
|
|
44134
44647
|
}
|
|
44135
|
-
if (!
|
|
44648
|
+
if (!existsSync45(abs)) {
|
|
44136
44649
|
return {
|
|
44137
44650
|
raw: token,
|
|
44138
44651
|
path: token,
|
|
@@ -44292,10 +44805,10 @@ __export(triggerLock_exports, {
|
|
|
44292
44805
|
lockPath: () => lockPath,
|
|
44293
44806
|
releaseLock: () => releaseLock
|
|
44294
44807
|
});
|
|
44295
|
-
import { promises as
|
|
44296
|
-
import * as
|
|
44808
|
+
import { promises as fs31 } from "node:fs";
|
|
44809
|
+
import * as path51 from "node:path";
|
|
44297
44810
|
function lockPath(projectRoot) {
|
|
44298
|
-
return
|
|
44811
|
+
return path51.join(projectRoot, ".zelari", "trigger.lock");
|
|
44299
44812
|
}
|
|
44300
44813
|
function isPidAlive(pid) {
|
|
44301
44814
|
try {
|
|
@@ -44308,10 +44821,10 @@ function isPidAlive(pid) {
|
|
|
44308
44821
|
}
|
|
44309
44822
|
async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
|
|
44310
44823
|
const lp = lockPath(projectRoot);
|
|
44311
|
-
const dir =
|
|
44312
|
-
await
|
|
44824
|
+
const dir = path51.dirname(lp);
|
|
44825
|
+
await fs31.mkdir(dir, { recursive: true });
|
|
44313
44826
|
try {
|
|
44314
|
-
const raw = await
|
|
44827
|
+
const raw = await fs31.readFile(lp, "utf8");
|
|
44315
44828
|
const existing = JSON.parse(raw);
|
|
44316
44829
|
if (existing.pid && isPidAlive(existing.pid)) {
|
|
44317
44830
|
return { acquired: false, heldBy: existing.pid, lockPath: lp };
|
|
@@ -44322,13 +44835,13 @@ async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date())
|
|
|
44322
44835
|
pid: process.pid,
|
|
44323
44836
|
acquiredAt: now().toISOString()
|
|
44324
44837
|
};
|
|
44325
|
-
await
|
|
44838
|
+
await fs31.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
44326
44839
|
return { acquired: true, lockPath: lp };
|
|
44327
44840
|
}
|
|
44328
44841
|
async function releaseLock(projectRoot) {
|
|
44329
44842
|
const lp = lockPath(projectRoot);
|
|
44330
44843
|
try {
|
|
44331
|
-
await
|
|
44844
|
+
await fs31.unlink(lp);
|
|
44332
44845
|
} catch {
|
|
44333
44846
|
}
|
|
44334
44847
|
}
|
|
@@ -44692,7 +45205,7 @@ var init_skillCategories = __esm({
|
|
|
44692
45205
|
|
|
44693
45206
|
// src/cli/skillConfigIo.ts
|
|
44694
45207
|
import {
|
|
44695
|
-
existsSync as
|
|
45208
|
+
existsSync as existsSync47,
|
|
44696
45209
|
mkdirSync as mkdirSync21,
|
|
44697
45210
|
readdirSync as readdirSync10,
|
|
44698
45211
|
readFileSync as readFileSync38,
|
|
@@ -44766,7 +45279,7 @@ function entryFromBuiltin(skill) {
|
|
|
44766
45279
|
};
|
|
44767
45280
|
}
|
|
44768
45281
|
function scanSkillsDir(dir, projectRoot, seen, out) {
|
|
44769
|
-
if (!
|
|
45282
|
+
if (!existsSync47(dir)) return;
|
|
44770
45283
|
let entries;
|
|
44771
45284
|
try {
|
|
44772
45285
|
entries = readdirSync10(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -44775,7 +45288,7 @@ function scanSkillsDir(dir, projectRoot, seen, out) {
|
|
|
44775
45288
|
}
|
|
44776
45289
|
for (const entry of entries) {
|
|
44777
45290
|
const skillPath = skillFilePath(dir, entry);
|
|
44778
|
-
if (!
|
|
45291
|
+
if (!existsSync47(skillPath)) continue;
|
|
44779
45292
|
try {
|
|
44780
45293
|
const parsed = parseSkillMd(readFileSync38(skillPath, "utf8"), skillPath);
|
|
44781
45294
|
if (!parsed) continue;
|
|
@@ -44861,7 +45374,7 @@ function upsertSkill(opts) {
|
|
|
44861
45374
|
}
|
|
44862
45375
|
dir = getProjectSkillsDir(root);
|
|
44863
45376
|
}
|
|
44864
|
-
const
|
|
45377
|
+
const path55 = skillFilePath(dir, name);
|
|
44865
45378
|
const content = serializeSkillMd({
|
|
44866
45379
|
name,
|
|
44867
45380
|
description,
|
|
@@ -44870,13 +45383,13 @@ function upsertSkill(opts) {
|
|
|
44870
45383
|
tools: opts.tools,
|
|
44871
45384
|
cost: opts.cost
|
|
44872
45385
|
});
|
|
44873
|
-
const parsed = parseSkillMd(content,
|
|
45386
|
+
const parsed = parseSkillMd(content, path55);
|
|
44874
45387
|
if (!parsed) {
|
|
44875
45388
|
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
44876
45389
|
}
|
|
44877
|
-
mkdirSync21(dirname10(
|
|
44878
|
-
writeFileSync24(
|
|
44879
|
-
return { ok: true, path:
|
|
45390
|
+
mkdirSync21(dirname10(path55), { recursive: true });
|
|
45391
|
+
writeFileSync24(path55, content, "utf8");
|
|
45392
|
+
return { ok: true, path: path55 };
|
|
44880
45393
|
}
|
|
44881
45394
|
function removeSkill(opts) {
|
|
44882
45395
|
const name = opts.name.trim().toLowerCase();
|
|
@@ -44894,8 +45407,8 @@ function removeSkill(opts) {
|
|
|
44894
45407
|
dir = getProjectSkillsDir(root);
|
|
44895
45408
|
}
|
|
44896
45409
|
const skillDir = join37(dir, name);
|
|
44897
|
-
const
|
|
44898
|
-
if (!
|
|
45410
|
+
const path55 = skillFilePath(dir, name);
|
|
45411
|
+
if (!existsSync47(path55) && !existsSync47(skillDir)) {
|
|
44899
45412
|
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
44900
45413
|
}
|
|
44901
45414
|
try {
|
|
@@ -44906,7 +45419,7 @@ function removeSkill(opts) {
|
|
|
44906
45419
|
error: err instanceof Error ? err.message : String(err)
|
|
44907
45420
|
};
|
|
44908
45421
|
}
|
|
44909
|
-
return { ok: true, path:
|
|
45422
|
+
return { ok: true, path: path55 };
|
|
44910
45423
|
}
|
|
44911
45424
|
var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
|
|
44912
45425
|
var init_skillConfigIo = __esm({
|
|
@@ -45200,14 +45713,14 @@ var init_permissionCli = __esm({
|
|
|
45200
45713
|
|
|
45201
45714
|
// src/cli/companion/config.ts
|
|
45202
45715
|
import {
|
|
45203
|
-
existsSync as
|
|
45716
|
+
existsSync as existsSync48,
|
|
45204
45717
|
mkdirSync as mkdirSync22,
|
|
45205
45718
|
readFileSync as readFileSync39,
|
|
45206
45719
|
writeFileSync as writeFileSync25
|
|
45207
45720
|
} from "node:fs";
|
|
45208
45721
|
import { join as join38 } from "node:path";
|
|
45209
45722
|
import { homedir as homedir13 } from "node:os";
|
|
45210
|
-
import { createHash as
|
|
45723
|
+
import { createHash as createHash10, randomBytes as randomBytes5, timingSafeEqual } from "node:crypto";
|
|
45211
45724
|
function getZelariHome() {
|
|
45212
45725
|
return join38(homedir13(), ".zelari-code");
|
|
45213
45726
|
}
|
|
@@ -45219,17 +45732,17 @@ function getCompanionTokenPath() {
|
|
|
45219
45732
|
}
|
|
45220
45733
|
function ensureHome() {
|
|
45221
45734
|
const home = getZelariHome();
|
|
45222
|
-
if (!
|
|
45735
|
+
if (!existsSync48(home)) {
|
|
45223
45736
|
mkdirSync22(home, { recursive: true });
|
|
45224
45737
|
}
|
|
45225
45738
|
}
|
|
45226
45739
|
function loadCompanionConfig() {
|
|
45227
|
-
const
|
|
45228
|
-
if (!
|
|
45740
|
+
const path55 = getCompanionConfigPath();
|
|
45741
|
+
if (!existsSync48(path55)) {
|
|
45229
45742
|
return { projects: [] };
|
|
45230
45743
|
}
|
|
45231
45744
|
try {
|
|
45232
|
-
const raw = JSON.parse(readFileSync39(
|
|
45745
|
+
const raw = JSON.parse(readFileSync39(path55, "utf8"));
|
|
45233
45746
|
const projects = Array.isArray(raw.projects) ? raw.projects.filter(
|
|
45234
45747
|
(p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
|
|
45235
45748
|
).map((p3) => ({
|
|
@@ -45267,24 +45780,24 @@ function loadOrCreateToken(explicit) {
|
|
|
45267
45780
|
return { token: explicit.trim(), created: false };
|
|
45268
45781
|
}
|
|
45269
45782
|
ensureHome();
|
|
45270
|
-
const
|
|
45271
|
-
if (
|
|
45272
|
-
const t = readFileSync39(
|
|
45783
|
+
const path55 = getCompanionTokenPath();
|
|
45784
|
+
if (existsSync48(path55)) {
|
|
45785
|
+
const t = readFileSync39(path55, "utf8").trim();
|
|
45273
45786
|
if (t) return { token: t, created: false };
|
|
45274
45787
|
}
|
|
45275
45788
|
const token = randomBytes5(24).toString("base64url");
|
|
45276
|
-
writeFileSync25(
|
|
45789
|
+
writeFileSync25(path55, token + "\n", "utf8");
|
|
45277
45790
|
try {
|
|
45278
|
-
const
|
|
45279
|
-
|
|
45791
|
+
const fs33 = __require("node:fs");
|
|
45792
|
+
fs33.chmodSync?.(path55, 384);
|
|
45280
45793
|
} catch {
|
|
45281
45794
|
}
|
|
45282
45795
|
return { token, created: true };
|
|
45283
45796
|
}
|
|
45284
45797
|
function tokenMatches(expected, provided) {
|
|
45285
45798
|
if (!provided) return false;
|
|
45286
|
-
const a =
|
|
45287
|
-
const b =
|
|
45799
|
+
const a = createHash10("sha256").update(expected).digest();
|
|
45800
|
+
const b = createHash10("sha256").update(provided).digest();
|
|
45288
45801
|
try {
|
|
45289
45802
|
return timingSafeEqual(a, b);
|
|
45290
45803
|
} catch {
|
|
@@ -45301,17 +45814,17 @@ function mergeProjects(cfg, extraPaths) {
|
|
|
45301
45814
|
byId.set(p3.id, p3);
|
|
45302
45815
|
}
|
|
45303
45816
|
for (const raw of extraPaths) {
|
|
45304
|
-
const
|
|
45305
|
-
if (!
|
|
45306
|
-
let id = slugFromPath(
|
|
45817
|
+
const path55 = raw.trim();
|
|
45818
|
+
if (!path55) continue;
|
|
45819
|
+
let id = slugFromPath(path55);
|
|
45307
45820
|
let n = 2;
|
|
45308
|
-
while (byId.has(id) && byId.get(id).path !==
|
|
45309
|
-
id = `${slugFromPath(
|
|
45821
|
+
while (byId.has(id) && byId.get(id).path !== path55) {
|
|
45822
|
+
id = `${slugFromPath(path55)}-${n++}`;
|
|
45310
45823
|
}
|
|
45311
45824
|
byId.set(id, {
|
|
45312
45825
|
id,
|
|
45313
|
-
name: slugFromPath(
|
|
45314
|
-
path:
|
|
45826
|
+
name: slugFromPath(path55),
|
|
45827
|
+
path: path55
|
|
45315
45828
|
});
|
|
45316
45829
|
}
|
|
45317
45830
|
return [...byId.values()];
|
|
@@ -45359,7 +45872,7 @@ var init_config = __esm({
|
|
|
45359
45872
|
});
|
|
45360
45873
|
|
|
45361
45874
|
// src/cli/companion/runManager.ts
|
|
45362
|
-
import { spawn as
|
|
45875
|
+
import { spawn as spawn15 } from "node:child_process";
|
|
45363
45876
|
import { createInterface as createInterface2 } from "node:readline";
|
|
45364
45877
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
45365
45878
|
import { writeFileSync as writeFileSync26, unlinkSync as unlinkSync3 } from "node:fs";
|
|
@@ -45475,7 +45988,7 @@ var init_runManager = __esm({
|
|
|
45475
45988
|
historyFile = void 0;
|
|
45476
45989
|
}
|
|
45477
45990
|
}
|
|
45478
|
-
const child =
|
|
45991
|
+
const child = spawn15(process.execPath, argv, {
|
|
45479
45992
|
cwd: args.cwd,
|
|
45480
45993
|
env: {
|
|
45481
45994
|
...process.env,
|
|
@@ -45594,7 +46107,7 @@ __export(serve_exports, {
|
|
|
45594
46107
|
runCompanionServe: () => runCompanionServe
|
|
45595
46108
|
});
|
|
45596
46109
|
import { createServer as createServer3 } from "node:http";
|
|
45597
|
-
import { existsSync as
|
|
46110
|
+
import { existsSync as existsSync49 } from "node:fs";
|
|
45598
46111
|
import { resolve as resolve2 } from "node:path";
|
|
45599
46112
|
function readBody(req, max = 2e6) {
|
|
45600
46113
|
return new Promise((resolveBody, reject) => {
|
|
@@ -45642,7 +46155,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
45642
46155
|
let projects = mergeProjects(fileCfg, opts.projects ?? []);
|
|
45643
46156
|
projects = projects.filter((p3) => {
|
|
45644
46157
|
const abs = resolve2(p3.path);
|
|
45645
|
-
if (!
|
|
46158
|
+
if (!existsSync49(abs)) {
|
|
45646
46159
|
process.stderr.write(
|
|
45647
46160
|
`[zelari-code serve] skip missing project path: ${p3.path}
|
|
45648
46161
|
`
|
|
@@ -45688,9 +46201,9 @@ async function runCompanionServe(opts = {}) {
|
|
|
45688
46201
|
return;
|
|
45689
46202
|
}
|
|
45690
46203
|
const url2 = parseUrl(req);
|
|
45691
|
-
const
|
|
46204
|
+
const path55 = url2.pathname.replace(/\/+$/, "") || "/";
|
|
45692
46205
|
try {
|
|
45693
|
-
if (req.method === "GET" && (
|
|
46206
|
+
if (req.method === "GET" && (path55 === "/health" || path55 === "/v1/health")) {
|
|
45694
46207
|
sendJson2(res, 200, {
|
|
45695
46208
|
ok: true,
|
|
45696
46209
|
service: "zelari-companion",
|
|
@@ -45702,18 +46215,18 @@ async function runCompanionServe(opts = {}) {
|
|
|
45702
46215
|
});
|
|
45703
46216
|
return;
|
|
45704
46217
|
}
|
|
45705
|
-
if (
|
|
46218
|
+
if (path55.startsWith("/v1")) {
|
|
45706
46219
|
if (!tokenMatches(token, getBearer(req))) {
|
|
45707
46220
|
sendJson2(res, 401, { ok: false, error: "unauthorized" });
|
|
45708
46221
|
return;
|
|
45709
46222
|
}
|
|
45710
46223
|
}
|
|
45711
|
-
if (req.method === "GET" &&
|
|
46224
|
+
if (req.method === "GET" && path55 === "/v1/config") {
|
|
45712
46225
|
const snap = buildDesktopConfigSnapshot();
|
|
45713
46226
|
sendJson2(res, 200, { ok: true, ...snap });
|
|
45714
46227
|
return;
|
|
45715
46228
|
}
|
|
45716
|
-
if (req.method === "GET" &&
|
|
46229
|
+
if (req.method === "GET" && path55 === "/v1/projects") {
|
|
45717
46230
|
sendJson2(res, 200, {
|
|
45718
46231
|
ok: true,
|
|
45719
46232
|
projects: projects.map((p3) => ({
|
|
@@ -45724,7 +46237,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
45724
46237
|
});
|
|
45725
46238
|
return;
|
|
45726
46239
|
}
|
|
45727
|
-
if (req.method === "GET" &&
|
|
46240
|
+
if (req.method === "GET" && path55 === "/v1/runs") {
|
|
45728
46241
|
sendJson2(res, 200, {
|
|
45729
46242
|
ok: true,
|
|
45730
46243
|
active: runs.getActive(),
|
|
@@ -45742,7 +46255,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
45742
46255
|
});
|
|
45743
46256
|
return;
|
|
45744
46257
|
}
|
|
45745
|
-
if (req.method === "POST" &&
|
|
46258
|
+
if (req.method === "POST" && path55 === "/v1/runs") {
|
|
45746
46259
|
const raw = await readBody(req);
|
|
45747
46260
|
let body = {};
|
|
45748
46261
|
try {
|
|
@@ -45789,7 +46302,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
45789
46302
|
});
|
|
45790
46303
|
return;
|
|
45791
46304
|
}
|
|
45792
|
-
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(
|
|
46305
|
+
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path55);
|
|
45793
46306
|
if (req.method === "GET" && eventsMatch) {
|
|
45794
46307
|
const runId = eventsMatch[1];
|
|
45795
46308
|
const run = runs.getRun(runId);
|
|
@@ -45854,7 +46367,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
45854
46367
|
}, 500);
|
|
45855
46368
|
return;
|
|
45856
46369
|
}
|
|
45857
|
-
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(
|
|
46370
|
+
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path55);
|
|
45858
46371
|
if (req.method === "POST" && cancelMatch) {
|
|
45859
46372
|
const runId = cancelMatch[1];
|
|
45860
46373
|
const result = runs.cancel(runId);
|
|
@@ -45964,26 +46477,26 @@ __export(doctor_exports, {
|
|
|
45964
46477
|
runDoctor: () => runDoctor
|
|
45965
46478
|
});
|
|
45966
46479
|
import { execSync as execSync2 } from "node:child_process";
|
|
45967
|
-
import { existsSync as
|
|
46480
|
+
import { existsSync as existsSync50, readFileSync as readFileSync40, readlinkSync, statSync as statSync9 } from "node:fs";
|
|
45968
46481
|
import { createRequire as createRequire3 } from "node:module";
|
|
45969
46482
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
45970
|
-
import
|
|
46483
|
+
import path53 from "node:path";
|
|
45971
46484
|
function findPackageRoot(start) {
|
|
45972
46485
|
let dir = start;
|
|
45973
46486
|
for (let i = 0; i < 6; i += 1) {
|
|
45974
|
-
const candidate =
|
|
45975
|
-
if (
|
|
46487
|
+
const candidate = path53.join(dir, "package.json");
|
|
46488
|
+
if (existsSync50(candidate)) {
|
|
45976
46489
|
try {
|
|
45977
46490
|
const pkg = JSON.parse(readFileSync40(candidate, "utf8"));
|
|
45978
46491
|
if (pkg.name === "zelari-code") return dir;
|
|
45979
46492
|
} catch {
|
|
45980
46493
|
}
|
|
45981
46494
|
}
|
|
45982
|
-
const parent =
|
|
46495
|
+
const parent = path53.dirname(dir);
|
|
45983
46496
|
if (parent === dir) break;
|
|
45984
46497
|
dir = parent;
|
|
45985
46498
|
}
|
|
45986
|
-
return
|
|
46499
|
+
return path53.resolve(__dirname3, "..", "..", "..");
|
|
45987
46500
|
}
|
|
45988
46501
|
function tryExec(cmd) {
|
|
45989
46502
|
try {
|
|
@@ -45997,7 +46510,7 @@ function tryExec(cmd) {
|
|
|
45997
46510
|
}
|
|
45998
46511
|
function readPackageJson3() {
|
|
45999
46512
|
try {
|
|
46000
|
-
const pkgPath =
|
|
46513
|
+
const pkgPath = path53.join(packageRoot, "package.json");
|
|
46001
46514
|
return JSON.parse(readFileSync40(pkgPath, "utf8"));
|
|
46002
46515
|
} catch {
|
|
46003
46516
|
return null;
|
|
@@ -46013,8 +46526,8 @@ function checkShim(pkgName) {
|
|
|
46013
46526
|
}
|
|
46014
46527
|
const isWin = process.platform === "win32";
|
|
46015
46528
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
46016
|
-
const shimPath =
|
|
46017
|
-
if (!
|
|
46529
|
+
const shimPath = path53.join(prefix, shimName);
|
|
46530
|
+
if (!existsSync50(shimPath)) {
|
|
46018
46531
|
return FAIL(
|
|
46019
46532
|
`shim not found at ${shimPath}
|
|
46020
46533
|
fix: npm install -g ${pkgName}@latest --force`
|
|
@@ -46041,8 +46554,8 @@ function checkShim(pkgName) {
|
|
|
46041
46554
|
fix: npm install -g ${pkgName}@latest --force`
|
|
46042
46555
|
);
|
|
46043
46556
|
}
|
|
46044
|
-
const resolved =
|
|
46045
|
-
const expected =
|
|
46557
|
+
const resolved = path53.resolve(path53.dirname(shimPath), target);
|
|
46558
|
+
const expected = path53.join(
|
|
46046
46559
|
prefix,
|
|
46047
46560
|
"node_modules",
|
|
46048
46561
|
pkgName,
|
|
@@ -46081,8 +46594,8 @@ function checkNode(pkg) {
|
|
|
46081
46594
|
return OK(`node ${raw}`);
|
|
46082
46595
|
}
|
|
46083
46596
|
function checkBundle() {
|
|
46084
|
-
const bundle =
|
|
46085
|
-
if (!
|
|
46597
|
+
const bundle = path53.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
46598
|
+
if (!existsSync50(bundle)) {
|
|
46086
46599
|
return FAIL(
|
|
46087
46600
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
46088
46601
|
fix: npm run build:cli (then reinstall or run via tsx)`
|
|
@@ -46102,7 +46615,7 @@ function checkRuntimeDeps() {
|
|
|
46102
46615
|
const missing = [];
|
|
46103
46616
|
for (const dep of required2) {
|
|
46104
46617
|
try {
|
|
46105
|
-
const localReq = createRequire3(
|
|
46618
|
+
const localReq = createRequire3(path53.join(packageRoot, "package.json"));
|
|
46106
46619
|
localReq.resolve(dep);
|
|
46107
46620
|
} catch {
|
|
46108
46621
|
missing.push(dep);
|
|
@@ -46278,7 +46791,7 @@ var init_doctor = __esm({
|
|
|
46278
46791
|
"use strict";
|
|
46279
46792
|
init_prereqChecks();
|
|
46280
46793
|
require3 = createRequire3(import.meta.url);
|
|
46281
|
-
__dirname3 =
|
|
46794
|
+
__dirname3 = path53.dirname(fileURLToPath2(import.meta.url));
|
|
46282
46795
|
packageRoot = findPackageRoot(__dirname3);
|
|
46283
46796
|
OK = (message) => ({
|
|
46284
46797
|
ok: true,
|
|
@@ -46462,15 +46975,15 @@ __export(inspect_exports, {
|
|
|
46462
46975
|
collectInspectReport: () => collectInspectReport,
|
|
46463
46976
|
runInspect: () => runInspect
|
|
46464
46977
|
});
|
|
46465
|
-
import
|
|
46466
|
-
import { existsSync as
|
|
46978
|
+
import path54 from "node:path";
|
|
46979
|
+
import { existsSync as existsSync51, readFileSync as readFileSync41, readdirSync as readdirSync11 } from "node:fs";
|
|
46467
46980
|
import { homedir as homedir14 } from "node:os";
|
|
46468
46981
|
async function collectInspectReport(cwd = process.cwd()) {
|
|
46469
46982
|
ensureBuiltinSkillsLoadedSync();
|
|
46470
46983
|
const snap = listSkillsSnapshot(cwd);
|
|
46471
46984
|
const mcp = listMcpServers(cwd);
|
|
46472
|
-
const userMcpPath =
|
|
46473
|
-
const projectMcpPath =
|
|
46985
|
+
const userMcpPath = path54.join(homedir14(), ".zelari-code", "mcp.json");
|
|
46986
|
+
const projectMcpPath = path54.join(cwd, ".zelari", "mcp.json");
|
|
46474
46987
|
const globalHooks = globalHooksDir();
|
|
46475
46988
|
const projectHooks = projectHooksDir(cwd);
|
|
46476
46989
|
const projectTrusted = isFolderTrusted(cwd);
|
|
@@ -46496,11 +47009,11 @@ async function collectInspectReport(cwd = process.cwd()) {
|
|
|
46496
47009
|
folders: listTrustedFolders()
|
|
46497
47010
|
},
|
|
46498
47011
|
configSources: [
|
|
46499
|
-
{ path: userMcpPath, exists:
|
|
46500
|
-
{ path: projectMcpPath, exists:
|
|
46501
|
-
{ path:
|
|
46502
|
-
{ path:
|
|
46503
|
-
{ path:
|
|
47012
|
+
{ path: userMcpPath, exists: existsSync51(userMcpPath) },
|
|
47013
|
+
{ path: projectMcpPath, exists: existsSync51(projectMcpPath) },
|
|
47014
|
+
{ path: path54.join(homedir14(), ".zelari-code", "provider.json"), exists: existsSync51(path54.join(homedir14(), ".zelari-code", "provider.json")) },
|
|
47015
|
+
{ path: path54.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync51(path54.join(cwd, ".zelari", "AGENTS.md")) },
|
|
47016
|
+
{ path: path54.join(cwd, "AGENTS.md"), exists: existsSync51(path54.join(cwd, "AGENTS.md")) }
|
|
46504
47017
|
],
|
|
46505
47018
|
skills: {
|
|
46506
47019
|
total: snap.skills.length,
|
|
@@ -46513,7 +47026,7 @@ async function collectInspectReport(cwd = process.cwd()) {
|
|
|
46513
47026
|
user: mcp.servers.filter((s) => s.scope === "user").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
|
|
46514
47027
|
project: mcp.servers.filter((s) => s.scope === "project").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
|
|
46515
47028
|
projectTrusted,
|
|
46516
|
-
projectConfigExists:
|
|
47029
|
+
projectConfigExists: existsSync51(projectMcpPath)
|
|
46517
47030
|
},
|
|
46518
47031
|
hooks: {
|
|
46519
47032
|
global: {
|
|
@@ -46540,12 +47053,12 @@ function listJsonFiles(dir) {
|
|
|
46540
47053
|
}
|
|
46541
47054
|
function findAgentsMd(cwd) {
|
|
46542
47055
|
const candidates = [
|
|
46543
|
-
|
|
46544
|
-
|
|
47056
|
+
path54.join(cwd, "AGENTS.md"),
|
|
47057
|
+
path54.join(cwd, ".zelari", "AGENTS.md")
|
|
46545
47058
|
];
|
|
46546
47059
|
const found = [];
|
|
46547
47060
|
for (const c of candidates) {
|
|
46548
|
-
if (
|
|
47061
|
+
if (existsSync51(c)) {
|
|
46549
47062
|
try {
|
|
46550
47063
|
const text = readFileSync41(c, "utf8");
|
|
46551
47064
|
found.push(`${c} (${text.length} bytes)`);
|
|
@@ -50321,6 +50834,8 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
50321
50834
|
"You are in PLAN mode. Explore and design only.",
|
|
50322
50835
|
"- Do NOT implement production code or run destructive shell commands.",
|
|
50323
50836
|
"- write_file / edit_file / bash / apply_diff are unavailable.",
|
|
50837
|
+
"- inspect_command IS available: allowlisted read-only inspector (no shell). Use it for git_status/git_log/git_diff/git_show/git_branch_current/git_ls_files/typecheck/node_version/npm_ls/npm_outdated/npm_view - it turns claims into execution-verified observations.",
|
|
50838
|
+
"- OBSERVATION INTEGRITY: negative evidence is valid only from a completed observation. Never conclude that code/symbols/files do not exist from degraded results, zero files examined, or unavailable backends (grep_content SEARCH_EMPTY_SCOPE, ast/LSP degraded status, inspect_command unsupported shapes).",
|
|
50324
50839
|
"- Produce a clear plan, ask clarifying questions (---QUESTION---), use workspace plan tools when relevant.",
|
|
50325
50840
|
"- When the plan is ready, tell the user to run /build to implement."
|
|
50326
50841
|
].join("\n") : workPhase === "build" ? [
|
|
@@ -52423,7 +52938,7 @@ init_messageHelpers();
|
|
|
52423
52938
|
// src/cli/gitOps.ts
|
|
52424
52939
|
import { execFile as execFile4 } from "node:child_process";
|
|
52425
52940
|
import { promisify as promisify3 } from "node:util";
|
|
52426
|
-
import
|
|
52941
|
+
import path39 from "node:path";
|
|
52427
52942
|
var execFileAsync3 = promisify3(execFile4);
|
|
52428
52943
|
async function git3(cwd, args) {
|
|
52429
52944
|
try {
|
|
@@ -52469,7 +52984,7 @@ async function undoWorkingChanges(opts = {}) {
|
|
|
52469
52984
|
};
|
|
52470
52985
|
}
|
|
52471
52986
|
function defaultProjectRoot() {
|
|
52472
|
-
return
|
|
52987
|
+
return path39.resolve(__dirname, "..", "..", "..");
|
|
52473
52988
|
}
|
|
52474
52989
|
|
|
52475
52990
|
// src/cli/slashHandlers/git.ts
|
|
@@ -52914,13 +53429,13 @@ ${digest}
|
|
|
52914
53429
|
init_auditLogger();
|
|
52915
53430
|
init_toolRegistry();
|
|
52916
53431
|
init_messageHelpers();
|
|
52917
|
-
import { promises as
|
|
53432
|
+
import { promises as fs25 } from "node:fs";
|
|
52918
53433
|
|
|
52919
53434
|
// src/cli/tools/krakenCsvFanout.ts
|
|
52920
53435
|
init_zod();
|
|
52921
53436
|
init_taskTool();
|
|
52922
|
-
import { promises as
|
|
52923
|
-
import
|
|
53437
|
+
import { promises as fs24 } from "node:fs";
|
|
53438
|
+
import path43 from "node:path";
|
|
52924
53439
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
52925
53440
|
var CsvFanoutArgsSchema = external_exports.object({
|
|
52926
53441
|
csv_path: external_exports.string().min(1),
|
|
@@ -52941,7 +53456,7 @@ var CsvFanoutArgsSchema = external_exports.object({
|
|
|
52941
53456
|
max_runtime_seconds: external_exports.number().int().positive().optional()
|
|
52942
53457
|
});
|
|
52943
53458
|
async function readCsv(filePath) {
|
|
52944
|
-
const text = await
|
|
53459
|
+
const text = await fs24.readFile(filePath, "utf8");
|
|
52945
53460
|
return parseCsv(text);
|
|
52946
53461
|
}
|
|
52947
53462
|
function parseCsv(text) {
|
|
@@ -53014,8 +53529,8 @@ function resolveMaxConcurrency(env = process.env) {
|
|
|
53014
53529
|
}
|
|
53015
53530
|
async function runCsvFanout(args, deps, opts) {
|
|
53016
53531
|
const start = Date.now();
|
|
53017
|
-
const absCsv =
|
|
53018
|
-
const absOut =
|
|
53532
|
+
const absCsv = path43.isAbsolute(args.csv_path) ? args.csv_path : path43.join(opts.parentCwd, args.csv_path);
|
|
53533
|
+
const absOut = path43.isAbsolute(args.output_csv_path) ? args.output_csv_path : path43.join(opts.parentCwd, args.output_csv_path);
|
|
53019
53534
|
const { headers: headers2, rows } = await readCsv(absCsv);
|
|
53020
53535
|
if (headers2.length === 0) {
|
|
53021
53536
|
throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
|
|
@@ -53071,7 +53586,7 @@ async function runCsvFanout(args, deps, opts) {
|
|
|
53071
53586
|
errored += 1;
|
|
53072
53587
|
errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
|
|
53073
53588
|
}
|
|
53074
|
-
await
|
|
53589
|
+
await fs24.mkdir(path43.dirname(absOut), { recursive: true });
|
|
53075
53590
|
await queueWrite(serializeCsv(outHeaders, outputRecords));
|
|
53076
53591
|
}
|
|
53077
53592
|
}
|
|
@@ -53093,8 +53608,8 @@ async function runCsvFanout(args, deps, opts) {
|
|
|
53093
53608
|
}
|
|
53094
53609
|
async function atomicWrite(file2, contents) {
|
|
53095
53610
|
const tmp = `${file2}.${process.pid}.${Date.now()}.${randomBytes4(6).toString("hex")}.tmp`;
|
|
53096
|
-
await
|
|
53097
|
-
await
|
|
53611
|
+
await fs24.writeFile(tmp, contents, "utf8");
|
|
53612
|
+
await fs24.rename(tmp, file2);
|
|
53098
53613
|
}
|
|
53099
53614
|
|
|
53100
53615
|
// src/cli/slashHandlers/krakenFanout.ts
|
|
@@ -53192,7 +53707,7 @@ async function handleKrakenFanout(ctx, raw) {
|
|
|
53192
53707
|
}
|
|
53193
53708
|
const absCsv = isAbsolute(parsed.args.csv_path) ? parsed.args.csv_path : joinPath(ctx.cwd, parsed.args.csv_path);
|
|
53194
53709
|
try {
|
|
53195
|
-
await
|
|
53710
|
+
await fs25.access(absCsv);
|
|
53196
53711
|
} catch {
|
|
53197
53712
|
appendSystem(ctx.setMessages, `[kraken fanout] source CSV not found: ${absCsv}`);
|
|
53198
53713
|
return;
|
|
@@ -53265,8 +53780,8 @@ function splitArgs(s) {
|
|
|
53265
53780
|
|
|
53266
53781
|
// src/cli/slashHandlers/krakenWorkbench.ts
|
|
53267
53782
|
init_messageHelpers();
|
|
53268
|
-
import { promises as
|
|
53269
|
-
import
|
|
53783
|
+
import { promises as fs26 } from "node:fs";
|
|
53784
|
+
import path44 from "node:path";
|
|
53270
53785
|
|
|
53271
53786
|
// src/cli/kraken/workbenchView.ts
|
|
53272
53787
|
var EMPTY = {
|
|
@@ -53383,15 +53898,15 @@ function formatWorkbenchForTerminal(p3) {
|
|
|
53383
53898
|
|
|
53384
53899
|
// src/cli/slashHandlers/krakenWorkbench.ts
|
|
53385
53900
|
async function handleKrakenWorkbench(ctx) {
|
|
53386
|
-
const dir =
|
|
53901
|
+
const dir = path44.join(ctx.cwd, ".zelari", "radio");
|
|
53387
53902
|
let latest = null;
|
|
53388
53903
|
let latestMtime = 0;
|
|
53389
53904
|
try {
|
|
53390
|
-
const files = await
|
|
53905
|
+
const files = await fs26.readdir(dir);
|
|
53391
53906
|
for (const f of files) {
|
|
53392
53907
|
if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
|
|
53393
|
-
const full =
|
|
53394
|
-
const stat = await
|
|
53908
|
+
const full = path44.join(dir, f);
|
|
53909
|
+
const stat = await fs26.stat(full);
|
|
53395
53910
|
if (stat.mtimeMs > latestMtime) {
|
|
53396
53911
|
latestMtime = stat.mtimeMs;
|
|
53397
53912
|
latest = full;
|
|
@@ -53403,14 +53918,14 @@ async function handleKrakenWorkbench(ctx) {
|
|
|
53403
53918
|
appendSystem(ctx.setMessages, "[kraken workbench] no workbench file found (.zelari/radio/workbench-*.md)");
|
|
53404
53919
|
return;
|
|
53405
53920
|
}
|
|
53406
|
-
const content = await
|
|
53921
|
+
const content = await fs26.readFile(latest, "utf8");
|
|
53407
53922
|
const parsed = parseWorkbench(content);
|
|
53408
53923
|
const rendered = formatWorkbenchForTerminal(parsed);
|
|
53409
53924
|
if (!rendered.trim()) {
|
|
53410
|
-
appendSystem(ctx.setMessages, `[kraken workbench] ${
|
|
53925
|
+
appendSystem(ctx.setMessages, `[kraken workbench] ${path44.basename(latest)}: (no nodes / no events yet)`);
|
|
53411
53926
|
return;
|
|
53412
53927
|
}
|
|
53413
|
-
appendSystem(ctx.setMessages, `[kraken workbench] ${
|
|
53928
|
+
appendSystem(ctx.setMessages, `[kraken workbench] ${path44.basename(latest)}:
|
|
53414
53929
|
${rendered}`);
|
|
53415
53930
|
}
|
|
53416
53931
|
|
|
@@ -53564,8 +54079,8 @@ init_registry3();
|
|
|
53564
54079
|
// src/cli/plugins/installer.ts
|
|
53565
54080
|
init_cmdline();
|
|
53566
54081
|
init_updater();
|
|
53567
|
-
import { spawn as
|
|
53568
|
-
async function installPlugin(spec, cwd, executor =
|
|
54082
|
+
import { spawn as spawn14 } from "node:child_process";
|
|
54083
|
+
async function installPlugin(spec, cwd, executor = spawn14) {
|
|
53569
54084
|
const scopeFlag = spec.installScope === "global" ? "-g" : "-D";
|
|
53570
54085
|
const args = ["install", scopeFlag, spec.npmPackage];
|
|
53571
54086
|
let result = await runNpm2(executor, args, cwd, "shim");
|
|
@@ -53715,17 +54230,17 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
|
|
|
53715
54230
|
|
|
53716
54231
|
// src/cli/slashHandlers/promoteMember.ts
|
|
53717
54232
|
init_messageHelpers();
|
|
53718
|
-
import { promises as
|
|
53719
|
-
import
|
|
53720
|
-
import
|
|
54233
|
+
import { promises as fs27 } from "node:fs";
|
|
54234
|
+
import path47 from "node:path";
|
|
54235
|
+
import os12 from "node:os";
|
|
53721
54236
|
async function handlePromoteMember(ctx, memberId) {
|
|
53722
54237
|
try {
|
|
53723
54238
|
const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
53724
54239
|
const { skill, markdown } = promoteMember2(memberId);
|
|
53725
|
-
const skillDir = process.env.ANATHEMA_SKILL_DIR ??
|
|
53726
|
-
await
|
|
53727
|
-
const filePath =
|
|
53728
|
-
await
|
|
54240
|
+
const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path47.join(os12.homedir(), ".tmp", "zelari-code", "skills");
|
|
54241
|
+
await fs27.mkdir(skillDir, { recursive: true });
|
|
54242
|
+
const filePath = path47.join(skillDir, `${skill.id}.md`);
|
|
54243
|
+
await fs27.writeFile(filePath, markdown, "utf8");
|
|
53729
54244
|
appendSystem(
|
|
53730
54245
|
ctx.setMessages,
|
|
53731
54246
|
`[promote-member] ${skill.name} (${memberId}) \u2192 ${filePath}
|
|
@@ -53741,29 +54256,29 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
53741
54256
|
}
|
|
53742
54257
|
|
|
53743
54258
|
// src/cli/branchManager.ts
|
|
53744
|
-
import { promises as
|
|
53745
|
-
import
|
|
53746
|
-
import
|
|
54259
|
+
import { promises as fs28, existsSync as existsSync43, readFileSync as readFileSync35, writeFileSync as writeFileSync23, mkdirSync as mkdirSync19, statSync as statSync6, rmSync as rmSync3 } from "node:fs";
|
|
54260
|
+
import path48 from "node:path";
|
|
54261
|
+
import os13 from "node:os";
|
|
53747
54262
|
var META_FILENAME = "meta.json";
|
|
53748
54263
|
var SESSIONS_SUBDIR = "sessions";
|
|
53749
54264
|
function getBranchesBaseDir() {
|
|
53750
|
-
return process.env.ANATHEMA_BRANCHES_DIR ??
|
|
54265
|
+
return process.env.ANATHEMA_BRANCHES_DIR ?? path48.join(os13.homedir(), ".tmp", "zelari-code", "branches");
|
|
53751
54266
|
}
|
|
53752
54267
|
function getSessionsBaseDir() {
|
|
53753
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
54268
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path48.join(os13.homedir(), ".tmp", "zelari-code", "sessions");
|
|
53754
54269
|
}
|
|
53755
54270
|
function branchPathFor(name, baseDir) {
|
|
53756
|
-
return
|
|
54271
|
+
return path48.join(baseDir, name);
|
|
53757
54272
|
}
|
|
53758
54273
|
function metaPathFor(name, baseDir) {
|
|
53759
|
-
return
|
|
54274
|
+
return path48.join(baseDir, name, META_FILENAME);
|
|
53760
54275
|
}
|
|
53761
54276
|
function sessionsPathFor(name, baseDir) {
|
|
53762
|
-
return
|
|
54277
|
+
return path48.join(baseDir, name, SESSIONS_SUBDIR);
|
|
53763
54278
|
}
|
|
53764
54279
|
function readBranchMeta(name, baseDir) {
|
|
53765
54280
|
const metaPath = metaPathFor(name, baseDir);
|
|
53766
|
-
if (!
|
|
54281
|
+
if (!existsSync43(metaPath)) {
|
|
53767
54282
|
throw new BranchNotFoundError(`Branch "${name}" not found`);
|
|
53768
54283
|
}
|
|
53769
54284
|
try {
|
|
@@ -53784,13 +54299,13 @@ function readBranchMeta(name, baseDir) {
|
|
|
53784
54299
|
}
|
|
53785
54300
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
53786
54301
|
const metaPath = metaPathFor(name, baseDir);
|
|
53787
|
-
mkdirSync19(
|
|
54302
|
+
mkdirSync19(path48.dirname(metaPath), { recursive: true });
|
|
53788
54303
|
writeFileSync23(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
53789
54304
|
}
|
|
53790
54305
|
async function countSessions(name, baseDir) {
|
|
53791
54306
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
53792
54307
|
try {
|
|
53793
|
-
const entries = await
|
|
54308
|
+
const entries = await fs28.readdir(sessionsPath);
|
|
53794
54309
|
return entries.filter((e) => e.endsWith(".jsonl")).length;
|
|
53795
54310
|
} catch (err) {
|
|
53796
54311
|
if (err.code === "ENOENT") return 0;
|
|
@@ -53823,7 +54338,7 @@ var SessionNotFoundError = class extends Error {
|
|
|
53823
54338
|
};
|
|
53824
54339
|
function branchExists(name, baseDir = getBranchesBaseDir()) {
|
|
53825
54340
|
const bp = branchPathFor(name, baseDir);
|
|
53826
|
-
return
|
|
54341
|
+
return existsSync43(bp) && existsSync43(metaPathFor(name, baseDir));
|
|
53827
54342
|
}
|
|
53828
54343
|
async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(), sessionsBaseDir = getSessionsBaseDir()) {
|
|
53829
54344
|
if (!name || name.trim().length === 0) {
|
|
@@ -53835,15 +54350,15 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
53835
54350
|
if (branchExists(name, baseDir)) {
|
|
53836
54351
|
throw new BranchAlreadyExistsError(name);
|
|
53837
54352
|
}
|
|
53838
|
-
const sourcePath =
|
|
53839
|
-
if (!
|
|
54353
|
+
const sourcePath = path48.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
54354
|
+
if (!existsSync43(sourcePath)) {
|
|
53840
54355
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
53841
54356
|
}
|
|
53842
54357
|
const branchPath = branchPathFor(name, baseDir);
|
|
53843
54358
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
53844
54359
|
mkdirSync19(branchSessionsPath, { recursive: true });
|
|
53845
|
-
const destPath =
|
|
53846
|
-
await
|
|
54360
|
+
const destPath = path48.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
54361
|
+
await fs28.copyFile(sourcePath, destPath);
|
|
53847
54362
|
const meta3 = {
|
|
53848
54363
|
name,
|
|
53849
54364
|
createdAt: Date.now(),
|
|
@@ -53861,7 +54376,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
53861
54376
|
async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
53862
54377
|
let entries;
|
|
53863
54378
|
try {
|
|
53864
|
-
entries = await
|
|
54379
|
+
entries = await fs28.readdir(baseDir);
|
|
53865
54380
|
} catch (err) {
|
|
53866
54381
|
if (err.code === "ENOENT") return [];
|
|
53867
54382
|
throw err;
|
|
@@ -53869,7 +54384,7 @@ async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
|
53869
54384
|
const results = [];
|
|
53870
54385
|
for (const entry of entries) {
|
|
53871
54386
|
const metaPath = metaPathFor(entry, baseDir);
|
|
53872
|
-
if (!
|
|
54387
|
+
if (!existsSync43(metaPath)) continue;
|
|
53873
54388
|
try {
|
|
53874
54389
|
const meta3 = readBranchMeta(entry, baseDir);
|
|
53875
54390
|
const sessionCount = await countSessions(entry, baseDir);
|
|
@@ -53944,26 +54459,26 @@ async function handleBranchCheckout(ctx, branchName) {
|
|
|
53944
54459
|
|
|
53945
54460
|
// src/cli/slashHandlers/workspace.ts
|
|
53946
54461
|
init_messageHelpers();
|
|
53947
|
-
import { promises as
|
|
53948
|
-
import
|
|
54462
|
+
import { promises as fs29 } from "node:fs";
|
|
54463
|
+
import path49 from "node:path";
|
|
53949
54464
|
async function handleWorkspaceShow(ctx, what) {
|
|
53950
54465
|
try {
|
|
53951
|
-
const zelari =
|
|
54466
|
+
const zelari = path49.join(process.cwd(), ".zelari");
|
|
53952
54467
|
let content;
|
|
53953
54468
|
switch (what) {
|
|
53954
54469
|
case "plan": {
|
|
53955
|
-
const planPath =
|
|
54470
|
+
const planPath = path49.join(zelari, "plan.md");
|
|
53956
54471
|
try {
|
|
53957
|
-
content = await
|
|
54472
|
+
content = await fs29.readFile(planPath, "utf-8");
|
|
53958
54473
|
} catch {
|
|
53959
54474
|
content = "(no plan.md yet \u2014 run a council session first)";
|
|
53960
54475
|
}
|
|
53961
54476
|
break;
|
|
53962
54477
|
}
|
|
53963
54478
|
case "decisions": {
|
|
53964
|
-
const decisionsDir =
|
|
54479
|
+
const decisionsDir = path49.join(zelari, "decisions");
|
|
53965
54480
|
try {
|
|
53966
|
-
const files = (await
|
|
54481
|
+
const files = (await fs29.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
53967
54482
|
if (files.length === 0) {
|
|
53968
54483
|
content = "(no ADRs yet \u2014 invoke /council to generate some)";
|
|
53969
54484
|
} else {
|
|
@@ -53971,7 +54486,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
53971
54486
|
`];
|
|
53972
54487
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
53973
54488
|
for (const f of files) {
|
|
53974
|
-
const raw = await
|
|
54489
|
+
const raw = await fs29.readFile(path49.join(decisionsDir, f), "utf-8");
|
|
53975
54490
|
const { meta: meta3, body } = parseFrontmatter2(raw);
|
|
53976
54491
|
const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
|
|
53977
54492
|
lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
|
|
@@ -53984,27 +54499,27 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
53984
54499
|
break;
|
|
53985
54500
|
}
|
|
53986
54501
|
case "risks": {
|
|
53987
|
-
const risksPath =
|
|
54502
|
+
const risksPath = path49.join(zelari, "risks.md");
|
|
53988
54503
|
try {
|
|
53989
|
-
content = await
|
|
54504
|
+
content = await fs29.readFile(risksPath, "utf-8");
|
|
53990
54505
|
} catch {
|
|
53991
54506
|
content = "(no risks.md yet)";
|
|
53992
54507
|
}
|
|
53993
54508
|
break;
|
|
53994
54509
|
}
|
|
53995
54510
|
case "agents": {
|
|
53996
|
-
const agentsPath =
|
|
54511
|
+
const agentsPath = path49.join(process.cwd(), "AGENTS.MD");
|
|
53997
54512
|
try {
|
|
53998
|
-
content = await
|
|
54513
|
+
content = await fs29.readFile(agentsPath, "utf-8");
|
|
53999
54514
|
} catch {
|
|
54000
54515
|
content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
|
|
54001
54516
|
}
|
|
54002
54517
|
break;
|
|
54003
54518
|
}
|
|
54004
54519
|
case "docs": {
|
|
54005
|
-
const docsDir =
|
|
54520
|
+
const docsDir = path49.join(zelari, "docs");
|
|
54006
54521
|
try {
|
|
54007
|
-
const files = (await
|
|
54522
|
+
const files = (await fs29.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
54008
54523
|
content = files.length ? `# Docs (${files.length})
|
|
54009
54524
|
|
|
54010
54525
|
` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
|
|
@@ -54044,8 +54559,8 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
54044
54559
|
return;
|
|
54045
54560
|
}
|
|
54046
54561
|
try {
|
|
54047
|
-
const target =
|
|
54048
|
-
await
|
|
54562
|
+
const target = path49.join(process.cwd(), ".zelari");
|
|
54563
|
+
await fs29.rm(target, { recursive: true, force: true });
|
|
54049
54564
|
appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
|
|
54050
54565
|
} catch (err) {
|
|
54051
54566
|
appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -54056,16 +54571,16 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
54056
54571
|
init_provider2();
|
|
54057
54572
|
|
|
54058
54573
|
// src/cli/slashHandlers/skills.ts
|
|
54059
|
-
import
|
|
54060
|
-
import
|
|
54574
|
+
import path50 from "node:path";
|
|
54575
|
+
import os14 from "node:os";
|
|
54061
54576
|
|
|
54062
54577
|
// src/cli/skillHistory.ts
|
|
54063
|
-
import { promises as
|
|
54578
|
+
import { promises as fs30, existsSync as existsSync44, statSync as statSync7, renameSync as renameSync5, appendFileSync as appendFileSync4, mkdirSync as mkdirSync20 } from "node:fs";
|
|
54064
54579
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
54065
54580
|
async function readSkillHistory(file2) {
|
|
54066
54581
|
let raw = "";
|
|
54067
54582
|
try {
|
|
54068
|
-
raw = await
|
|
54583
|
+
raw = await fs30.readFile(file2, "utf-8");
|
|
54069
54584
|
} catch {
|
|
54070
54585
|
return [];
|
|
54071
54586
|
}
|
|
@@ -54185,7 +54700,7 @@ function handleSkillPicker(ctx, skills, openPicker, fallbackMessage) {
|
|
|
54185
54700
|
});
|
|
54186
54701
|
}
|
|
54187
54702
|
async function handleSkillStats(ctx, skillId) {
|
|
54188
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
54703
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path50.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
54189
54704
|
try {
|
|
54190
54705
|
const records = await readSkillHistory(historyFile);
|
|
54191
54706
|
const stats = getSkillStats(records, skillId);
|
|
@@ -54201,7 +54716,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
|
|
|
54201
54716
|
appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
|
|
54202
54717
|
return;
|
|
54203
54718
|
}
|
|
54204
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
54719
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path50.join(os14.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
54205
54720
|
try {
|
|
54206
54721
|
const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
|
|
54207
54722
|
appendSystem(ctx.setMessages, formatted);
|
|
@@ -55388,9 +55903,9 @@ function ContinueKey({ onContinue }) {
|
|
|
55388
55903
|
init_providerConfig();
|
|
55389
55904
|
|
|
55390
55905
|
// src/cli/wizard/firstRun.ts
|
|
55391
|
-
import { existsSync as
|
|
55906
|
+
import { existsSync as existsSync46 } from "node:fs";
|
|
55392
55907
|
function shouldRunWizard(input) {
|
|
55393
|
-
const exists = input.exists ??
|
|
55908
|
+
const exists = input.exists ?? existsSync46;
|
|
55394
55909
|
if (input.hasResetConfigFlag) {
|
|
55395
55910
|
return { shouldRun: true, reason: "--reset-config flag forced wizard" };
|
|
55396
55911
|
}
|
|
@@ -55711,6 +56226,16 @@ function parseHeadlessFlags(argv) {
|
|
|
55711
56226
|
} else if (arg === "--task") {
|
|
55712
56227
|
task = argv[i + 1];
|
|
55713
56228
|
i++;
|
|
56229
|
+
} else if (arg === "--task-file") {
|
|
56230
|
+
const next = argv[i + 1];
|
|
56231
|
+
if (next) {
|
|
56232
|
+
try {
|
|
56233
|
+
const fromFile = readFileSync37(next, "utf-8");
|
|
56234
|
+
if (fromFile.trim()) task = fromFile;
|
|
56235
|
+
} catch {
|
|
56236
|
+
}
|
|
56237
|
+
}
|
|
56238
|
+
i++;
|
|
55714
56239
|
} else if (arg === "--council") {
|
|
55715
56240
|
councilFlag = true;
|
|
55716
56241
|
} else if (arg === "--mode") {
|
|
@@ -55805,6 +56330,16 @@ function parseHeadlessFlags(argv) {
|
|
|
55805
56330
|
} else if (arg === "--kraken-graph") {
|
|
55806
56331
|
krakenGraph = argv[i + 1];
|
|
55807
56332
|
i++;
|
|
56333
|
+
} else if (arg === "--kraken-graph-file") {
|
|
56334
|
+
const next = argv[i + 1];
|
|
56335
|
+
if (next) {
|
|
56336
|
+
try {
|
|
56337
|
+
const fromFile = readFileSync37(next, "utf-8");
|
|
56338
|
+
if (fromFile.trim()) krakenGraph = fromFile;
|
|
56339
|
+
} catch {
|
|
56340
|
+
}
|
|
56341
|
+
}
|
|
56342
|
+
i++;
|
|
55808
56343
|
} else if (arg === "--plan-only") {
|
|
55809
56344
|
planOnly = true;
|
|
55810
56345
|
} else if (arg === "--run-plan") {
|
|
@@ -55913,8 +56448,8 @@ function createStreamScrubber2() {
|
|
|
55913
56448
|
// src/cli/runHeadless.ts
|
|
55914
56449
|
init_taskTool();
|
|
55915
56450
|
init_sessionTodos();
|
|
55916
|
-
import { promises as
|
|
55917
|
-
import
|
|
56451
|
+
import { promises as fs32 } from "node:fs";
|
|
56452
|
+
import path52 from "node:path";
|
|
55918
56453
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
55919
56454
|
async function runHeadless(opts) {
|
|
55920
56455
|
resetTaskSpawnCount();
|
|
@@ -56066,11 +56601,11 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
56066
56601
|
try {
|
|
56067
56602
|
let preflightGraph;
|
|
56068
56603
|
if (opts.runPlan && opts.runPlan.trim() !== "") {
|
|
56069
|
-
const planPath =
|
|
56604
|
+
const planPath = path52.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
|
|
56070
56605
|
log(`loading pre-flight plan: ${planPath}`);
|
|
56071
56606
|
let raw;
|
|
56072
56607
|
try {
|
|
56073
|
-
raw = await
|
|
56608
|
+
raw = await fs32.readFile(planPath, "utf8");
|
|
56074
56609
|
} catch (e) {
|
|
56075
56610
|
log(`plan file not found: ${planPath} (${e.message})`);
|
|
56076
56611
|
return 1;
|
|
@@ -56106,10 +56641,10 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
56106
56641
|
log(formatKrakenGraphAscii2(graph));
|
|
56107
56642
|
if (opts.planOnly) {
|
|
56108
56643
|
const planId = randomUUID6();
|
|
56109
|
-
const planDir =
|
|
56110
|
-
const planPath =
|
|
56111
|
-
await
|
|
56112
|
-
await
|
|
56644
|
+
const planDir = path52.join(cwd, ".zelari", "radio");
|
|
56645
|
+
const planPath = path52.join(planDir, `plan-${planId}.json`);
|
|
56646
|
+
await fs32.mkdir(planDir, { recursive: true });
|
|
56647
|
+
await fs32.writeFile(
|
|
56113
56648
|
planPath,
|
|
56114
56649
|
JSON.stringify(
|
|
56115
56650
|
{ id: graph.id, nodes: [...graph.nodes.values()] },
|
|
@@ -57214,8 +57749,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
|
|
|
57214
57749
|
let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
57215
57750
|
if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
|
|
57216
57751
|
try {
|
|
57217
|
-
const
|
|
57218
|
-
name =
|
|
57752
|
+
const path55 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
57753
|
+
name = path55 && /^[a-z0-9]/.test(path55) ? path55 : "imported-skill";
|
|
57219
57754
|
} catch {
|
|
57220
57755
|
name = "imported-skill";
|
|
57221
57756
|
}
|