zelari-code 1.31.0 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/inspect.js +166 -0
- package/dist/cli/commands/inspect.js.map +1 -0
- package/dist/cli/hooks/useSlashDispatch.js +17 -0
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/main.bundled.js +1560 -840
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +30 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/mcpManager.js +15 -4
- package/dist/cli/mcp/mcpManager.js.map +1 -1
- package/dist/cli/mcp/mcpPresets.js +12 -5
- package/dist/cli/mcp/mcpPresets.js.map +1 -1
- package/dist/cli/safety/folderTrust.js +124 -0
- package/dist/cli/safety/folderTrust.js.map +1 -0
- package/dist/cli/safety/lifecycleHooks.js +52 -0
- package/dist/cli/safety/lifecycleHooks.js.map +1 -0
- package/dist/cli/slashCommands.js +18 -1
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/slashHandlers/trust.js +52 -0
- package/dist/cli/slashHandlers/trust.js.map +1 -0
- package/dist/cli/toolRegistry.js +7 -0
- package/dist/cli/toolRegistry.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -395,7 +395,7 @@ async function refreshGrokToken(options) {
|
|
|
395
395
|
return parseTokenResponseBody(obj, accessToken);
|
|
396
396
|
}
|
|
397
397
|
async function openBrowser(url2) {
|
|
398
|
-
const { spawn:
|
|
398
|
+
const { spawn: spawn14 } = await import("node:child_process");
|
|
399
399
|
const cmd = (() => {
|
|
400
400
|
switch (process.platform) {
|
|
401
401
|
case "darwin":
|
|
@@ -408,7 +408,7 @@ async function openBrowser(url2) {
|
|
|
408
408
|
})();
|
|
409
409
|
return new Promise((resolve3, reject) => {
|
|
410
410
|
try {
|
|
411
|
-
const child =
|
|
411
|
+
const child = spawn14(cmd.bin, cmd.args, {
|
|
412
412
|
stdio: "ignore",
|
|
413
413
|
detached: true
|
|
414
414
|
});
|
|
@@ -1829,10 +1829,10 @@ function mergeDefs(...defs) {
|
|
|
1829
1829
|
function cloneDef(schema) {
|
|
1830
1830
|
return mergeDefs(schema._zod.def);
|
|
1831
1831
|
}
|
|
1832
|
-
function getElementAtPath(obj,
|
|
1833
|
-
if (!
|
|
1832
|
+
function getElementAtPath(obj, path51) {
|
|
1833
|
+
if (!path51)
|
|
1834
1834
|
return obj;
|
|
1835
|
-
return
|
|
1835
|
+
return path51.reduce((acc, key) => acc?.[key], obj);
|
|
1836
1836
|
}
|
|
1837
1837
|
function promiseAllObject(promisesObj) {
|
|
1838
1838
|
const keys = Object.keys(promisesObj);
|
|
@@ -2160,11 +2160,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
2160
2160
|
}
|
|
2161
2161
|
return false;
|
|
2162
2162
|
}
|
|
2163
|
-
function prefixIssues(
|
|
2163
|
+
function prefixIssues(path51, issues) {
|
|
2164
2164
|
return issues.map((iss) => {
|
|
2165
2165
|
var _a3;
|
|
2166
2166
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
2167
|
-
iss.path.unshift(
|
|
2167
|
+
iss.path.unshift(path51);
|
|
2168
2168
|
return iss;
|
|
2169
2169
|
});
|
|
2170
2170
|
}
|
|
@@ -2382,16 +2382,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2382
2382
|
}
|
|
2383
2383
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
2384
2384
|
const fieldErrors = { _errors: [] };
|
|
2385
|
-
const processError = (error52,
|
|
2385
|
+
const processError = (error52, path51 = []) => {
|
|
2386
2386
|
for (const issue2 of error52.issues) {
|
|
2387
2387
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2388
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2388
|
+
issue2.errors.map((issues) => processError({ issues }, [...path51, ...issue2.path]));
|
|
2389
2389
|
} else if (issue2.code === "invalid_key") {
|
|
2390
|
-
processError({ issues: issue2.issues }, [...
|
|
2390
|
+
processError({ issues: issue2.issues }, [...path51, ...issue2.path]);
|
|
2391
2391
|
} else if (issue2.code === "invalid_element") {
|
|
2392
|
-
processError({ issues: issue2.issues }, [...
|
|
2392
|
+
processError({ issues: issue2.issues }, [...path51, ...issue2.path]);
|
|
2393
2393
|
} else {
|
|
2394
|
-
const fullpath = [...
|
|
2394
|
+
const fullpath = [...path51, ...issue2.path];
|
|
2395
2395
|
if (fullpath.length === 0) {
|
|
2396
2396
|
fieldErrors._errors.push(mapper(issue2));
|
|
2397
2397
|
} else {
|
|
@@ -2418,17 +2418,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2418
2418
|
}
|
|
2419
2419
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
2420
2420
|
const result = { errors: [] };
|
|
2421
|
-
const processError = (error52,
|
|
2421
|
+
const processError = (error52, path51 = []) => {
|
|
2422
2422
|
var _a3, _b;
|
|
2423
2423
|
for (const issue2 of error52.issues) {
|
|
2424
2424
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2425
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2425
|
+
issue2.errors.map((issues) => processError({ issues }, [...path51, ...issue2.path]));
|
|
2426
2426
|
} else if (issue2.code === "invalid_key") {
|
|
2427
|
-
processError({ issues: issue2.issues }, [...
|
|
2427
|
+
processError({ issues: issue2.issues }, [...path51, ...issue2.path]);
|
|
2428
2428
|
} else if (issue2.code === "invalid_element") {
|
|
2429
|
-
processError({ issues: issue2.issues }, [...
|
|
2429
|
+
processError({ issues: issue2.issues }, [...path51, ...issue2.path]);
|
|
2430
2430
|
} else {
|
|
2431
|
-
const fullpath = [...
|
|
2431
|
+
const fullpath = [...path51, ...issue2.path];
|
|
2432
2432
|
if (fullpath.length === 0) {
|
|
2433
2433
|
result.errors.push(mapper(issue2));
|
|
2434
2434
|
continue;
|
|
@@ -2460,8 +2460,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2460
2460
|
}
|
|
2461
2461
|
function toDotPath(_path) {
|
|
2462
2462
|
const segs = [];
|
|
2463
|
-
const
|
|
2464
|
-
for (const seg of
|
|
2463
|
+
const path51 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
2464
|
+
for (const seg of path51) {
|
|
2465
2465
|
if (typeof seg === "number")
|
|
2466
2466
|
segs.push(`[${seg}]`);
|
|
2467
2467
|
else if (typeof seg === "symbol")
|
|
@@ -15964,13 +15964,13 @@ function resolveRef(ref, ctx) {
|
|
|
15964
15964
|
if (!ref.startsWith("#")) {
|
|
15965
15965
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
15966
15966
|
}
|
|
15967
|
-
const
|
|
15968
|
-
if (
|
|
15967
|
+
const path51 = ref.slice(1).split("/").filter(Boolean);
|
|
15968
|
+
if (path51.length === 0) {
|
|
15969
15969
|
return ctx.rootSchema;
|
|
15970
15970
|
}
|
|
15971
15971
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
15972
|
-
if (
|
|
15973
|
-
const key =
|
|
15972
|
+
if (path51[0] === defsKey) {
|
|
15973
|
+
const key = path51[1];
|
|
15974
15974
|
if (!key || !ctx.defs[key]) {
|
|
15975
15975
|
throw new Error(`Reference not found: ${ref}`);
|
|
15976
15976
|
}
|
|
@@ -18134,11 +18134,11 @@ var init_tools = __esm({
|
|
|
18134
18134
|
if (!ctx.addDocument)
|
|
18135
18135
|
return "Knowledge vault tool not available.";
|
|
18136
18136
|
const title = args["title"] || "New Document";
|
|
18137
|
-
const
|
|
18137
|
+
const path51 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
18138
18138
|
const content = args["content"] || "";
|
|
18139
18139
|
const tags = args["tags"] || [];
|
|
18140
18140
|
ctx.addDocument({
|
|
18141
|
-
path:
|
|
18141
|
+
path: path51,
|
|
18142
18142
|
title,
|
|
18143
18143
|
content,
|
|
18144
18144
|
format: "markdown",
|
|
@@ -18147,7 +18147,7 @@ var init_tools = __esm({
|
|
|
18147
18147
|
workspaceId: ctx.workspaceId
|
|
18148
18148
|
});
|
|
18149
18149
|
ctx.addActivity("vault", "created document", title);
|
|
18150
|
-
return `Document "${title}" created at "${
|
|
18150
|
+
return `Document "${title}" created at "${path51}".`;
|
|
18151
18151
|
}
|
|
18152
18152
|
}
|
|
18153
18153
|
];
|
|
@@ -21166,23 +21166,303 @@ var init_sessionJsonl = __esm({
|
|
|
21166
21166
|
}
|
|
21167
21167
|
});
|
|
21168
21168
|
|
|
21169
|
+
// packages/core/dist/core/hooks/types.js
|
|
21170
|
+
function normalizeToolName(raw) {
|
|
21171
|
+
const n = raw.toLowerCase().replace(/[_-]/g, "");
|
|
21172
|
+
return TOOL_ALIASES[n] ?? n;
|
|
21173
|
+
}
|
|
21174
|
+
function toolMatches(pattern, toolName) {
|
|
21175
|
+
if (pattern === "*")
|
|
21176
|
+
return true;
|
|
21177
|
+
return normalizeToolName(pattern) === normalizeToolName(toolName);
|
|
21178
|
+
}
|
|
21179
|
+
function hookMatches(hook, event, toolName) {
|
|
21180
|
+
if (!hook.match.events.includes(event))
|
|
21181
|
+
return false;
|
|
21182
|
+
if (event === "PreToolUse" || event === "PostToolUse") {
|
|
21183
|
+
if (!toolName)
|
|
21184
|
+
return false;
|
|
21185
|
+
return hook.match.tools.some((t) => toolMatches(t, toolName));
|
|
21186
|
+
}
|
|
21187
|
+
return true;
|
|
21188
|
+
}
|
|
21189
|
+
var TOOL_ALIASES;
|
|
21190
|
+
var init_types2 = __esm({
|
|
21191
|
+
"packages/core/dist/core/hooks/types.js"() {
|
|
21192
|
+
"use strict";
|
|
21193
|
+
TOOL_ALIASES = {
|
|
21194
|
+
read: "read_file",
|
|
21195
|
+
readfile: "read_file",
|
|
21196
|
+
cat: "read_file",
|
|
21197
|
+
write: "write_file",
|
|
21198
|
+
writefile: "write_file",
|
|
21199
|
+
edit: "edit_file",
|
|
21200
|
+
editfile: "edit_file",
|
|
21201
|
+
glob: "list_files",
|
|
21202
|
+
listdir: "list_files",
|
|
21203
|
+
listdirectory: "list_files",
|
|
21204
|
+
ls: "list_files",
|
|
21205
|
+
dir: "list_files",
|
|
21206
|
+
find: "list_files",
|
|
21207
|
+
grep: "grep_content",
|
|
21208
|
+
search: "grep_content",
|
|
21209
|
+
searchrag: "searchDocuments",
|
|
21210
|
+
rag: "searchDocuments",
|
|
21211
|
+
shell: "bash",
|
|
21212
|
+
terminal: "bash",
|
|
21213
|
+
cmd: "bash",
|
|
21214
|
+
run: "bash",
|
|
21215
|
+
exec: "bash"
|
|
21216
|
+
};
|
|
21217
|
+
}
|
|
21218
|
+
});
|
|
21219
|
+
|
|
21220
|
+
// packages/core/dist/core/hooks/lifecycleHookRunner.js
|
|
21221
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
21222
|
+
import { readdirSync, readFileSync as readFileSync4 } from "node:fs";
|
|
21223
|
+
import path12 from "node:path";
|
|
21224
|
+
function parseJson(text) {
|
|
21225
|
+
try {
|
|
21226
|
+
return JSON.parse(text);
|
|
21227
|
+
} catch {
|
|
21228
|
+
return null;
|
|
21229
|
+
}
|
|
21230
|
+
}
|
|
21231
|
+
var DEFAULT_TIMEOUT_MS, LifecycleHookRunner;
|
|
21232
|
+
var init_lifecycleHookRunner = __esm({
|
|
21233
|
+
"packages/core/dist/core/hooks/lifecycleHookRunner.js"() {
|
|
21234
|
+
"use strict";
|
|
21235
|
+
init_types2();
|
|
21236
|
+
DEFAULT_TIMEOUT_MS = 5e3;
|
|
21237
|
+
LifecycleHookRunner = class {
|
|
21238
|
+
hooks = [];
|
|
21239
|
+
logger;
|
|
21240
|
+
defaultTimeoutMs;
|
|
21241
|
+
constructor(options = {}) {
|
|
21242
|
+
this.logger = options.logger ?? ((msg) => console.error(`[hooks] ${msg}`));
|
|
21243
|
+
this.defaultTimeoutMs = options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
21244
|
+
for (const dir of options.dirs ?? []) {
|
|
21245
|
+
this.loadDir(dir);
|
|
21246
|
+
}
|
|
21247
|
+
}
|
|
21248
|
+
/** Add a single hook definition (used by tests / programmatic config). */
|
|
21249
|
+
addHook(hook) {
|
|
21250
|
+
this.hooks.push(hook);
|
|
21251
|
+
}
|
|
21252
|
+
/** Scan a directory for `*.json` hook files and load them. Returns count. */
|
|
21253
|
+
loadDir(dir) {
|
|
21254
|
+
let files;
|
|
21255
|
+
try {
|
|
21256
|
+
files = readdirSync(dir).filter((f) => f.endsWith(".json"));
|
|
21257
|
+
} catch {
|
|
21258
|
+
return 0;
|
|
21259
|
+
}
|
|
21260
|
+
let loaded = 0;
|
|
21261
|
+
for (const f of files) {
|
|
21262
|
+
const full = path12.join(dir, f);
|
|
21263
|
+
try {
|
|
21264
|
+
const parsed = parseJson(readFileSync4(full, "utf8"));
|
|
21265
|
+
if (!parsed || !parsed.name || !parsed.match) {
|
|
21266
|
+
this.logger(`skipping invalid hook file ${full}`);
|
|
21267
|
+
continue;
|
|
21268
|
+
}
|
|
21269
|
+
parsed.name = parsed.name || path12.basename(f, ".json");
|
|
21270
|
+
this.hooks.push(parsed);
|
|
21271
|
+
loaded += 1;
|
|
21272
|
+
} catch (err) {
|
|
21273
|
+
this.logger(`failed to load hook ${full}: ${err instanceof Error ? err.message : String(err)}`);
|
|
21274
|
+
}
|
|
21275
|
+
}
|
|
21276
|
+
return loaded;
|
|
21277
|
+
}
|
|
21278
|
+
listHooks() {
|
|
21279
|
+
return [...this.hooks];
|
|
21280
|
+
}
|
|
21281
|
+
/**
|
|
21282
|
+
* Run matching PreToolUse hooks. Returns `{ ok: false }` ONLY when a hook
|
|
21283
|
+
* explicitly denies. All other outcomes (no match, crash, timeout, invalid
|
|
21284
|
+
* JSON, allow decision) return `{ ok: true }`.
|
|
21285
|
+
*/
|
|
21286
|
+
async runPreToolUse(toolName, toolInput, ctx) {
|
|
21287
|
+
for (const hook of this.hooks) {
|
|
21288
|
+
if (!hookMatches(hook, "PreToolUse", toolName))
|
|
21289
|
+
continue;
|
|
21290
|
+
const payload = {
|
|
21291
|
+
event: "PreToolUse",
|
|
21292
|
+
toolName,
|
|
21293
|
+
toolInput,
|
|
21294
|
+
sessionId: ctx.sessionId,
|
|
21295
|
+
cwd: ctx.cwd
|
|
21296
|
+
};
|
|
21297
|
+
const decision = await this.runHookSafely(hook, payload);
|
|
21298
|
+
if (decision.decision === "deny") {
|
|
21299
|
+
return {
|
|
21300
|
+
ok: false,
|
|
21301
|
+
hookName: hook.name,
|
|
21302
|
+
reason: decision.reason || `blocked by hook "${hook.name}"`
|
|
21303
|
+
};
|
|
21304
|
+
}
|
|
21305
|
+
}
|
|
21306
|
+
return { ok: true };
|
|
21307
|
+
}
|
|
21308
|
+
/** Run matching PostToolUse hooks. Fail-open, results are logged only. */
|
|
21309
|
+
async runPostToolUse(toolName, toolInput, toolOutput, ctx) {
|
|
21310
|
+
for (const hook of this.hooks) {
|
|
21311
|
+
if (!hookMatches(hook, "PostToolUse", toolName))
|
|
21312
|
+
continue;
|
|
21313
|
+
const payload = {
|
|
21314
|
+
event: "PostToolUse",
|
|
21315
|
+
toolName,
|
|
21316
|
+
toolInput,
|
|
21317
|
+
toolOutput,
|
|
21318
|
+
ok: ctx.ok ?? true,
|
|
21319
|
+
error: ctx.error,
|
|
21320
|
+
sessionId: ctx.sessionId,
|
|
21321
|
+
cwd: ctx.cwd
|
|
21322
|
+
};
|
|
21323
|
+
await this.runHookSafely(hook, payload);
|
|
21324
|
+
}
|
|
21325
|
+
}
|
|
21326
|
+
/** Run matching SessionStart hooks. Fail-open; deny never throws. */
|
|
21327
|
+
async runSessionStart(ctx) {
|
|
21328
|
+
return this.runSessionHooks("SessionStart", ctx);
|
|
21329
|
+
}
|
|
21330
|
+
/** Run matching SessionEnd hooks. Fail-open. */
|
|
21331
|
+
async runSessionEnd(ctx) {
|
|
21332
|
+
return this.runSessionHooks("SessionEnd", ctx);
|
|
21333
|
+
}
|
|
21334
|
+
async runSessionHooks(event, ctx) {
|
|
21335
|
+
for (const hook of this.hooks) {
|
|
21336
|
+
if (!hookMatches(hook, event, void 0))
|
|
21337
|
+
continue;
|
|
21338
|
+
const payload = {
|
|
21339
|
+
event,
|
|
21340
|
+
sessionId: ctx.sessionId,
|
|
21341
|
+
cwd: ctx.cwd
|
|
21342
|
+
};
|
|
21343
|
+
const decision = await this.runHookSafely(hook, payload);
|
|
21344
|
+
if (decision.decision === "deny") {
|
|
21345
|
+
return {
|
|
21346
|
+
ok: false,
|
|
21347
|
+
hookName: hook.name,
|
|
21348
|
+
reason: decision.reason || `blocked by hook "${hook.name}"`
|
|
21349
|
+
};
|
|
21350
|
+
}
|
|
21351
|
+
}
|
|
21352
|
+
return { ok: true };
|
|
21353
|
+
}
|
|
21354
|
+
/** Execute a single hook, swallowing every failure into an allow. */
|
|
21355
|
+
async runHookSafely(hook, payload) {
|
|
21356
|
+
try {
|
|
21357
|
+
const timeoutMs = hook.timeoutMs ?? this.defaultTimeoutMs;
|
|
21358
|
+
const raw = hook.url ? await this.postHttp(hook.url, payload, timeoutMs) : await this.execCommand(hook.command ?? "", payload, timeoutMs, hook.cwd);
|
|
21359
|
+
const decision = parseJson(raw);
|
|
21360
|
+
if (!decision) {
|
|
21361
|
+
this.logger(`hook "${hook.name}" returned invalid JSON (fail-open): ${raw.slice(0, 200)}`);
|
|
21362
|
+
return { decision: "allow" };
|
|
21363
|
+
}
|
|
21364
|
+
if (decision.decision === "deny" && typeof decision.reason !== "string") {
|
|
21365
|
+
this.logger(`hook "${hook.name}" denied without reason (fail-open)`);
|
|
21366
|
+
return { decision: "allow" };
|
|
21367
|
+
}
|
|
21368
|
+
return decision;
|
|
21369
|
+
} catch (err) {
|
|
21370
|
+
this.logger(`hook "${hook.name}" failed (fail-open): ${err instanceof Error ? err.message : String(err)}`);
|
|
21371
|
+
return { decision: "allow" };
|
|
21372
|
+
}
|
|
21373
|
+
}
|
|
21374
|
+
/** Spawn `command`, write JSON payload to stdin, read stdout until close. */
|
|
21375
|
+
execCommand(command, payload, timeoutMs, cwd) {
|
|
21376
|
+
return new Promise((resolve3, reject) => {
|
|
21377
|
+
const child = spawn2(command, {
|
|
21378
|
+
shell: true,
|
|
21379
|
+
cwd,
|
|
21380
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
21381
|
+
windowsHide: true
|
|
21382
|
+
});
|
|
21383
|
+
let stdout = "";
|
|
21384
|
+
let stderr = "";
|
|
21385
|
+
const timer = setTimeout(() => {
|
|
21386
|
+
child.kill("SIGKILL");
|
|
21387
|
+
reject(new Error(`timed out after ${timeoutMs}ms`));
|
|
21388
|
+
}, timeoutMs);
|
|
21389
|
+
child.stdout?.on("data", (d) => {
|
|
21390
|
+
stdout += d.toString();
|
|
21391
|
+
});
|
|
21392
|
+
child.stderr?.on("data", (d) => {
|
|
21393
|
+
stderr += d.toString();
|
|
21394
|
+
});
|
|
21395
|
+
child.on("error", (err) => {
|
|
21396
|
+
clearTimeout(timer);
|
|
21397
|
+
reject(err);
|
|
21398
|
+
});
|
|
21399
|
+
child.on("close", (code) => {
|
|
21400
|
+
clearTimeout(timer);
|
|
21401
|
+
if (code !== 0) {
|
|
21402
|
+
reject(new Error(`exited ${code}: ${stderr.trim().slice(0, 200)}`));
|
|
21403
|
+
return;
|
|
21404
|
+
}
|
|
21405
|
+
resolve3(stdout);
|
|
21406
|
+
});
|
|
21407
|
+
child.stdin?.on("error", () => {
|
|
21408
|
+
});
|
|
21409
|
+
child.stdin?.write(JSON.stringify(payload));
|
|
21410
|
+
child.stdin?.end();
|
|
21411
|
+
});
|
|
21412
|
+
}
|
|
21413
|
+
/** POST JSON payload; resolve with the response body text. */
|
|
21414
|
+
async postHttp(url2, payload, timeoutMs) {
|
|
21415
|
+
const ctrl = new AbortController();
|
|
21416
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
21417
|
+
try {
|
|
21418
|
+
const res = await fetch(url2, {
|
|
21419
|
+
method: "POST",
|
|
21420
|
+
headers: { "content-type": "application/json" },
|
|
21421
|
+
body: JSON.stringify(payload),
|
|
21422
|
+
signal: ctrl.signal
|
|
21423
|
+
});
|
|
21424
|
+
if (!res.ok) {
|
|
21425
|
+
throw new Error(`HTTP ${res.status}`);
|
|
21426
|
+
}
|
|
21427
|
+
return await res.text();
|
|
21428
|
+
} finally {
|
|
21429
|
+
clearTimeout(timer);
|
|
21430
|
+
}
|
|
21431
|
+
}
|
|
21432
|
+
};
|
|
21433
|
+
}
|
|
21434
|
+
});
|
|
21435
|
+
|
|
21436
|
+
// packages/core/dist/core/hooks/index.js
|
|
21437
|
+
var init_hooks = __esm({
|
|
21438
|
+
"packages/core/dist/core/hooks/index.js"() {
|
|
21439
|
+
"use strict";
|
|
21440
|
+
init_types2();
|
|
21441
|
+
init_lifecycleHookRunner();
|
|
21442
|
+
}
|
|
21443
|
+
});
|
|
21444
|
+
|
|
21169
21445
|
// packages/core/dist/harness/index.js
|
|
21170
21446
|
var harness_exports = {};
|
|
21171
21447
|
__export(harness_exports, {
|
|
21172
21448
|
AgentHarness: () => AgentHarness,
|
|
21173
21449
|
DOOM_LOOP_THRESHOLD: () => DOOM_LOOP_THRESHOLD,
|
|
21450
|
+
LifecycleHookRunner: () => LifecycleHookRunner,
|
|
21174
21451
|
SessionJsonlWriter: () => SessionJsonlWriter,
|
|
21175
21452
|
TEXT_LOOP_RECOVERY_SYSTEM: () => TEXT_LOOP_RECOVERY_SYSTEM,
|
|
21176
21453
|
TEXT_LOOP_RECOVERY_USER_PROMPT: () => TEXT_LOOP_RECOVERY_USER_PROMPT,
|
|
21177
21454
|
collapseLoopedAssistantText: () => collapseLoopedAssistantText,
|
|
21178
21455
|
detectAssistantTextLoop: () => detectAssistantTextLoop,
|
|
21179
21456
|
hashToolCall: () => hashToolCall,
|
|
21457
|
+
hookMatches: () => hookMatches,
|
|
21180
21458
|
isStatusTheaterUnit: () => isStatusTheaterUnit,
|
|
21181
21459
|
normalizeLoopUnit: () => normalizeLoopUnit,
|
|
21182
21460
|
normalizeTextToolArgs: () => normalizeTextToolArgs,
|
|
21461
|
+
normalizeToolName: () => normalizeToolName,
|
|
21183
21462
|
parseMinimaxStyleToolCalls: () => parseMinimaxStyleToolCalls,
|
|
21184
21463
|
parseTextToolCalls: () => parseTextToolCalls,
|
|
21185
21464
|
readSession: () => readSession,
|
|
21465
|
+
toolMatches: () => toolMatches,
|
|
21186
21466
|
wrapLegacyStream: () => wrapLegacyStream
|
|
21187
21467
|
});
|
|
21188
21468
|
var init_harness = __esm({
|
|
@@ -21191,6 +21471,7 @@ var init_harness = __esm({
|
|
|
21191
21471
|
init_AgentHarness();
|
|
21192
21472
|
init_providerStream();
|
|
21193
21473
|
init_sessionJsonl();
|
|
21474
|
+
init_hooks();
|
|
21194
21475
|
}
|
|
21195
21476
|
});
|
|
21196
21477
|
|
|
@@ -21667,7 +21948,7 @@ var init_parseCssMotion = __esm({
|
|
|
21667
21948
|
});
|
|
21668
21949
|
|
|
21669
21950
|
// packages/core/dist/council/verification/citeVerify.js
|
|
21670
|
-
import { existsSync as existsSync5, readFileSync as
|
|
21951
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:fs";
|
|
21671
21952
|
import { join } from "node:path";
|
|
21672
21953
|
function extractCitations(text) {
|
|
21673
21954
|
const out = [];
|
|
@@ -21704,7 +21985,7 @@ function verifyCitations(projectRoot, synthesisText) {
|
|
|
21704
21985
|
});
|
|
21705
21986
|
continue;
|
|
21706
21987
|
}
|
|
21707
|
-
const lines =
|
|
21988
|
+
const lines = readFileSync5(abs, "utf8").split(/\r?\n/);
|
|
21708
21989
|
if (cite.line > lines.length) {
|
|
21709
21990
|
results.push({
|
|
21710
21991
|
id: "synthesis.cite-invalid",
|
|
@@ -21967,14 +22248,14 @@ var init_synthesisAudit = __esm({
|
|
|
21967
22248
|
});
|
|
21968
22249
|
|
|
21969
22250
|
// packages/core/dist/council/verification/runChecks.js
|
|
21970
|
-
import { existsSync as existsSync6, readFileSync as
|
|
22251
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
21971
22252
|
import { join as join2 } from "node:path";
|
|
21972
22253
|
function loadNfrSpec(zelariRoot) {
|
|
21973
|
-
const
|
|
21974
|
-
if (!existsSync6(
|
|
22254
|
+
const path51 = join2(zelariRoot, "nfr-spec.json");
|
|
22255
|
+
if (!existsSync6(path51))
|
|
21975
22256
|
return null;
|
|
21976
22257
|
try {
|
|
21977
|
-
const raw = JSON.parse(
|
|
22258
|
+
const raw = JSON.parse(readFileSync6(path51, "utf8"));
|
|
21978
22259
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
21979
22260
|
return null;
|
|
21980
22261
|
return raw;
|
|
@@ -22049,13 +22330,13 @@ function checkPlanReality(projectRoot, zelariRoot, targets, keywords) {
|
|
|
22049
22330
|
return [];
|
|
22050
22331
|
let plan;
|
|
22051
22332
|
try {
|
|
22052
|
-
plan = JSON.parse(
|
|
22333
|
+
plan = JSON.parse(readFileSync6(planPath, "utf8"));
|
|
22053
22334
|
} catch {
|
|
22054
22335
|
return [];
|
|
22055
22336
|
}
|
|
22056
22337
|
const milestoneText = (plan.milestones ?? []).map((m) => `${m.name ?? ""} ${m.description ?? ""}`).join(" ").toLowerCase();
|
|
22057
22338
|
const results = [];
|
|
22058
|
-
const targetContent = targets.map((t) =>
|
|
22339
|
+
const targetContent = targets.map((t) => readFileSync6(join2(projectRoot, t), "utf8").toLowerCase()).join("\n");
|
|
22059
22340
|
for (const kw of keywords) {
|
|
22060
22341
|
const low = kw.toLowerCase();
|
|
22061
22342
|
if (!milestoneText.includes(low))
|
|
@@ -22087,11 +22368,11 @@ function checkReadmeStale(projectRoot, targets) {
|
|
|
22087
22368
|
const readmePath = join2(projectRoot, "README.md");
|
|
22088
22369
|
if (!existsSync6(readmePath) || targets.length === 0)
|
|
22089
22370
|
return [];
|
|
22090
|
-
const readme =
|
|
22371
|
+
const readme = readFileSync6(readmePath, "utf8");
|
|
22091
22372
|
const htmlPath = join2(projectRoot, targets[0]);
|
|
22092
22373
|
if (!existsSync6(htmlPath))
|
|
22093
22374
|
return [];
|
|
22094
|
-
const html =
|
|
22375
|
+
const html = readFileSync6(htmlPath, "utf8");
|
|
22095
22376
|
const sectionCount = (html.match(/<section\s+id=/gi) ?? []).length;
|
|
22096
22377
|
const readmeSections = readme.match(/(\d+)\s+sezioni/i);
|
|
22097
22378
|
if (readmeSections) {
|
|
@@ -22129,7 +22410,7 @@ function runImplementationVerification(input) {
|
|
|
22129
22410
|
forbidLayoutProps: anim.forbidLayoutProps ?? true
|
|
22130
22411
|
};
|
|
22131
22412
|
for (const rel2 of targets) {
|
|
22132
|
-
const html =
|
|
22413
|
+
const html = readFileSync6(join2(input.projectRoot, rel2), "utf8");
|
|
22133
22414
|
for (const v of scanKeyframesViolations(html, scanOpts)) {
|
|
22134
22415
|
results.push({
|
|
22135
22416
|
id: "motion.keyframes",
|
|
@@ -22215,7 +22496,7 @@ var init_runChecks = __esm({
|
|
|
22215
22496
|
});
|
|
22216
22497
|
|
|
22217
22498
|
// packages/core/dist/council/verification/microGate.js
|
|
22218
|
-
import { existsSync as existsSync7, readFileSync as
|
|
22499
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
22219
22500
|
import { join as join3 } from "node:path";
|
|
22220
22501
|
function checkDeadHooksInHtml(html) {
|
|
22221
22502
|
const warnings = [];
|
|
@@ -22253,7 +22534,7 @@ function runMicroVerificationOnFile(projectRoot, relPath, zelariRoot) {
|
|
|
22253
22534
|
compositorOnly: anim.compositorOnly ?? true,
|
|
22254
22535
|
forbidLayoutProps: anim.forbidLayoutProps ?? true
|
|
22255
22536
|
};
|
|
22256
|
-
const html =
|
|
22537
|
+
const html = readFileSync7(abs, "utf8");
|
|
22257
22538
|
const warnings = [];
|
|
22258
22539
|
for (const v of scanKeyframesViolations(html, scanOpts)) {
|
|
22259
22540
|
warnings.push({
|
|
@@ -22609,7 +22890,7 @@ var init_implementationDelivery = __esm({
|
|
|
22609
22890
|
});
|
|
22610
22891
|
|
|
22611
22892
|
// packages/core/dist/council/verification/inlineJsAutofix.js
|
|
22612
|
-
import { readFileSync as
|
|
22893
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
22613
22894
|
import { join as join4 } from "node:path";
|
|
22614
22895
|
function minifyInlineJs(js) {
|
|
22615
22896
|
let out = js.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
@@ -22656,7 +22937,7 @@ function applyInlineJsAutofix(projectRoot, report) {
|
|
|
22656
22937
|
const abs = join4(projectRoot, rel2);
|
|
22657
22938
|
let html;
|
|
22658
22939
|
try {
|
|
22659
|
-
html =
|
|
22940
|
+
html = readFileSync8(abs, "utf8");
|
|
22660
22941
|
} catch {
|
|
22661
22942
|
continue;
|
|
22662
22943
|
}
|
|
@@ -24048,14 +24329,14 @@ var init_missionBrief = __esm({
|
|
|
24048
24329
|
});
|
|
24049
24330
|
|
|
24050
24331
|
// packages/core/dist/council/verification/types.js
|
|
24051
|
-
var
|
|
24332
|
+
var init_types3 = __esm({
|
|
24052
24333
|
"packages/core/dist/council/verification/types.js"() {
|
|
24053
24334
|
"use strict";
|
|
24054
24335
|
}
|
|
24055
24336
|
});
|
|
24056
24337
|
|
|
24057
24338
|
// packages/core/dist/council/verification/motionAutofix.js
|
|
24058
|
-
import { readFileSync as
|
|
24339
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
24059
24340
|
import { join as join6 } from "node:path";
|
|
24060
24341
|
function sanitizeTransitionPart(part) {
|
|
24061
24342
|
const tokens = part.trim().split(/\s+/);
|
|
@@ -24134,7 +24415,7 @@ function applyMotionAutofix(projectRoot, report) {
|
|
|
24134
24415
|
const abs = join6(projectRoot, rel2);
|
|
24135
24416
|
let html;
|
|
24136
24417
|
try {
|
|
24137
|
-
html =
|
|
24418
|
+
html = readFileSync9(abs, "utf8");
|
|
24138
24419
|
} catch {
|
|
24139
24420
|
continue;
|
|
24140
24421
|
}
|
|
@@ -24206,7 +24487,7 @@ var init_motionAutofix = __esm({
|
|
|
24206
24487
|
});
|
|
24207
24488
|
|
|
24208
24489
|
// packages/core/dist/council/verification/autofix.js
|
|
24209
|
-
import { readFileSync as
|
|
24490
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
24210
24491
|
import { join as join7 } from "node:path";
|
|
24211
24492
|
function applyDeterministicAutofix(projectRoot, report) {
|
|
24212
24493
|
const motion = applyMotionAutofix(projectRoot, report);
|
|
@@ -24222,7 +24503,7 @@ function applyDeterministicAutofix(projectRoot, report) {
|
|
|
24222
24503
|
if (!m || m[1] === "rm")
|
|
24223
24504
|
continue;
|
|
24224
24505
|
const abs = join7(projectRoot, rel2);
|
|
24225
|
-
let html =
|
|
24506
|
+
let html = readFileSync10(abs, "utf8");
|
|
24226
24507
|
const snippet = m[0];
|
|
24227
24508
|
if (!html.includes(snippet))
|
|
24228
24509
|
continue;
|
|
@@ -24252,7 +24533,7 @@ var init_autofix = __esm({
|
|
|
24252
24533
|
var init_verification = __esm({
|
|
24253
24534
|
"packages/core/dist/council/verification/index.js"() {
|
|
24254
24535
|
"use strict";
|
|
24255
|
-
|
|
24536
|
+
init_types3();
|
|
24256
24537
|
init_runChecks();
|
|
24257
24538
|
init_honesty();
|
|
24258
24539
|
init_parseCssMotion();
|
|
@@ -24270,19 +24551,19 @@ var init_verification = __esm({
|
|
|
24270
24551
|
});
|
|
24271
24552
|
|
|
24272
24553
|
// packages/core/dist/council/lessons/types.js
|
|
24273
|
-
var
|
|
24554
|
+
var init_types4 = __esm({
|
|
24274
24555
|
"packages/core/dist/council/lessons/types.js"() {
|
|
24275
24556
|
"use strict";
|
|
24276
24557
|
}
|
|
24277
24558
|
});
|
|
24278
24559
|
|
|
24279
24560
|
// packages/core/dist/council/lessons/io.js
|
|
24280
|
-
import { readFileSync as
|
|
24561
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
24281
24562
|
import { join as join8 } from "node:path";
|
|
24282
24563
|
function readLessonsDeduped(zelariRoot) {
|
|
24283
|
-
const
|
|
24564
|
+
const path51 = join8(zelariRoot, LESSONS_FILE);
|
|
24284
24565
|
try {
|
|
24285
|
-
const raw =
|
|
24566
|
+
const raw = readFileSync11(path51, "utf8");
|
|
24286
24567
|
const byId = /* @__PURE__ */ new Map();
|
|
24287
24568
|
for (const line of raw.split(/\r?\n/)) {
|
|
24288
24569
|
if (!line.trim())
|
|
@@ -24383,8 +24664,8 @@ function keywordsFrom(check2, signature) {
|
|
|
24383
24664
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
24384
24665
|
}
|
|
24385
24666
|
function writeLesson(zelariRoot, lesson) {
|
|
24386
|
-
const
|
|
24387
|
-
appendFileSync(
|
|
24667
|
+
const path51 = join9(zelariRoot, LESSONS_FILE);
|
|
24668
|
+
appendFileSync(path51, `${JSON.stringify(lesson)}
|
|
24388
24669
|
`, "utf8");
|
|
24389
24670
|
}
|
|
24390
24671
|
function findSimilar(lessons, signature) {
|
|
@@ -24523,7 +24804,7 @@ var init_recallLessons = __esm({
|
|
|
24523
24804
|
var init_lessons = __esm({
|
|
24524
24805
|
"packages/core/dist/council/lessons/index.js"() {
|
|
24525
24806
|
"use strict";
|
|
24526
|
-
|
|
24807
|
+
init_types4();
|
|
24527
24808
|
init_io();
|
|
24528
24809
|
init_isAnswerLeak();
|
|
24529
24810
|
init_signatures();
|
|
@@ -24533,7 +24814,7 @@ var init_lessons = __esm({
|
|
|
24533
24814
|
});
|
|
24534
24815
|
|
|
24535
24816
|
// packages/core/dist/council/completion/types.js
|
|
24536
|
-
var
|
|
24817
|
+
var init_types5 = __esm({
|
|
24537
24818
|
"packages/core/dist/council/completion/types.js"() {
|
|
24538
24819
|
"use strict";
|
|
24539
24820
|
}
|
|
@@ -24614,7 +24895,7 @@ var init_buildCompletion = __esm({
|
|
|
24614
24895
|
var init_completion2 = __esm({
|
|
24615
24896
|
"packages/core/dist/council/completion/index.js"() {
|
|
24616
24897
|
"use strict";
|
|
24617
|
-
|
|
24898
|
+
init_types5();
|
|
24618
24899
|
init_buildCompletion();
|
|
24619
24900
|
}
|
|
24620
24901
|
});
|
|
@@ -24933,7 +25214,7 @@ var init_council = __esm({
|
|
|
24933
25214
|
});
|
|
24934
25215
|
|
|
24935
25216
|
// packages/core/dist/memory/types.js
|
|
24936
|
-
var
|
|
25217
|
+
var init_types6 = __esm({
|
|
24937
25218
|
"packages/core/dist/memory/types.js"() {
|
|
24938
25219
|
"use strict";
|
|
24939
25220
|
}
|
|
@@ -24997,9 +25278,9 @@ function findCycle(nodes) {
|
|
|
24997
25278
|
if (color.get(start) !== WHITE)
|
|
24998
25279
|
continue;
|
|
24999
25280
|
const stack = [[start, 0]];
|
|
25000
|
-
const
|
|
25281
|
+
const path51 = [];
|
|
25001
25282
|
color.set(start, GRAY);
|
|
25002
|
-
|
|
25283
|
+
path51.push(start);
|
|
25003
25284
|
while (stack.length > 0) {
|
|
25004
25285
|
const top = stack[stack.length - 1];
|
|
25005
25286
|
const [id, idx] = top;
|
|
@@ -25012,17 +25293,17 @@ function findCycle(nodes) {
|
|
|
25012
25293
|
continue;
|
|
25013
25294
|
const c = color.get(dep);
|
|
25014
25295
|
if (c === GRAY) {
|
|
25015
|
-
const at =
|
|
25016
|
-
return [...
|
|
25296
|
+
const at = path51.indexOf(dep);
|
|
25297
|
+
return [...path51.slice(at), dep];
|
|
25017
25298
|
}
|
|
25018
25299
|
if (c === WHITE) {
|
|
25019
25300
|
color.set(dep, GRAY);
|
|
25020
|
-
|
|
25301
|
+
path51.push(dep);
|
|
25021
25302
|
stack.push([dep, 0]);
|
|
25022
25303
|
}
|
|
25023
25304
|
} else {
|
|
25024
25305
|
color.set(id, BLACK);
|
|
25025
|
-
|
|
25306
|
+
path51.pop();
|
|
25026
25307
|
stack.pop();
|
|
25027
25308
|
}
|
|
25028
25309
|
}
|
|
@@ -25649,7 +25930,7 @@ var init_personas = __esm({
|
|
|
25649
25930
|
|
|
25650
25931
|
// packages/core/dist/kraken/runtime/types.js
|
|
25651
25932
|
var PlanError;
|
|
25652
|
-
var
|
|
25933
|
+
var init_types7 = __esm({
|
|
25653
25934
|
"packages/core/dist/kraken/runtime/types.js"() {
|
|
25654
25935
|
"use strict";
|
|
25655
25936
|
PlanError = class extends Error {
|
|
@@ -25747,7 +26028,7 @@ var MAX_BUNDLE_BYTES, FORBIDDEN_TOKENS;
|
|
|
25747
26028
|
var init_sandbox = __esm({
|
|
25748
26029
|
"packages/core/dist/kraken/runtime/sandbox.js"() {
|
|
25749
26030
|
"use strict";
|
|
25750
|
-
|
|
26031
|
+
init_types7();
|
|
25751
26032
|
MAX_BUNDLE_BYTES = 256 * 1024;
|
|
25752
26033
|
FORBIDDEN_TOKENS = [
|
|
25753
26034
|
/\bprocess\b/,
|
|
@@ -25810,7 +26091,7 @@ var init_runner = __esm({
|
|
|
25810
26091
|
"use strict";
|
|
25811
26092
|
init_verdict();
|
|
25812
26093
|
init_personas();
|
|
25813
|
-
|
|
26094
|
+
init_types7();
|
|
25814
26095
|
DEFAULT_MAX_TENTACLES = 200;
|
|
25815
26096
|
DEFAULT_PLAN_TIMEOUT_MS = 30 * 6e4;
|
|
25816
26097
|
ScriptRunner = class {
|
|
@@ -25942,8 +26223,8 @@ var init_runner = __esm({
|
|
|
25942
26223
|
failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
|
|
25943
26224
|
pending: []
|
|
25944
26225
|
};
|
|
25945
|
-
const
|
|
25946
|
-
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${
|
|
26226
|
+
const path51 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
|
|
26227
|
+
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path51}`);
|
|
25947
26228
|
return snapshot;
|
|
25948
26229
|
}
|
|
25949
26230
|
callLog(msg, data) {
|
|
@@ -25994,7 +26275,7 @@ var init_runner = __esm({
|
|
|
25994
26275
|
var init_runtime = __esm({
|
|
25995
26276
|
"packages/core/dist/kraken/runtime/index.js"() {
|
|
25996
26277
|
"use strict";
|
|
25997
|
-
|
|
26278
|
+
init_types7();
|
|
25998
26279
|
init_sandbox();
|
|
25999
26280
|
init_runner();
|
|
26000
26281
|
}
|
|
@@ -26047,6 +26328,7 @@ __export(dist_exports, {
|
|
|
26047
26328
|
LANGUAGE_POLICY_MODULE_TYPE: () => LANGUAGE_POLICY_MODULE_TYPE,
|
|
26048
26329
|
LAYOUT_MOTION_PROPS: () => LAYOUT_MOTION_PROPS,
|
|
26049
26330
|
LESSONS_FILE: () => LESSONS_FILE,
|
|
26331
|
+
LifecycleHookRunner: () => LifecycleHookRunner,
|
|
26050
26332
|
MAX_DELIVERY_ATTEMPTS: () => MAX_DELIVERY_ATTEMPTS,
|
|
26051
26333
|
MAX_FINDINGS_CHARS: () => MAX_FINDINGS_CHARS,
|
|
26052
26334
|
MAX_RETRY_PER_MEMBER: () => MAX_RETRY_PER_MEMBER,
|
|
@@ -26155,6 +26437,7 @@ __export(dist_exports, {
|
|
|
26155
26437
|
getToolDescriptions: () => getToolDescriptions,
|
|
26156
26438
|
hasInteractiveClarification: () => hasInteractiveClarification,
|
|
26157
26439
|
hashToolCall: () => hashToolCall,
|
|
26440
|
+
hookMatches: () => hookMatches,
|
|
26158
26441
|
isAnswerLeak: () => isAnswerLeak,
|
|
26159
26442
|
isBrainAgentEndEvent: () => isBrainAgentEndEvent,
|
|
26160
26443
|
isBrainAgentStartEvent: () => isBrainAgentStartEvent,
|
|
@@ -26187,6 +26470,7 @@ __export(dist_exports, {
|
|
|
26187
26470
|
normalizeLoopUnit: () => normalizeLoopUnit,
|
|
26188
26471
|
normalizeScopePath: () => normalizeScopePath,
|
|
26189
26472
|
normalizeTextToolArgs: () => normalizeTextToolArgs,
|
|
26473
|
+
normalizeToolName: () => normalizeToolName,
|
|
26190
26474
|
parseClarificationRequest: () => parseClarificationRequest,
|
|
26191
26475
|
parseEvidenceTier: () => parseEvidenceTier,
|
|
26192
26476
|
parseMinimaxStyleToolCalls: () => parseMinimaxStyleToolCalls,
|
|
@@ -26241,6 +26525,7 @@ __export(dist_exports, {
|
|
|
26241
26525
|
taskMatchesNfrKeywords: () => taskMatchesNfrKeywords,
|
|
26242
26526
|
tierAtLeast: () => tierAtLeast,
|
|
26243
26527
|
tokenizeForSignature: () => tokenizeForSignature,
|
|
26528
|
+
toolMatches: () => toolMatches,
|
|
26244
26529
|
topoLevels: () => topoLevels,
|
|
26245
26530
|
unregisterCustomTool: () => unregisterCustomTool,
|
|
26246
26531
|
unregisterSkill: () => unregisterSkill,
|
|
@@ -26263,7 +26548,7 @@ var init_dist = __esm({
|
|
|
26263
26548
|
init_harness();
|
|
26264
26549
|
init_council();
|
|
26265
26550
|
init_skills2();
|
|
26266
|
-
|
|
26551
|
+
init_types6();
|
|
26267
26552
|
init_state();
|
|
26268
26553
|
init_kraken();
|
|
26269
26554
|
}
|
|
@@ -26961,9 +27246,9 @@ function spillToolOutput(fullText, meta3) {
|
|
|
26961
27246
|
const rnd = randomBytes(3).toString("hex");
|
|
26962
27247
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
26963
27248
|
const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
|
|
26964
|
-
const
|
|
26965
|
-
writeFileSync10(
|
|
26966
|
-
return
|
|
27249
|
+
const path51 = join11(dir, file2);
|
|
27250
|
+
writeFileSync10(path51, fullText, "utf8");
|
|
27251
|
+
return path51;
|
|
26967
27252
|
} catch {
|
|
26968
27253
|
return null;
|
|
26969
27254
|
}
|
|
@@ -27009,10 +27294,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
|
|
|
27009
27294
|
${tail}`;
|
|
27010
27295
|
}
|
|
27011
27296
|
if (doSpill) {
|
|
27012
|
-
const
|
|
27013
|
-
if (
|
|
27297
|
+
const path51 = spillToolOutput(text, { toolName: opts.toolName });
|
|
27298
|
+
if (path51) {
|
|
27014
27299
|
const spillNote = `
|
|
27015
|
-
\u2026 [full output spilled to: ${
|
|
27300
|
+
\u2026 [full output spilled to: ${path51} \u2014 re-read with read_file if you need the complete text] \u2026`;
|
|
27016
27301
|
if (preview.includes("] \u2026\n")) {
|
|
27017
27302
|
preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
|
|
27018
27303
|
`);
|
|
@@ -27062,12 +27347,21 @@ var init_registry2 = __esm({
|
|
|
27062
27347
|
})();
|
|
27063
27348
|
ToolRegistry = class {
|
|
27064
27349
|
tools = /* @__PURE__ */ new Map();
|
|
27350
|
+
/** v0.10.0: lifecycle hooks (PreToolUse/PostToolUse). Null = no hooks. */
|
|
27351
|
+
lifecycleHooks = null;
|
|
27065
27352
|
register(def) {
|
|
27066
27353
|
this.tools.set(def.name, def);
|
|
27067
27354
|
}
|
|
27068
27355
|
get(name) {
|
|
27069
27356
|
return this.tools.get(name);
|
|
27070
27357
|
}
|
|
27358
|
+
/** v0.10.0: attach the fail-open lifecycle hook runner (null to disable). */
|
|
27359
|
+
setLifecycleHooks(runner) {
|
|
27360
|
+
this.lifecycleHooks = runner;
|
|
27361
|
+
}
|
|
27362
|
+
getLifecycleHooks() {
|
|
27363
|
+
return this.lifecycleHooks;
|
|
27364
|
+
}
|
|
27071
27365
|
list() {
|
|
27072
27366
|
return Array.from(this.tools.keys());
|
|
27073
27367
|
}
|
|
@@ -27100,6 +27394,18 @@ var init_registry2 = __esm({
|
|
|
27100
27394
|
},
|
|
27101
27395
|
sessionId: options.sessionId ?? "default"
|
|
27102
27396
|
};
|
|
27397
|
+
if (this.lifecycleHooks) {
|
|
27398
|
+
try {
|
|
27399
|
+
const pre = await this.lifecycleHooks.runPreToolUse(name, parsed.data, {
|
|
27400
|
+
sessionId: ctx.sessionId,
|
|
27401
|
+
cwd: ctx.cwd
|
|
27402
|
+
});
|
|
27403
|
+
if (!pre.ok) {
|
|
27404
|
+
return typedErr(`[hook:${pre.hookName ?? "unknown"}] ${pre.reason ?? "denied"}`);
|
|
27405
|
+
}
|
|
27406
|
+
} catch (hookErr) {
|
|
27407
|
+
}
|
|
27408
|
+
}
|
|
27103
27409
|
try {
|
|
27104
27410
|
const result = await Promise.race([
|
|
27105
27411
|
tool.execute(parsed.data, ctx),
|
|
@@ -27128,6 +27434,17 @@ var init_registry2 = __esm({
|
|
|
27128
27434
|
}
|
|
27129
27435
|
}
|
|
27130
27436
|
}
|
|
27437
|
+
if (this.lifecycleHooks) {
|
|
27438
|
+
try {
|
|
27439
|
+
await this.lifecycleHooks.runPostToolUse(name, parsed.data, result, {
|
|
27440
|
+
sessionId: ctx.sessionId,
|
|
27441
|
+
cwd: ctx.cwd,
|
|
27442
|
+
ok: result.ok,
|
|
27443
|
+
error: result.ok ? void 0 : "error" in result ? result.error : void 0
|
|
27444
|
+
});
|
|
27445
|
+
} catch {
|
|
27446
|
+
}
|
|
27447
|
+
}
|
|
27131
27448
|
return result;
|
|
27132
27449
|
} catch (err) {
|
|
27133
27450
|
const error51 = err instanceof Error ? err.message : String(err);
|
|
@@ -27150,14 +27467,14 @@ var init_registry2 = __esm({
|
|
|
27150
27467
|
});
|
|
27151
27468
|
|
|
27152
27469
|
// src/cli/safety/sandboxPath.ts
|
|
27153
|
-
import
|
|
27470
|
+
import path15 from "node:path";
|
|
27154
27471
|
function resolveSandboxedPath(userPath, options = {}) {
|
|
27155
27472
|
if (typeof userPath !== "string" || userPath.length === 0) {
|
|
27156
27473
|
throw new SandboxViolationError("Empty path", userPath, "");
|
|
27157
27474
|
}
|
|
27158
|
-
const root =
|
|
27159
|
-
const resolved =
|
|
27160
|
-
const rootWithSep = root.endsWith(
|
|
27475
|
+
const root = path15.resolve(options.root ?? process.cwd());
|
|
27476
|
+
const resolved = path15.isAbsolute(userPath) ? path15.resolve(userPath) : path15.resolve(root, userPath);
|
|
27477
|
+
const rootWithSep = root.endsWith(path15.sep) ? root : root + path15.sep;
|
|
27161
27478
|
if (resolved !== root && !resolved.startsWith(rootWithSep)) {
|
|
27162
27479
|
throw new SandboxViolationError(
|
|
27163
27480
|
`Path escapes sandbox root: ${userPath} \u2192 ${resolved} (root: ${root})`,
|
|
@@ -27245,12 +27562,12 @@ __export(auditLogger_exports, {
|
|
|
27245
27562
|
AuditLogger: () => AuditLogger
|
|
27246
27563
|
});
|
|
27247
27564
|
import { promises as fs11 } from "node:fs";
|
|
27248
|
-
import
|
|
27565
|
+
import path16 from "node:path";
|
|
27249
27566
|
import os6 from "node:os";
|
|
27250
27567
|
function defaultAuditPath() {
|
|
27251
27568
|
const override = process.env.ANATHEMA_AUDIT_LOG;
|
|
27252
27569
|
if (override && override.trim().length > 0) return override;
|
|
27253
|
-
return
|
|
27570
|
+
return path16.join(os6.tmpdir(), "zelari-code", "audit.jsonl");
|
|
27254
27571
|
}
|
|
27255
27572
|
function redactArgs(args) {
|
|
27256
27573
|
const redacted = {};
|
|
@@ -27293,7 +27610,7 @@ var init_auditLogger = __esm({
|
|
|
27293
27610
|
async append(entry) {
|
|
27294
27611
|
const line = JSON.stringify(entry) + "\n";
|
|
27295
27612
|
this.writeQueue = this.writeQueue.then(async () => {
|
|
27296
|
-
await fs11.mkdir(
|
|
27613
|
+
await fs11.mkdir(path16.dirname(this.logPath), { recursive: true });
|
|
27297
27614
|
await fs11.appendFile(this.logPath, line, "utf-8");
|
|
27298
27615
|
});
|
|
27299
27616
|
return this.writeQueue;
|
|
@@ -27353,9 +27670,9 @@ var init_cmdline = __esm({
|
|
|
27353
27670
|
});
|
|
27354
27671
|
|
|
27355
27672
|
// src/cli/diagnostics/engine.ts
|
|
27356
|
-
import { spawn as
|
|
27673
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
27357
27674
|
import { existsSync as existsSync12 } from "node:fs";
|
|
27358
|
-
import
|
|
27675
|
+
import path17 from "node:path";
|
|
27359
27676
|
function parseEslintJson(stdout, _file2) {
|
|
27360
27677
|
const json2 = safeJson(stdout);
|
|
27361
27678
|
if (!Array.isArray(json2)) return [];
|
|
@@ -27414,7 +27731,7 @@ function safeJson(s) {
|
|
|
27414
27731
|
}
|
|
27415
27732
|
}
|
|
27416
27733
|
function providerForFile(file2, providers = DEFAULT_PROVIDERS) {
|
|
27417
|
-
const ext =
|
|
27734
|
+
const ext = path17.extname(file2).toLowerCase();
|
|
27418
27735
|
return providers.find((p3) => p3.extensions.includes(ext)) ?? null;
|
|
27419
27736
|
}
|
|
27420
27737
|
function resolveBin(bin, cwd) {
|
|
@@ -27422,10 +27739,10 @@ function resolveBin(bin, cwd) {
|
|
|
27422
27739
|
let dir = cwd;
|
|
27423
27740
|
for (let i = 0; i < 6; i += 1) {
|
|
27424
27741
|
for (const suffix of suffixes) {
|
|
27425
|
-
const candidate =
|
|
27742
|
+
const candidate = path17.join(dir, "node_modules", ".bin", `${bin}${suffix}`);
|
|
27426
27743
|
if (existsSync12(candidate)) return candidate;
|
|
27427
27744
|
}
|
|
27428
|
-
const parent =
|
|
27745
|
+
const parent = path17.dirname(dir);
|
|
27429
27746
|
if (parent === dir) break;
|
|
27430
27747
|
dir = parent;
|
|
27431
27748
|
}
|
|
@@ -27498,7 +27815,7 @@ var init_engine = __esm({
|
|
|
27498
27815
|
};
|
|
27499
27816
|
let child;
|
|
27500
27817
|
try {
|
|
27501
|
-
child = process.platform === "win32" ?
|
|
27818
|
+
child = process.platform === "win32" ? spawn3(buildCmdLine(cmd, args), { cwd: opts.cwd, shell: true }) : spawn3(cmd, args, { cwd: opts.cwd });
|
|
27502
27819
|
} catch {
|
|
27503
27820
|
done({ code: null, stdout: "", stderr: "" });
|
|
27504
27821
|
return;
|
|
@@ -27529,14 +27846,14 @@ var init_engine = __esm({
|
|
|
27529
27846
|
});
|
|
27530
27847
|
|
|
27531
27848
|
// src/cli/tools/krakenRadio.ts
|
|
27532
|
-
import { appendFileSync as appendFileSync3, existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as
|
|
27533
|
-
import
|
|
27849
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync13, readdirSync as readdirSync2 } from "node:fs";
|
|
27850
|
+
import path18 from "node:path";
|
|
27534
27851
|
function radioDir(cwd) {
|
|
27535
|
-
return
|
|
27852
|
+
return path18.join(cwd, ".zelari", "radio");
|
|
27536
27853
|
}
|
|
27537
27854
|
function radioPath(cwd, sessionId) {
|
|
27538
27855
|
const safe = (sessionId || "default").replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
27539
|
-
return
|
|
27856
|
+
return path18.join(radioDir(cwd), `${safe}.jsonl`);
|
|
27540
27857
|
}
|
|
27541
27858
|
function appendKrakenRadio(cwd, sessionId, event) {
|
|
27542
27859
|
try {
|
|
@@ -27563,7 +27880,7 @@ function readKrakenRadio(cwd, sessionId, limit = 50) {
|
|
|
27563
27880
|
try {
|
|
27564
27881
|
const file2 = radioPath(cwd, sessionId);
|
|
27565
27882
|
if (!existsSync13(file2)) return [];
|
|
27566
|
-
const lines =
|
|
27883
|
+
const lines = readFileSync13(file2, "utf8").split(/\r?\n/).filter(Boolean);
|
|
27567
27884
|
const slice = lines.slice(-Math.max(1, limit));
|
|
27568
27885
|
const out = [];
|
|
27569
27886
|
for (const line of slice) {
|
|
@@ -27586,7 +27903,7 @@ function formatKrakenRadioStatus(cwd, sessionId, limit = 12) {
|
|
|
27586
27903
|
const flag = e.ok === false ? "\u2717" : e.ok === true ? "\u2713" : "\xB7";
|
|
27587
27904
|
const ms = e.durationMs != null ? ` ${e.durationMs}ms` : "";
|
|
27588
27905
|
const model = e.model ? ` [${e.model}]` : "";
|
|
27589
|
-
const wt = e.worktree ? ` wt=${
|
|
27906
|
+
const wt = e.worktree ? ` wt=${path18.basename(e.worktree)}` : "";
|
|
27590
27907
|
const detail = e.detail ? ` \u2014 ${e.detail.slice(0, 120)}` : "";
|
|
27591
27908
|
return `${flag} ${e.ts.slice(11, 19)} ${e.kind} ${e.agent} "${e.description}"${model}${wt}${ms}${detail}`;
|
|
27592
27909
|
});
|
|
@@ -27601,7 +27918,7 @@ var init_krakenRadio = __esm({
|
|
|
27601
27918
|
// src/cli/tools/krakenWorktree.ts
|
|
27602
27919
|
import { execFile as execFile2 } from "node:child_process";
|
|
27603
27920
|
import { existsSync as existsSync14, mkdirSync as mkdirSync8, rmSync } from "node:fs";
|
|
27604
|
-
import
|
|
27921
|
+
import path19 from "node:path";
|
|
27605
27922
|
import { promisify } from "node:util";
|
|
27606
27923
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
27607
27924
|
function isKrakenWorktreeEnabled(env = process.env) {
|
|
@@ -27649,8 +27966,8 @@ async function createKrakenWorktree(cwd, label) {
|
|
|
27649
27966
|
const id = `${Date.now().toString(36)}-${randomBytes2(3).toString("hex")}`;
|
|
27650
27967
|
const slug = (label ?? "task").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) || "task";
|
|
27651
27968
|
const branch = `kraken/${slug}-${id}`;
|
|
27652
|
-
const wtRoot =
|
|
27653
|
-
const wtPath =
|
|
27969
|
+
const wtRoot = path19.join(repoRoot, ".zelari", "worktrees");
|
|
27970
|
+
const wtPath = path19.join(wtRoot, `kraken-${id}`);
|
|
27654
27971
|
try {
|
|
27655
27972
|
if (!existsSync14(wtRoot)) mkdirSync8(wtRoot, { recursive: true });
|
|
27656
27973
|
} catch {
|
|
@@ -28243,7 +28560,7 @@ var init_askUser = __esm({
|
|
|
28243
28560
|
});
|
|
28244
28561
|
|
|
28245
28562
|
// src/cli/skillsMd.ts
|
|
28246
|
-
import { existsSync as existsSync15, readdirSync as
|
|
28563
|
+
import { existsSync as existsSync15, readdirSync as readdirSync3, readFileSync as readFileSync14 } from "node:fs";
|
|
28247
28564
|
import { join as join12 } from "node:path";
|
|
28248
28565
|
import { homedir as homedir4 } from "node:os";
|
|
28249
28566
|
function skillMdSearchDirs(projectRoot = process.cwd()) {
|
|
@@ -28312,7 +28629,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
28312
28629
|
if (!existsSync15(dir)) continue;
|
|
28313
28630
|
let entries;
|
|
28314
28631
|
try {
|
|
28315
|
-
entries =
|
|
28632
|
+
entries = readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
28316
28633
|
} catch {
|
|
28317
28634
|
continue;
|
|
28318
28635
|
}
|
|
@@ -28320,7 +28637,7 @@ function loadSkillMdSkills(projectRoot = process.cwd(), options = {}) {
|
|
|
28320
28637
|
const skillPath = join12(dir, entry, "SKILL.md");
|
|
28321
28638
|
if (!existsSync15(skillPath)) continue;
|
|
28322
28639
|
try {
|
|
28323
|
-
const parsed = parseSkillMd(
|
|
28640
|
+
const parsed = parseSkillMd(readFileSync14(skillPath, "utf8"), skillPath);
|
|
28324
28641
|
if (!parsed) {
|
|
28325
28642
|
summary.skipped.push({ path: skillPath, reason: "missing/invalid frontmatter (name, description) or empty body" });
|
|
28326
28643
|
continue;
|
|
@@ -28725,9 +29042,9 @@ var init_client = __esm({
|
|
|
28725
29042
|
});
|
|
28726
29043
|
|
|
28727
29044
|
// src/cli/lsp/servers.ts
|
|
28728
|
-
import
|
|
29045
|
+
import path20 from "node:path";
|
|
28729
29046
|
function languageIdForFile(file2) {
|
|
28730
|
-
const ext =
|
|
29047
|
+
const ext = path20.extname(file2).toLowerCase();
|
|
28731
29048
|
const map2 = {
|
|
28732
29049
|
".ts": "typescript",
|
|
28733
29050
|
".tsx": "typescriptreact",
|
|
@@ -28742,7 +29059,7 @@ function languageIdForFile(file2) {
|
|
|
28742
29059
|
return map2[ext] ?? "plaintext";
|
|
28743
29060
|
}
|
|
28744
29061
|
function serverForFile(file2, servers = LSP_SERVERS) {
|
|
28745
|
-
const ext =
|
|
29062
|
+
const ext = path20.extname(file2).toLowerCase();
|
|
28746
29063
|
return servers.find((s) => s.extensions.includes(ext)) ?? null;
|
|
28747
29064
|
}
|
|
28748
29065
|
function resolveServerCommand(file2, cwd, servers = LSP_SERVERS) {
|
|
@@ -28791,8 +29108,8 @@ var init_servers = __esm({
|
|
|
28791
29108
|
});
|
|
28792
29109
|
|
|
28793
29110
|
// src/cli/lsp/manager.ts
|
|
28794
|
-
import { spawn as
|
|
28795
|
-
import { readFileSync as
|
|
29111
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
29112
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
28796
29113
|
function processTransport(child) {
|
|
28797
29114
|
return {
|
|
28798
29115
|
send: (data) => {
|
|
@@ -28927,7 +29244,7 @@ var init_manager = __esm({
|
|
|
28927
29244
|
// languages already flagged as unavailable
|
|
28928
29245
|
constructor(options = {}) {
|
|
28929
29246
|
this.cwd = options.cwd ?? process.cwd();
|
|
28930
|
-
this.spawnImpl = options.spawnImpl ??
|
|
29247
|
+
this.spawnImpl = options.spawnImpl ?? spawn4;
|
|
28931
29248
|
this.timeoutMs = options.timeoutMs ?? 15e3;
|
|
28932
29249
|
this.onWarn = options.onWarn ?? ((m) => console.error(m));
|
|
28933
29250
|
}
|
|
@@ -28995,7 +29312,7 @@ var init_manager = __esm({
|
|
|
28995
29312
|
const uri = pathToUri(file2);
|
|
28996
29313
|
let text;
|
|
28997
29314
|
try {
|
|
28998
|
-
text =
|
|
29315
|
+
text = readFileSync15(file2, "utf8");
|
|
28999
29316
|
} catch {
|
|
29000
29317
|
text = "";
|
|
29001
29318
|
}
|
|
@@ -29110,9 +29427,9 @@ var init_manager = __esm({
|
|
|
29110
29427
|
|
|
29111
29428
|
// src/cli/ast/engine.ts
|
|
29112
29429
|
import { readFile } from "node:fs/promises";
|
|
29113
|
-
import
|
|
29430
|
+
import path21 from "node:path";
|
|
29114
29431
|
function isAstSupported(file2) {
|
|
29115
|
-
return TS_EXTENSIONS.has(
|
|
29432
|
+
return TS_EXTENSIONS.has(path21.extname(file2).toLowerCase());
|
|
29116
29433
|
}
|
|
29117
29434
|
function loadTs() {
|
|
29118
29435
|
if (!tsPromise) {
|
|
@@ -29132,7 +29449,7 @@ async function parseFileSymbols(file2) {
|
|
|
29132
29449
|
}
|
|
29133
29450
|
let source;
|
|
29134
29451
|
try {
|
|
29135
|
-
source = ts.createSourceFile(
|
|
29452
|
+
source = ts.createSourceFile(path21.basename(file2), text, ts.ScriptTarget.Latest, true);
|
|
29136
29453
|
} catch {
|
|
29137
29454
|
return [];
|
|
29138
29455
|
}
|
|
@@ -29317,13 +29634,13 @@ var init_store = __esm({
|
|
|
29317
29634
|
});
|
|
29318
29635
|
|
|
29319
29636
|
// src/cli/semantic/index.ts
|
|
29320
|
-
import { promises as fs12, existsSync as existsSync16, readFileSync as
|
|
29637
|
+
import { promises as fs12, existsSync as existsSync16, readFileSync as readFileSync16 } from "node:fs";
|
|
29321
29638
|
import { homedir as homedir5 } from "node:os";
|
|
29322
|
-
import
|
|
29639
|
+
import path22 from "node:path";
|
|
29323
29640
|
import { createHash as createHash2 } from "node:crypto";
|
|
29324
29641
|
function getIndexPath(root) {
|
|
29325
|
-
const hash3 = createHash2("sha1").update(
|
|
29326
|
-
return process.env.ZELARI_SEMANTIC_FILE ??
|
|
29642
|
+
const hash3 = createHash2("sha1").update(path22.resolve(root)).digest("hex").slice(0, 16);
|
|
29643
|
+
return process.env.ZELARI_SEMANTIC_FILE ?? path22.join(homedir5(), ".tmp", "zelari-code", "semantic", `${hash3}.json`);
|
|
29327
29644
|
}
|
|
29328
29645
|
async function collectSourceFiles(root, maxFiles = 1500) {
|
|
29329
29646
|
const out = [];
|
|
@@ -29341,11 +29658,11 @@ async function collectSourceFiles(root, maxFiles = 1500) {
|
|
|
29341
29658
|
if (entry.isDirectory() && IGNORE_DIRS.has(entry.name)) continue;
|
|
29342
29659
|
if (entry.isDirectory()) continue;
|
|
29343
29660
|
}
|
|
29344
|
-
const full =
|
|
29661
|
+
const full = path22.join(dir, entry.name);
|
|
29345
29662
|
if (entry.isDirectory()) {
|
|
29346
29663
|
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
29347
29664
|
await walk2(full);
|
|
29348
|
-
} else if (SOURCE_EXTENSIONS.has(
|
|
29665
|
+
} else if (SOURCE_EXTENSIONS.has(path22.extname(entry.name).toLowerCase())) {
|
|
29349
29666
|
out.push(full);
|
|
29350
29667
|
}
|
|
29351
29668
|
}
|
|
@@ -29394,7 +29711,7 @@ async function buildIndex(files, embed, options) {
|
|
|
29394
29711
|
}
|
|
29395
29712
|
async function saveIndex(root, data) {
|
|
29396
29713
|
const file2 = getIndexPath(root);
|
|
29397
|
-
await fs12.mkdir(
|
|
29714
|
+
await fs12.mkdir(path22.dirname(file2), { recursive: true });
|
|
29398
29715
|
const tmp = `${file2}.tmp-${process.pid}`;
|
|
29399
29716
|
await fs12.writeFile(tmp, JSON.stringify(data), "utf8");
|
|
29400
29717
|
await fs12.rename(tmp, file2);
|
|
@@ -29403,7 +29720,7 @@ function loadIndex(root) {
|
|
|
29403
29720
|
const file2 = getIndexPath(root);
|
|
29404
29721
|
if (!existsSync16(file2)) return null;
|
|
29405
29722
|
try {
|
|
29406
|
-
const parsed = JSON.parse(
|
|
29723
|
+
const parsed = JSON.parse(readFileSync16(file2, "utf8"));
|
|
29407
29724
|
if (parsed && Array.isArray(parsed.chunks)) return parsed;
|
|
29408
29725
|
} catch {
|
|
29409
29726
|
}
|
|
@@ -29546,7 +29863,7 @@ var init_provider = __esm({
|
|
|
29546
29863
|
});
|
|
29547
29864
|
|
|
29548
29865
|
// src/cli/semantic/tools.ts
|
|
29549
|
-
import
|
|
29866
|
+
import path23 from "node:path";
|
|
29550
29867
|
function createSemanticTool(deps) {
|
|
29551
29868
|
const buildEmbedFn = deps.buildEmbedFn ?? buildProviderEmbedFn;
|
|
29552
29869
|
return {
|
|
@@ -29573,7 +29890,7 @@ function createSemanticTool(deps) {
|
|
|
29573
29890
|
return typedOk({
|
|
29574
29891
|
count: res.hits.length,
|
|
29575
29892
|
results: res.hits.map((h) => ({
|
|
29576
|
-
location: `${
|
|
29893
|
+
location: `${path23.relative(deps.root, h.file) || h.file}:${h.startLine}-${h.endLine}`,
|
|
29577
29894
|
score: Number(h.score.toFixed(3)),
|
|
29578
29895
|
preview: h.text.length > 400 ? `${h.text.slice(0, 400)}\u2026` : h.text
|
|
29579
29896
|
}))
|
|
@@ -29593,7 +29910,7 @@ var init_tools4 = __esm({
|
|
|
29593
29910
|
|
|
29594
29911
|
// src/cli/browser/driver.ts
|
|
29595
29912
|
import { createRequire } from "node:module";
|
|
29596
|
-
import
|
|
29913
|
+
import path24 from "node:path";
|
|
29597
29914
|
import { pathToFileURL } from "node:url";
|
|
29598
29915
|
function asPlaywright(mod) {
|
|
29599
29916
|
if (!mod || typeof mod !== "object") return null;
|
|
@@ -29604,10 +29921,10 @@ function asPlaywright(mod) {
|
|
|
29604
29921
|
return null;
|
|
29605
29922
|
}
|
|
29606
29923
|
async function loadPlaywright(cwd) {
|
|
29607
|
-
const base = cwd && cwd.length > 0 ?
|
|
29924
|
+
const base = cwd && cwd.length > 0 ? path24.resolve(cwd) : void 0;
|
|
29608
29925
|
if (base) {
|
|
29609
29926
|
try {
|
|
29610
|
-
const req = createRequire(
|
|
29927
|
+
const req = createRequire(path24.join(base, "package.json"));
|
|
29611
29928
|
const resolved = req.resolve("playwright");
|
|
29612
29929
|
const mod = await import(pathToFileURL(resolved).href);
|
|
29613
29930
|
const pw = asPlaywright(mod);
|
|
@@ -29822,7 +30139,7 @@ var init_driver = __esm({
|
|
|
29822
30139
|
});
|
|
29823
30140
|
|
|
29824
30141
|
// src/cli/browser/tools.ts
|
|
29825
|
-
import
|
|
30142
|
+
import path25 from "node:path";
|
|
29826
30143
|
import os7 from "node:os";
|
|
29827
30144
|
function createBrowserTool(deps = {}) {
|
|
29828
30145
|
return {
|
|
@@ -29841,7 +30158,7 @@ function createBrowserTool(deps = {}) {
|
|
|
29841
30158
|
execute: async (args, ctx) => {
|
|
29842
30159
|
const a = args;
|
|
29843
30160
|
const dir = deps.screenshotDir ?? os7.tmpdir();
|
|
29844
|
-
const screenshotPath = a.screenshot === false ? void 0 :
|
|
30161
|
+
const screenshotPath = a.screenshot === false ? void 0 : path25.join(dir, `zelari-browser-${Date.now()}.png`);
|
|
29845
30162
|
const result = await runBrowserCheck(
|
|
29846
30163
|
{
|
|
29847
30164
|
url: a.url,
|
|
@@ -29935,12 +30252,12 @@ import {
|
|
|
29935
30252
|
chmodSync,
|
|
29936
30253
|
existsSync as existsSync17,
|
|
29937
30254
|
mkdirSync as mkdirSync9,
|
|
29938
|
-
readFileSync as
|
|
30255
|
+
readFileSync as readFileSync17,
|
|
29939
30256
|
writeFileSync as writeFileSync11
|
|
29940
30257
|
} from "node:fs";
|
|
29941
30258
|
import { dirname as dirname2, join as join13 } from "node:path";
|
|
29942
30259
|
import { homedir as homedir6 } from "node:os";
|
|
29943
|
-
import { spawn as
|
|
30260
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
29944
30261
|
function getSshTargetsPath() {
|
|
29945
30262
|
return join13(homedir6(), ".zelari-code", "ssh-targets.json");
|
|
29946
30263
|
}
|
|
@@ -29953,21 +30270,21 @@ function normalizeAuth(auth) {
|
|
|
29953
30270
|
return "agent";
|
|
29954
30271
|
}
|
|
29955
30272
|
function readSecrets() {
|
|
29956
|
-
const
|
|
29957
|
-
if (!existsSync17(
|
|
30273
|
+
const path51 = getSshSecretsPath();
|
|
30274
|
+
if (!existsSync17(path51)) return {};
|
|
29958
30275
|
try {
|
|
29959
|
-
return JSON.parse(
|
|
30276
|
+
return JSON.parse(readFileSync17(path51, "utf8"));
|
|
29960
30277
|
} catch {
|
|
29961
30278
|
return {};
|
|
29962
30279
|
}
|
|
29963
30280
|
}
|
|
29964
30281
|
function writeSecrets(data) {
|
|
29965
|
-
const
|
|
29966
|
-
mkdirSync9(dirname2(
|
|
29967
|
-
writeFileSync11(
|
|
30282
|
+
const path51 = getSshSecretsPath();
|
|
30283
|
+
mkdirSync9(dirname2(path51), { recursive: true });
|
|
30284
|
+
writeFileSync11(path51, `${JSON.stringify(data, null, 2)}
|
|
29968
30285
|
`, "utf8");
|
|
29969
30286
|
try {
|
|
29970
|
-
chmodSync(
|
|
30287
|
+
chmodSync(path51, 384);
|
|
29971
30288
|
} catch {
|
|
29972
30289
|
}
|
|
29973
30290
|
}
|
|
@@ -29996,10 +30313,10 @@ function deleteSshPassword(id) {
|
|
|
29996
30313
|
writeSecrets({ passwords });
|
|
29997
30314
|
}
|
|
29998
30315
|
function readStore2() {
|
|
29999
|
-
const
|
|
30000
|
-
if (!existsSync17(
|
|
30316
|
+
const path51 = getSshTargetsPath();
|
|
30317
|
+
if (!existsSync17(path51)) return [];
|
|
30001
30318
|
try {
|
|
30002
|
-
const parsed = JSON.parse(
|
|
30319
|
+
const parsed = JSON.parse(readFileSync17(path51, "utf8"));
|
|
30003
30320
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
30004
30321
|
return list.filter(
|
|
30005
30322
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -30014,11 +30331,11 @@ function readStore2() {
|
|
|
30014
30331
|
}
|
|
30015
30332
|
}
|
|
30016
30333
|
function writeStore2(targets) {
|
|
30017
|
-
const
|
|
30018
|
-
mkdirSync9(dirname2(
|
|
30334
|
+
const path51 = getSshTargetsPath();
|
|
30335
|
+
mkdirSync9(dirname2(path51), { recursive: true });
|
|
30019
30336
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
30020
30337
|
writeFileSync11(
|
|
30021
|
-
|
|
30338
|
+
path51,
|
|
30022
30339
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
30023
30340
|
`,
|
|
30024
30341
|
"utf8"
|
|
@@ -30170,7 +30487,7 @@ function runSsh(target, remoteCommand, timeoutMs = 6e4) {
|
|
|
30170
30487
|
if (!env.DISPLAY) env.DISPLAY = "1";
|
|
30171
30488
|
env.ZELARI_SSH_ASKPASS_PASS = pass;
|
|
30172
30489
|
}
|
|
30173
|
-
const child =
|
|
30490
|
+
const child = spawn5("ssh", args, {
|
|
30174
30491
|
windowsHide: true,
|
|
30175
30492
|
env,
|
|
30176
30493
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -30213,7 +30530,7 @@ function readSshPublicKey(keyOrPubPath) {
|
|
|
30213
30530
|
for (const p3 of candidates) {
|
|
30214
30531
|
if (!existsSync17(p3)) continue;
|
|
30215
30532
|
try {
|
|
30216
|
-
const content =
|
|
30533
|
+
const content = readFileSync17(p3, "utf8").trim();
|
|
30217
30534
|
if (!content) continue;
|
|
30218
30535
|
if (/BEGIN .*PRIVATE KEY/i.test(content)) {
|
|
30219
30536
|
return {
|
|
@@ -30264,11 +30581,11 @@ function formatSshTargetsForPrompt() {
|
|
|
30264
30581
|
];
|
|
30265
30582
|
for (const t of targets) {
|
|
30266
30583
|
const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
|
|
30267
|
-
const
|
|
30584
|
+
const path51 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
|
|
30268
30585
|
const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
|
|
30269
30586
|
const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
|
|
30270
30587
|
lines.push(
|
|
30271
|
-
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${
|
|
30588
|
+
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path51}${tags}${allow}`
|
|
30272
30589
|
);
|
|
30273
30590
|
}
|
|
30274
30591
|
return lines.join("\n");
|
|
@@ -30395,10 +30712,10 @@ var init_tools6 = __esm({
|
|
|
30395
30712
|
|
|
30396
30713
|
// src/cli/workspace/worldModel.ts
|
|
30397
30714
|
import { promises as fs13 } from "node:fs";
|
|
30398
|
-
import
|
|
30399
|
-
import { spawn as
|
|
30715
|
+
import path26 from "node:path";
|
|
30716
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
30400
30717
|
function worldDir(cwd) {
|
|
30401
|
-
return
|
|
30718
|
+
return path26.join(cwd, WORLD_DIR_NAME);
|
|
30402
30719
|
}
|
|
30403
30720
|
async function ensureWorldDir(cwd) {
|
|
30404
30721
|
const dir = worldDir(cwd);
|
|
@@ -30408,10 +30725,10 @@ async function ensureWorldDir(cwd) {
|
|
|
30408
30725
|
async function appendTimeline(cwd, entry) {
|
|
30409
30726
|
const dir = await ensureWorldDir(cwd);
|
|
30410
30727
|
const line = JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry }) + "\n";
|
|
30411
|
-
await fs13.appendFile(
|
|
30728
|
+
await fs13.appendFile(path26.join(dir, TIMELINE_FILE), line, "utf8");
|
|
30412
30729
|
}
|
|
30413
30730
|
async function readChecks(cwd) {
|
|
30414
|
-
const p3 =
|
|
30731
|
+
const p3 = path26.join(worldDir(cwd), CHECKS_FILE);
|
|
30415
30732
|
try {
|
|
30416
30733
|
const raw = await fs13.readFile(p3, "utf8");
|
|
30417
30734
|
const parsed = JSON.parse(raw);
|
|
@@ -30423,7 +30740,7 @@ async function readChecks(cwd) {
|
|
|
30423
30740
|
function runShell(command, cwd, timeoutMs, signal) {
|
|
30424
30741
|
return new Promise((resolve3) => {
|
|
30425
30742
|
const isWin = process.platform === "win32";
|
|
30426
|
-
const child =
|
|
30743
|
+
const child = spawn6(isWin ? "cmd.exe" : "/bin/sh", isWin ? ["/c", command] : ["-c", command], {
|
|
30427
30744
|
cwd,
|
|
30428
30745
|
env: process.env,
|
|
30429
30746
|
windowsHide: true,
|
|
@@ -30486,8 +30803,8 @@ function runShell(command, cwd, timeoutMs, signal) {
|
|
|
30486
30803
|
});
|
|
30487
30804
|
}
|
|
30488
30805
|
async function runBacktest(cwd, signal) {
|
|
30489
|
-
const checksPath =
|
|
30490
|
-
const hypothesisPath =
|
|
30806
|
+
const checksPath = path26.join(worldDir(cwd), CHECKS_FILE);
|
|
30807
|
+
const hypothesisPath = path26.join(worldDir(cwd), HYPOTHESIS_FILE);
|
|
30491
30808
|
const checks = await readChecks(cwd);
|
|
30492
30809
|
if (checks.length === 0) {
|
|
30493
30810
|
return {
|
|
@@ -30556,7 +30873,7 @@ var init_worldModel = __esm({
|
|
|
30556
30873
|
"use strict";
|
|
30557
30874
|
init_zod();
|
|
30558
30875
|
init_toolTypes();
|
|
30559
|
-
WORLD_DIR_NAME =
|
|
30876
|
+
WORLD_DIR_NAME = path26.join(".zelari", "world");
|
|
30560
30877
|
HYPOTHESIS_FILE = "hypothesis.md";
|
|
30561
30878
|
CHECKS_FILE = "checks.json";
|
|
30562
30879
|
TIMELINE_FILE = "timeline.jsonl";
|
|
@@ -30573,7 +30890,7 @@ var init_worldModel = __esm({
|
|
|
30573
30890
|
execute: async (args, ctx) => {
|
|
30574
30891
|
try {
|
|
30575
30892
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
30576
|
-
const file2 =
|
|
30893
|
+
const file2 = path26.join(dir, HYPOTHESIS_FILE);
|
|
30577
30894
|
if (args.append) {
|
|
30578
30895
|
const block = `
|
|
30579
30896
|
|
|
@@ -30612,7 +30929,7 @@ ${args.content}
|
|
|
30612
30929
|
execute: async (args, ctx) => {
|
|
30613
30930
|
try {
|
|
30614
30931
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
30615
|
-
const file2 =
|
|
30932
|
+
const file2 = path26.join(dir, CHECKS_FILE);
|
|
30616
30933
|
const body = { checks: args.checks };
|
|
30617
30934
|
await fs13.writeFile(file2, JSON.stringify(body, null, 2) + "\n", "utf8");
|
|
30618
30935
|
await appendTimeline(ctx.cwd, { kind: "checks_set", count: args.checks.length });
|
|
@@ -30651,8 +30968,8 @@ ${args.content}
|
|
|
30651
30968
|
stdoutPreview: "(dryRun)",
|
|
30652
30969
|
mismatch: "dryRun"
|
|
30653
30970
|
})),
|
|
30654
|
-
hypothesisPath:
|
|
30655
|
-
checksPath:
|
|
30971
|
+
hypothesisPath: path26.join(worldDir(ctx.cwd), HYPOTHESIS_FILE),
|
|
30972
|
+
checksPath: path26.join(worldDir(ctx.cwd), CHECKS_FILE)
|
|
30656
30973
|
});
|
|
30657
30974
|
}
|
|
30658
30975
|
const result = await runBacktest(ctx.cwd, ctx.signal);
|
|
@@ -30676,7 +30993,7 @@ ${args.content}
|
|
|
30676
30993
|
execute: async (args, ctx) => {
|
|
30677
30994
|
try {
|
|
30678
30995
|
const dir = await ensureWorldDir(ctx.cwd);
|
|
30679
|
-
const file2 =
|
|
30996
|
+
const file2 = path26.join(dir, TIMELINE_FILE);
|
|
30680
30997
|
await appendTimeline(ctx.cwd, {
|
|
30681
30998
|
kind: args.kind,
|
|
30682
30999
|
summary: args.summary,
|
|
@@ -30772,6 +31089,138 @@ var init_toolPermissions = __esm({
|
|
|
30772
31089
|
}
|
|
30773
31090
|
});
|
|
30774
31091
|
|
|
31092
|
+
// src/cli/safety/folderTrust.ts
|
|
31093
|
+
var folderTrust_exports = {};
|
|
31094
|
+
__export(folderTrust_exports, {
|
|
31095
|
+
_setTrustStorePathForTests: () => _setTrustStorePathForTests,
|
|
31096
|
+
getTrustStorePath: () => getTrustStorePath,
|
|
31097
|
+
hasTrustStore: () => hasTrustStore,
|
|
31098
|
+
isFolderTrusted: () => isFolderTrusted,
|
|
31099
|
+
listTrustedFolders: () => listTrustedFolders,
|
|
31100
|
+
trustFolder: () => trustFolder,
|
|
31101
|
+
untrustFolder: () => untrustFolder
|
|
31102
|
+
});
|
|
31103
|
+
import { homedir as homedir7 } from "node:os";
|
|
31104
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync10, readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "node:fs";
|
|
31105
|
+
import path27 from "node:path";
|
|
31106
|
+
function trustStorePath() {
|
|
31107
|
+
return _overrideStorePath ?? path27.join(homedir7(), ".zelari-code", "trust.json");
|
|
31108
|
+
}
|
|
31109
|
+
function normalize(p3) {
|
|
31110
|
+
const resolved = path27.resolve(p3);
|
|
31111
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
31112
|
+
}
|
|
31113
|
+
function readStore3() {
|
|
31114
|
+
try {
|
|
31115
|
+
const raw = readFileSync18(trustStorePath(), "utf8");
|
|
31116
|
+
const parsed = JSON.parse(raw);
|
|
31117
|
+
if (parsed && Array.isArray(parsed.folders)) return parsed;
|
|
31118
|
+
return DEFAULT_STORE;
|
|
31119
|
+
} catch {
|
|
31120
|
+
return DEFAULT_STORE;
|
|
31121
|
+
}
|
|
31122
|
+
}
|
|
31123
|
+
function writeStore3(store2) {
|
|
31124
|
+
const p3 = trustStorePath();
|
|
31125
|
+
try {
|
|
31126
|
+
mkdirSync10(path27.dirname(p3), { recursive: true });
|
|
31127
|
+
writeFileSync12(p3, JSON.stringify(store2, null, 2), "utf8");
|
|
31128
|
+
} catch (err) {
|
|
31129
|
+
throw new Error(
|
|
31130
|
+
`failed to persist trust store ${p3}: ${err instanceof Error ? err.message : String(err)}`
|
|
31131
|
+
);
|
|
31132
|
+
}
|
|
31133
|
+
}
|
|
31134
|
+
function envTrustedFolder() {
|
|
31135
|
+
const raw = process.env.ZELARI_FOLDER_TRUST?.trim();
|
|
31136
|
+
if (!raw) return null;
|
|
31137
|
+
const v = raw.toLowerCase();
|
|
31138
|
+
if (v === "1" || v === "true" || v === "yes" || v === "all") return "all";
|
|
31139
|
+
if (v === "0" || v === "false" || v === "no" || v === "none") return "none";
|
|
31140
|
+
return raw;
|
|
31141
|
+
}
|
|
31142
|
+
function isFolderTrusted(folderPath) {
|
|
31143
|
+
const env = envTrustedFolder();
|
|
31144
|
+
if (env === "all") return true;
|
|
31145
|
+
if (env === "none") return false;
|
|
31146
|
+
if (env) return normalize(env) === normalize(folderPath);
|
|
31147
|
+
const target = normalize(folderPath);
|
|
31148
|
+
return readStore3().folders.some((f) => normalize(f.path) === target);
|
|
31149
|
+
}
|
|
31150
|
+
function trustFolder(folderPath) {
|
|
31151
|
+
const store2 = readStore3();
|
|
31152
|
+
const normalized = path27.resolve(folderPath);
|
|
31153
|
+
if (!store2.folders.some((f) => normalize(f.path) === normalize(normalized))) {
|
|
31154
|
+
store2.folders.push({ path: normalized, trustedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
31155
|
+
writeStore3(store2);
|
|
31156
|
+
}
|
|
31157
|
+
return { ok: true, path: normalized };
|
|
31158
|
+
}
|
|
31159
|
+
function untrustFolder(folderPath) {
|
|
31160
|
+
const store2 = readStore3();
|
|
31161
|
+
const target = normalize(folderPath);
|
|
31162
|
+
const before = store2.folders.length;
|
|
31163
|
+
store2.folders = store2.folders.filter((f) => normalize(f.path) !== target);
|
|
31164
|
+
if (store2.folders.length === before) return { ok: true, removed: false };
|
|
31165
|
+
writeStore3(store2);
|
|
31166
|
+
return { ok: true, removed: true };
|
|
31167
|
+
}
|
|
31168
|
+
function listTrustedFolders() {
|
|
31169
|
+
const env = envTrustedFolder();
|
|
31170
|
+
if (env === "all") {
|
|
31171
|
+
return [{ path: "<all>", trustedAt: "env" }];
|
|
31172
|
+
}
|
|
31173
|
+
if (env) {
|
|
31174
|
+
return [{ path: env, trustedAt: "env" }];
|
|
31175
|
+
}
|
|
31176
|
+
return readStore3().folders;
|
|
31177
|
+
}
|
|
31178
|
+
function getTrustStorePath() {
|
|
31179
|
+
return trustStorePath();
|
|
31180
|
+
}
|
|
31181
|
+
function hasTrustStore() {
|
|
31182
|
+
return existsSync18(trustStorePath());
|
|
31183
|
+
}
|
|
31184
|
+
function _setTrustStorePathForTests(p3) {
|
|
31185
|
+
_overrideStorePath = p3;
|
|
31186
|
+
}
|
|
31187
|
+
var DEFAULT_STORE, _overrideStorePath;
|
|
31188
|
+
var init_folderTrust = __esm({
|
|
31189
|
+
"src/cli/safety/folderTrust.ts"() {
|
|
31190
|
+
"use strict";
|
|
31191
|
+
DEFAULT_STORE = { folders: [] };
|
|
31192
|
+
_overrideStorePath = null;
|
|
31193
|
+
}
|
|
31194
|
+
});
|
|
31195
|
+
|
|
31196
|
+
// src/cli/safety/lifecycleHooks.ts
|
|
31197
|
+
import { homedir as homedir8 } from "node:os";
|
|
31198
|
+
import { join as join14 } from "node:path";
|
|
31199
|
+
function globalHooksDir() {
|
|
31200
|
+
return join14(homedir8(), ".zelari-code", "hooks");
|
|
31201
|
+
}
|
|
31202
|
+
function projectHooksDir(projectRoot) {
|
|
31203
|
+
return join14(projectRoot, ".zelari", "hooks");
|
|
31204
|
+
}
|
|
31205
|
+
function createDefaultLifecycleHooks(projectRoot = process.cwd()) {
|
|
31206
|
+
const runner = new LifecycleHookRunner();
|
|
31207
|
+
const dirs = [globalHooksDir()];
|
|
31208
|
+
if (isFolderTrusted(projectRoot)) {
|
|
31209
|
+
dirs.push(projectHooksDir(projectRoot));
|
|
31210
|
+
}
|
|
31211
|
+
for (const dir of dirs) {
|
|
31212
|
+
runner.loadDir(dir);
|
|
31213
|
+
}
|
|
31214
|
+
return runner;
|
|
31215
|
+
}
|
|
31216
|
+
var init_lifecycleHooks = __esm({
|
|
31217
|
+
"src/cli/safety/lifecycleHooks.ts"() {
|
|
31218
|
+
"use strict";
|
|
31219
|
+
init_harness();
|
|
31220
|
+
init_folderTrust();
|
|
31221
|
+
}
|
|
31222
|
+
});
|
|
31223
|
+
|
|
30775
31224
|
// src/cli/tools/krakenModel.ts
|
|
30776
31225
|
var krakenModel_exports = {};
|
|
30777
31226
|
__export(krakenModel_exports, {
|
|
@@ -30887,6 +31336,9 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
30887
31336
|
const safeWebSearch = wrapWithAudit(webSearchTool, audit, sessionId);
|
|
30888
31337
|
const registry4 = new ToolRegistry();
|
|
30889
31338
|
const profile = options.profile ?? "full";
|
|
31339
|
+
const isParent = !options.profile || options.profile === "full";
|
|
31340
|
+
const hooks = isParent ? options.lifecycleHooks ?? createDefaultLifecycleHooks(root) : null;
|
|
31341
|
+
if (hooks) registry4.setLifecycleHooks(hooks);
|
|
30890
31342
|
const readOnly = options.readOnly === true || options.planMode === true || profile === "explore";
|
|
30891
31343
|
const verifyMode = profile === "verify";
|
|
30892
31344
|
const allowMutators = !readOnly && !verifyMode;
|
|
@@ -31291,6 +31743,7 @@ var init_toolRegistry = __esm({
|
|
|
31291
31743
|
init_worldModel();
|
|
31292
31744
|
init_openai_compatible();
|
|
31293
31745
|
init_toolPermissions();
|
|
31746
|
+
init_lifecycleHooks();
|
|
31294
31747
|
init_toolTypes();
|
|
31295
31748
|
init_skills2();
|
|
31296
31749
|
HARNESS_BUILTIN_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -31311,12 +31764,12 @@ var init_toolRegistry = __esm({
|
|
|
31311
31764
|
// src/cli/state/fileStateStore.ts
|
|
31312
31765
|
import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
|
|
31313
31766
|
import { promises as fs14 } from "node:fs";
|
|
31314
|
-
import * as
|
|
31767
|
+
import * as path28 from "node:path";
|
|
31315
31768
|
function shortId() {
|
|
31316
31769
|
return randomUUID2().replace(/-/g, "").slice(0, 12);
|
|
31317
31770
|
}
|
|
31318
31771
|
async function writeJsonAtomic(filePath, data) {
|
|
31319
|
-
await fs14.mkdir(
|
|
31772
|
+
await fs14.mkdir(path28.dirname(filePath), { recursive: true });
|
|
31320
31773
|
const tmp = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
31321
31774
|
await fs14.writeFile(tmp, JSON.stringify(data, null, 2) + "\n", "utf8");
|
|
31322
31775
|
await fs14.rename(tmp, filePath);
|
|
@@ -31377,11 +31830,11 @@ var init_fileStateStore = __esm({
|
|
|
31377
31830
|
indexPath = "";
|
|
31378
31831
|
async init(projectRoot) {
|
|
31379
31832
|
this.root = projectRoot;
|
|
31380
|
-
this.stateDir =
|
|
31381
|
-
this.commitsDir =
|
|
31382
|
-
this.artifactsDir =
|
|
31383
|
-
this.headPath =
|
|
31384
|
-
this.indexPath =
|
|
31833
|
+
this.stateDir = path28.join(projectRoot, ".zelari", "state");
|
|
31834
|
+
this.commitsDir = path28.join(this.stateDir, "commits");
|
|
31835
|
+
this.artifactsDir = path28.join(this.stateDir, "artifacts");
|
|
31836
|
+
this.headPath = path28.join(this.stateDir, "HEAD.json");
|
|
31837
|
+
this.indexPath = path28.join(this.stateDir, "index.jsonl");
|
|
31385
31838
|
await fs14.mkdir(this.commitsDir, { recursive: true });
|
|
31386
31839
|
await fs14.mkdir(this.artifactsDir, { recursive: true });
|
|
31387
31840
|
}
|
|
@@ -31394,13 +31847,13 @@ var init_fileStateStore = __esm({
|
|
|
31394
31847
|
const discoveries = input.discoveries ?? [];
|
|
31395
31848
|
const parent = await this.head();
|
|
31396
31849
|
const id = shortId();
|
|
31397
|
-
const artifactRel =
|
|
31398
|
-
const artifactAbs =
|
|
31850
|
+
const artifactRel = path28.join("artifacts", id);
|
|
31851
|
+
const artifactAbs = path28.join(this.artifactsDir, id);
|
|
31399
31852
|
await fs14.mkdir(artifactAbs, { recursive: true });
|
|
31400
31853
|
const summary = defaultSummary(input, discoveries);
|
|
31401
|
-
await fs14.writeFile(
|
|
31402
|
-
await writeJsonAtomic(
|
|
31403
|
-
await writeJsonAtomic(
|
|
31854
|
+
await fs14.writeFile(path28.join(artifactAbs, "summary.md"), summary + "\n", "utf8");
|
|
31855
|
+
await writeJsonAtomic(path28.join(artifactAbs, "discoveries.json"), discoveries);
|
|
31856
|
+
await writeJsonAtomic(path28.join(artifactAbs, "verification.json"), input.verification);
|
|
31404
31857
|
const meta3 = {
|
|
31405
31858
|
id,
|
|
31406
31859
|
parentId: parent?.id ?? null,
|
|
@@ -31412,14 +31865,14 @@ var init_fileStateStore = __esm({
|
|
|
31412
31865
|
workspaceCheckpointId: input.workspaceCheckpointId,
|
|
31413
31866
|
verification: {
|
|
31414
31867
|
...input.verification,
|
|
31415
|
-
reportPath: input.verification.reportPath ??
|
|
31868
|
+
reportPath: input.verification.reportPath ?? path28.join(".zelari", "state", artifactRel, "verification.json").replace(/\\/g, "/")
|
|
31416
31869
|
},
|
|
31417
31870
|
changedPaths: input.changedPaths ?? [],
|
|
31418
31871
|
stablePromptHash: input.stablePromptHash,
|
|
31419
31872
|
discoveryCount: discoveries.length,
|
|
31420
31873
|
artifactDir: artifactRel.replace(/\\/g, "/")
|
|
31421
31874
|
};
|
|
31422
|
-
await writeJsonAtomic(
|
|
31875
|
+
await writeJsonAtomic(path28.join(this.commitsDir, `${id}.json`), meta3);
|
|
31423
31876
|
await writeJsonAtomic(this.headPath, { id, updatedAt: meta3.createdAt });
|
|
31424
31877
|
await fs14.appendFile(this.indexPath, JSON.stringify({ id, createdAt: meta3.createdAt, label: meta3.label }) + "\n", "utf8");
|
|
31425
31878
|
return stripStored(meta3);
|
|
@@ -31430,7 +31883,7 @@ var init_fileStateStore = __esm({
|
|
|
31430
31883
|
return this.get(head.id);
|
|
31431
31884
|
}
|
|
31432
31885
|
async get(id) {
|
|
31433
|
-
const stored = await readJsonFile(
|
|
31886
|
+
const stored = await readJsonFile(path28.join(this.commitsDir, `${id}.json`));
|
|
31434
31887
|
return stored ? stripStored(stored) : null;
|
|
31435
31888
|
}
|
|
31436
31889
|
async list(limit = 20) {
|
|
@@ -31469,9 +31922,9 @@ var init_fileStateStore = __esm({
|
|
|
31469
31922
|
async loadDiscoveries(id) {
|
|
31470
31923
|
const meta3 = id ? await this.get(id) : await this.head();
|
|
31471
31924
|
if (!meta3) return [];
|
|
31472
|
-
const stored = await readJsonFile(
|
|
31925
|
+
const stored = await readJsonFile(path28.join(this.commitsDir, `${meta3.id}.json`));
|
|
31473
31926
|
if (!stored?.artifactDir) return [];
|
|
31474
|
-
const discPath =
|
|
31927
|
+
const discPath = path28.join(this.stateDir, stored.artifactDir, "discoveries.json");
|
|
31475
31928
|
return await readJsonFile(discPath) ?? [];
|
|
31476
31929
|
}
|
|
31477
31930
|
async materializeContext(id, maxChars = DEFAULT_MATERIALIZE_CHARS) {
|
|
@@ -31917,8 +32370,8 @@ __export(conversationContext_exports, {
|
|
|
31917
32370
|
setHistory: () => setHistory,
|
|
31918
32371
|
setLastClarification: () => setLastClarification
|
|
31919
32372
|
});
|
|
31920
|
-
import { existsSync as
|
|
31921
|
-
import { join as
|
|
32373
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
32374
|
+
import { join as join16 } from "node:path";
|
|
31922
32375
|
function getHistory() {
|
|
31923
32376
|
return history;
|
|
31924
32377
|
}
|
|
@@ -31926,7 +32379,7 @@ function setHistory(messages) {
|
|
|
31926
32379
|
history = [...messages];
|
|
31927
32380
|
}
|
|
31928
32381
|
function compactInPlace(cwd = process.cwd()) {
|
|
31929
|
-
const durableStatePresent =
|
|
32382
|
+
const durableStatePresent = existsSync19(join16(cwd, ".zelari", "state", "HEAD.json"));
|
|
31930
32383
|
history = compactHistory(history, { durableStatePresent });
|
|
31931
32384
|
}
|
|
31932
32385
|
function appendMessages(msgs) {
|
|
@@ -32315,7 +32768,7 @@ var claudeProvider_exports = {};
|
|
|
32315
32768
|
__export(claudeProvider_exports, {
|
|
32316
32769
|
createLocalCliProvider: () => createLocalCliProvider
|
|
32317
32770
|
});
|
|
32318
|
-
import { spawn as
|
|
32771
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
32319
32772
|
function waitForExit(child, timeoutMs = 2e3) {
|
|
32320
32773
|
return new Promise((resolve3) => {
|
|
32321
32774
|
if (child.exitCode != null) return resolve3(child.exitCode);
|
|
@@ -32344,7 +32797,7 @@ function createLocalCliProvider(opts = {}) {
|
|
|
32344
32797
|
);
|
|
32345
32798
|
}
|
|
32346
32799
|
}
|
|
32347
|
-
const spawnFn = opts.spawnFn ??
|
|
32800
|
+
const spawnFn = opts.spawnFn ?? spawn7;
|
|
32348
32801
|
let child;
|
|
32349
32802
|
try {
|
|
32350
32803
|
child = spawnFn(cli, args, {
|
|
@@ -32439,14 +32892,14 @@ var init_claudeProvider = __esm({
|
|
|
32439
32892
|
});
|
|
32440
32893
|
|
|
32441
32894
|
// src/cli/workspace/projectInstructions.ts
|
|
32442
|
-
import { existsSync as
|
|
32443
|
-
import { join as
|
|
32895
|
+
import { existsSync as existsSync20, readFileSync as readFileSync19 } from "node:fs";
|
|
32896
|
+
import { join as join17 } from "node:path";
|
|
32444
32897
|
function loadProjectInstructions(projectRoot = process.cwd(), maxChars = MAX_CHARS) {
|
|
32445
32898
|
for (const name of CANDIDATES) {
|
|
32446
|
-
const full =
|
|
32447
|
-
if (!
|
|
32899
|
+
const full = join17(projectRoot, name);
|
|
32900
|
+
if (!existsSync20(full)) continue;
|
|
32448
32901
|
try {
|
|
32449
|
-
let raw =
|
|
32902
|
+
let raw = readFileSync19(full, "utf8");
|
|
32450
32903
|
raw = raw.replace(/\r\n/g, "\n").trim();
|
|
32451
32904
|
if (!raw) continue;
|
|
32452
32905
|
if (raw.length <= maxChars) {
|
|
@@ -32483,20 +32936,20 @@ var init_projectInstructions = __esm({
|
|
|
32483
32936
|
|
|
32484
32937
|
// src/cli/workspace/paths.ts
|
|
32485
32938
|
import {
|
|
32486
|
-
mkdirSync as
|
|
32487
|
-
writeFileSync as
|
|
32488
|
-
existsSync as
|
|
32939
|
+
mkdirSync as mkdirSync11,
|
|
32940
|
+
writeFileSync as writeFileSync13,
|
|
32941
|
+
existsSync as existsSync21,
|
|
32489
32942
|
accessSync,
|
|
32490
32943
|
constants,
|
|
32491
32944
|
realpathSync
|
|
32492
32945
|
} from "node:fs";
|
|
32493
|
-
import { join as
|
|
32494
|
-
import { homedir as
|
|
32946
|
+
import { join as join18, basename } from "node:path";
|
|
32947
|
+
import { homedir as homedir9 } from "node:os";
|
|
32495
32948
|
import { createHash as createHash4 } from "node:crypto";
|
|
32496
32949
|
function resolveWorkspaceRoot(projectRoot = process.cwd()) {
|
|
32497
32950
|
const candidates = [
|
|
32498
|
-
|
|
32499
|
-
|
|
32951
|
+
join18(projectRoot, ".zelari"),
|
|
32952
|
+
join18(homedir9(), ".zelari-code", "workspace", hashProject(projectRoot))
|
|
32500
32953
|
];
|
|
32501
32954
|
for (const candidate of candidates) {
|
|
32502
32955
|
if (isWritableDir(projectRoot) || candidate !== candidates[0]) {
|
|
@@ -32512,7 +32965,7 @@ function hashProject(projectPath) {
|
|
|
32512
32965
|
}
|
|
32513
32966
|
function isWritableDir(dir) {
|
|
32514
32967
|
try {
|
|
32515
|
-
if (!
|
|
32968
|
+
if (!existsSync21(dir)) return false;
|
|
32516
32969
|
accessSync(dir, constants.W_OK);
|
|
32517
32970
|
return true;
|
|
32518
32971
|
} catch {
|
|
@@ -32520,26 +32973,26 @@ function isWritableDir(dir) {
|
|
|
32520
32973
|
}
|
|
32521
32974
|
}
|
|
32522
32975
|
function ensureWorkspaceDir(workspaceDir) {
|
|
32523
|
-
|
|
32524
|
-
if (workspaceDir.endsWith("/.zelari") &&
|
|
32525
|
-
const gitignorePath =
|
|
32526
|
-
if (!
|
|
32527
|
-
|
|
32976
|
+
mkdirSync11(workspaceDir, { recursive: true });
|
|
32977
|
+
if (workspaceDir.endsWith("/.zelari") && existsSync21(join18(workspaceDir, "..", ".git"))) {
|
|
32978
|
+
const gitignorePath = join18(workspaceDir, ".gitignore");
|
|
32979
|
+
if (!existsSync21(gitignorePath)) {
|
|
32980
|
+
writeFileSync13(gitignorePath, "*\n!.gitignore\n");
|
|
32528
32981
|
}
|
|
32529
32982
|
}
|
|
32530
32983
|
}
|
|
32531
32984
|
function workspaceFile(rootDir, kind) {
|
|
32532
32985
|
switch (kind) {
|
|
32533
32986
|
case "plan":
|
|
32534
|
-
return
|
|
32987
|
+
return join18(rootDir, "plan.md");
|
|
32535
32988
|
case "risks":
|
|
32536
|
-
return
|
|
32989
|
+
return join18(rootDir, "risks.md");
|
|
32537
32990
|
case "index":
|
|
32538
|
-
return
|
|
32991
|
+
return join18(rootDir, "workspace.json");
|
|
32539
32992
|
}
|
|
32540
32993
|
}
|
|
32541
32994
|
function workspaceArtifact(rootDir, subdir, slug) {
|
|
32542
|
-
return
|
|
32995
|
+
return join18(rootDir, subdir, `${slug}.md`);
|
|
32543
32996
|
}
|
|
32544
32997
|
function projectName(projectRoot = process.cwd()) {
|
|
32545
32998
|
return basename(realpathSync(projectRoot));
|
|
@@ -32559,8 +33012,8 @@ __export(workspaceSummary_exports, {
|
|
|
32559
33012
|
buildWorkspaceSummary: () => buildWorkspaceSummary,
|
|
32560
33013
|
buildZelariReadHint: () => buildZelariReadHint
|
|
32561
33014
|
});
|
|
32562
|
-
import { existsSync as
|
|
32563
|
-
import { join as
|
|
33015
|
+
import { existsSync as existsSync22, readFileSync as readFileSync20, readdirSync as readdirSync4, statSync as statSync3 } from "node:fs";
|
|
33016
|
+
import { join as join19, relative } from "node:path";
|
|
32564
33017
|
function buildWorkspaceSummary(projectRoot = process.cwd(), options = {}) {
|
|
32565
33018
|
const { maxEntries = 30, maxChars = 3500, maxDeps = 24, maxScripts = 16 } = options;
|
|
32566
33019
|
const name = safeProjectName(projectRoot);
|
|
@@ -32593,11 +33046,11 @@ function formatTaskLine(t) {
|
|
|
32593
33046
|
}
|
|
32594
33047
|
function buildPlanSummary(projectRoot = process.cwd(), options) {
|
|
32595
33048
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
32596
|
-
const planPath =
|
|
32597
|
-
if (!
|
|
33049
|
+
const planPath = join19(zelariRoot, "plan.json");
|
|
33050
|
+
if (!existsSync22(planPath)) return null;
|
|
32598
33051
|
let plan;
|
|
32599
33052
|
try {
|
|
32600
|
-
plan = JSON.parse(
|
|
33053
|
+
plan = JSON.parse(readFileSync20(planPath, "utf8"));
|
|
32601
33054
|
} catch {
|
|
32602
33055
|
return null;
|
|
32603
33056
|
}
|
|
@@ -32733,8 +33186,8 @@ function pickNextTask(open) {
|
|
|
32733
33186
|
)[0];
|
|
32734
33187
|
}
|
|
32735
33188
|
function buildZelariReadHint(projectRoot = process.cwd()) {
|
|
32736
|
-
const planPath =
|
|
32737
|
-
if (!
|
|
33189
|
+
const planPath = join19(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
33190
|
+
if (!existsSync22(planPath)) return "";
|
|
32738
33191
|
return [
|
|
32739
33192
|
"# Council workspace detected (.zelari/) \u2014 DRAFT vault",
|
|
32740
33193
|
"`.zelari/plan.json` and `.zelari/docs/` hold **design hypotheses**, not verified product state.",
|
|
@@ -32749,10 +33202,10 @@ function safeProjectName(root) {
|
|
|
32749
33202
|
}
|
|
32750
33203
|
}
|
|
32751
33204
|
function readPackageJson(projectRoot) {
|
|
32752
|
-
const p3 =
|
|
32753
|
-
if (!
|
|
33205
|
+
const p3 = join19(projectRoot, "package.json");
|
|
33206
|
+
if (!existsSync22(p3)) return null;
|
|
32754
33207
|
try {
|
|
32755
|
-
return JSON.parse(
|
|
33208
|
+
return JSON.parse(readFileSync20(p3, "utf8"));
|
|
32756
33209
|
} catch {
|
|
32757
33210
|
return null;
|
|
32758
33211
|
}
|
|
@@ -32793,7 +33246,7 @@ function readBuildScripts(projectRoot, maxScripts = 16) {
|
|
|
32793
33246
|
function listShallow(projectRoot, maxEntries) {
|
|
32794
33247
|
const out = [];
|
|
32795
33248
|
try {
|
|
32796
|
-
const top =
|
|
33249
|
+
const top = readdirSync4(projectRoot, { withFileTypes: true }).filter(
|
|
32797
33250
|
(e) => !e.name.startsWith(".") && e.name !== "node_modules" && e.name !== "dist"
|
|
32798
33251
|
).sort((a, b) => a.name.localeCompare(b.name));
|
|
32799
33252
|
let count = 0;
|
|
@@ -32802,11 +33255,11 @@ function listShallow(projectRoot, maxEntries) {
|
|
|
32802
33255
|
out.push(`\u2026 (+${top.length - count} more)`);
|
|
32803
33256
|
break;
|
|
32804
33257
|
}
|
|
32805
|
-
const rel2 = relative(projectRoot,
|
|
33258
|
+
const rel2 = relative(projectRoot, join19(projectRoot, entry.name));
|
|
32806
33259
|
if (entry.isDirectory()) {
|
|
32807
33260
|
let inner = "";
|
|
32808
33261
|
try {
|
|
32809
|
-
const sub =
|
|
33262
|
+
const sub = readdirSync4(join19(projectRoot, entry.name), {
|
|
32810
33263
|
withFileTypes: true
|
|
32811
33264
|
}).filter((e) => !e.name.startsWith(".")).slice(0, 4).map((e) => e.name);
|
|
32812
33265
|
if (sub.length > 0)
|
|
@@ -32854,12 +33307,12 @@ var init_workspaceSummary = __esm({
|
|
|
32854
33307
|
});
|
|
32855
33308
|
|
|
32856
33309
|
// src/cli/workspace/buildLessonsSummary.ts
|
|
32857
|
-
import { existsSync as
|
|
32858
|
-
import { join as
|
|
33310
|
+
import { existsSync as existsSync23 } from "node:fs";
|
|
33311
|
+
import { join as join20 } from "node:path";
|
|
32859
33312
|
function buildLessonsSummary(projectRoot = process.cwd(), taskText) {
|
|
32860
33313
|
if (process.env["ZELARI_LESSONS"] === "0") return null;
|
|
32861
33314
|
const zelariRoot = resolveWorkspaceRoot(projectRoot);
|
|
32862
|
-
if (!
|
|
33315
|
+
if (!existsSync23(join20(zelariRoot, "lessons.jsonl"))) return null;
|
|
32863
33316
|
const lessons = recallLessons(zelariRoot, {
|
|
32864
33317
|
maxLessons: 5,
|
|
32865
33318
|
maxBytes: 2048,
|
|
@@ -32880,8 +33333,8 @@ var composeContext_exports = {};
|
|
|
32880
33333
|
__export(composeContext_exports, {
|
|
32881
33334
|
composeProjectContext: () => composeProjectContext
|
|
32882
33335
|
});
|
|
32883
|
-
import { existsSync as
|
|
32884
|
-
import { join as
|
|
33336
|
+
import { existsSync as existsSync24, readdirSync as readdirSync5, readFileSync as readFileSync21 } from "node:fs";
|
|
33337
|
+
import { join as join21 } from "node:path";
|
|
32885
33338
|
function cap2(text, max, label) {
|
|
32886
33339
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
32887
33340
|
return {
|
|
@@ -32893,19 +33346,19 @@ function cap2(text, max, label) {
|
|
|
32893
33346
|
}
|
|
32894
33347
|
function buildDesignIndex(projectRoot, maxChars) {
|
|
32895
33348
|
const root = resolveWorkspaceRoot(projectRoot);
|
|
32896
|
-
if (!
|
|
33349
|
+
if (!existsSync24(root)) return "";
|
|
32897
33350
|
const lines = [
|
|
32898
33351
|
"# Design vault index (.zelari/) \u2014 HYPOTHESES only",
|
|
32899
33352
|
"Full design docs are NOT product source of truth. Open with list_files / read_file / searchDocuments if needed."
|
|
32900
33353
|
];
|
|
32901
|
-
const docsDir =
|
|
32902
|
-
if (
|
|
33354
|
+
const docsDir = join21(root, "docs");
|
|
33355
|
+
if (existsSync24(docsDir)) {
|
|
32903
33356
|
try {
|
|
32904
|
-
const docs =
|
|
33357
|
+
const docs = readdirSync5(docsDir).filter((n) => n.endsWith(".md")).slice(0, 12);
|
|
32905
33358
|
if (docs.length > 0) {
|
|
32906
33359
|
lines.push("", "## docs/ (titles only)");
|
|
32907
33360
|
for (const d of docs) lines.push(`- .zelari/docs/${d}`);
|
|
32908
|
-
if (
|
|
33361
|
+
if (readdirSync5(docsDir).filter((n) => n.endsWith(".md")).length > 12) {
|
|
32909
33362
|
lines.push("- \u2026 (more under .zelari/docs/)");
|
|
32910
33363
|
}
|
|
32911
33364
|
}
|
|
@@ -32913,14 +33366,14 @@ function buildDesignIndex(projectRoot, maxChars) {
|
|
|
32913
33366
|
}
|
|
32914
33367
|
}
|
|
32915
33368
|
for (const name of ["risks.md", "plan.json", "nfr-spec.json"]) {
|
|
32916
|
-
if (
|
|
33369
|
+
if (existsSync24(join21(root, name))) {
|
|
32917
33370
|
lines.push(`- .zelari/${name} present`);
|
|
32918
33371
|
}
|
|
32919
33372
|
}
|
|
32920
|
-
const decisionsDir =
|
|
32921
|
-
if (
|
|
33373
|
+
const decisionsDir = join21(root, "decisions");
|
|
33374
|
+
if (existsSync24(decisionsDir)) {
|
|
32922
33375
|
try {
|
|
32923
|
-
const n =
|
|
33376
|
+
const n = readdirSync5(decisionsDir).filter((f) => f.endsWith(".md")).length;
|
|
32924
33377
|
if (n > 0) lines.push(`- .zelari/decisions/ (${n} ADR file(s) \u2014 treat proposed as non-binding)`);
|
|
32925
33378
|
} catch {
|
|
32926
33379
|
}
|
|
@@ -33019,17 +33472,17 @@ function composeProjectContext(input) {
|
|
|
33019
33472
|
}
|
|
33020
33473
|
function readDurableHeadSync(projectRoot) {
|
|
33021
33474
|
try {
|
|
33022
|
-
const headPath =
|
|
33023
|
-
if (!
|
|
33024
|
-
const head = JSON.parse(
|
|
33475
|
+
const headPath = join21(projectRoot, ".zelari", "state", "HEAD.json");
|
|
33476
|
+
if (!existsSync24(headPath)) return "";
|
|
33477
|
+
const head = JSON.parse(readFileSync21(headPath, "utf8"));
|
|
33025
33478
|
if (!head?.id) return "";
|
|
33026
|
-
const metaPath =
|
|
33027
|
-
if (!
|
|
33028
|
-
const meta3 = JSON.parse(
|
|
33029
|
-
const discPath = meta3.artifactDir ?
|
|
33479
|
+
const metaPath = join21(projectRoot, ".zelari", "state", "commits", `${head.id}.json`);
|
|
33480
|
+
if (!existsSync24(metaPath)) return "";
|
|
33481
|
+
const meta3 = JSON.parse(readFileSync21(metaPath, "utf8"));
|
|
33482
|
+
const discPath = meta3.artifactDir ? join21(projectRoot, ".zelari", "state", meta3.artifactDir, "discoveries.json") : join21(projectRoot, ".zelari", "state", "artifacts", head.id, "discoveries.json");
|
|
33030
33483
|
let discoveries = [];
|
|
33031
|
-
if (
|
|
33032
|
-
discoveries = JSON.parse(
|
|
33484
|
+
if (existsSync24(discPath)) {
|
|
33485
|
+
discoveries = JSON.parse(readFileSync21(discPath, "utf8"));
|
|
33033
33486
|
}
|
|
33034
33487
|
const reusable = discoveries.filter((d) => d.reusable !== false);
|
|
33035
33488
|
const lines = [
|
|
@@ -33062,13 +33515,13 @@ var planDetect_exports = {};
|
|
|
33062
33515
|
__export(planDetect_exports, {
|
|
33063
33516
|
hasWorkspacePlan: () => hasWorkspacePlan
|
|
33064
33517
|
});
|
|
33065
|
-
import { existsSync as
|
|
33066
|
-
import { join as
|
|
33518
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22 } from "node:fs";
|
|
33519
|
+
import { join as join22 } from "node:path";
|
|
33067
33520
|
function hasWorkspacePlan(projectRoot = process.cwd()) {
|
|
33068
|
-
const planPath =
|
|
33069
|
-
if (!
|
|
33521
|
+
const planPath = join22(resolveWorkspaceRoot(projectRoot), "plan.json");
|
|
33522
|
+
if (!existsSync25(planPath)) return false;
|
|
33070
33523
|
try {
|
|
33071
|
-
const parsed = JSON.parse(
|
|
33524
|
+
const parsed = JSON.parse(readFileSync22(planPath, "utf8"));
|
|
33072
33525
|
return Array.isArray(parsed.phases) && parsed.phases.length > 0;
|
|
33073
33526
|
} catch {
|
|
33074
33527
|
return false;
|
|
@@ -33128,14 +33581,14 @@ __export(storage_exports, {
|
|
|
33128
33581
|
workspaceMutex: () => workspaceMutex
|
|
33129
33582
|
});
|
|
33130
33583
|
import {
|
|
33131
|
-
readFileSync as
|
|
33132
|
-
writeFileSync as
|
|
33133
|
-
existsSync as
|
|
33134
|
-
mkdirSync as
|
|
33135
|
-
readdirSync as
|
|
33584
|
+
readFileSync as readFileSync23,
|
|
33585
|
+
writeFileSync as writeFileSync14,
|
|
33586
|
+
existsSync as existsSync26,
|
|
33587
|
+
mkdirSync as mkdirSync12,
|
|
33588
|
+
readdirSync as readdirSync6,
|
|
33136
33589
|
renameSync as renameSync2
|
|
33137
33590
|
} from "node:fs";
|
|
33138
|
-
import { dirname as dirname4, join as
|
|
33591
|
+
import { dirname as dirname4, join as join23 } from "node:path";
|
|
33139
33592
|
function parseFrontmatter(md) {
|
|
33140
33593
|
const m = FRONTMATTER_RE.exec(md);
|
|
33141
33594
|
if (!m) return { meta: {}, body: md };
|
|
@@ -33389,33 +33842,33 @@ var init_storage = __esm({
|
|
|
33389
33842
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
33390
33843
|
Storage = class {
|
|
33391
33844
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
33392
|
-
read(
|
|
33393
|
-
if (!
|
|
33394
|
-
throw new Error(`File not found: ${
|
|
33845
|
+
read(path51) {
|
|
33846
|
+
if (!existsSync26(path51)) {
|
|
33847
|
+
throw new Error(`File not found: ${path51}`);
|
|
33395
33848
|
}
|
|
33396
|
-
const md =
|
|
33849
|
+
const md = readFileSync23(path51, "utf8");
|
|
33397
33850
|
return parseFrontmatter(md);
|
|
33398
33851
|
}
|
|
33399
33852
|
/** Read a Markdown file; returns null if not found. */
|
|
33400
|
-
readIfExists(
|
|
33401
|
-
if (!
|
|
33402
|
-
return this.read(
|
|
33853
|
+
readIfExists(path51) {
|
|
33854
|
+
if (!existsSync26(path51)) return null;
|
|
33855
|
+
return this.read(path51);
|
|
33403
33856
|
}
|
|
33404
33857
|
/**
|
|
33405
33858
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
33406
33859
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
33407
33860
|
*/
|
|
33408
|
-
write(
|
|
33409
|
-
|
|
33410
|
-
const tmp =
|
|
33861
|
+
write(path51, meta3, body) {
|
|
33862
|
+
mkdirSync12(dirname4(path51), { recursive: true });
|
|
33863
|
+
const tmp = path51 + ".tmp-" + process.pid;
|
|
33411
33864
|
const md = serializeFrontmatter(meta3, body);
|
|
33412
|
-
|
|
33413
|
-
renameSync2(tmp,
|
|
33865
|
+
writeFileSync14(tmp, md, "utf8");
|
|
33866
|
+
renameSync2(tmp, path51);
|
|
33414
33867
|
}
|
|
33415
33868
|
/** List all .md files in a directory (non-recursive). */
|
|
33416
33869
|
listMarkdown(dir) {
|
|
33417
|
-
if (!
|
|
33418
|
-
return
|
|
33870
|
+
if (!existsSync26(dir)) return [];
|
|
33871
|
+
return readdirSync6(dir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).map((f) => join23(dir, f));
|
|
33419
33872
|
}
|
|
33420
33873
|
};
|
|
33421
33874
|
KeyedMutex = class {
|
|
@@ -33454,14 +33907,14 @@ __export(stubs_exports, {
|
|
|
33454
33907
|
resolveWorkspaceRoot: () => resolveWorkspaceRoot
|
|
33455
33908
|
});
|
|
33456
33909
|
import {
|
|
33457
|
-
existsSync as
|
|
33458
|
-
readdirSync as
|
|
33459
|
-
writeFileSync as
|
|
33460
|
-
readFileSync as
|
|
33461
|
-
mkdirSync as
|
|
33910
|
+
existsSync as existsSync27,
|
|
33911
|
+
readdirSync as readdirSync7,
|
|
33912
|
+
writeFileSync as writeFileSync15,
|
|
33913
|
+
readFileSync as readFileSync24,
|
|
33914
|
+
mkdirSync as mkdirSync13,
|
|
33462
33915
|
renameSync as renameSync3
|
|
33463
33916
|
} from "node:fs";
|
|
33464
|
-
import { join as
|
|
33917
|
+
import { join as join24, basename as basename2, dirname as dirname5, relative as relative2 } from "node:path";
|
|
33465
33918
|
function createWorkspaceContext(projectRoot = process.cwd()) {
|
|
33466
33919
|
const rootDir = resolveWorkspaceRoot(projectRoot);
|
|
33467
33920
|
return {
|
|
@@ -33471,14 +33924,14 @@ function createWorkspaceContext(projectRoot = process.cwd()) {
|
|
|
33471
33924
|
};
|
|
33472
33925
|
}
|
|
33473
33926
|
function planJsonPath(ctx) {
|
|
33474
|
-
return
|
|
33927
|
+
return join24(ctx.rootDir, "plan.json");
|
|
33475
33928
|
}
|
|
33476
33929
|
function readPlan(ctx) {
|
|
33477
33930
|
const jsonPath = planJsonPath(ctx);
|
|
33478
|
-
if (
|
|
33931
|
+
if (existsSync27(jsonPath)) {
|
|
33479
33932
|
try {
|
|
33480
33933
|
const parsed = JSON.parse(
|
|
33481
|
-
|
|
33934
|
+
readFileSync24(jsonPath, "utf8")
|
|
33482
33935
|
);
|
|
33483
33936
|
return {
|
|
33484
33937
|
phases: Array.isArray(parsed.phases) ? parsed.phases : [],
|
|
@@ -33488,8 +33941,8 @@ function readPlan(ctx) {
|
|
|
33488
33941
|
} catch {
|
|
33489
33942
|
}
|
|
33490
33943
|
}
|
|
33491
|
-
const
|
|
33492
|
-
const doc = ctx.storage.readIfExists(
|
|
33944
|
+
const path51 = workspaceFile(ctx.rootDir, "plan");
|
|
33945
|
+
const doc = ctx.storage.readIfExists(path51);
|
|
33493
33946
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
33494
33947
|
const meta3 = doc.meta;
|
|
33495
33948
|
return {
|
|
@@ -33500,9 +33953,9 @@ function readPlan(ctx) {
|
|
|
33500
33953
|
}
|
|
33501
33954
|
function writePlan(ctx, summary) {
|
|
33502
33955
|
const jsonPath = planJsonPath(ctx);
|
|
33503
|
-
|
|
33956
|
+
mkdirSync13(dirname5(jsonPath), { recursive: true });
|
|
33504
33957
|
const tmp = jsonPath + ".tmp-" + process.pid;
|
|
33505
|
-
|
|
33958
|
+
writeFileSync15(tmp, JSON.stringify(summary, null, 2), "utf8");
|
|
33506
33959
|
renameSync3(tmp, jsonPath);
|
|
33507
33960
|
const mdPath = workspaceFile(ctx.rootDir, "plan");
|
|
33508
33961
|
const summaryMeta = {
|
|
@@ -33569,9 +34022,9 @@ function renderPlanBody(summary) {
|
|
|
33569
34022
|
return lines.join("\n");
|
|
33570
34023
|
}
|
|
33571
34024
|
function nextAdrId(ctx) {
|
|
33572
|
-
const decisionsDir =
|
|
33573
|
-
if (!
|
|
33574
|
-
const existing =
|
|
34025
|
+
const decisionsDir = join24(ctx.rootDir, "decisions");
|
|
34026
|
+
if (!existsSync27(decisionsDir)) return "001";
|
|
34027
|
+
const existing = readdirSync7(decisionsDir).filter((f) => f.endsWith(".md")).map((f) => f.match(/^(\d+)-/)).filter((m) => !!m).map((m) => parseInt(m[1], 10));
|
|
33575
34028
|
const max = existing.length === 0 ? 0 : Math.max(...existing);
|
|
33576
34029
|
return String(max + 1).padStart(3, "0");
|
|
33577
34030
|
}
|
|
@@ -33612,7 +34065,7 @@ function addTaskRecord(ctx, summary, phaseId, t, options) {
|
|
|
33612
34065
|
status: "pending",
|
|
33613
34066
|
priority: t.priority
|
|
33614
34067
|
});
|
|
33615
|
-
const taskPath =
|
|
34068
|
+
const taskPath = join24(ctx.rootDir, "plan-tasks", `${id}.md`);
|
|
33616
34069
|
const meta3 = {
|
|
33617
34070
|
kind: "task",
|
|
33618
34071
|
id,
|
|
@@ -33654,7 +34107,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
33654
34107
|
dueDate: input.dueDate,
|
|
33655
34108
|
targetVersion: version2
|
|
33656
34109
|
});
|
|
33657
|
-
const
|
|
34110
|
+
const path51 = join24(ctx.rootDir, "milestones", `${id}.md`);
|
|
33658
34111
|
const meta3 = {
|
|
33659
34112
|
kind: "milestone",
|
|
33660
34113
|
id,
|
|
@@ -33671,7 +34124,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
33671
34124
|
`Target version: ${version2}`,
|
|
33672
34125
|
""
|
|
33673
34126
|
].join("\n");
|
|
33674
|
-
ctx.storage.write(
|
|
34127
|
+
ctx.storage.write(path51, meta3, body);
|
|
33675
34128
|
return { id, created: true };
|
|
33676
34129
|
}
|
|
33677
34130
|
function readPlanSummary(ctx) {
|
|
@@ -33875,7 +34328,7 @@ function addIdeaStub(ctx) {
|
|
|
33875
34328
|
const tags = args["tags"] ?? [];
|
|
33876
34329
|
const category = args["category"] ?? "General";
|
|
33877
34330
|
const id = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
33878
|
-
const
|
|
34331
|
+
const path51 = workspaceArtifact(ctx.rootDir, "decisions", id);
|
|
33879
34332
|
const meta3 = {
|
|
33880
34333
|
kind: "adr",
|
|
33881
34334
|
status: "proposed",
|
|
@@ -33901,7 +34354,7 @@ function addIdeaStub(ctx) {
|
|
|
33901
34354
|
...consequences.map((c) => `- ${c}`),
|
|
33902
34355
|
""
|
|
33903
34356
|
].join("\n");
|
|
33904
|
-
ctx.storage.write(
|
|
34357
|
+
ctx.storage.write(path51, meta3, body);
|
|
33905
34358
|
return `ADR ${id} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
33906
34359
|
});
|
|
33907
34360
|
}
|
|
@@ -33952,8 +34405,8 @@ function createNfrSpecStub(ctx) {
|
|
|
33952
34405
|
},
|
|
33953
34406
|
planFeatureKeywords: Array.isArray(args["planFeatureKeywords"]) ? args["planFeatureKeywords"] : void 0
|
|
33954
34407
|
};
|
|
33955
|
-
const outPath =
|
|
33956
|
-
|
|
34408
|
+
const outPath = join24(ctx.rootDir, "nfr-spec.json");
|
|
34409
|
+
writeFileSync15(outPath, JSON.stringify(spec, null, 2), "utf8");
|
|
33957
34410
|
return `NFR spec written to nfr-spec.json (${targets.length} target(s)).`;
|
|
33958
34411
|
});
|
|
33959
34412
|
}
|
|
@@ -33983,14 +34436,14 @@ function createDocumentStub(ctx) {
|
|
|
33983
34436
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
33984
34437
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
33985
34438
|
}
|
|
33986
|
-
const
|
|
34439
|
+
const path51 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
33987
34440
|
const meta3 = {
|
|
33988
34441
|
kind: "doc",
|
|
33989
34442
|
id: slug,
|
|
33990
34443
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
33991
34444
|
tags
|
|
33992
34445
|
};
|
|
33993
|
-
ctx.storage.write(
|
|
34446
|
+
ctx.storage.write(path51, meta3, content);
|
|
33994
34447
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
33995
34448
|
});
|
|
33996
34449
|
}
|
|
@@ -34016,18 +34469,18 @@ function searchDocumentsStub(ctx) {
|
|
|
34016
34469
|
(w) => w.length >= 3 && w !== "or" && w !== "and" && w !== "the"
|
|
34017
34470
|
);
|
|
34018
34471
|
const files = [
|
|
34019
|
-
...ctx.storage.listMarkdown(
|
|
34020
|
-
...ctx.storage.listMarkdown(
|
|
34021
|
-
...ctx.storage.listMarkdown(
|
|
34022
|
-
...ctx.storage.listMarkdown(
|
|
34023
|
-
...ctx.storage.listMarkdown(
|
|
34472
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "decisions")),
|
|
34473
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "docs")),
|
|
34474
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "reviews")),
|
|
34475
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "plan-tasks")),
|
|
34476
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "milestones")),
|
|
34024
34477
|
workspaceFile(ctx.rootDir, "plan"),
|
|
34025
34478
|
workspaceFile(ctx.rootDir, "risks")
|
|
34026
34479
|
];
|
|
34027
34480
|
const results = [];
|
|
34028
34481
|
for (const file2 of files) {
|
|
34029
|
-
if (!
|
|
34030
|
-
const raw =
|
|
34482
|
+
if (!existsSync27(file2)) continue;
|
|
34483
|
+
const raw = readFileSync24(file2, "utf8");
|
|
34031
34484
|
const content = raw.toLowerCase();
|
|
34032
34485
|
let idx = -1;
|
|
34033
34486
|
let matchLen = 0;
|
|
@@ -34078,9 +34531,9 @@ function linkDocumentsStub(ctx) {
|
|
|
34078
34531
|
const toId = args["toId"] ?? args["targetId"] ?? args["targetPathOrTitle"];
|
|
34079
34532
|
if (!fromId || !toId) return "linkDocuments requires fromId and toId.";
|
|
34080
34533
|
const allFiles = [
|
|
34081
|
-
...ctx.storage.listMarkdown(
|
|
34082
|
-
...ctx.storage.listMarkdown(
|
|
34083
|
-
...ctx.storage.listMarkdown(
|
|
34534
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "decisions")),
|
|
34535
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "docs")),
|
|
34536
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "reviews"))
|
|
34084
34537
|
];
|
|
34085
34538
|
const source = allFiles.find((f) => {
|
|
34086
34539
|
try {
|
|
@@ -34111,9 +34564,9 @@ function getDocumentBacklinksStub(ctx) {
|
|
|
34111
34564
|
const targetId = args["targetId"] ?? args["id"];
|
|
34112
34565
|
if (!targetId) return "getDocumentBacklinks requires targetId.";
|
|
34113
34566
|
const allFiles = [
|
|
34114
|
-
...ctx.storage.listMarkdown(
|
|
34115
|
-
...ctx.storage.listMarkdown(
|
|
34116
|
-
...ctx.storage.listMarkdown(
|
|
34567
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "decisions")),
|
|
34568
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "docs")),
|
|
34569
|
+
...ctx.storage.listMarkdown(join24(ctx.rootDir, "reviews"))
|
|
34117
34570
|
];
|
|
34118
34571
|
const backlinks = [];
|
|
34119
34572
|
for (const file2 of allFiles) {
|
|
@@ -34207,21 +34660,21 @@ __export(updater_exports, {
|
|
|
34207
34660
|
resolveBundledNpmCli: () => resolveBundledNpmCli
|
|
34208
34661
|
});
|
|
34209
34662
|
import { createRequire as createRequire2 } from "node:module";
|
|
34210
|
-
import { spawn as
|
|
34211
|
-
import { existsSync as
|
|
34212
|
-
import
|
|
34663
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
34664
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
34665
|
+
import path29 from "node:path";
|
|
34213
34666
|
import { fileURLToPath } from "node:url";
|
|
34214
34667
|
function resolveBundledNpmCli(execPath = process.execPath) {
|
|
34215
|
-
const dir =
|
|
34668
|
+
const dir = path29.dirname(execPath);
|
|
34216
34669
|
const candidates = [
|
|
34217
34670
|
// Windows: C:\...\node.exe → C:\...\node_modules\npm\bin\npm-cli.js
|
|
34218
|
-
|
|
34671
|
+
path29.join(dir, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
34219
34672
|
// POSIX: <prefix>/bin/node → <prefix>/lib/node_modules/npm/bin/npm-cli.js
|
|
34220
|
-
|
|
34673
|
+
path29.join(dir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
34221
34674
|
];
|
|
34222
34675
|
for (const candidate of candidates) {
|
|
34223
34676
|
try {
|
|
34224
|
-
if (
|
|
34677
|
+
if (existsSync28(candidate)) return candidate;
|
|
34225
34678
|
} catch {
|
|
34226
34679
|
}
|
|
34227
34680
|
}
|
|
@@ -34234,7 +34687,7 @@ function looksLikeBrokenShim(exitCode, output) {
|
|
|
34234
34687
|
}
|
|
34235
34688
|
function getCurrentVersion() {
|
|
34236
34689
|
try {
|
|
34237
|
-
const pkgPath =
|
|
34690
|
+
const pkgPath = path29.resolve(__dirname2, "..", "..", "package.json");
|
|
34238
34691
|
const pkg = require2(pkgPath);
|
|
34239
34692
|
return pkg.version;
|
|
34240
34693
|
} catch {
|
|
@@ -34294,7 +34747,7 @@ async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
|
34294
34747
|
updateAvailable: cmp < 0
|
|
34295
34748
|
};
|
|
34296
34749
|
}
|
|
34297
|
-
async function performUpdate(packageName = "zelari-code", executor =
|
|
34750
|
+
async function performUpdate(packageName = "zelari-code", executor = spawn8, resolveNpmCli = resolveBundledNpmCli) {
|
|
34298
34751
|
const args = ["install", "-g", `${packageName}@latest`];
|
|
34299
34752
|
const primary = await runNpm(executor, args, "shim");
|
|
34300
34753
|
if (primary.ok) return primary;
|
|
@@ -34346,13 +34799,13 @@ var init_updater = __esm({
|
|
|
34346
34799
|
"use strict";
|
|
34347
34800
|
init_cmdline();
|
|
34348
34801
|
require2 = createRequire2(import.meta.url);
|
|
34349
|
-
__dirname2 =
|
|
34802
|
+
__dirname2 = path29.dirname(fileURLToPath(import.meta.url));
|
|
34350
34803
|
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
34351
34804
|
}
|
|
34352
34805
|
});
|
|
34353
34806
|
|
|
34354
34807
|
// src/cli/mcp/mcpClient.ts
|
|
34355
|
-
import { spawn as
|
|
34808
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
34356
34809
|
var DEFAULT_REQUEST_TIMEOUT_MS, INIT_TIMEOUT_MS, MCP_PROTOCOL_VERSION, McpClient;
|
|
34357
34810
|
var init_mcpClient = __esm({
|
|
34358
34811
|
"src/cli/mcp/mcpClient.ts"() {
|
|
@@ -34380,10 +34833,10 @@ var init_mcpClient = __esm({
|
|
|
34380
34833
|
env: { ...process.env, ...this.config.env ?? {} },
|
|
34381
34834
|
windowsHide: true
|
|
34382
34835
|
};
|
|
34383
|
-
const child = process.platform === "win32" ?
|
|
34836
|
+
const child = process.platform === "win32" ? spawn9(buildCmdLine(this.config.command, this.config.args ?? []), {
|
|
34384
34837
|
...spawnOpts,
|
|
34385
34838
|
shell: true
|
|
34386
|
-
}) :
|
|
34839
|
+
}) : spawn9(this.config.command, this.config.args ?? [], spawnOpts);
|
|
34387
34840
|
this.child = child;
|
|
34388
34841
|
child.stdout.setEncoding("utf8");
|
|
34389
34842
|
child.stdout.on("data", (chunk) => this.onStdout(chunk));
|
|
@@ -34521,23 +34974,23 @@ var init_mcpClient = __esm({
|
|
|
34521
34974
|
|
|
34522
34975
|
// src/cli/mcp/mcpConfigIo.ts
|
|
34523
34976
|
import {
|
|
34524
|
-
existsSync as
|
|
34525
|
-
mkdirSync as
|
|
34526
|
-
readFileSync as
|
|
34527
|
-
writeFileSync as
|
|
34977
|
+
existsSync as existsSync29,
|
|
34978
|
+
mkdirSync as mkdirSync14,
|
|
34979
|
+
readFileSync as readFileSync25,
|
|
34980
|
+
writeFileSync as writeFileSync16
|
|
34528
34981
|
} from "node:fs";
|
|
34529
|
-
import { dirname as dirname6, join as
|
|
34530
|
-
import { homedir as
|
|
34982
|
+
import { dirname as dirname6, join as join25 } from "node:path";
|
|
34983
|
+
import { homedir as homedir10 } from "node:os";
|
|
34531
34984
|
function getUserMcpPath() {
|
|
34532
|
-
return
|
|
34985
|
+
return join25(homedir10(), ".zelari-code", "mcp.json");
|
|
34533
34986
|
}
|
|
34534
34987
|
function getProjectMcpPath(projectRoot) {
|
|
34535
|
-
return
|
|
34988
|
+
return join25(projectRoot, ".zelari", "mcp.json");
|
|
34536
34989
|
}
|
|
34537
|
-
function readFile2(
|
|
34538
|
-
if (!
|
|
34990
|
+
function readFile2(path51) {
|
|
34991
|
+
if (!existsSync29(path51)) return {};
|
|
34539
34992
|
try {
|
|
34540
|
-
const parsed = JSON.parse(
|
|
34993
|
+
const parsed = JSON.parse(readFileSync25(path51, "utf8"));
|
|
34541
34994
|
const out = {};
|
|
34542
34995
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
34543
34996
|
if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
|
|
@@ -34553,10 +35006,10 @@ function readFile2(path48) {
|
|
|
34553
35006
|
return {};
|
|
34554
35007
|
}
|
|
34555
35008
|
}
|
|
34556
|
-
function writeFile(
|
|
34557
|
-
|
|
35009
|
+
function writeFile(path51, servers) {
|
|
35010
|
+
mkdirSync14(dirname6(path51), { recursive: true });
|
|
34558
35011
|
const body = { mcpServers: servers };
|
|
34559
|
-
|
|
35012
|
+
writeFileSync16(path51, `${JSON.stringify(body, null, 2)}
|
|
34560
35013
|
`, "utf8");
|
|
34561
35014
|
}
|
|
34562
35015
|
function listMcpServers(projectRoot) {
|
|
@@ -34589,9 +35042,9 @@ function upsertMcpServer(opts) {
|
|
|
34589
35042
|
if (!opts.config.command?.trim()) {
|
|
34590
35043
|
return { ok: false, error: "command is required" };
|
|
34591
35044
|
}
|
|
34592
|
-
let
|
|
35045
|
+
let path51;
|
|
34593
35046
|
if (opts.scope === "user") {
|
|
34594
|
-
|
|
35047
|
+
path51 = getUserMcpPath();
|
|
34595
35048
|
} else {
|
|
34596
35049
|
const root = opts.projectRoot?.trim();
|
|
34597
35050
|
if (!root) {
|
|
@@ -34600,30 +35053,30 @@ function upsertMcpServer(opts) {
|
|
|
34600
35053
|
error: "projectRoot required for project scope (Open Folder first)"
|
|
34601
35054
|
};
|
|
34602
35055
|
}
|
|
34603
|
-
|
|
35056
|
+
path51 = getProjectMcpPath(root);
|
|
34604
35057
|
}
|
|
34605
|
-
const current = readFile2(
|
|
35058
|
+
const current = readFile2(path51);
|
|
34606
35059
|
current[name] = {
|
|
34607
35060
|
command: opts.config.command.trim(),
|
|
34608
35061
|
args: opts.config.args,
|
|
34609
35062
|
env: opts.config.env,
|
|
34610
35063
|
enabled: opts.config.enabled !== false
|
|
34611
35064
|
};
|
|
34612
|
-
writeFile(
|
|
34613
|
-
return { ok: true, path:
|
|
35065
|
+
writeFile(path51, current);
|
|
35066
|
+
return { ok: true, path: path51 };
|
|
34614
35067
|
}
|
|
34615
35068
|
function removeMcpServer(opts) {
|
|
34616
|
-
const
|
|
34617
|
-
if (!
|
|
35069
|
+
const path51 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
|
|
35070
|
+
if (!path51) {
|
|
34618
35071
|
return { ok: false, error: "projectRoot required for project scope" };
|
|
34619
35072
|
}
|
|
34620
|
-
const current = readFile2(
|
|
35073
|
+
const current = readFile2(path51);
|
|
34621
35074
|
if (!(opts.name in current)) {
|
|
34622
|
-
return { ok: false, error: `Server "${opts.name}" not found in ${
|
|
35075
|
+
return { ok: false, error: `Server "${opts.name}" not found in ${path51}` };
|
|
34623
35076
|
}
|
|
34624
35077
|
delete current[opts.name];
|
|
34625
|
-
writeFile(
|
|
34626
|
-
return { ok: true, path:
|
|
35078
|
+
writeFile(path51, current);
|
|
35079
|
+
return { ok: true, path: path51 };
|
|
34627
35080
|
}
|
|
34628
35081
|
var init_mcpConfigIo = __esm({
|
|
34629
35082
|
"src/cli/mcp/mcpConfigIo.ts"() {
|
|
@@ -34654,13 +35107,16 @@ function buildComposioPreset() {
|
|
|
34654
35107
|
}
|
|
34655
35108
|
function buildQwenMmPreset() {
|
|
34656
35109
|
const plugin = process.env.QWEN_MM_PLUGIN?.trim() || "qwen-mm-plugins-core";
|
|
35110
|
+
const cap3 = plugin.replace(/^qwen-mm-plugins-/, "");
|
|
35111
|
+
const spec = `qwen-mm-plugins[${cap3}] @ git+https://github.com/QwenLM/Qwen-MM-Plugins.git@${plugin}-v1.0.1`;
|
|
34657
35112
|
return {
|
|
34658
35113
|
id: "qwen-mm-plugins",
|
|
34659
35114
|
servers: {
|
|
34660
35115
|
"qwen-mm-plugins": {
|
|
34661
35116
|
command: "uvx",
|
|
34662
|
-
args: [plugin],
|
|
35117
|
+
args: ["--from", spec, plugin],
|
|
34663
35118
|
env: {
|
|
35119
|
+
PYTHONIOENCODING: "utf-8",
|
|
34664
35120
|
...process.env.DASHSCOPE_API_KEY ? { DASHSCOPE_API_KEY: process.env.DASHSCOPE_API_KEY } : {},
|
|
34665
35121
|
...process.env.SERPER_API_KEY ? { SERPER_API_KEY: process.env.SERPER_API_KEY } : {}
|
|
34666
35122
|
},
|
|
@@ -34669,8 +35125,8 @@ function buildQwenMmPreset() {
|
|
|
34669
35125
|
},
|
|
34670
35126
|
notes: [
|
|
34671
35127
|
"Qwen-MM-Plugins \u2014 multimodal capabilities (core / video-memory / video-edit / blender / freecad) as MCP tools.",
|
|
34672
|
-
"
|
|
34673
|
-
"Windows:
|
|
35128
|
+
"Installs via uvx from the GitHub release tag (qwen-mm-plugins-<cap>-v1.0.1); first launch downloads ~70 packages.",
|
|
35129
|
+
"Windows: verified working natively with PYTHONIOENCODING=utf-8 (WSL2 also supported upstream).",
|
|
34674
35130
|
"Pick a capability: export QWEN_MM_PLUGIN=qwen-mm-plugins-video-memory (default: qwen-mm-plugins-core).",
|
|
34675
35131
|
"API keys read at apply time: DASHSCOPE_API_KEY, SERPER_API_KEY (native reading works without them).",
|
|
34676
35132
|
"Blender/FreeCAD variants: start the host app before invoking tools.",
|
|
@@ -34762,20 +35218,22 @@ __export(mcpManager_exports, {
|
|
|
34762
35218
|
readMcpConfig: () => readMcpConfig,
|
|
34763
35219
|
registerMcpTools: () => registerMcpTools
|
|
34764
35220
|
});
|
|
34765
|
-
import { existsSync as
|
|
34766
|
-
import { join as
|
|
34767
|
-
import { homedir as
|
|
34768
|
-
function readMcpConfig(projectRoot = process.cwd()) {
|
|
35221
|
+
import { existsSync as existsSync30, readFileSync as readFileSync26 } from "node:fs";
|
|
35222
|
+
import { join as join26 } from "node:path";
|
|
35223
|
+
import { homedir as homedir11 } from "node:os";
|
|
35224
|
+
function readMcpConfig(projectRoot = process.cwd(), opts) {
|
|
34769
35225
|
const merged = {};
|
|
34770
35226
|
const paths = [];
|
|
34771
35227
|
if (process.env["ZELARI_MCP_USER"] !== "0") {
|
|
34772
|
-
paths.push(
|
|
35228
|
+
paths.push(join26(homedir11(), ".zelari-code", "mcp.json"));
|
|
35229
|
+
}
|
|
35230
|
+
if (!opts?.skipProjectMcp) {
|
|
35231
|
+
paths.push(join26(projectRoot, ".zelari", "mcp.json"));
|
|
34773
35232
|
}
|
|
34774
|
-
paths.push(join25(projectRoot, ".zelari", "mcp.json"));
|
|
34775
35233
|
for (const p3 of paths) {
|
|
34776
|
-
if (!
|
|
35234
|
+
if (!existsSync30(p3)) continue;
|
|
34777
35235
|
try {
|
|
34778
|
-
const parsed = JSON.parse(
|
|
35236
|
+
const parsed = JSON.parse(readFileSync26(p3, "utf8"));
|
|
34779
35237
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
34780
35238
|
if (!cfg || typeof cfg.command !== "string" || cfg.command.length === 0) continue;
|
|
34781
35239
|
merged[name] = cfg;
|
|
@@ -34788,7 +35246,13 @@ function readMcpConfig(projectRoot = process.cwd()) {
|
|
|
34788
35246
|
async function ensureLoaded(projectRoot) {
|
|
34789
35247
|
if (state2.loaded) return;
|
|
34790
35248
|
state2.loaded = true;
|
|
34791
|
-
const
|
|
35249
|
+
const trusted = isFolderTrusted(projectRoot);
|
|
35250
|
+
if (!trusted && existsSync30(join26(projectRoot, ".zelari", "mcp.json"))) {
|
|
35251
|
+
state2.warnings.push(
|
|
35252
|
+
"[mcp] project .zelari/mcp.json ignored \u2014 folder not trusted (run /trust or `zelari-code --trust` to enable project MCP)"
|
|
35253
|
+
);
|
|
35254
|
+
}
|
|
35255
|
+
const servers = readMcpConfig(projectRoot, { skipProjectMcp: !trusted });
|
|
34792
35256
|
for (const [name, cfg] of Object.entries(servers)) {
|
|
34793
35257
|
if (cfg.enabled === false) continue;
|
|
34794
35258
|
if (isCuaDisabled() && isCuaMcpServerName(name)) {
|
|
@@ -34871,6 +35335,7 @@ var init_mcpManager = __esm({
|
|
|
34871
35335
|
init_toolTypes();
|
|
34872
35336
|
init_mcpClient();
|
|
34873
35337
|
init_mcpPresets();
|
|
35338
|
+
init_folderTrust();
|
|
34874
35339
|
state2 = { loaded: false, tools: [], warnings: [], clients: [] };
|
|
34875
35340
|
}
|
|
34876
35341
|
});
|
|
@@ -35007,15 +35472,15 @@ __export(agentsMd_exports, {
|
|
|
35007
35472
|
serializeAgentsMd: () => serializeAgentsMd,
|
|
35008
35473
|
updateAgentsMd: () => updateAgentsMd
|
|
35009
35474
|
});
|
|
35010
|
-
import { existsSync as
|
|
35475
|
+
import { existsSync as existsSync31, readFileSync as readFileSync27, writeFileSync as writeFileSync17 } from "node:fs";
|
|
35011
35476
|
import { createHash as createHash5 } from "node:crypto";
|
|
35012
|
-
import { join as
|
|
35477
|
+
import { join as join27 } from "node:path";
|
|
35013
35478
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
35014
35479
|
async function readPackageJson2(projectRoot) {
|
|
35015
|
-
const
|
|
35016
|
-
if (!
|
|
35480
|
+
const path51 = join27(projectRoot, "package.json");
|
|
35481
|
+
if (!existsSync31(path51)) return null;
|
|
35017
35482
|
try {
|
|
35018
|
-
return JSON.parse(await readFile3(
|
|
35483
|
+
return JSON.parse(await readFile3(path51, "utf8"));
|
|
35019
35484
|
} catch {
|
|
35020
35485
|
return null;
|
|
35021
35486
|
}
|
|
@@ -35037,8 +35502,8 @@ async function genTechStack(ctx) {
|
|
|
35037
35502
|
].join("\n");
|
|
35038
35503
|
}
|
|
35039
35504
|
async function genDecisions(ctx) {
|
|
35040
|
-
const decisionsDir =
|
|
35041
|
-
if (!
|
|
35505
|
+
const decisionsDir = join27(ctx.rootDir, "decisions");
|
|
35506
|
+
if (!existsSync31(decisionsDir)) return "_No ADRs yet._";
|
|
35042
35507
|
const files = ctx.storage.listMarkdown(decisionsDir).sort();
|
|
35043
35508
|
const accepted = [];
|
|
35044
35509
|
const proposed = [];
|
|
@@ -35063,9 +35528,9 @@ async function genDecisions(ctx) {
|
|
|
35063
35528
|
}
|
|
35064
35529
|
async function genConventions(ctx) {
|
|
35065
35530
|
const lines = [];
|
|
35066
|
-
const claudeMd =
|
|
35067
|
-
if (
|
|
35068
|
-
const content =
|
|
35531
|
+
const claudeMd = join27(ctx.projectRoot, "CLAUDE.MD");
|
|
35532
|
+
if (existsSync31(claudeMd)) {
|
|
35533
|
+
const content = readFileSync27(claudeMd, "utf8");
|
|
35069
35534
|
const match = content.match(/## Architecture rules[\s\S]+?(?=\n## |\n*$)/);
|
|
35070
35535
|
if (match) {
|
|
35071
35536
|
lines.push('<!-- Extracted from CLAUDE.MD "Architecture rules" -->');
|
|
@@ -35097,9 +35562,9 @@ async function genBuild(ctx) {
|
|
|
35097
35562
|
].join("\n");
|
|
35098
35563
|
}
|
|
35099
35564
|
async function genOpenQuestions(ctx) {
|
|
35100
|
-
const
|
|
35101
|
-
if (!
|
|
35102
|
-
const content =
|
|
35565
|
+
const path51 = join27(ctx.rootDir, "risks.md");
|
|
35566
|
+
if (!existsSync31(path51)) return "_No open questions._";
|
|
35567
|
+
const content = readFileSync27(path51, "utf8");
|
|
35103
35568
|
const lines = content.split("\n");
|
|
35104
35569
|
const questions = [];
|
|
35105
35570
|
let currentTitle = "";
|
|
@@ -35173,9 +35638,9 @@ function titleCase(id) {
|
|
|
35173
35638
|
return id.split("-").map((w) => w[0].toUpperCase() + w.slice(1)).join(" ");
|
|
35174
35639
|
}
|
|
35175
35640
|
async function updateAgentsMd(ctx, projectRoot) {
|
|
35176
|
-
const agentsPath =
|
|
35177
|
-
if (
|
|
35178
|
-
const content =
|
|
35641
|
+
const agentsPath = join27(projectRoot, "AGENTS.MD");
|
|
35642
|
+
if (existsSync31(agentsPath)) {
|
|
35643
|
+
const content = readFileSync27(agentsPath, "utf8");
|
|
35179
35644
|
const hasAnyMarker = AUTO_SECTIONS.some((id) => content.includes(MARKER_OPEN(id)));
|
|
35180
35645
|
if (!hasAnyMarker) {
|
|
35181
35646
|
return {
|
|
@@ -35190,8 +35655,8 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
35190
35655
|
newSections.set(id, await GENERATORS[id](ctx));
|
|
35191
35656
|
}
|
|
35192
35657
|
let manualContent = "";
|
|
35193
|
-
if (
|
|
35194
|
-
const { manualBlocks } = parseAgentsMd(
|
|
35658
|
+
if (existsSync31(agentsPath)) {
|
|
35659
|
+
const { manualBlocks } = parseAgentsMd(readFileSync27(agentsPath, "utf8"));
|
|
35195
35660
|
manualContent = manualBlocks.after;
|
|
35196
35661
|
} else {
|
|
35197
35662
|
const projectName2 = projectName(projectRoot);
|
|
@@ -35207,7 +35672,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
35207
35672
|
""
|
|
35208
35673
|
].join("\n");
|
|
35209
35674
|
}
|
|
35210
|
-
const oldContent =
|
|
35675
|
+
const oldContent = existsSync31(agentsPath) ? readFileSync27(agentsPath, "utf8") : "";
|
|
35211
35676
|
const { sections: oldSections } = parseAgentsMd(oldContent);
|
|
35212
35677
|
const changedSections = [];
|
|
35213
35678
|
for (const id of AUTO_SECTIONS) {
|
|
@@ -35219,7 +35684,7 @@ async function updateAgentsMd(ctx, projectRoot) {
|
|
|
35219
35684
|
return { changed: false, sections: [] };
|
|
35220
35685
|
}
|
|
35221
35686
|
const newContent = serializeAgentsMd(manualContent, newSections);
|
|
35222
|
-
|
|
35687
|
+
writeFileSync17(agentsPath, newContent, "utf8");
|
|
35223
35688
|
return { changed: true, sections: changedSections };
|
|
35224
35689
|
}
|
|
35225
35690
|
function hash2(s) {
|
|
@@ -35344,9 +35809,9 @@ var init_completeDesign = __esm({
|
|
|
35344
35809
|
});
|
|
35345
35810
|
|
|
35346
35811
|
// src/cli/workspace/projectSmoke.ts
|
|
35347
|
-
import { spawn as
|
|
35348
|
-
import { existsSync as
|
|
35349
|
-
import { join as
|
|
35812
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
35813
|
+
import { existsSync as existsSync32, readFileSync as readFileSync28 } from "node:fs";
|
|
35814
|
+
import { join as join28 } from "node:path";
|
|
35350
35815
|
function pickSmokeScript(scripts) {
|
|
35351
35816
|
if (!scripts) return null;
|
|
35352
35817
|
for (const name of SMOKE_SCRIPT_PRIORITY) {
|
|
@@ -35354,17 +35819,17 @@ function pickSmokeScript(scripts) {
|
|
|
35354
35819
|
}
|
|
35355
35820
|
return null;
|
|
35356
35821
|
}
|
|
35357
|
-
async function runProjectSmoke(projectRoot, timeoutMs =
|
|
35822
|
+
async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS2) {
|
|
35358
35823
|
if (process.env["ZELARI_SMOKE"] === "0") {
|
|
35359
35824
|
return { ran: false, reason: "ZELARI_SMOKE=0 (disabled)" };
|
|
35360
35825
|
}
|
|
35361
|
-
const pkgPath =
|
|
35362
|
-
if (!
|
|
35826
|
+
const pkgPath = join28(projectRoot, "package.json");
|
|
35827
|
+
if (!existsSync32(pkgPath)) {
|
|
35363
35828
|
return { ran: false, reason: "no package.json (skipped)" };
|
|
35364
35829
|
}
|
|
35365
35830
|
let scripts = {};
|
|
35366
35831
|
try {
|
|
35367
|
-
const pkg = JSON.parse(
|
|
35832
|
+
const pkg = JSON.parse(readFileSync28(pkgPath, "utf8"));
|
|
35368
35833
|
scripts = pkg.scripts ?? {};
|
|
35369
35834
|
} catch {
|
|
35370
35835
|
return { ran: false, reason: "package.json unreadable (skipped)" };
|
|
@@ -35374,12 +35839,12 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
|
35374
35839
|
return { ran: false, reason: "no typecheck/test/build script (skipped)" };
|
|
35375
35840
|
}
|
|
35376
35841
|
return await new Promise((resolveRun) => {
|
|
35377
|
-
const child = process.platform === "win32" ?
|
|
35842
|
+
const child = process.platform === "win32" ? spawn10(buildCmdLine("npm.cmd", ["run", script]), {
|
|
35378
35843
|
cwd: projectRoot,
|
|
35379
35844
|
stdio: ["ignore", "pipe", "pipe"],
|
|
35380
35845
|
env: process.env,
|
|
35381
35846
|
shell: true
|
|
35382
|
-
}) :
|
|
35847
|
+
}) : spawn10("npm", ["run", script], {
|
|
35383
35848
|
cwd: projectRoot,
|
|
35384
35849
|
stdio: ["ignore", "pipe", "pipe"],
|
|
35385
35850
|
env: process.env
|
|
@@ -35434,13 +35899,13 @@ async function runProjectSmoke(projectRoot, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
|
35434
35899
|
});
|
|
35435
35900
|
});
|
|
35436
35901
|
}
|
|
35437
|
-
var SMOKE_SCRIPT_PRIORITY,
|
|
35902
|
+
var SMOKE_SCRIPT_PRIORITY, DEFAULT_TIMEOUT_MS2;
|
|
35438
35903
|
var init_projectSmoke = __esm({
|
|
35439
35904
|
"src/cli/workspace/projectSmoke.ts"() {
|
|
35440
35905
|
"use strict";
|
|
35441
35906
|
init_cmdline();
|
|
35442
35907
|
SMOKE_SCRIPT_PRIORITY = ["typecheck", "test", "build"];
|
|
35443
|
-
|
|
35908
|
+
DEFAULT_TIMEOUT_MS2 = 12e4;
|
|
35444
35909
|
}
|
|
35445
35910
|
});
|
|
35446
35911
|
|
|
@@ -35451,9 +35916,9 @@ __export(postCouncilHook_exports, {
|
|
|
35451
35916
|
runImplementationVerificationHook: () => runImplementationVerificationHook,
|
|
35452
35917
|
runPostCouncilHook: () => runPostCouncilHook
|
|
35453
35918
|
});
|
|
35454
|
-
import { spawn as
|
|
35455
|
-
import { existsSync as
|
|
35456
|
-
import { join as
|
|
35919
|
+
import { spawn as spawn11 } from "node:child_process";
|
|
35920
|
+
import { existsSync as existsSync33, readFileSync as readFileSync29 } from "node:fs";
|
|
35921
|
+
import { join as join29 } from "node:path";
|
|
35457
35922
|
async function runCompleteDesignPostProcessor(ctx, options) {
|
|
35458
35923
|
if (options?.runMode === "implementation") {
|
|
35459
35924
|
return {
|
|
@@ -35464,9 +35929,9 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
35464
35929
|
if (process.env["ZELARI_COMPLETE_DESIGN"] === "0") {
|
|
35465
35930
|
return { ran: false, reason: "ZELARI_COMPLETE_DESIGN=0 (disabled)" };
|
|
35466
35931
|
}
|
|
35467
|
-
const planJsonPath2 =
|
|
35468
|
-
const scriptPath =
|
|
35469
|
-
if (!
|
|
35932
|
+
const planJsonPath2 = join29(ctx.rootDir, "plan.json");
|
|
35933
|
+
const scriptPath = join29(ctx.projectRoot, "complete-design.mjs");
|
|
35934
|
+
if (!existsSync33(planJsonPath2)) {
|
|
35470
35935
|
return {
|
|
35471
35936
|
ran: false,
|
|
35472
35937
|
reason: ".zelari/plan.json missing (not design-phase)"
|
|
@@ -35474,7 +35939,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
35474
35939
|
}
|
|
35475
35940
|
let phaseCount = 0;
|
|
35476
35941
|
try {
|
|
35477
|
-
const parsed = JSON.parse(
|
|
35942
|
+
const parsed = JSON.parse(readFileSync29(planJsonPath2, "utf8"));
|
|
35478
35943
|
phaseCount = Array.isArray(parsed.phases) ? parsed.phases.length : 0;
|
|
35479
35944
|
} catch {
|
|
35480
35945
|
return { ran: false, reason: ".zelari/plan.json corrupt" };
|
|
@@ -35482,7 +35947,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
35482
35947
|
if (phaseCount === 0) {
|
|
35483
35948
|
return { ran: false, reason: ".zelari/plan.json has no phases" };
|
|
35484
35949
|
}
|
|
35485
|
-
if (!
|
|
35950
|
+
if (!existsSync33(scriptPath)) {
|
|
35486
35951
|
try {
|
|
35487
35952
|
const builtin = await runBuiltinCompleteDesign(ctx);
|
|
35488
35953
|
return {
|
|
@@ -35500,7 +35965,7 @@ async function runCompleteDesignPostProcessor(ctx, options) {
|
|
|
35500
35965
|
}
|
|
35501
35966
|
}
|
|
35502
35967
|
return await new Promise((resolveRun) => {
|
|
35503
|
-
const child =
|
|
35968
|
+
const child = spawn11(process.execPath, [scriptPath], {
|
|
35504
35969
|
cwd: ctx.projectRoot,
|
|
35505
35970
|
stdio: ["ignore", "pipe", "pipe"],
|
|
35506
35971
|
env: process.env
|
|
@@ -35666,8 +36131,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
35666
36131
|
sources: scope.sources
|
|
35667
36132
|
} : void 0
|
|
35668
36133
|
});
|
|
35669
|
-
const
|
|
35670
|
-
completionHook = { ran: true, path:
|
|
36134
|
+
const path51 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
36135
|
+
completionHook = { ran: true, path: path51, completion };
|
|
35671
36136
|
} catch (err) {
|
|
35672
36137
|
completionHook = {
|
|
35673
36138
|
ran: true,
|
|
@@ -35705,12 +36170,12 @@ __export(councilFeedback_exports, {
|
|
|
35705
36170
|
});
|
|
35706
36171
|
import {
|
|
35707
36172
|
promises as fs15,
|
|
35708
|
-
existsSync as
|
|
35709
|
-
readFileSync as
|
|
35710
|
-
writeFileSync as
|
|
35711
|
-
mkdirSync as
|
|
36173
|
+
existsSync as existsSync34,
|
|
36174
|
+
readFileSync as readFileSync30,
|
|
36175
|
+
writeFileSync as writeFileSync18,
|
|
36176
|
+
mkdirSync as mkdirSync15
|
|
35712
36177
|
} from "node:fs";
|
|
35713
|
-
import
|
|
36178
|
+
import path30 from "node:path";
|
|
35714
36179
|
import os8 from "node:os";
|
|
35715
36180
|
var FeedbackStore;
|
|
35716
36181
|
var init_councilFeedback = __esm({
|
|
@@ -35721,7 +36186,7 @@ var init_councilFeedback = __esm({
|
|
|
35721
36186
|
now;
|
|
35722
36187
|
entries = [];
|
|
35723
36188
|
constructor(options = {}) {
|
|
35724
|
-
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ??
|
|
36189
|
+
this.file = options.file ?? (process.env.ANATHEMA_COUNCIL_FEEDBACK_FILE ?? path30.join(os8.homedir(), ".tmp", "zelari-code", "council-feedback.json"));
|
|
35725
36190
|
this.now = options.now ?? Date.now;
|
|
35726
36191
|
this.load();
|
|
35727
36192
|
}
|
|
@@ -35814,9 +36279,9 @@ var init_councilFeedback = __esm({
|
|
|
35814
36279
|
}
|
|
35815
36280
|
// --- persistence ---------------------------------------------------------
|
|
35816
36281
|
load() {
|
|
35817
|
-
if (!
|
|
36282
|
+
if (!existsSync34(this.file)) return;
|
|
35818
36283
|
try {
|
|
35819
|
-
const raw =
|
|
36284
|
+
const raw = readFileSync30(this.file, "utf-8");
|
|
35820
36285
|
const parsed = JSON.parse(raw);
|
|
35821
36286
|
if (parsed && Array.isArray(parsed.entries)) {
|
|
35822
36287
|
this.entries = parsed.entries.filter(
|
|
@@ -35827,8 +36292,8 @@ var init_councilFeedback = __esm({
|
|
|
35827
36292
|
}
|
|
35828
36293
|
}
|
|
35829
36294
|
save() {
|
|
35830
|
-
|
|
35831
|
-
|
|
36295
|
+
mkdirSync15(path30.dirname(this.file), { recursive: true });
|
|
36296
|
+
writeFileSync18(
|
|
35832
36297
|
this.file,
|
|
35833
36298
|
JSON.stringify({ entries: this.entries }, null, 2),
|
|
35834
36299
|
{ encoding: "utf-8", mode: 384 }
|
|
@@ -35895,7 +36360,7 @@ import { execFile as execFile3 } from "node:child_process";
|
|
|
35895
36360
|
import { promisify as promisify2 } from "node:util";
|
|
35896
36361
|
import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
|
|
35897
36362
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
35898
|
-
import
|
|
36363
|
+
import path31 from "node:path";
|
|
35899
36364
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
35900
36365
|
async function git2(cwd, args, env) {
|
|
35901
36366
|
const { stdout } = await execFileAsync2("git", ["-C", cwd, ...args], {
|
|
@@ -35915,8 +36380,8 @@ async function isGitRepo(cwd) {
|
|
|
35915
36380
|
return await gitSafe(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true";
|
|
35916
36381
|
}
|
|
35917
36382
|
async function withTempIndex(fn) {
|
|
35918
|
-
const dir = mkdtempSync(
|
|
35919
|
-
const indexFile =
|
|
36383
|
+
const dir = mkdtempSync(path31.join(tmpdir2(), "zelari-ckpt-"));
|
|
36384
|
+
const indexFile = path31.join(dir, "index");
|
|
35920
36385
|
try {
|
|
35921
36386
|
return await fn(indexFile);
|
|
35922
36387
|
} finally {
|
|
@@ -36007,7 +36472,7 @@ async function restoreCheckpoint(cwd, id) {
|
|
|
36007
36472
|
const deleted = [];
|
|
36008
36473
|
for (const rel2 of added) {
|
|
36009
36474
|
try {
|
|
36010
|
-
rmSync2(
|
|
36475
|
+
rmSync2(path31.join(cwd, rel2), { force: true });
|
|
36011
36476
|
deleted.push(rel2);
|
|
36012
36477
|
} catch {
|
|
36013
36478
|
}
|
|
@@ -36108,7 +36573,7 @@ __export(fileBackend_exports, {
|
|
|
36108
36573
|
});
|
|
36109
36574
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
36110
36575
|
import { promises as fs16 } from "node:fs";
|
|
36111
|
-
import * as
|
|
36576
|
+
import * as path32 from "node:path";
|
|
36112
36577
|
function tokenize(text) {
|
|
36113
36578
|
return text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((t) => t.length >= 3);
|
|
36114
36579
|
}
|
|
@@ -36152,8 +36617,8 @@ var init_fileBackend = __esm({
|
|
|
36152
36617
|
logPath = "";
|
|
36153
36618
|
memoryDir = "";
|
|
36154
36619
|
async init(projectRoot) {
|
|
36155
|
-
this.memoryDir =
|
|
36156
|
-
this.logPath =
|
|
36620
|
+
this.memoryDir = path32.join(projectRoot, ".zelari", "memory");
|
|
36621
|
+
this.logPath = path32.join(this.memoryDir, "log.jsonl");
|
|
36157
36622
|
await fs16.mkdir(this.memoryDir, { recursive: true });
|
|
36158
36623
|
}
|
|
36159
36624
|
async add(content, metadata = {}, graph) {
|
|
@@ -36226,12 +36691,12 @@ var init_fileBackend = __esm({
|
|
|
36226
36691
|
|
|
36227
36692
|
// src/cli/traceStore.ts
|
|
36228
36693
|
import { promises as fs17 } from "node:fs";
|
|
36229
|
-
import * as
|
|
36694
|
+
import * as path33 from "node:path";
|
|
36230
36695
|
function traceDir(projectRoot) {
|
|
36231
|
-
return
|
|
36696
|
+
return path33.join(projectRoot, ".zelari", "trace");
|
|
36232
36697
|
}
|
|
36233
36698
|
function tracePath(projectRoot, missionId) {
|
|
36234
|
-
return
|
|
36699
|
+
return path33.join(traceDir(projectRoot), `${missionId}.json`);
|
|
36235
36700
|
}
|
|
36236
36701
|
async function saveTrace(projectRoot, missionId, entries) {
|
|
36237
36702
|
const dir = traceDir(projectRoot);
|
|
@@ -36266,7 +36731,7 @@ __export(zelariMission_exports, {
|
|
|
36266
36731
|
});
|
|
36267
36732
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
36268
36733
|
import { promises as fs18 } from "node:fs";
|
|
36269
|
-
import * as
|
|
36734
|
+
import * as path34 from "node:path";
|
|
36270
36735
|
function resolveMaxIterations(env = process.env) {
|
|
36271
36736
|
const raw = env.ZELARI_MISSION_MAX_ITER;
|
|
36272
36737
|
const n = raw ? Number.parseInt(raw, 10) : DEFAULT_MAX_ITER;
|
|
@@ -36294,10 +36759,10 @@ function isMissionAutoStart(env = process.env) {
|
|
|
36294
36759
|
return env.ZELARI_MISSION_AUTO === "1";
|
|
36295
36760
|
}
|
|
36296
36761
|
async function writeMissionState(projectRoot, state3) {
|
|
36297
|
-
const dir =
|
|
36762
|
+
const dir = path34.join(projectRoot, ".zelari");
|
|
36298
36763
|
await fs18.mkdir(dir, { recursive: true });
|
|
36299
36764
|
await fs18.writeFile(
|
|
36300
|
-
|
|
36765
|
+
path34.join(dir, "mission-state.json"),
|
|
36301
36766
|
JSON.stringify(state3, null, 2) + "\n",
|
|
36302
36767
|
"utf8"
|
|
36303
36768
|
);
|
|
@@ -36897,7 +37362,7 @@ function safeSocketPath(socketPath) {
|
|
|
36897
37362
|
return socketPath.trim();
|
|
36898
37363
|
}
|
|
36899
37364
|
function startPermissionBroker(socketPath, handlers, opts) {
|
|
36900
|
-
const
|
|
37365
|
+
const path51 = safeSocketPath(socketPath);
|
|
36901
37366
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
36902
37367
|
const sockets = /* @__PURE__ */ new Set();
|
|
36903
37368
|
const server = createServer((socket) => {
|
|
@@ -36997,10 +37462,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
36997
37462
|
return new Promise((resolve3, reject) => {
|
|
36998
37463
|
const onError = (err) => reject(err);
|
|
36999
37464
|
server.once("error", onError);
|
|
37000
|
-
server.listen(
|
|
37465
|
+
server.listen(path51, () => {
|
|
37001
37466
|
server.removeListener("error", onError);
|
|
37002
37467
|
resolve3({
|
|
37003
|
-
socketPath:
|
|
37468
|
+
socketPath: path51,
|
|
37004
37469
|
stop: () => new Promise((res) => {
|
|
37005
37470
|
for (const s of sockets) s.destroy();
|
|
37006
37471
|
sockets.clear();
|
|
@@ -37011,7 +37476,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
37011
37476
|
if (done) return;
|
|
37012
37477
|
done = true;
|
|
37013
37478
|
if (process.platform !== "win32") {
|
|
37014
|
-
unlink(
|
|
37479
|
+
unlink(path51, () => res());
|
|
37015
37480
|
} else {
|
|
37016
37481
|
res();
|
|
37017
37482
|
}
|
|
@@ -37024,11 +37489,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
37024
37489
|
});
|
|
37025
37490
|
}
|
|
37026
37491
|
function requestBrokerAsk(socketPath, ask, opts) {
|
|
37027
|
-
const
|
|
37492
|
+
const path51 = safeSocketPath(socketPath);
|
|
37028
37493
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
37029
37494
|
const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
|
|
37030
37495
|
return new Promise((resolve3, reject) => {
|
|
37031
|
-
const socket = connect(
|
|
37496
|
+
const socket = connect(path51);
|
|
37032
37497
|
let buffer = "";
|
|
37033
37498
|
let settled = false;
|
|
37034
37499
|
const settle = (fn) => {
|
|
@@ -37043,7 +37508,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
|
|
|
37043
37508
|
settle(
|
|
37044
37509
|
() => reject(
|
|
37045
37510
|
new Error(
|
|
37046
|
-
`permission broker unavailable at "${
|
|
37511
|
+
`permission broker unavailable at "${path51}" (connect timed out after ${connectTimeoutMs}ms)`
|
|
37047
37512
|
)
|
|
37048
37513
|
)
|
|
37049
37514
|
);
|
|
@@ -37776,9 +38241,9 @@ __export(graphMemory_exports, {
|
|
|
37776
38241
|
toGraphSnapshot: () => toGraphSnapshot
|
|
37777
38242
|
});
|
|
37778
38243
|
import { promises as fs19 } from "node:fs";
|
|
37779
|
-
import
|
|
38244
|
+
import path36 from "node:path";
|
|
37780
38245
|
function snapshotPath(cwd) {
|
|
37781
|
-
return
|
|
38246
|
+
return path36.join(cwd, SNAPSHOT_DIR, SNAPSHOT_FILE);
|
|
37782
38247
|
}
|
|
37783
38248
|
function toGraphSnapshot(graph, opts) {
|
|
37784
38249
|
const unresolved = (opts.unresolvedFindings ?? []).map((u) => ({
|
|
@@ -37805,7 +38270,7 @@ async function saveGraphSnapshot(cwd, snapshot) {
|
|
|
37805
38270
|
try {
|
|
37806
38271
|
await fs19.access(cwd);
|
|
37807
38272
|
const file2 = snapshotPath(cwd);
|
|
37808
|
-
await fs19.mkdir(
|
|
38273
|
+
await fs19.mkdir(path36.dirname(file2), { recursive: true });
|
|
37809
38274
|
await fs19.writeFile(file2, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
37810
38275
|
} catch {
|
|
37811
38276
|
}
|
|
@@ -37872,7 +38337,7 @@ var SNAPSHOT_DIR, SNAPSHOT_FILE, MAX_SNAPSHOT_FINDINGS_CHARS;
|
|
|
37872
38337
|
var init_graphMemory = __esm({
|
|
37873
38338
|
"src/cli/kraken/graphMemory.ts"() {
|
|
37874
38339
|
"use strict";
|
|
37875
|
-
SNAPSHOT_DIR =
|
|
38340
|
+
SNAPSHOT_DIR = path36.join(".zelari", "kraken");
|
|
37876
38341
|
SNAPSHOT_FILE = "last-graph.json";
|
|
37877
38342
|
MAX_SNAPSHOT_FINDINGS_CHARS = 400;
|
|
37878
38343
|
}
|
|
@@ -37888,14 +38353,14 @@ var init_tentacle = __esm({
|
|
|
37888
38353
|
|
|
37889
38354
|
// src/cli/kraken/workbench.ts
|
|
37890
38355
|
import { promises as fs20 } from "node:fs";
|
|
37891
|
-
import
|
|
38356
|
+
import path37 from "node:path";
|
|
37892
38357
|
function isWorkbenchEnabled(env = process.env) {
|
|
37893
38358
|
const v = (env.ZELARI_KRAKEN_WORKBENCH ?? "1").trim().toLowerCase();
|
|
37894
38359
|
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
37895
38360
|
return true;
|
|
37896
38361
|
}
|
|
37897
38362
|
function workbenchPath(cwd, graphId) {
|
|
37898
|
-
return
|
|
38363
|
+
return path37.join(cwd, ".zelari", "radio", `workbench-${graphId}.md`);
|
|
37899
38364
|
}
|
|
37900
38365
|
function countByStatus2(nodes) {
|
|
37901
38366
|
const out = { pending: 0, running: 0, done: 0, error: 0, skipped: 0 };
|
|
@@ -38058,7 +38523,7 @@ var init_workbench = __esm({
|
|
|
38058
38523
|
if (!this.enabled) return null;
|
|
38059
38524
|
if (!this.dirty && this.lastWrite) return this.lastWrite;
|
|
38060
38525
|
const out = workbenchPath(this.cwd, this.graphId);
|
|
38061
|
-
await fs20.mkdir(
|
|
38526
|
+
await fs20.mkdir(path37.dirname(out), { recursive: true });
|
|
38062
38527
|
const body = this.render();
|
|
38063
38528
|
const tmp = `${out}.${process.pid}.${Date.now()}.tmp`;
|
|
38064
38529
|
await fs20.writeFile(tmp, body, "utf8");
|
|
@@ -38254,8 +38719,8 @@ __export(executor_exports, {
|
|
|
38254
38719
|
resolveNodeTimeoutMs: () => resolveNodeTimeoutMs,
|
|
38255
38720
|
thoroughnessForKind: () => thoroughnessForKind
|
|
38256
38721
|
});
|
|
38257
|
-
import { existsSync as
|
|
38258
|
-
import
|
|
38722
|
+
import { existsSync as existsSync35 } from "node:fs";
|
|
38723
|
+
import path38 from "node:path";
|
|
38259
38724
|
function resolveMaxParallel(env = process.env) {
|
|
38260
38725
|
const raw = env.ZELARI_KRAKEN_MAX_PARALLEL;
|
|
38261
38726
|
if (raw === void 0 || raw === "") return DEFAULT_MAX_PARALLEL;
|
|
@@ -38313,7 +38778,7 @@ function isWorldModelGateEnabled(cwd, env = process.env, checksExists = defaultC
|
|
|
38313
38778
|
}
|
|
38314
38779
|
function defaultChecksExists(cwd) {
|
|
38315
38780
|
try {
|
|
38316
|
-
return
|
|
38781
|
+
return existsSync35(path38.join(cwd, ".zelari", "world", "checks.json"));
|
|
38317
38782
|
} catch {
|
|
38318
38783
|
return false;
|
|
38319
38784
|
}
|
|
@@ -39280,7 +39745,7 @@ __export(prereqChecks_exports, {
|
|
|
39280
39745
|
runPrereqChecks: () => runPrereqChecks
|
|
39281
39746
|
});
|
|
39282
39747
|
import { execSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
39283
|
-
import { existsSync as
|
|
39748
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
39284
39749
|
import { dirname as dirname7 } from "node:path";
|
|
39285
39750
|
function isWslBashPath2(p3) {
|
|
39286
39751
|
if (!p3 || typeof p3 !== "string") return false;
|
|
@@ -39404,7 +39869,7 @@ function agentProbeEnv() {
|
|
|
39404
39869
|
}
|
|
39405
39870
|
function existsSyncSafe2(p3) {
|
|
39406
39871
|
try {
|
|
39407
|
-
return
|
|
39872
|
+
return existsSync36(p3);
|
|
39408
39873
|
} catch {
|
|
39409
39874
|
return false;
|
|
39410
39875
|
}
|
|
@@ -39651,17 +40116,17 @@ var init_prereqChecks = __esm({
|
|
|
39651
40116
|
});
|
|
39652
40117
|
|
|
39653
40118
|
// src/cli/plugins/prefs.ts
|
|
39654
|
-
import { existsSync as
|
|
39655
|
-
import
|
|
40119
|
+
import { existsSync as existsSync37, readFileSync as readFileSync31, writeFileSync as writeFileSync19, mkdirSync as mkdirSync16 } from "node:fs";
|
|
40120
|
+
import path41 from "node:path";
|
|
39656
40121
|
import os9 from "node:os";
|
|
39657
40122
|
function getPluginPrefsPath() {
|
|
39658
|
-
return process.env.ZELARI_PLUGINS_PREFS_FILE ??
|
|
40123
|
+
return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path41.join(os9.homedir(), ".tmp", "zelari-code", "plugins.json");
|
|
39659
40124
|
}
|
|
39660
40125
|
function getPluginPrefs() {
|
|
39661
40126
|
const file2 = getPluginPrefsPath();
|
|
39662
40127
|
try {
|
|
39663
|
-
if (!
|
|
39664
|
-
const raw =
|
|
40128
|
+
if (!existsSync37(file2)) return { ...DEFAULTS2, dontAskAgain: {} };
|
|
40129
|
+
const raw = readFileSync31(file2, "utf-8");
|
|
39665
40130
|
const parsed = JSON.parse(raw);
|
|
39666
40131
|
if (parsed && typeof parsed === "object" && parsed.dontAskAgain && typeof parsed.dontAskAgain === "object") {
|
|
39667
40132
|
const clean = {};
|
|
@@ -39676,8 +40141,8 @@ function getPluginPrefs() {
|
|
|
39676
40141
|
}
|
|
39677
40142
|
function writePluginPrefs(prefs) {
|
|
39678
40143
|
const file2 = getPluginPrefsPath();
|
|
39679
|
-
|
|
39680
|
-
|
|
40144
|
+
mkdirSync16(path41.dirname(file2), { recursive: true });
|
|
40145
|
+
writeFileSync19(file2, JSON.stringify(prefs, null, 2), {
|
|
39681
40146
|
encoding: "utf-8",
|
|
39682
40147
|
mode: 384
|
|
39683
40148
|
});
|
|
@@ -39712,8 +40177,8 @@ __export(registry_exports, {
|
|
|
39712
40177
|
findPlugin: () => findPlugin,
|
|
39713
40178
|
isBinaryOnPath: () => isBinaryOnPath
|
|
39714
40179
|
});
|
|
39715
|
-
import { existsSync as
|
|
39716
|
-
import
|
|
40180
|
+
import { existsSync as existsSync38 } from "node:fs";
|
|
40181
|
+
import path42 from "node:path";
|
|
39717
40182
|
function detectLocalBin(bin) {
|
|
39718
40183
|
return (cwd) => {
|
|
39719
40184
|
try {
|
|
@@ -39729,9 +40194,9 @@ function isBinaryOnPath(bin, opts = {}) {
|
|
|
39729
40194
|
return false;
|
|
39730
40195
|
}
|
|
39731
40196
|
const platform = opts.platform ?? process.platform;
|
|
39732
|
-
const exists = opts.exists ??
|
|
40197
|
+
const exists = opts.exists ?? existsSync38;
|
|
39733
40198
|
const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
|
|
39734
|
-
const pathMod = platform === "win32" ?
|
|
40199
|
+
const pathMod = platform === "win32" ? path42.win32 : path42.posix;
|
|
39735
40200
|
const sep2 = platform === "win32" ? ";" : ":";
|
|
39736
40201
|
const dirs = pathEnv.split(sep2).filter((d) => d.length > 0);
|
|
39737
40202
|
const candidates = [bin];
|
|
@@ -39868,7 +40333,7 @@ __export(atMentions_exports, {
|
|
|
39868
40333
|
extractAtMentions: () => extractAtMentions,
|
|
39869
40334
|
hasAtMentions: () => hasAtMentions
|
|
39870
40335
|
});
|
|
39871
|
-
import { existsSync as
|
|
40336
|
+
import { existsSync as existsSync41, readFileSync as readFileSync33, statSync as statSync6 } from "node:fs";
|
|
39872
40337
|
import { basename as basename3, isAbsolute as isAbsolute2, relative as relative3, resolve, sep } from "node:path";
|
|
39873
40338
|
function isImagePath(abs) {
|
|
39874
40339
|
const ext = abs.split(".").pop()?.toLowerCase() ?? "";
|
|
@@ -39922,7 +40387,7 @@ function resolveMention(token, cwd) {
|
|
|
39922
40387
|
note: "outside project root \u2014 skipped"
|
|
39923
40388
|
};
|
|
39924
40389
|
}
|
|
39925
|
-
if (!
|
|
40390
|
+
if (!existsSync41(abs)) {
|
|
39926
40391
|
return {
|
|
39927
40392
|
raw: token,
|
|
39928
40393
|
path: token,
|
|
@@ -39974,7 +40439,7 @@ function resolveMention(token, cwd) {
|
|
|
39974
40439
|
note: `image too large (${Math.round(st.size / 1024)} KB) \u2014 path only`
|
|
39975
40440
|
};
|
|
39976
40441
|
}
|
|
39977
|
-
const dataBase64 =
|
|
40442
|
+
const dataBase64 = readFileSync33(abs).toString("base64");
|
|
39978
40443
|
return {
|
|
39979
40444
|
raw: token,
|
|
39980
40445
|
path: rel2,
|
|
@@ -39985,7 +40450,7 @@ function resolveMention(token, cwd) {
|
|
|
39985
40450
|
};
|
|
39986
40451
|
}
|
|
39987
40452
|
try {
|
|
39988
|
-
const buf =
|
|
40453
|
+
const buf = readFileSync33(abs);
|
|
39989
40454
|
const head = buf.subarray(0, 800).toString("utf8");
|
|
39990
40455
|
if (!isProbablyText(abs, head)) {
|
|
39991
40456
|
return {
|
|
@@ -40083,9 +40548,9 @@ __export(triggerLock_exports, {
|
|
|
40083
40548
|
releaseLock: () => releaseLock
|
|
40084
40549
|
});
|
|
40085
40550
|
import { promises as fs28 } from "node:fs";
|
|
40086
|
-
import * as
|
|
40551
|
+
import * as path47 from "node:path";
|
|
40087
40552
|
function lockPath(projectRoot) {
|
|
40088
|
-
return
|
|
40553
|
+
return path47.join(projectRoot, ".zelari", "trigger.lock");
|
|
40089
40554
|
}
|
|
40090
40555
|
function isPidAlive(pid) {
|
|
40091
40556
|
try {
|
|
@@ -40098,7 +40563,7 @@ function isPidAlive(pid) {
|
|
|
40098
40563
|
}
|
|
40099
40564
|
async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
|
|
40100
40565
|
const lp = lockPath(projectRoot);
|
|
40101
|
-
const dir =
|
|
40566
|
+
const dir = path47.dirname(lp);
|
|
40102
40567
|
await fs28.mkdir(dir, { recursive: true });
|
|
40103
40568
|
try {
|
|
40104
40569
|
const raw = await fs28.readFile(lp, "utf8");
|
|
@@ -40380,6 +40845,269 @@ var init_desktopConfig = __esm({
|
|
|
40380
40845
|
}
|
|
40381
40846
|
});
|
|
40382
40847
|
|
|
40848
|
+
// src/cli/skillCategories.ts
|
|
40849
|
+
var CODING_CATEGORIES_LIST, CODING_CATEGORIES2;
|
|
40850
|
+
var init_skillCategories = __esm({
|
|
40851
|
+
"src/cli/skillCategories.ts"() {
|
|
40852
|
+
"use strict";
|
|
40853
|
+
CODING_CATEGORIES_LIST = [
|
|
40854
|
+
"plan",
|
|
40855
|
+
"refactor",
|
|
40856
|
+
"debug",
|
|
40857
|
+
"review",
|
|
40858
|
+
"test",
|
|
40859
|
+
"docs",
|
|
40860
|
+
"ops",
|
|
40861
|
+
"git",
|
|
40862
|
+
"db",
|
|
40863
|
+
"maint"
|
|
40864
|
+
];
|
|
40865
|
+
CODING_CATEGORIES2 = new Set(CODING_CATEGORIES_LIST);
|
|
40866
|
+
}
|
|
40867
|
+
});
|
|
40868
|
+
|
|
40869
|
+
// src/cli/skillConfigIo.ts
|
|
40870
|
+
import {
|
|
40871
|
+
existsSync as existsSync43,
|
|
40872
|
+
mkdirSync as mkdirSync19,
|
|
40873
|
+
readdirSync as readdirSync8,
|
|
40874
|
+
readFileSync as readFileSync35,
|
|
40875
|
+
rmSync as rmSync4,
|
|
40876
|
+
writeFileSync as writeFileSync21
|
|
40877
|
+
} from "node:fs";
|
|
40878
|
+
import { dirname as dirname9, join as join35 } from "node:path";
|
|
40879
|
+
import { homedir as homedir12 } from "node:os";
|
|
40880
|
+
function ensureBuiltinSkillsLoadedSync() {
|
|
40881
|
+
if (builtinsLoaded) return;
|
|
40882
|
+
for (const spec of BUILTIN_SKILL_MODULES) {
|
|
40883
|
+
try {
|
|
40884
|
+
require?.(spec);
|
|
40885
|
+
} catch {
|
|
40886
|
+
}
|
|
40887
|
+
}
|
|
40888
|
+
}
|
|
40889
|
+
function getUserSkillsDir() {
|
|
40890
|
+
return join35(homedir12(), ".zelari-code", "skills");
|
|
40891
|
+
}
|
|
40892
|
+
function getProjectSkillsDir(projectRoot) {
|
|
40893
|
+
return join35(projectRoot, ".zelari", "skills");
|
|
40894
|
+
}
|
|
40895
|
+
function skillFilePath(dir, name) {
|
|
40896
|
+
return join35(dir, name, "SKILL.md");
|
|
40897
|
+
}
|
|
40898
|
+
function classifyScope(skillPath, projectRoot) {
|
|
40899
|
+
const userDir = getUserSkillsDir().replace(/\\/g, "/");
|
|
40900
|
+
const norm = skillPath.replace(/\\/g, "/");
|
|
40901
|
+
if (norm.startsWith(userDir + "/") || norm === userDir) {
|
|
40902
|
+
return { scope: "user", writable: true };
|
|
40903
|
+
}
|
|
40904
|
+
if (projectRoot) {
|
|
40905
|
+
const projDir = getProjectSkillsDir(projectRoot).replace(/\\/g, "/");
|
|
40906
|
+
if (norm.startsWith(projDir + "/") || norm === projDir) {
|
|
40907
|
+
return { scope: "project", writable: true };
|
|
40908
|
+
}
|
|
40909
|
+
}
|
|
40910
|
+
return { scope: "compat", writable: false };
|
|
40911
|
+
}
|
|
40912
|
+
function entryFromParsed(parsed, projectRoot) {
|
|
40913
|
+
const { scope, writable } = classifyScope(parsed.sourcePath, projectRoot);
|
|
40914
|
+
return {
|
|
40915
|
+
id: parsed.name,
|
|
40916
|
+
name: parsed.name,
|
|
40917
|
+
description: parsed.description,
|
|
40918
|
+
category: parsed.category,
|
|
40919
|
+
estimatedCost: parsed.estimatedCost,
|
|
40920
|
+
requiredTools: parsed.requiredTools,
|
|
40921
|
+
scope,
|
|
40922
|
+
path: parsed.sourcePath,
|
|
40923
|
+
body: parsed.body,
|
|
40924
|
+
builtin: false,
|
|
40925
|
+
writable
|
|
40926
|
+
};
|
|
40927
|
+
}
|
|
40928
|
+
function entryFromBuiltin(skill) {
|
|
40929
|
+
return {
|
|
40930
|
+
id: skill.id,
|
|
40931
|
+
name: skill.name || skill.id,
|
|
40932
|
+
description: skill.description || "",
|
|
40933
|
+
category: skill.category,
|
|
40934
|
+
estimatedCost: skill.estimatedCost,
|
|
40935
|
+
requiredTools: skill.requiredTools,
|
|
40936
|
+
scope: "builtin",
|
|
40937
|
+
path: null,
|
|
40938
|
+
// Expose body so Desktop skill picker can expand like `/skill <id>`.
|
|
40939
|
+
body: skill.systemPromptFragment || void 0,
|
|
40940
|
+
builtin: true,
|
|
40941
|
+
writable: false
|
|
40942
|
+
};
|
|
40943
|
+
}
|
|
40944
|
+
function scanSkillsDir(dir, projectRoot, seen, out) {
|
|
40945
|
+
if (!existsSync43(dir)) return;
|
|
40946
|
+
let entries;
|
|
40947
|
+
try {
|
|
40948
|
+
entries = readdirSync8(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
40949
|
+
} catch {
|
|
40950
|
+
return;
|
|
40951
|
+
}
|
|
40952
|
+
for (const entry of entries) {
|
|
40953
|
+
const skillPath = skillFilePath(dir, entry);
|
|
40954
|
+
if (!existsSync43(skillPath)) continue;
|
|
40955
|
+
try {
|
|
40956
|
+
const parsed = parseSkillMd(readFileSync35(skillPath, "utf8"), skillPath);
|
|
40957
|
+
if (!parsed) continue;
|
|
40958
|
+
if (seen.has(parsed.name)) continue;
|
|
40959
|
+
seen.add(parsed.name);
|
|
40960
|
+
out.push(entryFromParsed(parsed, projectRoot));
|
|
40961
|
+
} catch {
|
|
40962
|
+
}
|
|
40963
|
+
}
|
|
40964
|
+
}
|
|
40965
|
+
function listSkillsSnapshot(projectRoot) {
|
|
40966
|
+
const root = projectRoot && projectRoot.trim() ? projectRoot.trim() : null;
|
|
40967
|
+
const userSkillsDir = getUserSkillsDir();
|
|
40968
|
+
const projectSkillsDir = root ? getProjectSkillsDir(root) : null;
|
|
40969
|
+
const skills = [];
|
|
40970
|
+
const seen = /* @__PURE__ */ new Set();
|
|
40971
|
+
if (root) {
|
|
40972
|
+
scanSkillsDir(join35(root, ".zelari", "skills"), root, seen, skills);
|
|
40973
|
+
scanSkillsDir(join35(root, ".claude", "skills"), root, seen, skills);
|
|
40974
|
+
scanSkillsDir(join35(root, ".opencode", "skills"), root, seen, skills);
|
|
40975
|
+
}
|
|
40976
|
+
scanSkillsDir(userSkillsDir, root, seen, skills);
|
|
40977
|
+
for (const s of listCodingSkills()) {
|
|
40978
|
+
if (seen.has(s.id)) continue;
|
|
40979
|
+
seen.add(s.id);
|
|
40980
|
+
if (s.builtin) {
|
|
40981
|
+
skills.push(entryFromBuiltin(s));
|
|
40982
|
+
}
|
|
40983
|
+
}
|
|
40984
|
+
skills.sort((a, b) => {
|
|
40985
|
+
const order = (s) => s === "project" ? 0 : s === "user" ? 1 : s === "compat" ? 2 : 3;
|
|
40986
|
+
const d = order(a.scope) - order(b.scope);
|
|
40987
|
+
if (d !== 0) return d;
|
|
40988
|
+
return a.id.localeCompare(b.id);
|
|
40989
|
+
});
|
|
40990
|
+
return { userSkillsDir, projectSkillsDir, skills };
|
|
40991
|
+
}
|
|
40992
|
+
function serializeSkillMd(opts) {
|
|
40993
|
+
const name = opts.name.trim().toLowerCase();
|
|
40994
|
+
const description = opts.description.trim();
|
|
40995
|
+
const body = opts.body.trim();
|
|
40996
|
+
const lines = ["---", `name: ${name}`, `description: ${description}`];
|
|
40997
|
+
const cat = (opts.category ?? "").trim().toLowerCase();
|
|
40998
|
+
if (cat && CODING_CATEGORIES2.has(cat)) {
|
|
40999
|
+
lines.push(`category: ${cat}`);
|
|
41000
|
+
}
|
|
41001
|
+
if (opts.tools && opts.tools.length > 0) {
|
|
41002
|
+
lines.push(`tools: [${opts.tools.map((t) => t.trim()).filter(Boolean).join(", ")}]`);
|
|
41003
|
+
}
|
|
41004
|
+
const cost = (opts.cost ?? "").trim().toLowerCase();
|
|
41005
|
+
if (cost === "low" || cost === "medium" || cost === "high") {
|
|
41006
|
+
lines.push(`cost: ${cost}`);
|
|
41007
|
+
}
|
|
41008
|
+
lines.push("---", "", body, "");
|
|
41009
|
+
return lines.join("\n");
|
|
41010
|
+
}
|
|
41011
|
+
function upsertSkill(opts) {
|
|
41012
|
+
const name = opts.name.trim().toLowerCase();
|
|
41013
|
+
if (!name || !NAME_RE.test(name)) {
|
|
41014
|
+
return {
|
|
41015
|
+
ok: false,
|
|
41016
|
+
error: "Invalid skill name (use lowercase letters, digits, hyphens; max 64 chars)"
|
|
41017
|
+
};
|
|
41018
|
+
}
|
|
41019
|
+
const description = opts.description.trim();
|
|
41020
|
+
if (!description) {
|
|
41021
|
+
return { ok: false, error: "description is required" };
|
|
41022
|
+
}
|
|
41023
|
+
const body = opts.body.trim();
|
|
41024
|
+
if (!body) {
|
|
41025
|
+
return { ok: false, error: "body is required" };
|
|
41026
|
+
}
|
|
41027
|
+
let dir;
|
|
41028
|
+
if (opts.scope === "user") {
|
|
41029
|
+
dir = getUserSkillsDir();
|
|
41030
|
+
} else {
|
|
41031
|
+
const root = opts.projectRoot?.trim();
|
|
41032
|
+
if (!root) {
|
|
41033
|
+
return {
|
|
41034
|
+
ok: false,
|
|
41035
|
+
error: "projectRoot required for project scope (Open Folder first)"
|
|
41036
|
+
};
|
|
41037
|
+
}
|
|
41038
|
+
dir = getProjectSkillsDir(root);
|
|
41039
|
+
}
|
|
41040
|
+
const path51 = skillFilePath(dir, name);
|
|
41041
|
+
const content = serializeSkillMd({
|
|
41042
|
+
name,
|
|
41043
|
+
description,
|
|
41044
|
+
body,
|
|
41045
|
+
category: opts.category,
|
|
41046
|
+
tools: opts.tools,
|
|
41047
|
+
cost: opts.cost
|
|
41048
|
+
});
|
|
41049
|
+
const parsed = parseSkillMd(content, path51);
|
|
41050
|
+
if (!parsed) {
|
|
41051
|
+
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
41052
|
+
}
|
|
41053
|
+
mkdirSync19(dirname9(path51), { recursive: true });
|
|
41054
|
+
writeFileSync21(path51, content, "utf8");
|
|
41055
|
+
return { ok: true, path: path51 };
|
|
41056
|
+
}
|
|
41057
|
+
function removeSkill(opts) {
|
|
41058
|
+
const name = opts.name.trim().toLowerCase();
|
|
41059
|
+
if (!name) {
|
|
41060
|
+
return { ok: false, error: "name is required" };
|
|
41061
|
+
}
|
|
41062
|
+
let dir;
|
|
41063
|
+
if (opts.scope === "user") {
|
|
41064
|
+
dir = getUserSkillsDir();
|
|
41065
|
+
} else {
|
|
41066
|
+
const root = opts.projectRoot?.trim();
|
|
41067
|
+
if (!root) {
|
|
41068
|
+
return { ok: false, error: "projectRoot required for project scope" };
|
|
41069
|
+
}
|
|
41070
|
+
dir = getProjectSkillsDir(root);
|
|
41071
|
+
}
|
|
41072
|
+
const skillDir = join35(dir, name);
|
|
41073
|
+
const path51 = skillFilePath(dir, name);
|
|
41074
|
+
if (!existsSync43(path51) && !existsSync43(skillDir)) {
|
|
41075
|
+
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
41076
|
+
}
|
|
41077
|
+
try {
|
|
41078
|
+
rmSync4(skillDir, { recursive: true, force: true });
|
|
41079
|
+
} catch (err) {
|
|
41080
|
+
return {
|
|
41081
|
+
ok: false,
|
|
41082
|
+
error: err instanceof Error ? err.message : String(err)
|
|
41083
|
+
};
|
|
41084
|
+
}
|
|
41085
|
+
return { ok: true, path: path51 };
|
|
41086
|
+
}
|
|
41087
|
+
var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
|
|
41088
|
+
var init_skillConfigIo = __esm({
|
|
41089
|
+
"src/cli/skillConfigIo.ts"() {
|
|
41090
|
+
"use strict";
|
|
41091
|
+
init_skills2();
|
|
41092
|
+
init_skillsMd();
|
|
41093
|
+
init_skillCategories();
|
|
41094
|
+
NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
41095
|
+
BUILTIN_SKILL_MODULES = [
|
|
41096
|
+
"@zelari/core/skills/builtin/debugging",
|
|
41097
|
+
"@zelari/core/skills/builtin/docs",
|
|
41098
|
+
"@zelari/core/skills/builtin/git-ops",
|
|
41099
|
+
"@zelari/core/skills/builtin/planning",
|
|
41100
|
+
"@zelari/core/skills/builtin/refactoring",
|
|
41101
|
+
"@zelari/core/skills/builtin/review",
|
|
41102
|
+
"@zelari/core/skills/builtin/testing",
|
|
41103
|
+
"@zelari/core/skills/builtin/schema-loop",
|
|
41104
|
+
"@zelari/core/skills/builtin/computer-use-cua",
|
|
41105
|
+
"@zelari/core/skills/builtin/qwen-mm-plugins"
|
|
41106
|
+
];
|
|
41107
|
+
builtinsLoaded = false;
|
|
41108
|
+
}
|
|
41109
|
+
});
|
|
41110
|
+
|
|
40383
41111
|
// src/cli/mcp/mcpPermissionServer.ts
|
|
40384
41112
|
import { createInterface } from "node:readline";
|
|
40385
41113
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
@@ -40648,36 +41376,36 @@ var init_permissionCli = __esm({
|
|
|
40648
41376
|
|
|
40649
41377
|
// src/cli/companion/config.ts
|
|
40650
41378
|
import {
|
|
40651
|
-
existsSync as
|
|
40652
|
-
mkdirSync as
|
|
40653
|
-
readFileSync as
|
|
40654
|
-
writeFileSync as
|
|
41379
|
+
existsSync as existsSync44,
|
|
41380
|
+
mkdirSync as mkdirSync20,
|
|
41381
|
+
readFileSync as readFileSync36,
|
|
41382
|
+
writeFileSync as writeFileSync22
|
|
40655
41383
|
} from "node:fs";
|
|
40656
|
-
import { join as
|
|
40657
|
-
import { homedir as
|
|
41384
|
+
import { join as join36 } from "node:path";
|
|
41385
|
+
import { homedir as homedir13 } from "node:os";
|
|
40658
41386
|
import { createHash as createHash6, randomBytes as randomBytes4, timingSafeEqual } from "node:crypto";
|
|
40659
41387
|
function getZelariHome() {
|
|
40660
|
-
return
|
|
41388
|
+
return join36(homedir13(), ".zelari-code");
|
|
40661
41389
|
}
|
|
40662
41390
|
function getCompanionConfigPath() {
|
|
40663
|
-
return
|
|
41391
|
+
return join36(getZelariHome(), "companion.json");
|
|
40664
41392
|
}
|
|
40665
41393
|
function getCompanionTokenPath() {
|
|
40666
|
-
return
|
|
41394
|
+
return join36(getZelariHome(), "companion.token");
|
|
40667
41395
|
}
|
|
40668
41396
|
function ensureHome() {
|
|
40669
41397
|
const home = getZelariHome();
|
|
40670
|
-
if (!
|
|
40671
|
-
|
|
41398
|
+
if (!existsSync44(home)) {
|
|
41399
|
+
mkdirSync20(home, { recursive: true });
|
|
40672
41400
|
}
|
|
40673
41401
|
}
|
|
40674
41402
|
function loadCompanionConfig() {
|
|
40675
|
-
const
|
|
40676
|
-
if (!
|
|
41403
|
+
const path51 = getCompanionConfigPath();
|
|
41404
|
+
if (!existsSync44(path51)) {
|
|
40677
41405
|
return { projects: [] };
|
|
40678
41406
|
}
|
|
40679
41407
|
try {
|
|
40680
|
-
const raw = JSON.parse(
|
|
41408
|
+
const raw = JSON.parse(readFileSync36(path51, "utf8"));
|
|
40681
41409
|
const projects = Array.isArray(raw.projects) ? raw.projects.filter(
|
|
40682
41410
|
(p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
|
|
40683
41411
|
).map((p3) => ({
|
|
@@ -40696,7 +41424,7 @@ function loadCompanionConfig() {
|
|
|
40696
41424
|
}
|
|
40697
41425
|
function saveCompanionConfig(cfg) {
|
|
40698
41426
|
ensureHome();
|
|
40699
|
-
|
|
41427
|
+
writeFileSync22(
|
|
40700
41428
|
getCompanionConfigPath(),
|
|
40701
41429
|
JSON.stringify(
|
|
40702
41430
|
{
|
|
@@ -40715,16 +41443,16 @@ function loadOrCreateToken(explicit) {
|
|
|
40715
41443
|
return { token: explicit.trim(), created: false };
|
|
40716
41444
|
}
|
|
40717
41445
|
ensureHome();
|
|
40718
|
-
const
|
|
40719
|
-
if (
|
|
40720
|
-
const t =
|
|
41446
|
+
const path51 = getCompanionTokenPath();
|
|
41447
|
+
if (existsSync44(path51)) {
|
|
41448
|
+
const t = readFileSync36(path51, "utf8").trim();
|
|
40721
41449
|
if (t) return { token: t, created: false };
|
|
40722
41450
|
}
|
|
40723
41451
|
const token = randomBytes4(24).toString("base64url");
|
|
40724
|
-
|
|
41452
|
+
writeFileSync22(path51, token + "\n", "utf8");
|
|
40725
41453
|
try {
|
|
40726
41454
|
const fs30 = __require("node:fs");
|
|
40727
|
-
fs30.chmodSync?.(
|
|
41455
|
+
fs30.chmodSync?.(path51, 384);
|
|
40728
41456
|
} catch {
|
|
40729
41457
|
}
|
|
40730
41458
|
return { token, created: true };
|
|
@@ -40749,17 +41477,17 @@ function mergeProjects(cfg, extraPaths) {
|
|
|
40749
41477
|
byId.set(p3.id, p3);
|
|
40750
41478
|
}
|
|
40751
41479
|
for (const raw of extraPaths) {
|
|
40752
|
-
const
|
|
40753
|
-
if (!
|
|
40754
|
-
let id = slugFromPath(
|
|
41480
|
+
const path51 = raw.trim();
|
|
41481
|
+
if (!path51) continue;
|
|
41482
|
+
let id = slugFromPath(path51);
|
|
40755
41483
|
let n = 2;
|
|
40756
|
-
while (byId.has(id) && byId.get(id).path !==
|
|
40757
|
-
id = `${slugFromPath(
|
|
41484
|
+
while (byId.has(id) && byId.get(id).path !== path51) {
|
|
41485
|
+
id = `${slugFromPath(path51)}-${n++}`;
|
|
40758
41486
|
}
|
|
40759
41487
|
byId.set(id, {
|
|
40760
41488
|
id,
|
|
40761
|
-
name: slugFromPath(
|
|
40762
|
-
path:
|
|
41489
|
+
name: slugFromPath(path51),
|
|
41490
|
+
path: path51
|
|
40763
41491
|
});
|
|
40764
41492
|
}
|
|
40765
41493
|
return [...byId.values()];
|
|
@@ -40807,11 +41535,11 @@ var init_config = __esm({
|
|
|
40807
41535
|
});
|
|
40808
41536
|
|
|
40809
41537
|
// src/cli/companion/runManager.ts
|
|
40810
|
-
import { spawn as
|
|
41538
|
+
import { spawn as spawn13 } from "node:child_process";
|
|
40811
41539
|
import { createInterface as createInterface2 } from "node:readline";
|
|
40812
41540
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
40813
|
-
import { writeFileSync as
|
|
40814
|
-
import { join as
|
|
41541
|
+
import { writeFileSync as writeFileSync23, unlinkSync as unlinkSync2 } from "node:fs";
|
|
41542
|
+
import { join as join37 } from "node:path";
|
|
40815
41543
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
40816
41544
|
var RunManager;
|
|
40817
41545
|
var init_runManager = __esm({
|
|
@@ -40915,15 +41643,15 @@ var init_runManager = __esm({
|
|
|
40915
41643
|
}
|
|
40916
41644
|
let historyFile;
|
|
40917
41645
|
if (args.history && Array.isArray(args.history) && args.history.length > 0) {
|
|
40918
|
-
historyFile =
|
|
41646
|
+
historyFile = join37(tmpdir3(), `zelari-companion-hist-${id}.json`);
|
|
40919
41647
|
try {
|
|
40920
|
-
|
|
41648
|
+
writeFileSync23(historyFile, JSON.stringify(args.history), "utf8");
|
|
40921
41649
|
argv.push("--history-file", historyFile);
|
|
40922
41650
|
} catch {
|
|
40923
41651
|
historyFile = void 0;
|
|
40924
41652
|
}
|
|
40925
41653
|
}
|
|
40926
|
-
const child =
|
|
41654
|
+
const child = spawn13(process.execPath, argv, {
|
|
40927
41655
|
cwd: args.cwd,
|
|
40928
41656
|
env: {
|
|
40929
41657
|
...process.env,
|
|
@@ -41042,7 +41770,7 @@ __export(serve_exports, {
|
|
|
41042
41770
|
runCompanionServe: () => runCompanionServe
|
|
41043
41771
|
});
|
|
41044
41772
|
import { createServer as createServer2 } from "node:http";
|
|
41045
|
-
import { existsSync as
|
|
41773
|
+
import { existsSync as existsSync45 } from "node:fs";
|
|
41046
41774
|
import { resolve as resolve2 } from "node:path";
|
|
41047
41775
|
function readBody(req, max = 2e6) {
|
|
41048
41776
|
return new Promise((resolveBody, reject) => {
|
|
@@ -41090,7 +41818,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
41090
41818
|
let projects = mergeProjects(fileCfg, opts.projects ?? []);
|
|
41091
41819
|
projects = projects.filter((p3) => {
|
|
41092
41820
|
const abs = resolve2(p3.path);
|
|
41093
|
-
if (!
|
|
41821
|
+
if (!existsSync45(abs)) {
|
|
41094
41822
|
process.stderr.write(
|
|
41095
41823
|
`[zelari-code serve] skip missing project path: ${p3.path}
|
|
41096
41824
|
`
|
|
@@ -41136,9 +41864,9 @@ async function runCompanionServe(opts = {}) {
|
|
|
41136
41864
|
return;
|
|
41137
41865
|
}
|
|
41138
41866
|
const url2 = parseUrl(req);
|
|
41139
|
-
const
|
|
41867
|
+
const path51 = url2.pathname.replace(/\/+$/, "") || "/";
|
|
41140
41868
|
try {
|
|
41141
|
-
if (req.method === "GET" && (
|
|
41869
|
+
if (req.method === "GET" && (path51 === "/health" || path51 === "/v1/health")) {
|
|
41142
41870
|
sendJson2(res, 200, {
|
|
41143
41871
|
ok: true,
|
|
41144
41872
|
service: "zelari-companion",
|
|
@@ -41150,18 +41878,18 @@ async function runCompanionServe(opts = {}) {
|
|
|
41150
41878
|
});
|
|
41151
41879
|
return;
|
|
41152
41880
|
}
|
|
41153
|
-
if (
|
|
41881
|
+
if (path51.startsWith("/v1")) {
|
|
41154
41882
|
if (!tokenMatches(token, getBearer(req))) {
|
|
41155
41883
|
sendJson2(res, 401, { ok: false, error: "unauthorized" });
|
|
41156
41884
|
return;
|
|
41157
41885
|
}
|
|
41158
41886
|
}
|
|
41159
|
-
if (req.method === "GET" &&
|
|
41887
|
+
if (req.method === "GET" && path51 === "/v1/config") {
|
|
41160
41888
|
const snap = buildDesktopConfigSnapshot();
|
|
41161
41889
|
sendJson2(res, 200, { ok: true, ...snap });
|
|
41162
41890
|
return;
|
|
41163
41891
|
}
|
|
41164
|
-
if (req.method === "GET" &&
|
|
41892
|
+
if (req.method === "GET" && path51 === "/v1/projects") {
|
|
41165
41893
|
sendJson2(res, 200, {
|
|
41166
41894
|
ok: true,
|
|
41167
41895
|
projects: projects.map((p3) => ({
|
|
@@ -41172,7 +41900,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
41172
41900
|
});
|
|
41173
41901
|
return;
|
|
41174
41902
|
}
|
|
41175
|
-
if (req.method === "GET" &&
|
|
41903
|
+
if (req.method === "GET" && path51 === "/v1/runs") {
|
|
41176
41904
|
sendJson2(res, 200, {
|
|
41177
41905
|
ok: true,
|
|
41178
41906
|
active: runs.getActive(),
|
|
@@ -41190,7 +41918,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
41190
41918
|
});
|
|
41191
41919
|
return;
|
|
41192
41920
|
}
|
|
41193
|
-
if (req.method === "POST" &&
|
|
41921
|
+
if (req.method === "POST" && path51 === "/v1/runs") {
|
|
41194
41922
|
const raw = await readBody(req);
|
|
41195
41923
|
let body = {};
|
|
41196
41924
|
try {
|
|
@@ -41237,7 +41965,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
41237
41965
|
});
|
|
41238
41966
|
return;
|
|
41239
41967
|
}
|
|
41240
|
-
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(
|
|
41968
|
+
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path51);
|
|
41241
41969
|
if (req.method === "GET" && eventsMatch) {
|
|
41242
41970
|
const runId = eventsMatch[1];
|
|
41243
41971
|
const run = runs.getRun(runId);
|
|
@@ -41302,7 +42030,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
41302
42030
|
}, 500);
|
|
41303
42031
|
return;
|
|
41304
42032
|
}
|
|
41305
|
-
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(
|
|
42033
|
+
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path51);
|
|
41306
42034
|
if (req.method === "POST" && cancelMatch) {
|
|
41307
42035
|
const runId = cancelMatch[1];
|
|
41308
42036
|
const result = runs.cancel(runId);
|
|
@@ -41411,26 +42139,26 @@ __export(doctor_exports, {
|
|
|
41411
42139
|
runDoctor: () => runDoctor
|
|
41412
42140
|
});
|
|
41413
42141
|
import { execSync as execSync2 } from "node:child_process";
|
|
41414
|
-
import { existsSync as
|
|
42142
|
+
import { existsSync as existsSync46, readFileSync as readFileSync37, readlinkSync, statSync as statSync7 } from "node:fs";
|
|
41415
42143
|
import { createRequire as createRequire3 } from "node:module";
|
|
41416
42144
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
41417
|
-
import
|
|
42145
|
+
import path49 from "node:path";
|
|
41418
42146
|
function findPackageRoot(start) {
|
|
41419
42147
|
let dir = start;
|
|
41420
42148
|
for (let i = 0; i < 6; i += 1) {
|
|
41421
|
-
const candidate =
|
|
41422
|
-
if (
|
|
42149
|
+
const candidate = path49.join(dir, "package.json");
|
|
42150
|
+
if (existsSync46(candidate)) {
|
|
41423
42151
|
try {
|
|
41424
|
-
const pkg = JSON.parse(
|
|
42152
|
+
const pkg = JSON.parse(readFileSync37(candidate, "utf8"));
|
|
41425
42153
|
if (pkg.name === "zelari-code") return dir;
|
|
41426
42154
|
} catch {
|
|
41427
42155
|
}
|
|
41428
42156
|
}
|
|
41429
|
-
const parent =
|
|
42157
|
+
const parent = path49.dirname(dir);
|
|
41430
42158
|
if (parent === dir) break;
|
|
41431
42159
|
dir = parent;
|
|
41432
42160
|
}
|
|
41433
|
-
return
|
|
42161
|
+
return path49.resolve(__dirname3, "..", "..", "..");
|
|
41434
42162
|
}
|
|
41435
42163
|
function tryExec(cmd) {
|
|
41436
42164
|
try {
|
|
@@ -41444,8 +42172,8 @@ function tryExec(cmd) {
|
|
|
41444
42172
|
}
|
|
41445
42173
|
function readPackageJson3() {
|
|
41446
42174
|
try {
|
|
41447
|
-
const pkgPath =
|
|
41448
|
-
return JSON.parse(
|
|
42175
|
+
const pkgPath = path49.join(packageRoot, "package.json");
|
|
42176
|
+
return JSON.parse(readFileSync37(pkgPath, "utf8"));
|
|
41449
42177
|
} catch {
|
|
41450
42178
|
return null;
|
|
41451
42179
|
}
|
|
@@ -41460,8 +42188,8 @@ function checkShim(pkgName) {
|
|
|
41460
42188
|
}
|
|
41461
42189
|
const isWin = process.platform === "win32";
|
|
41462
42190
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
41463
|
-
const shimPath =
|
|
41464
|
-
if (!
|
|
42191
|
+
const shimPath = path49.join(prefix, shimName);
|
|
42192
|
+
if (!existsSync46(shimPath)) {
|
|
41465
42193
|
return FAIL(
|
|
41466
42194
|
`shim not found at ${shimPath}
|
|
41467
42195
|
fix: npm install -g ${pkgName}@latest --force`
|
|
@@ -41470,7 +42198,7 @@ function checkShim(pkgName) {
|
|
|
41470
42198
|
try {
|
|
41471
42199
|
const st = statSync7(shimPath);
|
|
41472
42200
|
if (isWin) {
|
|
41473
|
-
const content =
|
|
42201
|
+
const content = readFileSync37(shimPath, "utf8");
|
|
41474
42202
|
if (content.includes(`${pkgName}\\bin\\`) || content.includes(`${pkgName}/bin/`)) {
|
|
41475
42203
|
return OK(`shim OK at ${shimPath} (${st.size} bytes)`);
|
|
41476
42204
|
}
|
|
@@ -41488,8 +42216,8 @@ function checkShim(pkgName) {
|
|
|
41488
42216
|
fix: npm install -g ${pkgName}@latest --force`
|
|
41489
42217
|
);
|
|
41490
42218
|
}
|
|
41491
|
-
const resolved =
|
|
41492
|
-
const expected =
|
|
42219
|
+
const resolved = path49.resolve(path49.dirname(shimPath), target);
|
|
42220
|
+
const expected = path49.join(
|
|
41493
42221
|
prefix,
|
|
41494
42222
|
"node_modules",
|
|
41495
42223
|
pkgName,
|
|
@@ -41528,8 +42256,8 @@ function checkNode(pkg) {
|
|
|
41528
42256
|
return OK(`node ${raw}`);
|
|
41529
42257
|
}
|
|
41530
42258
|
function checkBundle() {
|
|
41531
|
-
const bundle =
|
|
41532
|
-
if (!
|
|
42259
|
+
const bundle = path49.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
42260
|
+
if (!existsSync46(bundle)) {
|
|
41533
42261
|
return FAIL(
|
|
41534
42262
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
41535
42263
|
fix: npm run build:cli (then reinstall or run via tsx)`
|
|
@@ -41549,7 +42277,7 @@ function checkRuntimeDeps() {
|
|
|
41549
42277
|
const missing = [];
|
|
41550
42278
|
for (const dep of required2) {
|
|
41551
42279
|
try {
|
|
41552
|
-
const localReq = createRequire3(
|
|
42280
|
+
const localReq = createRequire3(path49.join(packageRoot, "package.json"));
|
|
41553
42281
|
localReq.resolve(dep);
|
|
41554
42282
|
} catch {
|
|
41555
42283
|
missing.push(dep);
|
|
@@ -41725,7 +42453,7 @@ var init_doctor = __esm({
|
|
|
41725
42453
|
"use strict";
|
|
41726
42454
|
init_prereqChecks();
|
|
41727
42455
|
require3 = createRequire3(import.meta.url);
|
|
41728
|
-
__dirname3 =
|
|
42456
|
+
__dirname3 = path49.dirname(fileURLToPath2(import.meta.url));
|
|
41729
42457
|
packageRoot = findPackageRoot(__dirname3);
|
|
41730
42458
|
OK = (message) => ({
|
|
41731
42459
|
ok: true,
|
|
@@ -41903,6 +42631,154 @@ var init_fixBudget = __esm({
|
|
|
41903
42631
|
}
|
|
41904
42632
|
});
|
|
41905
42633
|
|
|
42634
|
+
// src/cli/commands/inspect.ts
|
|
42635
|
+
var inspect_exports = {};
|
|
42636
|
+
__export(inspect_exports, {
|
|
42637
|
+
collectInspectReport: () => collectInspectReport,
|
|
42638
|
+
runInspect: () => runInspect
|
|
42639
|
+
});
|
|
42640
|
+
import path50 from "node:path";
|
|
42641
|
+
import { existsSync as existsSync47, readFileSync as readFileSync38, readdirSync as readdirSync9 } from "node:fs";
|
|
42642
|
+
import { homedir as homedir14 } from "node:os";
|
|
42643
|
+
async function collectInspectReport(cwd = process.cwd()) {
|
|
42644
|
+
ensureBuiltinSkillsLoadedSync();
|
|
42645
|
+
const snap = listSkillsSnapshot(cwd);
|
|
42646
|
+
const mcp = listMcpServers(cwd);
|
|
42647
|
+
const userMcpPath = path50.join(homedir14(), ".zelari-code", "mcp.json");
|
|
42648
|
+
const projectMcpPath = path50.join(cwd, ".zelari", "mcp.json");
|
|
42649
|
+
const globalHooks = globalHooksDir();
|
|
42650
|
+
const projectHooks = projectHooksDir(cwd);
|
|
42651
|
+
const projectTrusted = isFolderTrusted(cwd);
|
|
42652
|
+
const skillsByScope = (scope) => snap.skills.filter((s) => s.scope === scope).length;
|
|
42653
|
+
const pluginStates = await Promise.all(
|
|
42654
|
+
PLUGINS.map(async (p3) => ({
|
|
42655
|
+
id: p3.id,
|
|
42656
|
+
label: p3.label ?? p3.id,
|
|
42657
|
+
installed: await p3.detect(cwd)
|
|
42658
|
+
}))
|
|
42659
|
+
);
|
|
42660
|
+
return {
|
|
42661
|
+
schemaVersion: 1,
|
|
42662
|
+
zelariVersion: getCurrentVersion(),
|
|
42663
|
+
cwd,
|
|
42664
|
+
platform: `${process.platform}-${process.arch}`,
|
|
42665
|
+
node: process.version,
|
|
42666
|
+
phase: process.env.ZELARI_PHASE ?? "build",
|
|
42667
|
+
mode: process.env.ZELARI_MODE ?? "kraken",
|
|
42668
|
+
trust: {
|
|
42669
|
+
store: getTrustStorePath(),
|
|
42670
|
+
trusted: projectTrusted,
|
|
42671
|
+
folders: listTrustedFolders()
|
|
42672
|
+
},
|
|
42673
|
+
configSources: [
|
|
42674
|
+
{ path: userMcpPath, exists: existsSync47(userMcpPath) },
|
|
42675
|
+
{ path: projectMcpPath, exists: existsSync47(projectMcpPath) },
|
|
42676
|
+
{ path: path50.join(homedir14(), ".zelari-code", "provider.json"), exists: existsSync47(path50.join(homedir14(), ".zelari-code", "provider.json")) },
|
|
42677
|
+
{ path: path50.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync47(path50.join(cwd, ".zelari", "AGENTS.md")) },
|
|
42678
|
+
{ path: path50.join(cwd, "AGENTS.md"), exists: existsSync47(path50.join(cwd, "AGENTS.md")) }
|
|
42679
|
+
],
|
|
42680
|
+
skills: {
|
|
42681
|
+
total: snap.skills.length,
|
|
42682
|
+
builtin: skillsByScope("builtin"),
|
|
42683
|
+
user: skillsByScope("user"),
|
|
42684
|
+
project: skillsByScope("project"),
|
|
42685
|
+
compat: skillsByScope("compat")
|
|
42686
|
+
},
|
|
42687
|
+
mcp: {
|
|
42688
|
+
user: mcp.servers.filter((s) => s.scope === "user").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
|
|
42689
|
+
project: mcp.servers.filter((s) => s.scope === "project").map((s) => ({ name: s.name, enabled: s.enabled !== false })),
|
|
42690
|
+
projectTrusted,
|
|
42691
|
+
projectConfigExists: existsSync47(projectMcpPath)
|
|
42692
|
+
},
|
|
42693
|
+
hooks: {
|
|
42694
|
+
global: {
|
|
42695
|
+
path: globalHooks,
|
|
42696
|
+
active: true,
|
|
42697
|
+
files: listJsonFiles(globalHooks)
|
|
42698
|
+
},
|
|
42699
|
+
project: {
|
|
42700
|
+
path: projectHooks,
|
|
42701
|
+
active: projectTrusted,
|
|
42702
|
+
files: listJsonFiles(projectHooks)
|
|
42703
|
+
}
|
|
42704
|
+
},
|
|
42705
|
+
plugins: pluginStates,
|
|
42706
|
+
agentsMd: findAgentsMd(cwd)
|
|
42707
|
+
};
|
|
42708
|
+
}
|
|
42709
|
+
function listJsonFiles(dir) {
|
|
42710
|
+
try {
|
|
42711
|
+
return readdirSync9(dir).filter((f) => f.endsWith(".json")).sort();
|
|
42712
|
+
} catch {
|
|
42713
|
+
return [];
|
|
42714
|
+
}
|
|
42715
|
+
}
|
|
42716
|
+
function findAgentsMd(cwd) {
|
|
42717
|
+
const candidates = [
|
|
42718
|
+
path50.join(cwd, "AGENTS.md"),
|
|
42719
|
+
path50.join(cwd, ".zelari", "AGENTS.md")
|
|
42720
|
+
];
|
|
42721
|
+
const found = [];
|
|
42722
|
+
for (const c of candidates) {
|
|
42723
|
+
if (existsSync47(c)) {
|
|
42724
|
+
try {
|
|
42725
|
+
const text = readFileSync38(c, "utf8");
|
|
42726
|
+
found.push(`${c} (${text.length} bytes)`);
|
|
42727
|
+
} catch {
|
|
42728
|
+
found.push(`${c} (unreadable)`);
|
|
42729
|
+
}
|
|
42730
|
+
}
|
|
42731
|
+
}
|
|
42732
|
+
return found;
|
|
42733
|
+
}
|
|
42734
|
+
function formatHuman(r) {
|
|
42735
|
+
const lines = [
|
|
42736
|
+
`zelari-code inspect v${r.zelariVersion}`,
|
|
42737
|
+
` cwd: ${r.cwd}`,
|
|
42738
|
+
` platform: ${r.platform} node ${r.node}`,
|
|
42739
|
+
` phase: ${r.phase} mode: ${r.mode}`,
|
|
42740
|
+
``,
|
|
42741
|
+
`trust: ${r.trust.trusted ? "TRUSTED \u2714" : "NOT TRUSTED \u2716"} (store: ${r.trust.store})`,
|
|
42742
|
+
...r.trust.folders.map((f) => ` - ${f.path} (${f.trustedAt})`),
|
|
42743
|
+
``,
|
|
42744
|
+
`skills: ${r.skills.total} total (builtin ${r.skills.builtin}, user ${r.skills.user}, project ${r.skills.project}, compat ${r.skills.compat})`,
|
|
42745
|
+
``,
|
|
42746
|
+
`MCP:`,
|
|
42747
|
+
` user: ${r.mcp.user.length ? r.mcp.user.map((m) => m.name).join(", ") : "(none)"}`,
|
|
42748
|
+
` project: ${r.mcp.projectConfigExists ? r.mcp.projectTrusted ? r.mcp.project.map((m) => m.name).join(", ") || "(configured, no servers)" : "IGNORED (folder not trusted)" : "(no .zelari/mcp.json)"}`,
|
|
42749
|
+
``,
|
|
42750
|
+
`hooks:`,
|
|
42751
|
+
` global: ${r.hooks.global.active ? "active" : "inactive"} @ ${r.hooks.global.path} (${r.hooks.global.files.length} file(s))`,
|
|
42752
|
+
` project: ${r.hooks.project.active ? "active" : "IGNORED (folder not trusted)"} @ ${r.hooks.project.path} (${r.hooks.project.files.length} file(s))`,
|
|
42753
|
+
``,
|
|
42754
|
+
`plugins: ${r.plugins.length ? r.plugins.map((p3) => `${p3.id}${p3.installed ? "" : " (missing)"}`).join(", ") : "(none)"}`,
|
|
42755
|
+
``,
|
|
42756
|
+
`AGENTS.md rules:`,
|
|
42757
|
+
...r.agentsMd.length ? r.agentsMd.map((a) => ` - ${a}`) : [" (none)"]
|
|
42758
|
+
];
|
|
42759
|
+
return lines.join("\n");
|
|
42760
|
+
}
|
|
42761
|
+
async function runInspect(opts = {}) {
|
|
42762
|
+
const report = await collectInspectReport(opts.cwd ?? process.cwd());
|
|
42763
|
+
if (opts.json) {
|
|
42764
|
+
console.log(JSON.stringify(report, null, 2));
|
|
42765
|
+
} else {
|
|
42766
|
+
console.log(formatHuman(report));
|
|
42767
|
+
}
|
|
42768
|
+
return 0;
|
|
42769
|
+
}
|
|
42770
|
+
var init_inspect = __esm({
|
|
42771
|
+
"src/cli/commands/inspect.ts"() {
|
|
42772
|
+
"use strict";
|
|
42773
|
+
init_folderTrust();
|
|
42774
|
+
init_lifecycleHooks();
|
|
42775
|
+
init_mcpConfigIo();
|
|
42776
|
+
init_skillConfigIo();
|
|
42777
|
+
init_registry3();
|
|
42778
|
+
init_updater();
|
|
42779
|
+
}
|
|
42780
|
+
});
|
|
42781
|
+
|
|
41906
42782
|
// src/cli/main.ts
|
|
41907
42783
|
import React15 from "react";
|
|
41908
42784
|
import { render } from "ink";
|
|
@@ -44767,15 +45643,15 @@ import { useState as useState5, useRef as useRef3, useCallback, useEffect as use
|
|
|
44767
45643
|
|
|
44768
45644
|
// src/cli/sessionManager.ts
|
|
44769
45645
|
init_harness();
|
|
44770
|
-
import { promises as fs9, existsSync as existsSync9, readFileSync as
|
|
44771
|
-
import
|
|
45646
|
+
import { promises as fs9, existsSync as existsSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync9, mkdirSync as mkdirSync4, unlinkSync, statSync } from "node:fs";
|
|
45647
|
+
import path13 from "node:path";
|
|
44772
45648
|
import os4 from "node:os";
|
|
44773
45649
|
import { randomUUID } from "node:crypto";
|
|
44774
45650
|
function getSessionBaseDir() {
|
|
44775
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
45651
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path13.join(os4.homedir(), ".tmp", "zelari-code", "sessions");
|
|
44776
45652
|
}
|
|
44777
45653
|
function getCurrentSessionFile() {
|
|
44778
|
-
return process.env.ANATHEMA_CURRENT_SESSION_FILE ??
|
|
45654
|
+
return process.env.ANATHEMA_CURRENT_SESSION_FILE ?? path13.join(os4.homedir(), ".tmp", "zelari-code", "current.txt");
|
|
44779
45655
|
}
|
|
44780
45656
|
async function ensureSessionDir() {
|
|
44781
45657
|
await fs9.mkdir(getSessionBaseDir(), { recursive: true });
|
|
@@ -44784,7 +45660,7 @@ function getCurrentSessionId() {
|
|
|
44784
45660
|
const file2 = getCurrentSessionFile();
|
|
44785
45661
|
if (!existsSync9(file2)) return null;
|
|
44786
45662
|
try {
|
|
44787
|
-
const content =
|
|
45663
|
+
const content = readFileSync12(file2, "utf-8").trim();
|
|
44788
45664
|
return content.length > 0 ? content : null;
|
|
44789
45665
|
} catch {
|
|
44790
45666
|
return null;
|
|
@@ -44792,7 +45668,7 @@ function getCurrentSessionId() {
|
|
|
44792
45668
|
}
|
|
44793
45669
|
function setCurrentSessionId(id) {
|
|
44794
45670
|
const file2 = getCurrentSessionFile();
|
|
44795
|
-
mkdirSync4(
|
|
45671
|
+
mkdirSync4(path13.dirname(file2), { recursive: true });
|
|
44796
45672
|
writeFileSync9(file2, id, "utf-8");
|
|
44797
45673
|
}
|
|
44798
45674
|
function clearCurrentSessionId() {
|
|
@@ -44804,13 +45680,13 @@ function clearCurrentSessionId() {
|
|
|
44804
45680
|
}
|
|
44805
45681
|
}
|
|
44806
45682
|
function getCurrentBranchFile() {
|
|
44807
|
-
return process.env.ANATHEMA_CURRENT_BRANCH_FILE ??
|
|
45683
|
+
return process.env.ANATHEMA_CURRENT_BRANCH_FILE ?? path13.join(path13.dirname(getCurrentSessionFile()), "currentBranch.txt");
|
|
44808
45684
|
}
|
|
44809
45685
|
function getCurrentBranch() {
|
|
44810
45686
|
const file2 = getCurrentBranchFile();
|
|
44811
45687
|
if (!existsSync9(file2)) return null;
|
|
44812
45688
|
try {
|
|
44813
|
-
const content =
|
|
45689
|
+
const content = readFileSync12(file2, "utf-8").trim();
|
|
44814
45690
|
return content.length > 0 ? content : null;
|
|
44815
45691
|
} catch {
|
|
44816
45692
|
return null;
|
|
@@ -44818,7 +45694,7 @@ function getCurrentBranch() {
|
|
|
44818
45694
|
}
|
|
44819
45695
|
function setCurrentBranch(name) {
|
|
44820
45696
|
const file2 = getCurrentBranchFile();
|
|
44821
|
-
mkdirSync4(
|
|
45697
|
+
mkdirSync4(path13.dirname(file2), { recursive: true });
|
|
44822
45698
|
writeFileSync9(file2, name, "utf-8");
|
|
44823
45699
|
}
|
|
44824
45700
|
function newSessionId() {
|
|
@@ -44837,7 +45713,7 @@ async function listSessions() {
|
|
|
44837
45713
|
for (const entry of entries) {
|
|
44838
45714
|
if (!entry.endsWith(".jsonl")) continue;
|
|
44839
45715
|
const id = entry.replace(/\.jsonl$/, "");
|
|
44840
|
-
const filePath =
|
|
45716
|
+
const filePath = path13.join(baseDir, entry);
|
|
44841
45717
|
try {
|
|
44842
45718
|
const events = await readSession(filePath);
|
|
44843
45719
|
let firstTs = 0;
|
|
@@ -44884,7 +45760,7 @@ ${lines.join("\n")}`
|
|
|
44884
45760
|
return { message: `[${kind}] handled` };
|
|
44885
45761
|
}
|
|
44886
45762
|
async function loadSessionEvents(id) {
|
|
44887
|
-
const filePath =
|
|
45763
|
+
const filePath = path13.join(getSessionBaseDir(), `${id}.jsonl`);
|
|
44888
45764
|
return readSession(filePath);
|
|
44889
45765
|
}
|
|
44890
45766
|
|
|
@@ -45176,15 +46052,15 @@ import { useState as useState6, useRef as useRef4, useCallback as useCallback2 }
|
|
|
45176
46052
|
|
|
45177
46053
|
// src/cli/metrics.ts
|
|
45178
46054
|
import { promises as fs10, existsSync as existsSync10, statSync as statSync2, renameSync, appendFileSync as appendFileSync2, mkdirSync as mkdirSync5 } from "node:fs";
|
|
45179
|
-
import
|
|
46055
|
+
import path14 from "node:path";
|
|
45180
46056
|
import os5 from "node:os";
|
|
45181
46057
|
var METRICS_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
45182
46058
|
var MetricsLogger = class {
|
|
45183
46059
|
file;
|
|
45184
46060
|
writeQueue = Promise.resolve();
|
|
45185
46061
|
constructor(file2) {
|
|
45186
|
-
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ??
|
|
45187
|
-
mkdirSync5(
|
|
46062
|
+
this.file = file2 ?? process.env.ANATHEMA_METRICS_FILE ?? path14.join(os5.homedir(), ".tmp", "zelari-code", "metrics.jsonl");
|
|
46063
|
+
mkdirSync5(path14.dirname(this.file), { recursive: true });
|
|
45188
46064
|
}
|
|
45189
46065
|
/** Fire-and-forget record append. */
|
|
45190
46066
|
record(rec) {
|
|
@@ -47315,6 +48191,8 @@ function handleSlashCommand(text, availableSkills) {
|
|
|
47315
48191
|
/index [status] \u2014 build the semantic code index for semantic_search
|
|
47316
48192
|
/mode [kraken|council|zelari] \u2014 switch dispatch mode (same as shift+tab; agent=alias kraken)
|
|
47317
48193
|
/kraken [sessionId] \u2014 show Kraken tentacle radio (last spawns)
|
|
48194
|
+
/trust [path] \u2014 trust a folder so project MCP + project hooks load
|
|
48195
|
+
/trust remove [path] \u2014 revoke folder trust
|
|
47318
48196
|
/help \u2014 show this help
|
|
47319
48197
|
/exit \u2014 exit the CLI
|
|
47320
48198
|
|
|
@@ -47803,6 +48681,23 @@ ${formatSkillList(availableSkills)}`
|
|
|
47803
48681
|
message: "Usage: /state status | /state commit [label] | /state show [id] | /state restore [id] [--no-tree]\nDurable verified accumulation under .zelari/state/ (not memory RAG)."
|
|
47804
48682
|
};
|
|
47805
48683
|
}
|
|
48684
|
+
case "trust": {
|
|
48685
|
+
const first = args[0];
|
|
48686
|
+
if (first === "remove" || first === "untrust") {
|
|
48687
|
+
return {
|
|
48688
|
+
handled: true,
|
|
48689
|
+
kind: "trust_remove",
|
|
48690
|
+
trustPath: args[1],
|
|
48691
|
+
message: "Usage: /trust remove [path]"
|
|
48692
|
+
};
|
|
48693
|
+
}
|
|
48694
|
+
return {
|
|
48695
|
+
handled: true,
|
|
48696
|
+
kind: first ? "trust_add" : "trust_status",
|
|
48697
|
+
trustPath: first && first !== "." ? first : process.cwd(),
|
|
48698
|
+
message: first ? "Usage: /trust [path]" : "Usage: /trust [path] | /trust remove [path]"
|
|
48699
|
+
};
|
|
48700
|
+
}
|
|
47806
48701
|
case "cache": {
|
|
47807
48702
|
const sub = (args[0] ?? "stats").toLowerCase();
|
|
47808
48703
|
if (sub === "stats" || sub === "") {
|
|
@@ -47890,7 +48785,7 @@ ${formatSkillList(availableSkills)}`
|
|
|
47890
48785
|
// src/cli/gitOps.ts
|
|
47891
48786
|
import { execFile as execFile4 } from "node:child_process";
|
|
47892
48787
|
import { promisify as promisify3 } from "node:util";
|
|
47893
|
-
import
|
|
48788
|
+
import path35 from "node:path";
|
|
47894
48789
|
var execFileAsync3 = promisify3(execFile4);
|
|
47895
48790
|
async function git3(cwd, args) {
|
|
47896
48791
|
try {
|
|
@@ -47936,7 +48831,7 @@ async function undoWorkingChanges(opts = {}) {
|
|
|
47936
48831
|
};
|
|
47937
48832
|
}
|
|
47938
48833
|
function defaultProjectRoot() {
|
|
47939
|
-
return
|
|
48834
|
+
return path35.resolve(__dirname, "..", "..", "..");
|
|
47940
48835
|
}
|
|
47941
48836
|
|
|
47942
48837
|
// src/cli/slashHandlers/git.ts
|
|
@@ -48213,6 +49108,45 @@ function handleCacheStats(ctx) {
|
|
|
48213
49108
|
);
|
|
48214
49109
|
}
|
|
48215
49110
|
|
|
49111
|
+
// src/cli/slashHandlers/trust.ts
|
|
49112
|
+
init_folderTrust();
|
|
49113
|
+
function resolvePath(raw) {
|
|
49114
|
+
if (!raw || raw === "." || raw === "./") return process.cwd();
|
|
49115
|
+
return raw;
|
|
49116
|
+
}
|
|
49117
|
+
function handleTrustStatus(ctx, target) {
|
|
49118
|
+
const trusted = isFolderTrusted(target);
|
|
49119
|
+
const all = listTrustedFolders();
|
|
49120
|
+
const lines = [
|
|
49121
|
+
`[trust] ${target}`,
|
|
49122
|
+
` status: ${trusted ? "trusted \u2714" : "NOT trusted \u2716"}`,
|
|
49123
|
+
` store: ${getTrustStorePath()}`,
|
|
49124
|
+
` folders: ${all.length === 0 ? "(none)" : ""}`,
|
|
49125
|
+
...all.map((f) => ` - ${f.path} (${f.trustedAt})`),
|
|
49126
|
+
"",
|
|
49127
|
+
trusted ? " Project MCP + project hooks are enabled for this folder." : " Project MCP (.zelari/mcp.json) and project hooks (.zelari/hooks/) are IGNORED until you run /trust ."
|
|
49128
|
+
];
|
|
49129
|
+
appendSystem(ctx.setMessages, lines.join("\n"));
|
|
49130
|
+
}
|
|
49131
|
+
function handleTrust(ctx, rawPath) {
|
|
49132
|
+
const target = resolvePath(rawPath);
|
|
49133
|
+
const res = trustFolder(target);
|
|
49134
|
+
appendSystem(
|
|
49135
|
+
ctx.setMessages,
|
|
49136
|
+
`[trust] trusted ${res.path}
|
|
49137
|
+
Project MCP + project hooks will load on the next session/turn (run /trust to confirm).`
|
|
49138
|
+
);
|
|
49139
|
+
}
|
|
49140
|
+
function handleUntrust(ctx, rawPath) {
|
|
49141
|
+
const target = resolvePath(rawPath);
|
|
49142
|
+
const res = untrustFolder(target);
|
|
49143
|
+
appendSystem(
|
|
49144
|
+
ctx.setMessages,
|
|
49145
|
+
res.removed ? `[trust] removed trust for ${target}
|
|
49146
|
+
Project MCP + project hooks are now ignored for this folder.` : `[trust] ${target} was not trusted (nothing to remove).`
|
|
49147
|
+
);
|
|
49148
|
+
}
|
|
49149
|
+
|
|
48216
49150
|
// src/cli/slashHandlers/semantic.ts
|
|
48217
49151
|
init_semantic();
|
|
48218
49152
|
init_provider();
|
|
@@ -48338,7 +49272,7 @@ import { promises as fs22 } from "node:fs";
|
|
|
48338
49272
|
init_zod();
|
|
48339
49273
|
init_taskTool();
|
|
48340
49274
|
import { promises as fs21 } from "node:fs";
|
|
48341
|
-
import
|
|
49275
|
+
import path39 from "node:path";
|
|
48342
49276
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
48343
49277
|
var CsvFanoutArgsSchema = external_exports.object({
|
|
48344
49278
|
csv_path: external_exports.string().min(1),
|
|
@@ -48432,8 +49366,8 @@ function resolveMaxConcurrency(env = process.env) {
|
|
|
48432
49366
|
}
|
|
48433
49367
|
async function runCsvFanout(args, deps, opts) {
|
|
48434
49368
|
const start = Date.now();
|
|
48435
|
-
const absCsv =
|
|
48436
|
-
const absOut =
|
|
49369
|
+
const absCsv = path39.isAbsolute(args.csv_path) ? args.csv_path : path39.join(opts.parentCwd, args.csv_path);
|
|
49370
|
+
const absOut = path39.isAbsolute(args.output_csv_path) ? args.output_csv_path : path39.join(opts.parentCwd, args.output_csv_path);
|
|
48437
49371
|
const { headers, rows } = await readCsv(absCsv);
|
|
48438
49372
|
if (headers.length === 0) {
|
|
48439
49373
|
throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
|
|
@@ -48489,7 +49423,7 @@ async function runCsvFanout(args, deps, opts) {
|
|
|
48489
49423
|
errored += 1;
|
|
48490
49424
|
errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
|
|
48491
49425
|
}
|
|
48492
|
-
await fs21.mkdir(
|
|
49426
|
+
await fs21.mkdir(path39.dirname(absOut), { recursive: true });
|
|
48493
49427
|
await queueWrite(serializeCsv(outHeaders, outputRecords));
|
|
48494
49428
|
}
|
|
48495
49429
|
}
|
|
@@ -48683,7 +49617,7 @@ function splitArgs(s) {
|
|
|
48683
49617
|
|
|
48684
49618
|
// src/cli/slashHandlers/krakenWorkbench.ts
|
|
48685
49619
|
import { promises as fs23 } from "node:fs";
|
|
48686
|
-
import
|
|
49620
|
+
import path40 from "node:path";
|
|
48687
49621
|
|
|
48688
49622
|
// src/cli/kraken/workbenchView.ts
|
|
48689
49623
|
var EMPTY = {
|
|
@@ -48800,14 +49734,14 @@ function formatWorkbenchForTerminal(p3) {
|
|
|
48800
49734
|
|
|
48801
49735
|
// src/cli/slashHandlers/krakenWorkbench.ts
|
|
48802
49736
|
async function handleKrakenWorkbench(ctx) {
|
|
48803
|
-
const dir =
|
|
49737
|
+
const dir = path40.join(ctx.cwd, ".zelari", "radio");
|
|
48804
49738
|
let latest = null;
|
|
48805
49739
|
let latestMtime = 0;
|
|
48806
49740
|
try {
|
|
48807
49741
|
const files = await fs23.readdir(dir);
|
|
48808
49742
|
for (const f of files) {
|
|
48809
49743
|
if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
|
|
48810
|
-
const full =
|
|
49744
|
+
const full = path40.join(dir, f);
|
|
48811
49745
|
const stat = await fs23.stat(full);
|
|
48812
49746
|
if (stat.mtimeMs > latestMtime) {
|
|
48813
49747
|
latestMtime = stat.mtimeMs;
|
|
@@ -48824,10 +49758,10 @@ async function handleKrakenWorkbench(ctx) {
|
|
|
48824
49758
|
const parsed = parseWorkbench(content);
|
|
48825
49759
|
const rendered = formatWorkbenchForTerminal(parsed);
|
|
48826
49760
|
if (!rendered.trim()) {
|
|
48827
|
-
appendSystem(ctx.setMessages, `[kraken workbench] ${
|
|
49761
|
+
appendSystem(ctx.setMessages, `[kraken workbench] ${path40.basename(latest)}: (no nodes / no events yet)`);
|
|
48828
49762
|
return;
|
|
48829
49763
|
}
|
|
48830
|
-
appendSystem(ctx.setMessages, `[kraken workbench] ${
|
|
49764
|
+
appendSystem(ctx.setMessages, `[kraken workbench] ${path40.basename(latest)}:
|
|
48831
49765
|
${rendered}`);
|
|
48832
49766
|
}
|
|
48833
49767
|
|
|
@@ -48979,8 +49913,8 @@ init_registry3();
|
|
|
48979
49913
|
// src/cli/plugins/installer.ts
|
|
48980
49914
|
init_cmdline();
|
|
48981
49915
|
init_updater();
|
|
48982
|
-
import { spawn as
|
|
48983
|
-
async function installPlugin(spec, cwd, executor =
|
|
49916
|
+
import { spawn as spawn12 } from "node:child_process";
|
|
49917
|
+
async function installPlugin(spec, cwd, executor = spawn12) {
|
|
48984
49918
|
const scopeFlag = spec.installScope === "global" ? "-g" : "-D";
|
|
48985
49919
|
const args = ["install", scopeFlag, spec.npmPackage];
|
|
48986
49920
|
let result = await runNpm2(executor, args, cwd, "shim");
|
|
@@ -49129,15 +50063,15 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
|
|
|
49129
50063
|
|
|
49130
50064
|
// src/cli/slashHandlers/promoteMember.ts
|
|
49131
50065
|
import { promises as fs24 } from "node:fs";
|
|
49132
|
-
import
|
|
50066
|
+
import path43 from "node:path";
|
|
49133
50067
|
import os10 from "node:os";
|
|
49134
50068
|
async function handlePromoteMember(ctx, memberId) {
|
|
49135
50069
|
try {
|
|
49136
50070
|
const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
49137
50071
|
const { skill, markdown } = promoteMember2(memberId);
|
|
49138
|
-
const skillDir = process.env.ANATHEMA_SKILL_DIR ??
|
|
50072
|
+
const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path43.join(os10.homedir(), ".tmp", "zelari-code", "skills");
|
|
49139
50073
|
await fs24.mkdir(skillDir, { recursive: true });
|
|
49140
|
-
const filePath =
|
|
50074
|
+
const filePath = path43.join(skillDir, `${skill.id}.md`);
|
|
49141
50075
|
await fs24.writeFile(filePath, markdown, "utf8");
|
|
49142
50076
|
appendSystem(
|
|
49143
50077
|
ctx.setMessages,
|
|
@@ -49154,33 +50088,33 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
49154
50088
|
}
|
|
49155
50089
|
|
|
49156
50090
|
// src/cli/branchManager.ts
|
|
49157
|
-
import { promises as fs25, existsSync as
|
|
49158
|
-
import
|
|
50091
|
+
import { promises as fs25, existsSync as existsSync39, readFileSync as readFileSync32, writeFileSync as writeFileSync20, mkdirSync as mkdirSync17, statSync as statSync4, rmSync as rmSync3 } from "node:fs";
|
|
50092
|
+
import path44 from "node:path";
|
|
49159
50093
|
import os11 from "node:os";
|
|
49160
50094
|
var META_FILENAME = "meta.json";
|
|
49161
50095
|
var SESSIONS_SUBDIR = "sessions";
|
|
49162
50096
|
function getBranchesBaseDir() {
|
|
49163
|
-
return process.env.ANATHEMA_BRANCHES_DIR ??
|
|
50097
|
+
return process.env.ANATHEMA_BRANCHES_DIR ?? path44.join(os11.homedir(), ".tmp", "zelari-code", "branches");
|
|
49164
50098
|
}
|
|
49165
50099
|
function getSessionsBaseDir() {
|
|
49166
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
50100
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path44.join(os11.homedir(), ".tmp", "zelari-code", "sessions");
|
|
49167
50101
|
}
|
|
49168
50102
|
function branchPathFor(name, baseDir) {
|
|
49169
|
-
return
|
|
50103
|
+
return path44.join(baseDir, name);
|
|
49170
50104
|
}
|
|
49171
50105
|
function metaPathFor(name, baseDir) {
|
|
49172
|
-
return
|
|
50106
|
+
return path44.join(baseDir, name, META_FILENAME);
|
|
49173
50107
|
}
|
|
49174
50108
|
function sessionsPathFor(name, baseDir) {
|
|
49175
|
-
return
|
|
50109
|
+
return path44.join(baseDir, name, SESSIONS_SUBDIR);
|
|
49176
50110
|
}
|
|
49177
50111
|
function readBranchMeta(name, baseDir) {
|
|
49178
50112
|
const metaPath = metaPathFor(name, baseDir);
|
|
49179
|
-
if (!
|
|
50113
|
+
if (!existsSync39(metaPath)) {
|
|
49180
50114
|
throw new BranchNotFoundError(`Branch "${name}" not found`);
|
|
49181
50115
|
}
|
|
49182
50116
|
try {
|
|
49183
|
-
const raw =
|
|
50117
|
+
const raw = readFileSync32(metaPath, "utf-8");
|
|
49184
50118
|
const parsed = JSON.parse(raw);
|
|
49185
50119
|
if (!parsed || typeof parsed !== "object" || typeof parsed.name !== "string" || typeof parsed.createdAt !== "number" || typeof parsed.fromSessionId !== "string") {
|
|
49186
50120
|
throw new BranchCorruptError(`Branch "${name}" meta.json is malformed`);
|
|
@@ -49197,8 +50131,8 @@ function readBranchMeta(name, baseDir) {
|
|
|
49197
50131
|
}
|
|
49198
50132
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
49199
50133
|
const metaPath = metaPathFor(name, baseDir);
|
|
49200
|
-
|
|
49201
|
-
|
|
50134
|
+
mkdirSync17(path44.dirname(metaPath), { recursive: true });
|
|
50135
|
+
writeFileSync20(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
49202
50136
|
}
|
|
49203
50137
|
async function countSessions(name, baseDir) {
|
|
49204
50138
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
@@ -49236,7 +50170,7 @@ var SessionNotFoundError = class extends Error {
|
|
|
49236
50170
|
};
|
|
49237
50171
|
function branchExists(name, baseDir = getBranchesBaseDir()) {
|
|
49238
50172
|
const bp = branchPathFor(name, baseDir);
|
|
49239
|
-
return
|
|
50173
|
+
return existsSync39(bp) && existsSync39(metaPathFor(name, baseDir));
|
|
49240
50174
|
}
|
|
49241
50175
|
async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(), sessionsBaseDir = getSessionsBaseDir()) {
|
|
49242
50176
|
if (!name || name.trim().length === 0) {
|
|
@@ -49248,14 +50182,14 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
49248
50182
|
if (branchExists(name, baseDir)) {
|
|
49249
50183
|
throw new BranchAlreadyExistsError(name);
|
|
49250
50184
|
}
|
|
49251
|
-
const sourcePath =
|
|
49252
|
-
if (!
|
|
50185
|
+
const sourcePath = path44.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
50186
|
+
if (!existsSync39(sourcePath)) {
|
|
49253
50187
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
49254
50188
|
}
|
|
49255
50189
|
const branchPath = branchPathFor(name, baseDir);
|
|
49256
50190
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
49257
|
-
|
|
49258
|
-
const destPath =
|
|
50191
|
+
mkdirSync17(branchSessionsPath, { recursive: true });
|
|
50192
|
+
const destPath = path44.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
49259
50193
|
await fs25.copyFile(sourcePath, destPath);
|
|
49260
50194
|
const meta3 = {
|
|
49261
50195
|
name,
|
|
@@ -49282,7 +50216,7 @@ async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
|
49282
50216
|
const results = [];
|
|
49283
50217
|
for (const entry of entries) {
|
|
49284
50218
|
const metaPath = metaPathFor(entry, baseDir);
|
|
49285
|
-
if (!
|
|
50219
|
+
if (!existsSync39(metaPath)) continue;
|
|
49286
50220
|
try {
|
|
49287
50221
|
const meta3 = readBranchMeta(entry, baseDir);
|
|
49288
50222
|
const sessionCount = await countSessions(entry, baseDir);
|
|
@@ -49356,14 +50290,14 @@ async function handleBranchCheckout(ctx, branchName) {
|
|
|
49356
50290
|
|
|
49357
50291
|
// src/cli/slashHandlers/workspace.ts
|
|
49358
50292
|
import { promises as fs26 } from "node:fs";
|
|
49359
|
-
import
|
|
50293
|
+
import path45 from "node:path";
|
|
49360
50294
|
async function handleWorkspaceShow(ctx, what) {
|
|
49361
50295
|
try {
|
|
49362
|
-
const zelari =
|
|
50296
|
+
const zelari = path45.join(process.cwd(), ".zelari");
|
|
49363
50297
|
let content;
|
|
49364
50298
|
switch (what) {
|
|
49365
50299
|
case "plan": {
|
|
49366
|
-
const planPath =
|
|
50300
|
+
const planPath = path45.join(zelari, "plan.md");
|
|
49367
50301
|
try {
|
|
49368
50302
|
content = await fs26.readFile(planPath, "utf-8");
|
|
49369
50303
|
} catch {
|
|
@@ -49372,7 +50306,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
49372
50306
|
break;
|
|
49373
50307
|
}
|
|
49374
50308
|
case "decisions": {
|
|
49375
|
-
const decisionsDir =
|
|
50309
|
+
const decisionsDir = path45.join(zelari, "decisions");
|
|
49376
50310
|
try {
|
|
49377
50311
|
const files = (await fs26.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
49378
50312
|
if (files.length === 0) {
|
|
@@ -49382,7 +50316,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
49382
50316
|
`];
|
|
49383
50317
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
49384
50318
|
for (const f of files) {
|
|
49385
|
-
const raw = await fs26.readFile(
|
|
50319
|
+
const raw = await fs26.readFile(path45.join(decisionsDir, f), "utf-8");
|
|
49386
50320
|
const { meta: meta3, body } = parseFrontmatter2(raw);
|
|
49387
50321
|
const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
|
|
49388
50322
|
lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
|
|
@@ -49395,7 +50329,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
49395
50329
|
break;
|
|
49396
50330
|
}
|
|
49397
50331
|
case "risks": {
|
|
49398
|
-
const risksPath =
|
|
50332
|
+
const risksPath = path45.join(zelari, "risks.md");
|
|
49399
50333
|
try {
|
|
49400
50334
|
content = await fs26.readFile(risksPath, "utf-8");
|
|
49401
50335
|
} catch {
|
|
@@ -49404,7 +50338,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
49404
50338
|
break;
|
|
49405
50339
|
}
|
|
49406
50340
|
case "agents": {
|
|
49407
|
-
const agentsPath =
|
|
50341
|
+
const agentsPath = path45.join(process.cwd(), "AGENTS.MD");
|
|
49408
50342
|
try {
|
|
49409
50343
|
content = await fs26.readFile(agentsPath, "utf-8");
|
|
49410
50344
|
} catch {
|
|
@@ -49413,7 +50347,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
49413
50347
|
break;
|
|
49414
50348
|
}
|
|
49415
50349
|
case "docs": {
|
|
49416
|
-
const docsDir =
|
|
50350
|
+
const docsDir = path45.join(zelari, "docs");
|
|
49417
50351
|
try {
|
|
49418
50352
|
const files = (await fs26.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
49419
50353
|
content = files.length ? `# Docs (${files.length})
|
|
@@ -49455,7 +50389,7 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
49455
50389
|
return;
|
|
49456
50390
|
}
|
|
49457
50391
|
try {
|
|
49458
|
-
const target =
|
|
50392
|
+
const target = path45.join(process.cwd(), ".zelari");
|
|
49459
50393
|
await fs26.rm(target, { recursive: true, force: true });
|
|
49460
50394
|
appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
|
|
49461
50395
|
} catch (err) {
|
|
@@ -49815,11 +50749,11 @@ function handleModelsRefresh(ctx) {
|
|
|
49815
50749
|
}
|
|
49816
50750
|
|
|
49817
50751
|
// src/cli/slashHandlers/skills.ts
|
|
49818
|
-
import
|
|
50752
|
+
import path46 from "node:path";
|
|
49819
50753
|
import os12 from "node:os";
|
|
49820
50754
|
|
|
49821
50755
|
// src/cli/skillHistory.ts
|
|
49822
|
-
import { promises as fs27, existsSync as
|
|
50756
|
+
import { promises as fs27, existsSync as existsSync40, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync4, mkdirSync as mkdirSync18 } from "node:fs";
|
|
49823
50757
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
49824
50758
|
async function readSkillHistory(file2) {
|
|
49825
50759
|
let raw = "";
|
|
@@ -49941,7 +50875,7 @@ function handleSkillPicker(ctx, skills, openPicker, fallbackMessage) {
|
|
|
49941
50875
|
});
|
|
49942
50876
|
}
|
|
49943
50877
|
async function handleSkillStats(ctx, skillId) {
|
|
49944
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
50878
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path46.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
49945
50879
|
try {
|
|
49946
50880
|
const records = await readSkillHistory(historyFile);
|
|
49947
50881
|
const stats = getSkillStats(records, skillId);
|
|
@@ -49957,7 +50891,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
|
|
|
49957
50891
|
appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
|
|
49958
50892
|
return;
|
|
49959
50893
|
}
|
|
49960
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
50894
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path46.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
49961
50895
|
try {
|
|
49962
50896
|
const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
|
|
49963
50897
|
appendSystem(ctx.setMessages, formatted);
|
|
@@ -50347,6 +51281,21 @@ function useSlashDispatch(params) {
|
|
|
50347
51281
|
setInput("");
|
|
50348
51282
|
return;
|
|
50349
51283
|
}
|
|
51284
|
+
if (result.kind === "trust_status") {
|
|
51285
|
+
handleTrustStatus({ setMessages }, result.trustPath ?? process.cwd());
|
|
51286
|
+
setInput("");
|
|
51287
|
+
return;
|
|
51288
|
+
}
|
|
51289
|
+
if (result.kind === "trust_add") {
|
|
51290
|
+
handleTrust({ setMessages }, result.trustPath ?? process.cwd());
|
|
51291
|
+
setInput("");
|
|
51292
|
+
return;
|
|
51293
|
+
}
|
|
51294
|
+
if (result.kind === "trust_remove") {
|
|
51295
|
+
handleUntrust({ setMessages }, result.trustPath ?? process.cwd());
|
|
51296
|
+
setInput("");
|
|
51297
|
+
return;
|
|
51298
|
+
}
|
|
50350
51299
|
if (result.kind === "index_build") {
|
|
50351
51300
|
await handleIndexBuild({ ...baseCtx, cwd: process.cwd() });
|
|
50352
51301
|
setInput("");
|
|
@@ -51114,9 +52063,9 @@ function ContinueKey({ onContinue }) {
|
|
|
51114
52063
|
init_providerConfig();
|
|
51115
52064
|
|
|
51116
52065
|
// src/cli/wizard/firstRun.ts
|
|
51117
|
-
import { existsSync as
|
|
52066
|
+
import { existsSync as existsSync42 } from "node:fs";
|
|
51118
52067
|
function shouldRunWizard(input) {
|
|
51119
|
-
const exists = input.exists ??
|
|
52068
|
+
const exists = input.exists ?? existsSync42;
|
|
51120
52069
|
if (input.hasResetConfigFlag) {
|
|
51121
52070
|
return { shouldRun: true, reason: "--reset-config flag forced wizard" };
|
|
51122
52071
|
}
|
|
@@ -51401,7 +52350,7 @@ init_keyStore();
|
|
|
51401
52350
|
init_providerConfig();
|
|
51402
52351
|
init_openai_compatible();
|
|
51403
52352
|
init_phase();
|
|
51404
|
-
import { readFileSync as
|
|
52353
|
+
import { readFileSync as readFileSync34 } from "node:fs";
|
|
51405
52354
|
function parseHeadlessFlags(argv) {
|
|
51406
52355
|
if (!argv.includes("--headless")) {
|
|
51407
52356
|
return { options: null };
|
|
@@ -51473,7 +52422,7 @@ function parseHeadlessFlags(argv) {
|
|
|
51473
52422
|
let raw = null;
|
|
51474
52423
|
if (arg === "--history-file") {
|
|
51475
52424
|
try {
|
|
51476
|
-
raw =
|
|
52425
|
+
raw = readFileSync34(next, "utf-8");
|
|
51477
52426
|
} catch {
|
|
51478
52427
|
raw = null;
|
|
51479
52428
|
}
|
|
@@ -51619,7 +52568,7 @@ function createStreamScrubber() {
|
|
|
51619
52568
|
// src/cli/runHeadless.ts
|
|
51620
52569
|
init_taskTool();
|
|
51621
52570
|
import { promises as fs29 } from "node:fs";
|
|
51622
|
-
import
|
|
52571
|
+
import path48 from "node:path";
|
|
51623
52572
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
51624
52573
|
async function runHeadless(opts) {
|
|
51625
52574
|
resetTaskSpawnCount();
|
|
@@ -51767,7 +52716,7 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
51767
52716
|
try {
|
|
51768
52717
|
let preflightGraph;
|
|
51769
52718
|
if (opts.runPlan && opts.runPlan.trim() !== "") {
|
|
51770
|
-
const planPath =
|
|
52719
|
+
const planPath = path48.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
|
|
51771
52720
|
log(`loading pre-flight plan: ${planPath}`);
|
|
51772
52721
|
let raw;
|
|
51773
52722
|
try {
|
|
@@ -51807,8 +52756,8 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
51807
52756
|
log(formatKrakenGraphAscii2(graph));
|
|
51808
52757
|
if (opts.planOnly) {
|
|
51809
52758
|
const planId = randomUUID6();
|
|
51810
|
-
const planDir =
|
|
51811
|
-
const planPath =
|
|
52759
|
+
const planDir = path48.join(cwd, ".zelari", "radio");
|
|
52760
|
+
const planPath = path48.join(planDir, `plan-${planId}.json`);
|
|
51812
52761
|
await fs29.mkdir(planDir, { recursive: true });
|
|
51813
52762
|
await fs29.writeFile(planPath, JSON.stringify(graph, null, 2), "utf8");
|
|
51814
52763
|
log(`plan-only: wrote ${planPath} (${graph.nodes.size} nodes)`);
|
|
@@ -52796,263 +53745,13 @@ init_skillsMd();
|
|
|
52796
53745
|
init_skills2();
|
|
52797
53746
|
init_updater();
|
|
52798
53747
|
init_mcpConfigIo();
|
|
52799
|
-
|
|
52800
|
-
// src/cli/skillConfigIo.ts
|
|
52801
|
-
init_skills2();
|
|
52802
|
-
init_skillsMd();
|
|
52803
|
-
import {
|
|
52804
|
-
existsSync as existsSync42,
|
|
52805
|
-
mkdirSync as mkdirSync18,
|
|
52806
|
-
readdirSync as readdirSync7,
|
|
52807
|
-
readFileSync as readFileSync33,
|
|
52808
|
-
rmSync as rmSync4,
|
|
52809
|
-
writeFileSync as writeFileSync20
|
|
52810
|
-
} from "node:fs";
|
|
52811
|
-
import { dirname as dirname9, join as join34 } from "node:path";
|
|
52812
|
-
import { homedir as homedir10 } from "node:os";
|
|
52813
|
-
|
|
52814
|
-
// src/cli/skillCategories.ts
|
|
52815
|
-
var CODING_CATEGORIES_LIST = [
|
|
52816
|
-
"plan",
|
|
52817
|
-
"refactor",
|
|
52818
|
-
"debug",
|
|
52819
|
-
"review",
|
|
52820
|
-
"test",
|
|
52821
|
-
"docs",
|
|
52822
|
-
"ops",
|
|
52823
|
-
"git",
|
|
52824
|
-
"db",
|
|
52825
|
-
"maint"
|
|
52826
|
-
];
|
|
52827
|
-
var CODING_CATEGORIES2 = new Set(CODING_CATEGORIES_LIST);
|
|
52828
|
-
|
|
52829
|
-
// src/cli/skillConfigIo.ts
|
|
52830
|
-
var NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
52831
|
-
var BUILTIN_SKILL_MODULES = [
|
|
52832
|
-
"@zelari/core/skills/builtin/debugging",
|
|
52833
|
-
"@zelari/core/skills/builtin/docs",
|
|
52834
|
-
"@zelari/core/skills/builtin/git-ops",
|
|
52835
|
-
"@zelari/core/skills/builtin/planning",
|
|
52836
|
-
"@zelari/core/skills/builtin/refactoring",
|
|
52837
|
-
"@zelari/core/skills/builtin/review",
|
|
52838
|
-
"@zelari/core/skills/builtin/testing",
|
|
52839
|
-
"@zelari/core/skills/builtin/schema-loop",
|
|
52840
|
-
"@zelari/core/skills/builtin/computer-use-cua",
|
|
52841
|
-
"@zelari/core/skills/builtin/qwen-mm-plugins"
|
|
52842
|
-
];
|
|
52843
|
-
var builtinsLoaded = false;
|
|
52844
|
-
function ensureBuiltinSkillsLoadedSync() {
|
|
52845
|
-
if (builtinsLoaded) return;
|
|
52846
|
-
for (const spec of BUILTIN_SKILL_MODULES) {
|
|
52847
|
-
try {
|
|
52848
|
-
require?.(spec);
|
|
52849
|
-
} catch {
|
|
52850
|
-
}
|
|
52851
|
-
}
|
|
52852
|
-
}
|
|
52853
|
-
function getUserSkillsDir() {
|
|
52854
|
-
return join34(homedir10(), ".zelari-code", "skills");
|
|
52855
|
-
}
|
|
52856
|
-
function getProjectSkillsDir(projectRoot) {
|
|
52857
|
-
return join34(projectRoot, ".zelari", "skills");
|
|
52858
|
-
}
|
|
52859
|
-
function skillFilePath(dir, name) {
|
|
52860
|
-
return join34(dir, name, "SKILL.md");
|
|
52861
|
-
}
|
|
52862
|
-
function classifyScope(skillPath, projectRoot) {
|
|
52863
|
-
const userDir = getUserSkillsDir().replace(/\\/g, "/");
|
|
52864
|
-
const norm = skillPath.replace(/\\/g, "/");
|
|
52865
|
-
if (norm.startsWith(userDir + "/") || norm === userDir) {
|
|
52866
|
-
return { scope: "user", writable: true };
|
|
52867
|
-
}
|
|
52868
|
-
if (projectRoot) {
|
|
52869
|
-
const projDir = getProjectSkillsDir(projectRoot).replace(/\\/g, "/");
|
|
52870
|
-
if (norm.startsWith(projDir + "/") || norm === projDir) {
|
|
52871
|
-
return { scope: "project", writable: true };
|
|
52872
|
-
}
|
|
52873
|
-
}
|
|
52874
|
-
return { scope: "compat", writable: false };
|
|
52875
|
-
}
|
|
52876
|
-
function entryFromParsed(parsed, projectRoot) {
|
|
52877
|
-
const { scope, writable } = classifyScope(parsed.sourcePath, projectRoot);
|
|
52878
|
-
return {
|
|
52879
|
-
id: parsed.name,
|
|
52880
|
-
name: parsed.name,
|
|
52881
|
-
description: parsed.description,
|
|
52882
|
-
category: parsed.category,
|
|
52883
|
-
estimatedCost: parsed.estimatedCost,
|
|
52884
|
-
requiredTools: parsed.requiredTools,
|
|
52885
|
-
scope,
|
|
52886
|
-
path: parsed.sourcePath,
|
|
52887
|
-
body: parsed.body,
|
|
52888
|
-
builtin: false,
|
|
52889
|
-
writable
|
|
52890
|
-
};
|
|
52891
|
-
}
|
|
52892
|
-
function entryFromBuiltin(skill) {
|
|
52893
|
-
return {
|
|
52894
|
-
id: skill.id,
|
|
52895
|
-
name: skill.name || skill.id,
|
|
52896
|
-
description: skill.description || "",
|
|
52897
|
-
category: skill.category,
|
|
52898
|
-
estimatedCost: skill.estimatedCost,
|
|
52899
|
-
requiredTools: skill.requiredTools,
|
|
52900
|
-
scope: "builtin",
|
|
52901
|
-
path: null,
|
|
52902
|
-
// Expose body so Desktop skill picker can expand like `/skill <id>`.
|
|
52903
|
-
body: skill.systemPromptFragment || void 0,
|
|
52904
|
-
builtin: true,
|
|
52905
|
-
writable: false
|
|
52906
|
-
};
|
|
52907
|
-
}
|
|
52908
|
-
function scanSkillsDir(dir, projectRoot, seen, out) {
|
|
52909
|
-
if (!existsSync42(dir)) return;
|
|
52910
|
-
let entries;
|
|
52911
|
-
try {
|
|
52912
|
-
entries = readdirSync7(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
52913
|
-
} catch {
|
|
52914
|
-
return;
|
|
52915
|
-
}
|
|
52916
|
-
for (const entry of entries) {
|
|
52917
|
-
const skillPath = skillFilePath(dir, entry);
|
|
52918
|
-
if (!existsSync42(skillPath)) continue;
|
|
52919
|
-
try {
|
|
52920
|
-
const parsed = parseSkillMd(readFileSync33(skillPath, "utf8"), skillPath);
|
|
52921
|
-
if (!parsed) continue;
|
|
52922
|
-
if (seen.has(parsed.name)) continue;
|
|
52923
|
-
seen.add(parsed.name);
|
|
52924
|
-
out.push(entryFromParsed(parsed, projectRoot));
|
|
52925
|
-
} catch {
|
|
52926
|
-
}
|
|
52927
|
-
}
|
|
52928
|
-
}
|
|
52929
|
-
function listSkillsSnapshot(projectRoot) {
|
|
52930
|
-
const root = projectRoot && projectRoot.trim() ? projectRoot.trim() : null;
|
|
52931
|
-
const userSkillsDir = getUserSkillsDir();
|
|
52932
|
-
const projectSkillsDir = root ? getProjectSkillsDir(root) : null;
|
|
52933
|
-
const skills = [];
|
|
52934
|
-
const seen = /* @__PURE__ */ new Set();
|
|
52935
|
-
if (root) {
|
|
52936
|
-
scanSkillsDir(join34(root, ".zelari", "skills"), root, seen, skills);
|
|
52937
|
-
scanSkillsDir(join34(root, ".claude", "skills"), root, seen, skills);
|
|
52938
|
-
scanSkillsDir(join34(root, ".opencode", "skills"), root, seen, skills);
|
|
52939
|
-
}
|
|
52940
|
-
scanSkillsDir(userSkillsDir, root, seen, skills);
|
|
52941
|
-
for (const s of listCodingSkills()) {
|
|
52942
|
-
if (seen.has(s.id)) continue;
|
|
52943
|
-
seen.add(s.id);
|
|
52944
|
-
if (s.builtin) {
|
|
52945
|
-
skills.push(entryFromBuiltin(s));
|
|
52946
|
-
}
|
|
52947
|
-
}
|
|
52948
|
-
skills.sort((a, b) => {
|
|
52949
|
-
const order = (s) => s === "project" ? 0 : s === "user" ? 1 : s === "compat" ? 2 : 3;
|
|
52950
|
-
const d = order(a.scope) - order(b.scope);
|
|
52951
|
-
if (d !== 0) return d;
|
|
52952
|
-
return a.id.localeCompare(b.id);
|
|
52953
|
-
});
|
|
52954
|
-
return { userSkillsDir, projectSkillsDir, skills };
|
|
52955
|
-
}
|
|
52956
|
-
function serializeSkillMd(opts) {
|
|
52957
|
-
const name = opts.name.trim().toLowerCase();
|
|
52958
|
-
const description = opts.description.trim();
|
|
52959
|
-
const body = opts.body.trim();
|
|
52960
|
-
const lines = ["---", `name: ${name}`, `description: ${description}`];
|
|
52961
|
-
const cat = (opts.category ?? "").trim().toLowerCase();
|
|
52962
|
-
if (cat && CODING_CATEGORIES2.has(cat)) {
|
|
52963
|
-
lines.push(`category: ${cat}`);
|
|
52964
|
-
}
|
|
52965
|
-
if (opts.tools && opts.tools.length > 0) {
|
|
52966
|
-
lines.push(`tools: [${opts.tools.map((t) => t.trim()).filter(Boolean).join(", ")}]`);
|
|
52967
|
-
}
|
|
52968
|
-
const cost = (opts.cost ?? "").trim().toLowerCase();
|
|
52969
|
-
if (cost === "low" || cost === "medium" || cost === "high") {
|
|
52970
|
-
lines.push(`cost: ${cost}`);
|
|
52971
|
-
}
|
|
52972
|
-
lines.push("---", "", body, "");
|
|
52973
|
-
return lines.join("\n");
|
|
52974
|
-
}
|
|
52975
|
-
function upsertSkill(opts) {
|
|
52976
|
-
const name = opts.name.trim().toLowerCase();
|
|
52977
|
-
if (!name || !NAME_RE.test(name)) {
|
|
52978
|
-
return {
|
|
52979
|
-
ok: false,
|
|
52980
|
-
error: "Invalid skill name (use lowercase letters, digits, hyphens; max 64 chars)"
|
|
52981
|
-
};
|
|
52982
|
-
}
|
|
52983
|
-
const description = opts.description.trim();
|
|
52984
|
-
if (!description) {
|
|
52985
|
-
return { ok: false, error: "description is required" };
|
|
52986
|
-
}
|
|
52987
|
-
const body = opts.body.trim();
|
|
52988
|
-
if (!body) {
|
|
52989
|
-
return { ok: false, error: "body is required" };
|
|
52990
|
-
}
|
|
52991
|
-
let dir;
|
|
52992
|
-
if (opts.scope === "user") {
|
|
52993
|
-
dir = getUserSkillsDir();
|
|
52994
|
-
} else {
|
|
52995
|
-
const root = opts.projectRoot?.trim();
|
|
52996
|
-
if (!root) {
|
|
52997
|
-
return {
|
|
52998
|
-
ok: false,
|
|
52999
|
-
error: "projectRoot required for project scope (Open Folder first)"
|
|
53000
|
-
};
|
|
53001
|
-
}
|
|
53002
|
-
dir = getProjectSkillsDir(root);
|
|
53003
|
-
}
|
|
53004
|
-
const path48 = skillFilePath(dir, name);
|
|
53005
|
-
const content = serializeSkillMd({
|
|
53006
|
-
name,
|
|
53007
|
-
description,
|
|
53008
|
-
body,
|
|
53009
|
-
category: opts.category,
|
|
53010
|
-
tools: opts.tools,
|
|
53011
|
-
cost: opts.cost
|
|
53012
|
-
});
|
|
53013
|
-
const parsed = parseSkillMd(content, path48);
|
|
53014
|
-
if (!parsed) {
|
|
53015
|
-
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
53016
|
-
}
|
|
53017
|
-
mkdirSync18(dirname9(path48), { recursive: true });
|
|
53018
|
-
writeFileSync20(path48, content, "utf8");
|
|
53019
|
-
return { ok: true, path: path48 };
|
|
53020
|
-
}
|
|
53021
|
-
function removeSkill(opts) {
|
|
53022
|
-
const name = opts.name.trim().toLowerCase();
|
|
53023
|
-
if (!name) {
|
|
53024
|
-
return { ok: false, error: "name is required" };
|
|
53025
|
-
}
|
|
53026
|
-
let dir;
|
|
53027
|
-
if (opts.scope === "user") {
|
|
53028
|
-
dir = getUserSkillsDir();
|
|
53029
|
-
} else {
|
|
53030
|
-
const root = opts.projectRoot?.trim();
|
|
53031
|
-
if (!root) {
|
|
53032
|
-
return { ok: false, error: "projectRoot required for project scope" };
|
|
53033
|
-
}
|
|
53034
|
-
dir = getProjectSkillsDir(root);
|
|
53035
|
-
}
|
|
53036
|
-
const skillDir = join34(dir, name);
|
|
53037
|
-
const path48 = skillFilePath(dir, name);
|
|
53038
|
-
if (!existsSync42(path48) && !existsSync42(skillDir)) {
|
|
53039
|
-
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
53040
|
-
}
|
|
53041
|
-
try {
|
|
53042
|
-
rmSync4(skillDir, { recursive: true, force: true });
|
|
53043
|
-
} catch (err) {
|
|
53044
|
-
return {
|
|
53045
|
-
ok: false,
|
|
53046
|
-
error: err instanceof Error ? err.message : String(err)
|
|
53047
|
-
};
|
|
53048
|
-
}
|
|
53049
|
-
return { ok: true, path: path48 };
|
|
53050
|
-
}
|
|
53748
|
+
init_skillConfigIo();
|
|
53051
53749
|
|
|
53052
53750
|
// src/cli/generateSkillFromUrl.ts
|
|
53053
53751
|
init_providerConfig();
|
|
53054
53752
|
init_keyStore();
|
|
53055
53753
|
init_openai_compatible();
|
|
53754
|
+
init_skillCategories();
|
|
53056
53755
|
var MAX_PAGE_CHARS = 24e3;
|
|
53057
53756
|
var FETCH_TIMEOUT_MS2 = 25e3;
|
|
53058
53757
|
var LLM_TIMEOUT_MS = 9e4;
|
|
@@ -53136,8 +53835,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
|
|
|
53136
53835
|
let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
53137
53836
|
if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
|
|
53138
53837
|
try {
|
|
53139
|
-
const
|
|
53140
|
-
name =
|
|
53838
|
+
const path51 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
53839
|
+
name = path51 && /^[a-z0-9]/.test(path51) ? path51 : "imported-skill";
|
|
53141
53840
|
} catch {
|
|
53142
53841
|
name = "imported-skill";
|
|
53143
53842
|
}
|
|
@@ -53412,9 +54111,30 @@ function pickRootComponent() {
|
|
|
53412
54111
|
console.error(`${red}\u2717${reset} ${result.error}`);
|
|
53413
54112
|
process.exit(1);
|
|
53414
54113
|
}
|
|
54114
|
+
if (argv.includes("--inspect") || argv.includes("inspect")) {
|
|
54115
|
+
const { runInspect: runInspect2 } = (init_inspect(), __toCommonJS(inspect_exports));
|
|
54116
|
+
const json2 = argv.includes("--json");
|
|
54117
|
+
void runInspect2({ json: json2 }).then((code) => process.exit(code));
|
|
54118
|
+
return { kind: "done" };
|
|
54119
|
+
}
|
|
54120
|
+
if (argv.includes("--trust")) {
|
|
54121
|
+
const { trustFolder: trustFolder2 } = (init_folderTrust(), __toCommonJS(folderTrust_exports));
|
|
54122
|
+
const i = argv.indexOf("--trust");
|
|
54123
|
+
const target = argv[i + 1] && !argv[i + 1].startsWith("--") ? argv[i + 1] : process.cwd();
|
|
54124
|
+
try {
|
|
54125
|
+
const res = trustFolder2(target);
|
|
54126
|
+
console.log(JSON.stringify({ ok: true, path: res.path }));
|
|
54127
|
+
process.exit(0);
|
|
54128
|
+
} catch (err) {
|
|
54129
|
+
console.error(
|
|
54130
|
+
`[zelari-code --trust] ${err instanceof Error ? err.message : String(err)}`
|
|
54131
|
+
);
|
|
54132
|
+
process.exit(1);
|
|
54133
|
+
}
|
|
54134
|
+
}
|
|
53415
54135
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
53416
54136
|
console.log(
|
|
53417
|
-
"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 --fix-budget Set recommended ZELARI_MAX_TOOL_LOOP_HARD=180,\n ZELARI_MAX_TOOL_LOOP_ITERATIONS=60, ZELARI_CONTEXT_LIMIT=400000\n at User scope (prevents the agent stopping mid-task)\n --permission-mcp <socket> MCP stdio server for external agent permission prompts\n (spawned by claude --permission-prompt-tool)\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --print-config Print provider/model config as JSON (no secrets)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable (required)\n --args <json> JSON array of args (optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
|
|
54137
|
+
"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 --inspect [--json] Unified project inspection (config, skills, MCP,\n hooks, plugins, AGENTS.md, trust status)\n --trust [path] Trust the cwd (or path) so project MCP + hooks load\n --fix-path Add the npm global prefix to the user PATH\n (Windows only; fixes 'command not found' after install)\n --fix-budget Set recommended ZELARI_MAX_TOOL_LOOP_HARD=180,\n ZELARI_MAX_TOOL_LOOP_ITERATIONS=60, ZELARI_CONTEXT_LIMIT=400000\n at User scope (prevents the agent stopping mid-task)\n --permission-mcp <socket> MCP stdio server for external agent permission prompts\n (spawned by claude --permission-prompt-tool)\n --skip-checks Skip the boot-time prerequisite check\n (alias for ZELARI_SKIP_PREFLIGHT=1)\n --no-wizard Skip the first-run wizard\n --reset-config Re-run the wizard (clears provider.json on commit)\n --headless Run a single task without mounting the TUI\n --task <text> Task prompt (required in headless mode)\n --output json|plain Output format (default: json)\n --mode kraken|council|zelari Dispatch mode (default: kraken; agent=alias)\n --council Alias for --mode council\n --phase plan|build Work phase (default: build)\n --provider <id> Provider override (default: active)\n --model <id> Model override (default: provider default)\n serve Companion host for Android/remote clients (Tailscale)\n --bind <ip> Listen address (default: 127.0.0.1; use Tailscale IP)\n --port <n> Port (default: 7421)\n --token <secret> Bearer token (default: ~/.zelari-code/companion.token)\n --project <path> Allowlisted project root (repeatable)\n --save-projects Persist --project list to companion.json\n --print-config Print provider/model config as JSON (no secrets)\n --plugins-status JSON status of optional plugins (Playwright, eslint, \u2026)\n --plugins-install <id> Install plugin (playwright also fetches Chromium)\n --cwd <path> Workspace for -D installs (default: process.cwd())\n --set-config Persist provider/model/endpoint\n --provider <id> Set active provider\n --model <id> Set model for that provider\n --endpoint <url> Custom OpenAI-compatible base URL\n --endpoint-clear Remove custom endpoint override\n --set-key Store an API key (never printed back)\n --provider <id> Provider id (required)\n --key <secret> API key (required)\n --discover-models Refresh model list for a provider\n --provider <id> Provider (default: active)\n --print-mcp Print MCP server config (user + project)\n --cwd <path> Project root for .zelari/mcp.json\n --set-mcp Add/update an MCP server entry\n --name <id> Server name (required)\n --command <bin> Executable (required)\n --args <json> JSON array of args (optional)\n --scope user|project Default: user\n --enabled true|false Default: true\n --cwd <path> Required when scope=project\n --set-mcp-preset Install a named MCP preset (e.g. cua)\n --preset cua Cua Driver desktop computer-use (MCP)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-mcp Remove an MCP server entry\n --name <id> --scope user|project [--cwd <path>]\n --print-skills Print skills (builtin + user + project)\n --cwd <path> Project root for .zelari/skills\n --set-skill Add/update a SKILL.md skill\n --name <id> Skill id (required)\n --description <t> One-line description (required)\n --body <text> Markdown instructions (required)\n --category <c> plan|refactor|debug|review|test|docs|ops|git|db|maint\n --tools <csv> Comma-separated required tools (optional)\n --cost <l> low|medium|high (default: medium)\n --scope user|project Default: user\n --cwd <path> Required when scope=project\n --remove-skill Remove a user/project SKILL.md\n --name <id> --scope user|project [--cwd <path>]\n --generate-skill-from-url Fetch URL + draft skill via model (JSON)\n --url <https://...> Required\n --provider <id> Override active provider\n --model <name> Override model for the selected provider\n --print-ssh-targets Print SSH deploy/monitor targets\n --set-ssh-target Upsert target (--json '{...}' or flags)\n --remove-ssh-target --id <id>\n --test-ssh-target --id <id> (BatchMode ssh true)\n --print-ssh-pubkey --path <private-or-.pub> (display public key)\n\nEnvironment:\n ZELARI_NO_WIZARD=1 Skip the first-run wizard\n ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n ANATHEMA_DEV=1 Disable background update check + preflight\n"
|
|
53418
54138
|
);
|
|
53419
54139
|
process.exit(0);
|
|
53420
54140
|
}
|