zelari-code 2.21.0 → 2.23.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/main.bundled.js +524 -215
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/provider/anthropic.js +30 -2
- package/dist/cli/provider/anthropic.js.map +1 -1
- package/dist/cli/provider/chatgpt.js +29 -2
- package/dist/cli/provider/chatgpt.js.map +1 -1
- package/dist/cli/provider/openai-compatible.js +3 -3
- package/dist/cli/provider/openai-compatible.js.map +1 -1
- package/dist/cli/safety/selfKillGuard.js +147 -0
- package/dist/cli/safety/selfKillGuard.js.map +1 -0
- package/dist/cli/serve/harnessServer.js +11 -0
- package/dist/cli/serve/harnessServer.js.map +1 -1
- package/dist/cli/serve/spineLockSweep.js +76 -0
- package/dist/cli/serve/spineLockSweep.js.map +1 -0
- package/dist/cli/sessionSpine.js +11 -3
- package/dist/cli/sessionSpine.js.map +1 -1
- package/dist/cli/toolRegistry.js +21 -0
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/execProcess.js +11 -0
- package/dist/cli/tools/execProcess.js.map +1 -1
- package/dist/cli/utils/doctor.js +10 -3
- package/dist/cli/utils/doctor.js.map +1 -1
- package/dist/cli/utils/prereqChecks.js +2 -2
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -3288,10 +3288,10 @@ function mergeDefs(...defs) {
|
|
|
3288
3288
|
function cloneDef(schema) {
|
|
3289
3289
|
return mergeDefs(schema._zod.def);
|
|
3290
3290
|
}
|
|
3291
|
-
function getElementAtPath(obj,
|
|
3292
|
-
if (!
|
|
3291
|
+
function getElementAtPath(obj, path92) {
|
|
3292
|
+
if (!path92)
|
|
3293
3293
|
return obj;
|
|
3294
|
-
return
|
|
3294
|
+
return path92.reduce((acc, key) => acc?.[key], obj);
|
|
3295
3295
|
}
|
|
3296
3296
|
function promiseAllObject(promisesObj) {
|
|
3297
3297
|
const keys = Object.keys(promisesObj);
|
|
@@ -3619,11 +3619,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
3619
3619
|
}
|
|
3620
3620
|
return false;
|
|
3621
3621
|
}
|
|
3622
|
-
function prefixIssues(
|
|
3622
|
+
function prefixIssues(path92, issues) {
|
|
3623
3623
|
return issues.map((iss) => {
|
|
3624
3624
|
var _a3;
|
|
3625
3625
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
3626
|
-
iss.path.unshift(
|
|
3626
|
+
iss.path.unshift(path92);
|
|
3627
3627
|
return iss;
|
|
3628
3628
|
});
|
|
3629
3629
|
}
|
|
@@ -3841,16 +3841,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3841
3841
|
}
|
|
3842
3842
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
3843
3843
|
const fieldErrors = { _errors: [] };
|
|
3844
|
-
const processError = (error52,
|
|
3844
|
+
const processError = (error52, path92 = []) => {
|
|
3845
3845
|
for (const issue2 of error52.issues) {
|
|
3846
3846
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3847
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3847
|
+
issue2.errors.map((issues) => processError({ issues }, [...path92, ...issue2.path]));
|
|
3848
3848
|
} else if (issue2.code === "invalid_key") {
|
|
3849
|
-
processError({ issues: issue2.issues }, [...
|
|
3849
|
+
processError({ issues: issue2.issues }, [...path92, ...issue2.path]);
|
|
3850
3850
|
} else if (issue2.code === "invalid_element") {
|
|
3851
|
-
processError({ issues: issue2.issues }, [...
|
|
3851
|
+
processError({ issues: issue2.issues }, [...path92, ...issue2.path]);
|
|
3852
3852
|
} else {
|
|
3853
|
-
const fullpath = [...
|
|
3853
|
+
const fullpath = [...path92, ...issue2.path];
|
|
3854
3854
|
if (fullpath.length === 0) {
|
|
3855
3855
|
fieldErrors._errors.push(mapper(issue2));
|
|
3856
3856
|
} else {
|
|
@@ -3877,17 +3877,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3877
3877
|
}
|
|
3878
3878
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
3879
3879
|
const result = { errors: [] };
|
|
3880
|
-
const processError = (error52,
|
|
3880
|
+
const processError = (error52, path92 = []) => {
|
|
3881
3881
|
var _a3, _b;
|
|
3882
3882
|
for (const issue2 of error52.issues) {
|
|
3883
3883
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3884
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3884
|
+
issue2.errors.map((issues) => processError({ issues }, [...path92, ...issue2.path]));
|
|
3885
3885
|
} else if (issue2.code === "invalid_key") {
|
|
3886
|
-
processError({ issues: issue2.issues }, [...
|
|
3886
|
+
processError({ issues: issue2.issues }, [...path92, ...issue2.path]);
|
|
3887
3887
|
} else if (issue2.code === "invalid_element") {
|
|
3888
|
-
processError({ issues: issue2.issues }, [...
|
|
3888
|
+
processError({ issues: issue2.issues }, [...path92, ...issue2.path]);
|
|
3889
3889
|
} else {
|
|
3890
|
-
const fullpath = [...
|
|
3890
|
+
const fullpath = [...path92, ...issue2.path];
|
|
3891
3891
|
if (fullpath.length === 0) {
|
|
3892
3892
|
result.errors.push(mapper(issue2));
|
|
3893
3893
|
continue;
|
|
@@ -3919,8 +3919,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
3919
3919
|
}
|
|
3920
3920
|
function toDotPath(_path) {
|
|
3921
3921
|
const segs = [];
|
|
3922
|
-
const
|
|
3923
|
-
for (const seg of
|
|
3922
|
+
const path92 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
3923
|
+
for (const seg of path92) {
|
|
3924
3924
|
if (typeof seg === "number")
|
|
3925
3925
|
segs.push(`[${seg}]`);
|
|
3926
3926
|
else if (typeof seg === "symbol")
|
|
@@ -17423,13 +17423,13 @@ function resolveRef(ref, ctx) {
|
|
|
17423
17423
|
if (!ref.startsWith("#")) {
|
|
17424
17424
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
17425
17425
|
}
|
|
17426
|
-
const
|
|
17427
|
-
if (
|
|
17426
|
+
const path92 = ref.slice(1).split("/").filter(Boolean);
|
|
17427
|
+
if (path92.length === 0) {
|
|
17428
17428
|
return ctx.rootSchema;
|
|
17429
17429
|
}
|
|
17430
17430
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
17431
|
-
if (
|
|
17432
|
-
const key =
|
|
17431
|
+
if (path92[0] === defsKey) {
|
|
17432
|
+
const key = path92[1];
|
|
17433
17433
|
if (!key || !ctx.defs[key]) {
|
|
17434
17434
|
throw new Error(`Reference not found: ${ref}`);
|
|
17435
17435
|
}
|
|
@@ -19887,11 +19887,11 @@ var init_tools = __esm({
|
|
|
19887
19887
|
if (!ctx.addDocument)
|
|
19888
19888
|
return "Knowledge vault tool not available.";
|
|
19889
19889
|
const title = args["title"] || "New Document";
|
|
19890
|
-
const
|
|
19890
|
+
const path92 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
19891
19891
|
const content = args["content"] || "";
|
|
19892
19892
|
const tags = args["tags"] || [];
|
|
19893
19893
|
ctx.addDocument({
|
|
19894
|
-
path:
|
|
19894
|
+
path: path92,
|
|
19895
19895
|
title,
|
|
19896
19896
|
content,
|
|
19897
19897
|
format: "markdown",
|
|
@@ -19900,7 +19900,7 @@ var init_tools = __esm({
|
|
|
19900
19900
|
workspaceId: ctx.workspaceId
|
|
19901
19901
|
});
|
|
19902
19902
|
ctx.addActivity("vault", "created document", title);
|
|
19903
|
-
return `Document "${title}" created at "${
|
|
19903
|
+
return `Document "${title}" created at "${path92}".`;
|
|
19904
19904
|
}
|
|
19905
19905
|
}
|
|
19906
19906
|
];
|
|
@@ -26246,11 +26246,11 @@ var init_synthesisAudit = __esm({
|
|
|
26246
26246
|
import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
|
|
26247
26247
|
import { join as join4 } from "node:path";
|
|
26248
26248
|
function loadNfrSpec(zelariRoot) {
|
|
26249
|
-
const
|
|
26250
|
-
if (!existsSync7(
|
|
26249
|
+
const path92 = join4(zelariRoot, "nfr-spec.json");
|
|
26250
|
+
if (!existsSync7(path92))
|
|
26251
26251
|
return null;
|
|
26252
26252
|
try {
|
|
26253
|
-
const raw = JSON.parse(readFileSync7(
|
|
26253
|
+
const raw = JSON.parse(readFileSync7(path92, "utf8"));
|
|
26254
26254
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
26255
26255
|
return null;
|
|
26256
26256
|
return raw;
|
|
@@ -28556,9 +28556,9 @@ var init_types5 = __esm({
|
|
|
28556
28556
|
import { readFileSync as readFileSync12 } from "node:fs";
|
|
28557
28557
|
import { join as join10 } from "node:path";
|
|
28558
28558
|
function readLessonsDeduped(zelariRoot) {
|
|
28559
|
-
const
|
|
28559
|
+
const path92 = join10(zelariRoot, LESSONS_FILE);
|
|
28560
28560
|
try {
|
|
28561
|
-
const raw = readFileSync12(
|
|
28561
|
+
const raw = readFileSync12(path92, "utf8");
|
|
28562
28562
|
const byId = /* @__PURE__ */ new Map();
|
|
28563
28563
|
for (const line of raw.split(/\r?\n/)) {
|
|
28564
28564
|
if (!line.trim())
|
|
@@ -28659,8 +28659,8 @@ function keywordsFrom(check2, signature) {
|
|
|
28659
28659
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
28660
28660
|
}
|
|
28661
28661
|
function writeLesson(zelariRoot, lesson) {
|
|
28662
|
-
const
|
|
28663
|
-
appendFileSync(
|
|
28662
|
+
const path92 = join11(zelariRoot, LESSONS_FILE);
|
|
28663
|
+
appendFileSync(path92, `${JSON.stringify(lesson)}
|
|
28664
28664
|
`, "utf8");
|
|
28665
28665
|
}
|
|
28666
28666
|
function findSimilar(lessons, signature) {
|
|
@@ -30624,9 +30624,9 @@ function findCycle(nodes) {
|
|
|
30624
30624
|
if (color.get(start) !== WHITE)
|
|
30625
30625
|
continue;
|
|
30626
30626
|
const stack = [[start, 0]];
|
|
30627
|
-
const
|
|
30627
|
+
const path92 = [];
|
|
30628
30628
|
color.set(start, GRAY);
|
|
30629
|
-
|
|
30629
|
+
path92.push(start);
|
|
30630
30630
|
while (stack.length > 0) {
|
|
30631
30631
|
const top = stack[stack.length - 1];
|
|
30632
30632
|
const [id3, idx] = top;
|
|
@@ -30639,17 +30639,17 @@ function findCycle(nodes) {
|
|
|
30639
30639
|
continue;
|
|
30640
30640
|
const c = color.get(dep);
|
|
30641
30641
|
if (c === GRAY) {
|
|
30642
|
-
const at =
|
|
30643
|
-
return [...
|
|
30642
|
+
const at = path92.indexOf(dep);
|
|
30643
|
+
return [...path92.slice(at), dep];
|
|
30644
30644
|
}
|
|
30645
30645
|
if (c === WHITE) {
|
|
30646
30646
|
color.set(dep, GRAY);
|
|
30647
|
-
|
|
30647
|
+
path92.push(dep);
|
|
30648
30648
|
stack.push([dep, 0]);
|
|
30649
30649
|
}
|
|
30650
30650
|
} else {
|
|
30651
30651
|
color.set(id3, BLACK);
|
|
30652
|
-
|
|
30652
|
+
path92.pop();
|
|
30653
30653
|
stack.pop();
|
|
30654
30654
|
}
|
|
30655
30655
|
}
|
|
@@ -31569,8 +31569,8 @@ var init_runner = __esm({
|
|
|
31569
31569
|
failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
|
|
31570
31570
|
pending: []
|
|
31571
31571
|
};
|
|
31572
|
-
const
|
|
31573
|
-
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${
|
|
31572
|
+
const path92 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
|
|
31573
|
+
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path92}`);
|
|
31574
31574
|
return snapshot;
|
|
31575
31575
|
}
|
|
31576
31576
|
callLog(msg, data) {
|
|
@@ -32206,7 +32206,40 @@ var init_agentAdapter = __esm({
|
|
|
32206
32206
|
import { promises as fs9 } from "node:fs";
|
|
32207
32207
|
import path14 from "node:path";
|
|
32208
32208
|
import crypto2 from "node:crypto";
|
|
32209
|
-
|
|
32209
|
+
function defaultLockLivenessProbe(pid) {
|
|
32210
|
+
try {
|
|
32211
|
+
process.kill(pid, 0);
|
|
32212
|
+
return true;
|
|
32213
|
+
} catch (err) {
|
|
32214
|
+
return err.code !== "ESRCH";
|
|
32215
|
+
}
|
|
32216
|
+
}
|
|
32217
|
+
function resolveHeartbeatStaleMs(env = process.env) {
|
|
32218
|
+
const raw = env.ZELARI_SPINE_HEARTBEAT_STALE_MS;
|
|
32219
|
+
if (raw) {
|
|
32220
|
+
const parsed = Number.parseInt(raw, 10);
|
|
32221
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
32222
|
+
return parsed;
|
|
32223
|
+
}
|
|
32224
|
+
return DEFAULT_HEARTBEAT_STALE_MS;
|
|
32225
|
+
}
|
|
32226
|
+
function evaluateLockTakeover(lockInfo, opts) {
|
|
32227
|
+
const heartbeatStaleMs = opts.heartbeatStaleMs ?? DEFAULT_HEARTBEAT_STALE_MS;
|
|
32228
|
+
const staleLockMs = opts.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
|
|
32229
|
+
const ts = typeof lockInfo.ts === "number" && Number.isFinite(lockInfo.ts) && lockInfo.ts > 0 ? lockInfo.ts : 0;
|
|
32230
|
+
const pid = typeof lockInfo.pid === "number" && Number.isFinite(lockInfo.pid) && lockInfo.pid > 0 ? lockInfo.pid : void 0;
|
|
32231
|
+
if (pid !== void 0) {
|
|
32232
|
+
if (!opts.probe(pid))
|
|
32233
|
+
return { takeover: true, reason: "pid-dead" };
|
|
32234
|
+
if (ts > 0 && opts.now - ts < heartbeatStaleMs)
|
|
32235
|
+
return { takeover: false, reason: "alive-fresh" };
|
|
32236
|
+
return { takeover: true, reason: "heartbeat-stale" };
|
|
32237
|
+
}
|
|
32238
|
+
if (ts > 0 && opts.now - ts > staleLockMs)
|
|
32239
|
+
return { takeover: true, reason: "stale" };
|
|
32240
|
+
return { takeover: false, reason: "no-pid-locked" };
|
|
32241
|
+
}
|
|
32242
|
+
var SessionLogLockedError, DEFAULT_STALE_LOCK_MS, DEFAULT_HEARTBEAT_STALE_MS, SessionLogWriter;
|
|
32210
32243
|
var init_writer = __esm({
|
|
32211
32244
|
"packages/core/dist/session/writer.js"() {
|
|
32212
32245
|
"use strict";
|
|
@@ -32223,13 +32256,18 @@ var init_writer = __esm({
|
|
|
32223
32256
|
}
|
|
32224
32257
|
};
|
|
32225
32258
|
DEFAULT_STALE_LOCK_MS = 10 * 60 * 1e3;
|
|
32259
|
+
DEFAULT_HEARTBEAT_STALE_MS = 12e4;
|
|
32226
32260
|
SessionLogWriter = class _SessionLogWriter {
|
|
32227
32261
|
sessionId;
|
|
32228
32262
|
eventsPath;
|
|
32229
32263
|
lockPath;
|
|
32230
32264
|
ownership = crypto2.randomUUID();
|
|
32231
32265
|
staleLockMs;
|
|
32266
|
+
heartbeatStaleMs;
|
|
32267
|
+
probe;
|
|
32232
32268
|
now;
|
|
32269
|
+
/** Last heartbeat ts written into the lock (throttle window anchor). */
|
|
32270
|
+
lastHeartbeatAt = 0;
|
|
32233
32271
|
nextSeq;
|
|
32234
32272
|
closed = false;
|
|
32235
32273
|
chain = Promise.resolve();
|
|
@@ -32239,6 +32277,8 @@ var init_writer = __esm({
|
|
|
32239
32277
|
this.lockPath = path14.join(sessionDir, "writer.lock");
|
|
32240
32278
|
this.nextSeq = startSeq;
|
|
32241
32279
|
this.staleLockMs = options.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
|
|
32280
|
+
this.heartbeatStaleMs = options.heartbeatStaleMs ?? resolveHeartbeatStaleMs();
|
|
32281
|
+
this.probe = options.probe ?? defaultLockLivenessProbe;
|
|
32242
32282
|
this.now = options.now ?? Date.now;
|
|
32243
32283
|
}
|
|
32244
32284
|
/** Create the writer and acquire the ownership lock. */
|
|
@@ -32261,6 +32301,7 @@ var init_writer = __esm({
|
|
|
32261
32301
|
const payload = this.lockPayload();
|
|
32262
32302
|
try {
|
|
32263
32303
|
await fs9.writeFile(this.lockPath, payload, { encoding: "utf-8", flag: "wx", mode: 420 });
|
|
32304
|
+
this.lastHeartbeatAt = this.now();
|
|
32264
32305
|
return;
|
|
32265
32306
|
} catch (err) {
|
|
32266
32307
|
if (err.code !== "EEXIST")
|
|
@@ -32268,19 +32309,43 @@ var init_writer = __esm({
|
|
|
32268
32309
|
}
|
|
32269
32310
|
const existing = await fs9.readFile(this.lockPath, "utf-8").catch(() => null);
|
|
32270
32311
|
let owner = "unknown";
|
|
32271
|
-
|
|
32312
|
+
const lockInfo = {};
|
|
32272
32313
|
if (existing) {
|
|
32273
32314
|
try {
|
|
32274
32315
|
const parsed = JSON.parse(existing);
|
|
32275
32316
|
owner = parsed.ownership ?? owner;
|
|
32276
|
-
|
|
32317
|
+
lockInfo.ownership = parsed.ownership;
|
|
32318
|
+
lockInfo.pid = parsed.pid;
|
|
32319
|
+
lockInfo.ts = parsed.ts;
|
|
32277
32320
|
} catch {
|
|
32278
32321
|
}
|
|
32279
32322
|
}
|
|
32280
|
-
const
|
|
32281
|
-
|
|
32323
|
+
const verdict = evaluateLockTakeover(lockInfo, {
|
|
32324
|
+
now: this.now(),
|
|
32325
|
+
probe: this.probe,
|
|
32326
|
+
heartbeatStaleMs: this.heartbeatStaleMs,
|
|
32327
|
+
staleLockMs: this.staleLockMs
|
|
32328
|
+
});
|
|
32329
|
+
if (!verdict.takeover)
|
|
32282
32330
|
throw new SessionLogLockedError(this.eventsPath, owner);
|
|
32283
32331
|
await fs9.writeFile(this.lockPath, payload, { encoding: "utf-8" });
|
|
32332
|
+
this.lastHeartbeatAt = this.now();
|
|
32333
|
+
}
|
|
32334
|
+
/** Min interval between lock-ts refreshes (≤ ~1 rewrite/second). */
|
|
32335
|
+
static HEARTBEAT_MIN_INTERVAL_MS = 1e3;
|
|
32336
|
+
/**
|
|
32337
|
+
* Lock heartbeat: while we own the lock, refresh its ts so concurrent
|
|
32338
|
+
* writers can tell a live owner from a hung one. Best-effort and throttled
|
|
32339
|
+
* to at most ~1 rewrite/second; it rides the append chain so close() always
|
|
32340
|
+
* lands AFTER the last heartbeat (never resurrects a removed lock).
|
|
32341
|
+
*/
|
|
32342
|
+
maybeHeartbeat() {
|
|
32343
|
+
const ts = this.now();
|
|
32344
|
+
if (ts - this.lastHeartbeatAt < _SessionLogWriter.HEARTBEAT_MIN_INTERVAL_MS)
|
|
32345
|
+
return;
|
|
32346
|
+
this.lastHeartbeatAt = ts;
|
|
32347
|
+
void fs9.writeFile(this.lockPath, this.lockPayload(), { encoding: "utf-8" }).catch(() => {
|
|
32348
|
+
});
|
|
32284
32349
|
}
|
|
32285
32350
|
/** Append one event; returns the validated envelope with its assigned seq. */
|
|
32286
32351
|
async append(input) {
|
|
@@ -32297,6 +32362,7 @@ var init_writer = __esm({
|
|
|
32297
32362
|
};
|
|
32298
32363
|
SessionEventEnvelopeSchema.parse(envelope);
|
|
32299
32364
|
this.nextSeq += 1;
|
|
32365
|
+
this.chain = this.chain.then(() => this.maybeHeartbeat());
|
|
32300
32366
|
const line = JSON.stringify(envelope) + "\n";
|
|
32301
32367
|
this.chain = this.chain.then(() => fs9.appendFile(this.eventsPath, line, "utf-8"));
|
|
32302
32368
|
await this.chain;
|
|
@@ -33771,7 +33837,7 @@ async function createExecutionContext(options = {}) {
|
|
|
33771
33837
|
workspaceKind: workspace.kind
|
|
33772
33838
|
}
|
|
33773
33839
|
});
|
|
33774
|
-
const
|
|
33840
|
+
const fs46 = options.fs ?? new NodeFsProvider(workspace);
|
|
33775
33841
|
const shell = options.shell ?? new NodeShellProvider(workspace);
|
|
33776
33842
|
const subagent = options.subagent ?? NOOP_SUBAGENT_PROVIDER;
|
|
33777
33843
|
const env = options.env ?? process.env;
|
|
@@ -33779,7 +33845,7 @@ async function createExecutionContext(options = {}) {
|
|
|
33779
33845
|
sessionId: sessionId2,
|
|
33780
33846
|
profile,
|
|
33781
33847
|
workspace,
|
|
33782
|
-
fs:
|
|
33848
|
+
fs: fs46,
|
|
33783
33849
|
shell,
|
|
33784
33850
|
subagent,
|
|
33785
33851
|
appendSessionEvent: (input) => writer.append(input),
|
|
@@ -34030,16 +34096,16 @@ function runRetentionFromEnv() {
|
|
|
34030
34096
|
maxTotalBytes: Number.isFinite(parseMb) && parseMb > 0 ? Math.round(parseMb * 1024 * 1024) : DEFAULT_RUN_RETENTION_MAX_MB * 1024 * 1024
|
|
34031
34097
|
};
|
|
34032
34098
|
}
|
|
34033
|
-
async function dirSize(
|
|
34099
|
+
async function dirSize(path92) {
|
|
34034
34100
|
let total = 0;
|
|
34035
34101
|
let entries;
|
|
34036
34102
|
try {
|
|
34037
|
-
entries = await readdir(
|
|
34103
|
+
entries = await readdir(path92, { withFileTypes: true });
|
|
34038
34104
|
} catch {
|
|
34039
34105
|
return 0;
|
|
34040
34106
|
}
|
|
34041
34107
|
for (const entry of entries) {
|
|
34042
|
-
const child = join13(
|
|
34108
|
+
const child = join13(path92, entry.name);
|
|
34043
34109
|
if (entry.isDirectory())
|
|
34044
34110
|
total += await dirSize(child);
|
|
34045
34111
|
else {
|
|
@@ -34066,19 +34132,19 @@ async function enforceRunRetention(runsDir, options = {}) {
|
|
|
34066
34132
|
for (const entry of entries) {
|
|
34067
34133
|
if (!entry.isDirectory())
|
|
34068
34134
|
continue;
|
|
34069
|
-
const
|
|
34135
|
+
const path92 = join13(runsDir, entry.name);
|
|
34070
34136
|
let startedAt = 0;
|
|
34071
34137
|
let endedAt;
|
|
34072
34138
|
let completed = false;
|
|
34073
34139
|
try {
|
|
34074
|
-
const manifest = JSON.parse(await readFile(join13(
|
|
34140
|
+
const manifest = JSON.parse(await readFile(join13(path92, "manifest.json"), "utf8"));
|
|
34075
34141
|
startedAt = manifest.startedAt ?? 0;
|
|
34076
34142
|
endedAt = manifest.endedAt;
|
|
34077
34143
|
completed = Boolean(endedAt) && manifest.status !== "running";
|
|
34078
34144
|
} catch {
|
|
34079
34145
|
completed = false;
|
|
34080
34146
|
}
|
|
34081
|
-
infos.push({ name: entry.name, path:
|
|
34147
|
+
infos.push({ name: entry.name, path: path92, startedAt, endedAt, completed, bytes: await dirSize(path92) });
|
|
34082
34148
|
}
|
|
34083
34149
|
const remove = async (info) => {
|
|
34084
34150
|
await rm(info.path, { recursive: true, force: true });
|
|
@@ -34850,12 +34916,12 @@ var init_engine = __esm({
|
|
|
34850
34916
|
* content digest) and the returned ref carries the event seq when the
|
|
34851
34917
|
* emitter resolved one.
|
|
34852
34918
|
*/
|
|
34853
|
-
async fsEvidence(observation,
|
|
34919
|
+
async fsEvidence(observation, path92, sha256, content, extra = {}) {
|
|
34854
34920
|
const digest = sha256 && content !== void 0 ? sha256(content) : void 0;
|
|
34855
|
-
const seq = await this.emitEvidence({ observation, path:
|
|
34921
|
+
const seq = await this.emitEvidence({ observation, path: path92, ...extra, ...digest ? { digest } : {} });
|
|
34856
34922
|
return {
|
|
34857
34923
|
tier: "fs-observation",
|
|
34858
|
-
ref:
|
|
34924
|
+
ref: path92,
|
|
34859
34925
|
capturedAt: Date.now(),
|
|
34860
34926
|
...digest ? { digest } : {},
|
|
34861
34927
|
...seq !== void 0 ? { seq } : {}
|
|
@@ -34863,25 +34929,25 @@ var init_engine = __esm({
|
|
|
34863
34929
|
}
|
|
34864
34930
|
async evalFileExists(check2, done) {
|
|
34865
34931
|
const sha256 = this.options.sha256 ?? defaultSha256;
|
|
34866
|
-
const
|
|
34867
|
-
if (!
|
|
34932
|
+
const fs46 = this.services.fs;
|
|
34933
|
+
if (!fs46)
|
|
34868
34934
|
return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
|
|
34869
|
-
const exists = await
|
|
34935
|
+
const exists = await fs46.exists(check2.path);
|
|
34870
34936
|
if (!exists) {
|
|
34871
34937
|
await this.emitEvidence({ observation: "file-exists", path: check2.path, exists: false });
|
|
34872
34938
|
return done({ status: "fail", evidence: [], detail: `file not found: ${check2.path}` });
|
|
34873
34939
|
}
|
|
34874
|
-
const content = await
|
|
34940
|
+
const content = await fs46.readFile(check2.path).catch(() => "");
|
|
34875
34941
|
return done({
|
|
34876
34942
|
status: "pass",
|
|
34877
34943
|
evidence: [await this.fsEvidence("file-exists", check2.path, sha256, content, { exists: true })]
|
|
34878
34944
|
});
|
|
34879
34945
|
}
|
|
34880
34946
|
async evalFileAbsent(check2, done) {
|
|
34881
|
-
const
|
|
34882
|
-
if (!
|
|
34947
|
+
const fs46 = this.services.fs;
|
|
34948
|
+
if (!fs46)
|
|
34883
34949
|
return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
|
|
34884
|
-
const exists = await
|
|
34950
|
+
const exists = await fs46.exists(check2.path);
|
|
34885
34951
|
if (exists) {
|
|
34886
34952
|
await this.emitEvidence({ observation: "file-absent", path: check2.path, exists: true });
|
|
34887
34953
|
return done({ status: "fail", evidence: [], detail: `file still present: ${check2.path}` });
|
|
@@ -34893,12 +34959,12 @@ var init_engine = __esm({
|
|
|
34893
34959
|
}
|
|
34894
34960
|
async evalFileContains(check2, done) {
|
|
34895
34961
|
const sha256 = this.options.sha256 ?? defaultSha256;
|
|
34896
|
-
const
|
|
34897
|
-
if (!
|
|
34962
|
+
const fs46 = this.services.fs;
|
|
34963
|
+
if (!fs46)
|
|
34898
34964
|
return done({ status: "unknown", evidence: [], detail: "fs provider unavailable" });
|
|
34899
34965
|
let content;
|
|
34900
34966
|
try {
|
|
34901
|
-
content = await
|
|
34967
|
+
content = await fs46.readFile(check2.path);
|
|
34902
34968
|
} catch {
|
|
34903
34969
|
await this.emitEvidence({ observation: "file-contains", path: check2.path, readable: false });
|
|
34904
34970
|
return done({ status: "fail", evidence: [], detail: `file not readable: ${check2.path}` });
|
|
@@ -35762,6 +35828,7 @@ __export(dist_exports, {
|
|
|
35762
35828
|
CriterionSchema: () => CriterionSchema,
|
|
35763
35829
|
CriterionSourceSchema: () => CriterionSourceSchema,
|
|
35764
35830
|
DEFAULT_CONTEXT_POLICY: () => DEFAULT_CONTEXT_POLICY,
|
|
35831
|
+
DEFAULT_HEARTBEAT_STALE_MS: () => DEFAULT_HEARTBEAT_STALE_MS,
|
|
35765
35832
|
DEFAULT_MAX_NODES: () => DEFAULT_MAX_NODES,
|
|
35766
35833
|
DEFAULT_MAX_TENTACLES: () => DEFAULT_MAX_TENTACLES,
|
|
35767
35834
|
DEFAULT_MEMORY_SCORING_WEIGHTS: () => DEFAULT_MEMORY_SCORING_WEIGHTS,
|
|
@@ -35992,6 +36059,7 @@ __export(dist_exports, {
|
|
|
35992
36059
|
createGraph: () => createGraph,
|
|
35993
36060
|
createRecorderObserver: () => createRecorderObserver,
|
|
35994
36061
|
createRoutedRequestSnapshot: () => createRoutedRequestSnapshot,
|
|
36062
|
+
defaultLockLivenessProbe: () => defaultLockLivenessProbe,
|
|
35995
36063
|
defaultPersonaParse: () => defaultPersonaParse,
|
|
35996
36064
|
defaultResourcePolicy: () => defaultResourcePolicy,
|
|
35997
36065
|
deriveInitialContract: () => deriveInitialContract,
|
|
@@ -36009,6 +36077,7 @@ __export(dist_exports, {
|
|
|
36009
36077
|
enforceRunRetention: () => enforceRunRetention,
|
|
36010
36078
|
evaluateBudgetContinuation: () => evaluateBudgetContinuation,
|
|
36011
36079
|
evaluateCompletion: () => evaluateCompletion,
|
|
36080
|
+
evaluateLockTakeover: () => evaluateLockTakeover,
|
|
36012
36081
|
evaluateMissionContinuation: () => evaluateMissionContinuation,
|
|
36013
36082
|
evaluateResourceReserveGate: () => evaluateResourceReserveGate,
|
|
36014
36083
|
executeTool: () => executeTool,
|
|
@@ -36160,6 +36229,7 @@ __export(dist_exports, {
|
|
|
36160
36229
|
replayChairmanTextTools: () => replayChairmanTextTools,
|
|
36161
36230
|
resolveAgentSkills: () => resolveAgentSkills,
|
|
36162
36231
|
resolveCouncilRunMode: () => resolveCouncilRunMode,
|
|
36232
|
+
resolveHeartbeatStaleMs: () => resolveHeartbeatStaleMs,
|
|
36163
36233
|
resolveInterventions: () => resolveInterventions,
|
|
36164
36234
|
resolveJailed: () => resolveJailed,
|
|
36165
36235
|
resolveMaxTentacles: () => resolveMaxTentacles,
|
|
@@ -37360,6 +37430,11 @@ var init_sessionSpine = __esm({
|
|
|
37360
37430
|
} catch (err) {
|
|
37361
37431
|
if (err instanceof SessionLogLockedError) {
|
|
37362
37432
|
mirror.status = "locked";
|
|
37433
|
+
mirror.warnOnce(
|
|
37434
|
+
err,
|
|
37435
|
+
`session lock held by another (possibly dead) owner: ${err.message} \u2014 the turn resumed WITHOUT derived spine context`,
|
|
37436
|
+
"locked"
|
|
37437
|
+
);
|
|
37363
37438
|
} else {
|
|
37364
37439
|
mirror.status = "degraded";
|
|
37365
37440
|
mirror.warnOnce(err);
|
|
@@ -37662,13 +37737,13 @@ var init_sessionSpine = __esm({
|
|
|
37662
37737
|
appendEvent(input) {
|
|
37663
37738
|
return this.append(input);
|
|
37664
37739
|
}
|
|
37665
|
-
warnOnce(err) {
|
|
37740
|
+
warnOnce(err, message, label = "degraded") {
|
|
37666
37741
|
if (this.warned || this.options.quiet) return;
|
|
37667
37742
|
this.warned = true;
|
|
37668
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
37743
|
+
const msg = message ?? (err instanceof Error ? err.message : String(err));
|
|
37669
37744
|
try {
|
|
37670
37745
|
process.stderr.write(
|
|
37671
|
-
`[zelari] session spine
|
|
37746
|
+
`[zelari] session spine ${label} for ${this.sessionId.slice(0, 8)}\u2026: ${msg} (transcript continues on the 1.x log)
|
|
37672
37747
|
`
|
|
37673
37748
|
);
|
|
37674
37749
|
} catch {
|
|
@@ -38029,9 +38104,9 @@ function spillToolOutput(fullText, meta3) {
|
|
|
38029
38104
|
const rnd = randomBytes3(3).toString("hex");
|
|
38030
38105
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
38031
38106
|
const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
|
|
38032
|
-
const
|
|
38033
|
-
writeFileSync11(
|
|
38034
|
-
return
|
|
38107
|
+
const path92 = join14(dir, file2);
|
|
38108
|
+
writeFileSync11(path92, fullText, "utf8");
|
|
38109
|
+
return path92;
|
|
38035
38110
|
} catch {
|
|
38036
38111
|
return null;
|
|
38037
38112
|
}
|
|
@@ -38077,10 +38152,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
|
|
|
38077
38152
|
${tail2}`;
|
|
38078
38153
|
}
|
|
38079
38154
|
if (doSpill) {
|
|
38080
|
-
const
|
|
38081
|
-
if (
|
|
38155
|
+
const path92 = spillToolOutput(text, { toolName: opts.toolName });
|
|
38156
|
+
if (path92) {
|
|
38082
38157
|
const spillNote = `
|
|
38083
|
-
\u2026 [full output spilled to: ${
|
|
38158
|
+
\u2026 [full output spilled to: ${path92} \u2014 re-read with read_file if you need the complete text] \u2026`;
|
|
38084
38159
|
if (preview.includes("] \u2026\n")) {
|
|
38085
38160
|
preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
|
|
38086
38161
|
`);
|
|
@@ -42052,28 +42127,28 @@ var init_storage = __esm({
|
|
|
42052
42127
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
42053
42128
|
Storage = class {
|
|
42054
42129
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
42055
|
-
read(
|
|
42056
|
-
if (!existsSync19(
|
|
42057
|
-
throw new Error(`File not found: ${
|
|
42130
|
+
read(path92) {
|
|
42131
|
+
if (!existsSync19(path92)) {
|
|
42132
|
+
throw new Error(`File not found: ${path92}`);
|
|
42058
42133
|
}
|
|
42059
|
-
const md = readFileSync16(
|
|
42134
|
+
const md = readFileSync16(path92, "utf8");
|
|
42060
42135
|
return parseFrontmatter(md);
|
|
42061
42136
|
}
|
|
42062
42137
|
/** Read a Markdown file; returns null if not found. */
|
|
42063
|
-
readIfExists(
|
|
42064
|
-
if (!existsSync19(
|
|
42065
|
-
return this.read(
|
|
42138
|
+
readIfExists(path92) {
|
|
42139
|
+
if (!existsSync19(path92)) return null;
|
|
42140
|
+
return this.read(path92);
|
|
42066
42141
|
}
|
|
42067
42142
|
/**
|
|
42068
42143
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
42069
42144
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
42070
42145
|
*/
|
|
42071
|
-
write(
|
|
42072
|
-
mkdirSync10(dirname2(
|
|
42073
|
-
const tmp =
|
|
42146
|
+
write(path92, meta3, body) {
|
|
42147
|
+
mkdirSync10(dirname2(path92), { recursive: true });
|
|
42148
|
+
const tmp = path92 + ".tmp-" + process.pid;
|
|
42074
42149
|
const md = serializeFrontmatter(meta3, body);
|
|
42075
42150
|
writeFileSync13(tmp, md, "utf8");
|
|
42076
|
-
renameSync(tmp,
|
|
42151
|
+
renameSync(tmp, path92);
|
|
42077
42152
|
}
|
|
42078
42153
|
/** List all .md files in a directory (non-recursive). */
|
|
42079
42154
|
listMarkdown(dir) {
|
|
@@ -42135,8 +42210,8 @@ function nextPlanTaskId(store6) {
|
|
|
42135
42210
|
return `t${store6.counter}`;
|
|
42136
42211
|
}
|
|
42137
42212
|
function writePlanTaskArtifact(rootDir, task) {
|
|
42138
|
-
const
|
|
42139
|
-
mkdirSync11(dirname3(
|
|
42213
|
+
const path92 = join18(rootDir, "plan-tasks", `${task.id}.md`);
|
|
42214
|
+
mkdirSync11(dirname3(path92), { recursive: true });
|
|
42140
42215
|
const meta3 = {
|
|
42141
42216
|
kind: "task",
|
|
42142
42217
|
id: task.id,
|
|
@@ -42157,7 +42232,7 @@ function writePlanTaskArtifact(rootDir, task) {
|
|
|
42157
42232
|
task.notes?.trim() ? task.notes.trim() : "_(no notes)_",
|
|
42158
42233
|
""
|
|
42159
42234
|
].filter((l) => l !== null).join("\n");
|
|
42160
|
-
new Storage().write(
|
|
42235
|
+
new Storage().write(path92, meta3, body);
|
|
42161
42236
|
}
|
|
42162
42237
|
function loadHandle(rootDir) {
|
|
42163
42238
|
const jsonPath = join18(rootDir, "plan.json");
|
|
@@ -42863,6 +42938,100 @@ var init_inspectCommand = __esm({
|
|
|
42863
42938
|
}
|
|
42864
42939
|
});
|
|
42865
42940
|
|
|
42941
|
+
// src/cli/safety/selfKillGuard.ts
|
|
42942
|
+
function cleanToken(raw) {
|
|
42943
|
+
return raw.replace(/^["']+|["',]+\s*$/g, "").trim();
|
|
42944
|
+
}
|
|
42945
|
+
function isProtectedImage(name) {
|
|
42946
|
+
return PROTECTED_IMAGE_RE.test(cleanToken(name));
|
|
42947
|
+
}
|
|
42948
|
+
function stripSubstitutions(cmd) {
|
|
42949
|
+
return cmd.replace(/\$\([^)]*\)/g, " ( ) ").replace(/\$\{[^}]*\}/g, " ").replace(/`[^`]*`/g, " ` ` ");
|
|
42950
|
+
}
|
|
42951
|
+
function findImageKill(cmd) {
|
|
42952
|
+
const im = cmd.match(/\/{1,2}im\s+["']?([a-z0-9_.-]+)/i);
|
|
42953
|
+
if (im && /\btaskkill\b/i.test(cmd) && isProtectedImage(im[1])) {
|
|
42954
|
+
return `taskkill /IM ${cleanToken(im[1])}`;
|
|
42955
|
+
}
|
|
42956
|
+
const fi = cmd.match(/imagename\s+eq\s+["']?([a-z0-9_.-]+)/i);
|
|
42957
|
+
if (fi && /\btaskkill\b/i.test(cmd) && isProtectedImage(fi[1])) {
|
|
42958
|
+
return `taskkill /FI "IMAGENAME eq ${cleanToken(fi[1])}"`;
|
|
42959
|
+
}
|
|
42960
|
+
const nm = cmd.match(/\b(?:stop-process|kill)\b[^|;&]*-name\s+["']?([a-z0-9_.-]+)/i);
|
|
42961
|
+
if (nm && isProtectedImage(nm[1])) {
|
|
42962
|
+
return `Stop-Process -Name ${cleanToken(nm[1])}`;
|
|
42963
|
+
}
|
|
42964
|
+
if (/\bget-process\b[^|;&]*\bnode(?:\.exe)?\b/i.test(cmd) && /\|\s*[^|]*?(?:stop-process|\.\s*kill\s*\(|\bkill\b)/i.test(cmd)) {
|
|
42965
|
+
return "Get-Process node | Stop-Process";
|
|
42966
|
+
}
|
|
42967
|
+
if (/\bpkill\b[^|;&]*\bnode(?:\.exe)?\b/i.test(cmd)) return "pkill node";
|
|
42968
|
+
if (/\bkillall\b[^|;&]*\bnode(?:\.exe)?\b/i.test(cmd)) return "killall node";
|
|
42969
|
+
if (/\bwmic\b[^|;&]*name\s*=\s*["']?node(?:\.exe)?["']?/i.test(cmd) && /\b(?:delete|terminate)\b/i.test(cmd)) {
|
|
42970
|
+
return "wmic process delete node.exe";
|
|
42971
|
+
}
|
|
42972
|
+
return null;
|
|
42973
|
+
}
|
|
42974
|
+
function findPsPipelineKill(cmd) {
|
|
42975
|
+
if (!/\bps\b[^|;&]*\|\s*(?:grep|findstr|awk|sed)[^|;&]*\bnode(?:\.exe)?\b/i.test(cmd)) {
|
|
42976
|
+
return null;
|
|
42977
|
+
}
|
|
42978
|
+
if (!/\b(?:xargs\s+)?(?:kill|taskkill|pkill|killall|stop-process)\b/i.test(cmd)) {
|
|
42979
|
+
return null;
|
|
42980
|
+
}
|
|
42981
|
+
return "ps | grep node | kill";
|
|
42982
|
+
}
|
|
42983
|
+
function findProtectedPidKill(cmd, ctx) {
|
|
42984
|
+
const protectedPids = /* @__PURE__ */ new Set([
|
|
42985
|
+
ctx.selfPid,
|
|
42986
|
+
...ctx.parentPid !== void 0 ? [ctx.parentPid] : [],
|
|
42987
|
+
...ctx.extraProtectedPids ?? []
|
|
42988
|
+
]);
|
|
42989
|
+
const hit = (pid, shape) => protectedPids.has(pid) ? `${shape} ${pid}` : null;
|
|
42990
|
+
const stripped = stripSubstitutions(cmd);
|
|
42991
|
+
for (const m of stripped.matchAll(/\/{1,2}pid(?:list)?\s+([\d,\s]+)/gi)) {
|
|
42992
|
+
for (const tok of m[1].split(/[\s,]+/)) {
|
|
42993
|
+
const pid = Number.parseInt(tok, 10);
|
|
42994
|
+
if (Number.isFinite(pid) && pid > 0) {
|
|
42995
|
+
const h = hit(pid, "taskkill /PID");
|
|
42996
|
+
if (h) return h;
|
|
42997
|
+
}
|
|
42998
|
+
}
|
|
42999
|
+
}
|
|
43000
|
+
for (const m of stripped.matchAll(/\b(?:stop-process|kill)\b[^|;&]*?-(?:id|pid)\s+(\d+)/gi)) {
|
|
43001
|
+
const h = hit(Number.parseInt(m[1], 10), "Stop-Process -Id");
|
|
43002
|
+
if (h) return h;
|
|
43003
|
+
}
|
|
43004
|
+
for (const m of stripped.matchAll(/\bkill\b([^|;&]*)/gi)) {
|
|
43005
|
+
for (const tok of m[1].split(/\s+/)) {
|
|
43006
|
+
if (!/^\d+$/.test(tok)) continue;
|
|
43007
|
+
const h = hit(Number.parseInt(tok, 10), "kill");
|
|
43008
|
+
if (h) return h;
|
|
43009
|
+
}
|
|
43010
|
+
}
|
|
43011
|
+
return null;
|
|
43012
|
+
}
|
|
43013
|
+
function blockedVerdict(reason, match) {
|
|
43014
|
+
return { blocked: true, reason, match, message: SELF_KILL_DENIAL_MESSAGE };
|
|
43015
|
+
}
|
|
43016
|
+
function inspectCommand(command, ctx) {
|
|
43017
|
+
if (typeof command !== "string" || command.length === 0) return { blocked: false };
|
|
43018
|
+
const imageMatch = findImageKill(command);
|
|
43019
|
+
if (imageMatch) return blockedVerdict("node-image", imageMatch);
|
|
43020
|
+
const pipelineMatch = findPsPipelineKill(command);
|
|
43021
|
+
if (pipelineMatch) return blockedVerdict("ps-pipeline", pipelineMatch);
|
|
43022
|
+
const pidMatch = findProtectedPidKill(command, ctx);
|
|
43023
|
+
if (pidMatch) return blockedVerdict("protected-pid", pidMatch);
|
|
43024
|
+
return { blocked: false };
|
|
43025
|
+
}
|
|
43026
|
+
var SELF_KILL_DENIAL_MESSAGE, PROTECTED_IMAGE_RE;
|
|
43027
|
+
var init_selfKillGuard = __esm({
|
|
43028
|
+
"src/cli/safety/selfKillGuard.ts"() {
|
|
43029
|
+
"use strict";
|
|
43030
|
+
SELF_KILL_DENIAL_MESSAGE = "Blocked: this command would kill the agent host process itself (node image / own process tree). To stop a dev server, kill by PORT instead: run `netstat -ano | findstr :<port>` to find the listener PID, then `taskkill //PID <listener-pid>` \u2014 never kill node by image name.";
|
|
43031
|
+
PROTECTED_IMAGE_RE = /^(?:node(?:\.exe)?|zelari(?:-code)?(?:\.exe)?)$/i;
|
|
43032
|
+
}
|
|
43033
|
+
});
|
|
43034
|
+
|
|
42866
43035
|
// src/cli/safety/policyLoadMode.ts
|
|
42867
43036
|
var policyLoadMode_exports = {};
|
|
42868
43037
|
__export(policyLoadMode_exports, {
|
|
@@ -43252,6 +43421,13 @@ function createExecProcessTool(root, opts = {}) {
|
|
|
43252
43421
|
if (blocked) {
|
|
43253
43422
|
return typedErr(`[shell-blocked] exec_process refused (${blocked.reason}): ${blocked.pattern}`);
|
|
43254
43423
|
}
|
|
43424
|
+
const selfKill = inspectCommand([input.program, ...argv].join(" "), {
|
|
43425
|
+
selfPid: process.pid,
|
|
43426
|
+
parentPid: process.ppid
|
|
43427
|
+
});
|
|
43428
|
+
if (selfKill.blocked && selfKill.message) {
|
|
43429
|
+
return typedErr(`[self-kill] exec_process refused: ${selfKill.message}`);
|
|
43430
|
+
}
|
|
43255
43431
|
let cwd;
|
|
43256
43432
|
try {
|
|
43257
43433
|
cwd = resolveSandboxedPath(input.cwd ?? ".", { root });
|
|
@@ -43326,6 +43502,7 @@ var init_execProcess = __esm({
|
|
|
43326
43502
|
init_zod();
|
|
43327
43503
|
init_toolTypes();
|
|
43328
43504
|
init_shellBlocklist();
|
|
43505
|
+
init_selfKillGuard();
|
|
43329
43506
|
init_sandboxPath();
|
|
43330
43507
|
init_osJail();
|
|
43331
43508
|
execProcessInputSchema = external_exports.object({
|
|
@@ -44725,7 +44902,10 @@ var init_semantic2 = __esm({
|
|
|
44725
44902
|
// src/cli/provider/openai-compatible.ts
|
|
44726
44903
|
var openai_compatible_exports = {};
|
|
44727
44904
|
__export(openai_compatible_exports, {
|
|
44905
|
+
PROVIDER_CONNECT_TIMEOUT_MS: () => PROVIDER_CONNECT_TIMEOUT_MS,
|
|
44728
44906
|
PROVIDER_ENDPOINTS: () => PROVIDER_ENDPOINTS,
|
|
44907
|
+
PROVIDER_STREAM_IDLE_MS: () => PROVIDER_STREAM_IDLE_MS,
|
|
44908
|
+
PROVIDER_STREAM_MAX_MS: () => PROVIDER_STREAM_MAX_MS,
|
|
44729
44909
|
dataUriFromImage: () => dataUriFromImage,
|
|
44730
44910
|
modelSupportsVision: () => modelSupportsVision,
|
|
44731
44911
|
openaiCompatibleProvider: () => openaiCompatibleProvider,
|
|
@@ -45828,21 +46008,21 @@ function normalizeAuth(auth) {
|
|
|
45828
46008
|
return "agent";
|
|
45829
46009
|
}
|
|
45830
46010
|
function readSecrets() {
|
|
45831
|
-
const
|
|
45832
|
-
if (!existsSync25(
|
|
46011
|
+
const path92 = getSshSecretsPath();
|
|
46012
|
+
if (!existsSync25(path92)) return {};
|
|
45833
46013
|
try {
|
|
45834
|
-
return JSON.parse(readFileSync20(
|
|
46014
|
+
return JSON.parse(readFileSync20(path92, "utf8"));
|
|
45835
46015
|
} catch {
|
|
45836
46016
|
return {};
|
|
45837
46017
|
}
|
|
45838
46018
|
}
|
|
45839
46019
|
function writeSecrets(data) {
|
|
45840
|
-
const
|
|
45841
|
-
mkdirSync12(dirname4(
|
|
45842
|
-
writeFileSync15(
|
|
46020
|
+
const path92 = getSshSecretsPath();
|
|
46021
|
+
mkdirSync12(dirname4(path92), { recursive: true });
|
|
46022
|
+
writeFileSync15(path92, `${JSON.stringify(data, null, 2)}
|
|
45843
46023
|
`, "utf8");
|
|
45844
46024
|
try {
|
|
45845
|
-
chmodSync(
|
|
46025
|
+
chmodSync(path92, 384);
|
|
45846
46026
|
} catch {
|
|
45847
46027
|
}
|
|
45848
46028
|
}
|
|
@@ -45871,10 +46051,10 @@ function deleteSshPassword(id3) {
|
|
|
45871
46051
|
writeSecrets({ passwords });
|
|
45872
46052
|
}
|
|
45873
46053
|
function readStore2() {
|
|
45874
|
-
const
|
|
45875
|
-
if (!existsSync25(
|
|
46054
|
+
const path92 = getSshTargetsPath();
|
|
46055
|
+
if (!existsSync25(path92)) return [];
|
|
45876
46056
|
try {
|
|
45877
|
-
const parsed = JSON.parse(readFileSync20(
|
|
46057
|
+
const parsed = JSON.parse(readFileSync20(path92, "utf8"));
|
|
45878
46058
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
45879
46059
|
return list.filter(
|
|
45880
46060
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -45889,11 +46069,11 @@ function readStore2() {
|
|
|
45889
46069
|
}
|
|
45890
46070
|
}
|
|
45891
46071
|
function writeStore2(targets) {
|
|
45892
|
-
const
|
|
45893
|
-
mkdirSync12(dirname4(
|
|
46072
|
+
const path92 = getSshTargetsPath();
|
|
46073
|
+
mkdirSync12(dirname4(path92), { recursive: true });
|
|
45894
46074
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
45895
46075
|
writeFileSync15(
|
|
45896
|
-
|
|
46076
|
+
path92,
|
|
45897
46077
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
45898
46078
|
`,
|
|
45899
46079
|
"utf8"
|
|
@@ -46139,11 +46319,11 @@ function formatSshTargetsForPrompt() {
|
|
|
46139
46319
|
];
|
|
46140
46320
|
for (const t of targets) {
|
|
46141
46321
|
const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
|
|
46142
|
-
const
|
|
46322
|
+
const path92 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
|
|
46143
46323
|
const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
|
|
46144
46324
|
const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
|
|
46145
46325
|
lines.push(
|
|
46146
|
-
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${
|
|
46326
|
+
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path92}${tags}${allow}`
|
|
46147
46327
|
);
|
|
46148
46328
|
}
|
|
46149
46329
|
return lines.join("\n");
|
|
@@ -46760,14 +46940,27 @@ function anthropicMessagesProvider(config2) {
|
|
|
46760
46940
|
const base2 = config2.baseUrl.replace(/\/$/, "").replace(/\/v1$/, "");
|
|
46761
46941
|
const url2 = `${base2}/v1/messages`;
|
|
46762
46942
|
let response;
|
|
46943
|
+
const connectController = new AbortController();
|
|
46944
|
+
const connectTimer = setTimeout(
|
|
46945
|
+
() => connectController.abort(
|
|
46946
|
+
new Error(
|
|
46947
|
+
`Provider connect timeout after ${Math.round(PROVIDER_CONNECT_TIMEOUT_MS / 1e3)}s (no response headers). Override ZELARI_PROVIDER_CONNECT_TIMEOUT_MS.`
|
|
46948
|
+
)
|
|
46949
|
+
),
|
|
46950
|
+
PROVIDER_CONNECT_TIMEOUT_MS
|
|
46951
|
+
);
|
|
46952
|
+
const signals = [connectController.signal];
|
|
46953
|
+
if (params.signal) signals.push(params.signal);
|
|
46763
46954
|
try {
|
|
46764
46955
|
response = await fetch(url2, {
|
|
46765
46956
|
method: "POST",
|
|
46766
46957
|
headers: authHeaders(config2.apiKey, ttlPref === "1h"),
|
|
46767
46958
|
body: JSON.stringify(body),
|
|
46768
|
-
signal:
|
|
46959
|
+
signal: signals.length === 1 ? signals[0] : AbortSignal.any(signals)
|
|
46769
46960
|
});
|
|
46961
|
+
clearTimeout(connectTimer);
|
|
46770
46962
|
} catch (err) {
|
|
46963
|
+
clearTimeout(connectTimer);
|
|
46771
46964
|
yield {
|
|
46772
46965
|
kind: "error",
|
|
46773
46966
|
message: `Network error: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -46802,9 +46995,17 @@ function anthropicMessagesProvider(config2) {
|
|
|
46802
46995
|
};
|
|
46803
46996
|
currentTool = null;
|
|
46804
46997
|
};
|
|
46998
|
+
const streamStartedAt = Date.now();
|
|
46999
|
+
let lastUsefulAt = streamStartedAt;
|
|
47000
|
+
const streamDeadline = streamStartedAt + PROVIDER_STREAM_MAX_MS;
|
|
46805
47001
|
try {
|
|
46806
47002
|
while (true) {
|
|
46807
|
-
const { value, done } = await reader
|
|
47003
|
+
const { value, done } = await readChunkWithTimeout(reader, {
|
|
47004
|
+
idleMs: PROVIDER_STREAM_IDLE_MS,
|
|
47005
|
+
deadlineMs: streamDeadline,
|
|
47006
|
+
signal: params.signal,
|
|
47007
|
+
lastUsefulAt: () => lastUsefulAt
|
|
47008
|
+
});
|
|
46808
47009
|
if (done) break;
|
|
46809
47010
|
buffer += decoder.decode(value, { stream: true });
|
|
46810
47011
|
const lines = buffer.split("\n");
|
|
@@ -46821,6 +47022,7 @@ function anthropicMessagesProvider(config2) {
|
|
|
46821
47022
|
continue;
|
|
46822
47023
|
}
|
|
46823
47024
|
const type = ev.type;
|
|
47025
|
+
if (type !== "ping") lastUsefulAt = Date.now();
|
|
46824
47026
|
if (type === "content_block_delta") {
|
|
46825
47027
|
const delta = ev.delta;
|
|
46826
47028
|
if (delta?.type === "text_delta" && typeof delta.text === "string") {
|
|
@@ -46894,6 +47096,7 @@ var ANTHROPIC_VERSION, ANTHROPIC_BETA, ANTHROPIC_BETA_EXTENDED_CACHE_TTL;
|
|
|
46894
47096
|
var init_anthropic = __esm({
|
|
46895
47097
|
"src/cli/provider/anthropic.ts"() {
|
|
46896
47098
|
"use strict";
|
|
47099
|
+
init_openai_compatible();
|
|
46897
47100
|
init_chatStats();
|
|
46898
47101
|
init_thinking();
|
|
46899
47102
|
ANTHROPIC_VERSION = "2023-06-01";
|
|
@@ -46972,14 +47175,27 @@ function chatgptResponsesProvider(config2) {
|
|
|
46972
47175
|
const base2 = config2.baseUrl.replace(/\/$/, "");
|
|
46973
47176
|
const url2 = `${base2}/responses`;
|
|
46974
47177
|
let response;
|
|
47178
|
+
const connectController = new AbortController();
|
|
47179
|
+
const connectTimer = setTimeout(
|
|
47180
|
+
() => connectController.abort(
|
|
47181
|
+
new Error(
|
|
47182
|
+
`Provider connect timeout after ${Math.round(PROVIDER_CONNECT_TIMEOUT_MS / 1e3)}s (no response headers). Override ZELARI_PROVIDER_CONNECT_TIMEOUT_MS.`
|
|
47183
|
+
)
|
|
47184
|
+
),
|
|
47185
|
+
PROVIDER_CONNECT_TIMEOUT_MS
|
|
47186
|
+
);
|
|
47187
|
+
const signals = [connectController.signal];
|
|
47188
|
+
if (params.signal) signals.push(params.signal);
|
|
46975
47189
|
try {
|
|
46976
47190
|
response = await fetch(url2, {
|
|
46977
47191
|
method: "POST",
|
|
46978
47192
|
headers: headers(config2),
|
|
46979
47193
|
body: JSON.stringify(body),
|
|
46980
|
-
signal:
|
|
47194
|
+
signal: signals.length === 1 ? signals[0] : AbortSignal.any(signals)
|
|
46981
47195
|
});
|
|
47196
|
+
clearTimeout(connectTimer);
|
|
46982
47197
|
} catch (err) {
|
|
47198
|
+
clearTimeout(connectTimer);
|
|
46983
47199
|
yield {
|
|
46984
47200
|
kind: "error",
|
|
46985
47201
|
message: `Network error: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -47009,9 +47225,17 @@ function chatgptResponsesProvider(config2) {
|
|
|
47009
47225
|
emittedTool = true;
|
|
47010
47226
|
yield { kind: "tool_call", toolCallId: t.id, toolName: t.name, args };
|
|
47011
47227
|
};
|
|
47228
|
+
const streamStartedAt = Date.now();
|
|
47229
|
+
let lastUsefulAt = streamStartedAt;
|
|
47230
|
+
const streamDeadline = streamStartedAt + PROVIDER_STREAM_MAX_MS;
|
|
47012
47231
|
try {
|
|
47013
47232
|
while (true) {
|
|
47014
|
-
const { value, done } = await reader
|
|
47233
|
+
const { value, done } = await readChunkWithTimeout(reader, {
|
|
47234
|
+
idleMs: PROVIDER_STREAM_IDLE_MS,
|
|
47235
|
+
deadlineMs: streamDeadline,
|
|
47236
|
+
signal: params.signal,
|
|
47237
|
+
lastUsefulAt: () => lastUsefulAt
|
|
47238
|
+
});
|
|
47015
47239
|
if (done) break;
|
|
47016
47240
|
buffer += decoder.decode(value, { stream: true });
|
|
47017
47241
|
const lines = buffer.split("\n");
|
|
@@ -47028,6 +47252,7 @@ function chatgptResponsesProvider(config2) {
|
|
|
47028
47252
|
continue;
|
|
47029
47253
|
}
|
|
47030
47254
|
const type = typeof ev.type === "string" ? ev.type : "";
|
|
47255
|
+
if (type) lastUsefulAt = Date.now();
|
|
47031
47256
|
if (type === "response.output_text.delta" && typeof ev.delta === "string") {
|
|
47032
47257
|
yield { kind: "text", delta: ev.delta };
|
|
47033
47258
|
} else if (type === "response.reasoning_text.delta" && typeof ev.delta === "string") {
|
|
@@ -47083,6 +47308,7 @@ function chatgptResponsesProvider(config2) {
|
|
|
47083
47308
|
var init_chatgpt = __esm({
|
|
47084
47309
|
"src/cli/provider/chatgpt.ts"() {
|
|
47085
47310
|
"use strict";
|
|
47311
|
+
init_openai_compatible();
|
|
47086
47312
|
init_thinking();
|
|
47087
47313
|
}
|
|
47088
47314
|
});
|
|
@@ -49152,6 +49378,23 @@ function wrapWithShellSafety(original, audit, sessionId2, root, jail) {
|
|
|
49152
49378
|
}
|
|
49153
49379
|
throw err;
|
|
49154
49380
|
}
|
|
49381
|
+
const selfKill = inspectCommand(cmd, { selfPid: process.pid, parentPid: process.ppid });
|
|
49382
|
+
if (selfKill.blocked && selfKill.message) {
|
|
49383
|
+
await audit.append({
|
|
49384
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
49385
|
+
sessionId: sessionId2,
|
|
49386
|
+
tool: original.name,
|
|
49387
|
+
args: redactForAudit(args),
|
|
49388
|
+
ok: false,
|
|
49389
|
+
resultSummary: selfKill.match ?? "self_kill",
|
|
49390
|
+
durationMs: 0,
|
|
49391
|
+
error: "self_kill_blocked"
|
|
49392
|
+
});
|
|
49393
|
+
return {
|
|
49394
|
+
ok: false,
|
|
49395
|
+
error: `[self-kill] ${selfKill.message}`
|
|
49396
|
+
};
|
|
49397
|
+
}
|
|
49155
49398
|
}
|
|
49156
49399
|
const rawCwd = args["cwd"];
|
|
49157
49400
|
try {
|
|
@@ -49278,6 +49521,7 @@ var init_toolRegistry = __esm({
|
|
|
49278
49521
|
init_resourceClaims();
|
|
49279
49522
|
init_osJail();
|
|
49280
49523
|
init_toolResultCache();
|
|
49524
|
+
init_selfKillGuard();
|
|
49281
49525
|
init_toolTypes();
|
|
49282
49526
|
init_skills2();
|
|
49283
49527
|
HARNESS_BUILTIN_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -54585,8 +54829,8 @@ function readPlan(ctx) {
|
|
|
54585
54829
|
} catch {
|
|
54586
54830
|
}
|
|
54587
54831
|
}
|
|
54588
|
-
const
|
|
54589
|
-
const doc = ctx.storage.readIfExists(
|
|
54832
|
+
const path92 = workspaceFile(ctx.rootDir, "plan");
|
|
54833
|
+
const doc = ctx.storage.readIfExists(path92);
|
|
54590
54834
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
54591
54835
|
const meta3 = doc.meta;
|
|
54592
54836
|
return {
|
|
@@ -54764,7 +55008,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
54764
55008
|
dueDate: input.dueDate,
|
|
54765
55009
|
targetVersion: version2
|
|
54766
55010
|
});
|
|
54767
|
-
const
|
|
55011
|
+
const path92 = join31(ctx.rootDir, "milestones", `${id3}.md`);
|
|
54768
55012
|
const meta3 = {
|
|
54769
55013
|
kind: "milestone",
|
|
54770
55014
|
id: id3,
|
|
@@ -54781,7 +55025,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
54781
55025
|
`Target version: ${version2}`,
|
|
54782
55026
|
""
|
|
54783
55027
|
].join("\n");
|
|
54784
|
-
ctx.storage.write(
|
|
55028
|
+
ctx.storage.write(path92, meta3, body);
|
|
54785
55029
|
return { id: id3, created: true };
|
|
54786
55030
|
}
|
|
54787
55031
|
function readPlanSummary(ctx) {
|
|
@@ -54985,7 +55229,7 @@ function addIdeaStub(ctx) {
|
|
|
54985
55229
|
const tags = args["tags"] ?? [];
|
|
54986
55230
|
const category = args["category"] ?? "General";
|
|
54987
55231
|
const id3 = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
54988
|
-
const
|
|
55232
|
+
const path92 = workspaceArtifact(ctx.rootDir, "decisions", id3);
|
|
54989
55233
|
const meta3 = {
|
|
54990
55234
|
kind: "adr",
|
|
54991
55235
|
status: "proposed",
|
|
@@ -55011,7 +55255,7 @@ function addIdeaStub(ctx) {
|
|
|
55011
55255
|
...consequences.map((c) => `- ${c}`),
|
|
55012
55256
|
""
|
|
55013
55257
|
].join("\n");
|
|
55014
|
-
ctx.storage.write(
|
|
55258
|
+
ctx.storage.write(path92, meta3, body);
|
|
55015
55259
|
return `ADR ${id3} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
55016
55260
|
});
|
|
55017
55261
|
}
|
|
@@ -55093,14 +55337,14 @@ function createDocumentStub(ctx) {
|
|
|
55093
55337
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
55094
55338
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
55095
55339
|
}
|
|
55096
|
-
const
|
|
55340
|
+
const path92 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
55097
55341
|
const meta3 = {
|
|
55098
55342
|
kind: "doc",
|
|
55099
55343
|
id: slug,
|
|
55100
55344
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
55101
55345
|
tags
|
|
55102
55346
|
};
|
|
55103
|
-
ctx.storage.write(
|
|
55347
|
+
ctx.storage.write(path92, meta3, content);
|
|
55104
55348
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
55105
55349
|
});
|
|
55106
55350
|
}
|
|
@@ -55726,10 +55970,10 @@ function getUserMcpPath() {
|
|
|
55726
55970
|
function getProjectMcpPath(projectRoot) {
|
|
55727
55971
|
return join32(projectRoot, ".zelari", "mcp.json");
|
|
55728
55972
|
}
|
|
55729
|
-
function readFile6(
|
|
55730
|
-
if (!existsSync37(
|
|
55973
|
+
function readFile6(path92) {
|
|
55974
|
+
if (!existsSync37(path92)) return {};
|
|
55731
55975
|
try {
|
|
55732
|
-
const parsed = JSON.parse(readFileSync29(
|
|
55976
|
+
const parsed = JSON.parse(readFileSync29(path92, "utf8"));
|
|
55733
55977
|
const out = {};
|
|
55734
55978
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
55735
55979
|
const hasCommand = !!cfg && typeof cfg.command === "string" && !!cfg.command.trim();
|
|
@@ -55751,10 +55995,10 @@ function readFile6(path91) {
|
|
|
55751
55995
|
return {};
|
|
55752
55996
|
}
|
|
55753
55997
|
}
|
|
55754
|
-
function writeFile2(
|
|
55755
|
-
mkdirSync16(dirname9(
|
|
55998
|
+
function writeFile2(path92, servers) {
|
|
55999
|
+
mkdirSync16(dirname9(path92), { recursive: true });
|
|
55756
56000
|
const body = { mcpServers: servers };
|
|
55757
|
-
writeFileSync18(
|
|
56001
|
+
writeFileSync18(path92, `${JSON.stringify(body, null, 2)}
|
|
55758
56002
|
`, "utf8");
|
|
55759
56003
|
}
|
|
55760
56004
|
function listMcpServers(projectRoot) {
|
|
@@ -55792,9 +56036,9 @@ function upsertMcpServer(opts) {
|
|
|
55792
56036
|
error: "either command (stdio) or url (http) is required"
|
|
55793
56037
|
};
|
|
55794
56038
|
}
|
|
55795
|
-
let
|
|
56039
|
+
let path92;
|
|
55796
56040
|
if (opts.scope === "user") {
|
|
55797
|
-
|
|
56041
|
+
path92 = getUserMcpPath();
|
|
55798
56042
|
} else {
|
|
55799
56043
|
const root = opts.projectRoot?.trim();
|
|
55800
56044
|
if (!root) {
|
|
@@ -55803,9 +56047,9 @@ function upsertMcpServer(opts) {
|
|
|
55803
56047
|
error: "projectRoot required for project scope (Open Folder first)"
|
|
55804
56048
|
};
|
|
55805
56049
|
}
|
|
55806
|
-
|
|
56050
|
+
path92 = getProjectMcpPath(root);
|
|
55807
56051
|
}
|
|
55808
|
-
const current = readFile6(
|
|
56052
|
+
const current = readFile6(path92);
|
|
55809
56053
|
current[name] = {
|
|
55810
56054
|
command: hasCommand ? opts.config.command.trim() : void 0,
|
|
55811
56055
|
args: opts.config.args,
|
|
@@ -55816,21 +56060,21 @@ function upsertMcpServer(opts) {
|
|
|
55816
56060
|
serial: opts.config.serial,
|
|
55817
56061
|
enabled: opts.config.enabled !== false
|
|
55818
56062
|
};
|
|
55819
|
-
writeFile2(
|
|
55820
|
-
return { ok: true, path:
|
|
56063
|
+
writeFile2(path92, current);
|
|
56064
|
+
return { ok: true, path: path92 };
|
|
55821
56065
|
}
|
|
55822
56066
|
function removeMcpServer(opts) {
|
|
55823
|
-
const
|
|
55824
|
-
if (!
|
|
56067
|
+
const path92 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
|
|
56068
|
+
if (!path92) {
|
|
55825
56069
|
return { ok: false, error: "projectRoot required for project scope" };
|
|
55826
56070
|
}
|
|
55827
|
-
const current = readFile6(
|
|
56071
|
+
const current = readFile6(path92);
|
|
55828
56072
|
if (!(opts.name in current)) {
|
|
55829
|
-
return { ok: false, error: `Server "${opts.name}" not found in ${
|
|
56073
|
+
return { ok: false, error: `Server "${opts.name}" not found in ${path92}` };
|
|
55830
56074
|
}
|
|
55831
56075
|
delete current[opts.name];
|
|
55832
|
-
writeFile2(
|
|
55833
|
-
return { ok: true, path:
|
|
56076
|
+
writeFile2(path92, current);
|
|
56077
|
+
return { ok: true, path: path92 };
|
|
55834
56078
|
}
|
|
55835
56079
|
var init_mcpConfigIo = __esm({
|
|
55836
56080
|
"src/cli/mcp/mcpConfigIo.ts"() {
|
|
@@ -56299,10 +56543,10 @@ import { createHash as createHash20 } from "node:crypto";
|
|
|
56299
56543
|
import { join as join34 } from "node:path";
|
|
56300
56544
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
56301
56545
|
async function readPackageJson3(projectRoot) {
|
|
56302
|
-
const
|
|
56303
|
-
if (!existsSync39(
|
|
56546
|
+
const path92 = join34(projectRoot, "package.json");
|
|
56547
|
+
if (!existsSync39(path92)) return null;
|
|
56304
56548
|
try {
|
|
56305
|
-
return JSON.parse(await readFile7(
|
|
56549
|
+
return JSON.parse(await readFile7(path92, "utf8"));
|
|
56306
56550
|
} catch {
|
|
56307
56551
|
return null;
|
|
56308
56552
|
}
|
|
@@ -56384,9 +56628,9 @@ async function genBuild(ctx) {
|
|
|
56384
56628
|
].join("\n");
|
|
56385
56629
|
}
|
|
56386
56630
|
async function genOpenQuestions(ctx) {
|
|
56387
|
-
const
|
|
56388
|
-
if (!existsSync39(
|
|
56389
|
-
const content = readFileSync31(
|
|
56631
|
+
const path92 = join34(ctx.rootDir, "risks.md");
|
|
56632
|
+
if (!existsSync39(path92)) return "_No open questions._";
|
|
56633
|
+
const content = readFileSync31(path92, "utf8");
|
|
56390
56634
|
const lines = content.split("\n");
|
|
56391
56635
|
const questions = [];
|
|
56392
56636
|
let currentTitle = "";
|
|
@@ -56660,9 +56904,9 @@ function versionKey(value) {
|
|
|
56660
56904
|
function firstString2(v) {
|
|
56661
56905
|
return typeof v === "string" && v.trim().length > 0 ? v : null;
|
|
56662
56906
|
}
|
|
56663
|
-
function readFileSyncSafe(
|
|
56907
|
+
function readFileSyncSafe(path92) {
|
|
56664
56908
|
try {
|
|
56665
|
-
return readFileSync32(
|
|
56909
|
+
return readFileSync32(path92, "utf8");
|
|
56666
56910
|
} catch {
|
|
56667
56911
|
return null;
|
|
56668
56912
|
}
|
|
@@ -57125,8 +57369,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
57125
57369
|
sources: scope.sources
|
|
57126
57370
|
} : void 0
|
|
57127
57371
|
});
|
|
57128
|
-
const
|
|
57129
|
-
completionHook = { ran: true, path:
|
|
57372
|
+
const path92 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
57373
|
+
completionHook = { ran: true, path: path92, completion };
|
|
57130
57374
|
} catch (err) {
|
|
57131
57375
|
completionHook = {
|
|
57132
57376
|
ran: true,
|
|
@@ -58462,7 +58706,7 @@ function safeSocketPath(socketPath) {
|
|
|
58462
58706
|
return socketPath.trim();
|
|
58463
58707
|
}
|
|
58464
58708
|
function startPermissionBroker(socketPath, handlers, opts) {
|
|
58465
|
-
const
|
|
58709
|
+
const path92 = safeSocketPath(socketPath);
|
|
58466
58710
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
58467
58711
|
const sockets = /* @__PURE__ */ new Set();
|
|
58468
58712
|
const server = createServer2((socket) => {
|
|
@@ -58562,10 +58806,10 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
58562
58806
|
return new Promise((resolve9, reject) => {
|
|
58563
58807
|
const onError = (err) => reject(err);
|
|
58564
58808
|
server.once("error", onError);
|
|
58565
|
-
server.listen(
|
|
58809
|
+
server.listen(path92, () => {
|
|
58566
58810
|
server.removeListener("error", onError);
|
|
58567
58811
|
resolve9({
|
|
58568
|
-
socketPath:
|
|
58812
|
+
socketPath: path92,
|
|
58569
58813
|
stop: () => new Promise((res) => {
|
|
58570
58814
|
for (const s of sockets) s.destroy();
|
|
58571
58815
|
sockets.clear();
|
|
@@ -58576,7 +58820,7 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
58576
58820
|
if (done) return;
|
|
58577
58821
|
done = true;
|
|
58578
58822
|
if (process.platform !== "win32") {
|
|
58579
|
-
unlink(
|
|
58823
|
+
unlink(path92, () => res());
|
|
58580
58824
|
} else {
|
|
58581
58825
|
res();
|
|
58582
58826
|
}
|
|
@@ -58589,11 +58833,11 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
58589
58833
|
});
|
|
58590
58834
|
}
|
|
58591
58835
|
function requestBrokerAsk(socketPath, ask, opts) {
|
|
58592
|
-
const
|
|
58836
|
+
const path92 = safeSocketPath(socketPath);
|
|
58593
58837
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
58594
58838
|
const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
|
|
58595
58839
|
return new Promise((resolve9, reject) => {
|
|
58596
|
-
const socket = connect(
|
|
58840
|
+
const socket = connect(path92);
|
|
58597
58841
|
let buffer = "";
|
|
58598
58842
|
let settled = false;
|
|
58599
58843
|
const settle = (fn) => {
|
|
@@ -58608,7 +58852,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
|
|
|
58608
58852
|
settle(
|
|
58609
58853
|
() => reject(
|
|
58610
58854
|
new Error(
|
|
58611
|
-
`permission broker unavailable at "${
|
|
58855
|
+
`permission broker unavailable at "${path92}" (connect timed out after ${connectTimeoutMs}ms)`
|
|
58612
58856
|
)
|
|
58613
58857
|
)
|
|
58614
58858
|
);
|
|
@@ -62338,7 +62582,7 @@ var MIN_NODE_MAJOR, STANDARD_BASH_PATHS2, POWERSHELL_EXES2, STANDARD_POWERSHELL_
|
|
|
62338
62582
|
var init_prereqChecks = __esm({
|
|
62339
62583
|
"src/cli/utils/prereqChecks.ts"() {
|
|
62340
62584
|
"use strict";
|
|
62341
|
-
MIN_NODE_MAJOR =
|
|
62585
|
+
MIN_NODE_MAJOR = 24;
|
|
62342
62586
|
STANDARD_BASH_PATHS2 = [
|
|
62343
62587
|
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
62344
62588
|
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
@@ -64426,7 +64670,7 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
|
|
|
64426
64670
|
skipped
|
|
64427
64671
|
};
|
|
64428
64672
|
const fsRoot = options.fsRoot ?? process.cwd();
|
|
64429
|
-
let
|
|
64673
|
+
let fs46 = null;
|
|
64430
64674
|
const pending = [];
|
|
64431
64675
|
for (const dir of dirs) {
|
|
64432
64676
|
const files = candidateFiles(dir.path);
|
|
@@ -64481,9 +64725,9 @@ async function loadExtensionsFromDirs(dirs, options = {}) {
|
|
|
64481
64725
|
skipped.push(`${file2}: missing ZelariExtension export`);
|
|
64482
64726
|
continue;
|
|
64483
64727
|
}
|
|
64484
|
-
if (!
|
|
64728
|
+
if (!fs46) fs46 = bindSandboxedFs(fsRoot);
|
|
64485
64729
|
try {
|
|
64486
|
-
await runtime.registry.registerExtension(ext, { fs:
|
|
64730
|
+
await runtime.registry.registerExtension(ext, { fs: fs46 });
|
|
64487
64731
|
runtime.loaded.push({ id: ext.id, file: file2, scope });
|
|
64488
64732
|
} catch (err) {
|
|
64489
64733
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -67797,7 +68041,7 @@ function upsertSkill(opts) {
|
|
|
67797
68041
|
}
|
|
67798
68042
|
dir = getProjectSkillsDir(root);
|
|
67799
68043
|
}
|
|
67800
|
-
const
|
|
68044
|
+
const path92 = skillFilePath(dir, name);
|
|
67801
68045
|
const content = serializeSkillMd({
|
|
67802
68046
|
name,
|
|
67803
68047
|
description,
|
|
@@ -67806,13 +68050,13 @@ function upsertSkill(opts) {
|
|
|
67806
68050
|
tools: opts.tools,
|
|
67807
68051
|
cost: opts.cost
|
|
67808
68052
|
});
|
|
67809
|
-
const parsed = parseSkillMd(content,
|
|
68053
|
+
const parsed = parseSkillMd(content, path92);
|
|
67810
68054
|
if (!parsed) {
|
|
67811
68055
|
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
67812
68056
|
}
|
|
67813
|
-
mkdirSync21(dirname13(
|
|
67814
|
-
writeFileSync24(
|
|
67815
|
-
return { ok: true, path:
|
|
68057
|
+
mkdirSync21(dirname13(path92), { recursive: true });
|
|
68058
|
+
writeFileSync24(path92, content, "utf8");
|
|
68059
|
+
return { ok: true, path: path92 };
|
|
67816
68060
|
}
|
|
67817
68061
|
function removeSkill(opts) {
|
|
67818
68062
|
const name = opts.name.trim().toLowerCase();
|
|
@@ -67830,8 +68074,8 @@ function removeSkill(opts) {
|
|
|
67830
68074
|
dir = getProjectSkillsDir(root);
|
|
67831
68075
|
}
|
|
67832
68076
|
const skillDir = join46(dir, name);
|
|
67833
|
-
const
|
|
67834
|
-
if (!existsSync52(
|
|
68077
|
+
const path92 = skillFilePath(dir, name);
|
|
68078
|
+
if (!existsSync52(path92) && !existsSync52(skillDir)) {
|
|
67835
68079
|
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
67836
68080
|
}
|
|
67837
68081
|
try {
|
|
@@ -67842,7 +68086,7 @@ function removeSkill(opts) {
|
|
|
67842
68086
|
error: err instanceof Error ? err.message : String(err)
|
|
67843
68087
|
};
|
|
67844
68088
|
}
|
|
67845
|
-
return { ok: true, path:
|
|
68089
|
+
return { ok: true, path: path92 };
|
|
67846
68090
|
}
|
|
67847
68091
|
var NAME_RE, BUILTIN_SKILL_MODULES, builtinsLoaded;
|
|
67848
68092
|
var init_skillConfigIo = __esm({
|
|
@@ -68661,12 +68905,12 @@ function ensureHome() {
|
|
|
68661
68905
|
}
|
|
68662
68906
|
}
|
|
68663
68907
|
function loadCompanionConfig() {
|
|
68664
|
-
const
|
|
68665
|
-
if (!existsSync53(
|
|
68908
|
+
const path92 = getCompanionConfigPath();
|
|
68909
|
+
if (!existsSync53(path92)) {
|
|
68666
68910
|
return { projects: [] };
|
|
68667
68911
|
}
|
|
68668
68912
|
try {
|
|
68669
|
-
const raw = JSON.parse(readFileSync41(
|
|
68913
|
+
const raw = JSON.parse(readFileSync41(path92, "utf8"));
|
|
68670
68914
|
const projects = Array.isArray(raw.projects) ? raw.projects.filter(
|
|
68671
68915
|
(p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
|
|
68672
68916
|
).map((p3) => ({
|
|
@@ -68704,16 +68948,16 @@ function loadOrCreateToken(explicit) {
|
|
|
68704
68948
|
return { token: explicit.trim(), created: false };
|
|
68705
68949
|
}
|
|
68706
68950
|
ensureHome();
|
|
68707
|
-
const
|
|
68708
|
-
if (existsSync53(
|
|
68709
|
-
const t = readFileSync41(
|
|
68951
|
+
const path92 = getCompanionTokenPath();
|
|
68952
|
+
if (existsSync53(path92)) {
|
|
68953
|
+
const t = readFileSync41(path92, "utf8").trim();
|
|
68710
68954
|
if (t) return { token: t, created: false };
|
|
68711
68955
|
}
|
|
68712
68956
|
const token = randomBytes7(24).toString("base64url");
|
|
68713
|
-
writeFileSync25(
|
|
68957
|
+
writeFileSync25(path92, token + "\n", "utf8");
|
|
68714
68958
|
try {
|
|
68715
|
-
const
|
|
68716
|
-
|
|
68959
|
+
const fs46 = __require("node:fs");
|
|
68960
|
+
fs46.chmodSync?.(path92, 384);
|
|
68717
68961
|
} catch {
|
|
68718
68962
|
}
|
|
68719
68963
|
return { token, created: true };
|
|
@@ -68738,17 +68982,17 @@ function mergeProjects(cfg, extraPaths) {
|
|
|
68738
68982
|
byId.set(p3.id, p3);
|
|
68739
68983
|
}
|
|
68740
68984
|
for (const raw of extraPaths) {
|
|
68741
|
-
const
|
|
68742
|
-
if (!
|
|
68743
|
-
let id3 = slugFromPath(
|
|
68985
|
+
const path92 = raw.trim();
|
|
68986
|
+
if (!path92) continue;
|
|
68987
|
+
let id3 = slugFromPath(path92);
|
|
68744
68988
|
let n = 2;
|
|
68745
|
-
while (byId.has(id3) && byId.get(id3).path !==
|
|
68746
|
-
id3 = `${slugFromPath(
|
|
68989
|
+
while (byId.has(id3) && byId.get(id3).path !== path92) {
|
|
68990
|
+
id3 = `${slugFromPath(path92)}-${n++}`;
|
|
68747
68991
|
}
|
|
68748
68992
|
byId.set(id3, {
|
|
68749
68993
|
id: id3,
|
|
68750
|
-
name: slugFromPath(
|
|
68751
|
-
path:
|
|
68994
|
+
name: slugFromPath(path92),
|
|
68995
|
+
path: path92
|
|
68752
68996
|
});
|
|
68753
68997
|
}
|
|
68754
68998
|
return [...byId.values()];
|
|
@@ -68795,6 +69039,63 @@ var init_config = __esm({
|
|
|
68795
69039
|
}
|
|
68796
69040
|
});
|
|
68797
69041
|
|
|
69042
|
+
// src/cli/serve/spineLockSweep.ts
|
|
69043
|
+
import { promises as fs45 } from "node:fs";
|
|
69044
|
+
import path88 from "node:path";
|
|
69045
|
+
async function sweepOrphanSpineLocks(sessionsDir, options = {}) {
|
|
69046
|
+
const dir = sessionsDir ?? resolveSessionsDir();
|
|
69047
|
+
const onSwept = options.onSwept ?? ((sessionId2, reason) => {
|
|
69048
|
+
console.error(
|
|
69049
|
+
`[zelari] spine-lock sweep: removed orphan writer.lock for session ${sessionId2} (${reason})`
|
|
69050
|
+
);
|
|
69051
|
+
});
|
|
69052
|
+
const now = options.now ?? Date.now;
|
|
69053
|
+
const probe = options.probe ?? defaultLockLivenessProbe;
|
|
69054
|
+
const result = { swept: 0, kept: 0, errors: 0 };
|
|
69055
|
+
let entries;
|
|
69056
|
+
try {
|
|
69057
|
+
entries = await fs45.readdir(dir);
|
|
69058
|
+
} catch {
|
|
69059
|
+
return result;
|
|
69060
|
+
}
|
|
69061
|
+
for (const sessionId2 of entries) {
|
|
69062
|
+
const lockPath2 = path88.join(dir, sessionId2, "writer.lock");
|
|
69063
|
+
try {
|
|
69064
|
+
const raw = await fs45.readFile(lockPath2, "utf-8");
|
|
69065
|
+
let lockInfo = {};
|
|
69066
|
+
try {
|
|
69067
|
+
lockInfo = JSON.parse(raw);
|
|
69068
|
+
} catch {
|
|
69069
|
+
result.kept += 1;
|
|
69070
|
+
continue;
|
|
69071
|
+
}
|
|
69072
|
+
const verdict = evaluateLockTakeover(lockInfo, {
|
|
69073
|
+
now: now(),
|
|
69074
|
+
probe,
|
|
69075
|
+
heartbeatStaleMs: options.heartbeatStaleMs ?? resolveHeartbeatStaleMs()
|
|
69076
|
+
});
|
|
69077
|
+
if (!verdict.takeover) {
|
|
69078
|
+
result.kept += 1;
|
|
69079
|
+
continue;
|
|
69080
|
+
}
|
|
69081
|
+
await fs45.rm(lockPath2, { force: true });
|
|
69082
|
+
result.swept += 1;
|
|
69083
|
+
onSwept(sessionId2, verdict.reason);
|
|
69084
|
+
} catch (err) {
|
|
69085
|
+
const code = err.code;
|
|
69086
|
+
if (code === "ENOENT" || code === "ENOTDIR") continue;
|
|
69087
|
+
result.errors += 1;
|
|
69088
|
+
}
|
|
69089
|
+
}
|
|
69090
|
+
return result;
|
|
69091
|
+
}
|
|
69092
|
+
var init_spineLockSweep = __esm({
|
|
69093
|
+
"src/cli/serve/spineLockSweep.ts"() {
|
|
69094
|
+
"use strict";
|
|
69095
|
+
init_session();
|
|
69096
|
+
}
|
|
69097
|
+
});
|
|
69098
|
+
|
|
68798
69099
|
// src/cli/serve/harnessServer.ts
|
|
68799
69100
|
var harnessServer_exports = {};
|
|
68800
69101
|
__export(harnessServer_exports, {
|
|
@@ -69042,6 +69343,10 @@ function startHarnessServer(options = {}) {
|
|
|
69042
69343
|
async function runHarnessServer() {
|
|
69043
69344
|
setActivePolicyLoadSurface("headless");
|
|
69044
69345
|
setActiveProofPersistenceSurface("headless");
|
|
69346
|
+
try {
|
|
69347
|
+
await sweepOrphanSpineLocks();
|
|
69348
|
+
} catch {
|
|
69349
|
+
}
|
|
69045
69350
|
process.env.ZELARI_SERVE_HARNESS = "1";
|
|
69046
69351
|
const started = startHarnessServer();
|
|
69047
69352
|
await new Promise((resolvePromise) => {
|
|
@@ -69066,6 +69371,7 @@ var init_harnessServer = __esm({
|
|
|
69066
69371
|
init_completionProofPersist();
|
|
69067
69372
|
init_policyGate();
|
|
69068
69373
|
init_policyLoadMode();
|
|
69374
|
+
init_spineLockSweep();
|
|
69069
69375
|
}
|
|
69070
69376
|
});
|
|
69071
69377
|
|
|
@@ -69723,9 +70029,9 @@ async function runCompanionServe(opts = {}) {
|
|
|
69723
70029
|
return;
|
|
69724
70030
|
}
|
|
69725
70031
|
const url2 = parseUrl(req);
|
|
69726
|
-
const
|
|
70032
|
+
const path92 = url2.pathname.replace(/\/+$/, "") || "/";
|
|
69727
70033
|
try {
|
|
69728
|
-
if (req.method === "GET" && (
|
|
70034
|
+
if (req.method === "GET" && (path92 === "/health" || path92 === "/v1/health")) {
|
|
69729
70035
|
sendJson2(res, 200, {
|
|
69730
70036
|
ok: true,
|
|
69731
70037
|
service: "zelari-companion",
|
|
@@ -69737,18 +70043,18 @@ async function runCompanionServe(opts = {}) {
|
|
|
69737
70043
|
});
|
|
69738
70044
|
return;
|
|
69739
70045
|
}
|
|
69740
|
-
if (
|
|
70046
|
+
if (path92.startsWith("/v1")) {
|
|
69741
70047
|
if (!tokenMatches(token, getBearer(req))) {
|
|
69742
70048
|
sendJson2(res, 401, { ok: false, error: "unauthorized" });
|
|
69743
70049
|
return;
|
|
69744
70050
|
}
|
|
69745
70051
|
}
|
|
69746
|
-
if (req.method === "GET" &&
|
|
70052
|
+
if (req.method === "GET" && path92 === "/v1/config") {
|
|
69747
70053
|
const snap = buildDesktopConfigSnapshot();
|
|
69748
70054
|
sendJson2(res, 200, { ok: true, ...snap });
|
|
69749
70055
|
return;
|
|
69750
70056
|
}
|
|
69751
|
-
if (req.method === "GET" &&
|
|
70057
|
+
if (req.method === "GET" && path92 === "/v1/projects") {
|
|
69752
70058
|
sendJson2(res, 200, {
|
|
69753
70059
|
ok: true,
|
|
69754
70060
|
projects: projects.map((p3) => ({
|
|
@@ -69759,7 +70065,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
69759
70065
|
});
|
|
69760
70066
|
return;
|
|
69761
70067
|
}
|
|
69762
|
-
if (req.method === "GET" &&
|
|
70068
|
+
if (req.method === "GET" && path92 === "/v1/runs") {
|
|
69763
70069
|
sendJson2(res, 200, {
|
|
69764
70070
|
ok: true,
|
|
69765
70071
|
active: runs.getActive(),
|
|
@@ -69777,7 +70083,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
69777
70083
|
});
|
|
69778
70084
|
return;
|
|
69779
70085
|
}
|
|
69780
|
-
if (req.method === "POST" &&
|
|
70086
|
+
if (req.method === "POST" && path92 === "/v1/runs") {
|
|
69781
70087
|
const raw = await readBody(req);
|
|
69782
70088
|
let body = {};
|
|
69783
70089
|
try {
|
|
@@ -69825,7 +70131,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
69825
70131
|
});
|
|
69826
70132
|
return;
|
|
69827
70133
|
}
|
|
69828
|
-
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(
|
|
70134
|
+
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path92);
|
|
69829
70135
|
if (req.method === "GET" && eventsMatch) {
|
|
69830
70136
|
const runId = eventsMatch[1];
|
|
69831
70137
|
const run = runs.getRun(runId);
|
|
@@ -69890,7 +70196,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
69890
70196
|
}, 500);
|
|
69891
70197
|
return;
|
|
69892
70198
|
}
|
|
69893
|
-
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(
|
|
70199
|
+
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path92);
|
|
69894
70200
|
if (req.method === "POST" && cancelMatch) {
|
|
69895
70201
|
const runId = cancelMatch[1];
|
|
69896
70202
|
const result = runs.cancel(runId);
|
|
@@ -69901,7 +70207,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
69901
70207
|
sendJson2(res, 200, { ok: true, cancelled: runId });
|
|
69902
70208
|
return;
|
|
69903
70209
|
}
|
|
69904
|
-
const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(
|
|
70210
|
+
const steerMatch = /^\/v1\/runs\/([^/]+)\/steer$/.exec(path92);
|
|
69905
70211
|
if (req.method === "POST" && steerMatch) {
|
|
69906
70212
|
const runId = steerMatch[1];
|
|
69907
70213
|
const raw = await readBody(req);
|
|
@@ -70068,11 +70374,11 @@ import { execSync as execSync2 } from "node:child_process";
|
|
|
70068
70374
|
import { existsSync as existsSync55, readFileSync as readFileSync42, readlinkSync, statSync as statSync10 } from "node:fs";
|
|
70069
70375
|
import { createRequire as createRequire3 } from "node:module";
|
|
70070
70376
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
70071
|
-
import
|
|
70377
|
+
import path89 from "node:path";
|
|
70072
70378
|
function findPackageRoot(start) {
|
|
70073
70379
|
let dir = start;
|
|
70074
70380
|
for (let i = 0; i < 6; i += 1) {
|
|
70075
|
-
const candidate =
|
|
70381
|
+
const candidate = path89.join(dir, "package.json");
|
|
70076
70382
|
if (existsSync55(candidate)) {
|
|
70077
70383
|
try {
|
|
70078
70384
|
const pkg = JSON.parse(readFileSync42(candidate, "utf8"));
|
|
@@ -70080,11 +70386,11 @@ function findPackageRoot(start) {
|
|
|
70080
70386
|
} catch {
|
|
70081
70387
|
}
|
|
70082
70388
|
}
|
|
70083
|
-
const parent =
|
|
70389
|
+
const parent = path89.dirname(dir);
|
|
70084
70390
|
if (parent === dir) break;
|
|
70085
70391
|
dir = parent;
|
|
70086
70392
|
}
|
|
70087
|
-
return
|
|
70393
|
+
return path89.resolve(__dirname3, "..", "..", "..");
|
|
70088
70394
|
}
|
|
70089
70395
|
function tryExec(cmd) {
|
|
70090
70396
|
try {
|
|
@@ -70098,7 +70404,7 @@ function tryExec(cmd) {
|
|
|
70098
70404
|
}
|
|
70099
70405
|
function readPackageJson4() {
|
|
70100
70406
|
try {
|
|
70101
|
-
const pkgPath =
|
|
70407
|
+
const pkgPath = path89.join(packageRoot, "package.json");
|
|
70102
70408
|
return JSON.parse(readFileSync42(pkgPath, "utf8"));
|
|
70103
70409
|
} catch {
|
|
70104
70410
|
return null;
|
|
@@ -70114,7 +70420,7 @@ function checkShim(pkgName) {
|
|
|
70114
70420
|
}
|
|
70115
70421
|
const isWin = process.platform === "win32";
|
|
70116
70422
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
70117
|
-
const shimPath =
|
|
70423
|
+
const shimPath = path89.join(prefix, shimName);
|
|
70118
70424
|
if (!existsSync55(shimPath)) {
|
|
70119
70425
|
return FAIL(
|
|
70120
70426
|
`shim not found at ${shimPath}
|
|
@@ -70142,8 +70448,8 @@ function checkShim(pkgName) {
|
|
|
70142
70448
|
fix: npm install -g ${pkgName}@latest --force`
|
|
70143
70449
|
);
|
|
70144
70450
|
}
|
|
70145
|
-
const resolved =
|
|
70146
|
-
const expected =
|
|
70451
|
+
const resolved = path89.resolve(path89.dirname(shimPath), target);
|
|
70452
|
+
const expected = path89.join(
|
|
70147
70453
|
prefix,
|
|
70148
70454
|
"node_modules",
|
|
70149
70455
|
pkgName,
|
|
@@ -70174,15 +70480,18 @@ function checkNode(pkg) {
|
|
|
70174
70480
|
return WARN(`could not parse node version: ${raw}`);
|
|
70175
70481
|
}
|
|
70176
70482
|
const major = Number(m[1]);
|
|
70177
|
-
|
|
70483
|
+
const enginesNode = pkg?.engines?.node;
|
|
70484
|
+
const requiredMajor = Number(enginesNode?.match(/\d+/)?.[0] ?? 20);
|
|
70485
|
+
if (major < requiredMajor) {
|
|
70178
70486
|
return FAIL(
|
|
70179
|
-
`node ${raw} is older than the required engines.node (>= 20.0.0)
|
|
70487
|
+
`node ${raw} is older than the required engines.node (${enginesNode ?? ">= 20.0.0"})
|
|
70488
|
+
fix: install Node.js ${requiredMajor}+ (LTS) and reopen the terminal`
|
|
70180
70489
|
);
|
|
70181
70490
|
}
|
|
70182
|
-
return OK(`node ${raw}`);
|
|
70491
|
+
return OK(`node ${raw} (engines.node ${enginesNode ?? ">= 20.0.0"})`);
|
|
70183
70492
|
}
|
|
70184
70493
|
function checkBundle() {
|
|
70185
|
-
const bundle =
|
|
70494
|
+
const bundle = path89.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
70186
70495
|
if (!existsSync55(bundle)) {
|
|
70187
70496
|
return FAIL(
|
|
70188
70497
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
@@ -70203,7 +70512,7 @@ function checkRuntimeDeps() {
|
|
|
70203
70512
|
const missing = [];
|
|
70204
70513
|
for (const dep of required2) {
|
|
70205
70514
|
try {
|
|
70206
|
-
const localReq = createRequire3(
|
|
70515
|
+
const localReq = createRequire3(path89.join(packageRoot, "package.json"));
|
|
70207
70516
|
localReq.resolve(dep);
|
|
70208
70517
|
} catch {
|
|
70209
70518
|
missing.push(dep);
|
|
@@ -70403,7 +70712,7 @@ var init_doctor = __esm({
|
|
|
70403
70712
|
init_metrics3();
|
|
70404
70713
|
init_contextGrowthSummary();
|
|
70405
70714
|
require3 = createRequire3(import.meta.url);
|
|
70406
|
-
__dirname3 =
|
|
70715
|
+
__dirname3 = path89.dirname(fileURLToPath3(import.meta.url));
|
|
70407
70716
|
packageRoot = findPackageRoot(__dirname3);
|
|
70408
70717
|
OK = (message) => ({
|
|
70409
70718
|
ok: true,
|
|
@@ -70587,7 +70896,7 @@ __export(inspectSession_exports, {
|
|
|
70587
70896
|
renderInspectReport: () => renderInspectReport,
|
|
70588
70897
|
runInspectSession: () => runInspectSession
|
|
70589
70898
|
});
|
|
70590
|
-
import
|
|
70899
|
+
import path90 from "node:path";
|
|
70591
70900
|
import { existsSync as existsSync56 } from "node:fs";
|
|
70592
70901
|
function formatLimit(limit) {
|
|
70593
70902
|
return `${Math.round(limit / 1e3)}k`;
|
|
@@ -70621,8 +70930,8 @@ function renderInspectReport(state3) {
|
|
|
70621
70930
|
}
|
|
70622
70931
|
async function runInspectSession(opts) {
|
|
70623
70932
|
const sessionsDir = resolveSessionsDir({ workspaceRoot: opts.cwd ?? process.cwd() });
|
|
70624
|
-
const sessionDir =
|
|
70625
|
-
const eventsPath =
|
|
70933
|
+
const sessionDir = path90.join(sessionsDir, opts.sessionId);
|
|
70934
|
+
const eventsPath = path90.join(sessionDir, "events.jsonl");
|
|
70626
70935
|
if (!existsSync56(sessionDir)) {
|
|
70627
70936
|
console.error(`zelari-code inspect: no session directory at ${sessionDir}`);
|
|
70628
70937
|
return 1;
|
|
@@ -70656,15 +70965,15 @@ __export(inspect_exports, {
|
|
|
70656
70965
|
collectInspectReport: () => collectInspectReport,
|
|
70657
70966
|
runInspect: () => runInspect
|
|
70658
70967
|
});
|
|
70659
|
-
import
|
|
70968
|
+
import path91 from "node:path";
|
|
70660
70969
|
import { existsSync as existsSync57, readFileSync as readFileSync43, readdirSync as readdirSync12 } from "node:fs";
|
|
70661
70970
|
import { homedir as homedir17 } from "node:os";
|
|
70662
70971
|
async function collectInspectReport(cwd = process.cwd()) {
|
|
70663
70972
|
ensureBuiltinSkillsLoadedSync();
|
|
70664
70973
|
const snap = listSkillsSnapshot(cwd);
|
|
70665
70974
|
const mcp = listMcpServers(cwd);
|
|
70666
|
-
const userMcpPath =
|
|
70667
|
-
const projectMcpPath =
|
|
70975
|
+
const userMcpPath = path91.join(homedir17(), ".zelari-code", "mcp.json");
|
|
70976
|
+
const projectMcpPath = path91.join(cwd, ".zelari", "mcp.json");
|
|
70668
70977
|
const globalHooks = globalHooksDir();
|
|
70669
70978
|
const projectHooks = projectHooksDir(cwd);
|
|
70670
70979
|
const projectTrusted = isFolderTrusted(cwd);
|
|
@@ -70692,9 +71001,9 @@ async function collectInspectReport(cwd = process.cwd()) {
|
|
|
70692
71001
|
configSources: [
|
|
70693
71002
|
{ path: userMcpPath, exists: existsSync57(userMcpPath) },
|
|
70694
71003
|
{ path: projectMcpPath, exists: existsSync57(projectMcpPath) },
|
|
70695
|
-
{ path:
|
|
70696
|
-
{ path:
|
|
70697
|
-
{ path:
|
|
71004
|
+
{ path: path91.join(homedir17(), ".zelari-code", "provider.json"), exists: existsSync57(path91.join(homedir17(), ".zelari-code", "provider.json")) },
|
|
71005
|
+
{ path: path91.join(cwd, ".zelari", "AGENTS.md"), exists: existsSync57(path91.join(cwd, ".zelari", "AGENTS.md")) },
|
|
71006
|
+
{ path: path91.join(cwd, "AGENTS.md"), exists: existsSync57(path91.join(cwd, "AGENTS.md")) }
|
|
70698
71007
|
],
|
|
70699
71008
|
skills: {
|
|
70700
71009
|
total: snap.skills.length,
|
|
@@ -70734,8 +71043,8 @@ function listJsonFiles(dir) {
|
|
|
70734
71043
|
}
|
|
70735
71044
|
function findAgentsMd(cwd) {
|
|
70736
71045
|
const candidates = [
|
|
70737
|
-
|
|
70738
|
-
|
|
71046
|
+
path91.join(cwd, "AGENTS.md"),
|
|
71047
|
+
path91.join(cwd, ".zelari", "AGENTS.md")
|
|
70739
71048
|
];
|
|
70740
71049
|
const found = [];
|
|
70741
71050
|
for (const c of candidates) {
|
|
@@ -80380,8 +80689,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
|
|
|
80380
80689
|
let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
80381
80690
|
if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
|
|
80382
80691
|
try {
|
|
80383
|
-
const
|
|
80384
|
-
name =
|
|
80692
|
+
const path92 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
80693
|
+
name = path92 && /^[a-z0-9]/.test(path92) ? path92 : "imported-skill";
|
|
80385
80694
|
} catch {
|
|
80386
80695
|
name = "imported-skill";
|
|
80387
80696
|
}
|