zelari-code 2.43.1 → 2.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -5
- package/dist/cli/companion/config.js +70 -9
- package/dist/cli/companion/config.js.map +1 -1
- package/dist/cli/companion/runManager.js +194 -9
- package/dist/cli/companion/runManager.js.map +1 -1
- package/dist/cli/companion/serve.js +223 -9
- package/dist/cli/companion/serve.js.map +1 -1
- package/dist/cli/main.bundled.js +750 -252
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/safety/toolPermissions.js +43 -17
- package/dist/cli/safety/toolPermissions.js.map +1 -1
- package/dist/cli/serve/askUserBridge.js +27 -4
- package/dist/cli/serve/askUserBridge.js.map +1 -1
- package/dist/cli/serve/harnessClient.js +14 -0
- package/dist/cli/serve/harnessClient.js.map +1 -1
- package/dist/cli/serve/harnessServer.js +38 -10
- package/dist/cli/serve/harnessServer.js.map +1 -1
- package/dist/cli/serve/permissionBridge.js +37 -8
- package/dist/cli/serve/permissionBridge.js.map +1 -1
- package/dist/cli/serve/sessionControl.js +13 -0
- package/dist/cli/serve/sessionControl.js.map +1 -1
- package/dist/cli/slashHandlers/updater.js +10 -2
- package/dist/cli/slashHandlers/updater.js.map +1 -1
- package/dist/cli/toolRegistry.js +7 -0
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/taskTool.js +10 -4
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/dist/cli/updater.js +88 -3
- package/dist/cli/updater.js.map +1 -1
- package/dist/cli/utils/doctor.js +11 -0
- package/dist/cli/utils/doctor.js.map +1 -1
- package/dist/cli/utils/prereqChecks.js +2 -2
- package/dist/cli/utils/prereqChecks.js.map +1 -1
- package/package.json +4 -5
package/dist/cli/main.bundled.js
CHANGED
|
@@ -807,7 +807,7 @@ async function openBrowser(url2) {
|
|
|
807
807
|
return { bin: "xdg-open", args: [url2] };
|
|
808
808
|
}
|
|
809
809
|
})();
|
|
810
|
-
return new Promise((
|
|
810
|
+
return new Promise((resolve11, reject) => {
|
|
811
811
|
try {
|
|
812
812
|
const child = spawn19(cmd.bin, cmd.args, {
|
|
813
813
|
stdio: "ignore",
|
|
@@ -816,9 +816,9 @@ async function openBrowser(url2) {
|
|
|
816
816
|
child.on("error", (err) => reject(err));
|
|
817
817
|
child.on("spawn", () => {
|
|
818
818
|
child.unref();
|
|
819
|
-
|
|
819
|
+
resolve11();
|
|
820
820
|
});
|
|
821
|
-
setTimeout(() =>
|
|
821
|
+
setTimeout(() => resolve11(), 100);
|
|
822
822
|
} catch (err) {
|
|
823
823
|
reject(err);
|
|
824
824
|
}
|
|
@@ -867,7 +867,7 @@ async function waitForLoopbackCallback(options) {
|
|
|
867
867
|
const host = options.host ?? "127.0.0.1";
|
|
868
868
|
const timeoutMs2 = options.timeoutMs ?? 3e5;
|
|
869
869
|
const expectedPath = options.path.startsWith("/") ? options.path : `/${options.path}`;
|
|
870
|
-
return new Promise((
|
|
870
|
+
return new Promise((resolve11, reject) => {
|
|
871
871
|
let settled = false;
|
|
872
872
|
const server = createServer((req, res) => {
|
|
873
873
|
const url2 = new URL(req.url ?? "/", `http://${host}`);
|
|
@@ -896,7 +896,7 @@ async function waitForLoopbackCallback(options) {
|
|
|
896
896
|
clearTimeout(timer);
|
|
897
897
|
server.close(() => {
|
|
898
898
|
if (err) reject(err);
|
|
899
|
-
else
|
|
899
|
+
else resolve11(value ?? {});
|
|
900
900
|
});
|
|
901
901
|
};
|
|
902
902
|
server.on("error", (err) => finish2(void 0, err));
|
|
@@ -19086,7 +19086,7 @@ function createBashTool(spawnSeam) {
|
|
|
19086
19086
|
timeoutMs: 6e4,
|
|
19087
19087
|
inputSchema: BashArgsSchema,
|
|
19088
19088
|
execute: async (args, ctx) => {
|
|
19089
|
-
return new Promise((
|
|
19089
|
+
return new Promise((resolve11) => {
|
|
19090
19090
|
const start = Date.now();
|
|
19091
19091
|
const cwd = args.cwd ?? ctx.cwd;
|
|
19092
19092
|
const resolved = resolveShell();
|
|
@@ -19113,7 +19113,7 @@ function createBashTool(spawnSeam) {
|
|
|
19113
19113
|
if (spawnSeam) {
|
|
19114
19114
|
const seamResult = spawnSeam({ program, argv, cwd, env, signal: ctx.signal });
|
|
19115
19115
|
if (seamResult.outcome !== "spawned") {
|
|
19116
|
-
|
|
19116
|
+
resolve11(typedErr(seamResult.reason));
|
|
19117
19117
|
return;
|
|
19118
19118
|
}
|
|
19119
19119
|
child = seamResult.child;
|
|
@@ -19140,14 +19140,14 @@ function createBashTool(spawnSeam) {
|
|
|
19140
19140
|
});
|
|
19141
19141
|
const timer = setTimeout(() => {
|
|
19142
19142
|
child.kill("SIGTERM");
|
|
19143
|
-
|
|
19143
|
+
resolve11(typedErr(`Bash command timed out after ${args.timeoutMs}ms. If it was waiting for interactive input: stdin is closed \u2014 pass non-interactive flags or create the files directly instead of retrying.`));
|
|
19144
19144
|
}, args.timeoutMs);
|
|
19145
19145
|
child.on("close", (code) => {
|
|
19146
19146
|
clearTimeout(timer);
|
|
19147
19147
|
const cappedStdout = stdout.slice(0, maxBuffer);
|
|
19148
19148
|
const cappedStderr = stderr.slice(0, maxBuffer);
|
|
19149
19149
|
const interactive = INTERACTIVE_CANCEL_RE.test(cappedStdout) || INTERACTIVE_CANCEL_RE.test(cappedStderr);
|
|
19150
|
-
|
|
19150
|
+
resolve11(typedOk({
|
|
19151
19151
|
stdout: cappedStdout,
|
|
19152
19152
|
stderr: cappedStderr,
|
|
19153
19153
|
exitCode: code ?? -1,
|
|
@@ -19159,7 +19159,7 @@ function createBashTool(spawnSeam) {
|
|
|
19159
19159
|
});
|
|
19160
19160
|
child.on("error", (err) => {
|
|
19161
19161
|
clearTimeout(timer);
|
|
19162
|
-
|
|
19162
|
+
resolve11(typedErr(err.message));
|
|
19163
19163
|
});
|
|
19164
19164
|
});
|
|
19165
19165
|
}
|
|
@@ -22296,7 +22296,7 @@ var init_nodeProviders = __esm({
|
|
|
22296
22296
|
const isWindows = process.platform === "win32";
|
|
22297
22297
|
const file2 = isWindows ? "cmd.exe" : "/bin/sh";
|
|
22298
22298
|
const args = isWindows ? ["/d", "/s", "/c", command] : ["-c", command];
|
|
22299
|
-
return await new Promise((
|
|
22299
|
+
return await new Promise((resolve11) => {
|
|
22300
22300
|
const child = spawn2(file2, args, {
|
|
22301
22301
|
cwd,
|
|
22302
22302
|
shell: false,
|
|
@@ -22329,7 +22329,7 @@ var init_nodeProviders = __esm({
|
|
|
22329
22329
|
});
|
|
22330
22330
|
child.on("error", (err) => {
|
|
22331
22331
|
clearTimeout(timer);
|
|
22332
|
-
|
|
22332
|
+
resolve11({
|
|
22333
22333
|
exitCode: null,
|
|
22334
22334
|
stdout,
|
|
22335
22335
|
stderr: `${stderr}${err.message}`,
|
|
@@ -22339,7 +22339,7 @@ var init_nodeProviders = __esm({
|
|
|
22339
22339
|
});
|
|
22340
22340
|
child.on("close", (code) => {
|
|
22341
22341
|
clearTimeout(timer);
|
|
22342
|
-
|
|
22342
|
+
resolve11({ exitCode: code, stdout, stderr, durationMs: Date.now() - started, timedOut });
|
|
22343
22343
|
});
|
|
22344
22344
|
});
|
|
22345
22345
|
}
|
|
@@ -22417,7 +22417,7 @@ import path16 from "node:path";
|
|
|
22417
22417
|
import crypto2 from "node:crypto";
|
|
22418
22418
|
import { spawn as spawn3 } from "node:child_process";
|
|
22419
22419
|
async function git(cwd, args) {
|
|
22420
|
-
return await new Promise((
|
|
22420
|
+
return await new Promise((resolve11, reject) => {
|
|
22421
22421
|
const child = spawn3("git", args, { cwd, shell: false });
|
|
22422
22422
|
let stdout = "";
|
|
22423
22423
|
let stderr = "";
|
|
@@ -22426,7 +22426,7 @@ async function git(cwd, args) {
|
|
|
22426
22426
|
child.on("error", (err) => reject(err));
|
|
22427
22427
|
child.on("close", (code) => {
|
|
22428
22428
|
if (code === 0)
|
|
22429
|
-
|
|
22429
|
+
resolve11(stdout);
|
|
22430
22430
|
else
|
|
22431
22431
|
reject(new Error(`git ${args.join(" ")} failed (${code}): ${stderr.trim()}`));
|
|
22432
22432
|
});
|
|
@@ -30565,8 +30565,8 @@ function wrapLegacyStream(legacyStream, params, _messages, _tools) {
|
|
|
30565
30565
|
}
|
|
30566
30566
|
if (done)
|
|
30567
30567
|
break;
|
|
30568
|
-
await new Promise((
|
|
30569
|
-
resolveNext =
|
|
30568
|
+
await new Promise((resolve11) => {
|
|
30569
|
+
resolveNext = resolve11;
|
|
30570
30570
|
});
|
|
30571
30571
|
}
|
|
30572
30572
|
await promise2;
|
|
@@ -30699,11 +30699,11 @@ var init_sessionJsonl = __esm({
|
|
|
30699
30699
|
*/
|
|
30700
30700
|
scheduleFlush() {
|
|
30701
30701
|
if (this.pending.length > 0 && !this.flushDeferred) {
|
|
30702
|
-
let
|
|
30702
|
+
let resolve11;
|
|
30703
30703
|
const promise2 = new Promise((r) => {
|
|
30704
|
-
|
|
30704
|
+
resolve11 = r;
|
|
30705
30705
|
});
|
|
30706
|
-
this.flushDeferred = { promise: promise2, resolve:
|
|
30706
|
+
this.flushDeferred = { promise: promise2, resolve: resolve11 };
|
|
30707
30707
|
}
|
|
30708
30708
|
if (this.flushTimer === null && this.pending.length > 0) {
|
|
30709
30709
|
this.flushTimer = setTimeout(() => {
|
|
@@ -31010,7 +31010,7 @@ var init_lifecycleHookRunner = __esm({
|
|
|
31010
31010
|
}
|
|
31011
31011
|
/** Spawn `command`, write JSON payload to stdin, read stdout until close. */
|
|
31012
31012
|
execCommand(command, payload, timeoutMs2, cwd) {
|
|
31013
|
-
return new Promise((
|
|
31013
|
+
return new Promise((resolve11, reject) => {
|
|
31014
31014
|
const argv = splitHookCommandLine(command);
|
|
31015
31015
|
if (argv.length === 0) {
|
|
31016
31016
|
reject(new Error("empty hook command"));
|
|
@@ -31044,7 +31044,7 @@ var init_lifecycleHookRunner = __esm({
|
|
|
31044
31044
|
reject(new Error(`exited ${code}: ${stderr.trim().slice(0, 200)}`));
|
|
31045
31045
|
return;
|
|
31046
31046
|
}
|
|
31047
|
-
|
|
31047
|
+
resolve11(stdout);
|
|
31048
31048
|
});
|
|
31049
31049
|
child.stdin?.on("error", () => {
|
|
31050
31050
|
});
|
|
@@ -38898,7 +38898,7 @@ var CORE_VERSION;
|
|
|
38898
38898
|
var init_version = __esm({
|
|
38899
38899
|
"packages/core/dist/version.js"() {
|
|
38900
38900
|
"use strict";
|
|
38901
|
-
CORE_VERSION = "2.
|
|
38901
|
+
CORE_VERSION = "2.45.0";
|
|
38902
38902
|
}
|
|
38903
38903
|
});
|
|
38904
38904
|
|
|
@@ -40116,15 +40116,48 @@ __export(updater_exports, {
|
|
|
40116
40116
|
fetchLatestVersion: () => fetchLatestVersion,
|
|
40117
40117
|
getCurrentVersion: () => getCurrentVersion,
|
|
40118
40118
|
looksLikeBrokenShim: () => looksLikeBrokenShim,
|
|
40119
|
+
nonGlobalUpdateAdvisory: () => nonGlobalUpdateAdvisory,
|
|
40119
40120
|
performUpdate: () => performUpdate,
|
|
40120
40121
|
registryUrlForTag: () => registryUrlForTag,
|
|
40121
|
-
resolveBundledNpmCli: () => resolveBundledNpmCli
|
|
40122
|
+
resolveBundledNpmCli: () => resolveBundledNpmCli,
|
|
40123
|
+
resolveInstallKind: () => resolveInstallKind
|
|
40122
40124
|
});
|
|
40123
40125
|
import { createRequire } from "node:module";
|
|
40124
|
-
import { spawn as spawn6 } from "node:child_process";
|
|
40126
|
+
import { execSync, spawn as spawn6 } from "node:child_process";
|
|
40125
40127
|
import { existsSync as existsSync14 } from "node:fs";
|
|
40128
|
+
import os2 from "node:os";
|
|
40126
40129
|
import path32 from "node:path";
|
|
40127
40130
|
import { fileURLToPath } from "node:url";
|
|
40131
|
+
function getGlobalPrefix() {
|
|
40132
|
+
try {
|
|
40133
|
+
const out = execSync("npm prefix -g", {
|
|
40134
|
+
encoding: "utf8",
|
|
40135
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
40136
|
+
}).trim();
|
|
40137
|
+
return out || null;
|
|
40138
|
+
} catch {
|
|
40139
|
+
return null;
|
|
40140
|
+
}
|
|
40141
|
+
}
|
|
40142
|
+
function normalizeForMatch2(p3) {
|
|
40143
|
+
return path32.resolve(p3).replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
40144
|
+
}
|
|
40145
|
+
function resolveInstallKind(npmPrefix = getGlobalPrefix(), packageRoot2 = PKG_ROOT) {
|
|
40146
|
+
const root = normalizeForMatch2(packageRoot2);
|
|
40147
|
+
const tmp = normalizeForMatch2(os2.tmpdir());
|
|
40148
|
+
const inTmp = tmp !== "" && (root === tmp || root.startsWith(`${tmp}/`));
|
|
40149
|
+
if (root.split("/").includes("_npx") || inTmp) return "npx";
|
|
40150
|
+
if (!npmPrefix) return "unknown";
|
|
40151
|
+
const prefix = normalizeForMatch2(npmPrefix);
|
|
40152
|
+
if (root === prefix || root.startsWith(`${prefix}/`)) return "global";
|
|
40153
|
+
return "local";
|
|
40154
|
+
}
|
|
40155
|
+
function nonGlobalUpdateAdvisory(kind2) {
|
|
40156
|
+
const where = kind2 === "npx" ? "was started via npx (from npm's cache)" : "is a local/source install";
|
|
40157
|
+
return `[update] this zelari-code ${where}, not a global install \u2014 self-update is disabled.
|
|
40158
|
+
update with: npx zelari-code@latest (always fetches the latest)
|
|
40159
|
+
or install persistently: npm install -g zelari-code (enables /update)`;
|
|
40160
|
+
}
|
|
40128
40161
|
function resolveBundledNpmCli(execPath = process.execPath) {
|
|
40129
40162
|
const dir = path32.dirname(execPath);
|
|
40130
40163
|
const candidates = [
|
|
@@ -40218,7 +40251,16 @@ async function checkForUpdate(fetcher = fetch, registryUrl) {
|
|
|
40218
40251
|
updateAvailable: cmp < 0
|
|
40219
40252
|
};
|
|
40220
40253
|
}
|
|
40221
|
-
async function performUpdate(packageName = "zelari-code", executor = spawn6, resolveNpmCli = resolveBundledNpmCli, channel) {
|
|
40254
|
+
async function performUpdate(packageName = "zelari-code", executor = spawn6, resolveNpmCli = resolveBundledNpmCli, channel, installKind = resolveInstallKind()) {
|
|
40255
|
+
if (installKind === "npx" || installKind === "local") {
|
|
40256
|
+
return {
|
|
40257
|
+
ok: false,
|
|
40258
|
+
output: nonGlobalUpdateAdvisory(installKind),
|
|
40259
|
+
error: "self-update skipped: non-global install",
|
|
40260
|
+
exitCode: null,
|
|
40261
|
+
installKind
|
|
40262
|
+
};
|
|
40263
|
+
}
|
|
40222
40264
|
const tag = channel ?? distTagForVersion(getCurrentVersion());
|
|
40223
40265
|
const args = ["install", "-g", `${packageName}@${tag}`];
|
|
40224
40266
|
const primary = await runNpm(executor, args, "shim");
|
|
@@ -40235,7 +40277,7 @@ ${fallback.output}`
|
|
|
40235
40277
|
return primary;
|
|
40236
40278
|
}
|
|
40237
40279
|
function runNpm(executor, args, mode, npmCliPath) {
|
|
40238
|
-
return new Promise((
|
|
40280
|
+
return new Promise((resolve11) => {
|
|
40239
40281
|
let stdout = "";
|
|
40240
40282
|
let stderr = "";
|
|
40241
40283
|
const stdio = ["ignore", "pipe", "pipe"];
|
|
@@ -40247,7 +40289,7 @@ function runNpm(executor, args, mode, npmCliPath) {
|
|
|
40247
40289
|
stderr += chunk.toString();
|
|
40248
40290
|
});
|
|
40249
40291
|
child.on("error", (err) => {
|
|
40250
|
-
|
|
40292
|
+
resolve11({
|
|
40251
40293
|
ok: false,
|
|
40252
40294
|
output: stdout + stderr,
|
|
40253
40295
|
error: err.message,
|
|
@@ -40256,7 +40298,7 @@ function runNpm(executor, args, mode, npmCliPath) {
|
|
|
40256
40298
|
});
|
|
40257
40299
|
child.on("close", (code) => {
|
|
40258
40300
|
const ok = code === 0;
|
|
40259
|
-
|
|
40301
|
+
resolve11({
|
|
40260
40302
|
ok,
|
|
40261
40303
|
output: stdout + stderr,
|
|
40262
40304
|
error: ok ? void 0 : `npm exited with code ${code}`,
|
|
@@ -40265,13 +40307,14 @@ function runNpm(executor, args, mode, npmCliPath) {
|
|
|
40265
40307
|
});
|
|
40266
40308
|
});
|
|
40267
40309
|
}
|
|
40268
|
-
var require2, __dirname2, REGISTRY_URL;
|
|
40310
|
+
var require2, __dirname2, PKG_ROOT, REGISTRY_URL;
|
|
40269
40311
|
var init_updater = __esm({
|
|
40270
40312
|
"src/cli/updater.ts"() {
|
|
40271
40313
|
"use strict";
|
|
40272
40314
|
init_cmdline();
|
|
40273
40315
|
require2 = createRequire(import.meta.url);
|
|
40274
40316
|
__dirname2 = path32.dirname(fileURLToPath(import.meta.url));
|
|
40317
|
+
PKG_ROOT = path32.resolve(__dirname2, "..", "..");
|
|
40275
40318
|
REGISTRY_URL = "https://registry.npmjs.org/zelari-code/latest";
|
|
40276
40319
|
}
|
|
40277
40320
|
});
|
|
@@ -42278,8 +42321,8 @@ var init_storage = __esm({
|
|
|
42278
42321
|
const prev2 = this.chains.get(key) ?? Promise.resolve();
|
|
42279
42322
|
let release = () => {
|
|
42280
42323
|
};
|
|
42281
|
-
const next = new Promise((
|
|
42282
|
-
release =
|
|
42324
|
+
const next = new Promise((resolve11) => {
|
|
42325
|
+
release = resolve11;
|
|
42283
42326
|
});
|
|
42284
42327
|
const chained = prev2.then(() => next);
|
|
42285
42328
|
this.chains.set(key, chained);
|
|
@@ -43075,14 +43118,14 @@ var init_engine2 = __esm({
|
|
|
43075
43118
|
parse: parseRuffJson
|
|
43076
43119
|
}
|
|
43077
43120
|
];
|
|
43078
|
-
defaultRunner = (cmd, args, opts) => new Promise((
|
|
43121
|
+
defaultRunner = (cmd, args, opts) => new Promise((resolve11) => {
|
|
43079
43122
|
let stdout = "";
|
|
43080
43123
|
let stderr = "";
|
|
43081
43124
|
let settled = false;
|
|
43082
43125
|
const done = (r) => {
|
|
43083
43126
|
if (settled) return;
|
|
43084
43127
|
settled = true;
|
|
43085
|
-
|
|
43128
|
+
resolve11(r);
|
|
43086
43129
|
};
|
|
43087
43130
|
let child;
|
|
43088
43131
|
try {
|
|
@@ -44137,7 +44180,7 @@ async function readChecks(cwd) {
|
|
|
44137
44180
|
}
|
|
44138
44181
|
}
|
|
44139
44182
|
function runShell(command, cwd, timeoutMs2, signal) {
|
|
44140
|
-
return new Promise((
|
|
44183
|
+
return new Promise((resolve11) => {
|
|
44141
44184
|
const isWin = process.platform === "win32";
|
|
44142
44185
|
const child = spawn8(isWin ? "cmd.exe" : "/bin/sh", isWin ? ["/c", command] : ["-c", command], {
|
|
44143
44186
|
cwd,
|
|
@@ -44151,7 +44194,7 @@ function runShell(command, cwd, timeoutMs2, signal) {
|
|
|
44151
44194
|
const finish2 = (exitCode) => {
|
|
44152
44195
|
if (settled) return;
|
|
44153
44196
|
settled = true;
|
|
44154
|
-
|
|
44197
|
+
resolve11({ exitCode, stdout, stderr });
|
|
44155
44198
|
};
|
|
44156
44199
|
const timer = setTimeout(() => {
|
|
44157
44200
|
try {
|
|
@@ -46862,8 +46905,8 @@ ${upstream}` : node.prompt,
|
|
|
46862
46905
|
if (ms <= 0) return promise2;
|
|
46863
46906
|
let timer;
|
|
46864
46907
|
const TIMED_OUT = Symbol("timeout");
|
|
46865
|
-
const timeout = new Promise((
|
|
46866
|
-
timer = setTimeout(() =>
|
|
46908
|
+
const timeout = new Promise((resolve11) => {
|
|
46909
|
+
timer = setTimeout(() => resolve11(TIMED_OUT), ms);
|
|
46867
46910
|
});
|
|
46868
46911
|
const raced = await Promise.race([promise2, timeout]).finally(() => {
|
|
46869
46912
|
if (timer) clearTimeout(timer);
|
|
@@ -46872,8 +46915,8 @@ ${upstream}` : node.prompt,
|
|
|
46872
46915
|
controller?.abort();
|
|
46873
46916
|
const graceMs = this.cancelGraceMs ?? resolveCancelGraceMs();
|
|
46874
46917
|
let graceTimer;
|
|
46875
|
-
const grace = new Promise((
|
|
46876
|
-
graceTimer = setTimeout(() =>
|
|
46918
|
+
const grace = new Promise((resolve11) => {
|
|
46919
|
+
graceTimer = setTimeout(() => resolve11(TIMED_OUT), graceMs);
|
|
46877
46920
|
});
|
|
46878
46921
|
const settled = await Promise.race([promise2, grace]).finally(() => {
|
|
46879
46922
|
if (graceTimer) clearTimeout(graceTimer);
|
|
@@ -47640,13 +47683,13 @@ ${findings || "(the reviewer reported FAIL without detail)"}`;
|
|
|
47640
47683
|
async function runAutoVerifyAfterGeneral(opts) {
|
|
47641
47684
|
const g = globalThis;
|
|
47642
47685
|
g.__zelariGeneralVerifyDebt = { description: opts.original.description };
|
|
47643
|
-
const emitVerifyPhase = (detail2, ok) => {
|
|
47686
|
+
const emitVerifyPhase = (detail2, ok, terminal) => {
|
|
47644
47687
|
const agentId = opts.general.agentId;
|
|
47645
47688
|
if (agentId) {
|
|
47646
47689
|
opts.deps.onTentacleEvent?.({
|
|
47647
47690
|
type: "agent_status",
|
|
47648
47691
|
agentId,
|
|
47649
|
-
status: "running",
|
|
47692
|
+
status: terminal ?? "running",
|
|
47650
47693
|
message: detail2,
|
|
47651
47694
|
id: randomUUID4(),
|
|
47652
47695
|
sessionId: opts.sessionId,
|
|
@@ -47714,6 +47757,7 @@ async function runAutoVerifyAfterGeneral(opts) {
|
|
|
47714
47757
|
detail: detail2,
|
|
47715
47758
|
ok: false
|
|
47716
47759
|
});
|
|
47760
|
+
emitVerifyPhase(`rework round ${round2} failed`, false, "failed");
|
|
47717
47761
|
return `
|
|
47718
47762
|
|
|
47719
47763
|
[kraken:auto-verify] verify FAIL \u2014 rework round ${round2} failed to run (${rework.error}). Work stays UNVERIFIED; strict done will close this turn blocked.`;
|
|
@@ -47725,14 +47769,15 @@ async function runAutoVerifyAfterGeneral(opts) {
|
|
|
47725
47769
|
}
|
|
47726
47770
|
if (verdict === "pass") {
|
|
47727
47771
|
g.__zelariGeneralVerifyDebt = null;
|
|
47728
|
-
emitVerifyPhase("verify PASS", true);
|
|
47772
|
+
emitVerifyPhase("verify PASS", true, "completed");
|
|
47729
47773
|
return `
|
|
47730
47774
|
|
|
47731
47775
|
[kraken:auto-verify] verify PASS \u2014 general\u21D2verify obligation satisfied.`;
|
|
47732
47776
|
}
|
|
47733
47777
|
emitVerifyPhase(
|
|
47734
47778
|
verdict === "fail" ? "verify FAIL" : verify.ok ? "verify unknown" : "verify failed",
|
|
47735
|
-
verdict === "fail" || !verify.ok ? false : void 0
|
|
47779
|
+
verdict === "fail" || !verify.ok ? false : void 0,
|
|
47780
|
+
"failed"
|
|
47736
47781
|
);
|
|
47737
47782
|
const detail = verdict === "fail" ? `verify FAIL unresolved (rework budget spent): ${findings || "no findings reported"}` : verify.ok ? "verify produced no parseable VERDICT \u2014 unverified" : `verify tentacle failed: ${verify.error}`;
|
|
47738
47783
|
g.__zelariGeneralVerifyDebt = { description: opts.original.description, detail };
|
|
@@ -50772,13 +50817,13 @@ async function scanTsbuildinfo(root) {
|
|
|
50772
50817
|
return found;
|
|
50773
50818
|
}
|
|
50774
50819
|
async function gitStatusPorcelain(root) {
|
|
50775
|
-
return new Promise((
|
|
50820
|
+
return new Promise((resolve11) => {
|
|
50776
50821
|
const child = spawn9("git", ["status", "--porcelain"], { cwd: root, shell: false });
|
|
50777
50822
|
let out = "";
|
|
50778
50823
|
child.stdout.on("data", (d) => out += d.toString());
|
|
50779
50824
|
child.stderr.on("data", (d) => out += d.toString());
|
|
50780
|
-
child.on("error", () =>
|
|
50781
|
-
child.on("close", (code) =>
|
|
50825
|
+
child.on("error", () => resolve11("<git-unavailable>"));
|
|
50826
|
+
child.on("close", (code) => resolve11(code === 0 ? out : `<git-exit-${code ?? "none"}>`));
|
|
50782
50827
|
});
|
|
50783
50828
|
}
|
|
50784
50829
|
async function fingerprintWorkspace(root) {
|
|
@@ -50826,7 +50871,7 @@ var init_inspectTypecheckSafety = __esm({
|
|
|
50826
50871
|
import { spawn as spawn10 } from "node:child_process";
|
|
50827
50872
|
import { createHash as createHash14 } from "node:crypto";
|
|
50828
50873
|
import { existsSync as existsSync30, promises as fs23 } from "node:fs";
|
|
50829
|
-
import
|
|
50874
|
+
import os3 from "node:os";
|
|
50830
50875
|
import path52 from "node:path";
|
|
50831
50876
|
function resolveNodeModuleBin(start, rel2) {
|
|
50832
50877
|
let dir = path52.resolve(start);
|
|
@@ -50912,7 +50957,7 @@ function buildInspectCommand(op, ctx) {
|
|
|
50912
50957
|
case "typecheck": {
|
|
50913
50958
|
const project = path52.resolve(ctx.cwd, op.project ?? "tsconfig.json");
|
|
50914
50959
|
const hash3 = createHash14("sha256").update(project).digest("hex").slice(0, 16);
|
|
50915
|
-
const tsBuildInfoFile = path52.join(
|
|
50960
|
+
const tsBuildInfoFile = path52.join(os3.tmpdir(), "zelari-inspect", `${hash3}.tsbuildinfo`);
|
|
50916
50961
|
return {
|
|
50917
50962
|
ok: true,
|
|
50918
50963
|
command: process.execPath,
|
|
@@ -50936,12 +50981,12 @@ function buildInspectCommand(op, ctx) {
|
|
|
50936
50981
|
}
|
|
50937
50982
|
}
|
|
50938
50983
|
function runSpawn(command, argv, opts) {
|
|
50939
|
-
return new Promise((
|
|
50984
|
+
return new Promise((resolve11) => {
|
|
50940
50985
|
let child;
|
|
50941
50986
|
try {
|
|
50942
50987
|
child = spawn10(command, argv, { cwd: opts.cwd, shell: false });
|
|
50943
50988
|
} catch (err) {
|
|
50944
|
-
|
|
50989
|
+
resolve11({ code: null, stdout: "", stderr: String(err), timedOut: false, spawnError: String(err) });
|
|
50945
50990
|
return;
|
|
50946
50991
|
}
|
|
50947
50992
|
let stdout = "";
|
|
@@ -50963,14 +51008,14 @@ function runSpawn(command, argv, opts) {
|
|
|
50963
51008
|
if (settled) return;
|
|
50964
51009
|
settled = true;
|
|
50965
51010
|
clearTimeout(timer);
|
|
50966
|
-
|
|
51011
|
+
resolve11({ code: null, stdout, stderr, timedOut, spawnError: err.message });
|
|
50967
51012
|
});
|
|
50968
51013
|
child.on("close", (code) => {
|
|
50969
51014
|
if (settled) return;
|
|
50970
51015
|
settled = true;
|
|
50971
51016
|
clearTimeout(timer);
|
|
50972
51017
|
opts.signal?.removeEventListener("abort", onAbort);
|
|
50973
|
-
|
|
51018
|
+
resolve11({ code, stdout, stderr, timedOut });
|
|
50974
51019
|
});
|
|
50975
51020
|
});
|
|
50976
51021
|
}
|
|
@@ -51255,7 +51300,7 @@ function createExecProcessTool(root, opts = {}) {
|
|
|
51255
51300
|
const msg = err instanceof SandboxViolationError ? err.message : String(err);
|
|
51256
51301
|
return typedErr(`[sandbox] ${msg}`);
|
|
51257
51302
|
}
|
|
51258
|
-
return new Promise((
|
|
51303
|
+
return new Promise((resolve11) => {
|
|
51259
51304
|
const start = Date.now();
|
|
51260
51305
|
const spec = { ...baseSpec, network: opts.resolveNetwork?.(input) ?? baseSpec.network };
|
|
51261
51306
|
const res = spawnJailed(spec, {
|
|
@@ -51267,11 +51312,11 @@ function createExecProcessTool(root, opts = {}) {
|
|
|
51267
51312
|
envExtras: { CI: process.env.CI ?? "1" }
|
|
51268
51313
|
});
|
|
51269
51314
|
if (res.outcome === "denied") {
|
|
51270
|
-
|
|
51315
|
+
resolve11(typedErr(res.reason));
|
|
51271
51316
|
return;
|
|
51272
51317
|
}
|
|
51273
51318
|
if (res.outcome === "failed") {
|
|
51274
|
-
|
|
51319
|
+
resolve11(typedErr(`exec_process could not launch ${input.program}: ${res.reason}`));
|
|
51275
51320
|
return;
|
|
51276
51321
|
}
|
|
51277
51322
|
const meta3 = res.notice ? { status: "complete", warnings: [`os-jail: ${res.notice}`] } : void 0;
|
|
@@ -51287,7 +51332,7 @@ function createExecProcessTool(root, opts = {}) {
|
|
|
51287
51332
|
const timeoutMs2 = typeof input.timeoutMs === "number" && input.timeoutMs > 0 ? input.timeoutMs : 3e4;
|
|
51288
51333
|
const timer = setTimeout(() => {
|
|
51289
51334
|
child.kill("SIGTERM");
|
|
51290
|
-
|
|
51335
|
+
resolve11(
|
|
51291
51336
|
typedErr(
|
|
51292
51337
|
`exec_process timed out after ${timeoutMs2}ms running: ${[input.program, ...argv].join(" ")}`
|
|
51293
51338
|
)
|
|
@@ -51295,11 +51340,11 @@ function createExecProcessTool(root, opts = {}) {
|
|
|
51295
51340
|
}, timeoutMs2);
|
|
51296
51341
|
child.on("error", (err) => {
|
|
51297
51342
|
clearTimeout(timer);
|
|
51298
|
-
|
|
51343
|
+
resolve11(typedErr(`exec_process could not launch ${input.program}: ${err.message}`));
|
|
51299
51344
|
});
|
|
51300
51345
|
child.on("close", (code) => {
|
|
51301
51346
|
clearTimeout(timer);
|
|
51302
|
-
|
|
51347
|
+
resolve11(
|
|
51303
51348
|
typedOk(
|
|
51304
51349
|
{
|
|
51305
51350
|
exitCode: code ?? -1,
|
|
@@ -51828,12 +51873,12 @@ var init_client = __esm({
|
|
|
51828
51873
|
if (this.closed) return Promise.reject(new Error("LSP transport is closed"));
|
|
51829
51874
|
const id3 = this.nextId++;
|
|
51830
51875
|
const msg = { jsonrpc: "2.0", id: id3, method, ...params !== void 0 ? { params } : {} };
|
|
51831
|
-
return new Promise((
|
|
51876
|
+
return new Promise((resolve11, reject) => {
|
|
51832
51877
|
const timer = setTimeout(() => {
|
|
51833
51878
|
this.pending.delete(id3);
|
|
51834
51879
|
reject(new Error(`LSP request "${method}" timed out after ${this.timeoutMs}ms`));
|
|
51835
51880
|
}, this.timeoutMs);
|
|
51836
|
-
this.pending.set(id3, { resolve:
|
|
51881
|
+
this.pending.set(id3, { resolve: resolve11, reject, timer });
|
|
51837
51882
|
this.transport.send(encodeMessage(msg));
|
|
51838
51883
|
});
|
|
51839
51884
|
}
|
|
@@ -52110,8 +52155,8 @@ var init_manager = __esm({
|
|
|
52110
52155
|
if (cached2 !== void 0) return cached2;
|
|
52111
52156
|
let resolveInit;
|
|
52112
52157
|
let rejectInit;
|
|
52113
|
-
const initialized = new Promise((
|
|
52114
|
-
resolveInit =
|
|
52158
|
+
const initialized = new Promise((resolve11, reject) => {
|
|
52159
|
+
resolveInit = resolve11;
|
|
52115
52160
|
rejectInit = reject;
|
|
52116
52161
|
});
|
|
52117
52162
|
let entry = null;
|
|
@@ -52636,14 +52681,14 @@ function resolveStreamTimeouts(capabilities) {
|
|
|
52636
52681
|
};
|
|
52637
52682
|
}
|
|
52638
52683
|
function abortableSleep(ms, signal) {
|
|
52639
|
-
return new Promise((
|
|
52640
|
-
if (signal?.aborted) return
|
|
52641
|
-
const t = setTimeout(
|
|
52684
|
+
return new Promise((resolve11) => {
|
|
52685
|
+
if (signal?.aborted) return resolve11();
|
|
52686
|
+
const t = setTimeout(resolve11, ms);
|
|
52642
52687
|
signal?.addEventListener(
|
|
52643
52688
|
"abort",
|
|
52644
52689
|
() => {
|
|
52645
52690
|
clearTimeout(t);
|
|
52646
|
-
|
|
52691
|
+
resolve11();
|
|
52647
52692
|
},
|
|
52648
52693
|
{ once: true }
|
|
52649
52694
|
);
|
|
@@ -53517,8 +53562,8 @@ async function runBrowserCheck(options, loader) {
|
|
|
53517
53562
|
const failedRequests = [];
|
|
53518
53563
|
const evaluateResults = [];
|
|
53519
53564
|
const base2 = { ok: false, consoleErrors, pageErrors, failedRequests };
|
|
53520
|
-
const
|
|
53521
|
-
const pw = await
|
|
53565
|
+
const resolve11 = loader ?? (() => loadPlaywright(options.cwd ?? process.cwd()));
|
|
53566
|
+
const pw = await resolve11();
|
|
53522
53567
|
if (!pw) {
|
|
53523
53568
|
return {
|
|
53524
53569
|
...base2,
|
|
@@ -53681,7 +53726,7 @@ var init_driver = __esm({
|
|
|
53681
53726
|
|
|
53682
53727
|
// src/cli/browser/tools.ts
|
|
53683
53728
|
import path58 from "node:path";
|
|
53684
|
-
import
|
|
53729
|
+
import os4 from "node:os";
|
|
53685
53730
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
53686
53731
|
async function loadImageBlock(filePath) {
|
|
53687
53732
|
try {
|
|
@@ -53708,7 +53753,7 @@ function createBrowserTool(deps = {}) {
|
|
|
53708
53753
|
}),
|
|
53709
53754
|
execute: async (args, ctx) => {
|
|
53710
53755
|
const a = args;
|
|
53711
|
-
const dir = deps.screenshotDir ??
|
|
53756
|
+
const dir = deps.screenshotDir ?? os4.tmpdir();
|
|
53712
53757
|
const screenshotPath = a.screenshot === false ? void 0 : path58.join(dir, `zelari-browser-${Date.now()}.png`);
|
|
53713
53758
|
const result = await runBrowserCheck(
|
|
53714
53759
|
{
|
|
@@ -54111,9 +54156,9 @@ exec node "$(dirname "$0")/askpass.cjs"
|
|
|
54111
54156
|
return sh;
|
|
54112
54157
|
}
|
|
54113
54158
|
function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
54114
|
-
return new Promise((
|
|
54159
|
+
return new Promise((resolve11) => {
|
|
54115
54160
|
if (target.auth === "password" && !getSshPassword(target.id)) {
|
|
54116
|
-
|
|
54161
|
+
resolve11({
|
|
54117
54162
|
code: 1,
|
|
54118
54163
|
stdout: "",
|
|
54119
54164
|
stderr: "No password stored for this target \u2014 edit target and set password"
|
|
@@ -54145,7 +54190,7 @@ function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
|
54145
54190
|
});
|
|
54146
54191
|
const timer = setTimeout(() => {
|
|
54147
54192
|
child.kill("SIGTERM");
|
|
54148
|
-
|
|
54193
|
+
resolve11({
|
|
54149
54194
|
code: 124,
|
|
54150
54195
|
stdout,
|
|
54151
54196
|
stderr: stderr + "\n[ssh] timeout"
|
|
@@ -54153,7 +54198,7 @@ function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
|
54153
54198
|
}, timeoutMs2);
|
|
54154
54199
|
child.on("error", (err) => {
|
|
54155
54200
|
clearTimeout(timer);
|
|
54156
|
-
|
|
54201
|
+
resolve11({
|
|
54157
54202
|
code: 127,
|
|
54158
54203
|
stdout,
|
|
54159
54204
|
stderr: err.message.includes("ENOENT") ? "ssh not found on PATH \u2014 install OpenSSH client" : err.message
|
|
@@ -54161,7 +54206,7 @@ function runSsh(target, remoteCommand, timeoutMs2 = 6e4) {
|
|
|
54161
54206
|
});
|
|
54162
54207
|
child.on("close", (code) => {
|
|
54163
54208
|
clearTimeout(timer);
|
|
54164
|
-
|
|
54209
|
+
resolve11({ code: code ?? 1, stdout, stderr });
|
|
54165
54210
|
});
|
|
54166
54211
|
});
|
|
54167
54212
|
}
|
|
@@ -54938,14 +54983,14 @@ function backoffDelay2(attempt, retryAfterHeader) {
|
|
|
54938
54983
|
return Math.min(BACKOFF_BASE_MS2 * 2 ** attempt, BACKOFF_CAP_MS2);
|
|
54939
54984
|
}
|
|
54940
54985
|
function abortableSleep2(ms, signal) {
|
|
54941
|
-
return new Promise((
|
|
54942
|
-
if (signal?.aborted) return
|
|
54943
|
-
const t = setTimeout(
|
|
54986
|
+
return new Promise((resolve11) => {
|
|
54987
|
+
if (signal?.aborted) return resolve11();
|
|
54988
|
+
const t = setTimeout(resolve11, ms);
|
|
54944
54989
|
signal?.addEventListener(
|
|
54945
54990
|
"abort",
|
|
54946
54991
|
() => {
|
|
54947
54992
|
clearTimeout(t);
|
|
54948
|
-
|
|
54993
|
+
resolve11();
|
|
54949
54994
|
},
|
|
54950
54995
|
{ once: true }
|
|
54951
54996
|
);
|
|
@@ -55346,6 +55391,45 @@ var init_crossProviderFailover = __esm({
|
|
|
55346
55391
|
}
|
|
55347
55392
|
});
|
|
55348
55393
|
|
|
55394
|
+
// src/cli/serve/sessionControl.ts
|
|
55395
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
55396
|
+
function runWithSession(sessionId2, fn) {
|
|
55397
|
+
return dispatchContext.run({ sessionId: sessionId2, token: {} }, fn);
|
|
55398
|
+
}
|
|
55399
|
+
function getCurrentHarnessSessionId() {
|
|
55400
|
+
return dispatchContext.getStore()?.sessionId;
|
|
55401
|
+
}
|
|
55402
|
+
function registerLiveTurnControl(control) {
|
|
55403
|
+
const store6 = dispatchContext.getStore();
|
|
55404
|
+
if (!store6) return void 0;
|
|
55405
|
+
const registered = { ...control, token: store6.token };
|
|
55406
|
+
liveTurns.set(store6.sessionId, registered);
|
|
55407
|
+
return () => {
|
|
55408
|
+
if (liveTurns.get(store6.sessionId) === registered) {
|
|
55409
|
+
liveTurns.delete(store6.sessionId);
|
|
55410
|
+
}
|
|
55411
|
+
};
|
|
55412
|
+
}
|
|
55413
|
+
function getLiveTurnControl(sessionId2) {
|
|
55414
|
+
return liveTurns.get(sessionId2);
|
|
55415
|
+
}
|
|
55416
|
+
function clearSessionTurnControl(sessionId2) {
|
|
55417
|
+
const store6 = dispatchContext.getStore();
|
|
55418
|
+
if (!store6 || store6.sessionId !== sessionId2) return;
|
|
55419
|
+
const registered = liveTurns.get(sessionId2);
|
|
55420
|
+
if (registered && registered.token === store6.token) {
|
|
55421
|
+
liveTurns.delete(sessionId2);
|
|
55422
|
+
}
|
|
55423
|
+
}
|
|
55424
|
+
var dispatchContext, liveTurns;
|
|
55425
|
+
var init_sessionControl = __esm({
|
|
55426
|
+
"src/cli/serve/sessionControl.ts"() {
|
|
55427
|
+
"use strict";
|
|
55428
|
+
dispatchContext = new AsyncLocalStorage();
|
|
55429
|
+
liveTurns = /* @__PURE__ */ new Map();
|
|
55430
|
+
}
|
|
55431
|
+
});
|
|
55432
|
+
|
|
55349
55433
|
// src/cli/safety/toolPermissions.ts
|
|
55350
55434
|
var toolPermissions_exports = {};
|
|
55351
55435
|
__export(toolPermissions_exports, {
|
|
@@ -55362,27 +55446,42 @@ __export(toolPermissions_exports, {
|
|
|
55362
55446
|
parsePermissionPreset: () => parsePermissionPreset,
|
|
55363
55447
|
resolveToolPermission: () => resolveToolPermission
|
|
55364
55448
|
});
|
|
55365
|
-
function
|
|
55449
|
+
function grantsBucket(sessionId2) {
|
|
55450
|
+
const key = sessionId2 && sessionId2.trim() ? sessionId2 : GLOBAL_BUCKET;
|
|
55451
|
+
let bucket = grantsBySession.get(key);
|
|
55452
|
+
if (!bucket) {
|
|
55453
|
+
bucket = { tools: /* @__PURE__ */ new Set(), categories: /* @__PURE__ */ new Set() };
|
|
55454
|
+
grantsBySession.set(key, bucket);
|
|
55455
|
+
}
|
|
55456
|
+
return bucket;
|
|
55457
|
+
}
|
|
55458
|
+
function grantSessionTool(toolName, sessionId2) {
|
|
55366
55459
|
const n = toolName.trim();
|
|
55367
|
-
if (n)
|
|
55460
|
+
if (n) grantsBucket(sessionId2).tools.add(n);
|
|
55368
55461
|
}
|
|
55369
|
-
function grantSessionCategory(cat) {
|
|
55370
|
-
|
|
55462
|
+
function grantSessionCategory(cat, sessionId2) {
|
|
55463
|
+
grantsBucket(sessionId2).categories.add(cat);
|
|
55371
55464
|
}
|
|
55372
|
-
function clearSessionPermissionGrants() {
|
|
55373
|
-
|
|
55374
|
-
|
|
55465
|
+
function clearSessionPermissionGrants(sessionId2) {
|
|
55466
|
+
if (sessionId2 === void 0) {
|
|
55467
|
+
grantsBySession.clear();
|
|
55468
|
+
return;
|
|
55469
|
+
}
|
|
55470
|
+
grantsBySession.delete(sessionId2 && sessionId2.trim() ? sessionId2 : GLOBAL_BUCKET);
|
|
55375
55471
|
}
|
|
55376
|
-
function listSessionPermissionGrants() {
|
|
55472
|
+
function listSessionPermissionGrants(sessionId2) {
|
|
55473
|
+
const bucket = grantsBucket(sessionId2);
|
|
55377
55474
|
return {
|
|
55378
|
-
tools: [...
|
|
55379
|
-
categories: [...
|
|
55475
|
+
tools: [...bucket.tools].sort(),
|
|
55476
|
+
categories: [...bucket.categories]
|
|
55380
55477
|
};
|
|
55381
55478
|
}
|
|
55382
|
-
function isSessionGranted(toolName, required2) {
|
|
55383
|
-
|
|
55479
|
+
function isSessionGranted(toolName, required2, sessionId2) {
|
|
55480
|
+
const scope = sessionId2 ?? getCurrentHarnessSessionId();
|
|
55481
|
+
const bucket = grantsBucket(scope);
|
|
55482
|
+
if (bucket.tools.has(toolName)) return true;
|
|
55384
55483
|
if (!required2.length) return false;
|
|
55385
|
-
return required2.every((c) =>
|
|
55484
|
+
return required2.every((c) => bucket.categories.has(c));
|
|
55386
55485
|
}
|
|
55387
55486
|
function parseAction(raw, fallback) {
|
|
55388
55487
|
const v = raw?.trim().toLowerCase();
|
|
@@ -55464,12 +55563,13 @@ function resolveToolPermission(toolName, required2, policy) {
|
|
|
55464
55563
|
categories: hit
|
|
55465
55564
|
};
|
|
55466
55565
|
}
|
|
55467
|
-
var
|
|
55566
|
+
var GLOBAL_BUCKET, grantsBySession, PERMISSION_PRESETS, ACTION_RANK2;
|
|
55468
55567
|
var init_toolPermissions = __esm({
|
|
55469
55568
|
"src/cli/safety/toolPermissions.ts"() {
|
|
55470
55569
|
"use strict";
|
|
55471
|
-
|
|
55472
|
-
|
|
55570
|
+
init_sessionControl();
|
|
55571
|
+
GLOBAL_BUCKET = "";
|
|
55572
|
+
grantsBySession = /* @__PURE__ */ new Map();
|
|
55473
55573
|
PERMISSION_PRESETS = {
|
|
55474
55574
|
standard: { read: "allow", write: "allow", execute: "ask", network: "ask" },
|
|
55475
55575
|
strict: { read: "allow", write: "ask", execute: "ask", network: "deny" },
|
|
@@ -56980,6 +57080,9 @@ function wrapWithPermissions(original, policy, onAsk, agentLayers, precedence =
|
|
|
56980
57080
|
}
|
|
56981
57081
|
const claimHit = claims && claims.effect !== void 0 ? claims.matchedRules.find((x) => x.effect === claims.effect) : void 0;
|
|
56982
57082
|
const rulePrefix = contractRule ? `[contract] rule '${contractRule.match}'${contractRule.reason ? ` \u2014 ${contractRule.reason}` : ""}` : rule ? `[policy] rule '${rule.match}'${rule.reason ? ` \u2014 ${rule.reason}` : ""}` : claimHit ? `[policy] claim '${claimHit.match}'${claimHit.reason ? ` \u2014 ${claimHit.reason}` : ""}` : "";
|
|
57083
|
+
if (action === "ask" && activePermissionPreset() === "yolo") {
|
|
57084
|
+
action = "allow";
|
|
57085
|
+
}
|
|
56983
57086
|
if (action === "deny") {
|
|
56984
57087
|
return typedErr(`[permission] ${rulePrefix || decision.reason}`);
|
|
56985
57088
|
}
|
|
@@ -57510,12 +57613,12 @@ var init_metrics3 = __esm({
|
|
|
57510
57613
|
}
|
|
57511
57614
|
/** Append a single record synchronously (file I/O). */
|
|
57512
57615
|
append(rec) {
|
|
57513
|
-
return new Promise((
|
|
57616
|
+
return new Promise((resolve11, reject) => {
|
|
57514
57617
|
try {
|
|
57515
57618
|
this.maybeRotate();
|
|
57516
57619
|
const line = JSON.stringify(rec) + "\n";
|
|
57517
57620
|
appendFileSync3(this.file, line, { encoding: "utf-8" });
|
|
57518
|
-
|
|
57621
|
+
resolve11();
|
|
57519
57622
|
} catch (err) {
|
|
57520
57623
|
reject(err);
|
|
57521
57624
|
}
|
|
@@ -58900,8 +59003,8 @@ var init_sqliteRpc = __esm({
|
|
|
58900
59003
|
const worker = this.worker;
|
|
58901
59004
|
if (!worker) return Promise.reject(new Error("SQLite worker is not open."));
|
|
58902
59005
|
const id3 = this.nextId++;
|
|
58903
|
-
return new Promise((
|
|
58904
|
-
this.pending.set(id3, { resolve:
|
|
59006
|
+
return new Promise((resolve11, reject) => {
|
|
59007
|
+
this.pending.set(id3, { resolve: resolve11, reject });
|
|
58905
59008
|
worker.postMessage({ id: id3, operation, args });
|
|
58906
59009
|
});
|
|
58907
59010
|
}
|
|
@@ -58912,7 +59015,7 @@ var init_sqliteRpc = __esm({
|
|
|
58912
59015
|
return await this.request(operation, args);
|
|
58913
59016
|
} catch (error51) {
|
|
58914
59017
|
if (!isBusy(error51) || attempt >= 3) throw error51;
|
|
58915
|
-
await new Promise((
|
|
59018
|
+
await new Promise((resolve11) => setTimeout(resolve11, 25 * 2 ** attempt));
|
|
58916
59019
|
attempt += 1;
|
|
58917
59020
|
}
|
|
58918
59021
|
}
|
|
@@ -61831,13 +61934,13 @@ __export(claudeProvider_exports, {
|
|
|
61831
61934
|
});
|
|
61832
61935
|
import { spawn as spawn13 } from "node:child_process";
|
|
61833
61936
|
function waitForExit(child, timeoutMs2 = 2e3) {
|
|
61834
|
-
return new Promise((
|
|
61835
|
-
if (child.exitCode != null) return
|
|
61836
|
-
const timer = setTimeout(() =>
|
|
61937
|
+
return new Promise((resolve11) => {
|
|
61938
|
+
if (child.exitCode != null) return resolve11(child.exitCode);
|
|
61939
|
+
const timer = setTimeout(() => resolve11(child.exitCode ?? null), timeoutMs2);
|
|
61837
61940
|
timer.unref?.();
|
|
61838
61941
|
child.once("exit", (code) => {
|
|
61839
61942
|
clearTimeout(timer);
|
|
61840
|
-
|
|
61943
|
+
resolve11(code ?? null);
|
|
61841
61944
|
});
|
|
61842
61945
|
});
|
|
61843
61946
|
}
|
|
@@ -63752,7 +63855,7 @@ var init_mcpClient = __esm({
|
|
|
63752
63855
|
if (!transport && !child)
|
|
63753
63856
|
return Promise.reject(new Error(`[mcp:${this.serverName}] not started`));
|
|
63754
63857
|
const id3 = this.nextId++;
|
|
63755
|
-
return new Promise((
|
|
63858
|
+
return new Promise((resolve11, reject) => {
|
|
63756
63859
|
const timer = setTimeout(() => {
|
|
63757
63860
|
this.pending.delete(id3);
|
|
63758
63861
|
reject(
|
|
@@ -63761,7 +63864,7 @@ var init_mcpClient = __esm({
|
|
|
63761
63864
|
)
|
|
63762
63865
|
);
|
|
63763
63866
|
}, timeoutMs2);
|
|
63764
|
-
this.pending.set(id3, { resolve:
|
|
63867
|
+
this.pending.set(id3, { resolve: resolve11, reject, timer });
|
|
63765
63868
|
if (transport) {
|
|
63766
63869
|
void transport.send({ id: id3, method, params }, timeoutMs2);
|
|
63767
63870
|
} else {
|
|
@@ -66947,12 +67050,12 @@ function startPermissionBroker(socketPath, handlers, opts) {
|
|
|
66947
67050
|
});
|
|
66948
67051
|
}
|
|
66949
67052
|
}
|
|
66950
|
-
return new Promise((
|
|
67053
|
+
return new Promise((resolve11, reject) => {
|
|
66951
67054
|
const onError = (err) => reject(err);
|
|
66952
67055
|
server.once("error", onError);
|
|
66953
67056
|
server.listen(path104, () => {
|
|
66954
67057
|
server.removeListener("error", onError);
|
|
66955
|
-
|
|
67058
|
+
resolve11({
|
|
66956
67059
|
socketPath: path104,
|
|
66957
67060
|
stop: () => new Promise((res) => {
|
|
66958
67061
|
for (const s of sockets) s.destroy();
|
|
@@ -66980,7 +67083,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
|
|
|
66980
67083
|
const path104 = safeSocketPath(socketPath);
|
|
66981
67084
|
const requestTimeoutMs = opts?.requestTimeoutMs ?? PERMISSION_BROKER_DEFAULT_TIMEOUT_MS;
|
|
66982
67085
|
const connectTimeoutMs = opts?.connectTimeoutMs ?? PERMISSION_BROKER_DEFAULT_CONNECT_TIMEOUT_MS;
|
|
66983
|
-
return new Promise((
|
|
67086
|
+
return new Promise((resolve11, reject) => {
|
|
66984
67087
|
const socket = connect(path104);
|
|
66985
67088
|
let buffer = "";
|
|
66986
67089
|
let settled = false;
|
|
@@ -67033,7 +67136,7 @@ function requestBrokerAsk(socketPath, ask, opts) {
|
|
|
67033
67136
|
}
|
|
67034
67137
|
if (msg?.t === "answer" && msg.id === ask.id) {
|
|
67035
67138
|
const { t: _t, id: _id, ...answer } = msg;
|
|
67036
|
-
settle(() =>
|
|
67139
|
+
settle(() => resolve11(answer));
|
|
67037
67140
|
return;
|
|
67038
67141
|
}
|
|
67039
67142
|
}
|
|
@@ -67812,7 +67915,7 @@ __export(prereqChecks_exports, {
|
|
|
67812
67915
|
isWslBashPath: () => isWslBashPath2,
|
|
67813
67916
|
runPrereqChecks: () => runPrereqChecks
|
|
67814
67917
|
});
|
|
67815
|
-
import { execSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
67918
|
+
import { execSync as execSync2, spawnSync as spawnSync2 } from "node:child_process";
|
|
67816
67919
|
import { existsSync as existsSync54 } from "node:fs";
|
|
67817
67920
|
import { dirname as dirname13 } from "node:path";
|
|
67818
67921
|
function isWslBashPath2(p3) {
|
|
@@ -67972,7 +68075,7 @@ function probeTool(tool) {
|
|
|
67972
68075
|
}
|
|
67973
68076
|
} else if (process.platform === "win32") {
|
|
67974
68077
|
try {
|
|
67975
|
-
stdout =
|
|
68078
|
+
stdout = execSync2(`${tool} --version`, {
|
|
67976
68079
|
encoding: "utf8",
|
|
67977
68080
|
stdio: ["ignore", "pipe", "ignore"],
|
|
67978
68081
|
env
|
|
@@ -67981,7 +68084,7 @@ function probeTool(tool) {
|
|
|
67981
68084
|
}
|
|
67982
68085
|
} else {
|
|
67983
68086
|
try {
|
|
67984
|
-
stdout =
|
|
68087
|
+
stdout = execSync2(`${tool} --version`, {
|
|
67985
68088
|
encoding: "utf8",
|
|
67986
68089
|
stdio: ["ignore", "pipe", "ignore"],
|
|
67987
68090
|
env
|
|
@@ -68106,7 +68209,7 @@ function checkAgentBash() {
|
|
|
68106
68209
|
}
|
|
68107
68210
|
function checkMainNode() {
|
|
68108
68211
|
try {
|
|
68109
|
-
const raw =
|
|
68212
|
+
const raw = execSync2("node --version", {
|
|
68110
68213
|
encoding: "utf8",
|
|
68111
68214
|
stdio: ["ignore", "pipe", "ignore"]
|
|
68112
68215
|
}).trim();
|
|
@@ -68166,7 +68269,7 @@ var MIN_NODE_MAJOR, STANDARD_BASH_PATHS2, POWERSHELL_EXES2, STANDARD_POWERSHELL_
|
|
|
68166
68269
|
var init_prereqChecks = __esm({
|
|
68167
68270
|
"src/cli/utils/prereqChecks.ts"() {
|
|
68168
68271
|
"use strict";
|
|
68169
|
-
MIN_NODE_MAJOR =
|
|
68272
|
+
MIN_NODE_MAJOR = 20;
|
|
68170
68273
|
STANDARD_BASH_PATHS2 = [
|
|
68171
68274
|
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
68172
68275
|
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
@@ -69697,42 +69800,6 @@ var init_harnessStateEmit = __esm({
|
|
|
69697
69800
|
}
|
|
69698
69801
|
});
|
|
69699
69802
|
|
|
69700
|
-
// src/cli/serve/sessionControl.ts
|
|
69701
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
69702
|
-
function runWithSession(sessionId2, fn) {
|
|
69703
|
-
return dispatchContext.run({ sessionId: sessionId2, token: {} }, fn);
|
|
69704
|
-
}
|
|
69705
|
-
function registerLiveTurnControl(control) {
|
|
69706
|
-
const store6 = dispatchContext.getStore();
|
|
69707
|
-
if (!store6) return void 0;
|
|
69708
|
-
const registered = { ...control, token: store6.token };
|
|
69709
|
-
liveTurns.set(store6.sessionId, registered);
|
|
69710
|
-
return () => {
|
|
69711
|
-
if (liveTurns.get(store6.sessionId) === registered) {
|
|
69712
|
-
liveTurns.delete(store6.sessionId);
|
|
69713
|
-
}
|
|
69714
|
-
};
|
|
69715
|
-
}
|
|
69716
|
-
function getLiveTurnControl(sessionId2) {
|
|
69717
|
-
return liveTurns.get(sessionId2);
|
|
69718
|
-
}
|
|
69719
|
-
function clearSessionTurnControl(sessionId2) {
|
|
69720
|
-
const store6 = dispatchContext.getStore();
|
|
69721
|
-
if (!store6 || store6.sessionId !== sessionId2) return;
|
|
69722
|
-
const registered = liveTurns.get(sessionId2);
|
|
69723
|
-
if (registered && registered.token === store6.token) {
|
|
69724
|
-
liveTurns.delete(sessionId2);
|
|
69725
|
-
}
|
|
69726
|
-
}
|
|
69727
|
-
var dispatchContext, liveTurns;
|
|
69728
|
-
var init_sessionControl = __esm({
|
|
69729
|
-
"src/cli/serve/sessionControl.ts"() {
|
|
69730
|
-
"use strict";
|
|
69731
|
-
dispatchContext = new AsyncLocalStorage();
|
|
69732
|
-
liveTurns = /* @__PURE__ */ new Map();
|
|
69733
|
-
}
|
|
69734
|
-
});
|
|
69735
|
-
|
|
69736
69803
|
// src/cli/headless/controlReader.ts
|
|
69737
69804
|
function parseControlEvent(raw) {
|
|
69738
69805
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
@@ -74117,8 +74184,8 @@ async function startMemoryMcpServer(options) {
|
|
|
74117
74184
|
let stopped = false;
|
|
74118
74185
|
let finalizePromise;
|
|
74119
74186
|
let resolveClosed = () => void 0;
|
|
74120
|
-
const closed = new Promise((
|
|
74121
|
-
resolveClosed =
|
|
74187
|
+
const closed = new Promise((resolve11) => {
|
|
74188
|
+
resolveClosed = resolve11;
|
|
74122
74189
|
});
|
|
74123
74190
|
const adapter = new MemoryMcpAdapter({
|
|
74124
74191
|
service,
|
|
@@ -74265,8 +74332,8 @@ function startPermissionMcpServer(opts) {
|
|
|
74265
74332
|
});
|
|
74266
74333
|
let closedResolve = () => {
|
|
74267
74334
|
};
|
|
74268
|
-
const closed = new Promise((
|
|
74269
|
-
closedResolve =
|
|
74335
|
+
const closed = new Promise((resolve11) => {
|
|
74336
|
+
closedResolve = resolve11;
|
|
74270
74337
|
});
|
|
74271
74338
|
let stopped = false;
|
|
74272
74339
|
const send = (obj) => {
|
|
@@ -74522,9 +74589,10 @@ import {
|
|
|
74522
74589
|
existsSync as existsSync61,
|
|
74523
74590
|
mkdirSync as mkdirSync24,
|
|
74524
74591
|
readFileSync as readFileSync45,
|
|
74592
|
+
statSync as statSync10,
|
|
74525
74593
|
writeFileSync as writeFileSync26
|
|
74526
74594
|
} from "node:fs";
|
|
74527
|
-
import { join as join48 } from "node:path";
|
|
74595
|
+
import { join as join48, resolve as resolve9 } from "node:path";
|
|
74528
74596
|
import { createHash as createHash26, randomBytes as randomBytes7, timingSafeEqual } from "node:crypto";
|
|
74529
74597
|
function getZelariHome() {
|
|
74530
74598
|
return zelariHome();
|
|
@@ -74613,6 +74681,30 @@ function slugFromPath(p3) {
|
|
|
74613
74681
|
const base2 = p3.replace(/[/\\]+$/, "").split(/[/\\]/).pop() || "project";
|
|
74614
74682
|
return base2.toLowerCase().replace(/[^a-z0-9-_]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "project";
|
|
74615
74683
|
}
|
|
74684
|
+
function resolveFsDirectory(rawPath) {
|
|
74685
|
+
const trimmed = rawPath.trim();
|
|
74686
|
+
if (!trimmed) return { ok: false, error: "cwd is required" };
|
|
74687
|
+
const norm = trimmed.replace(/\\/g, "/");
|
|
74688
|
+
const absolute = /^([a-zA-Z]:\/|\/)/.test(norm);
|
|
74689
|
+
if (!absolute || norm.split("/").includes("..")) {
|
|
74690
|
+
return {
|
|
74691
|
+
ok: false,
|
|
74692
|
+
error: `cwd must be an absolute path without '..': ${trimmed}`
|
|
74693
|
+
};
|
|
74694
|
+
}
|
|
74695
|
+
let stat8;
|
|
74696
|
+
try {
|
|
74697
|
+
stat8 = statSync10(trimmed);
|
|
74698
|
+
} catch {
|
|
74699
|
+
return { ok: false, error: `path not found: ${trimmed}` };
|
|
74700
|
+
}
|
|
74701
|
+
if (!stat8.isDirectory()) {
|
|
74702
|
+
return { ok: false, error: `not a directory: ${trimmed}` };
|
|
74703
|
+
}
|
|
74704
|
+
const abs = resolve9(trimmed);
|
|
74705
|
+
const slug = slugFromPath(abs);
|
|
74706
|
+
return { ok: true, project: { id: slug, name: slug, path: abs } };
|
|
74707
|
+
}
|
|
74616
74708
|
function mergeProjects(cfg, extraPaths) {
|
|
74617
74709
|
const byId = /* @__PURE__ */ new Map();
|
|
74618
74710
|
for (const p3 of cfg.projects) {
|
|
@@ -74634,24 +74726,24 @@ function mergeProjects(cfg, extraPaths) {
|
|
|
74634
74726
|
}
|
|
74635
74727
|
return [...byId.values()];
|
|
74636
74728
|
}
|
|
74637
|
-
function resolveProjectPath(projects, cwdOrId) {
|
|
74638
|
-
|
|
74729
|
+
function resolveProjectPath(projects, cwdOrId, opts = {}) {
|
|
74730
|
+
const key = String(cwdOrId ?? "").trim();
|
|
74731
|
+
if (!projects.length && !(opts.fullFs && key)) {
|
|
74639
74732
|
return {
|
|
74640
74733
|
ok: false,
|
|
74641
74734
|
error: "No projects configured. Pass --project <path> or edit ~/.zelari-code/companion.json"
|
|
74642
74735
|
};
|
|
74643
74736
|
}
|
|
74644
|
-
if (!
|
|
74645
|
-
return { ok: true, project: projects[0] };
|
|
74737
|
+
if (!key) {
|
|
74738
|
+
return { ok: true, project: projects[0], trusted: true };
|
|
74646
74739
|
}
|
|
74647
|
-
const key = String(cwdOrId).trim();
|
|
74648
74740
|
const byId = projects.find((p3) => p3.id === key || p3.name === key);
|
|
74649
|
-
if (byId) return { ok: true, project: byId };
|
|
74741
|
+
if (byId) return { ok: true, project: byId, trusted: true };
|
|
74650
74742
|
const norm = key.replace(/\\/g, "/").toLowerCase();
|
|
74651
74743
|
const byPath = projects.find(
|
|
74652
74744
|
(p3) => p3.path.replace(/\\/g, "/").toLowerCase() === norm
|
|
74653
74745
|
);
|
|
74654
|
-
if (byPath) return { ok: true, project: byPath };
|
|
74746
|
+
if (byPath) return { ok: true, project: byPath, trusted: true };
|
|
74655
74747
|
const under = projects.find((p3) => {
|
|
74656
74748
|
const root = p3.path.replace(/\\/g, "/").toLowerCase().replace(/\/$/, "");
|
|
74657
74749
|
return norm === root || norm.startsWith(root + "/");
|
|
@@ -74659,14 +74751,31 @@ function resolveProjectPath(projects, cwdOrId) {
|
|
|
74659
74751
|
if (under) {
|
|
74660
74752
|
return {
|
|
74661
74753
|
ok: true,
|
|
74662
|
-
project: { ...under, path: key }
|
|
74754
|
+
project: { ...under, path: key },
|
|
74755
|
+
trusted: true
|
|
74663
74756
|
};
|
|
74664
74757
|
}
|
|
74758
|
+
if (opts.fullFs) {
|
|
74759
|
+
const dir = resolveFsDirectory(key);
|
|
74760
|
+
if (dir.ok) return { ok: true, project: dir.project, trusted: false };
|
|
74761
|
+
return { ok: false, error: dir.error };
|
|
74762
|
+
}
|
|
74665
74763
|
return {
|
|
74666
74764
|
ok: false,
|
|
74667
74765
|
error: `cwd/project not in allowlist: ${key}. Allowed: ${projects.map((p3) => p3.id).join(", ")}`
|
|
74668
74766
|
};
|
|
74669
74767
|
}
|
|
74768
|
+
function isUnderRoots(rawPath, projects) {
|
|
74769
|
+
const norm = rawPath.replace(/\\/g, "/").toLowerCase().replace(/\/+$/, "");
|
|
74770
|
+
if (!norm || norm.split("/").includes("..")) return { ok: false };
|
|
74771
|
+
for (const p3 of projects) {
|
|
74772
|
+
const root = p3.path.replace(/\\/g, "/").toLowerCase().replace(/\/+$/, "");
|
|
74773
|
+
if (norm === root || norm.startsWith(root + "/")) {
|
|
74774
|
+
return { ok: true, root: p3, normalized: norm };
|
|
74775
|
+
}
|
|
74776
|
+
}
|
|
74777
|
+
return { ok: false };
|
|
74778
|
+
}
|
|
74670
74779
|
var DEFAULT_COMPANION_PORT, DEFAULT_COMPANION_BIND;
|
|
74671
74780
|
var init_config = __esm({
|
|
74672
74781
|
"src/cli/companion/config.ts"() {
|
|
@@ -74705,6 +74814,7 @@ function createServePermissionBridge(write, timeoutMs2 = 12e4) {
|
|
|
74705
74814
|
type: "permission.settled",
|
|
74706
74815
|
requestId,
|
|
74707
74816
|
decision,
|
|
74817
|
+
...entry.sessionId ? { sessionId: entry.sessionId } : {},
|
|
74708
74818
|
...timedOut ? { timedOut: true } : {}
|
|
74709
74819
|
})
|
|
74710
74820
|
);
|
|
@@ -74715,15 +74825,17 @@ function createServePermissionBridge(write, timeoutMs2 = 12e4) {
|
|
|
74715
74825
|
onPermissionAsk(payload) {
|
|
74716
74826
|
const requestId = `perm-${Date.now()}-${++seq}`;
|
|
74717
74827
|
const categories = payload.categories && payload.categories.length > 0 ? payload.categories : payload.category ? payload.category.split(",").map((c) => c.trim()).filter(Boolean) : [];
|
|
74718
|
-
return new Promise((
|
|
74828
|
+
return new Promise((resolve11) => {
|
|
74719
74829
|
const timer = setTimeout(() => {
|
|
74720
74830
|
settle(requestId, "deny", true);
|
|
74721
74831
|
}, timeoutMs2);
|
|
74722
|
-
|
|
74832
|
+
const sessionId2 = getCurrentHarnessSessionId();
|
|
74833
|
+
pending.set(requestId, { resolve: resolve11, timer, payload, sessionId: sessionId2 });
|
|
74723
74834
|
write(
|
|
74724
74835
|
JSON.stringify({
|
|
74725
74836
|
type: "permission.request",
|
|
74726
74837
|
requestId,
|
|
74838
|
+
...sessionId2 ? { sessionId: sessionId2 } : {},
|
|
74727
74839
|
tool: payload.tool,
|
|
74728
74840
|
category: payload.category,
|
|
74729
74841
|
categories,
|
|
@@ -74733,12 +74845,19 @@ function createServePermissionBridge(write, timeoutMs2 = 12e4) {
|
|
|
74733
74845
|
);
|
|
74734
74846
|
});
|
|
74735
74847
|
},
|
|
74736
|
-
respond: (requestId, decision) =>
|
|
74848
|
+
respond: (requestId, decision, scopeSessionId) => {
|
|
74849
|
+
const entry = pending.get(requestId);
|
|
74850
|
+
if (entry && scopeSessionId && entry.sessionId !== scopeSessionId) {
|
|
74851
|
+
return false;
|
|
74852
|
+
}
|
|
74853
|
+
return settle(requestId, decision, false);
|
|
74854
|
+
},
|
|
74855
|
+
sessionOf: (requestId) => pending.get(requestId)?.sessionId,
|
|
74737
74856
|
releaseGranted() {
|
|
74738
74857
|
let n = 0;
|
|
74739
74858
|
for (const [id3, entry] of [...pending]) {
|
|
74740
74859
|
const cats = entry.payload.categories && entry.payload.categories.length > 0 ? entry.payload.categories : entry.payload.category ? entry.payload.category.split(",").map((c) => c.trim()).filter(Boolean) : [];
|
|
74741
|
-
if (isSessionGranted(entry.payload.tool, cats)) {
|
|
74860
|
+
if (isSessionGranted(entry.payload.tool, cats, entry.sessionId)) {
|
|
74742
74861
|
if (settle(id3, "allow", false)) n += 1;
|
|
74743
74862
|
}
|
|
74744
74863
|
}
|
|
@@ -74751,7 +74870,7 @@ function servePermissionRespond(bridge, params) {
|
|
|
74751
74870
|
if (!params || typeof params !== "object") {
|
|
74752
74871
|
return { accepted: false, reason: "permission.respond requires an object params" };
|
|
74753
74872
|
}
|
|
74754
|
-
const { requestId, decision } = params;
|
|
74873
|
+
const { requestId, decision, sessionId: sessionId2 } = params;
|
|
74755
74874
|
if (typeof requestId !== "string" || requestId.length === 0) {
|
|
74756
74875
|
return { accepted: false, reason: "permission.respond requires a non-empty string requestId" };
|
|
74757
74876
|
}
|
|
@@ -74761,7 +74880,11 @@ function servePermissionRespond(bridge, params) {
|
|
|
74761
74880
|
reason: "permission.respond decision must be 'allow' | 'deny' | 'always-tool' | 'always-category'"
|
|
74762
74881
|
};
|
|
74763
74882
|
}
|
|
74764
|
-
|
|
74883
|
+
const scope = typeof sessionId2 === "string" && sessionId2.length > 0 ? sessionId2 : void 0;
|
|
74884
|
+
if (scope && bridge.sessionOf(requestId) !== scope) {
|
|
74885
|
+
return { accepted: false, reason: "session_mismatch: requestId belongs to another session" };
|
|
74886
|
+
}
|
|
74887
|
+
return { accepted: bridge.respond(requestId, decision, scope) };
|
|
74765
74888
|
}
|
|
74766
74889
|
function asRegistryAskHandler(bridge) {
|
|
74767
74890
|
return async (req) => {
|
|
@@ -74774,14 +74897,15 @@ function asRegistryAskHandler(bridge) {
|
|
|
74774
74897
|
...req.claims && req.claims.length > 0 ? { inputPreview: req.claims.map((c) => c.summary).join(" \xB7 ") } : {}
|
|
74775
74898
|
});
|
|
74776
74899
|
if (decision === "deny") return false;
|
|
74900
|
+
const sessionId2 = getCurrentHarnessSessionId();
|
|
74777
74901
|
if (decision === "always-tool") {
|
|
74778
|
-
grantSessionTool(req.toolName);
|
|
74902
|
+
grantSessionTool(req.toolName, sessionId2);
|
|
74779
74903
|
bridge.releaseGranted();
|
|
74780
74904
|
} else if (decision === "always-category") {
|
|
74781
74905
|
for (const cat of req.categories) {
|
|
74782
|
-
grantSessionCategory(cat);
|
|
74906
|
+
grantSessionCategory(cat, sessionId2);
|
|
74783
74907
|
}
|
|
74784
|
-
grantSessionTool(req.toolName);
|
|
74908
|
+
grantSessionTool(req.toolName, sessionId2);
|
|
74785
74909
|
bridge.releaseGranted();
|
|
74786
74910
|
}
|
|
74787
74911
|
return true;
|
|
@@ -74792,6 +74916,7 @@ var init_permissionBridge = __esm({
|
|
|
74792
74916
|
"src/cli/serve/permissionBridge.ts"() {
|
|
74793
74917
|
"use strict";
|
|
74794
74918
|
init_toolPermissions();
|
|
74919
|
+
init_sessionControl();
|
|
74795
74920
|
SERVE_PERMISSION_PRESETS = ["standard", "strict", "yolo"];
|
|
74796
74921
|
PRESET_ENV = "ZELARI_PERMISSION_PRESET";
|
|
74797
74922
|
PERMISSION_DECISIONS = [
|
|
@@ -74817,6 +74942,7 @@ function createServeAskUserBridge(write, timeoutMs2 = askUserTimeoutMs()) {
|
|
|
74817
74942
|
type: "ask_user.settled",
|
|
74818
74943
|
requestId,
|
|
74819
74944
|
answer,
|
|
74945
|
+
...entry.sessionId ? { sessionId: entry.sessionId } : {},
|
|
74820
74946
|
...timedOut ? { timedOut: true } : {}
|
|
74821
74947
|
})
|
|
74822
74948
|
);
|
|
@@ -74829,15 +74955,17 @@ function createServeAskUserBridge(write, timeoutMs2 = askUserTimeoutMs()) {
|
|
|
74829
74955
|
const choices = req.choices.map((c) => c.trim()).filter(Boolean);
|
|
74830
74956
|
if (choices.length < 2) return Promise.resolve(null);
|
|
74831
74957
|
const requestId = `ask-${Date.now()}-${++seq}`;
|
|
74832
|
-
return new Promise((
|
|
74958
|
+
return new Promise((resolve11) => {
|
|
74833
74959
|
const timer = setTimeout(() => {
|
|
74834
74960
|
settle(requestId, null, true);
|
|
74835
74961
|
}, timeoutMs2);
|
|
74836
|
-
|
|
74962
|
+
const sessionId2 = getCurrentHarnessSessionId();
|
|
74963
|
+
pending.set(requestId, { resolve: resolve11, timer, sessionId: sessionId2 });
|
|
74837
74964
|
write(
|
|
74838
74965
|
JSON.stringify({
|
|
74839
74966
|
type: "ask_user.request",
|
|
74840
74967
|
requestId,
|
|
74968
|
+
...sessionId2 ? { sessionId: sessionId2 } : {},
|
|
74841
74969
|
question,
|
|
74842
74970
|
choices,
|
|
74843
74971
|
...req.context ? { context: req.context } : {}
|
|
@@ -74845,7 +74973,14 @@ function createServeAskUserBridge(write, timeoutMs2 = askUserTimeoutMs()) {
|
|
|
74845
74973
|
);
|
|
74846
74974
|
});
|
|
74847
74975
|
},
|
|
74848
|
-
respond: (requestId, answer) =>
|
|
74976
|
+
respond: (requestId, answer, scopeSessionId) => {
|
|
74977
|
+
const entry = pending.get(requestId);
|
|
74978
|
+
if (entry && scopeSessionId && entry.sessionId && entry.sessionId !== scopeSessionId) {
|
|
74979
|
+
return false;
|
|
74980
|
+
}
|
|
74981
|
+
return settle(requestId, answer, false);
|
|
74982
|
+
},
|
|
74983
|
+
sessionOf: (requestId) => pending.get(requestId)?.sessionId,
|
|
74849
74984
|
pendingCount: () => pending.size
|
|
74850
74985
|
};
|
|
74851
74986
|
}
|
|
@@ -74853,20 +74988,25 @@ function serveAskUserRespond(bridge, params) {
|
|
|
74853
74988
|
if (!params || typeof params !== "object") {
|
|
74854
74989
|
return { accepted: false, reason: "ask_user.respond requires an object params" };
|
|
74855
74990
|
}
|
|
74856
|
-
const { requestId, answer } = params;
|
|
74991
|
+
const { requestId, answer, sessionId: sessionId2 } = params;
|
|
74857
74992
|
if (typeof requestId !== "string" || requestId.length === 0) {
|
|
74858
74993
|
return { accepted: false, reason: "ask_user.respond requires a non-empty string requestId" };
|
|
74859
74994
|
}
|
|
74860
74995
|
if (answer !== null && typeof answer !== "string") {
|
|
74861
74996
|
return { accepted: false, reason: "ask_user.respond answer must be a string or null" };
|
|
74862
74997
|
}
|
|
74998
|
+
const scope = typeof sessionId2 === "string" && sessionId2.length > 0 ? sessionId2 : void 0;
|
|
74999
|
+
if (scope && bridge.sessionOf(requestId) && bridge.sessionOf(requestId) !== scope) {
|
|
75000
|
+
return { accepted: false, reason: "session_mismatch: requestId belongs to another session" };
|
|
75001
|
+
}
|
|
74863
75002
|
const text = typeof answer === "string" ? answer.trim() : null;
|
|
74864
|
-
return { accepted: bridge.respond(requestId, text && text.length > 0 ? text : null) };
|
|
75003
|
+
return { accepted: bridge.respond(requestId, text && text.length > 0 ? text : null, scope) };
|
|
74865
75004
|
}
|
|
74866
75005
|
var init_askUserBridge = __esm({
|
|
74867
75006
|
"src/cli/serve/askUserBridge.ts"() {
|
|
74868
75007
|
"use strict";
|
|
74869
75008
|
init_askUserTimeout();
|
|
75009
|
+
init_sessionControl();
|
|
74870
75010
|
}
|
|
74871
75011
|
});
|
|
74872
75012
|
|
|
@@ -75030,17 +75170,23 @@ function createCliRunTurn(onPermissionAsk, onAskUser) {
|
|
|
75030
75170
|
const opts = bindHarnessTurnOptions(input, deps.session.workspaceRoot);
|
|
75031
75171
|
if (onPermissionAsk) opts.onPermissionAsk = onPermissionAsk;
|
|
75032
75172
|
if (onAskUser) opts.onAskUser = onAskUser;
|
|
75173
|
+
const priorPreset = process.env[PRESET_ENV2];
|
|
75033
75174
|
applyTurnPermissionPreset(input);
|
|
75034
|
-
|
|
75035
|
-
|
|
75036
|
-
|
|
75037
|
-
|
|
75038
|
-
|
|
75039
|
-
|
|
75040
|
-
|
|
75041
|
-
|
|
75042
|
-
|
|
75043
|
-
|
|
75175
|
+
try {
|
|
75176
|
+
const lspProvider = resolveTurnLspProvider(deps.services);
|
|
75177
|
+
const exitCode = await dispatchHeadlessTurn(
|
|
75178
|
+
opts,
|
|
75179
|
+
provider,
|
|
75180
|
+
model,
|
|
75181
|
+
stream,
|
|
75182
|
+
void 0,
|
|
75183
|
+
lspProvider ? { lspProvider } : void 0
|
|
75184
|
+
);
|
|
75185
|
+
return { exitCode };
|
|
75186
|
+
} finally {
|
|
75187
|
+
if (priorPreset === void 0) delete process.env[PRESET_ENV2];
|
|
75188
|
+
else process.env[PRESET_ENV2] = priorPreset;
|
|
75189
|
+
}
|
|
75044
75190
|
};
|
|
75045
75191
|
}
|
|
75046
75192
|
function unknownSessionEnvelope(id3, rawSessionId) {
|
|
@@ -75121,6 +75267,7 @@ function startHarnessServer(options = {}) {
|
|
|
75121
75267
|
return { id: req.id ?? null, ok: false, error: { code: "unknown_session", message: `no session '${String(params.sessionId ?? "")}'` } };
|
|
75122
75268
|
}
|
|
75123
75269
|
await session.dispose();
|
|
75270
|
+
clearSessionPermissionGrants(session.id);
|
|
75124
75271
|
return { id: req.id ?? null, ok: true, result: { disposed: true } };
|
|
75125
75272
|
}
|
|
75126
75273
|
// t32: session-scoped steer/cancel over the SAME protocol v2 — no new
|
|
@@ -75236,6 +75383,7 @@ async function runHarnessServer() {
|
|
|
75236
75383
|
process.once("SIGTERM", finish2);
|
|
75237
75384
|
});
|
|
75238
75385
|
}
|
|
75386
|
+
var PRESET_ENV2;
|
|
75239
75387
|
var init_harnessServer = __esm({
|
|
75240
75388
|
"src/cli/serve/harnessServer.ts"() {
|
|
75241
75389
|
"use strict";
|
|
@@ -75251,8 +75399,10 @@ var init_harnessServer = __esm({
|
|
|
75251
75399
|
init_policyGate();
|
|
75252
75400
|
init_policyLoadMode();
|
|
75253
75401
|
init_permissionBridge();
|
|
75402
|
+
init_toolPermissions();
|
|
75254
75403
|
init_askUserBridge();
|
|
75255
75404
|
init_spineLockSweep();
|
|
75405
|
+
PRESET_ENV2 = "ZELARI_PERMISSION_PRESET";
|
|
75256
75406
|
}
|
|
75257
75407
|
});
|
|
75258
75408
|
|
|
@@ -75314,8 +75464,8 @@ var init_harnessClient = __esm({
|
|
|
75314
75464
|
);
|
|
75315
75465
|
}
|
|
75316
75466
|
const id3 = this.nextId++;
|
|
75317
|
-
return new Promise((
|
|
75318
|
-
this.pending.set(id3, { resolve:
|
|
75467
|
+
return new Promise((resolve11, reject) => {
|
|
75468
|
+
this.pending.set(id3, { resolve: resolve11, reject });
|
|
75319
75469
|
this.transport.write(JSON.stringify({ id: id3, method, params }));
|
|
75320
75470
|
});
|
|
75321
75471
|
}
|
|
@@ -75341,6 +75491,18 @@ var init_harnessClient = __esm({
|
|
|
75341
75491
|
if (reason !== void 0) params["reason"] = reason;
|
|
75342
75492
|
return await this.request("session.cancel", params);
|
|
75343
75493
|
}
|
|
75494
|
+
/** t63: settle a permission.request (allow/deny/always-tool/always-category). */
|
|
75495
|
+
async permissionRespond(requestId, decision, sessionId2) {
|
|
75496
|
+
const params = { requestId, decision };
|
|
75497
|
+
if (sessionId2 !== void 0) params["sessionId"] = sessionId2;
|
|
75498
|
+
return await this.request("permission.respond", params);
|
|
75499
|
+
}
|
|
75500
|
+
/** t63: settle an ask_user.request (null = dismiss). */
|
|
75501
|
+
async askUserRespond(requestId, answer, sessionId2) {
|
|
75502
|
+
const params = { requestId, answer };
|
|
75503
|
+
if (sessionId2 !== void 0) params["sessionId"] = sessionId2;
|
|
75504
|
+
return await this.request("ask_user.respond", params);
|
|
75505
|
+
}
|
|
75344
75506
|
async disposeSession(sessionId2) {
|
|
75345
75507
|
await this.request("session.dispose", { sessionId: sessionId2 });
|
|
75346
75508
|
}
|
|
@@ -75370,6 +75532,9 @@ import { tmpdir as tmpdir4 } from "node:os";
|
|
|
75370
75532
|
function harnessServerMode() {
|
|
75371
75533
|
return process.env[HARNESS_SERVER_ENV] === "1";
|
|
75372
75534
|
}
|
|
75535
|
+
function isPermissionRequestEvent(ev) {
|
|
75536
|
+
return typeof ev === "object" && ev !== null && ev.type === "permission.request";
|
|
75537
|
+
}
|
|
75373
75538
|
var HARNESS_SERVER_ENV, RunManager;
|
|
75374
75539
|
var init_runManager = __esm({
|
|
75375
75540
|
"src/cli/companion/runManager.ts"() {
|
|
@@ -75427,6 +75592,13 @@ var init_runManager = __esm({
|
|
|
75427
75592
|
}
|
|
75428
75593
|
emit(ev) {
|
|
75429
75594
|
if (!this.active) return;
|
|
75595
|
+
if (this.active.permissionPreset === "yolo" && isPermissionRequestEvent(ev)) {
|
|
75596
|
+
const requestId = ev.requestId;
|
|
75597
|
+
if (typeof requestId === "string" && requestId.trim()) {
|
|
75598
|
+
void this.permissionRespond(this.active.run.id, requestId, "allow");
|
|
75599
|
+
return;
|
|
75600
|
+
}
|
|
75601
|
+
}
|
|
75430
75602
|
this.active.run.events.push(ev);
|
|
75431
75603
|
if (this.active.run.events.length > 5e3) {
|
|
75432
75604
|
this.active.run.events.splice(0, this.active.run.events.length - 4e3);
|
|
@@ -75438,7 +75610,7 @@ var init_runManager = __esm({
|
|
|
75438
75610
|
}
|
|
75439
75611
|
}
|
|
75440
75612
|
}
|
|
75441
|
-
start(args) {
|
|
75613
|
+
start(args, gate) {
|
|
75442
75614
|
if (this.active) {
|
|
75443
75615
|
return {
|
|
75444
75616
|
ok: false,
|
|
@@ -75460,9 +75632,79 @@ var init_runManager = __esm({
|
|
|
75460
75632
|
createdAt: Date.now(),
|
|
75461
75633
|
events: []
|
|
75462
75634
|
};
|
|
75635
|
+
if (gate?.awaitingTrust) {
|
|
75636
|
+
run.status = "awaiting_trust";
|
|
75637
|
+
this.active = {
|
|
75638
|
+
run,
|
|
75639
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
75640
|
+
trustArgs: args,
|
|
75641
|
+
trustMode: this.clientMode ? "harness" : "spawn",
|
|
75642
|
+
permissionPreset: args.permissionPreset
|
|
75643
|
+
};
|
|
75644
|
+
this.emit({
|
|
75645
|
+
type: "trust.pending",
|
|
75646
|
+
runId: id3,
|
|
75647
|
+
path: args.cwd,
|
|
75648
|
+
message: `[companion] run ${id3} awaiting desktop trust approval for ${args.cwd}`
|
|
75649
|
+
});
|
|
75650
|
+
return { ok: true, run, awaitingTrust: true };
|
|
75651
|
+
}
|
|
75463
75652
|
if (this.clientMode) {
|
|
75464
75653
|
return this.startViaHarness(run, args, mode, phase2);
|
|
75465
75654
|
}
|
|
75655
|
+
return this.launchSpawn(run, args);
|
|
75656
|
+
}
|
|
75657
|
+
/**
|
|
75658
|
+
* t66: desktop approved the parked run — launch it now, preserving the
|
|
75659
|
+
* listeners (phone SSE) attached while it was awaiting trust.
|
|
75660
|
+
*/
|
|
75661
|
+
releaseTrust() {
|
|
75662
|
+
const a = this.active;
|
|
75663
|
+
if (!a || a.run.status !== "awaiting_trust" || !a.trustArgs) {
|
|
75664
|
+
return { ok: false, error: "no run awaiting trust" };
|
|
75665
|
+
}
|
|
75666
|
+
const args = a.trustArgs;
|
|
75667
|
+
a.run.status = "running";
|
|
75668
|
+
this.emit({ type: "trust.settled", runId: a.run.id, approved: true });
|
|
75669
|
+
if (a.trustMode === "harness") {
|
|
75670
|
+
return this.startViaHarness(a.run, args, a.run.mode, a.run.phase);
|
|
75671
|
+
}
|
|
75672
|
+
return this.launchSpawn(a.run, args);
|
|
75673
|
+
}
|
|
75674
|
+
/** t66: desktop denied the parked run — fail it, fail-closed. */
|
|
75675
|
+
denyTrust(reason) {
|
|
75676
|
+
const a = this.active;
|
|
75677
|
+
if (!a || a.run.status !== "awaiting_trust") {
|
|
75678
|
+
return { ok: false, error: "no run awaiting trust" };
|
|
75679
|
+
}
|
|
75680
|
+
a.run.status = "error";
|
|
75681
|
+
a.run.error = reason;
|
|
75682
|
+
a.run.finishedAt = Date.now();
|
|
75683
|
+
this.emit({ type: "trust.settled", runId: a.run.id, approved: false });
|
|
75684
|
+
this.emit({
|
|
75685
|
+
type: "error",
|
|
75686
|
+
severity: "fatal",
|
|
75687
|
+
message: reason,
|
|
75688
|
+
code: "trust_denied"
|
|
75689
|
+
});
|
|
75690
|
+
this.emit({
|
|
75691
|
+
type: "run_finished",
|
|
75692
|
+
runId: a.run.id,
|
|
75693
|
+
status: "error",
|
|
75694
|
+
exitCode: null
|
|
75695
|
+
});
|
|
75696
|
+
this.finishActive();
|
|
75697
|
+
return { ok: true };
|
|
75698
|
+
}
|
|
75699
|
+
/** t66: current awaiting_trust run (if any) for GET /v1/trust/pending. */
|
|
75700
|
+
pendingTrust() {
|
|
75701
|
+
const a = this.active;
|
|
75702
|
+
if (!a || a.run.status !== "awaiting_trust") return null;
|
|
75703
|
+
return { runId: a.run.id, path: a.run.cwd };
|
|
75704
|
+
}
|
|
75705
|
+
/** t66: spawn-path launch, extracted from start() so releaseTrust can
|
|
75706
|
+
* launch a parked run. Preserves parked listeners (same run id). */
|
|
75707
|
+
launchSpawn(run, args) {
|
|
75466
75708
|
const cliEntry = process.argv[1];
|
|
75467
75709
|
if (!cliEntry) {
|
|
75468
75710
|
return { ok: false, error: "Cannot resolve CLI entry (process.argv[1])" };
|
|
@@ -75471,13 +75713,13 @@ var init_runManager = __esm({
|
|
|
75471
75713
|
cliEntry,
|
|
75472
75714
|
"--headless",
|
|
75473
75715
|
"--task",
|
|
75474
|
-
prompt,
|
|
75716
|
+
run.prompt,
|
|
75475
75717
|
"--output",
|
|
75476
75718
|
"json",
|
|
75477
75719
|
"--mode",
|
|
75478
|
-
mode === "council" || mode === "zelari" ? mode : "kraken",
|
|
75720
|
+
run.mode === "council" || run.mode === "zelari" ? run.mode : "kraken",
|
|
75479
75721
|
"--phase",
|
|
75480
|
-
|
|
75722
|
+
run.phase === "plan" ? "plan" : "build"
|
|
75481
75723
|
];
|
|
75482
75724
|
if (args.provider?.trim()) {
|
|
75483
75725
|
argv.push("--provider", args.provider.trim());
|
|
@@ -75485,9 +75727,14 @@ var init_runManager = __esm({
|
|
|
75485
75727
|
if (args.model?.trim()) {
|
|
75486
75728
|
argv.push("--model", args.model.trim());
|
|
75487
75729
|
}
|
|
75730
|
+
if (args.strictDone === true) argv.push("--strict-done");
|
|
75731
|
+
else if (args.strictDone === false) argv.push("--no-strict-done");
|
|
75732
|
+
if (args.permissionPreset) {
|
|
75733
|
+
argv.push("--permissions", args.permissionPreset);
|
|
75734
|
+
}
|
|
75488
75735
|
let historyFile;
|
|
75489
75736
|
if (args.history && Array.isArray(args.history) && args.history.length > 0) {
|
|
75490
|
-
historyFile = join49(tmpdir4(), `zelari-companion-hist-${
|
|
75737
|
+
historyFile = join49(tmpdir4(), `zelari-companion-hist-${run.id}.json`);
|
|
75491
75738
|
try {
|
|
75492
75739
|
writeFileSync27(historyFile, JSON.stringify(args.history), "utf8");
|
|
75493
75740
|
argv.push("--history-file", historyFile);
|
|
@@ -75501,15 +75748,26 @@ var init_runManager = __esm({
|
|
|
75501
75748
|
...process.env,
|
|
75502
75749
|
ZELARI_SKIP_PREFLIGHT: "1",
|
|
75503
75750
|
ANATHEMA_DEV: "1",
|
|
75504
|
-
FORCE_COLOR: "0"
|
|
75751
|
+
FORCE_COLOR: "0",
|
|
75752
|
+
// t65: belt-and-suspenders — the long-lived headless child reads the
|
|
75753
|
+
// preset straight from env even if it never re-parses --permissions;
|
|
75754
|
+
// mirrors main.ts's --permissions → ZELARI_PERMISSION_PRESET promotion.
|
|
75755
|
+
...args.permissionPreset ? { ZELARI_PERMISSION_PRESET: args.permissionPreset } : {}
|
|
75505
75756
|
},
|
|
75506
75757
|
stdio: ["ignore", "pipe", "pipe"],
|
|
75507
75758
|
windowsHide: true
|
|
75508
75759
|
});
|
|
75509
|
-
this.active
|
|
75760
|
+
const parked = this.active?.run.id === run.id ? this.active : null;
|
|
75761
|
+
this.active = {
|
|
75762
|
+
run,
|
|
75763
|
+
child,
|
|
75764
|
+
listeners: parked?.listeners ?? /* @__PURE__ */ new Set(),
|
|
75765
|
+
historyFile,
|
|
75766
|
+
permissionPreset: args.permissionPreset
|
|
75767
|
+
};
|
|
75510
75768
|
this.emit({
|
|
75511
75769
|
type: "log",
|
|
75512
|
-
message: `[companion] run ${
|
|
75770
|
+
message: `[companion] run ${run.id} started mode=${run.mode} phase=${run.phase} cwd=${args.cwd}`
|
|
75513
75771
|
});
|
|
75514
75772
|
if (child.stdout) {
|
|
75515
75773
|
const rl = createInterface4({ input: child.stdout });
|
|
@@ -75556,7 +75814,7 @@ var init_runManager = __esm({
|
|
|
75556
75814
|
}
|
|
75557
75815
|
this.emit({
|
|
75558
75816
|
type: "run_finished",
|
|
75559
|
-
runId:
|
|
75817
|
+
runId: run.id,
|
|
75560
75818
|
status: run.status,
|
|
75561
75819
|
exitCode: code
|
|
75562
75820
|
});
|
|
@@ -75571,7 +75829,12 @@ var init_runManager = __esm({
|
|
|
75571
75829
|
* reports through the usual run status + emit path.
|
|
75572
75830
|
*/
|
|
75573
75831
|
startViaHarness(run, args, mode, phase2) {
|
|
75574
|
-
this.active
|
|
75832
|
+
const parked = this.active?.run.id === run.id ? this.active : null;
|
|
75833
|
+
this.active = {
|
|
75834
|
+
run,
|
|
75835
|
+
listeners: parked?.listeners ?? /* @__PURE__ */ new Set(),
|
|
75836
|
+
permissionPreset: args.permissionPreset
|
|
75837
|
+
};
|
|
75575
75838
|
this.emit({
|
|
75576
75839
|
type: "log",
|
|
75577
75840
|
message: `[companion] run ${run.id} started mode=${mode} phase=${phase2} cwd=${args.cwd}`
|
|
@@ -75619,6 +75882,9 @@ var init_runManager = __esm({
|
|
|
75619
75882
|
if (Array.isArray(args.history) && args.history.length > 0) {
|
|
75620
75883
|
turnInput["history"] = args.history;
|
|
75621
75884
|
}
|
|
75885
|
+
if (args.permissionPreset) turnInput["permissionPreset"] = args.permissionPreset;
|
|
75886
|
+
if (args.strictDone !== void 0) turnInput["strictDone"] = args.strictDone;
|
|
75887
|
+
if (args.verifyPack !== void 0) turnInput["verifyPack"] = args.verifyPack;
|
|
75622
75888
|
const result = await client.runTurn(sessionId2, turnInput);
|
|
75623
75889
|
const stillOwner = this.active?.run.id === run.id;
|
|
75624
75890
|
if (stillOwner && run.status === "running") {
|
|
@@ -75719,6 +75985,51 @@ var init_runManager = __esm({
|
|
|
75719
75985
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
75720
75986
|
}
|
|
75721
75987
|
}
|
|
75988
|
+
/** t63: settle a permission.request on the active client-mode run. */
|
|
75989
|
+
async permissionRespond(runId, requestId, decision) {
|
|
75990
|
+
if (!this.active) return { ok: false, error: "No active run" };
|
|
75991
|
+
if (runId && this.active.run.id !== runId) {
|
|
75992
|
+
return { ok: false, error: `Run ${runId} is not active` };
|
|
75993
|
+
}
|
|
75994
|
+
const id3 = requestId?.trim();
|
|
75995
|
+
if (!id3) return { ok: false, error: "requestId is required" };
|
|
75996
|
+
if (!this.active.harnessSessionId || !this.harnessClient) {
|
|
75997
|
+
return {
|
|
75998
|
+
ok: false,
|
|
75999
|
+
error: `permission respond requires harness server mode (${HARNESS_SERVER_ENV}=1)`
|
|
76000
|
+
};
|
|
76001
|
+
}
|
|
76002
|
+
try {
|
|
76003
|
+
const result = await this.harnessClient.permissionRespond(id3, decision);
|
|
76004
|
+
return { ok: true, result };
|
|
76005
|
+
} catch (err) {
|
|
76006
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
76007
|
+
}
|
|
76008
|
+
}
|
|
76009
|
+
/** t63: settle an ask_user.request (answer null = dismiss). */
|
|
76010
|
+
async askUserRespond(runId, requestId, answer) {
|
|
76011
|
+
if (!this.active) return { ok: false, error: "No active run" };
|
|
76012
|
+
if (runId && this.active.run.id !== runId) {
|
|
76013
|
+
return { ok: false, error: `Run ${runId} is not active` };
|
|
76014
|
+
}
|
|
76015
|
+
const id3 = requestId?.trim();
|
|
76016
|
+
if (!id3) return { ok: false, error: "requestId is required" };
|
|
76017
|
+
if (answer != null && typeof answer !== "string") {
|
|
76018
|
+
return { ok: false, error: "answer must be a string or null" };
|
|
76019
|
+
}
|
|
76020
|
+
if (!this.active.harnessSessionId || !this.harnessClient) {
|
|
76021
|
+
return {
|
|
76022
|
+
ok: false,
|
|
76023
|
+
error: `ask respond requires harness server mode (${HARNESS_SERVER_ENV}=1)`
|
|
76024
|
+
};
|
|
76025
|
+
}
|
|
76026
|
+
try {
|
|
76027
|
+
const result = await this.harnessClient.askUserRespond(id3, answer);
|
|
76028
|
+
return { ok: true, result };
|
|
76029
|
+
} catch (err) {
|
|
76030
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
76031
|
+
}
|
|
76032
|
+
}
|
|
75722
76033
|
cancel(runId) {
|
|
75723
76034
|
if (!this.active) {
|
|
75724
76035
|
return { ok: false, error: "No active run" };
|
|
@@ -75810,8 +76121,8 @@ __export(serve_exports, {
|
|
|
75810
76121
|
runCompanionServe: () => runCompanionServe
|
|
75811
76122
|
});
|
|
75812
76123
|
import { createServer as createServer3 } from "node:http";
|
|
75813
|
-
import { existsSync as existsSync62 } from "node:fs";
|
|
75814
|
-
import { resolve as
|
|
76124
|
+
import { existsSync as existsSync62, readdirSync as readdirSync13 } from "node:fs";
|
|
76125
|
+
import { join as join50, resolve as resolve10 } from "node:path";
|
|
75815
76126
|
function readBody(req, max = 2e6) {
|
|
75816
76127
|
return new Promise((resolveBody, reject) => {
|
|
75817
76128
|
const chunks = [];
|
|
@@ -75858,7 +76169,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
75858
76169
|
const { token, created } = loadOrCreateToken(opts.token);
|
|
75859
76170
|
let projects = mergeProjects(fileCfg, opts.projects ?? []);
|
|
75860
76171
|
projects = projects.filter((p3) => {
|
|
75861
|
-
const abs =
|
|
76172
|
+
const abs = resolve10(p3.path);
|
|
75862
76173
|
if (!existsSync62(abs)) {
|
|
75863
76174
|
process.stderr.write(
|
|
75864
76175
|
`[zelari-code serve] skip missing project path: ${p3.path}
|
|
@@ -75878,7 +76189,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
75878
76189
|
});
|
|
75879
76190
|
}
|
|
75880
76191
|
if (projects.length === 0) {
|
|
75881
|
-
const cwd =
|
|
76192
|
+
const cwd = resolve10(process.cwd());
|
|
75882
76193
|
projects = [
|
|
75883
76194
|
{
|
|
75884
76195
|
id: "default",
|
|
@@ -75894,6 +76205,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
75894
76205
|
);
|
|
75895
76206
|
}
|
|
75896
76207
|
const runs = new RunManager();
|
|
76208
|
+
const fsFull = (opts.fsMode ?? "full") === "full";
|
|
75897
76209
|
const allowedOrigins = [
|
|
75898
76210
|
...loopbackOrigins(port),
|
|
75899
76211
|
...parseAllowedOrigins(process.env[COMPANION_ALLOWED_ORIGINS_ENV])
|
|
@@ -75935,6 +76247,65 @@ async function runCompanionServe(opts = {}) {
|
|
|
75935
76247
|
sendJson2(res, 200, { ok: true, ...snap });
|
|
75936
76248
|
return;
|
|
75937
76249
|
}
|
|
76250
|
+
if (req.method === "GET" && path104 === "/v1/fs") {
|
|
76251
|
+
const listFsRootsInline = () => {
|
|
76252
|
+
if (process.platform === "win32") {
|
|
76253
|
+
const roots = [];
|
|
76254
|
+
for (let code = 65; code <= 90; code++) {
|
|
76255
|
+
const letter = String.fromCharCode(code);
|
|
76256
|
+
const drive = `${letter}:\\`;
|
|
76257
|
+
if (existsSync62(drive)) {
|
|
76258
|
+
roots.push({
|
|
76259
|
+
id: `fs-${letter.toLowerCase()}`,
|
|
76260
|
+
name: drive,
|
|
76261
|
+
path: drive
|
|
76262
|
+
});
|
|
76263
|
+
}
|
|
76264
|
+
}
|
|
76265
|
+
return roots;
|
|
76266
|
+
}
|
|
76267
|
+
return [{ id: "fs-root", name: "/", path: "/" }];
|
|
76268
|
+
};
|
|
76269
|
+
const rawParam = url2.searchParams.get("path")?.trim() ?? "";
|
|
76270
|
+
if (!rawParam) {
|
|
76271
|
+
sendJson2(res, 200, {
|
|
76272
|
+
ok: true,
|
|
76273
|
+
roots: fsFull ? listFsRootsInline() : projects,
|
|
76274
|
+
entries: []
|
|
76275
|
+
});
|
|
76276
|
+
return;
|
|
76277
|
+
}
|
|
76278
|
+
const norm = rawParam.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
76279
|
+
const absolute = /^([a-zA-Z]:\/|\/)/.test(norm);
|
|
76280
|
+
const allowed = fsFull && absolute && !norm.split("/").includes("..") ? true : isUnderRoots(rawParam, projects).ok;
|
|
76281
|
+
if (!allowed) {
|
|
76282
|
+
sendJson2(res, 403, { ok: false, error: "path outside allowed roots" });
|
|
76283
|
+
return;
|
|
76284
|
+
}
|
|
76285
|
+
if (!existsSync62(rawParam)) {
|
|
76286
|
+
sendJson2(res, 404, { ok: false, error: "path not found" });
|
|
76287
|
+
return;
|
|
76288
|
+
}
|
|
76289
|
+
const dirs = readdirSync13(rawParam, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).sort((a, b) => a.name.localeCompare(b.name));
|
|
76290
|
+
const slash = norm.lastIndexOf("/");
|
|
76291
|
+
let parent = slash > 0 ? norm.slice(0, slash) : null;
|
|
76292
|
+
const rootHit = isUnderRoots(rawParam, projects);
|
|
76293
|
+
if (rootHit.ok) {
|
|
76294
|
+
const rootNorm = rootHit.root.path.replace(/\\/g, "/").toLowerCase().replace(/\/+$/, "");
|
|
76295
|
+
if (rootHit.normalized === rootNorm) parent = null;
|
|
76296
|
+
}
|
|
76297
|
+
sendJson2(res, 200, {
|
|
76298
|
+
ok: true,
|
|
76299
|
+
path: rawParam,
|
|
76300
|
+
parent,
|
|
76301
|
+
entries: dirs.map((d) => ({
|
|
76302
|
+
name: d.name,
|
|
76303
|
+
path: join50(rawParam, d.name),
|
|
76304
|
+
dir: true
|
|
76305
|
+
}))
|
|
76306
|
+
});
|
|
76307
|
+
return;
|
|
76308
|
+
}
|
|
75938
76309
|
if (req.method === "GET" && path104 === "/v1/projects") {
|
|
75939
76310
|
sendJson2(res, 200, {
|
|
75940
76311
|
ok: true,
|
|
@@ -75977,27 +76348,37 @@ async function runCompanionServe(opts = {}) {
|
|
|
75977
76348
|
const mode = String(body.mode ?? "kraken");
|
|
75978
76349
|
const phase2 = String(body.phase ?? "build");
|
|
75979
76350
|
const cwdArg = body.cwd != null ? String(body.cwd) : body.projectId != null ? String(body.projectId) : null;
|
|
75980
|
-
const resolved = resolveProjectPath(projects, cwdArg);
|
|
76351
|
+
const resolved = resolveProjectPath(projects, cwdArg, { fullFs: fsFull });
|
|
75981
76352
|
if (!resolved.ok) {
|
|
75982
76353
|
sendJson2(res, 400, { ok: false, error: resolved.error });
|
|
75983
76354
|
return;
|
|
75984
76355
|
}
|
|
75985
76356
|
const history2 = Array.isArray(body.history) ? body.history : void 0;
|
|
75986
|
-
const
|
|
76357
|
+
const presetRaw = typeof body.permissionPreset === "string" ? body.permissionPreset.trim().toLowerCase() : "";
|
|
76358
|
+
const permissionPreset = ["standard", "strict", "yolo"].includes(presetRaw) ? presetRaw : void 0;
|
|
76359
|
+
const strictDone = typeof body.strictDone === "boolean" ? body.strictDone : void 0;
|
|
76360
|
+
const verifyPack = typeof body.verifyPack === "boolean" ? body.verifyPack : void 0;
|
|
76361
|
+
const startArgs = {
|
|
75987
76362
|
prompt,
|
|
75988
76363
|
mode,
|
|
75989
76364
|
phase: phase2,
|
|
75990
76365
|
cwd: resolved.project.path,
|
|
75991
76366
|
provider: body.provider != null ? String(body.provider) : void 0,
|
|
75992
76367
|
model: body.model != null ? String(body.model) : void 0,
|
|
75993
|
-
history: history2
|
|
75994
|
-
|
|
76368
|
+
history: history2,
|
|
76369
|
+
permissionPreset,
|
|
76370
|
+
strictDone,
|
|
76371
|
+
verifyPack
|
|
76372
|
+
};
|
|
76373
|
+
const gate = fsFull && !resolved.trusted ? { awaitingTrust: true } : void 0;
|
|
76374
|
+
const result = runs.start(startArgs, gate);
|
|
75995
76375
|
if (!result.ok) {
|
|
75996
76376
|
sendJson2(res, 409, { ok: false, error: result.error });
|
|
75997
76377
|
return;
|
|
75998
76378
|
}
|
|
75999
76379
|
sendJson2(res, 201, {
|
|
76000
76380
|
ok: true,
|
|
76381
|
+
awaitingTrust: gate ? true : void 0,
|
|
76001
76382
|
run: {
|
|
76002
76383
|
id: result.run.id,
|
|
76003
76384
|
status: result.run.status,
|
|
@@ -76008,10 +76389,57 @@ async function runCompanionServe(opts = {}) {
|
|
|
76008
76389
|
},
|
|
76009
76390
|
eventsUrl: `/v1/runs/${result.run.id}/events`,
|
|
76010
76391
|
cancelUrl: `/v1/runs/${result.run.id}/cancel`,
|
|
76011
|
-
steerUrl: `/v1/runs/${result.run.id}/steer
|
|
76392
|
+
steerUrl: `/v1/runs/${result.run.id}/steer`,
|
|
76393
|
+
permissionUrl: `/v1/runs/${result.run.id}/permission`,
|
|
76394
|
+
askUrl: `/v1/runs/${result.run.id}/ask`
|
|
76012
76395
|
});
|
|
76013
76396
|
return;
|
|
76014
76397
|
}
|
|
76398
|
+
if (req.method === "POST" && path104 === "/v1/trust") {
|
|
76399
|
+
const raw = await readBody(req);
|
|
76400
|
+
let body = {};
|
|
76401
|
+
try {
|
|
76402
|
+
body = raw ? JSON.parse(raw) : {};
|
|
76403
|
+
} catch {
|
|
76404
|
+
sendJson2(res, 400, { ok: false, error: "invalid JSON body" });
|
|
76405
|
+
return;
|
|
76406
|
+
}
|
|
76407
|
+
const runId = typeof body.runId === "string" ? body.runId.trim() : "";
|
|
76408
|
+
if (!runId) {
|
|
76409
|
+
sendJson2(res, 400, { ok: false, error: "runId is required" });
|
|
76410
|
+
return;
|
|
76411
|
+
}
|
|
76412
|
+
const current = runs.pendingTrust();
|
|
76413
|
+
if (!current || current.runId !== runId) {
|
|
76414
|
+
sendJson2(res, 409, { ok: false, error: "no such awaiting_trust run" });
|
|
76415
|
+
return;
|
|
76416
|
+
}
|
|
76417
|
+
if (body.approve === true) {
|
|
76418
|
+
projects = mergeProjects({ ...fileCfg, projects }, [current.path]);
|
|
76419
|
+
try {
|
|
76420
|
+
saveCompanionConfig({ ...fileCfg, bind, port, projects });
|
|
76421
|
+
} catch {
|
|
76422
|
+
}
|
|
76423
|
+
const released = runs.releaseTrust();
|
|
76424
|
+
if (!released.ok) {
|
|
76425
|
+
sendJson2(res, 409, { ok: false, error: released.error });
|
|
76426
|
+
return;
|
|
76427
|
+
}
|
|
76428
|
+
sendJson2(res, 200, { ok: true, approved: runId, path: current.path });
|
|
76429
|
+
return;
|
|
76430
|
+
}
|
|
76431
|
+
const denied = runs.denyTrust("Trust negato sul desktop");
|
|
76432
|
+
if (!denied.ok) {
|
|
76433
|
+
sendJson2(res, 409, { ok: false, error: denied.error });
|
|
76434
|
+
return;
|
|
76435
|
+
}
|
|
76436
|
+
sendJson2(res, 200, { ok: true, denied: runId });
|
|
76437
|
+
return;
|
|
76438
|
+
}
|
|
76439
|
+
if (req.method === "GET" && path104 === "/v1/trust/pending") {
|
|
76440
|
+
sendJson2(res, 200, { ok: true, pending: runs.pendingTrust() });
|
|
76441
|
+
return;
|
|
76442
|
+
}
|
|
76015
76443
|
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path104);
|
|
76016
76444
|
if (req.method === "GET" && eventsMatch) {
|
|
76017
76445
|
const runId = eventsMatch[1];
|
|
@@ -76039,7 +76467,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
76039
76467
|
}
|
|
76040
76468
|
};
|
|
76041
76469
|
const unsub = runs.subscribe(runId, writeEv);
|
|
76042
|
-
if (run.status !== "running" && run.status !== "queued") {
|
|
76470
|
+
if (run.status !== "running" && run.status !== "queued" && run.status !== "awaiting_trust") {
|
|
76043
76471
|
writeEv({
|
|
76044
76472
|
type: "run_finished",
|
|
76045
76473
|
runId,
|
|
@@ -76065,7 +76493,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
76065
76493
|
req.on("close", onClose);
|
|
76066
76494
|
const check2 = setInterval(() => {
|
|
76067
76495
|
const r = runs.getRun(runId);
|
|
76068
|
-
if (!r || r.status !== "running" && r.status !== "queued") {
|
|
76496
|
+
if (!r || r.status !== "running" && r.status !== "queued" && r.status !== "awaiting_trust") {
|
|
76069
76497
|
clearInterval(check2);
|
|
76070
76498
|
clearInterval(heartbeat);
|
|
76071
76499
|
unsub();
|
|
@@ -76112,6 +76540,53 @@ async function runCompanionServe(opts = {}) {
|
|
|
76112
76540
|
sendJson2(res, 200, { ok: true, steered: runId, result: result.result });
|
|
76113
76541
|
return;
|
|
76114
76542
|
}
|
|
76543
|
+
const askMatch = /^\/v1\/runs\/([^/]+)\/(permission|ask)$/.exec(path104);
|
|
76544
|
+
if (req.method === "POST" && askMatch) {
|
|
76545
|
+
const runId = askMatch[1];
|
|
76546
|
+
const kind2 = askMatch[2];
|
|
76547
|
+
const raw = await readBody(req);
|
|
76548
|
+
let body = {};
|
|
76549
|
+
try {
|
|
76550
|
+
body = raw ? JSON.parse(raw) : {};
|
|
76551
|
+
} catch {
|
|
76552
|
+
sendJson2(res, 400, { ok: false, error: "invalid JSON body" });
|
|
76553
|
+
return;
|
|
76554
|
+
}
|
|
76555
|
+
const requestId = typeof body.requestId === "string" ? body.requestId.trim() : "";
|
|
76556
|
+
if (!requestId) {
|
|
76557
|
+
sendJson2(res, 400, { ok: false, error: "requestId is required" });
|
|
76558
|
+
return;
|
|
76559
|
+
}
|
|
76560
|
+
if (kind2 === "permission") {
|
|
76561
|
+
const decision = typeof body.decision === "string" ? body.decision.trim() : "";
|
|
76562
|
+
if (!["allow", "deny", "always-tool", "always-category"].includes(decision)) {
|
|
76563
|
+
sendJson2(res, 400, {
|
|
76564
|
+
ok: false,
|
|
76565
|
+
error: "decision must be allow|deny|always-tool|always-category"
|
|
76566
|
+
});
|
|
76567
|
+
return;
|
|
76568
|
+
}
|
|
76569
|
+
const result2 = await runs.permissionRespond(runId, requestId, decision);
|
|
76570
|
+
if (!result2.ok) {
|
|
76571
|
+
sendJson2(res, 404, { ok: false, error: result2.error });
|
|
76572
|
+
return;
|
|
76573
|
+
}
|
|
76574
|
+
sendJson2(res, 200, { ok: true, runId, requestId, result: result2.result });
|
|
76575
|
+
return;
|
|
76576
|
+
}
|
|
76577
|
+
const answer = body.answer == null ? null : typeof body.answer === "string" ? body.answer : void 0;
|
|
76578
|
+
if (answer === void 0) {
|
|
76579
|
+
sendJson2(res, 400, { ok: false, error: "answer must be a string or null" });
|
|
76580
|
+
return;
|
|
76581
|
+
}
|
|
76582
|
+
const result = await runs.askUserRespond(runId, requestId, answer);
|
|
76583
|
+
if (!result.ok) {
|
|
76584
|
+
sendJson2(res, 404, { ok: false, error: result.error });
|
|
76585
|
+
return;
|
|
76586
|
+
}
|
|
76587
|
+
sendJson2(res, 200, { ok: true, runId, requestId, result: result.result });
|
|
76588
|
+
return;
|
|
76589
|
+
}
|
|
76115
76590
|
sendJson2(res, 404, { ok: false, error: "not found" });
|
|
76116
76591
|
} catch (err) {
|
|
76117
76592
|
sendJson2(res, 500, {
|
|
@@ -76187,12 +76662,14 @@ function parseServeFlags(argv) {
|
|
|
76187
76662
|
}
|
|
76188
76663
|
const portRaw = get("--port");
|
|
76189
76664
|
const port = portRaw ? Number.parseInt(portRaw, 10) : void 0;
|
|
76665
|
+
const fsRaw = get("--fs");
|
|
76190
76666
|
return {
|
|
76191
76667
|
bind: get("--bind"),
|
|
76192
76668
|
port: Number.isFinite(port) ? port : void 0,
|
|
76193
76669
|
token: get("--token"),
|
|
76194
76670
|
projects,
|
|
76195
|
-
persistProjects: argv.includes("--save-projects")
|
|
76671
|
+
persistProjects: argv.includes("--save-projects"),
|
|
76672
|
+
fsMode: fsRaw === "allowlist" ? "allowlist" : fsRaw === "full" ? "full" : void 0
|
|
76196
76673
|
};
|
|
76197
76674
|
}
|
|
76198
76675
|
var init_serve = __esm({
|
|
@@ -76253,8 +76730,8 @@ __export(doctor_exports, {
|
|
|
76253
76730
|
firstBlockingRed: () => firstBlockingRed,
|
|
76254
76731
|
runDoctor: () => runDoctor
|
|
76255
76732
|
});
|
|
76256
|
-
import { execSync as
|
|
76257
|
-
import { existsSync as existsSync63, readFileSync as readFileSync46, readlinkSync, statSync as
|
|
76733
|
+
import { execSync as execSync3 } from "node:child_process";
|
|
76734
|
+
import { existsSync as existsSync63, readFileSync as readFileSync46, readlinkSync, statSync as statSync11 } from "node:fs";
|
|
76258
76735
|
import { createRequire as createRequire3 } from "node:module";
|
|
76259
76736
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
76260
76737
|
import path100 from "node:path";
|
|
@@ -76277,7 +76754,7 @@ function findPackageRoot(start) {
|
|
|
76277
76754
|
}
|
|
76278
76755
|
function tryExec(cmd) {
|
|
76279
76756
|
try {
|
|
76280
|
-
return
|
|
76757
|
+
return execSync3(cmd, {
|
|
76281
76758
|
encoding: "utf8",
|
|
76282
76759
|
stdio: ["ignore", "pipe", "ignore"]
|
|
76283
76760
|
}).trim();
|
|
@@ -76293,7 +76770,7 @@ function readPackageJson4() {
|
|
|
76293
76770
|
return null;
|
|
76294
76771
|
}
|
|
76295
76772
|
}
|
|
76296
|
-
function
|
|
76773
|
+
function getGlobalPrefix2() {
|
|
76297
76774
|
const fromNpm = tryExec("npm prefix -g");
|
|
76298
76775
|
if (fromNpm) return fromNpm;
|
|
76299
76776
|
return (process.env.npm_config_prefix || process.env.NPM_CONFIG_PREFIX || "").trim();
|
|
@@ -76302,7 +76779,7 @@ function isSourceCheckout() {
|
|
|
76302
76779
|
return existsSync63(path100.join(packageRoot, "src", "cli", "main.ts")) && existsSync63(path100.join(packageRoot, "apps", "desktop", "package.json"));
|
|
76303
76780
|
}
|
|
76304
76781
|
function checkShim(pkgName) {
|
|
76305
|
-
const prefix =
|
|
76782
|
+
const prefix = getGlobalPrefix2();
|
|
76306
76783
|
if (!prefix) {
|
|
76307
76784
|
return WARN("npm global prefix not detectable (run inside an npm context)");
|
|
76308
76785
|
}
|
|
@@ -76318,13 +76795,21 @@ function checkShim(pkgName) {
|
|
|
76318
76795
|
optional: npm install -g ${pkgName}@latest --force`
|
|
76319
76796
|
);
|
|
76320
76797
|
}
|
|
76798
|
+
const installKind = resolveInstallKind();
|
|
76799
|
+
if (installKind === "npx" || installKind === "local") {
|
|
76800
|
+
return WARN(
|
|
76801
|
+
`non-global install (${installKind}) \u2014 no global shim at ${shimPath}
|
|
76802
|
+
PATH/shim expectations do not apply to an npx or local run
|
|
76803
|
+
for a persistent install: npm install -g ${pkgName}@latest`
|
|
76804
|
+
);
|
|
76805
|
+
}
|
|
76321
76806
|
return FAIL(
|
|
76322
76807
|
`shim not found at ${shimPath}
|
|
76323
76808
|
fix: npm install -g ${pkgName}@latest --force`
|
|
76324
76809
|
);
|
|
76325
76810
|
}
|
|
76326
76811
|
try {
|
|
76327
|
-
const st =
|
|
76812
|
+
const st = statSync11(shimPath);
|
|
76328
76813
|
if (isWin) {
|
|
76329
76814
|
const content = readFileSync46(shimPath, "utf8");
|
|
76330
76815
|
if (content.includes(`${pkgName}\\bin\\`) || content.includes(`${pkgName}/bin/`)) {
|
|
@@ -76395,7 +76880,7 @@ function checkBundle() {
|
|
|
76395
76880
|
);
|
|
76396
76881
|
}
|
|
76397
76882
|
try {
|
|
76398
|
-
const st =
|
|
76883
|
+
const st = statSync11(bundle);
|
|
76399
76884
|
return OK(`bundle OK (${(st.size / 1024 / 1024).toFixed(2)} MB)`);
|
|
76400
76885
|
} catch (err) {
|
|
76401
76886
|
return FAIL(
|
|
@@ -76425,7 +76910,7 @@ function checkRuntimeDeps() {
|
|
|
76425
76910
|
);
|
|
76426
76911
|
}
|
|
76427
76912
|
function checkPath() {
|
|
76428
|
-
const prefix =
|
|
76913
|
+
const prefix = getGlobalPrefix2();
|
|
76429
76914
|
if (!prefix) return WARN("npm global prefix not detectable");
|
|
76430
76915
|
const pathSep = process.platform === "win32" ? ";" : ":";
|
|
76431
76916
|
const pathDirs = (process.env.PATH || "").split(pathSep);
|
|
@@ -76643,7 +77128,7 @@ async function runDoctor() {
|
|
|
76643
77128
|
console.log(`zelari-code doctor (v${pkg?.version ?? "unknown"})`);
|
|
76644
77129
|
console.log("platform:", process.platform, process.arch);
|
|
76645
77130
|
console.log("node: ", process.version);
|
|
76646
|
-
console.log("prefix: ",
|
|
77131
|
+
console.log("prefix: ", getGlobalPrefix2() || "(unknown)");
|
|
76647
77132
|
console.log("root: ", packageRoot);
|
|
76648
77133
|
console.log("");
|
|
76649
77134
|
let criticalFails = 0;
|
|
@@ -76684,6 +77169,7 @@ var init_doctor = __esm({
|
|
|
76684
77169
|
init_prereqChecks();
|
|
76685
77170
|
init_metrics3();
|
|
76686
77171
|
init_contextGrowthSummary();
|
|
77172
|
+
init_updater();
|
|
76687
77173
|
require3 = createRequire3(import.meta.url);
|
|
76688
77174
|
__dirname3 = path100.dirname(fileURLToPath3(import.meta.url));
|
|
76689
77175
|
packageRoot = findPackageRoot(__dirname3);
|
|
@@ -76711,7 +77197,7 @@ __export(fixPath_exports, {
|
|
|
76711
77197
|
repairWindowsUserPath: () => repairWindowsUserPath
|
|
76712
77198
|
});
|
|
76713
77199
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
76714
|
-
function
|
|
77200
|
+
function getGlobalPrefix3() {
|
|
76715
77201
|
try {
|
|
76716
77202
|
const fromNpm = spawnSync3("npm", ["prefix", "-g"], {
|
|
76717
77203
|
encoding: "utf8",
|
|
@@ -76736,7 +77222,7 @@ function powershell(script) {
|
|
|
76736
77222
|
}
|
|
76737
77223
|
}
|
|
76738
77224
|
function repairWindowsUserPath() {
|
|
76739
|
-
const prefix =
|
|
77225
|
+
const prefix = getGlobalPrefix3();
|
|
76740
77226
|
if (!prefix) {
|
|
76741
77227
|
return {
|
|
76742
77228
|
ok: false,
|
|
@@ -77146,7 +77632,7 @@ __export(inspect_exports, {
|
|
|
77146
77632
|
runInspect: () => runInspect
|
|
77147
77633
|
});
|
|
77148
77634
|
import path103 from "node:path";
|
|
77149
|
-
import { existsSync as existsSync66, readFileSync as readFileSync48, readdirSync as
|
|
77635
|
+
import { existsSync as existsSync66, readFileSync as readFileSync48, readdirSync as readdirSync14 } from "node:fs";
|
|
77150
77636
|
async function collectInspectReport(cwd = process.cwd()) {
|
|
77151
77637
|
ensureBuiltinSkillsLoadedSync();
|
|
77152
77638
|
const snap = listSkillsSnapshot(cwd);
|
|
@@ -77215,7 +77701,7 @@ async function collectInspectReport(cwd = process.cwd()) {
|
|
|
77215
77701
|
}
|
|
77216
77702
|
function listJsonFiles(dir) {
|
|
77217
77703
|
try {
|
|
77218
|
-
return
|
|
77704
|
+
return readdirSync14(dir).filter((f) => f.endsWith(".json")).sort();
|
|
77219
77705
|
} catch {
|
|
77220
77706
|
return [];
|
|
77221
77707
|
}
|
|
@@ -77682,12 +78168,12 @@ function mergeChanges(unstaged, staged, untrackedPaths) {
|
|
|
77682
78168
|
return [...byPath.values()].sort((a, b) => churn(b) - churn(a));
|
|
77683
78169
|
}
|
|
77684
78170
|
function runGit(args, cwd) {
|
|
77685
|
-
return new Promise((
|
|
78171
|
+
return new Promise((resolve11, reject) => {
|
|
77686
78172
|
execFile(
|
|
77687
78173
|
"git",
|
|
77688
78174
|
args,
|
|
77689
78175
|
{ cwd, timeout: 5e3, windowsHide: true, maxBuffer: 4 * 1024 * 1024 },
|
|
77690
|
-
(err, stdout) => err ? reject(err) :
|
|
78176
|
+
(err, stdout) => err ? reject(err) : resolve11(stdout)
|
|
77691
78177
|
);
|
|
77692
78178
|
});
|
|
77693
78179
|
}
|
|
@@ -80266,7 +80752,7 @@ init_toolPermissions();
|
|
|
80266
80752
|
init_askUserTimeout();
|
|
80267
80753
|
function createPermissionAskHandler(opts) {
|
|
80268
80754
|
const { setPicker: setPicker2, appendSystem: appendSystem2 } = opts;
|
|
80269
|
-
return (req) => new Promise((
|
|
80755
|
+
return (req) => new Promise((resolve11) => {
|
|
80270
80756
|
const cats = req.categories;
|
|
80271
80757
|
const catLabel = cats.length === 1 ? cats[0] : cats.join("+") || "action";
|
|
80272
80758
|
const title = `Allow tool "${req.toolName}"?`;
|
|
@@ -80292,7 +80778,7 @@ ${detail}${note}${claimsBlock}
|
|
|
80292
80778
|
cancelAskTimeout();
|
|
80293
80779
|
setPicker2(null);
|
|
80294
80780
|
if (note2) appendSystem2?.(note2, Date.now());
|
|
80295
|
-
|
|
80781
|
+
resolve11(ok);
|
|
80296
80782
|
};
|
|
80297
80783
|
cancelAskTimeout = armPickerTimeout(
|
|
80298
80784
|
() => finish2(
|
|
@@ -80491,10 +80977,10 @@ function useChatTurn(params) {
|
|
|
80491
80977
|
}
|
|
80492
80978
|
} catch {
|
|
80493
80979
|
}
|
|
80494
|
-
const onAskUser = setPicker2 ? (req) => new Promise((
|
|
80980
|
+
const onAskUser = setPicker2 ? (req) => new Promise((resolve11) => {
|
|
80495
80981
|
const choices = req.choices ?? [];
|
|
80496
80982
|
if (choices.length < 2) {
|
|
80497
|
-
|
|
80983
|
+
resolve11(null);
|
|
80498
80984
|
return;
|
|
80499
80985
|
}
|
|
80500
80986
|
setLastClarification({
|
|
@@ -80518,7 +81004,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il turno continua dopo
|
|
|
80518
81004
|
settled = true;
|
|
80519
81005
|
cancelAskTimeout();
|
|
80520
81006
|
setPicker2(null);
|
|
80521
|
-
|
|
81007
|
+
resolve11(value);
|
|
80522
81008
|
};
|
|
80523
81009
|
cancelAskTimeout = armPickerTimeout(
|
|
80524
81010
|
() => {
|
|
@@ -81464,10 +81950,10 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
81464
81950
|
const { composeProjectContext: composeProjectContext2 } = await Promise.resolve().then(() => (init_composeContext(), composeContext_exports));
|
|
81465
81951
|
const { FeedbackStore: FeedbackStore2 } = await Promise.resolve().then(() => (init_councilFeedback(), councilFeedback_exports));
|
|
81466
81952
|
const workPhase = getPhase();
|
|
81467
|
-
const onAskUserCouncil = setPicker2 ? (req) => new Promise((
|
|
81953
|
+
const onAskUserCouncil = setPicker2 ? (req) => new Promise((resolve11) => {
|
|
81468
81954
|
const choices = req.choices ?? [];
|
|
81469
81955
|
if (choices.length < 2) {
|
|
81470
|
-
|
|
81956
|
+
resolve11(null);
|
|
81471
81957
|
return;
|
|
81472
81958
|
}
|
|
81473
81959
|
setLastClarification({
|
|
@@ -81491,7 +81977,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
81491
81977
|
settled = true;
|
|
81492
81978
|
cancelAskTimeout();
|
|
81493
81979
|
setPicker2(null);
|
|
81494
|
-
|
|
81980
|
+
resolve11(value);
|
|
81495
81981
|
};
|
|
81496
81982
|
cancelAskTimeout = armPickerTimeout(
|
|
81497
81983
|
() => {
|
|
@@ -81673,10 +82159,10 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
81673
82159
|
appendSystem(setMessages, message, Date.now());
|
|
81674
82160
|
},
|
|
81675
82161
|
// v1.8.0: pause council when a member asks a structured question.
|
|
81676
|
-
onClarification: setPicker2 ? (req) => new Promise((
|
|
82162
|
+
onClarification: setPicker2 ? (req) => new Promise((resolve11) => {
|
|
81677
82163
|
const choices = req.choices ?? [];
|
|
81678
82164
|
if (choices.length < 2) {
|
|
81679
|
-
|
|
82165
|
+
resolve11(null);
|
|
81680
82166
|
return;
|
|
81681
82167
|
}
|
|
81682
82168
|
setLastClarification({
|
|
@@ -81697,7 +82183,7 @@ _(${req.context})_` : "") + "\n\u2192 scegli dalla lista (il membro riprende dop
|
|
|
81697
82183
|
if (settled) return;
|
|
81698
82184
|
settled = true;
|
|
81699
82185
|
setPicker2(null);
|
|
81700
|
-
|
|
82186
|
+
resolve11(value);
|
|
81701
82187
|
};
|
|
81702
82188
|
setPicker2({
|
|
81703
82189
|
kind: "clarification",
|
|
@@ -82355,10 +82841,10 @@ function usePermissionBroker(opts) {
|
|
|
82355
82841
|
setPicker: setPicker2,
|
|
82356
82842
|
appendSystem: (msg, at) => appendSystem(setMessages, msg, at ?? Date.now())
|
|
82357
82843
|
});
|
|
82358
|
-
const onQuestion = (req) => new Promise((
|
|
82844
|
+
const onQuestion = (req) => new Promise((resolve11) => {
|
|
82359
82845
|
const choices = (req.choices ?? []).map((c) => String(c).trim()).filter((c) => c.length > 0);
|
|
82360
82846
|
if (choices.length < 2) {
|
|
82361
|
-
|
|
82847
|
+
resolve11(null);
|
|
82362
82848
|
return;
|
|
82363
82849
|
}
|
|
82364
82850
|
let settled = false;
|
|
@@ -82368,7 +82854,7 @@ function usePermissionBroker(opts) {
|
|
|
82368
82854
|
settled = true;
|
|
82369
82855
|
cancelWaitTimeout?.();
|
|
82370
82856
|
setPicker2(null);
|
|
82371
|
-
|
|
82857
|
+
resolve11(value);
|
|
82372
82858
|
};
|
|
82373
82859
|
const waitTimeoutMs = askUserTimeoutMs();
|
|
82374
82860
|
cancelWaitTimeout = armPickerTimeout(() => {
|
|
@@ -84622,7 +85108,8 @@ async function handleUpdateCheck(ctx) {
|
|
|
84622
85108
|
appendSystem(
|
|
84623
85109
|
ctx.setMessages,
|
|
84624
85110
|
`[update] \u{1F195} zelari-code ${info.latestVersion} available (current: ${info.currentVersion})
|
|
84625
|
-
Run \`/update --yes\` to install
|
|
85111
|
+
Run \`/update --yes\` to install (global installs only).
|
|
85112
|
+
On npx/local installs, update with \`npx zelari-code@latest\` \u2014 you'll need to restart manually after.`
|
|
84626
85113
|
);
|
|
84627
85114
|
} else {
|
|
84628
85115
|
appendSystem(
|
|
@@ -84639,7 +85126,18 @@ async function handleUpdateCheck(ctx) {
|
|
|
84639
85126
|
}
|
|
84640
85127
|
async function handleUpdatePerform(ctx) {
|
|
84641
85128
|
try {
|
|
84642
|
-
const {
|
|
85129
|
+
const {
|
|
85130
|
+
performUpdate: performUpdate2,
|
|
85131
|
+
resolveInstallKind: resolveInstallKind2,
|
|
85132
|
+
nonGlobalUpdateAdvisory: nonGlobalUpdateAdvisory2,
|
|
85133
|
+
distTagForVersion: distTagForVersion2,
|
|
85134
|
+
getCurrentVersion: getCurrentVersion2
|
|
85135
|
+
} = await Promise.resolve().then(() => (init_updater(), updater_exports));
|
|
85136
|
+
const kind2 = resolveInstallKind2();
|
|
85137
|
+
if (kind2 === "npx" || kind2 === "local") {
|
|
85138
|
+
appendSystem(ctx.setMessages, nonGlobalUpdateAdvisory2(kind2));
|
|
85139
|
+
return;
|
|
85140
|
+
}
|
|
84643
85141
|
const tag = distTagForVersion2(getCurrentVersion2());
|
|
84644
85142
|
appendSystem(
|
|
84645
85143
|
ctx.setMessages,
|
|
@@ -84746,7 +85244,7 @@ ${browsers.output}` : "") + (browsers.ok ? "" : `
|
|
|
84746
85244
|
return result;
|
|
84747
85245
|
}
|
|
84748
85246
|
function runPlaywrightInstallChromium(cwd, executor) {
|
|
84749
|
-
return new Promise((
|
|
85247
|
+
return new Promise((resolve11) => {
|
|
84750
85248
|
let stdout = "";
|
|
84751
85249
|
let stderr = "";
|
|
84752
85250
|
const stdio = ["ignore", "pipe", "pipe"];
|
|
@@ -84759,7 +85257,7 @@ function runPlaywrightInstallChromium(cwd, executor) {
|
|
|
84759
85257
|
stderr += chunk.toString();
|
|
84760
85258
|
});
|
|
84761
85259
|
child.on("error", (err) => {
|
|
84762
|
-
|
|
85260
|
+
resolve11({
|
|
84763
85261
|
ok: false,
|
|
84764
85262
|
output: stdout + stderr,
|
|
84765
85263
|
error: err.message,
|
|
@@ -84768,7 +85266,7 @@ function runPlaywrightInstallChromium(cwd, executor) {
|
|
|
84768
85266
|
});
|
|
84769
85267
|
child.on("close", (code) => {
|
|
84770
85268
|
const ok = code === 0;
|
|
84771
|
-
|
|
85269
|
+
resolve11({
|
|
84772
85270
|
ok,
|
|
84773
85271
|
output: stdout + stderr,
|
|
84774
85272
|
exitCode: code,
|
|
@@ -84778,7 +85276,7 @@ function runPlaywrightInstallChromium(cwd, executor) {
|
|
|
84778
85276
|
});
|
|
84779
85277
|
}
|
|
84780
85278
|
function runNpm2(executor, args, cwd, mode, npmCliPath) {
|
|
84781
|
-
return new Promise((
|
|
85279
|
+
return new Promise((resolve11) => {
|
|
84782
85280
|
let stdout = "";
|
|
84783
85281
|
let stderr = "";
|
|
84784
85282
|
const stdio = ["ignore", "pipe", "pipe"];
|
|
@@ -84790,7 +85288,7 @@ function runNpm2(executor, args, cwd, mode, npmCliPath) {
|
|
|
84790
85288
|
stderr += chunk.toString();
|
|
84791
85289
|
});
|
|
84792
85290
|
child.on("error", (err) => {
|
|
84793
|
-
|
|
85291
|
+
resolve11({
|
|
84794
85292
|
ok: false,
|
|
84795
85293
|
output: stdout + stderr,
|
|
84796
85294
|
error: err.message,
|
|
@@ -84799,7 +85297,7 @@ function runNpm2(executor, args, cwd, mode, npmCliPath) {
|
|
|
84799
85297
|
});
|
|
84800
85298
|
child.on("close", (code) => {
|
|
84801
85299
|
const ok = code === 0;
|
|
84802
|
-
|
|
85300
|
+
resolve11({
|
|
84803
85301
|
ok,
|
|
84804
85302
|
output: stdout + stderr,
|
|
84805
85303
|
exitCode: code,
|
|
@@ -87263,7 +87761,7 @@ function runPreflight() {
|
|
|
87263
87761
|
}
|
|
87264
87762
|
async function backgroundUpdateCheck() {
|
|
87265
87763
|
if (process.env.ANATHEMA_DEV === "1") return;
|
|
87266
|
-
await new Promise((
|
|
87764
|
+
await new Promise((resolve11) => setTimeout(resolve11, 3e3));
|
|
87267
87765
|
try {
|
|
87268
87766
|
const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_updater(), updater_exports));
|
|
87269
87767
|
const info = await checkForUpdate2();
|
|
@@ -88064,7 +88562,7 @@ function main() {
|
|
|
88064
88562
|
closeMcpClients2();
|
|
88065
88563
|
} catch {
|
|
88066
88564
|
}
|
|
88067
|
-
await new Promise((
|
|
88565
|
+
await new Promise((resolve11) => setImmediate(resolve11));
|
|
88068
88566
|
process.exit(code);
|
|
88069
88567
|
}).catch(async (err) => {
|
|
88070
88568
|
console.error(
|