zelari-code 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -3
- package/dist/cli/components/PluginGate.js +195 -0
- package/dist/cli/components/PluginGate.js.map +1 -0
- package/dist/cli/diagnostics/engine.js +2 -10
- package/dist/cli/diagnostics/engine.js.map +1 -1
- package/dist/cli/hooks/useSlashDispatch.js +17 -0
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/lsp/tools.js +3 -12
- package/dist/cli/lsp/tools.js.map +1 -1
- package/dist/cli/main.bundled.js +1460 -551
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +124 -6
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/plugins/installer.js +103 -0
- package/dist/cli/plugins/installer.js.map +1 -0
- package/dist/cli/plugins/prefs.js +96 -0
- package/dist/cli/plugins/prefs.js.map +1 -0
- package/dist/cli/plugins/registry.js +209 -0
- package/dist/cli/plugins/registry.js.map +1 -0
- package/dist/cli/slashCommands.js +18 -1
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/slashHandlers/plugins.js +75 -0
- package/dist/cli/slashHandlers/plugins.js.map +1 -0
- package/dist/cli/slashHandlers/updater.js +27 -3
- package/dist/cli/slashHandlers/updater.js.map +1 -1
- package/dist/cli/updater.js +1 -1
- package/dist/cli/updater.js.map +1 -1
- package/dist/cli/utils/doctor.js +66 -4
- package/dist/cli/utils/doctor.js.map +1 -1
- package/dist/cli/utils/fixPath.js +119 -0
- package/dist/cli/utils/fixPath.js.map +1 -0
- package/dist/cli/utils/paths.js +47 -0
- package/dist/cli/utils/paths.js.map +1 -1
- package/dist/cli/utils/prereqChecks.js +362 -0
- package/dist/cli/utils/prereqChecks.js.map +1 -0
- package/package.json +4 -2
- package/scripts/diagnose-path.ps1 +22 -0
- package/scripts/dump-path.ps1 +13 -0
- package/scripts/fix-path.ps1 +26 -0
- package/scripts/path-length.ps1 +15 -0
- package/scripts/postinstall.mjs +78 -1
- package/scripts/repair-path.mjs +104 -0
package/dist/cli/main.bundled.js
CHANGED
|
@@ -308,7 +308,7 @@ async function refreshGrokToken(options) {
|
|
|
308
308
|
return parseTokenResponseBody(obj, accessToken);
|
|
309
309
|
}
|
|
310
310
|
async function openBrowser(url2) {
|
|
311
|
-
const { spawn:
|
|
311
|
+
const { spawn: spawn9 } = await import("node:child_process");
|
|
312
312
|
const cmd = (() => {
|
|
313
313
|
switch (process.platform) {
|
|
314
314
|
case "darwin":
|
|
@@ -321,7 +321,7 @@ async function openBrowser(url2) {
|
|
|
321
321
|
})();
|
|
322
322
|
return new Promise((resolve, reject) => {
|
|
323
323
|
try {
|
|
324
|
-
const child =
|
|
324
|
+
const child = spawn9(cmd.bin, cmd.args, {
|
|
325
325
|
stdio: "ignore",
|
|
326
326
|
detached: true
|
|
327
327
|
});
|
|
@@ -1535,10 +1535,10 @@ function mergeDefs(...defs) {
|
|
|
1535
1535
|
function cloneDef(schema) {
|
|
1536
1536
|
return mergeDefs(schema._zod.def);
|
|
1537
1537
|
}
|
|
1538
|
-
function getElementAtPath(obj,
|
|
1539
|
-
if (!
|
|
1538
|
+
function getElementAtPath(obj, path34) {
|
|
1539
|
+
if (!path34)
|
|
1540
1540
|
return obj;
|
|
1541
|
-
return
|
|
1541
|
+
return path34.reduce((acc, key) => acc?.[key], obj);
|
|
1542
1542
|
}
|
|
1543
1543
|
function promiseAllObject(promisesObj) {
|
|
1544
1544
|
const keys = Object.keys(promisesObj);
|
|
@@ -1866,11 +1866,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
1866
1866
|
}
|
|
1867
1867
|
return false;
|
|
1868
1868
|
}
|
|
1869
|
-
function prefixIssues(
|
|
1869
|
+
function prefixIssues(path34, issues) {
|
|
1870
1870
|
return issues.map((iss) => {
|
|
1871
1871
|
var _a3;
|
|
1872
1872
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
1873
|
-
iss.path.unshift(
|
|
1873
|
+
iss.path.unshift(path34);
|
|
1874
1874
|
return iss;
|
|
1875
1875
|
});
|
|
1876
1876
|
}
|
|
@@ -2088,16 +2088,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2088
2088
|
}
|
|
2089
2089
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
2090
2090
|
const fieldErrors = { _errors: [] };
|
|
2091
|
-
const processError = (error52,
|
|
2091
|
+
const processError = (error52, path34 = []) => {
|
|
2092
2092
|
for (const issue2 of error52.issues) {
|
|
2093
2093
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2094
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2094
|
+
issue2.errors.map((issues) => processError({ issues }, [...path34, ...issue2.path]));
|
|
2095
2095
|
} else if (issue2.code === "invalid_key") {
|
|
2096
|
-
processError({ issues: issue2.issues }, [...
|
|
2096
|
+
processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
|
|
2097
2097
|
} else if (issue2.code === "invalid_element") {
|
|
2098
|
-
processError({ issues: issue2.issues }, [...
|
|
2098
|
+
processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
|
|
2099
2099
|
} else {
|
|
2100
|
-
const fullpath = [...
|
|
2100
|
+
const fullpath = [...path34, ...issue2.path];
|
|
2101
2101
|
if (fullpath.length === 0) {
|
|
2102
2102
|
fieldErrors._errors.push(mapper(issue2));
|
|
2103
2103
|
} else {
|
|
@@ -2124,17 +2124,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2124
2124
|
}
|
|
2125
2125
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
2126
2126
|
const result = { errors: [] };
|
|
2127
|
-
const processError = (error52,
|
|
2127
|
+
const processError = (error52, path34 = []) => {
|
|
2128
2128
|
var _a3, _b;
|
|
2129
2129
|
for (const issue2 of error52.issues) {
|
|
2130
2130
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2131
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2131
|
+
issue2.errors.map((issues) => processError({ issues }, [...path34, ...issue2.path]));
|
|
2132
2132
|
} else if (issue2.code === "invalid_key") {
|
|
2133
|
-
processError({ issues: issue2.issues }, [...
|
|
2133
|
+
processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
|
|
2134
2134
|
} else if (issue2.code === "invalid_element") {
|
|
2135
|
-
processError({ issues: issue2.issues }, [...
|
|
2135
|
+
processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
|
|
2136
2136
|
} else {
|
|
2137
|
-
const fullpath = [...
|
|
2137
|
+
const fullpath = [...path34, ...issue2.path];
|
|
2138
2138
|
if (fullpath.length === 0) {
|
|
2139
2139
|
result.errors.push(mapper(issue2));
|
|
2140
2140
|
continue;
|
|
@@ -2166,8 +2166,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2166
2166
|
}
|
|
2167
2167
|
function toDotPath(_path) {
|
|
2168
2168
|
const segs = [];
|
|
2169
|
-
const
|
|
2170
|
-
for (const seg of
|
|
2169
|
+
const path34 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
2170
|
+
for (const seg of path34) {
|
|
2171
2171
|
if (typeof seg === "number")
|
|
2172
2172
|
segs.push(`[${seg}]`);
|
|
2173
2173
|
else if (typeof seg === "symbol")
|
|
@@ -15670,13 +15670,13 @@ function resolveRef(ref, ctx) {
|
|
|
15670
15670
|
if (!ref.startsWith("#")) {
|
|
15671
15671
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
15672
15672
|
}
|
|
15673
|
-
const
|
|
15674
|
-
if (
|
|
15673
|
+
const path34 = ref.slice(1).split("/").filter(Boolean);
|
|
15674
|
+
if (path34.length === 0) {
|
|
15675
15675
|
return ctx.rootSchema;
|
|
15676
15676
|
}
|
|
15677
15677
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
15678
|
-
if (
|
|
15679
|
-
const key =
|
|
15678
|
+
if (path34[0] === defsKey) {
|
|
15679
|
+
const key = path34[1];
|
|
15680
15680
|
if (!key || !ctx.defs[key]) {
|
|
15681
15681
|
throw new Error(`Reference not found: ${ref}`);
|
|
15682
15682
|
}
|
|
@@ -16836,7 +16836,7 @@ var init_walk = __esm({
|
|
|
16836
16836
|
// packages/core/dist/core/tools/builtin/search.js
|
|
16837
16837
|
import { promises as fs6 } from "node:fs";
|
|
16838
16838
|
import path7 from "node:path";
|
|
16839
|
-
async function searchFile(absPath,
|
|
16839
|
+
async function searchFile(absPath, relPath, regex, contextLines, remainingSlots) {
|
|
16840
16840
|
let buf;
|
|
16841
16841
|
try {
|
|
16842
16842
|
buf = await fs6.readFile(absPath, "utf-8");
|
|
@@ -16856,7 +16856,7 @@ async function searchFile(absPath, relPath2, regex, contextLines, remainingSlots
|
|
|
16856
16856
|
const endAfter = Math.min(lines.length - 1, i + contextLines);
|
|
16857
16857
|
matches.push({
|
|
16858
16858
|
file: absPath,
|
|
16859
|
-
relPath
|
|
16859
|
+
relPath,
|
|
16860
16860
|
line: i + 1,
|
|
16861
16861
|
text: lines[i],
|
|
16862
16862
|
context: {
|
|
@@ -17706,11 +17706,11 @@ var init_tools = __esm({
|
|
|
17706
17706
|
if (!ctx.addDocument)
|
|
17707
17707
|
return "Knowledge vault tool not available.";
|
|
17708
17708
|
const title = args["title"] || "New Document";
|
|
17709
|
-
const
|
|
17709
|
+
const path34 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
17710
17710
|
const content = args["content"] || "";
|
|
17711
17711
|
const tags = args["tags"] || [];
|
|
17712
17712
|
ctx.addDocument({
|
|
17713
|
-
path:
|
|
17713
|
+
path: path34,
|
|
17714
17714
|
title,
|
|
17715
17715
|
content,
|
|
17716
17716
|
format: "markdown",
|
|
@@ -17719,7 +17719,7 @@ var init_tools = __esm({
|
|
|
17719
17719
|
workspaceId: ctx.workspaceId
|
|
17720
17720
|
});
|
|
17721
17721
|
ctx.addActivity("vault", "created document", title);
|
|
17722
|
-
return `Document "${title}" created at "${
|
|
17722
|
+
return `Document "${title}" created at "${path34}".`;
|
|
17723
17723
|
}
|
|
17724
17724
|
}
|
|
17725
17725
|
];
|
|
@@ -18096,6 +18096,33 @@ var init_skills2 = __esm({
|
|
|
18096
18096
|
}
|
|
18097
18097
|
});
|
|
18098
18098
|
|
|
18099
|
+
// src/cli/utils/paths.ts
|
|
18100
|
+
import { homedir as homedir2 } from "node:os";
|
|
18101
|
+
import path10 from "node:path";
|
|
18102
|
+
function shortenCwd(p3, maxLen = 40, home = homedir2()) {
|
|
18103
|
+
let out = p3;
|
|
18104
|
+
if (home && (out === home || out.startsWith(`${home}\\`) || out.startsWith(`${home}/`))) {
|
|
18105
|
+
out = `~${out.slice(home.length)}`;
|
|
18106
|
+
}
|
|
18107
|
+
if (out.length <= maxLen) return out;
|
|
18108
|
+
return `\u2026${out.slice(-(maxLen - 1))}`;
|
|
18109
|
+
}
|
|
18110
|
+
function relativePosix(from, to) {
|
|
18111
|
+
try {
|
|
18112
|
+
const p3 = process.platform === "win32" ? path10.win32 : path10.posix;
|
|
18113
|
+
const rel2 = p3.relative(from, to);
|
|
18114
|
+
if (!rel2 || rel2.startsWith("..")) return to;
|
|
18115
|
+
return rel2.split(/[\\/]/).join("/");
|
|
18116
|
+
} catch {
|
|
18117
|
+
return to;
|
|
18118
|
+
}
|
|
18119
|
+
}
|
|
18120
|
+
var init_paths = __esm({
|
|
18121
|
+
"src/cli/utils/paths.ts"() {
|
|
18122
|
+
"use strict";
|
|
18123
|
+
}
|
|
18124
|
+
});
|
|
18125
|
+
|
|
18099
18126
|
// packages/core/dist/shared/events.js
|
|
18100
18127
|
function createBrainEvent(type, sessionId, data) {
|
|
18101
18128
|
return {
|
|
@@ -18802,7 +18829,7 @@ var init_providerStream = __esm({
|
|
|
18802
18829
|
|
|
18803
18830
|
// packages/core/dist/core/sessionJsonl.js
|
|
18804
18831
|
import { promises as fs8 } from "node:fs";
|
|
18805
|
-
import
|
|
18832
|
+
import path11 from "node:path";
|
|
18806
18833
|
import os3 from "node:os";
|
|
18807
18834
|
async function readSession(filePath) {
|
|
18808
18835
|
try {
|
|
@@ -18828,7 +18855,7 @@ async function readSession(filePath) {
|
|
|
18828
18855
|
}
|
|
18829
18856
|
}
|
|
18830
18857
|
function defaultBaseDir() {
|
|
18831
|
-
return
|
|
18858
|
+
return path11.join(os3.tmpdir(), "zelari-code", "sessions");
|
|
18832
18859
|
}
|
|
18833
18860
|
var SessionJsonlWriter;
|
|
18834
18861
|
var init_sessionJsonl = __esm({
|
|
@@ -18839,7 +18866,7 @@ var init_sessionJsonl = __esm({
|
|
|
18839
18866
|
onError;
|
|
18840
18867
|
constructor(sessionId, options = {}) {
|
|
18841
18868
|
const baseDir = options.baseDir ?? defaultBaseDir();
|
|
18842
|
-
this.filePath =
|
|
18869
|
+
this.filePath = path11.join(baseDir, `${sessionId}.jsonl`);
|
|
18843
18870
|
this.onError = options.onError ?? console.error;
|
|
18844
18871
|
}
|
|
18845
18872
|
/** Absolute path to the session JSONL file. */
|
|
@@ -18849,7 +18876,7 @@ var init_sessionJsonl = __esm({
|
|
|
18849
18876
|
/** Append a BrainEvent as one JSON line. Creates the file + parent dirs if missing. */
|
|
18850
18877
|
async append(event) {
|
|
18851
18878
|
try {
|
|
18852
|
-
await fs8.mkdir(
|
|
18879
|
+
await fs8.mkdir(path11.dirname(this.filePath), { recursive: true });
|
|
18853
18880
|
const line = JSON.stringify({
|
|
18854
18881
|
ts: event.ts,
|
|
18855
18882
|
sessionId: event.sessionId,
|
|
@@ -19221,6 +19248,346 @@ var init_registry = __esm({
|
|
|
19221
19248
|
}
|
|
19222
19249
|
});
|
|
19223
19250
|
|
|
19251
|
+
// src/cli/diagnostics/engine.ts
|
|
19252
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
19253
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
19254
|
+
import path16 from "node:path";
|
|
19255
|
+
function parseEslintJson(stdout, _file2) {
|
|
19256
|
+
const json2 = safeJson(stdout);
|
|
19257
|
+
if (!Array.isArray(json2)) return [];
|
|
19258
|
+
const out = [];
|
|
19259
|
+
for (const fileResult of json2) {
|
|
19260
|
+
if (!fileResult || typeof fileResult !== "object") continue;
|
|
19261
|
+
const fr = fileResult;
|
|
19262
|
+
const filePath = typeof fr.filePath === "string" ? fr.filePath : _file2;
|
|
19263
|
+
if (!Array.isArray(fr.messages)) continue;
|
|
19264
|
+
for (const m of fr.messages) {
|
|
19265
|
+
if (!m || typeof m !== "object") continue;
|
|
19266
|
+
const msg = m;
|
|
19267
|
+
out.push({
|
|
19268
|
+
file: filePath,
|
|
19269
|
+
line: typeof msg.line === "number" ? msg.line : 0,
|
|
19270
|
+
...typeof msg.column === "number" ? { column: msg.column } : {},
|
|
19271
|
+
// ESLint severity: 2 = error, 1 = warning.
|
|
19272
|
+
severity: msg.severity === 2 ? "error" : "warning",
|
|
19273
|
+
message: typeof msg.message === "string" ? msg.message : "(no message)",
|
|
19274
|
+
...typeof msg.ruleId === "string" && msg.ruleId ? { code: msg.ruleId } : {},
|
|
19275
|
+
source: "eslint"
|
|
19276
|
+
});
|
|
19277
|
+
}
|
|
19278
|
+
}
|
|
19279
|
+
return out;
|
|
19280
|
+
}
|
|
19281
|
+
function parseRuffJson(stdout, _file2) {
|
|
19282
|
+
const json2 = safeJson(stdout);
|
|
19283
|
+
if (!Array.isArray(json2)) return [];
|
|
19284
|
+
const out = [];
|
|
19285
|
+
for (const issue2 of json2) {
|
|
19286
|
+
if (!issue2 || typeof issue2 !== "object") continue;
|
|
19287
|
+
const it = issue2;
|
|
19288
|
+
const code = typeof it.code === "string" ? it.code : void 0;
|
|
19289
|
+
out.push({
|
|
19290
|
+
file: typeof it.filename === "string" ? it.filename : _file2,
|
|
19291
|
+
line: typeof it.location?.row === "number" ? it.location.row : 0,
|
|
19292
|
+
...typeof it.location?.column === "number" ? { column: it.location.column } : {},
|
|
19293
|
+
// Ruff has no severity field; E999 is a syntax error, everything else
|
|
19294
|
+
// is a lint warning.
|
|
19295
|
+
severity: code === "E999" ? "error" : "warning",
|
|
19296
|
+
message: typeof it.message === "string" ? it.message : "(no message)",
|
|
19297
|
+
...code ? { code } : {},
|
|
19298
|
+
source: "ruff"
|
|
19299
|
+
});
|
|
19300
|
+
}
|
|
19301
|
+
return out;
|
|
19302
|
+
}
|
|
19303
|
+
function safeJson(s) {
|
|
19304
|
+
const trimmed = s.trim();
|
|
19305
|
+
if (!trimmed) return null;
|
|
19306
|
+
try {
|
|
19307
|
+
return JSON.parse(trimmed);
|
|
19308
|
+
} catch {
|
|
19309
|
+
return null;
|
|
19310
|
+
}
|
|
19311
|
+
}
|
|
19312
|
+
function providerForFile(file2, providers = DEFAULT_PROVIDERS) {
|
|
19313
|
+
const ext = path16.extname(file2).toLowerCase();
|
|
19314
|
+
return providers.find((p3) => p3.extensions.includes(ext)) ?? null;
|
|
19315
|
+
}
|
|
19316
|
+
function resolveBin(bin, cwd) {
|
|
19317
|
+
const suffixes = process.platform === "win32" ? [".cmd", ".exe", ""] : [""];
|
|
19318
|
+
let dir = cwd;
|
|
19319
|
+
for (let i = 0; i < 6; i += 1) {
|
|
19320
|
+
for (const suffix of suffixes) {
|
|
19321
|
+
const candidate = path16.join(dir, "node_modules", ".bin", `${bin}${suffix}`);
|
|
19322
|
+
if (existsSync7(candidate)) return candidate;
|
|
19323
|
+
}
|
|
19324
|
+
const parent = path16.dirname(dir);
|
|
19325
|
+
if (parent === dir) break;
|
|
19326
|
+
dir = parent;
|
|
19327
|
+
}
|
|
19328
|
+
return bin;
|
|
19329
|
+
}
|
|
19330
|
+
async function runDiagnosticsForFile(file2, options = {}) {
|
|
19331
|
+
const provider = providerForFile(file2, options.providers);
|
|
19332
|
+
if (!provider) return [];
|
|
19333
|
+
const cwd = options.cwd ?? process.cwd();
|
|
19334
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
19335
|
+
const runner = options.runner ?? defaultRunner;
|
|
19336
|
+
try {
|
|
19337
|
+
const bin = options.runner ? provider.bin : resolveBin(provider.bin, cwd);
|
|
19338
|
+
const result = await runner(bin, provider.args(file2), { cwd, timeoutMs });
|
|
19339
|
+
return provider.parse(result.stdout, file2);
|
|
19340
|
+
} catch {
|
|
19341
|
+
return [];
|
|
19342
|
+
}
|
|
19343
|
+
}
|
|
19344
|
+
function formatDiagnostics(diagnostics, opts = {}) {
|
|
19345
|
+
if (diagnostics.length === 0) return "";
|
|
19346
|
+
const maxLines = opts.maxLines ?? 20;
|
|
19347
|
+
const rank = { error: 0, warning: 1, info: 2 };
|
|
19348
|
+
const sorted = [...diagnostics].sort(
|
|
19349
|
+
(a, b) => rank[a.severity] - rank[b.severity] || a.line - b.line
|
|
19350
|
+
);
|
|
19351
|
+
const errors = sorted.filter((d) => d.severity === "error").length;
|
|
19352
|
+
const warnings = sorted.filter((d) => d.severity === "warning").length;
|
|
19353
|
+
const header = `\u26A0 ${diagnostics.length} diagnostic${diagnostics.length === 1 ? "" : "s"} (${errors} error${errors === 1 ? "" : "s"}, ${warnings} warning${warnings === 1 ? "" : "s"}) \u2014 fix before continuing:`;
|
|
19354
|
+
const shown = sorted.slice(0, maxLines).map((d) => {
|
|
19355
|
+
const loc = opts.relativeTo ? relativePosix(opts.relativeTo, d.file) : d.file;
|
|
19356
|
+
const pos = d.column ? `${d.line}:${d.column}` : `${d.line}`;
|
|
19357
|
+
const tag = d.severity === "error" ? "error" : d.severity === "warning" ? "warn" : "info";
|
|
19358
|
+
const code = d.code ? ` [${d.code}]` : "";
|
|
19359
|
+
return ` ${loc}:${pos} ${tag}${code}: ${d.message} (${d.source})`;
|
|
19360
|
+
});
|
|
19361
|
+
const overflow = sorted.length > maxLines ? [` \u2026 and ${sorted.length - maxLines} more`] : [];
|
|
19362
|
+
return [header, ...shown, ...overflow].join("\n");
|
|
19363
|
+
}
|
|
19364
|
+
var DEFAULT_PROVIDERS, defaultRunner;
|
|
19365
|
+
var init_engine = __esm({
|
|
19366
|
+
"src/cli/diagnostics/engine.ts"() {
|
|
19367
|
+
"use strict";
|
|
19368
|
+
init_paths();
|
|
19369
|
+
DEFAULT_PROVIDERS = [
|
|
19370
|
+
{
|
|
19371
|
+
name: "eslint",
|
|
19372
|
+
bin: "eslint",
|
|
19373
|
+
extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"],
|
|
19374
|
+
args: (file2) => ["--format", "json", file2],
|
|
19375
|
+
parse: parseEslintJson
|
|
19376
|
+
},
|
|
19377
|
+
{
|
|
19378
|
+
name: "ruff",
|
|
19379
|
+
bin: "ruff",
|
|
19380
|
+
extensions: [".py"],
|
|
19381
|
+
args: (file2) => ["check", "--output-format", "json", file2],
|
|
19382
|
+
parse: parseRuffJson
|
|
19383
|
+
}
|
|
19384
|
+
];
|
|
19385
|
+
defaultRunner = (cmd, args, opts) => new Promise((resolve) => {
|
|
19386
|
+
let stdout = "";
|
|
19387
|
+
let stderr = "";
|
|
19388
|
+
let settled = false;
|
|
19389
|
+
const done = (r) => {
|
|
19390
|
+
if (settled) return;
|
|
19391
|
+
settled = true;
|
|
19392
|
+
resolve(r);
|
|
19393
|
+
};
|
|
19394
|
+
let child;
|
|
19395
|
+
try {
|
|
19396
|
+
child = process.platform === "win32" ? spawn2(`${cmd} ${args.join(" ")}`, { cwd: opts.cwd, shell: true }) : spawn2(cmd, args, { cwd: opts.cwd });
|
|
19397
|
+
} catch {
|
|
19398
|
+
done({ code: null, stdout: "", stderr: "" });
|
|
19399
|
+
return;
|
|
19400
|
+
}
|
|
19401
|
+
const timer = setTimeout(() => {
|
|
19402
|
+
try {
|
|
19403
|
+
child.kill();
|
|
19404
|
+
} catch {
|
|
19405
|
+
}
|
|
19406
|
+
done({ code: null, stdout, stderr });
|
|
19407
|
+
}, opts.timeoutMs);
|
|
19408
|
+
child.stdout?.on("data", (c) => {
|
|
19409
|
+
stdout += c.toString();
|
|
19410
|
+
});
|
|
19411
|
+
child.stderr?.on("data", (c) => {
|
|
19412
|
+
stderr += c.toString();
|
|
19413
|
+
});
|
|
19414
|
+
child.on("error", () => {
|
|
19415
|
+
clearTimeout(timer);
|
|
19416
|
+
done({ code: null, stdout: "", stderr: "" });
|
|
19417
|
+
});
|
|
19418
|
+
child.on("close", (code) => {
|
|
19419
|
+
clearTimeout(timer);
|
|
19420
|
+
done({ code, stdout, stderr });
|
|
19421
|
+
});
|
|
19422
|
+
});
|
|
19423
|
+
}
|
|
19424
|
+
});
|
|
19425
|
+
|
|
19426
|
+
// src/cli/lsp/servers.ts
|
|
19427
|
+
import path17 from "node:path";
|
|
19428
|
+
function languageIdForFile(file2) {
|
|
19429
|
+
const ext = path17.extname(file2).toLowerCase();
|
|
19430
|
+
const map2 = {
|
|
19431
|
+
".ts": "typescript",
|
|
19432
|
+
".tsx": "typescriptreact",
|
|
19433
|
+
".js": "javascript",
|
|
19434
|
+
".jsx": "javascriptreact",
|
|
19435
|
+
".mjs": "javascript",
|
|
19436
|
+
".cjs": "javascript",
|
|
19437
|
+
".py": "python",
|
|
19438
|
+
".go": "go",
|
|
19439
|
+
".rs": "rust"
|
|
19440
|
+
};
|
|
19441
|
+
return map2[ext] ?? "plaintext";
|
|
19442
|
+
}
|
|
19443
|
+
function serverForFile(file2, servers = LSP_SERVERS) {
|
|
19444
|
+
const ext = path17.extname(file2).toLowerCase();
|
|
19445
|
+
return servers.find((s) => s.extensions.includes(ext)) ?? null;
|
|
19446
|
+
}
|
|
19447
|
+
function resolveServerCommand(file2, cwd, servers = LSP_SERVERS) {
|
|
19448
|
+
const spec = serverForFile(file2, servers);
|
|
19449
|
+
if (!spec) return null;
|
|
19450
|
+
const command = resolveBin(spec.bin, cwd);
|
|
19451
|
+
return {
|
|
19452
|
+
language: spec.language,
|
|
19453
|
+
command,
|
|
19454
|
+
args: spec.args,
|
|
19455
|
+
resolved: command !== spec.bin
|
|
19456
|
+
};
|
|
19457
|
+
}
|
|
19458
|
+
var LSP_SERVERS;
|
|
19459
|
+
var init_servers = __esm({
|
|
19460
|
+
"src/cli/lsp/servers.ts"() {
|
|
19461
|
+
"use strict";
|
|
19462
|
+
init_engine();
|
|
19463
|
+
LSP_SERVERS = [
|
|
19464
|
+
{
|
|
19465
|
+
language: "typescript",
|
|
19466
|
+
bin: "typescript-language-server",
|
|
19467
|
+
args: ["--stdio"],
|
|
19468
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]
|
|
19469
|
+
},
|
|
19470
|
+
{
|
|
19471
|
+
language: "python",
|
|
19472
|
+
bin: "pyright-langserver",
|
|
19473
|
+
args: ["--stdio"],
|
|
19474
|
+
extensions: [".py"]
|
|
19475
|
+
},
|
|
19476
|
+
{
|
|
19477
|
+
language: "go",
|
|
19478
|
+
bin: "gopls",
|
|
19479
|
+
args: [],
|
|
19480
|
+
extensions: [".go"]
|
|
19481
|
+
},
|
|
19482
|
+
{
|
|
19483
|
+
language: "rust",
|
|
19484
|
+
bin: "rust-analyzer",
|
|
19485
|
+
args: [],
|
|
19486
|
+
extensions: [".rs"]
|
|
19487
|
+
}
|
|
19488
|
+
];
|
|
19489
|
+
}
|
|
19490
|
+
});
|
|
19491
|
+
|
|
19492
|
+
// src/cli/browser/driver.ts
|
|
19493
|
+
async function runBrowserCheck(options, loader = defaultPlaywrightLoader) {
|
|
19494
|
+
const consoleErrors = [];
|
|
19495
|
+
const pageErrors = [];
|
|
19496
|
+
const failedRequests = [];
|
|
19497
|
+
const base = { ok: false, consoleErrors, pageErrors, failedRequests };
|
|
19498
|
+
const pw = await loader();
|
|
19499
|
+
if (!pw) {
|
|
19500
|
+
return {
|
|
19501
|
+
...base,
|
|
19502
|
+
error: "browser automation unavailable \u2014 install Playwright (`npm i -D playwright && npx playwright install chromium`) to enable browser_check"
|
|
19503
|
+
};
|
|
19504
|
+
}
|
|
19505
|
+
const timeout = options.timeoutMs ?? 15e3;
|
|
19506
|
+
let browser;
|
|
19507
|
+
try {
|
|
19508
|
+
browser = await pw.chromium.launch({ headless: true });
|
|
19509
|
+
const page = await browser.newPage();
|
|
19510
|
+
page.on("console", (msg) => {
|
|
19511
|
+
if (msg.type() === "error") consoleErrors.push(msg.text());
|
|
19512
|
+
});
|
|
19513
|
+
page.on("pageerror", (err) => pageErrors.push(err.message));
|
|
19514
|
+
page.on("requestfailed", (req) => {
|
|
19515
|
+
const f = req.failure();
|
|
19516
|
+
failedRequests.push(`${req.url()}${f ? ` (${f.errorText})` : ""}`);
|
|
19517
|
+
});
|
|
19518
|
+
await page.goto(options.url, { waitUntil: "load", timeout });
|
|
19519
|
+
for (const action of options.actions ?? []) {
|
|
19520
|
+
switch (action.type) {
|
|
19521
|
+
case "click":
|
|
19522
|
+
await page.click(action.selector, { timeout });
|
|
19523
|
+
break;
|
|
19524
|
+
case "fill":
|
|
19525
|
+
await page.fill(action.selector, action.value, { timeout });
|
|
19526
|
+
break;
|
|
19527
|
+
case "goto":
|
|
19528
|
+
await page.goto(action.url, { waitUntil: "load", timeout });
|
|
19529
|
+
break;
|
|
19530
|
+
case "wait":
|
|
19531
|
+
await page.waitForTimeout(action.ms);
|
|
19532
|
+
break;
|
|
19533
|
+
default:
|
|
19534
|
+
break;
|
|
19535
|
+
}
|
|
19536
|
+
}
|
|
19537
|
+
let selectorFound;
|
|
19538
|
+
if (options.waitForSelector) {
|
|
19539
|
+
try {
|
|
19540
|
+
await page.waitForSelector(options.waitForSelector, { timeout });
|
|
19541
|
+
selectorFound = true;
|
|
19542
|
+
} catch {
|
|
19543
|
+
selectorFound = false;
|
|
19544
|
+
}
|
|
19545
|
+
}
|
|
19546
|
+
let screenshotPath;
|
|
19547
|
+
if (options.screenshotPath) {
|
|
19548
|
+
try {
|
|
19549
|
+
await page.screenshot({ path: options.screenshotPath });
|
|
19550
|
+
screenshotPath = options.screenshotPath;
|
|
19551
|
+
} catch {
|
|
19552
|
+
}
|
|
19553
|
+
}
|
|
19554
|
+
const title = await page.title().catch(() => void 0);
|
|
19555
|
+
return {
|
|
19556
|
+
ok: true,
|
|
19557
|
+
consoleErrors,
|
|
19558
|
+
pageErrors,
|
|
19559
|
+
failedRequests,
|
|
19560
|
+
url: page.url(),
|
|
19561
|
+
...title !== void 0 ? { title } : {},
|
|
19562
|
+
...selectorFound !== void 0 ? { selectorFound } : {},
|
|
19563
|
+
...screenshotPath ? { screenshotPath } : {}
|
|
19564
|
+
};
|
|
19565
|
+
} catch (err) {
|
|
19566
|
+
return { ...base, error: err instanceof Error ? err.message : String(err) };
|
|
19567
|
+
} finally {
|
|
19568
|
+
try {
|
|
19569
|
+
await browser?.close();
|
|
19570
|
+
} catch {
|
|
19571
|
+
}
|
|
19572
|
+
}
|
|
19573
|
+
}
|
|
19574
|
+
var defaultPlaywrightLoader;
|
|
19575
|
+
var init_driver = __esm({
|
|
19576
|
+
"src/cli/browser/driver.ts"() {
|
|
19577
|
+
"use strict";
|
|
19578
|
+
defaultPlaywrightLoader = async () => {
|
|
19579
|
+
try {
|
|
19580
|
+
const pkg = "playwright";
|
|
19581
|
+
const mod = await import(pkg);
|
|
19582
|
+
if (mod && mod.chromium && typeof mod.chromium.launch === "function") return mod;
|
|
19583
|
+
return null;
|
|
19584
|
+
} catch {
|
|
19585
|
+
return null;
|
|
19586
|
+
}
|
|
19587
|
+
};
|
|
19588
|
+
}
|
|
19589
|
+
});
|
|
19590
|
+
|
|
19224
19591
|
// packages/core/dist/agents/roles.js
|
|
19225
19592
|
function getAgent(id) {
|
|
19226
19593
|
return AGENT_ROLES.find((a) => a.id === id);
|
|
@@ -20408,11 +20775,11 @@ var init_synthesisAudit = __esm({
|
|
|
20408
20775
|
import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
20409
20776
|
import { join as join2 } from "node:path";
|
|
20410
20777
|
function loadNfrSpec(zelariRoot) {
|
|
20411
|
-
const
|
|
20412
|
-
if (!existsSync10(
|
|
20778
|
+
const path34 = join2(zelariRoot, "nfr-spec.json");
|
|
20779
|
+
if (!existsSync10(path34))
|
|
20413
20780
|
return null;
|
|
20414
20781
|
try {
|
|
20415
|
-
const raw = JSON.parse(readFileSync8(
|
|
20782
|
+
const raw = JSON.parse(readFileSync8(path34, "utf8"));
|
|
20416
20783
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
20417
20784
|
return null;
|
|
20418
20785
|
return raw;
|
|
@@ -20681,9 +21048,9 @@ function checkDeadHooksInHtml(html) {
|
|
|
20681
21048
|
}
|
|
20682
21049
|
return warnings;
|
|
20683
21050
|
}
|
|
20684
|
-
function runMicroVerificationOnFile(projectRoot,
|
|
20685
|
-
const abs = join3(projectRoot,
|
|
20686
|
-
if (!existsSync11(abs) || !/\.html?$/i.test(
|
|
21051
|
+
function runMicroVerificationOnFile(projectRoot, relPath, zelariRoot) {
|
|
21052
|
+
const abs = join3(projectRoot, relPath);
|
|
21053
|
+
if (!existsSync11(abs) || !/\.html?$/i.test(relPath))
|
|
20687
21054
|
return [];
|
|
20688
21055
|
const spec = (zelariRoot ? loadNfrSpec(zelariRoot) : null) ?? DEFAULT_NFR_SPEC;
|
|
20689
21056
|
const anim = spec.animation ?? { compositorOnly: true, forbidLayoutProps: true };
|
|
@@ -20697,7 +21064,7 @@ function runMicroVerificationOnFile(projectRoot, relPath2, zelariRoot) {
|
|
|
20697
21064
|
warnings.push({
|
|
20698
21065
|
id: "motion.keyframes",
|
|
20699
21066
|
message: `@keyframes uses non-allowed property "${v.property}"`,
|
|
20700
|
-
file:
|
|
21067
|
+
file: relPath,
|
|
20701
21068
|
line: v.line
|
|
20702
21069
|
});
|
|
20703
21070
|
}
|
|
@@ -20705,12 +21072,12 @@ function runMicroVerificationOnFile(projectRoot, relPath2, zelariRoot) {
|
|
|
20705
21072
|
warnings.push({
|
|
20706
21073
|
id: "motion.transitions",
|
|
20707
21074
|
message: `transition uses non-allowed property "${v.property}"`,
|
|
20708
|
-
file:
|
|
21075
|
+
file: relPath,
|
|
20709
21076
|
line: v.line
|
|
20710
21077
|
});
|
|
20711
21078
|
}
|
|
20712
21079
|
for (const w of checkDeadHooksInHtml(html)) {
|
|
20713
|
-
warnings.push({ ...w, file:
|
|
21080
|
+
warnings.push({ ...w, file: relPath });
|
|
20714
21081
|
}
|
|
20715
21082
|
return warnings;
|
|
20716
21083
|
}
|
|
@@ -22039,8 +22406,8 @@ async function* runChairmanFixLoop(args) {
|
|
|
22039
22406
|
break;
|
|
22040
22407
|
}
|
|
22041
22408
|
const rescanned = /* @__PURE__ */ new Map();
|
|
22042
|
-
for (const
|
|
22043
|
-
for (const w of runChairmanMicroGate({ projectRoot: args.projectRoot, relPath
|
|
22409
|
+
for (const relPath of args.changedFiles) {
|
|
22410
|
+
for (const w of runChairmanMicroGate({ projectRoot: args.projectRoot, relPath, zelariRoot })) {
|
|
22044
22411
|
rescanned.set(`${w.id}|${w.file}|${w.line ?? ""}`, w);
|
|
22045
22412
|
}
|
|
22046
22413
|
}
|
|
@@ -22601,9 +22968,9 @@ var init_types2 = __esm({
|
|
|
22601
22968
|
import { readFileSync as readFileSync13 } from "node:fs";
|
|
22602
22969
|
import { join as join8 } from "node:path";
|
|
22603
22970
|
function readLessonsDeduped(zelariRoot) {
|
|
22604
|
-
const
|
|
22971
|
+
const path34 = join8(zelariRoot, LESSONS_FILE);
|
|
22605
22972
|
try {
|
|
22606
|
-
const raw = readFileSync13(
|
|
22973
|
+
const raw = readFileSync13(path34, "utf8");
|
|
22607
22974
|
const byId = /* @__PURE__ */ new Map();
|
|
22608
22975
|
for (const line of raw.split(/\r?\n/)) {
|
|
22609
22976
|
if (!line.trim())
|
|
@@ -22704,8 +23071,8 @@ function keywordsFrom(check2, signature) {
|
|
|
22704
23071
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
22705
23072
|
}
|
|
22706
23073
|
function writeLesson(zelariRoot, lesson) {
|
|
22707
|
-
const
|
|
22708
|
-
appendFileSync2(
|
|
23074
|
+
const path34 = join9(zelariRoot, LESSONS_FILE);
|
|
23075
|
+
appendFileSync2(path34, `${JSON.stringify(lesson)}
|
|
22709
23076
|
`, "utf8");
|
|
22710
23077
|
}
|
|
22711
23078
|
function findSimilar(lessons, signature) {
|
|
@@ -23301,7 +23668,7 @@ function workspaceArtifact(rootDir, subdir, slug) {
|
|
|
23301
23668
|
function projectName(projectRoot = process.cwd()) {
|
|
23302
23669
|
return basename(realpathSync(projectRoot));
|
|
23303
23670
|
}
|
|
23304
|
-
var
|
|
23671
|
+
var init_paths2 = __esm({
|
|
23305
23672
|
"src/cli/workspace/paths.ts"() {
|
|
23306
23673
|
"use strict";
|
|
23307
23674
|
}
|
|
@@ -23316,7 +23683,7 @@ __export(workspaceSummary_exports, {
|
|
|
23316
23683
|
buildZelariReadHint: () => buildZelariReadHint
|
|
23317
23684
|
});
|
|
23318
23685
|
import { existsSync as existsSync14, readFileSync as readFileSync14, readdirSync, statSync as statSync3 } from "node:fs";
|
|
23319
|
-
import { join as join12, relative
|
|
23686
|
+
import { join as join12, relative } from "node:path";
|
|
23320
23687
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
23321
23688
|
const { maxEntries = 30 } = options;
|
|
23322
23689
|
const name = safeProjectName(projectRoot);
|
|
@@ -23529,7 +23896,7 @@ function listShallow(projectRoot, maxEntries) {
|
|
|
23529
23896
|
out.push(`\u2026 (+${top.length - count} more)`);
|
|
23530
23897
|
break;
|
|
23531
23898
|
}
|
|
23532
|
-
const rel2 =
|
|
23899
|
+
const rel2 = relative(projectRoot, join12(projectRoot, entry.name));
|
|
23533
23900
|
if (entry.isDirectory()) {
|
|
23534
23901
|
let inner = "";
|
|
23535
23902
|
try {
|
|
@@ -23562,7 +23929,7 @@ var init_workspaceSummary = __esm({
|
|
|
23562
23929
|
"src/cli/workspace/workspaceSummary.ts"() {
|
|
23563
23930
|
"use strict";
|
|
23564
23931
|
init_council();
|
|
23565
|
-
|
|
23932
|
+
init_paths2();
|
|
23566
23933
|
PLAN_SUMMARY_MAX_TASKS = 15;
|
|
23567
23934
|
PRIORITY_RANK = {
|
|
23568
23935
|
critical: 3,
|
|
@@ -23845,28 +24212,28 @@ var init_storage = __esm({
|
|
|
23845
24212
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
23846
24213
|
Storage = class {
|
|
23847
24214
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
23848
|
-
read(
|
|
23849
|
-
if (!existsSync15(
|
|
23850
|
-
throw new Error(`File not found: ${
|
|
24215
|
+
read(path34) {
|
|
24216
|
+
if (!existsSync15(path34)) {
|
|
24217
|
+
throw new Error(`File not found: ${path34}`);
|
|
23851
24218
|
}
|
|
23852
|
-
const md = readFileSync15(
|
|
24219
|
+
const md = readFileSync15(path34, "utf8");
|
|
23853
24220
|
return parseFrontmatter(md);
|
|
23854
24221
|
}
|
|
23855
24222
|
/** Read a Markdown file; returns null if not found. */
|
|
23856
|
-
readIfExists(
|
|
23857
|
-
if (!existsSync15(
|
|
23858
|
-
return this.read(
|
|
24223
|
+
readIfExists(path34) {
|
|
24224
|
+
if (!existsSync15(path34)) return null;
|
|
24225
|
+
return this.read(path34);
|
|
23859
24226
|
}
|
|
23860
24227
|
/**
|
|
23861
24228
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
23862
24229
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
23863
24230
|
*/
|
|
23864
|
-
write(
|
|
23865
|
-
mkdirSync7(dirname(
|
|
23866
|
-
const tmp =
|
|
24231
|
+
write(path34, meta3, body) {
|
|
24232
|
+
mkdirSync7(dirname(path34), { recursive: true });
|
|
24233
|
+
const tmp = path34 + ".tmp-" + process.pid;
|
|
23867
24234
|
const md = serializeFrontmatter(meta3, body);
|
|
23868
24235
|
writeFileSync11(tmp, md, "utf8");
|
|
23869
|
-
renameSync2(tmp,
|
|
24236
|
+
renameSync2(tmp, path34);
|
|
23870
24237
|
}
|
|
23871
24238
|
/** List all .md files in a directory (non-recursive). */
|
|
23872
24239
|
listMarkdown(dir) {
|
|
@@ -23917,7 +24284,7 @@ import {
|
|
|
23917
24284
|
mkdirSync as mkdirSync8,
|
|
23918
24285
|
renameSync as renameSync3
|
|
23919
24286
|
} from "node:fs";
|
|
23920
|
-
import { join as join14, basename as basename2, dirname as dirname2, relative as
|
|
24287
|
+
import { join as join14, basename as basename2, dirname as dirname2, relative as relative2 } from "node:path";
|
|
23921
24288
|
function createWorkspaceContext(projectRoot = process.cwd()) {
|
|
23922
24289
|
const rootDir = resolveWorkspaceRoot(projectRoot);
|
|
23923
24290
|
return {
|
|
@@ -23944,8 +24311,8 @@ function readPlan(ctx) {
|
|
|
23944
24311
|
} catch {
|
|
23945
24312
|
}
|
|
23946
24313
|
}
|
|
23947
|
-
const
|
|
23948
|
-
const doc = ctx.storage.readIfExists(
|
|
24314
|
+
const path34 = workspaceFile(ctx.rootDir, "plan");
|
|
24315
|
+
const doc = ctx.storage.readIfExists(path34);
|
|
23949
24316
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
23950
24317
|
const meta3 = doc.meta;
|
|
23951
24318
|
return {
|
|
@@ -24110,7 +24477,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
24110
24477
|
dueDate: input.dueDate,
|
|
24111
24478
|
targetVersion: version2
|
|
24112
24479
|
});
|
|
24113
|
-
const
|
|
24480
|
+
const path34 = join14(ctx.rootDir, "milestones", `${id}.md`);
|
|
24114
24481
|
const meta3 = {
|
|
24115
24482
|
kind: "milestone",
|
|
24116
24483
|
id,
|
|
@@ -24127,7 +24494,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
24127
24494
|
`Target version: ${version2}`,
|
|
24128
24495
|
""
|
|
24129
24496
|
].join("\n");
|
|
24130
|
-
ctx.storage.write(
|
|
24497
|
+
ctx.storage.write(path34, meta3, body);
|
|
24131
24498
|
return { id, created: true };
|
|
24132
24499
|
}
|
|
24133
24500
|
function readPlanSummary(ctx) {
|
|
@@ -24331,7 +24698,7 @@ function addIdeaStub(ctx) {
|
|
|
24331
24698
|
const tags = args["tags"] ?? [];
|
|
24332
24699
|
const category = args["category"] ?? "General";
|
|
24333
24700
|
const id = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
24334
|
-
const
|
|
24701
|
+
const path34 = workspaceArtifact(ctx.rootDir, "decisions", id);
|
|
24335
24702
|
const meta3 = {
|
|
24336
24703
|
kind: "adr",
|
|
24337
24704
|
status: "proposed",
|
|
@@ -24357,7 +24724,7 @@ function addIdeaStub(ctx) {
|
|
|
24357
24724
|
...consequences.map((c) => `- ${c}`),
|
|
24358
24725
|
""
|
|
24359
24726
|
].join("\n");
|
|
24360
|
-
ctx.storage.write(
|
|
24727
|
+
ctx.storage.write(path34, meta3, body);
|
|
24361
24728
|
return `ADR ${id} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
24362
24729
|
});
|
|
24363
24730
|
}
|
|
@@ -24439,14 +24806,14 @@ function createDocumentStub(ctx) {
|
|
|
24439
24806
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
24440
24807
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
24441
24808
|
}
|
|
24442
|
-
const
|
|
24809
|
+
const path34 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
24443
24810
|
const meta3 = {
|
|
24444
24811
|
kind: "doc",
|
|
24445
24812
|
id: slug,
|
|
24446
24813
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
24447
24814
|
tags
|
|
24448
24815
|
};
|
|
24449
|
-
ctx.storage.write(
|
|
24816
|
+
ctx.storage.write(path34, meta3, content);
|
|
24450
24817
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
24451
24818
|
});
|
|
24452
24819
|
}
|
|
@@ -24510,7 +24877,7 @@ function searchDocumentsStub(ctx) {
|
|
|
24510
24877
|
const end = Math.min(raw.length, idx + matchLen + 40);
|
|
24511
24878
|
const snippet = "\u2026" + raw.slice(start, end).replace(/\n/g, " ").trim() + "\u2026";
|
|
24512
24879
|
results.push({
|
|
24513
|
-
path:
|
|
24880
|
+
path: relative2(ctx.rootDir, file2) || basename2(file2),
|
|
24514
24881
|
snippet
|
|
24515
24882
|
});
|
|
24516
24883
|
if (results.length >= limit) break;
|
|
@@ -24594,7 +24961,7 @@ var init_stubs = __esm({
|
|
|
24594
24961
|
"src/cli/workspace/stubs.ts"() {
|
|
24595
24962
|
"use strict";
|
|
24596
24963
|
init_storage();
|
|
24597
|
-
|
|
24964
|
+
init_paths2();
|
|
24598
24965
|
init_storage();
|
|
24599
24966
|
SEARCH_NUDGE_THRESHOLD = 5;
|
|
24600
24967
|
}
|
|
@@ -24673,6 +25040,7 @@ __export(updater_exports, {
|
|
|
24673
25040
|
compareSemver: () => compareSemver,
|
|
24674
25041
|
fetchLatestVersion: () => fetchLatestVersion,
|
|
24675
25042
|
getCurrentVersion: () => getCurrentVersion,
|
|
25043
|
+
looksLikeBrokenShim: () => looksLikeBrokenShim,
|
|
24676
25044
|
performUpdate: () => performUpdate,
|
|
24677
25045
|
resolveBundledNpmCli: () => resolveBundledNpmCli
|
|
24678
25046
|
});
|
|
@@ -25157,7 +25525,7 @@ function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
|
25157
25525
|
var init_planDetect = __esm({
|
|
25158
25526
|
"src/cli/workspace/planDetect.ts"() {
|
|
25159
25527
|
"use strict";
|
|
25160
|
-
|
|
25528
|
+
init_paths2();
|
|
25161
25529
|
}
|
|
25162
25530
|
});
|
|
25163
25531
|
|
|
@@ -25250,10 +25618,10 @@ import { createHash as createHash3 } from "node:crypto";
|
|
|
25250
25618
|
import { join as join17 } from "node:path";
|
|
25251
25619
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
25252
25620
|
async function readPackageJson2(projectRoot) {
|
|
25253
|
-
const
|
|
25254
|
-
if (!existsSync20(
|
|
25621
|
+
const path34 = join17(projectRoot, "package.json");
|
|
25622
|
+
if (!existsSync20(path34)) return null;
|
|
25255
25623
|
try {
|
|
25256
|
-
return JSON.parse(await readFile2(
|
|
25624
|
+
return JSON.parse(await readFile2(path34, "utf8"));
|
|
25257
25625
|
} catch {
|
|
25258
25626
|
return null;
|
|
25259
25627
|
}
|
|
@@ -25335,9 +25703,9 @@ async function genBuild(ctx) {
|
|
|
25335
25703
|
].join("\n");
|
|
25336
25704
|
}
|
|
25337
25705
|
async function genOpenQuestions(ctx) {
|
|
25338
|
-
const
|
|
25339
|
-
if (!existsSync20(
|
|
25340
|
-
const content = readFileSync19(
|
|
25706
|
+
const path34 = join17(ctx.rootDir, "risks.md");
|
|
25707
|
+
if (!existsSync20(path34)) return "_No open questions._";
|
|
25708
|
+
const content = readFileSync19(path34, "utf8");
|
|
25341
25709
|
const lines = content.split("\n");
|
|
25342
25710
|
const questions = [];
|
|
25343
25711
|
let currentTitle = "";
|
|
@@ -25467,7 +25835,7 @@ var AUTO_SECTIONS, MARKER_OPEN, MARKER_CLOSE, GENERATORS;
|
|
|
25467
25835
|
var init_agentsMd = __esm({
|
|
25468
25836
|
"src/cli/workspace/agentsMd.ts"() {
|
|
25469
25837
|
"use strict";
|
|
25470
|
-
|
|
25838
|
+
init_paths2();
|
|
25471
25839
|
AUTO_SECTIONS = [
|
|
25472
25840
|
"tech-stack",
|
|
25473
25841
|
"decisions",
|
|
@@ -25900,8 +26268,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
25900
26268
|
sources: scope.sources
|
|
25901
26269
|
} : void 0
|
|
25902
26270
|
});
|
|
25903
|
-
const
|
|
25904
|
-
completionHook = { ran: true, path:
|
|
26271
|
+
const path34 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
26272
|
+
completionHook = { ran: true, path: path34, completion };
|
|
25905
26273
|
} catch (err) {
|
|
25906
26274
|
completionHook = {
|
|
25907
26275
|
ran: true,
|
|
@@ -25954,7 +26322,7 @@ var init_buildLessonsSummary = __esm({
|
|
|
25954
26322
|
"src/cli/workspace/buildLessonsSummary.ts"() {
|
|
25955
26323
|
"use strict";
|
|
25956
26324
|
init_council();
|
|
25957
|
-
|
|
26325
|
+
init_paths2();
|
|
25958
26326
|
}
|
|
25959
26327
|
});
|
|
25960
26328
|
|
|
@@ -26534,36 +26902,478 @@ var init_zelariMission = __esm({
|
|
|
26534
26902
|
}
|
|
26535
26903
|
});
|
|
26536
26904
|
|
|
26905
|
+
// src/cli/utils/prereqChecks.ts
|
|
26906
|
+
var prereqChecks_exports = {};
|
|
26907
|
+
__export(prereqChecks_exports, {
|
|
26908
|
+
checkAgentBash: () => checkAgentBash,
|
|
26909
|
+
checkAgentGit: () => checkAgentGit,
|
|
26910
|
+
checkAgentNode: () => checkAgentNode,
|
|
26911
|
+
checkMainNode: () => checkMainNode,
|
|
26912
|
+
runPrereqChecks: () => runPrereqChecks
|
|
26913
|
+
});
|
|
26914
|
+
import { execSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
26915
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
26916
|
+
function resolveAgentShellSync() {
|
|
26917
|
+
if (process.platform !== "win32") {
|
|
26918
|
+
return { bashPath: null, isBash: true, via: "/bin/sh" };
|
|
26919
|
+
}
|
|
26920
|
+
const envShell = process.env.ZELARI_SHELL;
|
|
26921
|
+
if (envShell && envShell.trim().length > 0 && existsSyncSafe2(envShell)) {
|
|
26922
|
+
return { bashPath: envShell, isBash: true, via: `bash (${envShell})` };
|
|
26923
|
+
}
|
|
26924
|
+
const sessionShell = process.env.SHELL;
|
|
26925
|
+
if (sessionShell && sessionShell.trim().length > 0 && existsSyncSafe2(sessionShell)) {
|
|
26926
|
+
return {
|
|
26927
|
+
bashPath: sessionShell,
|
|
26928
|
+
isBash: true,
|
|
26929
|
+
via: `bash (${sessionShell})`
|
|
26930
|
+
};
|
|
26931
|
+
}
|
|
26932
|
+
for (const p3 of STANDARD_BASH_PATHS2) {
|
|
26933
|
+
if (existsSyncSafe2(p3)) {
|
|
26934
|
+
return { bashPath: p3, isBash: true, via: `bash (${p3})` };
|
|
26935
|
+
}
|
|
26936
|
+
}
|
|
26937
|
+
try {
|
|
26938
|
+
const result = spawnSync2("where", ["bash"], {
|
|
26939
|
+
encoding: "utf8",
|
|
26940
|
+
windowsHide: true
|
|
26941
|
+
});
|
|
26942
|
+
if (result.status === 0 && result.stdout) {
|
|
26943
|
+
const first = result.stdout.split(/\r?\n/).find((l) => l.trim().length > 0);
|
|
26944
|
+
if (first && existsSyncSafe2(first)) {
|
|
26945
|
+
const trimmed = first.trim();
|
|
26946
|
+
return { bashPath: trimmed, isBash: true, via: `bash (${trimmed})` };
|
|
26947
|
+
}
|
|
26948
|
+
}
|
|
26949
|
+
} catch {
|
|
26950
|
+
}
|
|
26951
|
+
return { bashPath: null, isBash: false, via: "cmd.exe" };
|
|
26952
|
+
}
|
|
26953
|
+
function existsSyncSafe2(p3) {
|
|
26954
|
+
try {
|
|
26955
|
+
return existsSync25(p3);
|
|
26956
|
+
} catch {
|
|
26957
|
+
return false;
|
|
26958
|
+
}
|
|
26959
|
+
}
|
|
26960
|
+
function probeTool(tool) {
|
|
26961
|
+
const shell = resolveAgentShellSync();
|
|
26962
|
+
let stdout = "";
|
|
26963
|
+
if (shell.bashPath) {
|
|
26964
|
+
try {
|
|
26965
|
+
const r = spawnSync2(shell.bashPath, ["-c", `${tool} --version`], {
|
|
26966
|
+
encoding: "utf8",
|
|
26967
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
26968
|
+
windowsHide: true
|
|
26969
|
+
});
|
|
26970
|
+
if (r.status === 0) stdout = (r.stdout || "").trim();
|
|
26971
|
+
} catch {
|
|
26972
|
+
}
|
|
26973
|
+
} else if (process.platform === "win32") {
|
|
26974
|
+
try {
|
|
26975
|
+
stdout = execSync(`${tool} --version`, {
|
|
26976
|
+
encoding: "utf8",
|
|
26977
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
26978
|
+
}).trim();
|
|
26979
|
+
} catch {
|
|
26980
|
+
}
|
|
26981
|
+
} else {
|
|
26982
|
+
try {
|
|
26983
|
+
stdout = execSync(`${tool} --version`, {
|
|
26984
|
+
encoding: "utf8",
|
|
26985
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
26986
|
+
}).trim();
|
|
26987
|
+
} catch {
|
|
26988
|
+
}
|
|
26989
|
+
}
|
|
26990
|
+
const m = stdout.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
26991
|
+
return {
|
|
26992
|
+
found: stdout.length > 0,
|
|
26993
|
+
version: m ? `${m[1]}.${m[2]}.${m[3]}` : "",
|
|
26994
|
+
raw: stdout
|
|
26995
|
+
};
|
|
26996
|
+
}
|
|
26997
|
+
function nodeMissingHint() {
|
|
26998
|
+
const shell = resolveAgentShellSync();
|
|
26999
|
+
if (process.platform === "win32") {
|
|
27000
|
+
return `node is not reachable from the agent's shell (${shell.via}).
|
|
27001
|
+
This usually means Node was installed for "current user" only,
|
|
27002
|
+
while Git Bash inherits the SYSTEM Path. Fix (pick one):
|
|
27003
|
+
- Reinstall Node (https://nodejs.org) and choose
|
|
27004
|
+
"Add to PATH for all users", OR
|
|
27005
|
+
- Add C:\\Program Files\\nodejs\\ to the SYSTEM Path
|
|
27006
|
+
(System Properties \u2192 Environment Variables \u2192 Path), OR
|
|
27007
|
+
- Set ZELARI_SHELL to a bash that already sees node.`;
|
|
27008
|
+
}
|
|
27009
|
+
return `node is not on the agent's shell PATH.
|
|
27010
|
+
Install Node >= ${MIN_NODE_MAJOR} (https://nodejs.org) or, if you use
|
|
27011
|
+
nvm, run \`nvm use <version>\` and reopen this terminal.`;
|
|
27012
|
+
}
|
|
27013
|
+
function checkAgentNode() {
|
|
27014
|
+
const probe = probeTool("node");
|
|
27015
|
+
if (!probe.found) {
|
|
27016
|
+
return {
|
|
27017
|
+
ok: false,
|
|
27018
|
+
severity: "critical",
|
|
27019
|
+
tool: "node",
|
|
27020
|
+
message: nodeMissingHint()
|
|
27021
|
+
};
|
|
27022
|
+
}
|
|
27023
|
+
const major = Number(probe.version.split(".")[0]);
|
|
27024
|
+
if (!probe.version || Number.isNaN(major)) {
|
|
27025
|
+
return {
|
|
27026
|
+
ok: false,
|
|
27027
|
+
severity: "warn",
|
|
27028
|
+
tool: "node",
|
|
27029
|
+
message: `could not parse node version from "${probe.raw}" (node is reachable, but version check skipped)`
|
|
27030
|
+
};
|
|
27031
|
+
}
|
|
27032
|
+
if (major < MIN_NODE_MAJOR) {
|
|
27033
|
+
return {
|
|
27034
|
+
ok: false,
|
|
27035
|
+
severity: "critical",
|
|
27036
|
+
tool: "node",
|
|
27037
|
+
message: `node ${probe.version} is older than the required >= ${MIN_NODE_MAJOR}.0.0 (from engines.node). Upgrade: https://nodejs.org`
|
|
27038
|
+
};
|
|
27039
|
+
}
|
|
27040
|
+
return {
|
|
27041
|
+
ok: true,
|
|
27042
|
+
severity: "critical",
|
|
27043
|
+
tool: "node",
|
|
27044
|
+
message: `node ${probe.version} (agent shell)`
|
|
27045
|
+
};
|
|
27046
|
+
}
|
|
27047
|
+
function checkAgentGit() {
|
|
27048
|
+
const probe = probeTool("git");
|
|
27049
|
+
if (!probe.found) {
|
|
27050
|
+
const hint = process.platform === "win32" ? `Install Git for Windows: https://git-scm.com/download/win` : `Install git (e.g. \`brew install git\` on macOS, \`apt install git\` on Debian)`;
|
|
27051
|
+
return {
|
|
27052
|
+
ok: false,
|
|
27053
|
+
severity: "warn",
|
|
27054
|
+
tool: "git",
|
|
27055
|
+
message: `git not found on the agent's shell PATH \u2014 /diff, /undo and the git sidebar will be disabled. ${hint}`
|
|
27056
|
+
};
|
|
27057
|
+
}
|
|
27058
|
+
return {
|
|
27059
|
+
ok: true,
|
|
27060
|
+
severity: "warn",
|
|
27061
|
+
tool: "git",
|
|
27062
|
+
message: `git ${probe.version} (agent shell)`
|
|
27063
|
+
};
|
|
27064
|
+
}
|
|
27065
|
+
function checkAgentBash() {
|
|
27066
|
+
if (process.platform !== "win32") {
|
|
27067
|
+
return {
|
|
27068
|
+
ok: true,
|
|
27069
|
+
severity: "warn",
|
|
27070
|
+
tool: "bash",
|
|
27071
|
+
message: "POSIX shell always available on this platform"
|
|
27072
|
+
};
|
|
27073
|
+
}
|
|
27074
|
+
const shell = resolveAgentShellSync();
|
|
27075
|
+
if (shell.isBash) {
|
|
27076
|
+
return {
|
|
27077
|
+
ok: true,
|
|
27078
|
+
severity: "warn",
|
|
27079
|
+
tool: "bash",
|
|
27080
|
+
message: `real bash available (${shell.via})`
|
|
27081
|
+
};
|
|
27082
|
+
}
|
|
27083
|
+
return {
|
|
27084
|
+
ok: false,
|
|
27085
|
+
severity: "warn",
|
|
27086
|
+
tool: "bash",
|
|
27087
|
+
message: `no Git Bash found \u2014 the agent's \`bash\` tool falls back to cmd.exe,
|
|
27088
|
+
where POSIX commands (ls, which, $VAR, &&) may fail. Install Git
|
|
27089
|
+
for Windows (https://git-scm.com/download/win) or set ZELARI_SHELL
|
|
27090
|
+
to your bash binary.`
|
|
27091
|
+
};
|
|
27092
|
+
}
|
|
27093
|
+
function checkMainNode() {
|
|
27094
|
+
try {
|
|
27095
|
+
const raw = execSync("node --version", {
|
|
27096
|
+
encoding: "utf8",
|
|
27097
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
27098
|
+
}).trim();
|
|
27099
|
+
const m = raw.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
27100
|
+
const version2 = m ? `${m[1]}.${m[2]}.${m[3]}` : "";
|
|
27101
|
+
const major = Number(version2.split(".")[0]);
|
|
27102
|
+
if (version2 && !Number.isNaN(major) && major >= MIN_NODE_MAJOR) {
|
|
27103
|
+
return {
|
|
27104
|
+
ok: true,
|
|
27105
|
+
severity: "critical",
|
|
27106
|
+
tool: "node",
|
|
27107
|
+
message: `node ${version2} (main process)`
|
|
27108
|
+
};
|
|
27109
|
+
}
|
|
27110
|
+
return {
|
|
27111
|
+
ok: false,
|
|
27112
|
+
severity: "warn",
|
|
27113
|
+
tool: "node",
|
|
27114
|
+
message: `node present in main process but version unparseable or < ${MIN_NODE_MAJOR}: "${raw}"`
|
|
27115
|
+
};
|
|
27116
|
+
} catch {
|
|
27117
|
+
return {
|
|
27118
|
+
ok: false,
|
|
27119
|
+
severity: "critical",
|
|
27120
|
+
tool: "node",
|
|
27121
|
+
message: "node not found on the main process PATH (zelari-code itself runs on node \u2014 this is unexpected)"
|
|
27122
|
+
};
|
|
27123
|
+
}
|
|
27124
|
+
}
|
|
27125
|
+
function runPrereqChecks(opts = { mode: "preflight" }) {
|
|
27126
|
+
const checks = [
|
|
27127
|
+
() => checkAgentNode(),
|
|
27128
|
+
() => checkAgentGit(),
|
|
27129
|
+
() => checkAgentBash()
|
|
27130
|
+
];
|
|
27131
|
+
const results = [];
|
|
27132
|
+
for (const run of checks) {
|
|
27133
|
+
try {
|
|
27134
|
+
results.push(run());
|
|
27135
|
+
} catch (err) {
|
|
27136
|
+
results.push({
|
|
27137
|
+
ok: false,
|
|
27138
|
+
severity: "warn",
|
|
27139
|
+
tool: "node",
|
|
27140
|
+
message: `prereq check crashed: ${err instanceof Error ? err.message : String(err)}`
|
|
27141
|
+
});
|
|
27142
|
+
}
|
|
27143
|
+
}
|
|
27144
|
+
const hasCriticalFail = results.some(
|
|
27145
|
+
(r) => !r.ok && r.severity === "critical"
|
|
27146
|
+
);
|
|
27147
|
+
const warnings = results.filter((r) => !r.ok && r.severity === "warn");
|
|
27148
|
+
void opts.mode;
|
|
27149
|
+
return { results, hasCriticalFail, warnings };
|
|
27150
|
+
}
|
|
27151
|
+
var MIN_NODE_MAJOR, STANDARD_BASH_PATHS2;
|
|
27152
|
+
var init_prereqChecks = __esm({
|
|
27153
|
+
"src/cli/utils/prereqChecks.ts"() {
|
|
27154
|
+
"use strict";
|
|
27155
|
+
MIN_NODE_MAJOR = 20;
|
|
27156
|
+
STANDARD_BASH_PATHS2 = [
|
|
27157
|
+
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
27158
|
+
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
27159
|
+
"C:\\Program Files (x86)\\Git\\bin\\bash.exe",
|
|
27160
|
+
"C:\\Program Files (x86)\\Git\\usr\\bin\\bash.exe"
|
|
27161
|
+
];
|
|
27162
|
+
}
|
|
27163
|
+
});
|
|
27164
|
+
|
|
27165
|
+
// src/cli/plugins/prefs.ts
|
|
27166
|
+
import { existsSync as existsSync26, readFileSync as readFileSync23, writeFileSync as writeFileSync15, mkdirSync as mkdirSync10 } from "node:fs";
|
|
27167
|
+
import path28 from "node:path";
|
|
27168
|
+
import os9 from "node:os";
|
|
27169
|
+
function getPluginPrefsPath() {
|
|
27170
|
+
return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path28.join(os9.homedir(), ".tmp", "zelari-code", "plugins.json");
|
|
27171
|
+
}
|
|
27172
|
+
function getPluginPrefs() {
|
|
27173
|
+
const file2 = getPluginPrefsPath();
|
|
27174
|
+
try {
|
|
27175
|
+
if (!existsSync26(file2)) return { ...DEFAULTS2, dontAskAgain: {} };
|
|
27176
|
+
const raw = readFileSync23(file2, "utf-8");
|
|
27177
|
+
const parsed = JSON.parse(raw);
|
|
27178
|
+
if (parsed && typeof parsed === "object" && parsed.dontAskAgain && typeof parsed.dontAskAgain === "object") {
|
|
27179
|
+
const clean = {};
|
|
27180
|
+
for (const [k, v] of Object.entries(parsed.dontAskAgain)) {
|
|
27181
|
+
if (typeof k === "string" && k.length > 0 && v === true) clean[k] = true;
|
|
27182
|
+
}
|
|
27183
|
+
return { version: 1, dontAskAgain: clean };
|
|
27184
|
+
}
|
|
27185
|
+
} catch {
|
|
27186
|
+
}
|
|
27187
|
+
return { ...DEFAULTS2, dontAskAgain: {} };
|
|
27188
|
+
}
|
|
27189
|
+
function writePluginPrefs(prefs) {
|
|
27190
|
+
const file2 = getPluginPrefsPath();
|
|
27191
|
+
mkdirSync10(path28.dirname(file2), { recursive: true });
|
|
27192
|
+
writeFileSync15(file2, JSON.stringify(prefs, null, 2), {
|
|
27193
|
+
encoding: "utf-8",
|
|
27194
|
+
mode: 384
|
|
27195
|
+
});
|
|
27196
|
+
}
|
|
27197
|
+
function markDontAskAgain(pluginId) {
|
|
27198
|
+
try {
|
|
27199
|
+
const prefs = getPluginPrefs();
|
|
27200
|
+
prefs.dontAskAgain[pluginId] = true;
|
|
27201
|
+
writePluginPrefs(prefs);
|
|
27202
|
+
} catch {
|
|
27203
|
+
}
|
|
27204
|
+
}
|
|
27205
|
+
function isMuted(pluginId) {
|
|
27206
|
+
return getPluginPrefs().dontAskAgain[pluginId] === true;
|
|
27207
|
+
}
|
|
27208
|
+
var DEFAULTS2;
|
|
27209
|
+
var init_prefs = __esm({
|
|
27210
|
+
"src/cli/plugins/prefs.ts"() {
|
|
27211
|
+
"use strict";
|
|
27212
|
+
DEFAULTS2 = {
|
|
27213
|
+
version: 1,
|
|
27214
|
+
dontAskAgain: {}
|
|
27215
|
+
};
|
|
27216
|
+
}
|
|
27217
|
+
});
|
|
27218
|
+
|
|
27219
|
+
// src/cli/plugins/registry.ts
|
|
27220
|
+
var registry_exports = {};
|
|
27221
|
+
__export(registry_exports, {
|
|
27222
|
+
PLUGINS: () => PLUGINS,
|
|
27223
|
+
detectMissingPlugins: () => detectMissingPlugins,
|
|
27224
|
+
findPlugin: () => findPlugin
|
|
27225
|
+
});
|
|
27226
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
27227
|
+
function detectLocalBin(bin) {
|
|
27228
|
+
return (cwd) => {
|
|
27229
|
+
try {
|
|
27230
|
+
const resolved = resolveBin(bin, cwd);
|
|
27231
|
+
return Promise.resolve(resolved !== bin);
|
|
27232
|
+
} catch {
|
|
27233
|
+
return Promise.resolve(false);
|
|
27234
|
+
}
|
|
27235
|
+
};
|
|
27236
|
+
}
|
|
27237
|
+
function detectGlobalBin(bin) {
|
|
27238
|
+
return () => {
|
|
27239
|
+
try {
|
|
27240
|
+
const res = spawnSync3(bin, ["--version"], {
|
|
27241
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
27242
|
+
shell: process.platform === "win32",
|
|
27243
|
+
timeout: 4e3
|
|
27244
|
+
});
|
|
27245
|
+
return Promise.resolve(res.status === 0 || res.stdout != null && res.stdout.toString().trim().length > 0 && res.error === void 0);
|
|
27246
|
+
} catch {
|
|
27247
|
+
return Promise.resolve(false);
|
|
27248
|
+
}
|
|
27249
|
+
};
|
|
27250
|
+
}
|
|
27251
|
+
async function detectPlaywright() {
|
|
27252
|
+
try {
|
|
27253
|
+
const mod = await defaultPlaywrightLoader();
|
|
27254
|
+
return mod !== null;
|
|
27255
|
+
} catch {
|
|
27256
|
+
return false;
|
|
27257
|
+
}
|
|
27258
|
+
}
|
|
27259
|
+
function binForProvider(name) {
|
|
27260
|
+
const p3 = DEFAULT_PROVIDERS.find((x) => x.name === name);
|
|
27261
|
+
if (!p3) throw new Error(`plugin registry: unknown diagnostic provider '${name}'`);
|
|
27262
|
+
return p3.bin;
|
|
27263
|
+
}
|
|
27264
|
+
function binForLspLanguage(language) {
|
|
27265
|
+
const s = LSP_SERVERS.find((x) => x.language === language);
|
|
27266
|
+
if (!s) throw new Error(`plugin registry: unknown LSP language '${language}'`);
|
|
27267
|
+
return s.bin;
|
|
27268
|
+
}
|
|
27269
|
+
async function detectMissingPlugins(cwd, opts = {}) {
|
|
27270
|
+
const missing = [];
|
|
27271
|
+
for (const spec of PLUGINS) {
|
|
27272
|
+
if (process.env[spec.featureGate] === "0") continue;
|
|
27273
|
+
if (!opts.includeMuted && isMuted(spec.id)) continue;
|
|
27274
|
+
let present = false;
|
|
27275
|
+
try {
|
|
27276
|
+
present = await spec.detect(cwd);
|
|
27277
|
+
} catch {
|
|
27278
|
+
present = false;
|
|
27279
|
+
}
|
|
27280
|
+
if (!present) missing.push(spec);
|
|
27281
|
+
}
|
|
27282
|
+
return missing;
|
|
27283
|
+
}
|
|
27284
|
+
function findPlugin(id) {
|
|
27285
|
+
return PLUGINS.find((p3) => p3.id === id);
|
|
27286
|
+
}
|
|
27287
|
+
var PLUGINS;
|
|
27288
|
+
var init_registry2 = __esm({
|
|
27289
|
+
"src/cli/plugins/registry.ts"() {
|
|
27290
|
+
"use strict";
|
|
27291
|
+
init_engine();
|
|
27292
|
+
init_driver();
|
|
27293
|
+
init_engine();
|
|
27294
|
+
init_servers();
|
|
27295
|
+
init_prefs();
|
|
27296
|
+
PLUGINS = [
|
|
27297
|
+
{
|
|
27298
|
+
id: "eslint",
|
|
27299
|
+
label: "ESLint (diagnostics for JS/TS)",
|
|
27300
|
+
npmPackage: "eslint",
|
|
27301
|
+
installScope: "dev",
|
|
27302
|
+
detect: detectLocalBin(binForProvider("eslint")),
|
|
27303
|
+
featureGate: "ZELARI_DIAGNOSTICS",
|
|
27304
|
+
description: "Enables the post-edit diagnostics loop for .js/.jsx/.ts/.tsx/.mjs/.cjs files."
|
|
27305
|
+
},
|
|
27306
|
+
{
|
|
27307
|
+
id: "ruff",
|
|
27308
|
+
label: "Ruff (diagnostics for Python)",
|
|
27309
|
+
npmPackage: "ruff",
|
|
27310
|
+
installScope: "dev",
|
|
27311
|
+
detect: detectLocalBin(binForProvider("ruff")),
|
|
27312
|
+
featureGate: "ZELARI_DIAGNOSTICS",
|
|
27313
|
+
description: "Enables the post-edit diagnostics loop for .py files."
|
|
27314
|
+
},
|
|
27315
|
+
{
|
|
27316
|
+
id: "playwright",
|
|
27317
|
+
label: "Playwright (browser_check tool)",
|
|
27318
|
+
npmPackage: "playwright",
|
|
27319
|
+
installScope: "dev",
|
|
27320
|
+
detect: () => detectPlaywright(),
|
|
27321
|
+
postInstallHint: "Then fetch the browser binary: `npx playwright install chromium`",
|
|
27322
|
+
featureGate: "ZELARI_BROWSER",
|
|
27323
|
+
description: "Powers the browser_check tool (URL probing, click/fill/wait, screenshots)."
|
|
27324
|
+
},
|
|
27325
|
+
{
|
|
27326
|
+
id: "typescript-language-server",
|
|
27327
|
+
label: "typescript-language-server (LSP for TS/JS)",
|
|
27328
|
+
npmPackage: "typescript-language-server",
|
|
27329
|
+
installScope: "global",
|
|
27330
|
+
detect: detectGlobalBin(binForLspLanguage("typescript")),
|
|
27331
|
+
featureGate: "ZELARI_LSP",
|
|
27332
|
+
description: "Powers go_to_definition / find_references / hover_type / rename_symbol for TS/JS."
|
|
27333
|
+
},
|
|
27334
|
+
{
|
|
27335
|
+
id: "pyright",
|
|
27336
|
+
label: "pyright (LSP for Python)",
|
|
27337
|
+
npmPackage: "pyright",
|
|
27338
|
+
installScope: "global",
|
|
27339
|
+
detect: detectGlobalBin(binForLspLanguage("python")),
|
|
27340
|
+
featureGate: "ZELARI_LSP",
|
|
27341
|
+
description: "Powers go_to_definition / find_references / hover_type / rename_symbol for Python."
|
|
27342
|
+
}
|
|
27343
|
+
];
|
|
27344
|
+
}
|
|
27345
|
+
});
|
|
27346
|
+
|
|
26537
27347
|
// src/cli/utils/doctor.ts
|
|
26538
27348
|
var doctor_exports = {};
|
|
26539
27349
|
__export(doctor_exports, {
|
|
26540
27350
|
runDoctor: () => runDoctor
|
|
26541
27351
|
});
|
|
26542
|
-
import { execSync } from "node:child_process";
|
|
26543
|
-
import { existsSync as
|
|
27352
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
27353
|
+
import { existsSync as existsSync31, readFileSync as readFileSync26, readlinkSync, statSync as statSync6 } from "node:fs";
|
|
26544
27354
|
import { createRequire as createRequire2 } from "node:module";
|
|
26545
27355
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
26546
|
-
import
|
|
27356
|
+
import path33 from "node:path";
|
|
26547
27357
|
function findPackageRoot(start) {
|
|
26548
27358
|
let dir = start;
|
|
26549
27359
|
for (let i = 0; i < 6; i += 1) {
|
|
26550
|
-
const candidate =
|
|
26551
|
-
if (
|
|
27360
|
+
const candidate = path33.join(dir, "package.json");
|
|
27361
|
+
if (existsSync31(candidate)) {
|
|
26552
27362
|
try {
|
|
26553
|
-
const pkg = JSON.parse(
|
|
27363
|
+
const pkg = JSON.parse(readFileSync26(candidate, "utf8"));
|
|
26554
27364
|
if (pkg.name === "zelari-code") return dir;
|
|
26555
27365
|
} catch {
|
|
26556
27366
|
}
|
|
26557
27367
|
}
|
|
26558
|
-
const parent =
|
|
27368
|
+
const parent = path33.dirname(dir);
|
|
26559
27369
|
if (parent === dir) break;
|
|
26560
27370
|
dir = parent;
|
|
26561
27371
|
}
|
|
26562
|
-
return
|
|
27372
|
+
return path33.resolve(__dirname3, "..", "..", "..");
|
|
26563
27373
|
}
|
|
26564
27374
|
function tryExec(cmd) {
|
|
26565
27375
|
try {
|
|
26566
|
-
return
|
|
27376
|
+
return execSync2(cmd, {
|
|
26567
27377
|
encoding: "utf8",
|
|
26568
27378
|
stdio: ["ignore", "pipe", "ignore"]
|
|
26569
27379
|
}).trim();
|
|
@@ -26573,8 +27383,8 @@ function tryExec(cmd) {
|
|
|
26573
27383
|
}
|
|
26574
27384
|
function readPackageJson3() {
|
|
26575
27385
|
try {
|
|
26576
|
-
const pkgPath =
|
|
26577
|
-
return JSON.parse(
|
|
27386
|
+
const pkgPath = path33.join(packageRoot, "package.json");
|
|
27387
|
+
return JSON.parse(readFileSync26(pkgPath, "utf8"));
|
|
26578
27388
|
} catch {
|
|
26579
27389
|
return null;
|
|
26580
27390
|
}
|
|
@@ -26589,8 +27399,8 @@ function checkShim(pkgName) {
|
|
|
26589
27399
|
}
|
|
26590
27400
|
const isWin = process.platform === "win32";
|
|
26591
27401
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
26592
|
-
const shimPath =
|
|
26593
|
-
if (!
|
|
27402
|
+
const shimPath = path33.join(prefix, shimName);
|
|
27403
|
+
if (!existsSync31(shimPath)) {
|
|
26594
27404
|
return FAIL(
|
|
26595
27405
|
`shim not found at ${shimPath}
|
|
26596
27406
|
fix: npm install -g ${pkgName}@latest --force`
|
|
@@ -26599,7 +27409,7 @@ function checkShim(pkgName) {
|
|
|
26599
27409
|
try {
|
|
26600
27410
|
const st = statSync6(shimPath);
|
|
26601
27411
|
if (isWin) {
|
|
26602
|
-
const content =
|
|
27412
|
+
const content = readFileSync26(shimPath, "utf8");
|
|
26603
27413
|
if (content.includes(`${pkgName}\\bin\\`) || content.includes(`${pkgName}/bin/`)) {
|
|
26604
27414
|
return OK(`shim OK at ${shimPath} (${st.size} bytes)`);
|
|
26605
27415
|
}
|
|
@@ -26617,8 +27427,8 @@ function checkShim(pkgName) {
|
|
|
26617
27427
|
fix: npm install -g ${pkgName}@latest --force`
|
|
26618
27428
|
);
|
|
26619
27429
|
}
|
|
26620
|
-
const resolved =
|
|
26621
|
-
const expected =
|
|
27430
|
+
const resolved = path33.resolve(path33.dirname(shimPath), target);
|
|
27431
|
+
const expected = path33.join(
|
|
26622
27432
|
prefix,
|
|
26623
27433
|
"node_modules",
|
|
26624
27434
|
pkgName,
|
|
@@ -26657,8 +27467,8 @@ function checkNode(pkg) {
|
|
|
26657
27467
|
return OK(`node ${raw}`);
|
|
26658
27468
|
}
|
|
26659
27469
|
function checkBundle() {
|
|
26660
|
-
const bundle =
|
|
26661
|
-
if (!
|
|
27470
|
+
const bundle = path33.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
27471
|
+
if (!existsSync31(bundle)) {
|
|
26662
27472
|
return FAIL(
|
|
26663
27473
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
26664
27474
|
fix: npm run build:cli (then reinstall or run via tsx)`
|
|
@@ -26678,7 +27488,7 @@ function checkRuntimeDeps() {
|
|
|
26678
27488
|
const missing = [];
|
|
26679
27489
|
for (const dep of required2) {
|
|
26680
27490
|
try {
|
|
26681
|
-
const localReq = createRequire2(
|
|
27491
|
+
const localReq = createRequire2(path33.join(packageRoot, "package.json"));
|
|
26682
27492
|
localReq.resolve(dep);
|
|
26683
27493
|
} catch {
|
|
26684
27494
|
missing.push(dep);
|
|
@@ -26702,22 +27512,60 @@ function checkPath() {
|
|
|
26702
27512
|
if (pathDirs.includes(prefix)) {
|
|
26703
27513
|
return OK(`PATH includes npm prefix (${prefix})`);
|
|
26704
27514
|
}
|
|
27515
|
+
const winHint = ` fix: zelari-code --fix-path (adds ${prefix} to the user PATH)
|
|
27516
|
+
then open a NEW terminal and run \`zelari-code --version\`
|
|
27517
|
+
if it persists: see scripts/diagnose-path.ps1 in the repo`;
|
|
27518
|
+
const posixHint = ` fix: export PATH="${prefix}/bin:$PATH"
|
|
27519
|
+
(add it to ~/.bashrc / ~/.zshrc to persist)`;
|
|
26705
27520
|
return WARN(
|
|
26706
27521
|
`PATH does not include npm prefix (${prefix})
|
|
26707
27522
|
symptom: "zelari-code: command not found" after install
|
|
26708
|
-
|
|
26709
|
-
fix (Windows): $env:Path = "$(npm prefix -g);$env:Path"`
|
|
27523
|
+
` + (process.platform === "win32" ? winHint : posixHint)
|
|
26710
27524
|
);
|
|
26711
27525
|
}
|
|
26712
|
-
function
|
|
27526
|
+
function prereqToCheckResult(r) {
|
|
27527
|
+
if (r.ok) return OK(r.message);
|
|
27528
|
+
return r.severity === "critical" ? FAIL(r.message, "critical") : WARN(r.message);
|
|
27529
|
+
}
|
|
27530
|
+
async function checkOptionalPlugins() {
|
|
27531
|
+
const { detectMissingPlugins: detectMissingPlugins2 } = await Promise.resolve().then(() => (init_registry2(), registry_exports));
|
|
27532
|
+
let missing;
|
|
27533
|
+
try {
|
|
27534
|
+
missing = await detectMissingPlugins2(packageRoot, { includeMuted: true });
|
|
27535
|
+
} catch {
|
|
27536
|
+
return WARN("could not detect optional plugins");
|
|
27537
|
+
}
|
|
27538
|
+
if (missing.length === 0) return OK("all optional plugins available");
|
|
27539
|
+
const lines = missing.map((p3) => `${p3.id} missing \u2014 /plugins install ${p3.id}`);
|
|
27540
|
+
return WARN(
|
|
27541
|
+
`${missing.length} optional plugin(s) missing (features degrade silently without them):
|
|
27542
|
+
` + lines.map((l) => ` ${l}`).join("\n") + "\n install via: /plugins (or the boot prompt)"
|
|
27543
|
+
);
|
|
27544
|
+
}
|
|
27545
|
+
async function runDoctor() {
|
|
26713
27546
|
const pkg = readPackageJson3();
|
|
26714
27547
|
const pkgName = pkg?.name ?? "zelari-code";
|
|
26715
27548
|
const checks = [
|
|
27549
|
+
// --- install-health checks (main-process probes) ---
|
|
26716
27550
|
{ name: "node", run: () => checkNode(pkg) },
|
|
26717
27551
|
{ name: "bin shim", run: () => checkShim(pkgName) },
|
|
26718
27552
|
{ name: "cli bundle", run: () => checkBundle() },
|
|
26719
27553
|
{ name: "runtime deps", run: () => checkRuntimeDeps() },
|
|
26720
|
-
{ name: "PATH", run: () => checkPath() }
|
|
27554
|
+
{ name: "PATH", run: () => checkPath() },
|
|
27555
|
+
// --- agent-shell checks (v1.4.0) ---
|
|
27556
|
+
// These probe node/git/bash THROUGH the resolved shell the agent uses.
|
|
27557
|
+
// A pass on "node" + a FAIL on "node (agent shell)" is the tell-tale
|
|
27558
|
+
// signature of the PATH-mismatch bug (node visible to the main process,
|
|
27559
|
+
// invisible to Git Bash) that silently breaks council builds.
|
|
27560
|
+
{ name: "node (agent shell)", run: () => prereqToCheckResult(checkAgentNode()) },
|
|
27561
|
+
{ name: "git (agent shell)", run: () => prereqToCheckResult(checkAgentGit()) },
|
|
27562
|
+
{ name: "bash", run: () => prereqToCheckResult(checkAgentBash()) },
|
|
27563
|
+
// --- optional tool plugins (v1.5.0) ---
|
|
27564
|
+
// Playwright / eslint / ruff / LSP servers. WARN-only (never critical):
|
|
27565
|
+
// these power edge features that degrade silently when absent. Surfaced
|
|
27566
|
+
// here so `zelari-code --doctor` tells the user what's missing + how to
|
|
27567
|
+
// install (`/plugins` or the boot PluginGate).
|
|
27568
|
+
{ name: "plugins", run: () => checkOptionalPlugins() }
|
|
26721
27569
|
];
|
|
26722
27570
|
console.log(`zelari-code doctor (v${pkg?.version ?? "unknown"})`);
|
|
26723
27571
|
console.log("platform:", process.platform, process.arch);
|
|
@@ -26730,7 +27578,7 @@ function runDoctor() {
|
|
|
26730
27578
|
for (const c of checks) {
|
|
26731
27579
|
let result;
|
|
26732
27580
|
try {
|
|
26733
|
-
result = c.run();
|
|
27581
|
+
result = await c.run();
|
|
26734
27582
|
} catch (err) {
|
|
26735
27583
|
result = FAIL(
|
|
26736
27584
|
`unexpected error: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -26759,8 +27607,9 @@ var require3, __dirname3, packageRoot, OK, FAIL, WARN;
|
|
|
26759
27607
|
var init_doctor = __esm({
|
|
26760
27608
|
"src/cli/utils/doctor.ts"() {
|
|
26761
27609
|
"use strict";
|
|
27610
|
+
init_prereqChecks();
|
|
26762
27611
|
require3 = createRequire2(import.meta.url);
|
|
26763
|
-
__dirname3 =
|
|
27612
|
+
__dirname3 = path33.dirname(fileURLToPath2(import.meta.url));
|
|
26764
27613
|
packageRoot = findPackageRoot(__dirname3);
|
|
26765
27614
|
OK = (message) => ({
|
|
26766
27615
|
ok: true,
|
|
@@ -26780,8 +27629,87 @@ var init_doctor = __esm({
|
|
|
26780
27629
|
}
|
|
26781
27630
|
});
|
|
26782
27631
|
|
|
27632
|
+
// src/cli/utils/fixPath.ts
|
|
27633
|
+
var fixPath_exports = {};
|
|
27634
|
+
__export(fixPath_exports, {
|
|
27635
|
+
repairWindowsUserPath: () => repairWindowsUserPath
|
|
27636
|
+
});
|
|
27637
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
27638
|
+
function getGlobalPrefix2() {
|
|
27639
|
+
return (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || "").trim() || (() => {
|
|
27640
|
+
try {
|
|
27641
|
+
return spawnSync4("npm", ["prefix", "-g"], {
|
|
27642
|
+
encoding: "utf8",
|
|
27643
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
27644
|
+
}).stdout?.trim() ?? "";
|
|
27645
|
+
} catch {
|
|
27646
|
+
return "";
|
|
27647
|
+
}
|
|
27648
|
+
})();
|
|
27649
|
+
}
|
|
27650
|
+
function powershell(script) {
|
|
27651
|
+
try {
|
|
27652
|
+
const res = spawnSync4(
|
|
27653
|
+
"powershell.exe",
|
|
27654
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
27655
|
+
{ encoding: "utf8" }
|
|
27656
|
+
);
|
|
27657
|
+
if (res.status === 0) return (res.stdout || "").trim();
|
|
27658
|
+
return "";
|
|
27659
|
+
} catch {
|
|
27660
|
+
return "";
|
|
27661
|
+
}
|
|
27662
|
+
}
|
|
27663
|
+
function repairWindowsUserPath() {
|
|
27664
|
+
const prefix = getGlobalPrefix2();
|
|
27665
|
+
if (!prefix) {
|
|
27666
|
+
return {
|
|
27667
|
+
ok: false,
|
|
27668
|
+
prefix: "",
|
|
27669
|
+
error: "could not detect the npm global prefix (run inside an npm context, or set npm_config_prefix)"
|
|
27670
|
+
};
|
|
27671
|
+
}
|
|
27672
|
+
if (process.platform !== "win32") {
|
|
27673
|
+
return {
|
|
27674
|
+
ok: false,
|
|
27675
|
+
prefix,
|
|
27676
|
+
error: `--fix-path is Windows-only. On ${process.platform}, add to your shell profile:
|
|
27677
|
+
export PATH="${prefix}/bin:$PATH"`
|
|
27678
|
+
};
|
|
27679
|
+
}
|
|
27680
|
+
const userPath = powershell(
|
|
27681
|
+
"[Environment]::GetEnvironmentVariable('Path','User')"
|
|
27682
|
+
);
|
|
27683
|
+
const norm = (p3) => p3.toLowerCase().replace(/\/+/g, "\\").replace(/\\+$/, "");
|
|
27684
|
+
const entries = userPath.split(";").map((e) => e.trim()).filter(Boolean);
|
|
27685
|
+
if (entries.some((e) => norm(e) === norm(prefix))) {
|
|
27686
|
+
return { ok: true, alreadyOk: true, prefix };
|
|
27687
|
+
}
|
|
27688
|
+
const updated = userPath === "" || userPath.endsWith(";") ? `${userPath}${prefix}` : `${userPath};${prefix}`;
|
|
27689
|
+
const writeRes = powershell(
|
|
27690
|
+
`[Environment]::SetEnvironmentVariable('Path', ${JSON.stringify(updated)}, 'User')`
|
|
27691
|
+
);
|
|
27692
|
+
const reread = powershell(
|
|
27693
|
+
"[Environment]::GetEnvironmentVariable('Path','User')"
|
|
27694
|
+
);
|
|
27695
|
+
const rereadEntries = reread.split(";").map((e) => e.trim()).filter(Boolean);
|
|
27696
|
+
if (rereadEntries.some((e) => norm(e) === norm(prefix))) {
|
|
27697
|
+
return { ok: true, alreadyOk: false, prefix };
|
|
27698
|
+
}
|
|
27699
|
+
return {
|
|
27700
|
+
ok: false,
|
|
27701
|
+
prefix,
|
|
27702
|
+
error: writeRes === null && reread === userPath ? "PowerShell write did not take effect (permission denied? run as the same user that owns the install)" : "PATH write failed for an unknown reason"
|
|
27703
|
+
};
|
|
27704
|
+
}
|
|
27705
|
+
var init_fixPath = __esm({
|
|
27706
|
+
"src/cli/utils/fixPath.ts"() {
|
|
27707
|
+
"use strict";
|
|
27708
|
+
}
|
|
27709
|
+
});
|
|
27710
|
+
|
|
26783
27711
|
// src/cli/main.ts
|
|
26784
|
-
import
|
|
27712
|
+
import React14 from "react";
|
|
26785
27713
|
import { render } from "ink";
|
|
26786
27714
|
|
|
26787
27715
|
// src/cli/app.tsx
|
|
@@ -27714,16 +28642,8 @@ function useExecutionTimer(busy, tickMs = 1e3) {
|
|
|
27714
28642
|
return { elapsedMs, lastMs };
|
|
27715
28643
|
}
|
|
27716
28644
|
|
|
27717
|
-
// src/cli/
|
|
27718
|
-
|
|
27719
|
-
function shortenCwd(p3, maxLen = 40, home = homedir2()) {
|
|
27720
|
-
let out = p3;
|
|
27721
|
-
if (home && (out === home || out.startsWith(`${home}\\`) || out.startsWith(`${home}/`))) {
|
|
27722
|
-
out = `~${out.slice(home.length)}`;
|
|
27723
|
-
}
|
|
27724
|
-
if (out.length <= maxLen) return out;
|
|
27725
|
-
return `\u2026${out.slice(-(maxLen - 1))}`;
|
|
27726
|
-
}
|
|
28645
|
+
// src/cli/app.tsx
|
|
28646
|
+
init_paths();
|
|
27727
28647
|
|
|
27728
28648
|
// packages/core/dist/agents/skills/builtin/debugging.js
|
|
27729
28649
|
init_skills();
|
|
@@ -29717,14 +30637,14 @@ import { useState as useState5, useRef as useRef3, useCallback, useEffect as use
|
|
|
29717
30637
|
// src/cli/sessionManager.ts
|
|
29718
30638
|
init_harness();
|
|
29719
30639
|
import { promises as fs9, existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync, statSync } from "node:fs";
|
|
29720
|
-
import
|
|
30640
|
+
import path12 from "node:path";
|
|
29721
30641
|
import os4 from "node:os";
|
|
29722
30642
|
import { randomUUID } from "node:crypto";
|
|
29723
30643
|
function getSessionBaseDir() {
|
|
29724
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
30644
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path12.join(os4.homedir(), ".tmp", "zelari-code", "sessions");
|
|
29725
30645
|
}
|
|
29726
30646
|
function getCurrentSessionFile() {
|
|
29727
|
-
return process.env.ANATHEMA_CURRENT_SESSION_FILE ??
|
|
30647
|
+
return process.env.ANATHEMA_CURRENT_SESSION_FILE ?? path12.join(os4.homedir(), ".tmp", "zelari-code", "current.txt");
|
|
29728
30648
|
}
|
|
29729
30649
|
async function ensureSessionDir() {
|
|
29730
30650
|
await fs9.mkdir(getSessionBaseDir(), { recursive: true });
|
|
@@ -29741,7 +30661,7 @@ function getCurrentSessionId() {
|
|
|
29741
30661
|
}
|
|
29742
30662
|
function setCurrentSessionId(id) {
|
|
29743
30663
|
const file2 = getCurrentSessionFile();
|
|
29744
|
-
mkdirSync4(
|
|
30664
|
+
mkdirSync4(path12.dirname(file2), { recursive: true });
|
|
29745
30665
|
writeFileSync4(file2, id, "utf-8");
|
|
29746
30666
|
}
|
|
29747
30667
|
function clearCurrentSessionId() {
|
|
@@ -29753,7 +30673,7 @@ function clearCurrentSessionId() {
|
|
|
29753
30673
|
}
|
|
29754
30674
|
}
|
|
29755
30675
|
function getCurrentBranchFile() {
|
|
29756
|
-
return process.env.ANATHEMA_CURRENT_BRANCH_FILE ??
|
|
30676
|
+
return process.env.ANATHEMA_CURRENT_BRANCH_FILE ?? path12.join(path12.dirname(getCurrentSessionFile()), "currentBranch.txt");
|
|
29757
30677
|
}
|
|
29758
30678
|
function getCurrentBranch() {
|
|
29759
30679
|
const file2 = getCurrentBranchFile();
|
|
@@ -29767,7 +30687,7 @@ function getCurrentBranch() {
|
|
|
29767
30687
|
}
|
|
29768
30688
|
function setCurrentBranch(name) {
|
|
29769
30689
|
const file2 = getCurrentBranchFile();
|
|
29770
|
-
mkdirSync4(
|
|
30690
|
+
mkdirSync4(path12.dirname(file2), { recursive: true });
|
|
29771
30691
|
writeFileSync4(file2, name, "utf-8");
|
|
29772
30692
|
}
|
|
29773
30693
|
function newSessionId() {
|
|
@@ -29786,7 +30706,7 @@ async function listSessions() {
|
|
|
29786
30706
|
for (const entry of entries) {
|
|
29787
30707
|
if (!entry.endsWith(".jsonl")) continue;
|
|
29788
30708
|
const id = entry.replace(/\.jsonl$/, "");
|
|
29789
|
-
const filePath =
|
|
30709
|
+
const filePath = path12.join(baseDir, entry);
|
|
29790
30710
|
try {
|
|
29791
30711
|
const events = await readSession(filePath);
|
|
29792
30712
|
let firstTs = 0;
|
|
@@ -29833,7 +30753,7 @@ ${lines.join("\n")}`
|
|
|
29833
30753
|
return { message: `[${kind}] handled` };
|
|
29834
30754
|
}
|
|
29835
30755
|
async function loadSessionEvents(id) {
|
|
29836
|
-
const filePath =
|
|
30756
|
+
const filePath = path12.join(getSessionBaseDir(), `${id}.jsonl`);
|
|
29837
30757
|
return readSession(filePath);
|
|
29838
30758
|
}
|
|
29839
30759
|
|
|
@@ -30125,15 +31045,15 @@ import { useState as useState6, useRef as useRef4, useCallback as useCallback2 }
|
|
|
30125
31045
|
|
|
30126
31046
|
// src/cli/metrics.ts
|
|
30127
31047
|
import { promises as fs10, existsSync as existsSync6, statSync as statSync2, renameSync, appendFileSync, mkdirSync as mkdirSync5 } from "node:fs";
|
|
30128
|
-
import
|
|
31048
|
+
import path13 from "node:path";
|
|
30129
31049
|
import os5 from "node:os";
|
|
30130
31050
|
var METRICS_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
30131
31051
|
var MetricsLogger = class {
|
|
30132
31052
|
file;
|
|
30133
31053
|
writeQueue = Promise.resolve();
|
|
30134
31054
|
constructor(file2) {
|
|
30135
|
-
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ??
|
|
30136
|
-
mkdirSync5(
|
|
31055
|
+
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path13.join(os5.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
|
|
31056
|
+
mkdirSync5(path13.dirname(this.file), { recursive: true });
|
|
30137
31057
|
}
|
|
30138
31058
|
/** Fire-and-forget record append. */
|
|
30139
31059
|
record(rec) {
|
|
@@ -30298,7 +31218,7 @@ init_diff();
|
|
|
30298
31218
|
init_web();
|
|
30299
31219
|
|
|
30300
31220
|
// src/cli/safety/sandboxPath.ts
|
|
30301
|
-
import
|
|
31221
|
+
import path14 from "node:path";
|
|
30302
31222
|
var SandboxViolationError = class extends Error {
|
|
30303
31223
|
constructor(message, attemptedPath, resolvedPath) {
|
|
30304
31224
|
super(message);
|
|
@@ -30311,9 +31231,9 @@ function resolveSandboxedPath(userPath, options = {}) {
|
|
|
30311
31231
|
if (typeof userPath !== "string" || userPath.length === 0) {
|
|
30312
31232
|
throw new SandboxViolationError("Empty path", userPath, "");
|
|
30313
31233
|
}
|
|
30314
|
-
const root =
|
|
30315
|
-
const resolved =
|
|
30316
|
-
const rootWithSep = root.endsWith(
|
|
31234
|
+
const root = path14.resolve(options.root ?? process.cwd());
|
|
31235
|
+
const resolved = path14.isAbsolute(userPath) ? path14.resolve(userPath) : path14.resolve(root, userPath);
|
|
31236
|
+
const rootWithSep = root.endsWith(path14.sep) ? root : root + path14.sep;
|
|
30317
31237
|
if (resolved !== root && !resolved.startsWith(rootWithSep)) {
|
|
30318
31238
|
throw new SandboxViolationError(
|
|
30319
31239
|
`Path escapes sandbox root: ${userPath} \u2192 ${resolved} (root: ${root})`,
|
|
@@ -30377,7 +31297,7 @@ function assertShellAllowed(command) {
|
|
|
30377
31297
|
|
|
30378
31298
|
// src/cli/safety/auditLogger.ts
|
|
30379
31299
|
import { promises as fs11 } from "node:fs";
|
|
30380
|
-
import
|
|
31300
|
+
import path15 from "node:path";
|
|
30381
31301
|
import os6 from "node:os";
|
|
30382
31302
|
var AuditLogger = class {
|
|
30383
31303
|
logPath;
|
|
@@ -30396,7 +31316,7 @@ var AuditLogger = class {
|
|
|
30396
31316
|
async append(entry) {
|
|
30397
31317
|
const line = JSON.stringify(entry) + "\n";
|
|
30398
31318
|
this.writeQueue = this.writeQueue.then(async () => {
|
|
30399
|
-
await fs11.mkdir(
|
|
31319
|
+
await fs11.mkdir(path15.dirname(this.logPath), { recursive: true });
|
|
30400
31320
|
await fs11.appendFile(this.logPath, line, "utf-8");
|
|
30401
31321
|
});
|
|
30402
31322
|
return this.writeQueue;
|
|
@@ -30440,7 +31360,7 @@ var AuditLogger = class {
|
|
|
30440
31360
|
function defaultAuditPath() {
|
|
30441
31361
|
const override = process.env.ANATHEMA_AUDIT_LOG;
|
|
30442
31362
|
if (override && override.trim().length > 0) return override;
|
|
30443
|
-
return
|
|
31363
|
+
return path15.join(os6.tmpdir(), "zelari-code", "audit.jsonl");
|
|
30444
31364
|
}
|
|
30445
31365
|
function redactArgs(args) {
|
|
30446
31366
|
const redacted = {};
|
|
@@ -30463,181 +31383,8 @@ function safeStringify(value) {
|
|
|
30463
31383
|
}
|
|
30464
31384
|
}
|
|
30465
31385
|
|
|
30466
|
-
// src/cli/
|
|
30467
|
-
|
|
30468
|
-
import { existsSync as existsSync7 } from "node:fs";
|
|
30469
|
-
import path15 from "node:path";
|
|
30470
|
-
function parseEslintJson(stdout, _file2) {
|
|
30471
|
-
const json2 = safeJson(stdout);
|
|
30472
|
-
if (!Array.isArray(json2)) return [];
|
|
30473
|
-
const out = [];
|
|
30474
|
-
for (const fileResult of json2) {
|
|
30475
|
-
if (!fileResult || typeof fileResult !== "object") continue;
|
|
30476
|
-
const fr = fileResult;
|
|
30477
|
-
const filePath = typeof fr.filePath === "string" ? fr.filePath : _file2;
|
|
30478
|
-
if (!Array.isArray(fr.messages)) continue;
|
|
30479
|
-
for (const m of fr.messages) {
|
|
30480
|
-
if (!m || typeof m !== "object") continue;
|
|
30481
|
-
const msg = m;
|
|
30482
|
-
out.push({
|
|
30483
|
-
file: filePath,
|
|
30484
|
-
line: typeof msg.line === "number" ? msg.line : 0,
|
|
30485
|
-
...typeof msg.column === "number" ? { column: msg.column } : {},
|
|
30486
|
-
// ESLint severity: 2 = error, 1 = warning.
|
|
30487
|
-
severity: msg.severity === 2 ? "error" : "warning",
|
|
30488
|
-
message: typeof msg.message === "string" ? msg.message : "(no message)",
|
|
30489
|
-
...typeof msg.ruleId === "string" && msg.ruleId ? { code: msg.ruleId } : {},
|
|
30490
|
-
source: "eslint"
|
|
30491
|
-
});
|
|
30492
|
-
}
|
|
30493
|
-
}
|
|
30494
|
-
return out;
|
|
30495
|
-
}
|
|
30496
|
-
function parseRuffJson(stdout, _file2) {
|
|
30497
|
-
const json2 = safeJson(stdout);
|
|
30498
|
-
if (!Array.isArray(json2)) return [];
|
|
30499
|
-
const out = [];
|
|
30500
|
-
for (const issue2 of json2) {
|
|
30501
|
-
if (!issue2 || typeof issue2 !== "object") continue;
|
|
30502
|
-
const it = issue2;
|
|
30503
|
-
const code = typeof it.code === "string" ? it.code : void 0;
|
|
30504
|
-
out.push({
|
|
30505
|
-
file: typeof it.filename === "string" ? it.filename : _file2,
|
|
30506
|
-
line: typeof it.location?.row === "number" ? it.location.row : 0,
|
|
30507
|
-
...typeof it.location?.column === "number" ? { column: it.location.column } : {},
|
|
30508
|
-
// Ruff has no severity field; E999 is a syntax error, everything else
|
|
30509
|
-
// is a lint warning.
|
|
30510
|
-
severity: code === "E999" ? "error" : "warning",
|
|
30511
|
-
message: typeof it.message === "string" ? it.message : "(no message)",
|
|
30512
|
-
...code ? { code } : {},
|
|
30513
|
-
source: "ruff"
|
|
30514
|
-
});
|
|
30515
|
-
}
|
|
30516
|
-
return out;
|
|
30517
|
-
}
|
|
30518
|
-
function safeJson(s) {
|
|
30519
|
-
const trimmed = s.trim();
|
|
30520
|
-
if (!trimmed) return null;
|
|
30521
|
-
try {
|
|
30522
|
-
return JSON.parse(trimmed);
|
|
30523
|
-
} catch {
|
|
30524
|
-
return null;
|
|
30525
|
-
}
|
|
30526
|
-
}
|
|
30527
|
-
var DEFAULT_PROVIDERS = [
|
|
30528
|
-
{
|
|
30529
|
-
name: "eslint",
|
|
30530
|
-
bin: "eslint",
|
|
30531
|
-
extensions: [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"],
|
|
30532
|
-
args: (file2) => ["--format", "json", file2],
|
|
30533
|
-
parse: parseEslintJson
|
|
30534
|
-
},
|
|
30535
|
-
{
|
|
30536
|
-
name: "ruff",
|
|
30537
|
-
bin: "ruff",
|
|
30538
|
-
extensions: [".py"],
|
|
30539
|
-
args: (file2) => ["check", "--output-format", "json", file2],
|
|
30540
|
-
parse: parseRuffJson
|
|
30541
|
-
}
|
|
30542
|
-
];
|
|
30543
|
-
function providerForFile(file2, providers = DEFAULT_PROVIDERS) {
|
|
30544
|
-
const ext = path15.extname(file2).toLowerCase();
|
|
30545
|
-
return providers.find((p3) => p3.extensions.includes(ext)) ?? null;
|
|
30546
|
-
}
|
|
30547
|
-
function resolveBin(bin, cwd) {
|
|
30548
|
-
const suffixes = process.platform === "win32" ? [".cmd", ".exe", ""] : [""];
|
|
30549
|
-
let dir = cwd;
|
|
30550
|
-
for (let i = 0; i < 6; i += 1) {
|
|
30551
|
-
for (const suffix of suffixes) {
|
|
30552
|
-
const candidate = path15.join(dir, "node_modules", ".bin", `${bin}${suffix}`);
|
|
30553
|
-
if (existsSync7(candidate)) return candidate;
|
|
30554
|
-
}
|
|
30555
|
-
const parent = path15.dirname(dir);
|
|
30556
|
-
if (parent === dir) break;
|
|
30557
|
-
dir = parent;
|
|
30558
|
-
}
|
|
30559
|
-
return bin;
|
|
30560
|
-
}
|
|
30561
|
-
var defaultRunner = (cmd, args, opts) => new Promise((resolve) => {
|
|
30562
|
-
let stdout = "";
|
|
30563
|
-
let stderr = "";
|
|
30564
|
-
let settled = false;
|
|
30565
|
-
const done = (r) => {
|
|
30566
|
-
if (settled) return;
|
|
30567
|
-
settled = true;
|
|
30568
|
-
resolve(r);
|
|
30569
|
-
};
|
|
30570
|
-
let child;
|
|
30571
|
-
try {
|
|
30572
|
-
child = process.platform === "win32" ? spawn2(`${cmd} ${args.join(" ")}`, { cwd: opts.cwd, shell: true }) : spawn2(cmd, args, { cwd: opts.cwd });
|
|
30573
|
-
} catch {
|
|
30574
|
-
done({ code: null, stdout: "", stderr: "" });
|
|
30575
|
-
return;
|
|
30576
|
-
}
|
|
30577
|
-
const timer = setTimeout(() => {
|
|
30578
|
-
try {
|
|
30579
|
-
child.kill();
|
|
30580
|
-
} catch {
|
|
30581
|
-
}
|
|
30582
|
-
done({ code: null, stdout, stderr });
|
|
30583
|
-
}, opts.timeoutMs);
|
|
30584
|
-
child.stdout?.on("data", (c) => {
|
|
30585
|
-
stdout += c.toString();
|
|
30586
|
-
});
|
|
30587
|
-
child.stderr?.on("data", (c) => {
|
|
30588
|
-
stderr += c.toString();
|
|
30589
|
-
});
|
|
30590
|
-
child.on("error", () => {
|
|
30591
|
-
clearTimeout(timer);
|
|
30592
|
-
done({ code: null, stdout: "", stderr: "" });
|
|
30593
|
-
});
|
|
30594
|
-
child.on("close", (code) => {
|
|
30595
|
-
clearTimeout(timer);
|
|
30596
|
-
done({ code, stdout, stderr });
|
|
30597
|
-
});
|
|
30598
|
-
});
|
|
30599
|
-
async function runDiagnosticsForFile(file2, options = {}) {
|
|
30600
|
-
const provider = providerForFile(file2, options.providers);
|
|
30601
|
-
if (!provider) return [];
|
|
30602
|
-
const cwd = options.cwd ?? process.cwd();
|
|
30603
|
-
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
30604
|
-
const runner = options.runner ?? defaultRunner;
|
|
30605
|
-
try {
|
|
30606
|
-
const bin = options.runner ? provider.bin : resolveBin(provider.bin, cwd);
|
|
30607
|
-
const result = await runner(bin, provider.args(file2), { cwd, timeoutMs });
|
|
30608
|
-
return provider.parse(result.stdout, file2);
|
|
30609
|
-
} catch {
|
|
30610
|
-
return [];
|
|
30611
|
-
}
|
|
30612
|
-
}
|
|
30613
|
-
function formatDiagnostics(diagnostics, opts = {}) {
|
|
30614
|
-
if (diagnostics.length === 0) return "";
|
|
30615
|
-
const maxLines = opts.maxLines ?? 20;
|
|
30616
|
-
const rank = { error: 0, warning: 1, info: 2 };
|
|
30617
|
-
const sorted = [...diagnostics].sort(
|
|
30618
|
-
(a, b) => rank[a.severity] - rank[b.severity] || a.line - b.line
|
|
30619
|
-
);
|
|
30620
|
-
const errors = sorted.filter((d) => d.severity === "error").length;
|
|
30621
|
-
const warnings = sorted.filter((d) => d.severity === "warning").length;
|
|
30622
|
-
const header = `\u26A0 ${diagnostics.length} diagnostic${diagnostics.length === 1 ? "" : "s"} (${errors} error${errors === 1 ? "" : "s"}, ${warnings} warning${warnings === 1 ? "" : "s"}) \u2014 fix before continuing:`;
|
|
30623
|
-
const shown = sorted.slice(0, maxLines).map((d) => {
|
|
30624
|
-
const loc = opts.relativeTo ? relative(opts.relativeTo, d.file) : d.file;
|
|
30625
|
-
const pos = d.column ? `${d.line}:${d.column}` : `${d.line}`;
|
|
30626
|
-
const tag = d.severity === "error" ? "error" : d.severity === "warning" ? "warn" : "info";
|
|
30627
|
-
const code = d.code ? ` [${d.code}]` : "";
|
|
30628
|
-
return ` ${loc}:${pos} ${tag}${code}: ${d.message} (${d.source})`;
|
|
30629
|
-
});
|
|
30630
|
-
const overflow = sorted.length > maxLines ? [` \u2026 and ${sorted.length - maxLines} more`] : [];
|
|
30631
|
-
return [header, ...shown, ...overflow].join("\n");
|
|
30632
|
-
}
|
|
30633
|
-
function relative(from, to) {
|
|
30634
|
-
try {
|
|
30635
|
-
const rel2 = path15.relative(from, to);
|
|
30636
|
-
return rel2 && !rel2.startsWith("..") ? rel2 : to;
|
|
30637
|
-
} catch {
|
|
30638
|
-
return to;
|
|
30639
|
-
}
|
|
30640
|
-
}
|
|
31386
|
+
// src/cli/toolRegistry.ts
|
|
31387
|
+
init_engine();
|
|
30641
31388
|
|
|
30642
31389
|
// src/cli/tools/taskTool.ts
|
|
30643
31390
|
init_zod();
|
|
@@ -30744,7 +31491,6 @@ function createTaskTool(deps) {
|
|
|
30744
31491
|
// src/cli/lsp/tools.ts
|
|
30745
31492
|
init_zod();
|
|
30746
31493
|
init_toolTypes();
|
|
30747
|
-
import path16 from "node:path";
|
|
30748
31494
|
|
|
30749
31495
|
// src/cli/lsp/protocol.ts
|
|
30750
31496
|
function encodeMessage(message) {
|
|
@@ -30797,21 +31543,14 @@ function uriToPath(uri) {
|
|
|
30797
31543
|
}
|
|
30798
31544
|
|
|
30799
31545
|
// src/cli/lsp/tools.ts
|
|
31546
|
+
init_paths();
|
|
30800
31547
|
function fmtLocation(loc, relativeTo) {
|
|
30801
31548
|
const file2 = uriToPath(loc.uri);
|
|
30802
|
-
const rel2 = relativeTo ?
|
|
31549
|
+
const rel2 = relativeTo ? relativePosix(relativeTo, file2) : file2;
|
|
30803
31550
|
const line = (loc.range?.start?.line ?? 0) + 1;
|
|
30804
31551
|
const col = (loc.range?.start?.character ?? 0) + 1;
|
|
30805
31552
|
return `${rel2}:${line}:${col}`;
|
|
30806
31553
|
}
|
|
30807
|
-
function relPath(from, to) {
|
|
30808
|
-
try {
|
|
30809
|
-
const r = path16.relative(from, to);
|
|
30810
|
-
return r && !r.startsWith("..") ? r : to;
|
|
30811
|
-
} catch {
|
|
30812
|
-
return to;
|
|
30813
|
-
}
|
|
30814
|
-
}
|
|
30815
31554
|
var PosArgs = external_exports.object({
|
|
30816
31555
|
path: external_exports.string().min(1).describe("File path (relative to the project root or absolute)."),
|
|
30817
31556
|
line: external_exports.number().int().positive().describe("1-based line number of the symbol."),
|
|
@@ -30888,7 +31627,7 @@ function createLspTools(provider, root = process.cwd()) {
|
|
|
30888
31627
|
}
|
|
30889
31628
|
return typedOk({
|
|
30890
31629
|
totalEdits: result.totalEdits,
|
|
30891
|
-
files: result.files.map((f) => `${
|
|
31630
|
+
files: result.files.map((f) => `${relativePosix(root, f.file)} (${f.count} edit${f.count === 1 ? "" : "s"})`)
|
|
30892
31631
|
});
|
|
30893
31632
|
}
|
|
30894
31633
|
};
|
|
@@ -30971,66 +31710,8 @@ var LspClient = class {
|
|
|
30971
31710
|
}
|
|
30972
31711
|
};
|
|
30973
31712
|
|
|
30974
|
-
// src/cli/lsp/servers.ts
|
|
30975
|
-
import path17 from "node:path";
|
|
30976
|
-
var LSP_SERVERS = [
|
|
30977
|
-
{
|
|
30978
|
-
language: "typescript",
|
|
30979
|
-
bin: "typescript-language-server",
|
|
30980
|
-
args: ["--stdio"],
|
|
30981
|
-
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]
|
|
30982
|
-
},
|
|
30983
|
-
{
|
|
30984
|
-
language: "python",
|
|
30985
|
-
bin: "pyright-langserver",
|
|
30986
|
-
args: ["--stdio"],
|
|
30987
|
-
extensions: [".py"]
|
|
30988
|
-
},
|
|
30989
|
-
{
|
|
30990
|
-
language: "go",
|
|
30991
|
-
bin: "gopls",
|
|
30992
|
-
args: [],
|
|
30993
|
-
extensions: [".go"]
|
|
30994
|
-
},
|
|
30995
|
-
{
|
|
30996
|
-
language: "rust",
|
|
30997
|
-
bin: "rust-analyzer",
|
|
30998
|
-
args: [],
|
|
30999
|
-
extensions: [".rs"]
|
|
31000
|
-
}
|
|
31001
|
-
];
|
|
31002
|
-
function languageIdForFile(file2) {
|
|
31003
|
-
const ext = path17.extname(file2).toLowerCase();
|
|
31004
|
-
const map2 = {
|
|
31005
|
-
".ts": "typescript",
|
|
31006
|
-
".tsx": "typescriptreact",
|
|
31007
|
-
".js": "javascript",
|
|
31008
|
-
".jsx": "javascriptreact",
|
|
31009
|
-
".mjs": "javascript",
|
|
31010
|
-
".cjs": "javascript",
|
|
31011
|
-
".py": "python",
|
|
31012
|
-
".go": "go",
|
|
31013
|
-
".rs": "rust"
|
|
31014
|
-
};
|
|
31015
|
-
return map2[ext] ?? "plaintext";
|
|
31016
|
-
}
|
|
31017
|
-
function serverForFile(file2, servers = LSP_SERVERS) {
|
|
31018
|
-
const ext = path17.extname(file2).toLowerCase();
|
|
31019
|
-
return servers.find((s) => s.extensions.includes(ext)) ?? null;
|
|
31020
|
-
}
|
|
31021
|
-
function resolveServerCommand(file2, cwd, servers = LSP_SERVERS) {
|
|
31022
|
-
const spec = serverForFile(file2, servers);
|
|
31023
|
-
if (!spec) return null;
|
|
31024
|
-
const command = resolveBin(spec.bin, cwd);
|
|
31025
|
-
return {
|
|
31026
|
-
language: spec.language,
|
|
31027
|
-
command,
|
|
31028
|
-
args: spec.args,
|
|
31029
|
-
resolved: command !== spec.bin
|
|
31030
|
-
};
|
|
31031
|
-
}
|
|
31032
|
-
|
|
31033
31713
|
// src/cli/lsp/manager.ts
|
|
31714
|
+
init_servers();
|
|
31034
31715
|
function processTransport(child) {
|
|
31035
31716
|
return {
|
|
31036
31717
|
send: (data) => {
|
|
@@ -31753,103 +32434,9 @@ function createSemanticTool(deps) {
|
|
|
31753
32434
|
// src/cli/browser/tools.ts
|
|
31754
32435
|
init_zod();
|
|
31755
32436
|
init_toolTypes();
|
|
32437
|
+
init_driver();
|
|
31756
32438
|
import path21 from "node:path";
|
|
31757
32439
|
import os7 from "node:os";
|
|
31758
|
-
|
|
31759
|
-
// src/cli/browser/driver.ts
|
|
31760
|
-
var defaultPlaywrightLoader = async () => {
|
|
31761
|
-
try {
|
|
31762
|
-
const pkg = "playwright";
|
|
31763
|
-
const mod = await import(pkg);
|
|
31764
|
-
if (mod && mod.chromium && typeof mod.chromium.launch === "function") return mod;
|
|
31765
|
-
return null;
|
|
31766
|
-
} catch {
|
|
31767
|
-
return null;
|
|
31768
|
-
}
|
|
31769
|
-
};
|
|
31770
|
-
async function runBrowserCheck(options, loader = defaultPlaywrightLoader) {
|
|
31771
|
-
const consoleErrors = [];
|
|
31772
|
-
const pageErrors = [];
|
|
31773
|
-
const failedRequests = [];
|
|
31774
|
-
const base = { ok: false, consoleErrors, pageErrors, failedRequests };
|
|
31775
|
-
const pw = await loader();
|
|
31776
|
-
if (!pw) {
|
|
31777
|
-
return {
|
|
31778
|
-
...base,
|
|
31779
|
-
error: "browser automation unavailable \u2014 install Playwright (`npm i -D playwright && npx playwright install chromium`) to enable browser_check"
|
|
31780
|
-
};
|
|
31781
|
-
}
|
|
31782
|
-
const timeout = options.timeoutMs ?? 15e3;
|
|
31783
|
-
let browser;
|
|
31784
|
-
try {
|
|
31785
|
-
browser = await pw.chromium.launch({ headless: true });
|
|
31786
|
-
const page = await browser.newPage();
|
|
31787
|
-
page.on("console", (msg) => {
|
|
31788
|
-
if (msg.type() === "error") consoleErrors.push(msg.text());
|
|
31789
|
-
});
|
|
31790
|
-
page.on("pageerror", (err) => pageErrors.push(err.message));
|
|
31791
|
-
page.on("requestfailed", (req) => {
|
|
31792
|
-
const f = req.failure();
|
|
31793
|
-
failedRequests.push(`${req.url()}${f ? ` (${f.errorText})` : ""}`);
|
|
31794
|
-
});
|
|
31795
|
-
await page.goto(options.url, { waitUntil: "load", timeout });
|
|
31796
|
-
for (const action of options.actions ?? []) {
|
|
31797
|
-
switch (action.type) {
|
|
31798
|
-
case "click":
|
|
31799
|
-
await page.click(action.selector, { timeout });
|
|
31800
|
-
break;
|
|
31801
|
-
case "fill":
|
|
31802
|
-
await page.fill(action.selector, action.value, { timeout });
|
|
31803
|
-
break;
|
|
31804
|
-
case "goto":
|
|
31805
|
-
await page.goto(action.url, { waitUntil: "load", timeout });
|
|
31806
|
-
break;
|
|
31807
|
-
case "wait":
|
|
31808
|
-
await page.waitForTimeout(action.ms);
|
|
31809
|
-
break;
|
|
31810
|
-
default:
|
|
31811
|
-
break;
|
|
31812
|
-
}
|
|
31813
|
-
}
|
|
31814
|
-
let selectorFound;
|
|
31815
|
-
if (options.waitForSelector) {
|
|
31816
|
-
try {
|
|
31817
|
-
await page.waitForSelector(options.waitForSelector, { timeout });
|
|
31818
|
-
selectorFound = true;
|
|
31819
|
-
} catch {
|
|
31820
|
-
selectorFound = false;
|
|
31821
|
-
}
|
|
31822
|
-
}
|
|
31823
|
-
let screenshotPath;
|
|
31824
|
-
if (options.screenshotPath) {
|
|
31825
|
-
try {
|
|
31826
|
-
await page.screenshot({ path: options.screenshotPath });
|
|
31827
|
-
screenshotPath = options.screenshotPath;
|
|
31828
|
-
} catch {
|
|
31829
|
-
}
|
|
31830
|
-
}
|
|
31831
|
-
const title = await page.title().catch(() => void 0);
|
|
31832
|
-
return {
|
|
31833
|
-
ok: true,
|
|
31834
|
-
consoleErrors,
|
|
31835
|
-
pageErrors,
|
|
31836
|
-
failedRequests,
|
|
31837
|
-
url: page.url(),
|
|
31838
|
-
...title !== void 0 ? { title } : {},
|
|
31839
|
-
...selectorFound !== void 0 ? { selectorFound } : {},
|
|
31840
|
-
...screenshotPath ? { screenshotPath } : {}
|
|
31841
|
-
};
|
|
31842
|
-
} catch (err) {
|
|
31843
|
-
return { ...base, error: err instanceof Error ? err.message : String(err) };
|
|
31844
|
-
} finally {
|
|
31845
|
-
try {
|
|
31846
|
-
await browser?.close();
|
|
31847
|
-
} catch {
|
|
31848
|
-
}
|
|
31849
|
-
}
|
|
31850
|
-
}
|
|
31851
|
-
|
|
31852
|
-
// src/cli/browser/tools.ts
|
|
31853
32440
|
var ActionSchema = external_exports.discriminatedUnion("type", [
|
|
31854
32441
|
external_exports.object({ type: external_exports.literal("click"), selector: external_exports.string().min(1) }),
|
|
31855
32442
|
external_exports.object({ type: external_exports.literal("fill"), selector: external_exports.string().min(1), value: external_exports.string() }),
|
|
@@ -33198,6 +33785,8 @@ function handleSlashCommand(text, availableSkills) {
|
|
|
33198
33785
|
/council-feedback <memberId> <1-5> [note] \u2014 rate a council member for future ranking (Task I.2)
|
|
33199
33786
|
/promote-member <memberId> \u2014 promote a council member to a standalone skill (v3-K)
|
|
33200
33787
|
/update [--yes|-y] \u2014 check for zelari-code updates; --yes performs the update (v3-N)
|
|
33788
|
+
/plugins \u2014 list optional tool plugins (Playwright, eslint, ruff, LSP servers)
|
|
33789
|
+
/plugins install <id> \u2014 install a plugin now (e.g. /plugins install eslint)
|
|
33201
33790
|
/steer <text> \u2014 enqueue a follow-up prompt on the active run (Task 18.2)
|
|
33202
33791
|
/steer --interrupt <text> \u2014 cancel current run + enqueue <text> for next dispatch (Task C.3.2)
|
|
33203
33792
|
/compact \u2014 compact the session transcript
|
|
@@ -33540,6 +34129,19 @@ ${formatSkillList(availableSkills)}`
|
|
|
33540
34129
|
updateForce: force
|
|
33541
34130
|
};
|
|
33542
34131
|
}
|
|
34132
|
+
case "plugins": {
|
|
34133
|
+
if (args.length === 0) {
|
|
34134
|
+
return { handled: true, kind: "plugins_list" };
|
|
34135
|
+
}
|
|
34136
|
+
if (args[0] === "install" && args[1]) {
|
|
34137
|
+
return { handled: true, kind: "plugins_install", pluginId: args[1] };
|
|
34138
|
+
}
|
|
34139
|
+
return {
|
|
34140
|
+
handled: true,
|
|
34141
|
+
kind: "plugins_usage",
|
|
34142
|
+
message: "Usage: /plugins \u2014 list optional tool plugins (Playwright, eslint, ruff, LSP servers)\n /plugins install <id> \u2014 install a plugin now (e.g. /plugins install eslint)"
|
|
34143
|
+
};
|
|
34144
|
+
}
|
|
33543
34145
|
case "undo": {
|
|
33544
34146
|
const confirmed = args.includes("--yes") || args.includes("-y");
|
|
33545
34147
|
if (confirmed) {
|
|
@@ -33931,12 +34533,18 @@ async function handleUpdatePerform(ctx) {
|
|
|
33931
34533
|
const { performUpdate: performUpdate2 } = await Promise.resolve().then(() => (init_updater(), updater_exports));
|
|
33932
34534
|
const res = await performUpdate2();
|
|
33933
34535
|
if (res.ok) {
|
|
34536
|
+
let prereqBlock = "";
|
|
34537
|
+
try {
|
|
34538
|
+
const { runPrereqChecks: runPrereqChecks2 } = await Promise.resolve().then(() => (init_prereqChecks(), prereqChecks_exports));
|
|
34539
|
+
const { warnings } = runPrereqChecks2({ mode: "preflight" });
|
|
34540
|
+
if (warnings.length > 0) {
|
|
34541
|
+
prereqBlock = "\n\n\u26A0 Prerequisite warnings (the agent may be limited after restart):\n" + warnings.map((w) => ` - ${w.tool}: ${w.message.replace(/\n/g, "\n ")}`).join("\n") + "\n Run `zelari-code --doctor` after restart for the full report.";
|
|
34542
|
+
}
|
|
34543
|
+
} catch {
|
|
34544
|
+
}
|
|
33934
34545
|
appendSystem(
|
|
33935
34546
|
ctx.setMessages,
|
|
33936
|
-
|
|
33937
|
-
|
|
33938
|
-
Please restart zelari-code manually to use the new version.
|
|
33939
|
-
(exit with /exit or Ctrl+C, then run \`zelari-code\` again)`
|
|
34547
|
+
"[update] \u2705 installed successfully\n\nPlease restart zelari-code manually to use the new version.\n(exit with /exit or Ctrl+C, then run `zelari-code` again)" + prereqBlock
|
|
33940
34548
|
);
|
|
33941
34549
|
} else {
|
|
33942
34550
|
const output = res.output?.trim() || "(empty)";
|
|
@@ -33985,17 +34593,124 @@ ${output}`.toLowerCase();
|
|
|
33985
34593
|
return "\u{1F4A1} hint: the install did not succeed. To retry with more detail:\n npm install -g zelari-code@latest --verbose 2>&1 | tail -40\n On Windows, also try: `npm install -g zelari-code@latest --force`\n" + (isWin ? " Run `zelari-code doctor` from a new terminal to diagnose shim / PATH issues.\n" : "");
|
|
33986
34594
|
}
|
|
33987
34595
|
|
|
34596
|
+
// src/cli/slashHandlers/plugins.ts
|
|
34597
|
+
init_registry2();
|
|
34598
|
+
|
|
34599
|
+
// src/cli/plugins/installer.ts
|
|
34600
|
+
init_cmdline();
|
|
34601
|
+
init_updater();
|
|
34602
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
34603
|
+
async function installPlugin(spec, cwd, executor = spawn8) {
|
|
34604
|
+
const scopeFlag = spec.installScope === "global" ? "-g" : "-D";
|
|
34605
|
+
const args = ["install", scopeFlag, spec.npmPackage];
|
|
34606
|
+
const primary = await runNpm2(executor, args, cwd, "shim");
|
|
34607
|
+
if (primary.ok) return primary;
|
|
34608
|
+
const npmCli = resolveBundledNpmCli();
|
|
34609
|
+
if (npmCli && looksLikeBrokenShim(primary.exitCode, primary.output)) {
|
|
34610
|
+
const fallback = await runNpm2(executor, args, cwd, "bundled", npmCli);
|
|
34611
|
+
return {
|
|
34612
|
+
...fallback,
|
|
34613
|
+
output: `[plugins] npm shim failed (${primary.error ?? "exit " + primary.exitCode}); retried via bundled npm (${npmCli}).
|
|
34614
|
+
${fallback.output}`
|
|
34615
|
+
};
|
|
34616
|
+
}
|
|
34617
|
+
return primary;
|
|
34618
|
+
}
|
|
34619
|
+
function runNpm2(executor, args, cwd, mode, npmCliPath) {
|
|
34620
|
+
return new Promise((resolve) => {
|
|
34621
|
+
let stdout = "";
|
|
34622
|
+
let stderr = "";
|
|
34623
|
+
const stdio = ["ignore", "pipe", "pipe"];
|
|
34624
|
+
const child = mode === "bundled" && npmCliPath ? executor(process.execPath, [npmCliPath, ...args], { stdio, cwd }) : process.platform === "win32" ? executor(buildCmdLine("npm", args), { stdio, shell: true, cwd }) : executor("npm", args, { stdio, cwd });
|
|
34625
|
+
child.stdout?.on("data", (chunk) => {
|
|
34626
|
+
stdout += chunk.toString();
|
|
34627
|
+
});
|
|
34628
|
+
child.stderr?.on("data", (chunk) => {
|
|
34629
|
+
stderr += chunk.toString();
|
|
34630
|
+
});
|
|
34631
|
+
child.on("error", (err) => {
|
|
34632
|
+
resolve({
|
|
34633
|
+
ok: false,
|
|
34634
|
+
output: stdout + stderr,
|
|
34635
|
+
error: err.message,
|
|
34636
|
+
exitCode: null
|
|
34637
|
+
});
|
|
34638
|
+
});
|
|
34639
|
+
child.on("close", (code) => {
|
|
34640
|
+
const ok = code === 0;
|
|
34641
|
+
resolve({
|
|
34642
|
+
ok,
|
|
34643
|
+
output: stdout + stderr,
|
|
34644
|
+
exitCode: code,
|
|
34645
|
+
error: ok ? void 0 : `npm exited with code ${code}`
|
|
34646
|
+
});
|
|
34647
|
+
});
|
|
34648
|
+
});
|
|
34649
|
+
}
|
|
34650
|
+
|
|
34651
|
+
// src/cli/slashHandlers/plugins.ts
|
|
34652
|
+
async function handlePluginsList(ctx, cwd) {
|
|
34653
|
+
const lines = ["[plugins] optional tool plugins:"];
|
|
34654
|
+
for (const spec of PLUGINS) {
|
|
34655
|
+
let present = false;
|
|
34656
|
+
try {
|
|
34657
|
+
present = await spec.detect(cwd);
|
|
34658
|
+
} catch {
|
|
34659
|
+
present = false;
|
|
34660
|
+
}
|
|
34661
|
+
const mark = present ? "\u2713" : "\u2717";
|
|
34662
|
+
const state2 = present ? "installed" : "missing";
|
|
34663
|
+
const hint = present ? "" : ` \u2014 run \`/plugins install ${spec.id}\``;
|
|
34664
|
+
lines.push(` ${mark} ${spec.label.padEnd(38)} ${state2}${hint}`);
|
|
34665
|
+
}
|
|
34666
|
+
lines.push("Missing plugins are optional \u2014 features degrade silently without them.");
|
|
34667
|
+
appendSystem(ctx.setMessages, lines.join("\n"));
|
|
34668
|
+
}
|
|
34669
|
+
async function handlePluginsInstall(ctx, cwd, pluginId) {
|
|
34670
|
+
const spec = findPlugin(pluginId);
|
|
34671
|
+
if (!spec) {
|
|
34672
|
+
appendSystem(
|
|
34673
|
+
ctx.setMessages,
|
|
34674
|
+
`[plugins] unknown plugin id: '${pluginId}'. Available: ${PLUGINS.map((p3) => p3.id).join(", ")}`
|
|
34675
|
+
);
|
|
34676
|
+
return;
|
|
34677
|
+
}
|
|
34678
|
+
const scopeFlag = spec.installScope === "global" ? "-g" : "-D";
|
|
34679
|
+
appendSystem(
|
|
34680
|
+
ctx.setMessages,
|
|
34681
|
+
`[plugins] installing ${spec.label} (\`npm i ${scopeFlag} ${spec.npmPackage}\`)\u2026`
|
|
34682
|
+
);
|
|
34683
|
+
let result;
|
|
34684
|
+
try {
|
|
34685
|
+
result = await installPlugin(spec, cwd);
|
|
34686
|
+
} catch {
|
|
34687
|
+
result = { ok: false, output: "", exitCode: null, error: "unexpected error" };
|
|
34688
|
+
}
|
|
34689
|
+
if (result.ok) {
|
|
34690
|
+
const post = spec.postInstallHint ? `
|
|
34691
|
+
\u2192 ${spec.postInstallHint}` : "";
|
|
34692
|
+
appendSystem(ctx.setMessages, `[plugins] \u2713 installed ${spec.label}${post}`);
|
|
34693
|
+
} else {
|
|
34694
|
+
const tail = result.output ? `
|
|
34695
|
+
${result.output.split("\n").slice(-8).join("\n")}` : "";
|
|
34696
|
+
appendSystem(
|
|
34697
|
+
ctx.setMessages,
|
|
34698
|
+
`[plugins] \u2717 install failed for ${spec.label}: ${result.error ?? "unknown error"}${tail}`
|
|
34699
|
+
);
|
|
34700
|
+
}
|
|
34701
|
+
}
|
|
34702
|
+
|
|
33988
34703
|
// src/cli/slashHandlers/promoteMember.ts
|
|
33989
34704
|
import { promises as fs16 } from "node:fs";
|
|
33990
|
-
import
|
|
33991
|
-
import
|
|
34705
|
+
import path29 from "node:path";
|
|
34706
|
+
import os10 from "node:os";
|
|
33992
34707
|
async function handlePromoteMember(ctx, memberId) {
|
|
33993
34708
|
try {
|
|
33994
34709
|
const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
33995
34710
|
const { skill, markdown } = promoteMember2(memberId);
|
|
33996
|
-
const skillDir = process.env.ANATHEMA_SKILL_DIR ??
|
|
34711
|
+
const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path29.join(os10.homedir(), ".tmp", "zelari-code", "skills");
|
|
33997
34712
|
await fs16.mkdir(skillDir, { recursive: true });
|
|
33998
|
-
const filePath =
|
|
34713
|
+
const filePath = path29.join(skillDir, `${skill.id}.md`);
|
|
33999
34714
|
await fs16.writeFile(filePath, markdown, "utf8");
|
|
34000
34715
|
appendSystem(
|
|
34001
34716
|
ctx.setMessages,
|
|
@@ -34012,33 +34727,33 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
34012
34727
|
}
|
|
34013
34728
|
|
|
34014
34729
|
// src/cli/branchManager.ts
|
|
34015
|
-
import { promises as fs17, existsSync as
|
|
34016
|
-
import
|
|
34017
|
-
import
|
|
34730
|
+
import { promises as fs17, existsSync as existsSync27, readFileSync as readFileSync24, writeFileSync as writeFileSync16, mkdirSync as mkdirSync11, statSync as statSync4, rmSync as rmSync2 } from "node:fs";
|
|
34731
|
+
import path30 from "node:path";
|
|
34732
|
+
import os11 from "node:os";
|
|
34018
34733
|
var META_FILENAME = "meta.json";
|
|
34019
34734
|
var SESSIONS_SUBDIR = "sessions";
|
|
34020
34735
|
function getBranchesBaseDir() {
|
|
34021
|
-
return process.env.ANATHEMA_BRANCHES_DIR ??
|
|
34736
|
+
return process.env.ANATHEMA_BRANCHES_DIR ?? path30.join(os11.homedir(), ".tmp", "zelari-code", "branches");
|
|
34022
34737
|
}
|
|
34023
34738
|
function getSessionsBaseDir() {
|
|
34024
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
34739
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path30.join(os11.homedir(), ".tmp", "zelari-code", "sessions");
|
|
34025
34740
|
}
|
|
34026
34741
|
function branchPathFor(name, baseDir) {
|
|
34027
|
-
return
|
|
34742
|
+
return path30.join(baseDir, name);
|
|
34028
34743
|
}
|
|
34029
34744
|
function metaPathFor(name, baseDir) {
|
|
34030
|
-
return
|
|
34745
|
+
return path30.join(baseDir, name, META_FILENAME);
|
|
34031
34746
|
}
|
|
34032
34747
|
function sessionsPathFor(name, baseDir) {
|
|
34033
|
-
return
|
|
34748
|
+
return path30.join(baseDir, name, SESSIONS_SUBDIR);
|
|
34034
34749
|
}
|
|
34035
34750
|
function readBranchMeta(name, baseDir) {
|
|
34036
34751
|
const metaPath = metaPathFor(name, baseDir);
|
|
34037
|
-
if (!
|
|
34752
|
+
if (!existsSync27(metaPath)) {
|
|
34038
34753
|
throw new BranchNotFoundError(`Branch "${name}" not found`);
|
|
34039
34754
|
}
|
|
34040
34755
|
try {
|
|
34041
|
-
const raw =
|
|
34756
|
+
const raw = readFileSync24(metaPath, "utf-8");
|
|
34042
34757
|
const parsed = JSON.parse(raw);
|
|
34043
34758
|
if (!parsed || typeof parsed !== "object" || typeof parsed.name !== "string" || typeof parsed.createdAt !== "number" || typeof parsed.fromSessionId !== "string") {
|
|
34044
34759
|
throw new BranchCorruptError(`Branch "${name}" meta.json is malformed`);
|
|
@@ -34055,8 +34770,8 @@ function readBranchMeta(name, baseDir) {
|
|
|
34055
34770
|
}
|
|
34056
34771
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
34057
34772
|
const metaPath = metaPathFor(name, baseDir);
|
|
34058
|
-
|
|
34059
|
-
|
|
34773
|
+
mkdirSync11(path30.dirname(metaPath), { recursive: true });
|
|
34774
|
+
writeFileSync16(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
34060
34775
|
}
|
|
34061
34776
|
async function countSessions(name, baseDir) {
|
|
34062
34777
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
@@ -34094,7 +34809,7 @@ var SessionNotFoundError = class extends Error {
|
|
|
34094
34809
|
};
|
|
34095
34810
|
function branchExists(name, baseDir = getBranchesBaseDir()) {
|
|
34096
34811
|
const bp = branchPathFor(name, baseDir);
|
|
34097
|
-
return
|
|
34812
|
+
return existsSync27(bp) && existsSync27(metaPathFor(name, baseDir));
|
|
34098
34813
|
}
|
|
34099
34814
|
async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(), sessionsBaseDir = getSessionsBaseDir()) {
|
|
34100
34815
|
if (!name || name.trim().length === 0) {
|
|
@@ -34106,14 +34821,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
34106
34821
|
if (branchExists(name, baseDir)) {
|
|
34107
34822
|
throw new BranchAlreadyExistsError(name);
|
|
34108
34823
|
}
|
|
34109
|
-
const sourcePath =
|
|
34110
|
-
if (!
|
|
34824
|
+
const sourcePath = path30.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
34825
|
+
if (!existsSync27(sourcePath)) {
|
|
34111
34826
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
34112
34827
|
}
|
|
34113
34828
|
const branchPath = branchPathFor(name, baseDir);
|
|
34114
34829
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
34115
|
-
|
|
34116
|
-
const destPath =
|
|
34830
|
+
mkdirSync11(branchSessionsPath, { recursive: true });
|
|
34831
|
+
const destPath = path30.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
34117
34832
|
await fs17.copyFile(sourcePath, destPath);
|
|
34118
34833
|
const meta3 = {
|
|
34119
34834
|
name,
|
|
@@ -34140,7 +34855,7 @@ async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
|
34140
34855
|
const results = [];
|
|
34141
34856
|
for (const entry of entries) {
|
|
34142
34857
|
const metaPath = metaPathFor(entry, baseDir);
|
|
34143
|
-
if (!
|
|
34858
|
+
if (!existsSync27(metaPath)) continue;
|
|
34144
34859
|
try {
|
|
34145
34860
|
const meta3 = readBranchMeta(entry, baseDir);
|
|
34146
34861
|
const sessionCount = await countSessions(entry, baseDir);
|
|
@@ -34214,14 +34929,14 @@ async function handleBranchCheckout(ctx, branchName) {
|
|
|
34214
34929
|
|
|
34215
34930
|
// src/cli/slashHandlers/workspace.ts
|
|
34216
34931
|
import { promises as fs18 } from "node:fs";
|
|
34217
|
-
import
|
|
34932
|
+
import path31 from "node:path";
|
|
34218
34933
|
async function handleWorkspaceShow(ctx, what) {
|
|
34219
34934
|
try {
|
|
34220
|
-
const zelari =
|
|
34935
|
+
const zelari = path31.join(process.cwd(), ".zelari");
|
|
34221
34936
|
let content;
|
|
34222
34937
|
switch (what) {
|
|
34223
34938
|
case "plan": {
|
|
34224
|
-
const planPath =
|
|
34939
|
+
const planPath = path31.join(zelari, "plan.md");
|
|
34225
34940
|
try {
|
|
34226
34941
|
content = await fs18.readFile(planPath, "utf-8");
|
|
34227
34942
|
} catch {
|
|
@@ -34230,7 +34945,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
34230
34945
|
break;
|
|
34231
34946
|
}
|
|
34232
34947
|
case "decisions": {
|
|
34233
|
-
const decisionsDir =
|
|
34948
|
+
const decisionsDir = path31.join(zelari, "decisions");
|
|
34234
34949
|
try {
|
|
34235
34950
|
const files = (await fs18.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
34236
34951
|
if (files.length === 0) {
|
|
@@ -34240,7 +34955,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
34240
34955
|
`];
|
|
34241
34956
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
34242
34957
|
for (const f of files) {
|
|
34243
|
-
const raw = await fs18.readFile(
|
|
34958
|
+
const raw = await fs18.readFile(path31.join(decisionsDir, f), "utf-8");
|
|
34244
34959
|
const { meta: meta3, body } = parseFrontmatter2(raw);
|
|
34245
34960
|
const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
|
|
34246
34961
|
lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
|
|
@@ -34253,7 +34968,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
34253
34968
|
break;
|
|
34254
34969
|
}
|
|
34255
34970
|
case "risks": {
|
|
34256
|
-
const risksPath =
|
|
34971
|
+
const risksPath = path31.join(zelari, "risks.md");
|
|
34257
34972
|
try {
|
|
34258
34973
|
content = await fs18.readFile(risksPath, "utf-8");
|
|
34259
34974
|
} catch {
|
|
@@ -34262,7 +34977,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
34262
34977
|
break;
|
|
34263
34978
|
}
|
|
34264
34979
|
case "agents": {
|
|
34265
|
-
const agentsPath =
|
|
34980
|
+
const agentsPath = path31.join(process.cwd(), "AGENTS.MD");
|
|
34266
34981
|
try {
|
|
34267
34982
|
content = await fs18.readFile(agentsPath, "utf-8");
|
|
34268
34983
|
} catch {
|
|
@@ -34271,7 +34986,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
34271
34986
|
break;
|
|
34272
34987
|
}
|
|
34273
34988
|
case "docs": {
|
|
34274
|
-
const docsDir =
|
|
34989
|
+
const docsDir = path31.join(zelari, "docs");
|
|
34275
34990
|
try {
|
|
34276
34991
|
const files = (await fs18.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
34277
34992
|
content = files.length ? `# Docs (${files.length})
|
|
@@ -34313,7 +35028,7 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
34313
35028
|
return;
|
|
34314
35029
|
}
|
|
34315
35030
|
try {
|
|
34316
|
-
const target =
|
|
35031
|
+
const target = path31.join(process.cwd(), ".zelari");
|
|
34317
35032
|
await fs18.rm(target, { recursive: true, force: true });
|
|
34318
35033
|
appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
|
|
34319
35034
|
} catch (err) {
|
|
@@ -34672,11 +35387,11 @@ function handleModelsRefresh(ctx) {
|
|
|
34672
35387
|
}
|
|
34673
35388
|
|
|
34674
35389
|
// src/cli/slashHandlers/skills.ts
|
|
34675
|
-
import
|
|
34676
|
-
import
|
|
35390
|
+
import path32 from "node:path";
|
|
35391
|
+
import os12 from "node:os";
|
|
34677
35392
|
|
|
34678
35393
|
// src/cli/skillHistory.ts
|
|
34679
|
-
import { promises as fs19, existsSync as
|
|
35394
|
+
import { promises as fs19, existsSync as existsSync28, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync3, mkdirSync as mkdirSync12 } from "node:fs";
|
|
34680
35395
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
34681
35396
|
async function readSkillHistory(file2) {
|
|
34682
35397
|
let raw = "";
|
|
@@ -34774,7 +35489,7 @@ async function applySteerInterrupt(options) {
|
|
|
34774
35489
|
|
|
34775
35490
|
// src/cli/slashHandlers/skills.ts
|
|
34776
35491
|
async function handleSkillStats(ctx, skillId) {
|
|
34777
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
35492
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path32.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
34778
35493
|
try {
|
|
34779
35494
|
const records = await readSkillHistory(historyFile);
|
|
34780
35495
|
const stats = getSkillStats(records, skillId);
|
|
@@ -34790,7 +35505,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
|
|
|
34790
35505
|
appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
|
|
34791
35506
|
return;
|
|
34792
35507
|
}
|
|
34793
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
35508
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path32.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
34794
35509
|
try {
|
|
34795
35510
|
const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
|
|
34796
35511
|
appendSystem(ctx.setMessages, formatted);
|
|
@@ -35053,6 +35768,24 @@ function useSlashDispatch(params) {
|
|
|
35053
35768
|
setInput("");
|
|
35054
35769
|
return;
|
|
35055
35770
|
}
|
|
35771
|
+
if (result.kind === "plugins_list") {
|
|
35772
|
+
await handlePluginsList({ setMessages }, process.cwd());
|
|
35773
|
+
setInput("");
|
|
35774
|
+
return;
|
|
35775
|
+
}
|
|
35776
|
+
if (result.kind === "plugins_install") {
|
|
35777
|
+
await handlePluginsInstall({ setMessages }, process.cwd(), result.pluginId ?? "");
|
|
35778
|
+
setInput("");
|
|
35779
|
+
return;
|
|
35780
|
+
}
|
|
35781
|
+
if (result.kind === "plugins_usage") {
|
|
35782
|
+
appendSystem(
|
|
35783
|
+
setMessages,
|
|
35784
|
+
result.message ?? "Usage: /plugins | /plugins install <id>"
|
|
35785
|
+
);
|
|
35786
|
+
setInput("");
|
|
35787
|
+
return;
|
|
35788
|
+
}
|
|
35056
35789
|
if (result.kind === "workspace") {
|
|
35057
35790
|
appendSystem(
|
|
35058
35791
|
setMessages,
|
|
@@ -35616,13 +36349,131 @@ function SplashGate({
|
|
|
35616
36349
|
return /* @__PURE__ */ React10.createElement(React10.Fragment, null, children);
|
|
35617
36350
|
}
|
|
35618
36351
|
|
|
36352
|
+
// src/cli/components/PluginGate.tsx
|
|
36353
|
+
import React11, { useEffect as useEffect9, useState as useState10, useCallback as useCallback6 } from "react";
|
|
36354
|
+
import { Box as Box10, Text as Text11, useStdin as useStdin4 } from "ink";
|
|
36355
|
+
init_registry2();
|
|
36356
|
+
init_prefs();
|
|
36357
|
+
var CHOICE_INSTALL = "__install__";
|
|
36358
|
+
var CHOICE_LATER = "__later__";
|
|
36359
|
+
var CHOICE_NEVER = "__never__";
|
|
36360
|
+
function PluginGate({ cwd, children }) {
|
|
36361
|
+
const { isRawModeSupported } = useStdin4();
|
|
36362
|
+
const [phase, setPhase] = useState10("detecting");
|
|
36363
|
+
const [queue, setQueue] = useState10([]);
|
|
36364
|
+
const [current, setCurrent] = useState10(null);
|
|
36365
|
+
const [result, setResult] = useState10(null);
|
|
36366
|
+
const skipGate = process.env.ZELARI_NO_PLUGIN_PROMPT === "1" || isRawModeSupported !== true;
|
|
36367
|
+
useEffect9(() => {
|
|
36368
|
+
if (skipGate) {
|
|
36369
|
+
setPhase("done");
|
|
36370
|
+
return;
|
|
36371
|
+
}
|
|
36372
|
+
let cancelled = false;
|
|
36373
|
+
void detectMissingPlugins(cwd).then((missing) => {
|
|
36374
|
+
if (cancelled) return;
|
|
36375
|
+
if (missing.length === 0) {
|
|
36376
|
+
setPhase("done");
|
|
36377
|
+
return;
|
|
36378
|
+
}
|
|
36379
|
+
setQueue(missing);
|
|
36380
|
+
setCurrent(missing[0] ?? null);
|
|
36381
|
+
setPhase(missing[0] ? "prompting" : "done");
|
|
36382
|
+
}).catch(() => {
|
|
36383
|
+
if (!cancelled) setPhase("done");
|
|
36384
|
+
});
|
|
36385
|
+
return () => {
|
|
36386
|
+
cancelled = true;
|
|
36387
|
+
};
|
|
36388
|
+
}, [cwd, skipGate]);
|
|
36389
|
+
const advance = useCallback6(() => {
|
|
36390
|
+
setQueue((q) => {
|
|
36391
|
+
const rest = q.slice(1);
|
|
36392
|
+
if (rest.length === 0) {
|
|
36393
|
+
setPhase("done");
|
|
36394
|
+
setCurrent(null);
|
|
36395
|
+
return rest;
|
|
36396
|
+
}
|
|
36397
|
+
setCurrent(rest[0] ?? null);
|
|
36398
|
+
setPhase(rest[0] ? "prompting" : "done");
|
|
36399
|
+
setResult(null);
|
|
36400
|
+
return rest;
|
|
36401
|
+
});
|
|
36402
|
+
}, []);
|
|
36403
|
+
const onSelect = useCallback6(
|
|
36404
|
+
(value) => {
|
|
36405
|
+
if (!current) return;
|
|
36406
|
+
if (value === CHOICE_LATER) {
|
|
36407
|
+
advance();
|
|
36408
|
+
} else if (value === CHOICE_NEVER) {
|
|
36409
|
+
markDontAskAgain(current.id);
|
|
36410
|
+
advance();
|
|
36411
|
+
} else if (value === CHOICE_INSTALL) {
|
|
36412
|
+
setPhase("installing");
|
|
36413
|
+
void installPlugin(current, cwd).then((r) => {
|
|
36414
|
+
setResult(r);
|
|
36415
|
+
setPhase("result");
|
|
36416
|
+
}).catch(() => {
|
|
36417
|
+
setResult({ ok: false, output: "", exitCode: null, error: "unexpected error" });
|
|
36418
|
+
setPhase("result");
|
|
36419
|
+
});
|
|
36420
|
+
}
|
|
36421
|
+
},
|
|
36422
|
+
[current, cwd, advance]
|
|
36423
|
+
);
|
|
36424
|
+
if (phase === "done") {
|
|
36425
|
+
return /* @__PURE__ */ React11.createElement(React11.Fragment, null, children);
|
|
36426
|
+
}
|
|
36427
|
+
if (phase === "detecting") {
|
|
36428
|
+
return /* @__PURE__ */ React11.createElement(Box10, { paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "Checking for optional tool plugins\u2026"));
|
|
36429
|
+
}
|
|
36430
|
+
if (!current) {
|
|
36431
|
+
return /* @__PURE__ */ React11.createElement(React11.Fragment, null, children);
|
|
36432
|
+
}
|
|
36433
|
+
if (phase === "installing") {
|
|
36434
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: "cyan" }, "\u23F3 Installing ", current.label, "\u2026"), /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "npm install ", current.installScope === "global" ? "-g" : "-D", " ", current.npmPackage));
|
|
36435
|
+
}
|
|
36436
|
+
if (phase === "result") {
|
|
36437
|
+
const ok = result?.ok === true;
|
|
36438
|
+
return /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(Text11, { color: ok ? "green" : "red" }, ok ? "\u2713" : "\u2717", " ", ok ? "Installed" : "Install failed", ": ", current.label), !ok && result?.error ? /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, result.error) : null, ok && current.postInstallHint ? /* @__PURE__ */ React11.createElement(Text11, { color: "yellow" }, " \u2192 ", current.postInstallHint) : null, /* @__PURE__ */ React11.createElement(Text11, { dimColor: true }, "Press any key to continue\u2026"), /* @__PURE__ */ React11.createElement(ContinueKey, { onContinue: advance }));
|
|
36439
|
+
}
|
|
36440
|
+
const items = [
|
|
36441
|
+
{
|
|
36442
|
+
value: CHOICE_INSTALL,
|
|
36443
|
+
label: `Install now`,
|
|
36444
|
+
hint: `npm i ${current.installScope === "global" ? "-g" : "-D"} ${current.npmPackage}`
|
|
36445
|
+
},
|
|
36446
|
+
{ value: CHOICE_LATER, label: "Maybe later" },
|
|
36447
|
+
{ value: CHOICE_NEVER, label: "Don't ask again" }
|
|
36448
|
+
];
|
|
36449
|
+
return /* @__PURE__ */ React11.createElement(
|
|
36450
|
+
SelectList,
|
|
36451
|
+
{
|
|
36452
|
+
title: `Optional plugin missing: ${current.label}`,
|
|
36453
|
+
items,
|
|
36454
|
+
onSelect,
|
|
36455
|
+
onCancel: advance,
|
|
36456
|
+
maxVisible: 4
|
|
36457
|
+
}
|
|
36458
|
+
);
|
|
36459
|
+
}
|
|
36460
|
+
function ContinueKey({ onContinue }) {
|
|
36461
|
+
const { isRawModeSupported } = useStdin4();
|
|
36462
|
+
useEffect9(() => {
|
|
36463
|
+
const t = setTimeout(onContinue, 1500);
|
|
36464
|
+
return () => clearTimeout(t);
|
|
36465
|
+
}, [onContinue]);
|
|
36466
|
+
void isRawModeSupported;
|
|
36467
|
+
return null;
|
|
36468
|
+
}
|
|
36469
|
+
|
|
35619
36470
|
// src/cli/main.ts
|
|
35620
36471
|
init_providerConfig();
|
|
35621
36472
|
|
|
35622
36473
|
// src/cli/wizard/firstRun.ts
|
|
35623
|
-
import { existsSync as
|
|
36474
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
35624
36475
|
function shouldRunWizard(input) {
|
|
35625
|
-
const exists = input.exists ??
|
|
36476
|
+
const exists = input.exists ?? existsSync29;
|
|
35626
36477
|
if (input.hasResetConfigFlag) {
|
|
35627
36478
|
return { shouldRun: true, reason: "--reset-config flag forced wizard" };
|
|
35628
36479
|
}
|
|
@@ -35657,15 +36508,15 @@ function parseWizardFlags(argv) {
|
|
|
35657
36508
|
}
|
|
35658
36509
|
|
|
35659
36510
|
// src/cli/wizard/runWizard.tsx
|
|
35660
|
-
import
|
|
35661
|
-
import { Box as
|
|
36511
|
+
import React13, { useEffect as useEffect10, useState as useState11 } from "react";
|
|
36512
|
+
import { Box as Box12, Text as Text13 } from "ink";
|
|
35662
36513
|
import { useInput as useInput4 } from "ink";
|
|
35663
36514
|
init_keyStore();
|
|
35664
36515
|
init_providerConfig();
|
|
35665
36516
|
|
|
35666
36517
|
// src/cli/wizard/index.tsx
|
|
35667
|
-
import
|
|
35668
|
-
import { Box as
|
|
36518
|
+
import React12 from "react";
|
|
36519
|
+
import { Box as Box11, Text as Text12 } from "ink";
|
|
35669
36520
|
|
|
35670
36521
|
// src/cli/wizard/useWizardState.ts
|
|
35671
36522
|
init_providerConfig();
|
|
@@ -35781,16 +36632,16 @@ var API_KEY_OPTIONS = ["env", "keystore", "skip"];
|
|
|
35781
36632
|
|
|
35782
36633
|
// src/cli/wizard/index.tsx
|
|
35783
36634
|
function Frame({ children }) {
|
|
35784
|
-
return /* @__PURE__ */
|
|
36635
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1 }, children);
|
|
35785
36636
|
}
|
|
35786
36637
|
function Step(props) {
|
|
35787
|
-
return /* @__PURE__ */
|
|
36638
|
+
return /* @__PURE__ */ React12.createElement(Box11, null, /* @__PURE__ */ React12.createElement(Text12, { color: props.active ? "cyan" : "gray", inverse: props.active }, " ", props.index, "/", props.total, " ", props.name, " "));
|
|
35788
36639
|
}
|
|
35789
36640
|
function renderProviderList(providers, cursor) {
|
|
35790
|
-
return /* @__PURE__ */
|
|
36641
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, providers.map((p3, i) => {
|
|
35791
36642
|
const arrow = i === cursor ? "\u279C " : " ";
|
|
35792
36643
|
const color = i === cursor ? "cyan" : void 0;
|
|
35793
|
-
return /* @__PURE__ */
|
|
36644
|
+
return /* @__PURE__ */ React12.createElement(Text12, { key: p3.id, color }, arrow, p3.displayName, " ", /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "(", p3.id, ", uses env ", p3.envVar, ")"));
|
|
35794
36645
|
}));
|
|
35795
36646
|
}
|
|
35796
36647
|
function renderApiKeyOptions(cursor) {
|
|
@@ -35799,30 +36650,30 @@ function renderApiKeyOptions(cursor) {
|
|
|
35799
36650
|
keystore: "Save to local keyStore (encrypted)",
|
|
35800
36651
|
skip: "Skip for now (chat will fail until key is set)"
|
|
35801
36652
|
};
|
|
35802
|
-
return /* @__PURE__ */
|
|
36653
|
+
return /* @__PURE__ */ React12.createElement(Box11, { flexDirection: "column" }, API_KEY_OPTIONS.map((choice, i) => {
|
|
35803
36654
|
const arrow = i === cursor ? "\u279C " : " ";
|
|
35804
36655
|
const color = i === cursor ? "cyan" : void 0;
|
|
35805
|
-
return /* @__PURE__ */
|
|
36656
|
+
return /* @__PURE__ */ React12.createElement(Text12, { key: choice, color }, arrow, labels[choice]);
|
|
35806
36657
|
}));
|
|
35807
36658
|
}
|
|
35808
36659
|
function Wizard({ state: state2, providers }) {
|
|
35809
36660
|
const s = state2.state;
|
|
35810
36661
|
if (s.committed) {
|
|
35811
|
-
return /* @__PURE__ */
|
|
36662
|
+
return /* @__PURE__ */ React12.createElement(Frame, null, /* @__PURE__ */ React12.createElement(Text12, { color: "green" }, "\u2713 Setup complete!"), /* @__PURE__ */ React12.createElement(Text12, null, "Provider: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.providerId), " | ", "Model: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.model), " | ", "API key: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.apiKeyChoice ?? "n/a")), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "Launching zelari-code\u2026 (press any key)")));
|
|
35812
36663
|
}
|
|
35813
|
-
return /* @__PURE__ */
|
|
36664
|
+
return /* @__PURE__ */ React12.createElement(Frame, null, /* @__PURE__ */ React12.createElement(Text12, { color: "cyan", bold: true }, "zelari-code v", VERSION, " \u2014 first-time setup"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, marginBottom: 1, flexDirection: "row" }, /* @__PURE__ */ React12.createElement(Step, { index: 1, total: 5, name: "welcome", active: s.step === "welcome" }), /* @__PURE__ */ React12.createElement(Step, { index: 2, total: 5, name: "provider", active: s.step === "provider" }), /* @__PURE__ */ React12.createElement(Step, { index: 3, total: 5, name: "model", active: s.step === "model" }), /* @__PURE__ */ React12.createElement(Step, { index: 4, total: 5, name: "apikey", active: s.step === "apikey" }), /* @__PURE__ */ React12.createElement(Step, { index: 5, total: 5, name: "confirm", active: s.step === "confirm" })), s.step === "welcome" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "Welcome! Let's get you coding in under two minutes."), /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "We'll pick a provider, default model, and how to handle your API key."), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, null, "Press "), /* @__PURE__ */ React12.createElement(Text12, { color: "cyan", inverse: true }, " Enter "), /* @__PURE__ */ React12.createElement(Text12, null, " to continue, or "), /* @__PURE__ */ React12.createElement(Text12, { color: "red", inverse: true }, " Q "), /* @__PURE__ */ React12.createElement(Text12, null, " to quit (re-run with "), /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "--no-wizard"), /* @__PURE__ */ React12.createElement(Text12, null, " to skip later)."))), s.step === "provider" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "Choose your LLM provider:"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, renderProviderList(providers, s.providerCursor)), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "model" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "Model for ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.providerId), ":"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 }, /* @__PURE__ */ React12.createElement(Text12, null, s.model ?? "(empty)")), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, null, "Press ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan", inverse: true }, " Enter "), "to accept, or type a new name. ", /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "(default kept on empty input)")))), s.step === "apikey" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "How should we handle the API key?"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, renderApiKeyOptions(s.apiKeyCursor)), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, { color: "gray" }, "\u2191/\u2193 to move, Enter to confirm"))), s.step === "confirm" && /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(Text12, null, "Confirm your setup:"), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React12.createElement(Text12, null, "Provider: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.providerId)), /* @__PURE__ */ React12.createElement(Text12, null, "Model: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.model)), /* @__PURE__ */ React12.createElement(Text12, null, "API key: ", /* @__PURE__ */ React12.createElement(Text12, { color: "cyan" }, s.apiKeyChoice ?? "(unset)"))), /* @__PURE__ */ React12.createElement(Box11, { marginTop: 1 }, /* @__PURE__ */ React12.createElement(Text12, null, "Press ", /* @__PURE__ */ React12.createElement(Text12, { color: "green", inverse: true }, " Enter "), "to save and launch, or ", /* @__PURE__ */ React12.createElement(Text12, { color: "yellow", inverse: true }, " B "), "to go back."))));
|
|
35814
36665
|
}
|
|
35815
36666
|
|
|
35816
36667
|
// src/cli/wizard/runWizard.tsx
|
|
35817
36668
|
function RunWizard(_props) {
|
|
35818
|
-
const [wiz] =
|
|
36669
|
+
const [wiz] = useState11(
|
|
35819
36670
|
() => createWizardState({
|
|
35820
36671
|
providers: PROVIDERS,
|
|
35821
36672
|
defaultModelFor: (id) => getModelForProvider(id)
|
|
35822
36673
|
})
|
|
35823
36674
|
);
|
|
35824
|
-
const [, force] =
|
|
35825
|
-
|
|
36675
|
+
const [, force] = useState11(0);
|
|
36676
|
+
useEffect10(() => {
|
|
35826
36677
|
if (typeof wiz.subscribe === "function") {
|
|
35827
36678
|
const sub = wiz.subscribe(() => force((n) => n + 1));
|
|
35828
36679
|
return () => sub();
|
|
@@ -35886,20 +36737,20 @@ function RunWizard(_props) {
|
|
|
35886
36737
|
}
|
|
35887
36738
|
});
|
|
35888
36739
|
if (wiz.state.committed) {
|
|
35889
|
-
return /* @__PURE__ */
|
|
36740
|
+
return /* @__PURE__ */ React13.createElement(PostCommitBridge, null);
|
|
35890
36741
|
}
|
|
35891
|
-
return /* @__PURE__ */
|
|
36742
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React13.createElement(Wizard, { state: wiz, providers: PROVIDERS }));
|
|
35892
36743
|
}
|
|
35893
36744
|
function PostCommitBridge() {
|
|
35894
|
-
const [showApp, setShowApp] =
|
|
35895
|
-
|
|
36745
|
+
const [showApp, setShowApp] = useState11(false);
|
|
36746
|
+
useEffect10(() => {
|
|
35896
36747
|
const t = setTimeout(() => setShowApp(true), 1200);
|
|
35897
36748
|
return () => clearTimeout(t);
|
|
35898
36749
|
}, []);
|
|
35899
36750
|
if (showApp) {
|
|
35900
|
-
return /* @__PURE__ */
|
|
36751
|
+
return /* @__PURE__ */ React13.createElement(App, null);
|
|
35901
36752
|
}
|
|
35902
|
-
return /* @__PURE__ */
|
|
36753
|
+
return /* @__PURE__ */ React13.createElement(Box12, { flexDirection: "column", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React13.createElement(Box12, { borderStyle: "round", borderColor: "green", paddingX: 2, paddingY: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(Text13, { color: "green", bold: true }, "\u2713 Setup complete! Launching zelari-code\u2026"), /* @__PURE__ */ React13.createElement(Text13, { color: "gray" }, "Press Ctrl+C any time to exit.")));
|
|
35903
36754
|
}
|
|
35904
36755
|
|
|
35905
36756
|
// src/cli/headless.ts
|
|
@@ -36112,7 +36963,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream) {
|
|
|
36112
36963
|
|
|
36113
36964
|
// src/cli/skillsMd.ts
|
|
36114
36965
|
init_skills2();
|
|
36115
|
-
import { existsSync as
|
|
36966
|
+
import { existsSync as existsSync30, readdirSync as readdirSync4, readFileSync as readFileSync25 } from "node:fs";
|
|
36116
36967
|
import { join as join23 } from "node:path";
|
|
36117
36968
|
import { homedir as homedir6 } from "node:os";
|
|
36118
36969
|
var CODING_CATEGORIES = /* @__PURE__ */ new Set([
|
|
@@ -36190,7 +37041,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
36190
37041
|
const summary = { loaded: [], skipped: [] };
|
|
36191
37042
|
const seen = new Set(options.existingIds ?? []);
|
|
36192
37043
|
for (const dir of skillMdSearchDirs(projectRoot)) {
|
|
36193
|
-
if (!
|
|
37044
|
+
if (!existsSync30(dir)) continue;
|
|
36194
37045
|
let entries;
|
|
36195
37046
|
try {
|
|
36196
37047
|
entries = readdirSync4(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -36199,9 +37050,9 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
36199
37050
|
}
|
|
36200
37051
|
for (const entry of entries) {
|
|
36201
37052
|
const skillPath = join23(dir, entry, "SKILL.md");
|
|
36202
|
-
if (!
|
|
37053
|
+
if (!existsSync30(skillPath)) continue;
|
|
36203
37054
|
try {
|
|
36204
|
-
const parsed = parseSkillMd(
|
|
37055
|
+
const parsed = parseSkillMd(readFileSync25(skillPath, "utf8"), skillPath);
|
|
36205
37056
|
if (!parsed) {
|
|
36206
37057
|
summary.skipped.push({ path: skillPath, reason: "missing/invalid frontmatter (name, description) or empty body" });
|
|
36207
37058
|
continue;
|
|
@@ -36225,6 +37076,38 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
36225
37076
|
init_skills2();
|
|
36226
37077
|
init_updater();
|
|
36227
37078
|
var VERSION = getCurrentVersion();
|
|
37079
|
+
function runPreflight() {
|
|
37080
|
+
if (process.env.ZELARI_SKIP_PREFLIGHT === "1") return;
|
|
37081
|
+
if (process.argv.includes("--skip-checks")) return;
|
|
37082
|
+
if (process.env.ANATHEMA_DEV === "1") return;
|
|
37083
|
+
const { runPrereqChecks: runPrereqChecks2 } = (
|
|
37084
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
37085
|
+
(init_prereqChecks(), __toCommonJS(prereqChecks_exports))
|
|
37086
|
+
);
|
|
37087
|
+
const { results, hasCriticalFail, warnings } = runPrereqChecks2({
|
|
37088
|
+
mode: "preflight"
|
|
37089
|
+
});
|
|
37090
|
+
for (const w of warnings) {
|
|
37091
|
+
console.error(`\x1B[33m[zelari-code] \u26A0 ${w.tool}: ${w.message}\x1B[0m`);
|
|
37092
|
+
}
|
|
37093
|
+
if (hasCriticalFail) {
|
|
37094
|
+
const critical = results.find(
|
|
37095
|
+
(r) => !r.ok && r.severity === "critical"
|
|
37096
|
+
);
|
|
37097
|
+
console.error("");
|
|
37098
|
+
console.error(
|
|
37099
|
+
"\x1B[31m==============================================================\n zelari-code cannot start: a critical prerequisite is missing.\n==============================================================\x1B[0m"
|
|
37100
|
+
);
|
|
37101
|
+
if (critical) {
|
|
37102
|
+
console.error(`
|
|
37103
|
+
${critical.tool}: ${critical.message}`);
|
|
37104
|
+
}
|
|
37105
|
+
console.error(
|
|
37106
|
+
"\n Run `zelari-code --doctor` for the full diagnostic report.\n Bypass this check with ZELARI_SKIP_PREFLIGHT=1 (NOT recommended \u2014\n the agent will still fail when it tries to run npm/build/tsc)."
|
|
37107
|
+
);
|
|
37108
|
+
process.exit(1);
|
|
37109
|
+
}
|
|
37110
|
+
}
|
|
36228
37111
|
async function backgroundUpdateCheck() {
|
|
36229
37112
|
if (process.env.ANATHEMA_DEV === "1") return;
|
|
36230
37113
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
@@ -36259,12 +37142,34 @@ function pickRootComponent() {
|
|
|
36259
37142
|
}
|
|
36260
37143
|
if (argv.includes("--doctor") || argv.includes("doctor")) {
|
|
36261
37144
|
const { runDoctor: runDoctor2 } = (init_doctor(), __toCommonJS(doctor_exports));
|
|
36262
|
-
|
|
36263
|
-
|
|
37145
|
+
void runDoctor2().then((healthy) => process.exit(healthy ? 0 : 1));
|
|
37146
|
+
return { kind: "done" };
|
|
37147
|
+
}
|
|
37148
|
+
if (argv.includes("--fix-path") || argv.includes("fix-path")) {
|
|
37149
|
+
const { repairWindowsUserPath: repairWindowsUserPath2 } = (init_fixPath(), __toCommonJS(fixPath_exports));
|
|
37150
|
+
const result = repairWindowsUserPath2();
|
|
37151
|
+
const green = "\x1B[32m";
|
|
37152
|
+
const red = "\x1B[31m";
|
|
37153
|
+
const dim = "\x1B[2m";
|
|
37154
|
+
const reset = "\x1B[0m";
|
|
37155
|
+
if (result.ok) {
|
|
37156
|
+
if (result.alreadyOk) {
|
|
37157
|
+
console.log(`${green}\u2714${reset} npm prefix already on user PATH: ${result.prefix}`);
|
|
37158
|
+
} else {
|
|
37159
|
+
console.log(`${green}\u2714${reset} added npm prefix to user PATH: ${result.prefix}`);
|
|
37160
|
+
console.log(`${dim}open a NEW terminal for the change to take effect, then run: zelari-code --version${reset}`);
|
|
37161
|
+
}
|
|
37162
|
+
process.exit(0);
|
|
37163
|
+
}
|
|
37164
|
+
console.error(`${red}\u2717${reset} ${result.error}`);
|
|
37165
|
+
if (result.prefix) {
|
|
37166
|
+
console.error(`${dim}prefix: ${result.prefix}${reset}`);
|
|
37167
|
+
}
|
|
37168
|
+
process.exit(1);
|
|
36264
37169
|
}
|
|
36265
37170
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
36266
37171
|
console.log(
|
|
36267
|
-
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor Diagnose install health (shim, bundle, PATH, deps)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --council Use the 6-member council pipeline\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n\nEnvironment:\n ZELARI_NO_WIZARD=1
|
|
37172
|
+
"zelari-code \u2014 AI Council coding agent CLI.\n\nUsage: zelari-code [options]\n\nOptions:\n --version, -v Print version and exit\n --help, -h Print this help and exit\n --doctor Diagnose install health (shim, bundle, PATH, deps,\n node/git/bash in the agent shell)\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --council Use the 6-member council pipeline\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
|
|
36268
37173
|
);
|
|
36269
37174
|
process.exit(0);
|
|
36270
37175
|
}
|
|
@@ -36285,14 +37190,17 @@ function pickRootComponent() {
|
|
|
36285
37190
|
});
|
|
36286
37191
|
if (decision.shouldRun) {
|
|
36287
37192
|
console.error(`[zelari-code] starting wizard: ${decision.reason}`);
|
|
36288
|
-
return { kind: "wizard", element:
|
|
37193
|
+
return { kind: "wizard", element: React14.createElement(RunWizard) };
|
|
36289
37194
|
}
|
|
36290
37195
|
return {
|
|
36291
37196
|
kind: "app",
|
|
36292
|
-
element:
|
|
37197
|
+
element: React14.createElement(
|
|
36293
37198
|
SplashGate,
|
|
36294
37199
|
{ version: VERSION },
|
|
36295
|
-
|
|
37200
|
+
React14.createElement(PluginGate, {
|
|
37201
|
+
cwd: process.cwd(),
|
|
37202
|
+
children: React14.createElement(App)
|
|
37203
|
+
})
|
|
36296
37204
|
)
|
|
36297
37205
|
};
|
|
36298
37206
|
}
|
|
@@ -36314,6 +37222,7 @@ function loadUserSkills() {
|
|
|
36314
37222
|
function main() {
|
|
36315
37223
|
const picked = pickRootComponent();
|
|
36316
37224
|
if (picked.kind === "done") return;
|
|
37225
|
+
runPreflight();
|
|
36317
37226
|
loadUserSkills();
|
|
36318
37227
|
if (picked.kind === "headless") {
|
|
36319
37228
|
void runHeadless(picked.headlessOpts).then((code) => {
|