@slayzone/computer 0.36.2 → 0.36.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.cjs +981 -445
- package/dist/bin.cjs.map +4 -4
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -4415,26 +4415,26 @@ var require_ignore = __commonJS({
|
|
|
4415
4415
|
const index = body.indexOf(SLASH);
|
|
4416
4416
|
return index < 0 || index === body.length - 1;
|
|
4417
4417
|
};
|
|
4418
|
-
var basenameOf = (
|
|
4419
|
-
const end =
|
|
4420
|
-
const index =
|
|
4418
|
+
var basenameOf = (path11) => {
|
|
4419
|
+
const end = path11.length - 1;
|
|
4420
|
+
const index = path11.lastIndexOf(
|
|
4421
4421
|
SLASH,
|
|
4422
|
-
|
|
4422
|
+
path11[end] === SLASH ? end - 1 : end
|
|
4423
4423
|
);
|
|
4424
|
-
return index < 0 ?
|
|
4424
|
+
return index < 0 ? path11 : path11.slice(index + 1);
|
|
4425
4425
|
};
|
|
4426
|
-
var parentOf = (
|
|
4427
|
-
if (
|
|
4428
|
-
const slices =
|
|
4426
|
+
var parentOf = (path11) => {
|
|
4427
|
+
if (path11.charCodeAt(0) === SLASH_CODE || path11.indexOf(DOUBLE_SLASH) >= 0) {
|
|
4428
|
+
const slices = path11.split(SLASH).filter(Boolean);
|
|
4429
4429
|
slices.pop();
|
|
4430
4430
|
return slices.length ? slices.join(SLASH) + SLASH : EMPTY;
|
|
4431
4431
|
}
|
|
4432
|
-
const end =
|
|
4433
|
-
const cut =
|
|
4432
|
+
const end = path11.length - 1;
|
|
4433
|
+
const cut = path11.lastIndexOf(
|
|
4434
4434
|
SLASH,
|
|
4435
|
-
|
|
4435
|
+
path11.charCodeAt(end) === SLASH_CODE ? end - 1 : end
|
|
4436
4436
|
);
|
|
4437
|
-
return cut < 0 ? EMPTY :
|
|
4437
|
+
return cut < 0 ? EMPTY : path11.slice(0, cut + 1);
|
|
4438
4438
|
};
|
|
4439
4439
|
var isString2 = (subject) => typeof subject === "string";
|
|
4440
4440
|
var checkPattern = (pattern) => pattern && isString2(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
|
|
@@ -4543,20 +4543,20 @@ var require_ignore = __commonJS({
|
|
|
4543
4543
|
// path matching.
|
|
4544
4544
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
4545
4545
|
// @returns {TestResult} true if a file is ignored
|
|
4546
|
-
test(
|
|
4546
|
+
test(path11, checkUnignored, mode) {
|
|
4547
4547
|
let ignored = false;
|
|
4548
4548
|
let unignored = false;
|
|
4549
4549
|
let matchedRule;
|
|
4550
4550
|
const rules = this._rules;
|
|
4551
4551
|
const { length } = rules;
|
|
4552
4552
|
const shortcut = this._basenameCount * 2 >= length;
|
|
4553
|
-
const basename5 = shortcut ? basenameOf(
|
|
4553
|
+
const basename5 = shortcut ? basenameOf(path11) : path11;
|
|
4554
4554
|
for (let index = 0; index < length; index++) {
|
|
4555
4555
|
const rule = rules[index];
|
|
4556
4556
|
const { negative } = rule;
|
|
4557
4557
|
const skip = unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored;
|
|
4558
4558
|
if (!skip && rule[mode].test(
|
|
4559
|
-
shortcut && rule._basenameOnly ? basename5 :
|
|
4559
|
+
shortcut && rule._basenameOnly ? basename5 : path11
|
|
4560
4560
|
)) {
|
|
4561
4561
|
ignored = !negative;
|
|
4562
4562
|
unignored = negative;
|
|
@@ -4576,17 +4576,17 @@ var require_ignore = __commonJS({
|
|
|
4576
4576
|
var throwError = (message, Ctor) => {
|
|
4577
4577
|
throw new Ctor(message);
|
|
4578
4578
|
};
|
|
4579
|
-
var checkPath = (
|
|
4580
|
-
if (!isString2(
|
|
4579
|
+
var checkPath = (path11, originalPath, doThrow) => {
|
|
4580
|
+
if (!isString2(path11)) {
|
|
4581
4581
|
return doThrow(
|
|
4582
4582
|
`path must be a string, but got \`${originalPath}\``,
|
|
4583
4583
|
TypeError
|
|
4584
4584
|
);
|
|
4585
4585
|
}
|
|
4586
|
-
if (!
|
|
4586
|
+
if (!path11) {
|
|
4587
4587
|
return doThrow(`path must not be empty`, TypeError);
|
|
4588
4588
|
}
|
|
4589
|
-
if (checkPath.isNotRelative(
|
|
4589
|
+
if (checkPath.isNotRelative(path11)) {
|
|
4590
4590
|
const r = "`path.relative()`d";
|
|
4591
4591
|
return doThrow(
|
|
4592
4592
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -4595,25 +4595,25 @@ var require_ignore = __commonJS({
|
|
|
4595
4595
|
}
|
|
4596
4596
|
return true;
|
|
4597
4597
|
};
|
|
4598
|
-
var isNotRelative = (
|
|
4599
|
-
const first =
|
|
4598
|
+
var isNotRelative = (path11) => {
|
|
4599
|
+
const first = path11.charCodeAt(0);
|
|
4600
4600
|
if (first === SLASH_CODE) {
|
|
4601
4601
|
return true;
|
|
4602
4602
|
}
|
|
4603
4603
|
if (first !== DOT_CODE) {
|
|
4604
4604
|
return false;
|
|
4605
4605
|
}
|
|
4606
|
-
if (
|
|
4606
|
+
if (path11.length === 1) {
|
|
4607
4607
|
return true;
|
|
4608
4608
|
}
|
|
4609
|
-
const second =
|
|
4609
|
+
const second = path11.charCodeAt(1);
|
|
4610
4610
|
if (second === SLASH_CODE) {
|
|
4611
4611
|
return true;
|
|
4612
4612
|
}
|
|
4613
4613
|
if (second !== DOT_CODE) {
|
|
4614
4614
|
return false;
|
|
4615
4615
|
}
|
|
4616
|
-
return
|
|
4616
|
+
return path11.length === 2 || path11.charCodeAt(2) === SLASH_CODE;
|
|
4617
4617
|
};
|
|
4618
4618
|
checkPath.isNotRelative = isNotRelative;
|
|
4619
4619
|
checkPath.convert = (p) => p;
|
|
@@ -4644,56 +4644,56 @@ var require_ignore = __commonJS({
|
|
|
4644
4644
|
}
|
|
4645
4645
|
// @returns {TestResult}
|
|
4646
4646
|
_test(originalPath, cache, checkUnignored) {
|
|
4647
|
-
const
|
|
4647
|
+
const path11 = originalPath && checkPath.convert(originalPath);
|
|
4648
4648
|
checkPath(
|
|
4649
|
-
|
|
4649
|
+
path11,
|
|
4650
4650
|
originalPath,
|
|
4651
4651
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
4652
4652
|
);
|
|
4653
|
-
return this._t(
|
|
4653
|
+
return this._t(path11, cache, checkUnignored);
|
|
4654
4654
|
}
|
|
4655
|
-
checkIgnore(
|
|
4656
|
-
if (
|
|
4657
|
-
return this.test(
|
|
4655
|
+
checkIgnore(path11) {
|
|
4656
|
+
if (path11.charCodeAt(path11.length - 1) !== SLASH_CODE) {
|
|
4657
|
+
return this.test(path11);
|
|
4658
4658
|
}
|
|
4659
|
-
const parentPath = parentOf(
|
|
4659
|
+
const parentPath = parentOf(path11);
|
|
4660
4660
|
if (parentPath) {
|
|
4661
4661
|
const parent = this._t(parentPath, this._testCache, true);
|
|
4662
4662
|
if (parent.ignored) {
|
|
4663
4663
|
return parent;
|
|
4664
4664
|
}
|
|
4665
4665
|
}
|
|
4666
|
-
return this._rules.test(
|
|
4666
|
+
return this._rules.test(path11, false, MODE_CHECK_IGNORE);
|
|
4667
4667
|
}
|
|
4668
|
-
_t(
|
|
4669
|
-
if (
|
|
4670
|
-
return cache[
|
|
4668
|
+
_t(path11, cache, checkUnignored) {
|
|
4669
|
+
if (path11 in cache) {
|
|
4670
|
+
return cache[path11];
|
|
4671
4671
|
}
|
|
4672
|
-
const parentPath = parentOf(
|
|
4672
|
+
const parentPath = parentOf(path11);
|
|
4673
4673
|
const parent = parentPath ? this._t(parentPath, cache, checkUnignored) : UNDEFINED;
|
|
4674
|
-
return cache[
|
|
4674
|
+
return cache[path11] = parent && parent.ignored ? parent : this._rules.test(path11, checkUnignored, MODE_IGNORE);
|
|
4675
4675
|
}
|
|
4676
|
-
ignores(
|
|
4677
|
-
return this._test(
|
|
4676
|
+
ignores(path11) {
|
|
4677
|
+
return this._test(path11, this._ignoreCache, false).ignored;
|
|
4678
4678
|
}
|
|
4679
4679
|
createFilter() {
|
|
4680
|
-
return (
|
|
4680
|
+
return (path11) => !this.ignores(path11);
|
|
4681
4681
|
}
|
|
4682
4682
|
filter(paths) {
|
|
4683
4683
|
return makeArray(paths).filter(this.createFilter());
|
|
4684
4684
|
}
|
|
4685
4685
|
// @returns {TestResult}
|
|
4686
|
-
test(
|
|
4687
|
-
return this._test(
|
|
4686
|
+
test(path11) {
|
|
4687
|
+
return this._test(path11, this._testCache, true);
|
|
4688
4688
|
}
|
|
4689
4689
|
};
|
|
4690
4690
|
var factory = (options) => new Ignore(options);
|
|
4691
|
-
var isPathValid = (
|
|
4691
|
+
var isPathValid = (path11) => checkPath(path11 && checkPath.convert(path11), path11, RETURN_FALSE);
|
|
4692
4692
|
var setupWindows = () => {
|
|
4693
4693
|
const makePosix = (str2) => /^\\\\\?\\/.test(str2) || /["<>|\u0000-\u001F]+/u.test(str2) ? str2 : str2.replace(/\\/g, "/");
|
|
4694
4694
|
checkPath.convert = makePosix;
|
|
4695
4695
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
4696
|
-
checkPath.isNotRelative = (
|
|
4696
|
+
checkPath.isNotRelative = (path11) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path11) || isNotRelative(path11);
|
|
4697
4697
|
};
|
|
4698
4698
|
if (
|
|
4699
4699
|
// Detect `process` so that it can run in browsers.
|
|
@@ -5220,10 +5220,10 @@ var init_agent_hooks = __esm({
|
|
|
5220
5220
|
}
|
|
5221
5221
|
});
|
|
5222
5222
|
|
|
5223
|
-
// raw-import:/tmp/slz-publish-wt.
|
|
5223
|
+
// raw-import:/tmp/slz-publish-wt.GgutIu/packages/shared/hooks/src/notify.sh
|
|
5224
5224
|
var notify_default;
|
|
5225
5225
|
var init_notify = __esm({
|
|
5226
|
-
"raw-import:/tmp/slz-publish-wt.
|
|
5226
|
+
"raw-import:/tmp/slz-publish-wt.GgutIu/packages/shared/hooks/src/notify.sh"() {
|
|
5227
5227
|
notify_default = `#!/bin/sh
|
|
5228
5228
|
# SlayZone agent lifecycle hook \u2014 BENIGN DUMB FORWARDER.
|
|
5229
5229
|
#
|
|
@@ -5385,10 +5385,10 @@ exit 0
|
|
|
5385
5385
|
}
|
|
5386
5386
|
});
|
|
5387
5387
|
|
|
5388
|
-
// raw-import:/tmp/slz-publish-wt.
|
|
5388
|
+
// raw-import:/tmp/slz-publish-wt.GgutIu/packages/shared/hooks/src/opencode-plugin.js
|
|
5389
5389
|
var opencode_plugin_default;
|
|
5390
5390
|
var init_opencode_plugin = __esm({
|
|
5391
|
-
"raw-import:/tmp/slz-publish-wt.
|
|
5391
|
+
"raw-import:/tmp/slz-publish-wt.GgutIu/packages/shared/hooks/src/opencode-plugin.js"() {
|
|
5392
5392
|
opencode_plugin_default = "// SlayZone opencode plugin v1\n//\n// Forwards OpenCode SDK session lifecycle events to the SlayZone agent-hook\n// notify script over a local shell exec. Plugin is loaded by OpenCode from\n// ${XDG_CONFIG_HOME:-~/.config}/opencode/plugin/slayzone-notify.js\n//\n// The {{NOTIFY_PATH}} placeholder is substituted by the SlayZone installer\n// (packages/apps/app/src/main/agent-hooks/opencode-plugin-installer.ts) at\n// install time with the absolute path to `~/.slayzone/hooks/notify.sh`.\n//\n// Behavior:\n// - No-op when SLAYZONE_TASK_ID is unset (plugin only fires inside SlayZone PTYs).\n// - Subagent (child session) events are suppressed \u2014 oh-my-opencode + similar\n// tools spawn many child sessions and would otherwise flap Start/Stop.\n// - On client.session.list() error, sessions are assumed CHILD (safer to\n// suppress than emit a false-positive Start/Stop).\n// - Handles both modern (session.status w/ nested type) and legacy\n// (session.busy / session.idle) event shapes for forward compat.\n// - Singleton guard prevents double-load if OpenCode re-imports the plugin.\n\nexport const SlayzoneNotifyPlugin = async ({ $, client }) => {\n if (globalThis.__slayzoneOpencodePluginV1) return {}\n globalThis.__slayzoneOpencodePluginV1 = true\n if (!process?.env?.SLAYZONE_TASK_ID) return {}\n\n const notifyPath = '{{NOTIFY_PATH}}'\n let currentState = 'idle' // 'idle' | 'busy'\n let rootSessionID = null // first non-child session we see\n let stopSent = false // dedup Stop emits\n const childSessionCache = new Map() // sessionID -> isChild bool\n\n const notify = async (eventName) => {\n const payload = JSON.stringify({ hook_event_name: eventName })\n try {\n await $`bash ${notifyPath} ${payload}`\n } catch {\n // Hook failures must never bubble into the OpenCode TUI.\n }\n }\n\n const isChildSession = async (sessionID) => {\n if (!sessionID) return true\n if (!client?.session?.list) return true\n if (childSessionCache.has(sessionID)) return childSessionCache.get(sessionID)\n try {\n const sessions = await client.session.list()\n const session = sessions.data?.find((s) => s.id === sessionID)\n const isChild = !!session?.parentID\n childSessionCache.set(sessionID, isChild)\n return isChild\n } catch {\n // On error, assume CHILD \u2014 safer than emitting a false-positive Start/Stop.\n return true\n }\n }\n\n const handleBusy = async (sessionID) => {\n if (!rootSessionID) rootSessionID = sessionID\n if (sessionID !== rootSessionID) return\n if (currentState === 'idle') {\n currentState = 'busy'\n stopSent = false\n await notify('Start')\n }\n }\n\n const handleStop = async (sessionID) => {\n if (rootSessionID && sessionID !== rootSessionID) return\n if (currentState === 'busy' && !stopSent) {\n currentState = 'idle'\n stopSent = true\n await notify('Stop')\n rootSessionID = null // reset for next session\n }\n }\n\n return {\n event: async ({ event }) => {\n const sessionID = event.properties?.sessionID ?? event.properties?.info?.id ?? null\n\n if (event.type === 'session.created') {\n const isChild = Boolean(event.properties?.info?.parentID)\n if (sessionID) childSessionCache.set(sessionID, isChild)\n if (!isChild) await notify('SessionStart')\n return\n }\n\n if (event.type === 'session.deleted') {\n const cached = sessionID ? childSessionCache.get(sessionID) : undefined\n const isChild = cached !== undefined ? cached : await isChildSession(sessionID)\n if (!isChild) await notify('SessionEnd')\n if (sessionID) childSessionCache.delete(sessionID)\n return\n }\n\n if (await isChildSession(sessionID)) return\n\n if (event.type === 'session.status') {\n const status = event.properties?.status\n if (status?.type === 'busy') await handleBusy(sessionID)\n else if (status?.type === 'idle') await handleStop(sessionID)\n }\n // Backwards-compat: some OpenCode versions emit busy/idle as top-level events.\n if (event.type === 'session.busy') await handleBusy(sessionID)\n if (event.type === 'session.idle') await handleStop(sessionID)\n if (event.type === 'session.error') await handleStop(sessionID)\n },\n 'permission.ask': async (_permission, output) => {\n if (output.status === 'ask') await notify('PermissionRequest')\n }\n }\n}\n";
|
|
5393
5393
|
}
|
|
5394
5394
|
});
|
|
@@ -5431,8 +5431,8 @@ var init_agent_hooks2 = __esm({
|
|
|
5431
5431
|
});
|
|
5432
5432
|
|
|
5433
5433
|
// src/bin.ts
|
|
5434
|
-
var
|
|
5435
|
-
var
|
|
5434
|
+
var import_node_os10 = require("node:os");
|
|
5435
|
+
var import_node_path18 = require("node:path");
|
|
5436
5436
|
|
|
5437
5437
|
// ../../shared/platform/src/config-prompt.ts
|
|
5438
5438
|
var import_promises = require("node:readline/promises");
|
|
@@ -5467,14 +5467,14 @@ function coerceComputerConfig(raw) {
|
|
|
5467
5467
|
}
|
|
5468
5468
|
return cfg;
|
|
5469
5469
|
}
|
|
5470
|
-
function readJsonObject(
|
|
5470
|
+
function readJsonObject(path11) {
|
|
5471
5471
|
let raw;
|
|
5472
5472
|
try {
|
|
5473
|
-
raw = (0, import_node_fs.readFileSync)(
|
|
5473
|
+
raw = (0, import_node_fs.readFileSync)(path11, "utf8");
|
|
5474
5474
|
} catch (err) {
|
|
5475
5475
|
if (err.code === "ENOENT") return null;
|
|
5476
5476
|
process.stderr.write(
|
|
5477
|
-
`[slayzone-config] cannot read ${
|
|
5477
|
+
`[slayzone-config] cannot read ${path11}: ${err instanceof Error ? err.message : String(err)} \u2014 using empty config
|
|
5478
5478
|
`
|
|
5479
5479
|
);
|
|
5480
5480
|
return null;
|
|
@@ -5484,61 +5484,61 @@ function readJsonObject(path9) {
|
|
|
5484
5484
|
parsed = JSON.parse(raw);
|
|
5485
5485
|
} catch (err) {
|
|
5486
5486
|
process.stderr.write(
|
|
5487
|
-
`[slayzone-config] ${
|
|
5487
|
+
`[slayzone-config] ${path11} is not valid JSON: ${err instanceof Error ? err.message : String(err)} \u2014 using empty config
|
|
5488
5488
|
`
|
|
5489
5489
|
);
|
|
5490
5490
|
return null;
|
|
5491
5491
|
}
|
|
5492
5492
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
5493
|
-
process.stderr.write(`[slayzone-config] ${
|
|
5493
|
+
process.stderr.write(`[slayzone-config] ${path11} is not a JSON object \u2014 using empty config
|
|
5494
5494
|
`);
|
|
5495
5495
|
return null;
|
|
5496
5496
|
}
|
|
5497
5497
|
return parsed;
|
|
5498
5498
|
}
|
|
5499
|
-
function writeJsonAtomic(
|
|
5500
|
-
const dir = (0, import_node_path.dirname)(
|
|
5499
|
+
function writeJsonAtomic(path11, data) {
|
|
5500
|
+
const dir = (0, import_node_path.dirname)(path11);
|
|
5501
5501
|
(0, import_node_fs.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
5502
|
-
const tmpPath = `${
|
|
5502
|
+
const tmpPath = `${path11}.tmp-${process.pid}-${Date.now()}`;
|
|
5503
5503
|
(0, import_node_fs.writeFileSync)(tmpPath, `${JSON.stringify(data, null, 2)}
|
|
5504
5504
|
`, { mode: 384 });
|
|
5505
5505
|
try {
|
|
5506
|
-
(0, import_node_fs.renameSync)(tmpPath,
|
|
5506
|
+
(0, import_node_fs.renameSync)(tmpPath, path11);
|
|
5507
5507
|
} catch (err) {
|
|
5508
5508
|
(0, import_node_fs.rmSync)(tmpPath, { force: true });
|
|
5509
5509
|
throw err;
|
|
5510
5510
|
}
|
|
5511
5511
|
}
|
|
5512
|
-
function loadComputerConfigFile(
|
|
5513
|
-
const raw = readJsonObject(
|
|
5512
|
+
function loadComputerConfigFile(path11 = getComputerConfigFilePath()) {
|
|
5513
|
+
const raw = readJsonObject(path11);
|
|
5514
5514
|
if (raw) return coerceComputerConfig(raw);
|
|
5515
|
-
const legacy = readJsonObject(legacyConfigFilePathFor(
|
|
5515
|
+
const legacy = readJsonObject(legacyConfigFilePathFor(path11));
|
|
5516
5516
|
return legacy ? coerceComputerConfig(legacy) : {};
|
|
5517
5517
|
}
|
|
5518
|
-
function ignoredComputerConfigKeys(
|
|
5519
|
-
const raw = readJsonObject(
|
|
5518
|
+
function ignoredComputerConfigKeys(path11 = getComputerConfigFilePath()) {
|
|
5519
|
+
const raw = readJsonObject(path11) ?? readJsonObject(legacyConfigFilePathFor(path11));
|
|
5520
5520
|
if (!raw) return [];
|
|
5521
5521
|
return IGNORED_COMPUTER_CONFIG_KEYS.filter((key) => raw[key] !== void 0);
|
|
5522
5522
|
}
|
|
5523
|
-
function saveComputerConfigFile(cfg,
|
|
5524
|
-
writeJsonAtomic(
|
|
5523
|
+
function saveComputerConfigFile(cfg, path11 = getComputerConfigFilePath()) {
|
|
5524
|
+
writeJsonAtomic(path11, cfg);
|
|
5525
5525
|
}
|
|
5526
|
-
function updateComputerConfigFile(patch,
|
|
5527
|
-
const current = readJsonObject(
|
|
5526
|
+
function updateComputerConfigFile(patch, path11 = getComputerConfigFilePath()) {
|
|
5527
|
+
const current = readJsonObject(path11);
|
|
5528
5528
|
const merged = current ? coerceComputerConfig(current) : {};
|
|
5529
5529
|
for (const [k, v] of Object.entries(patch)) {
|
|
5530
5530
|
if (v !== void 0) merged[k] = v;
|
|
5531
5531
|
}
|
|
5532
|
-
saveComputerConfigFile(merged,
|
|
5532
|
+
saveComputerConfigFile(merged, path11);
|
|
5533
5533
|
return merged;
|
|
5534
5534
|
}
|
|
5535
|
-
function updateJsonFile(patch,
|
|
5536
|
-
const current = readJsonObject(
|
|
5535
|
+
function updateJsonFile(patch, path11) {
|
|
5536
|
+
const current = readJsonObject(path11) ?? {};
|
|
5537
5537
|
const merged = { ...current };
|
|
5538
5538
|
for (const [k, v] of Object.entries(patch)) {
|
|
5539
5539
|
if (v !== void 0) merged[k] = v;
|
|
5540
5540
|
}
|
|
5541
|
-
writeJsonAtomic(
|
|
5541
|
+
writeJsonAtomic(path11, merged);
|
|
5542
5542
|
}
|
|
5543
5543
|
|
|
5544
5544
|
// ../../shared/platform/src/config-prompt.ts
|
|
@@ -5610,10 +5610,10 @@ function isLoopbackAuthority(addr) {
|
|
|
5610
5610
|
return false;
|
|
5611
5611
|
}
|
|
5612
5612
|
}
|
|
5613
|
-
function hubUrlFromAddr(addr, kind,
|
|
5613
|
+
function hubUrlFromAddr(addr, kind, path11 = "") {
|
|
5614
5614
|
const secure = !isLoopbackAuthority(addr);
|
|
5615
5615
|
const scheme = kind === "ws" ? secure ? "wss" : "ws" : secure ? "https" : "http";
|
|
5616
|
-
return `${scheme}://${addr}${
|
|
5616
|
+
return `${scheme}://${addr}${path11}`;
|
|
5617
5617
|
}
|
|
5618
5618
|
function hubAddrFromUrl(url2) {
|
|
5619
5619
|
let u;
|
|
@@ -6715,10 +6715,10 @@ function mergeDefs(...defs) {
|
|
|
6715
6715
|
function cloneDef(schema) {
|
|
6716
6716
|
return mergeDefs(schema._zod.def);
|
|
6717
6717
|
}
|
|
6718
|
-
function getElementAtPath(obj,
|
|
6719
|
-
if (!
|
|
6718
|
+
function getElementAtPath(obj, path11) {
|
|
6719
|
+
if (!path11)
|
|
6720
6720
|
return obj;
|
|
6721
|
-
return
|
|
6721
|
+
return path11.reduce((acc, key) => acc?.[key], obj);
|
|
6722
6722
|
}
|
|
6723
6723
|
function promiseAllObject(promisesObj) {
|
|
6724
6724
|
const keys = Object.keys(promisesObj);
|
|
@@ -7058,11 +7058,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
7058
7058
|
}
|
|
7059
7059
|
return false;
|
|
7060
7060
|
}
|
|
7061
|
-
function prefixIssues(
|
|
7061
|
+
function prefixIssues(path11, issues) {
|
|
7062
7062
|
return issues.map((iss) => {
|
|
7063
7063
|
var _a3;
|
|
7064
7064
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
7065
|
-
iss.path.unshift(
|
|
7065
|
+
iss.path.unshift(path11);
|
|
7066
7066
|
return iss;
|
|
7067
7067
|
});
|
|
7068
7068
|
}
|
|
@@ -7512,16 +7512,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
|
|
|
7512
7512
|
}
|
|
7513
7513
|
function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
7514
7514
|
const fieldErrors = { _errors: [] };
|
|
7515
|
-
const processError = (error63,
|
|
7515
|
+
const processError = (error63, path11 = []) => {
|
|
7516
7516
|
for (const issue2 of error63.issues) {
|
|
7517
7517
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
7518
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
7518
|
+
issue2.errors.map((issues) => processError({ issues }, [...path11, ...issue2.path]));
|
|
7519
7519
|
} else if (issue2.code === "invalid_key") {
|
|
7520
|
-
processError({ issues: issue2.issues }, [...
|
|
7520
|
+
processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
|
|
7521
7521
|
} else if (issue2.code === "invalid_element") {
|
|
7522
|
-
processError({ issues: issue2.issues }, [...
|
|
7522
|
+
processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
|
|
7523
7523
|
} else {
|
|
7524
|
-
const fullpath = [...
|
|
7524
|
+
const fullpath = [...path11, ...issue2.path];
|
|
7525
7525
|
if (fullpath.length === 0) {
|
|
7526
7526
|
fieldErrors._errors.push(mapper(issue2));
|
|
7527
7527
|
} else {
|
|
@@ -7560,17 +7560,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
|
7560
7560
|
}
|
|
7561
7561
|
function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
7562
7562
|
const result = { errors: [] };
|
|
7563
|
-
const processError = (error63,
|
|
7563
|
+
const processError = (error63, path11 = []) => {
|
|
7564
7564
|
var _a3;
|
|
7565
7565
|
for (const issue2 of error63.issues) {
|
|
7566
7566
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
7567
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
7567
|
+
issue2.errors.map((issues) => processError({ issues }, [...path11, ...issue2.path]));
|
|
7568
7568
|
} else if (issue2.code === "invalid_key") {
|
|
7569
|
-
processError({ issues: issue2.issues }, [...
|
|
7569
|
+
processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
|
|
7570
7570
|
} else if (issue2.code === "invalid_element") {
|
|
7571
|
-
processError({ issues: issue2.issues }, [...
|
|
7571
|
+
processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
|
|
7572
7572
|
} else {
|
|
7573
|
-
const fullpath = [...
|
|
7573
|
+
const fullpath = [...path11, ...issue2.path];
|
|
7574
7574
|
if (fullpath.length === 0) {
|
|
7575
7575
|
result.errors.push(mapper(issue2));
|
|
7576
7576
|
continue;
|
|
@@ -7609,8 +7609,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
|
7609
7609
|
}
|
|
7610
7610
|
function toDotPath(_path) {
|
|
7611
7611
|
const segs = [];
|
|
7612
|
-
const
|
|
7613
|
-
for (const seg of
|
|
7612
|
+
const path11 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
7613
|
+
for (const seg of path11) {
|
|
7614
7614
|
if (typeof seg === "number")
|
|
7615
7615
|
segs.push(`[${seg}]`);
|
|
7616
7616
|
else if (typeof seg === "symbol")
|
|
@@ -7896,8 +7896,8 @@ function emoji() {
|
|
|
7896
7896
|
}
|
|
7897
7897
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
7898
7898
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
7899
|
-
var mac = (
|
|
7900
|
-
const escapedDelim = escapeRegex(
|
|
7899
|
+
var mac = (delimiter4) => {
|
|
7900
|
+
const escapedDelim = escapeRegex(delimiter4 ?? ":");
|
|
7901
7901
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
7902
7902
|
};
|
|
7903
7903
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -22585,14 +22585,14 @@ var nonoptionalProcessor = (schema, ctx, _json, params) => {
|
|
|
22585
22585
|
var UNREPRESENTABLE_DEFAULT = /* @__PURE__ */ Symbol();
|
|
22586
22586
|
function serializeDefaultValue(value, schema, ctx, json2, params) {
|
|
22587
22587
|
let unrepresentable = false;
|
|
22588
|
-
const
|
|
22588
|
+
const serialized2 = JSON.stringify(value, (_, val) => {
|
|
22589
22589
|
if (typeof val !== "bigint")
|
|
22590
22590
|
return val;
|
|
22591
22591
|
unrepresentable = true;
|
|
22592
22592
|
return null;
|
|
22593
22593
|
});
|
|
22594
22594
|
if (!unrepresentable)
|
|
22595
|
-
return JSON.parse(
|
|
22595
|
+
return JSON.parse(serialized2);
|
|
22596
22596
|
handleUnrepresentable(schema, ctx, json2, params, "BigInt defaults cannot be represented in JSON Schema");
|
|
22597
22597
|
return UNREPRESENTABLE_DEFAULT;
|
|
22598
22598
|
}
|
|
@@ -24712,13 +24712,13 @@ function resolveRef(ref, ctx) {
|
|
|
24712
24712
|
if (!ref.startsWith("#")) {
|
|
24713
24713
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
24714
24714
|
}
|
|
24715
|
-
const
|
|
24716
|
-
if (
|
|
24715
|
+
const path11 = ref.slice(1).split("/").filter(Boolean);
|
|
24716
|
+
if (path11.length === 0) {
|
|
24717
24717
|
return ctx.rootSchema;
|
|
24718
24718
|
}
|
|
24719
24719
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
24720
|
-
if (
|
|
24721
|
-
const key =
|
|
24720
|
+
if (path11[0] === defsKey) {
|
|
24721
|
+
const key = path11[1] === void 0 ? void 0 : decodeJSONPointerSegment(path11[1]);
|
|
24722
24722
|
if (!key || !ctx.defs[key]) {
|
|
24723
24723
|
throw new Error(`Reference not found: ${ref}`);
|
|
24724
24724
|
}
|
|
@@ -25592,8 +25592,20 @@ var ComputerTransportErrorCodes = {
|
|
|
25592
25592
|
* transient — retrying the same request is refused again. The hub audits it as
|
|
25593
25593
|
* `denied` and the message says what to do on the device.
|
|
25594
25594
|
*/
|
|
25595
|
-
refusedByComputer: -32006
|
|
25595
|
+
refusedByComputer: -32006,
|
|
25596
|
+
/**
|
|
25597
|
+
* An agent for a project this computer holds no folder for. Not transient, and
|
|
25598
|
+
* not a policy refusal: the user picks the project's folder on this computer
|
|
25599
|
+
* (or the hub delivers it), then the same spawn works.
|
|
25600
|
+
*/
|
|
25601
|
+
projectNotPlaced: -32007
|
|
25596
25602
|
};
|
|
25603
|
+
function projectNotPlacedError(projectId) {
|
|
25604
|
+
return new RpcError(
|
|
25605
|
+
ComputerTransportErrorCodes.projectNotPlaced,
|
|
25606
|
+
`This computer has no folder for project ${projectId}. Pick the project's folder on this computer, then try again.`
|
|
25607
|
+
);
|
|
25608
|
+
}
|
|
25597
25609
|
var requestActorSchema = external_exports.object({
|
|
25598
25610
|
userId: external_exports.string().min(1).max(200).nullable(),
|
|
25599
25611
|
/** `trpc <path>` / `METHOD /path` the request entered the hub through. */
|
|
@@ -25684,13 +25696,19 @@ var procDataParamsSchema = external_exports.object({
|
|
|
25684
25696
|
/** Monotonic per-session sequence number for `stdout`. Absent on stderr. */
|
|
25685
25697
|
seq: external_exports.number().int().nonnegative().optional(),
|
|
25686
25698
|
data: external_exports.string(),
|
|
25687
|
-
stream: external_exports.enum(["stdout", "stderr"]).optional()
|
|
25699
|
+
stream: external_exports.enum(["stdout", "stderr"]).optional(),
|
|
25700
|
+
/** The spawn attempt that produced this output; the hub drops a replaced attempt's. */
|
|
25701
|
+
spawnId: external_exports.string().min(1).optional()
|
|
25688
25702
|
});
|
|
25689
25703
|
var procExitParamsSchema = external_exports.object({
|
|
25690
25704
|
sessionId: external_exports.string().min(1),
|
|
25691
25705
|
exitCode: external_exports.number().int().nullable(),
|
|
25692
25706
|
signal: external_exports.string().nullable().optional(),
|
|
25693
|
-
reason: external_exports.string().min(1).optional()
|
|
25707
|
+
reason: external_exports.string().min(1).optional(),
|
|
25708
|
+
/** The spawn attempt that exited. */
|
|
25709
|
+
spawnId: external_exports.string().min(1).optional(),
|
|
25710
|
+
/** Why the process could not run (e.g. the OS refused to start it). */
|
|
25711
|
+
error: external_exports.string().optional()
|
|
25694
25712
|
});
|
|
25695
25713
|
var fsChangeParamsSchema = external_exports.object({
|
|
25696
25714
|
watchId: external_exports.string().min(1),
|
|
@@ -25717,6 +25735,8 @@ var HubToComputerMethods = {
|
|
|
25717
25735
|
ptyPrioritize: "pty.prioritize",
|
|
25718
25736
|
/** Which of claude's background jobs still have a live process under a session. */
|
|
25719
25737
|
ptyBackgroundJobs: "pty.backgroundJobs",
|
|
25738
|
+
/** Doctor's facts about this computer: node-pty install, the shell, agent binaries. */
|
|
25739
|
+
ptyDoctor: "pty.doctor",
|
|
25720
25740
|
// warm pool (pre-warmed agents live ON the computer — see server/warm-*)
|
|
25721
25741
|
ptyWarmSpawn: "pty.warmSpawn",
|
|
25722
25742
|
ptyWarmAdopt: "pty.warmAdopt",
|
|
@@ -25775,7 +25795,13 @@ var HubToComputerMethods = {
|
|
|
25775
25795
|
/** Edit the computer's own path-jail (Settings → Computers). */
|
|
25776
25796
|
computerSetAllowedRoots: "computer.setAllowedRoots",
|
|
25777
25797
|
/** Run `gh` on the computer (PR panel). One frame, not one per gh subcommand. */
|
|
25778
|
-
ghExec: "gh.exec"
|
|
25798
|
+
ghExec: "gh.exec",
|
|
25799
|
+
/**
|
|
25800
|
+
* Read the active branch of a Claude Code session file on the computer (a
|
|
25801
|
+
* resumed or handed-over conversation's history for the chat timeline). Only
|
|
25802
|
+
* that file: the path is built from the cwd and a uuid, nothing else.
|
|
25803
|
+
*/
|
|
25804
|
+
claudeSessionRead: "claudeSession.read"
|
|
25779
25805
|
};
|
|
25780
25806
|
var spawnIdField = external_exports.string().min(1).optional();
|
|
25781
25807
|
var exitedSessionSchema = external_exports.object({
|
|
@@ -25852,6 +25878,19 @@ var ptyBackgroundJobsResultSchema = external_exports.object({
|
|
|
25852
25878
|
supported: external_exports.boolean(),
|
|
25853
25879
|
alive: external_exports.array(external_exports.string())
|
|
25854
25880
|
});
|
|
25881
|
+
var ptyDoctorParamsSchema = external_exports.object({
|
|
25882
|
+
shell: external_exports.string().min(1).max(4096),
|
|
25883
|
+
/** Plain command names only (`claude`, `cursor-agent`), never paths or syntax. */
|
|
25884
|
+
binaries: external_exports.array(
|
|
25885
|
+
external_exports.string().min(1).max(128).regex(/^[A-Za-z0-9][A-Za-z0-9._+-]*$/)
|
|
25886
|
+
).max(16)
|
|
25887
|
+
}).strict();
|
|
25888
|
+
var ptyDoctorResultSchema = external_exports.object({
|
|
25889
|
+
ok: external_exports.literal(true),
|
|
25890
|
+
problems: external_exports.array(external_exports.object({ check: external_exports.string(), detail: external_exports.string(), fix: external_exports.string() })),
|
|
25891
|
+
shellExists: external_exports.boolean(),
|
|
25892
|
+
binaries: external_exports.array(external_exports.object({ binary: external_exports.string(), path: external_exports.string().nullable() }))
|
|
25893
|
+
});
|
|
25855
25894
|
var ptyResizeParamsSchema = external_exports.object({
|
|
25856
25895
|
sessionId: external_exports.string().min(1),
|
|
25857
25896
|
cols: external_exports.number().int().positive(),
|
|
@@ -26005,6 +26044,22 @@ var ghExecResultSchema = external_exports.object({
|
|
|
26005
26044
|
stdout: external_exports.string(),
|
|
26006
26045
|
stderr: external_exports.string()
|
|
26007
26046
|
});
|
|
26047
|
+
var claudeSessionReadParamsSchema = external_exports.object({
|
|
26048
|
+
cwd: external_exports.string().min(1).optional(),
|
|
26049
|
+
projectId: external_exports.string().min(1).optional(),
|
|
26050
|
+
sessionId: external_exports.string().uuid(),
|
|
26051
|
+
/** Newest records to return at most. */
|
|
26052
|
+
maxRecords: external_exports.number().int().positive().max(5e3),
|
|
26053
|
+
/** Their total JSON size at most (large tool results are shortened first). */
|
|
26054
|
+
maxBytes: external_exports.number().int().positive().max(16 * 1024 * 1024)
|
|
26055
|
+
});
|
|
26056
|
+
var claudeSessionReadResultSchema = external_exports.object({
|
|
26057
|
+
/** False: no session file for that id in that cwd's project dir. */
|
|
26058
|
+
found: external_exports.boolean(),
|
|
26059
|
+
records: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown())),
|
|
26060
|
+
/** Older records of the branch that were not sent (the caps). */
|
|
26061
|
+
omitted: external_exports.number().int().nonnegative()
|
|
26062
|
+
});
|
|
26008
26063
|
var computerShutdownParamsSchema = external_exports.object({
|
|
26009
26064
|
reason: external_exports.string().optional(),
|
|
26010
26065
|
/** Grace period before the computer may hard-exit. */
|
|
@@ -26252,7 +26307,9 @@ var procSpawnParamsSchema = external_exports.object({
|
|
|
26252
26307
|
*/
|
|
26253
26308
|
shell: external_exports.boolean().optional(),
|
|
26254
26309
|
cwd: external_exports.string().min(1).optional(),
|
|
26255
|
-
env: external_exports.record(external_exports.string(), external_exports.string()).optional()
|
|
26310
|
+
env: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
26311
|
+
/** Agent-start admission lane (chat agents), as for `pty.spawn`. Absent: start at once. */
|
|
26312
|
+
admission: ptySpawnAdmissionSchema.optional()
|
|
26256
26313
|
});
|
|
26257
26314
|
var procSpawnResultSchema = external_exports.object({
|
|
26258
26315
|
/** `null` when the OS never assigned one (immediate spawn failure). The computer
|
|
@@ -26262,12 +26319,38 @@ var procSpawnResultSchema = external_exports.object({
|
|
|
26262
26319
|
});
|
|
26263
26320
|
var procKillParamsSchema = external_exports.object({
|
|
26264
26321
|
sessionId: external_exports.string().min(1),
|
|
26265
|
-
signal: external_exports.string().optional()
|
|
26322
|
+
signal: external_exports.string().optional(),
|
|
26323
|
+
/** Only kill this attempt: a kill meant for a replaced process must not hit its successor. */
|
|
26324
|
+
spawnId: spawnIdField
|
|
26266
26325
|
});
|
|
26267
26326
|
var procWriteParamsSchema = external_exports.object({
|
|
26268
26327
|
sessionId: external_exports.string().min(1),
|
|
26269
|
-
data: external_exports.string()
|
|
26328
|
+
data: external_exports.string(),
|
|
26329
|
+
/** Only write to this attempt; a replaced process is refused (`stale-spawn`). */
|
|
26330
|
+
spawnId: spawnIdField,
|
|
26331
|
+
/**
|
|
26332
|
+
* Idempotency key: a write the hub retries (its reply was lost) is written once.
|
|
26333
|
+
* The reply is sent only after the bytes reached the process's stdin, and a
|
|
26334
|
+
* write that cannot be delivered (unknown session, replaced attempt, broken pipe)
|
|
26335
|
+
* is refused rather than acked — so `{ok:true}` means delivered.
|
|
26336
|
+
*/
|
|
26337
|
+
writeId: external_exports.string().min(1).max(200).optional()
|
|
26270
26338
|
});
|
|
26339
|
+
var procWriteResultSchema = external_exports.object({
|
|
26340
|
+
ok: external_exports.literal(true),
|
|
26341
|
+
delivered: external_exports.literal(true).optional(),
|
|
26342
|
+
duplicate: external_exports.boolean().optional()
|
|
26343
|
+
});
|
|
26344
|
+
var ProcRefusalReasons = {
|
|
26345
|
+
/** `proc.spawn`: the command is not on the computer's PATH. `data.binary` names it. */
|
|
26346
|
+
binaryNotFound: "binary-not-found",
|
|
26347
|
+
/** `proc.write`: no process under this session id. */
|
|
26348
|
+
unknownSession: "unknown-session",
|
|
26349
|
+
/** `proc.write`: the session now runs a different spawn attempt. */
|
|
26350
|
+
staleSpawn: "stale-spawn",
|
|
26351
|
+
/** `proc.write`: the process's stdin is closed or broken. */
|
|
26352
|
+
stdinClosed: "stdin-closed"
|
|
26353
|
+
};
|
|
26271
26354
|
var procGetBufferSinceParamsSchema = external_exports.object({
|
|
26272
26355
|
sessionId: external_exports.string().min(1),
|
|
26273
26356
|
seq: external_exports.number().int()
|
|
@@ -26917,7 +27000,17 @@ var computerConfigSchema = external_exports.object({
|
|
|
26917
27000
|
* projects the user adds. No file key and no env var sets it, so nothing a hub
|
|
26918
27001
|
* can write turns it on.
|
|
26919
27002
|
*/
|
|
26920
|
-
hubMayEditRoots: external_exports.boolean().optional()
|
|
27003
|
+
hubMayEditRoots: external_exports.boolean().optional(),
|
|
27004
|
+
/**
|
|
27005
|
+
* A directory whose executables take precedence over PATH for every process this
|
|
27006
|
+
* computer starts — prepended in `buildSpawnEnv`, the one place both the pty and
|
|
27007
|
+
* the proc handler build a child's env. Exists so tests can swap an agent CLI for
|
|
27008
|
+
* a scripted fake (`@slayzone/test-utils/fake-claude`): a dir merely prepended to
|
|
27009
|
+
* the inherited PATH loses, because the computer adopts the login-shell PATH with
|
|
27010
|
+
* its entries FIRST at boot (login-shell-path.ts). Absolute: a relative dir would
|
|
27011
|
+
* resolve against each spawn's cwd. Env channel only (`ENV_VARS.binOverrideDir`).
|
|
27012
|
+
*/
|
|
27013
|
+
binOverrideDir: external_exports.string().min(1).refine((dir) => (0, import_node_path3.isAbsolute)(dir), { message: "must be an absolute path" }).optional()
|
|
26921
27014
|
});
|
|
26922
27015
|
var ENV_VARS = {
|
|
26923
27016
|
// Authority ONLY — `host[:port]`, no scheme, no path. The dial scheme
|
|
@@ -26936,7 +27029,9 @@ var ENV_VARS = {
|
|
|
26936
27029
|
// named its CONSUMER, which is what CLAUDE.md rule 2 forbids. `_TOKEN` suffix +
|
|
26937
27030
|
// `HUB_` family per rule 3, matching the domain term used everywhere else
|
|
26938
27031
|
// (`szjt1.`, the `join_tokens` table, mintJoinToken, POST /api/computers/join-token).
|
|
26939
|
-
joinToken: "SLAYZONE_HUB_JOIN_TOKEN"
|
|
27032
|
+
joinToken: "SLAYZONE_HUB_JOIN_TOKEN",
|
|
27033
|
+
// Read only by the computer (rule 2), a directory (rule 3). See `binOverrideDir`.
|
|
27034
|
+
binOverrideDir: "SLAYZONE_COMPUTER_BIN_OVERRIDE_DIR"
|
|
26940
27035
|
// No alias for the pre-rename `SLAYZONE_RUNNER_JOIN_TOKEN`: it never shipped.
|
|
26941
27036
|
// The published computer betas (0.36.0-beta.2/3) read `SLAYZONE_JOIN_TOKEN`, and
|
|
26942
27037
|
// the name it was renamed FROM only ever existed on unreleased main, so there is
|
|
@@ -26979,8 +27074,8 @@ var protectedPaths = [];
|
|
|
26979
27074
|
function setProtectedPaths(paths) {
|
|
26980
27075
|
protectedPaths = paths.map((p) => realpathBoundary(p));
|
|
26981
27076
|
}
|
|
26982
|
-
function isInside(
|
|
26983
|
-
return
|
|
27077
|
+
function isInside(path11, dir) {
|
|
27078
|
+
return path11 === dir || path11.startsWith(dir + import_node_path3.sep);
|
|
26984
27079
|
}
|
|
26985
27080
|
function isProtectedPath(absolute) {
|
|
26986
27081
|
return protectedPaths.some((guarded) => isInside(absolute, guarded));
|
|
@@ -27055,7 +27150,8 @@ function loadComputerConfig(env = process.env, shared = env === process.env && e
|
|
|
27055
27150
|
// <ROOT>/computer.config.json — base under env (spread after). The single config file.
|
|
27056
27151
|
...fromShared,
|
|
27057
27152
|
...hubUrlFromEnv !== void 0 ? { hubUrl: hubUrlFromEnv } : {},
|
|
27058
|
-
...envJoinToken !== void 0 ? { joinToken: envJoinToken } : {}
|
|
27153
|
+
...envJoinToken !== void 0 ? { joinToken: envJoinToken } : {},
|
|
27154
|
+
...env[ENV_VARS.binOverrideDir] !== void 0 ? { binOverrideDir: env[ENV_VARS.binOverrideDir] } : {}
|
|
27059
27155
|
};
|
|
27060
27156
|
const result = computerConfigSchema.safeParse(merged);
|
|
27061
27157
|
if (result.success) {
|
|
@@ -27452,6 +27548,11 @@ var ENV_MANIFEST = {
|
|
|
27452
27548
|
// overrides below. `infra`: a spawned terminal must never inherit it, or an
|
|
27453
27549
|
// agent would resolve a different notify.sh than the one wired into its hooks.
|
|
27454
27550
|
SLAYZONE_MACHINE_DIR: "infra",
|
|
27551
|
+
// Computer-only: a directory whose executables take precedence over PATH for
|
|
27552
|
+
// every process the computer starts (spawn-env.ts). The e2e chat group puts its
|
|
27553
|
+
// fake `claude` there — a dir merely prepended to the inherited PATH loses to the
|
|
27554
|
+
// login-shell PATH the computer adopts at boot. Infra: an agent must not inherit it.
|
|
27555
|
+
SLAYZONE_COMPUTER_BIN_OVERRIDE_DIR: "infra",
|
|
27455
27556
|
// per-provider config/hook/plugin path overrides (test/sandbox redirects)
|
|
27456
27557
|
SLAYZONE_CLAUDE_SETTINGS_PATH: "infra",
|
|
27457
27558
|
SLAYZONE_GEMINI_SETTINGS_PATH: "infra",
|
|
@@ -27499,16 +27600,16 @@ var NON_PREFIXED_INFRA = /* @__PURE__ */ new Set([
|
|
|
27499
27600
|
function sanitizeSpawnEnv(base) {
|
|
27500
27601
|
const out = {};
|
|
27501
27602
|
for (const [key, value] of Object.entries(base)) {
|
|
27502
|
-
if (
|
|
27503
|
-
if (NON_PREFIXED_INFRA.has(key)) continue;
|
|
27504
|
-
if (key.startsWith("SLAYZONE_")) {
|
|
27505
|
-
if (ENV_MANIFEST[key] === "global") out[key] = value;
|
|
27506
|
-
continue;
|
|
27507
|
-
}
|
|
27508
|
-
out[key] = value;
|
|
27603
|
+
if (keptInSpawnEnv(key, value)) out[key] = value;
|
|
27509
27604
|
}
|
|
27510
27605
|
return out;
|
|
27511
27606
|
}
|
|
27607
|
+
function keptInSpawnEnv(key, value) {
|
|
27608
|
+
if (typeof value !== "string") return false;
|
|
27609
|
+
if (NON_PREFIXED_INFRA.has(key)) return false;
|
|
27610
|
+
if (key.startsWith("SLAYZONE_")) return ENV_MANIFEST[key] === "global";
|
|
27611
|
+
return true;
|
|
27612
|
+
}
|
|
27512
27613
|
|
|
27513
27614
|
// ../../shared/platform/src/index.ts
|
|
27514
27615
|
init_fs_utils();
|
|
@@ -27569,6 +27670,15 @@ function getShellStartupArgs(shellPath) {
|
|
|
27569
27670
|
}
|
|
27570
27671
|
return [];
|
|
27571
27672
|
}
|
|
27673
|
+
function quoteForShell(arg) {
|
|
27674
|
+
if ((0, import_os2.platform)() === "win32") {
|
|
27675
|
+
if (arg.length === 0) return '""';
|
|
27676
|
+
if (!/[\s"&|<>^%!]/.test(arg)) return arg;
|
|
27677
|
+
return `"${arg.replace(/"/g, '""')}"`;
|
|
27678
|
+
}
|
|
27679
|
+
if (arg.length === 0) return "''";
|
|
27680
|
+
return `'${arg.replace(/'/g, `'"'"'`)}'`;
|
|
27681
|
+
}
|
|
27572
27682
|
function buildShellInvocation(command) {
|
|
27573
27683
|
const shell = resolveUserShell();
|
|
27574
27684
|
if ((0, import_os2.platform)() === "win32") return { file: shell, args: ["/c", command] };
|
|
@@ -27645,6 +27755,16 @@ async function probeLoginShellPath(opts = {}) {
|
|
|
27645
27755
|
}
|
|
27646
27756
|
return null;
|
|
27647
27757
|
}
|
|
27758
|
+
var FIND_ON_PATH_TIMEOUT_MS = 3e3;
|
|
27759
|
+
function findOnPath(name, env) {
|
|
27760
|
+
const [file2, args] = (0, import_node_os3.platform)() === "win32" ? ["where", [name]] : ["/bin/sh", ["-c", `command -v ${quoteForShell(name)}`]];
|
|
27761
|
+
return new Promise((resolve9) => {
|
|
27762
|
+
(0, import_node_child_process2.execFile)(file2, args, { timeout: FIND_ON_PATH_TIMEOUT_MS, env }, (err, stdout2) => {
|
|
27763
|
+
const found = err ? "" : String(stdout2).trim().split("\n")[0]?.trim();
|
|
27764
|
+
resolve9(found ? found : null);
|
|
27765
|
+
});
|
|
27766
|
+
});
|
|
27767
|
+
}
|
|
27648
27768
|
|
|
27649
27769
|
// ../../shared/platform/src/slz-file-url.ts
|
|
27650
27770
|
var SLZ_FILE_HOST = "app";
|
|
@@ -27664,8 +27784,8 @@ async function adoptLoginShellPath(opts = {}) {
|
|
|
27664
27784
|
}
|
|
27665
27785
|
|
|
27666
27786
|
// src/main.ts
|
|
27667
|
-
var
|
|
27668
|
-
var
|
|
27787
|
+
var import_node_fs14 = require("node:fs");
|
|
27788
|
+
var import_node_path17 = require("node:path");
|
|
27669
27789
|
|
|
27670
27790
|
// src/request-log.ts
|
|
27671
27791
|
var import_node_fs4 = require("node:fs");
|
|
@@ -28465,9 +28585,9 @@ var WORKSPACE_MAX_SEARCH_RESULTS = 2e3;
|
|
|
28465
28585
|
function createLocalWorkspaceFs() {
|
|
28466
28586
|
return refuseOnSwitchedOffHub(createUnguardedLocalWorkspaceFs());
|
|
28467
28587
|
}
|
|
28468
|
-
function refuseOnSwitchedOffHub(
|
|
28588
|
+
function refuseOnSwitchedOffHub(fs8) {
|
|
28469
28589
|
const guarded = {};
|
|
28470
|
-
for (const [op, fn] of Object.entries(
|
|
28590
|
+
for (const [op, fn] of Object.entries(fs8)) {
|
|
28471
28591
|
guarded[op] = (...args) => {
|
|
28472
28592
|
assertHubLocalExecEnabled({ op: `fs.${op}` });
|
|
28473
28593
|
return fn(...args);
|
|
@@ -28492,8 +28612,8 @@ function createUnguardedLocalWorkspaceFs() {
|
|
|
28492
28612
|
sep: import_node_path9.sep
|
|
28493
28613
|
};
|
|
28494
28614
|
},
|
|
28495
|
-
async listDir(
|
|
28496
|
-
const abs = import_node_fs6.realpathSync.native((0, import_node_path9.resolve)(
|
|
28615
|
+
async listDir(path11, options) {
|
|
28616
|
+
const abs = import_node_fs6.realpathSync.native((0, import_node_path9.resolve)(path11));
|
|
28497
28617
|
const dirents = await (0, import_promises6.readdir)(abs, { withFileTypes: true });
|
|
28498
28618
|
const entries = [];
|
|
28499
28619
|
for (const e of dirents) {
|
|
@@ -28525,13 +28645,13 @@ function createUnguardedLocalWorkspaceFs() {
|
|
|
28525
28645
|
const parent = (0, import_node_path9.dirname)(abs);
|
|
28526
28646
|
return { path: abs, parent: parent === abs ? null : parent, entries };
|
|
28527
28647
|
},
|
|
28528
|
-
async mkdir(
|
|
28529
|
-
const abs = (0, import_node_path9.resolve)(
|
|
28648
|
+
async mkdir(path11) {
|
|
28649
|
+
const abs = (0, import_node_path9.resolve)(path11);
|
|
28530
28650
|
await (0, import_promises6.mkdir)(abs, { recursive: true });
|
|
28531
28651
|
return { path: import_node_fs6.realpathSync.native(abs) };
|
|
28532
28652
|
},
|
|
28533
|
-
pathExists(
|
|
28534
|
-
return (0, import_node_fs6.existsSync)((0, import_node_path9.resolve)(
|
|
28653
|
+
pathExists(path11) {
|
|
28654
|
+
return (0, import_node_fs6.existsSync)((0, import_node_path9.resolve)(path11));
|
|
28535
28655
|
},
|
|
28536
28656
|
// A hub has no path-jail — `allowedRoots` is a computer concept. Saying so is
|
|
28537
28657
|
// better than accepting the edit and discarding it, which would leave the
|
|
@@ -28546,12 +28666,12 @@ function createUnguardedLocalWorkspaceFs() {
|
|
|
28546
28666
|
// the fork sidecar and tests, neither of which should be minting a new
|
|
28547
28667
|
// persistent state file for a mapping a real computer owns.
|
|
28548
28668
|
resolveProjectPath(projectId) {
|
|
28549
|
-
const
|
|
28550
|
-
if (!
|
|
28551
|
-
return { path:
|
|
28669
|
+
const path11 = localProjectPaths.get(projectId);
|
|
28670
|
+
if (!path11) return { path: null };
|
|
28671
|
+
return { path: path11, exists: (0, import_node_fs6.existsSync)(path11) };
|
|
28552
28672
|
},
|
|
28553
|
-
setProjectPath(projectId,
|
|
28554
|
-
const abs = import_node_fs6.realpathSync.native((0, import_node_path9.resolve)(
|
|
28673
|
+
setProjectPath(projectId, path11) {
|
|
28674
|
+
const abs = import_node_fs6.realpathSync.native((0, import_node_path9.resolve)(path11));
|
|
28555
28675
|
localProjectPaths.set(projectId, abs);
|
|
28556
28676
|
return { path: abs };
|
|
28557
28677
|
},
|
|
@@ -28591,12 +28711,12 @@ function createUnguardedLocalWorkspaceFs() {
|
|
|
28591
28711
|
function createLocalWorkspaceFsAdapters(local = createLocalWorkspaceFs()) {
|
|
28592
28712
|
return {
|
|
28593
28713
|
listRoots: async () => local.listRoots(),
|
|
28594
|
-
listDir: async (_r,
|
|
28595
|
-
mkdir: async (_r,
|
|
28596
|
-
pathExists: async (_r,
|
|
28714
|
+
listDir: async (_r, path11, options) => local.listDir(path11, options),
|
|
28715
|
+
mkdir: async (_r, path11) => local.mkdir(path11),
|
|
28716
|
+
pathExists: async (_r, path11) => local.pathExists(path11),
|
|
28597
28717
|
setAllowedRoots: async (_r, roots) => local.setAllowedRoots(roots),
|
|
28598
28718
|
resolveProjectPath: async (_r, projectId) => local.resolveProjectPath(projectId),
|
|
28599
|
-
setProjectPath: async (_r, projectId,
|
|
28719
|
+
setProjectPath: async (_r, projectId, path11) => local.setProjectPath(projectId, path11),
|
|
28600
28720
|
forgetProjectPath: async (_r, projectId) => local.forgetProjectPath(projectId),
|
|
28601
28721
|
readDir: async (_r, rootPath, dirPath) => local.readDir(rootPath, dirPath),
|
|
28602
28722
|
readFile: async (_r, rootPath, filePath, force) => local.readFile(rootPath, filePath, force),
|
|
@@ -28686,28 +28806,28 @@ var noop = () => {
|
|
|
28686
28806
|
var freezeIfAvailable = (obj) => {
|
|
28687
28807
|
if (Object.freeze) Object.freeze(obj);
|
|
28688
28808
|
};
|
|
28689
|
-
function createInnerProxy(callback,
|
|
28809
|
+
function createInnerProxy(callback, path11, memo2) {
|
|
28690
28810
|
var _memo$cacheKey;
|
|
28691
|
-
const cacheKey =
|
|
28811
|
+
const cacheKey = path11.join(".");
|
|
28692
28812
|
(_memo$cacheKey = memo2[cacheKey]) !== null && _memo$cacheKey !== void 0 || (memo2[cacheKey] = new Proxy(noop, {
|
|
28693
28813
|
get(_obj, key) {
|
|
28694
28814
|
if (typeof key !== "string" || key === "then") return;
|
|
28695
|
-
return createInnerProxy(callback, [...
|
|
28815
|
+
return createInnerProxy(callback, [...path11, key], memo2);
|
|
28696
28816
|
},
|
|
28697
28817
|
apply(_1, _2, args) {
|
|
28698
|
-
const lastOfPath =
|
|
28699
|
-
if (lastOfPath === "valueOf" || lastOfPath === "toString" || lastOfPath === "toJSON") return `tRPC.proxy(${
|
|
28818
|
+
const lastOfPath = path11[path11.length - 1];
|
|
28819
|
+
if (lastOfPath === "valueOf" || lastOfPath === "toString" || lastOfPath === "toJSON") return `tRPC.proxy(${path11.slice(0, -1).join(".")})`;
|
|
28700
28820
|
let opts = {
|
|
28701
28821
|
args,
|
|
28702
|
-
path:
|
|
28822
|
+
path: path11
|
|
28703
28823
|
};
|
|
28704
28824
|
if (lastOfPath === "call") opts = {
|
|
28705
28825
|
args: args.length >= 2 ? [args[1]] : [],
|
|
28706
|
-
path:
|
|
28826
|
+
path: path11.slice(0, -1)
|
|
28707
28827
|
};
|
|
28708
28828
|
else if (lastOfPath === "apply") opts = {
|
|
28709
28829
|
args: args.length >= 2 ? args[1] : [],
|
|
28710
|
-
path:
|
|
28830
|
+
path: path11.slice(0, -1)
|
|
28711
28831
|
};
|
|
28712
28832
|
freezeIfAvailable(opts.args);
|
|
28713
28833
|
freezeIfAvailable(opts.path);
|
|
@@ -28886,12 +29006,12 @@ function createRouterFactory(config2) {
|
|
|
28886
29006
|
})
|
|
28887
29007
|
};
|
|
28888
29008
|
}
|
|
28889
|
-
function step(from,
|
|
29009
|
+
function step(from, path11 = []) {
|
|
28890
29010
|
const aggregate = emptyObject();
|
|
28891
29011
|
for (const [key, item] of Object.entries(from !== null && from !== void 0 ? from : {})) {
|
|
28892
29012
|
if (isLazy(item)) {
|
|
28893
|
-
lazy3[[...
|
|
28894
|
-
path:
|
|
29013
|
+
lazy3[[...path11, key].join(".")] = createLazyLoader({
|
|
29014
|
+
path: path11,
|
|
28895
29015
|
ref: item,
|
|
28896
29016
|
key,
|
|
28897
29017
|
aggregate
|
|
@@ -28899,14 +29019,14 @@ function createRouterFactory(config2) {
|
|
|
28899
29019
|
continue;
|
|
28900
29020
|
}
|
|
28901
29021
|
if (isRouter(item)) {
|
|
28902
|
-
aggregate[key] = step(item._def.record, [...
|
|
29022
|
+
aggregate[key] = step(item._def.record, [...path11, key]);
|
|
28903
29023
|
continue;
|
|
28904
29024
|
}
|
|
28905
29025
|
if (!isProcedure(item)) {
|
|
28906
|
-
aggregate[key] = step(item, [...
|
|
29026
|
+
aggregate[key] = step(item, [...path11, key]);
|
|
28907
29027
|
continue;
|
|
28908
29028
|
}
|
|
28909
|
-
const newPath = [...
|
|
29029
|
+
const newPath = [...path11, key].join(".");
|
|
28910
29030
|
if (procedures[newPath]) throw new Error(`Duplicate key: ${newPath}`);
|
|
28911
29031
|
procedures[newPath] = item;
|
|
28912
29032
|
aggregate[key] = item;
|
|
@@ -28930,14 +29050,14 @@ function createRouterFactory(config2) {
|
|
|
28930
29050
|
function isProcedure(procedureOrRouter) {
|
|
28931
29051
|
return typeof procedureOrRouter === "function";
|
|
28932
29052
|
}
|
|
28933
|
-
async function getProcedureAtPath(router2,
|
|
29053
|
+
async function getProcedureAtPath(router2, path11) {
|
|
28934
29054
|
const { _def } = router2;
|
|
28935
|
-
let procedure = _def.procedures[
|
|
29055
|
+
let procedure = _def.procedures[path11];
|
|
28936
29056
|
while (!procedure) {
|
|
28937
|
-
const key = Object.keys(_def.lazy).find((key2) =>
|
|
29057
|
+
const key = Object.keys(_def.lazy).find((key2) => path11 === key2 || path11.startsWith(key2 + "."));
|
|
28938
29058
|
if (!key) return null;
|
|
28939
29059
|
await _def.lazy[key].load();
|
|
28940
|
-
procedure = _def.procedures[
|
|
29060
|
+
procedure = _def.procedures[path11];
|
|
28941
29061
|
}
|
|
28942
29062
|
return procedure;
|
|
28943
29063
|
}
|
|
@@ -28946,15 +29066,15 @@ function createCallerFactory() {
|
|
|
28946
29066
|
const { _def } = router2;
|
|
28947
29067
|
return function createCaller(ctxOrCallback, opts) {
|
|
28948
29068
|
return createRecursiveProxy(async (innerOpts) => {
|
|
28949
|
-
const { path:
|
|
28950
|
-
const fullPath =
|
|
28951
|
-
if (
|
|
29069
|
+
const { path: path11, args } = innerOpts;
|
|
29070
|
+
const fullPath = path11.join(".");
|
|
29071
|
+
if (path11.length === 1 && path11[0] === "_def") return _def;
|
|
28952
29072
|
const procedure = await getProcedureAtPath(router2, fullPath);
|
|
28953
29073
|
let ctx = void 0;
|
|
28954
29074
|
try {
|
|
28955
29075
|
if (!procedure) throw new TRPCError({
|
|
28956
29076
|
code: "NOT_FOUND",
|
|
28957
|
-
message: `No procedure found on path "${
|
|
29077
|
+
message: `No procedure found on path "${path11}"`
|
|
28958
29078
|
});
|
|
28959
29079
|
ctx = isFunction(ctxOrCallback) ? await Promise.resolve(ctxOrCallback()) : ctxOrCallback;
|
|
28960
29080
|
return await procedure({
|
|
@@ -29558,7 +29678,7 @@ var isURL = (payload) => payload instanceof URL;
|
|
|
29558
29678
|
|
|
29559
29679
|
// ../../../node_modules/superjson/dist/pathstringifier.js
|
|
29560
29680
|
var escapeKey = (key) => key.replace(/\\/g, "\\\\").replace(/\./g, "\\.");
|
|
29561
|
-
var stringifyPath = (
|
|
29681
|
+
var stringifyPath = (path11) => path11.map(String).map(escapeKey).join(".");
|
|
29562
29682
|
var parsePath = (string4, legacyPaths) => {
|
|
29563
29683
|
const result = [];
|
|
29564
29684
|
let segment = "";
|
|
@@ -29805,26 +29925,26 @@ var getNthKey = (value, n) => {
|
|
|
29805
29925
|
}
|
|
29806
29926
|
return keys.next().value;
|
|
29807
29927
|
};
|
|
29808
|
-
function validatePath(
|
|
29809
|
-
if (includes(
|
|
29928
|
+
function validatePath(path11) {
|
|
29929
|
+
if (includes(path11, "__proto__")) {
|
|
29810
29930
|
throw new Error("__proto__ is not allowed as a property");
|
|
29811
29931
|
}
|
|
29812
|
-
if (includes(
|
|
29932
|
+
if (includes(path11, "prototype")) {
|
|
29813
29933
|
throw new Error("prototype is not allowed as a property");
|
|
29814
29934
|
}
|
|
29815
|
-
if (includes(
|
|
29935
|
+
if (includes(path11, "constructor")) {
|
|
29816
29936
|
throw new Error("constructor is not allowed as a property");
|
|
29817
29937
|
}
|
|
29818
29938
|
}
|
|
29819
|
-
var getDeep = (object2,
|
|
29820
|
-
validatePath(
|
|
29821
|
-
for (let i = 0; i <
|
|
29822
|
-
const key =
|
|
29939
|
+
var getDeep = (object2, path11) => {
|
|
29940
|
+
validatePath(path11);
|
|
29941
|
+
for (let i = 0; i < path11.length; i++) {
|
|
29942
|
+
const key = path11[i];
|
|
29823
29943
|
if (isSet(object2)) {
|
|
29824
29944
|
object2 = getNthKey(object2, +key);
|
|
29825
29945
|
} else if (isMap(object2)) {
|
|
29826
29946
|
const row = +key;
|
|
29827
|
-
const type = +
|
|
29947
|
+
const type = +path11[++i] === 0 ? "key" : "value";
|
|
29828
29948
|
const keyOfRow = getNthKey(object2, row);
|
|
29829
29949
|
switch (type) {
|
|
29830
29950
|
case "key":
|
|
@@ -29840,14 +29960,14 @@ var getDeep = (object2, path9) => {
|
|
|
29840
29960
|
}
|
|
29841
29961
|
return object2;
|
|
29842
29962
|
};
|
|
29843
|
-
var setDeep = (object2,
|
|
29844
|
-
validatePath(
|
|
29845
|
-
if (
|
|
29963
|
+
var setDeep = (object2, path11, mapper) => {
|
|
29964
|
+
validatePath(path11);
|
|
29965
|
+
if (path11.length === 0) {
|
|
29846
29966
|
return mapper(object2);
|
|
29847
29967
|
}
|
|
29848
29968
|
let parent = object2;
|
|
29849
|
-
for (let i = 0; i <
|
|
29850
|
-
const key =
|
|
29969
|
+
for (let i = 0; i < path11.length - 1; i++) {
|
|
29970
|
+
const key = path11[i];
|
|
29851
29971
|
if (isArray(parent)) {
|
|
29852
29972
|
const index = +key;
|
|
29853
29973
|
parent = parent[index];
|
|
@@ -29857,12 +29977,12 @@ var setDeep = (object2, path9, mapper) => {
|
|
|
29857
29977
|
const row = +key;
|
|
29858
29978
|
parent = getNthKey(parent, row);
|
|
29859
29979
|
} else if (isMap(parent)) {
|
|
29860
|
-
const isEnd = i ===
|
|
29980
|
+
const isEnd = i === path11.length - 2;
|
|
29861
29981
|
if (isEnd) {
|
|
29862
29982
|
break;
|
|
29863
29983
|
}
|
|
29864
29984
|
const row = +key;
|
|
29865
|
-
const type = +
|
|
29985
|
+
const type = +path11[++i] === 0 ? "key" : "value";
|
|
29866
29986
|
const keyOfRow = getNthKey(parent, row);
|
|
29867
29987
|
switch (type) {
|
|
29868
29988
|
case "key":
|
|
@@ -29874,7 +29994,7 @@ var setDeep = (object2, path9, mapper) => {
|
|
|
29874
29994
|
}
|
|
29875
29995
|
}
|
|
29876
29996
|
}
|
|
29877
|
-
const lastKey =
|
|
29997
|
+
const lastKey = path11[path11.length - 1];
|
|
29878
29998
|
if (isArray(parent)) {
|
|
29879
29999
|
parent[+lastKey] = mapper(parent[+lastKey]);
|
|
29880
30000
|
} else if (isPlainObject2(parent)) {
|
|
@@ -29889,7 +30009,7 @@ var setDeep = (object2, path9, mapper) => {
|
|
|
29889
30009
|
}
|
|
29890
30010
|
}
|
|
29891
30011
|
if (isMap(parent)) {
|
|
29892
|
-
const row = +
|
|
30012
|
+
const row = +path11[path11.length - 2];
|
|
29893
30013
|
const keyToRow = getNthKey(parent, row);
|
|
29894
30014
|
const type = +lastKey === 0 ? "key" : "value";
|
|
29895
30015
|
switch (type) {
|
|
@@ -29936,16 +30056,16 @@ function traverse(tree, walker2, version2, origin = []) {
|
|
|
29936
30056
|
walker2(nodeValue, origin);
|
|
29937
30057
|
}
|
|
29938
30058
|
function applyValueAnnotations(plain, annotations, version2, superJson) {
|
|
29939
|
-
traverse(annotations, (type,
|
|
29940
|
-
plain = setDeep(plain,
|
|
30059
|
+
traverse(annotations, (type, path11) => {
|
|
30060
|
+
plain = setDeep(plain, path11, (v) => untransformValue(v, type, superJson));
|
|
29941
30061
|
}, version2);
|
|
29942
30062
|
return plain;
|
|
29943
30063
|
}
|
|
29944
30064
|
function applyReferentialEqualityAnnotations(plain, annotations, version2) {
|
|
29945
30065
|
const legacyPaths = enableLegacyPaths(version2);
|
|
29946
|
-
function apply(identicalPaths,
|
|
29947
|
-
const object2 = getDeep(plain, parsePath(
|
|
29948
|
-
identicalPaths.map((
|
|
30066
|
+
function apply(identicalPaths, path11) {
|
|
30067
|
+
const object2 = getDeep(plain, parsePath(path11, legacyPaths));
|
|
30068
|
+
identicalPaths.map((path12) => parsePath(path12, legacyPaths)).forEach((identicalObjectPath) => {
|
|
29949
30069
|
plain = setDeep(plain, identicalObjectPath, () => object2);
|
|
29950
30070
|
});
|
|
29951
30071
|
}
|
|
@@ -29963,12 +30083,12 @@ function applyReferentialEqualityAnnotations(plain, annotations, version2) {
|
|
|
29963
30083
|
return plain;
|
|
29964
30084
|
}
|
|
29965
30085
|
var isDeep = (object2, superJson) => isPlainObject2(object2) || isArray(object2) || isMap(object2) || isSet(object2) || isError(object2) || isInstanceOfRegisteredClass(object2, superJson);
|
|
29966
|
-
function addIdentity(object2,
|
|
30086
|
+
function addIdentity(object2, path11, identities) {
|
|
29967
30087
|
const existingSet = identities.get(object2);
|
|
29968
30088
|
if (existingSet) {
|
|
29969
|
-
existingSet.push(
|
|
30089
|
+
existingSet.push(path11);
|
|
29970
30090
|
} else {
|
|
29971
|
-
identities.set(object2, [
|
|
30091
|
+
identities.set(object2, [path11]);
|
|
29972
30092
|
}
|
|
29973
30093
|
}
|
|
29974
30094
|
function generateReferentialEqualityAnnotations(identitites, dedupe) {
|
|
@@ -29979,7 +30099,7 @@ function generateReferentialEqualityAnnotations(identitites, dedupe) {
|
|
|
29979
30099
|
return;
|
|
29980
30100
|
}
|
|
29981
30101
|
if (!dedupe) {
|
|
29982
|
-
paths = paths.map((
|
|
30102
|
+
paths = paths.map((path11) => path11.map(String)).sort((a, b) => a.length - b.length);
|
|
29983
30103
|
}
|
|
29984
30104
|
const [representativePath, ...identicalPaths] = paths;
|
|
29985
30105
|
if (representativePath.length === 0) {
|
|
@@ -29998,10 +30118,10 @@ function generateReferentialEqualityAnnotations(identitites, dedupe) {
|
|
|
29998
30118
|
return isEmptyObject(result) ? void 0 : result;
|
|
29999
30119
|
}
|
|
30000
30120
|
}
|
|
30001
|
-
var walker = (object2, identities, superJson, dedupe,
|
|
30121
|
+
var walker = (object2, identities, superJson, dedupe, path11 = [], objectsInThisPath = [], seenObjects = /* @__PURE__ */ new Map()) => {
|
|
30002
30122
|
const primitive = isPrimitive(object2);
|
|
30003
30123
|
if (!primitive) {
|
|
30004
|
-
addIdentity(object2,
|
|
30124
|
+
addIdentity(object2, path11, identities);
|
|
30005
30125
|
const seen = seenObjects.get(object2);
|
|
30006
30126
|
if (seen) {
|
|
30007
30127
|
return dedupe ? {
|
|
@@ -30035,7 +30155,7 @@ var walker = (object2, identities, superJson, dedupe, path9 = [], objectsInThisP
|
|
|
30035
30155
|
if (index === "__proto__" || index === "constructor" || index === "prototype") {
|
|
30036
30156
|
throw new Error(`Detected property ${index}. This is a prototype pollution risk, please remove it from your object.`);
|
|
30037
30157
|
}
|
|
30038
|
-
const recursiveResult = walker(value, identities, superJson, dedupe, [...
|
|
30158
|
+
const recursiveResult = walker(value, identities, superJson, dedupe, [...path11, index], [...objectsInThisPath, object2], seenObjects);
|
|
30039
30159
|
transformedValue[index] = recursiveResult.transformedValue;
|
|
30040
30160
|
if (isArray(recursiveResult.annotations)) {
|
|
30041
30161
|
innerAnnotations[escapeKey(index)] = recursiveResult.annotations;
|
|
@@ -30281,12 +30401,12 @@ function auditAdminDenied(opts) {
|
|
|
30281
30401
|
detail: { reason: "not_admin", code: ADMIN_ONLY, ...opts.detail }
|
|
30282
30402
|
});
|
|
30283
30403
|
}
|
|
30284
|
-
function adminOnlyTrpcError(
|
|
30285
|
-
auditAdminDenied({ targetKind: "procedure", targetId:
|
|
30404
|
+
function adminOnlyTrpcError(path11) {
|
|
30405
|
+
auditAdminDenied({ targetKind: "procedure", targetId: path11 });
|
|
30286
30406
|
return new TRPCError({
|
|
30287
30407
|
code: "FORBIDDEN",
|
|
30288
|
-
message: `${
|
|
30289
|
-
cause: new AdminOnlyError(
|
|
30408
|
+
message: `${path11} needs a hub admin account`,
|
|
30409
|
+
cause: new AdminOnlyError(path11)
|
|
30290
30410
|
});
|
|
30291
30411
|
}
|
|
30292
30412
|
|
|
@@ -30339,45 +30459,45 @@ var router = t.router;
|
|
|
30339
30459
|
var middleware = t.middleware;
|
|
30340
30460
|
var mergeRouters2 = t.mergeRouters;
|
|
30341
30461
|
var securityContext = t.middleware(
|
|
30342
|
-
({ ctx, next, path:
|
|
30343
|
-
{ actor: ctx.principal?.userId ?? null, ip: peerAddress(ctx.req), route: `trpc ${
|
|
30462
|
+
({ ctx, next, path: path11 }) => runWithSecurityContext(
|
|
30463
|
+
{ actor: ctx.principal?.userId ?? null, ip: peerAddress(ctx.req), route: `trpc ${path11}` },
|
|
30344
30464
|
() => next()
|
|
30345
30465
|
)
|
|
30346
30466
|
);
|
|
30347
|
-
function auditDenied(
|
|
30467
|
+
function auditDenied(path11, detail) {
|
|
30348
30468
|
securityEvent({
|
|
30349
30469
|
event: "authz.denied",
|
|
30350
30470
|
outcome: "denied",
|
|
30351
30471
|
targetKind: "procedure",
|
|
30352
|
-
targetId:
|
|
30472
|
+
targetId: path11,
|
|
30353
30473
|
detail
|
|
30354
30474
|
});
|
|
30355
30475
|
}
|
|
30356
|
-
var authGate2 = t.middleware(({ ctx, next, path:
|
|
30476
|
+
var authGate2 = t.middleware(({ ctx, next, path: path11 }) => {
|
|
30357
30477
|
if (getAuthGate() && !ctx.principal) {
|
|
30358
|
-
auditDenied(
|
|
30478
|
+
auditDenied(path11, { reason: "unauthenticated" });
|
|
30359
30479
|
throw new TRPCError({ code: "UNAUTHORIZED", message: "hub requires authentication" });
|
|
30360
30480
|
}
|
|
30361
30481
|
return next();
|
|
30362
30482
|
});
|
|
30363
|
-
var scopeGate = t.middleware(({ ctx, next, path:
|
|
30483
|
+
var scopeGate = t.middleware(({ ctx, next, path: path11 }) => {
|
|
30364
30484
|
if (!getAuthGate()) return next();
|
|
30365
30485
|
const scopes = ctx.principal?.scopes ?? [];
|
|
30366
|
-
if (!procedurePolicy().scopeAllows(scopes,
|
|
30367
|
-
auditDenied(
|
|
30368
|
-
throw new TRPCError({ code: "FORBIDDEN", message: `insufficient scope for ${
|
|
30486
|
+
if (!procedurePolicy().scopeAllows(scopes, path11)) {
|
|
30487
|
+
auditDenied(path11, { reason: "scope", scopes });
|
|
30488
|
+
throw new TRPCError({ code: "FORBIDDEN", message: `insufficient scope for ${path11}` });
|
|
30369
30489
|
}
|
|
30370
30490
|
return next();
|
|
30371
30491
|
});
|
|
30372
|
-
var adminGate = t.middleware(({ ctx, next, path:
|
|
30492
|
+
var adminGate = t.middleware(({ ctx, next, path: path11 }) => {
|
|
30373
30493
|
if (!getAuthGate()) return next();
|
|
30374
|
-
if (!roleAllows(procedurePolicy().adminClassOf(
|
|
30375
|
-
throw adminOnlyTrpcError(
|
|
30494
|
+
if (!roleAllows(procedurePolicy().adminClassOf(path11), ctx.principal?.role ?? "user")) {
|
|
30495
|
+
throw adminOnlyTrpcError(path11);
|
|
30376
30496
|
}
|
|
30377
30497
|
return next();
|
|
30378
30498
|
});
|
|
30379
|
-
var ownerGate = t.middleware(async ({ ctx, next, path:
|
|
30380
|
-
const filter = getAuthGate() ? await procedurePolicy().ownerCheck({ ctx, path:
|
|
30499
|
+
var ownerGate = t.middleware(async ({ ctx, next, path: path11, type, getRawInput }) => {
|
|
30500
|
+
const filter = getAuthGate() ? await procedurePolicy().ownerCheck({ ctx, path: path11, type, getRawInput }) : null;
|
|
30381
30501
|
const result = await next();
|
|
30382
30502
|
if (!filter || !result.ok) return result;
|
|
30383
30503
|
return { ...result, data: await filter(result.data) };
|
|
@@ -30405,8 +30525,8 @@ var unsafePathRefusal = t.middleware(async ({ next }) => {
|
|
|
30405
30525
|
return result;
|
|
30406
30526
|
});
|
|
30407
30527
|
var publicProcedure = t.procedure.use(securityContext).use(authGate2).use(adminGate).use(scopeGate).use(ownerGate).use(switchRefusal).use(unsafePathRefusal);
|
|
30408
|
-
var hubLocalProcedure = publicProcedure.use(({ next, path:
|
|
30409
|
-
assertHubLocalExecEnabled({ op:
|
|
30528
|
+
var hubLocalProcedure = publicProcedure.use(({ next, path: path11 }) => {
|
|
30529
|
+
assertHubLocalExecEnabled({ op: path11 });
|
|
30410
30530
|
return next();
|
|
30411
30531
|
});
|
|
30412
30532
|
var openProcedure = t.procedure.use(securityContext);
|
|
@@ -30496,8 +30616,8 @@ var fileEditorRouter = router({
|
|
|
30496
30616
|
* should only offer this when the workspace is co-resident — the caller decides.
|
|
30497
30617
|
*/
|
|
30498
30618
|
showInFinder: publicProcedure.input(external_exports.object({ rootPath: external_exports.string(), targetPath: external_exports.string() })).mutation(async ({ input: input2 }) => {
|
|
30499
|
-
const
|
|
30500
|
-
const abs = input2.targetPath ?
|
|
30619
|
+
const path11 = await import("node:path");
|
|
30620
|
+
const abs = input2.targetPath ? path11.resolve(input2.rootPath, input2.targetPath) : path11.resolve(input2.rootPath);
|
|
30501
30621
|
getFileEditorRouterDeps().shellShowItemInFolder(abs);
|
|
30502
30622
|
}),
|
|
30503
30623
|
/**
|
|
@@ -30549,9 +30669,9 @@ var workspaceRouter = router({
|
|
|
30549
30669
|
* surfaced as such rather than rendered as an empty directory.
|
|
30550
30670
|
*/
|
|
30551
30671
|
listRoots: publicProcedure.input(targetInput).query(async ({ input: input2 }) => {
|
|
30552
|
-
const { fs:
|
|
30672
|
+
const { fs: fs8, resolveComputer, isLocalComputer } = getWorkspaceDeps();
|
|
30553
30673
|
const computerId = await resolveComputer(input2);
|
|
30554
|
-
return { computerId, isLocal: isLocalComputer(computerId), ...await
|
|
30674
|
+
return { computerId, isLocal: isLocalComputer(computerId), ...await fs8.listRoots(computerId) };
|
|
30555
30675
|
}),
|
|
30556
30676
|
listDir: publicProcedure.input(
|
|
30557
30677
|
targetInput.extend({
|
|
@@ -30561,18 +30681,18 @@ var workspaceRouter = router({
|
|
|
30561
30681
|
includeHidden: external_exports.boolean().optional()
|
|
30562
30682
|
})
|
|
30563
30683
|
).query(async ({ input: input2 }) => {
|
|
30564
|
-
const { fs:
|
|
30684
|
+
const { fs: fs8, resolveComputer } = getWorkspaceDeps();
|
|
30565
30685
|
const computerId = await resolveComputer(input2);
|
|
30566
|
-
const res = await
|
|
30686
|
+
const res = await fs8.listDir(computerId, input2.path, {
|
|
30567
30687
|
dirsOnly: input2.dirsOnly,
|
|
30568
30688
|
includeHidden: input2.includeHidden
|
|
30569
30689
|
});
|
|
30570
30690
|
return { computerId, ...res };
|
|
30571
30691
|
}),
|
|
30572
30692
|
mkdir: publicProcedure.input(targetInput.extend({ path: external_exports.string().min(1) })).mutation(async ({ input: input2 }) => {
|
|
30573
|
-
const { fs:
|
|
30693
|
+
const { fs: fs8, resolveComputer } = getWorkspaceDeps();
|
|
30574
30694
|
const computerId = await resolveComputer(input2);
|
|
30575
|
-
const res = await
|
|
30695
|
+
const res = await fs8.mkdir(computerId, input2.path);
|
|
30576
30696
|
return { computerId, ...res };
|
|
30577
30697
|
}),
|
|
30578
30698
|
/**
|
|
@@ -30588,9 +30708,9 @@ var workspaceRouter = router({
|
|
|
30588
30708
|
* from the enforced one.
|
|
30589
30709
|
*/
|
|
30590
30710
|
setAllowedRoots: publicProcedure.input(targetInput.extend({ roots: external_exports.array(external_exports.string().min(1)) })).mutation(async ({ input: input2 }) => {
|
|
30591
|
-
const { fs:
|
|
30711
|
+
const { fs: fs8, resolveComputer } = getWorkspaceDeps();
|
|
30592
30712
|
const computerId = await resolveComputer(input2);
|
|
30593
|
-
return { computerId, ...await
|
|
30713
|
+
return { computerId, ...await fs8.setAllowedRoots(computerId, input2.roots) };
|
|
30594
30714
|
}),
|
|
30595
30715
|
/**
|
|
30596
30716
|
* Where does the target machine keep this project?
|
|
@@ -30601,13 +30721,13 @@ var workspaceRouter = router({
|
|
|
30601
30721
|
* is different again: recorded, but the folder is gone.
|
|
30602
30722
|
*/
|
|
30603
30723
|
resolveProjectPath: publicProcedure.input(targetInput.extend({ projectId: external_exports.string().min(1) })).query(async ({ input: input2 }) => {
|
|
30604
|
-
const { fs:
|
|
30724
|
+
const { fs: fs8, resolveComputer } = getWorkspaceDeps();
|
|
30605
30725
|
const computerId = await resolveComputer(input2);
|
|
30606
30726
|
try {
|
|
30607
30727
|
return {
|
|
30608
30728
|
computerId,
|
|
30609
30729
|
reachable: true,
|
|
30610
|
-
...await
|
|
30730
|
+
...await fs8.resolveProjectPath(computerId, input2.projectId)
|
|
30611
30731
|
};
|
|
30612
30732
|
} catch (err) {
|
|
30613
30733
|
return {
|
|
@@ -30626,18 +30746,18 @@ var workspaceRouter = router({
|
|
|
30626
30746
|
path: external_exports.string().min(1)
|
|
30627
30747
|
})
|
|
30628
30748
|
).mutation(async ({ input: input2 }) => {
|
|
30629
|
-
const { fs:
|
|
30749
|
+
const { fs: fs8, resolveComputer } = getWorkspaceDeps();
|
|
30630
30750
|
const computerId = await resolveComputer(input2);
|
|
30631
30751
|
return {
|
|
30632
30752
|
computerId,
|
|
30633
|
-
...await
|
|
30753
|
+
...await fs8.setProjectPath(computerId, input2.projectId, input2.path)
|
|
30634
30754
|
};
|
|
30635
30755
|
}),
|
|
30636
30756
|
/** Drop the mapping on that machine. The checkout itself is left alone. */
|
|
30637
30757
|
forgetProjectPath: publicProcedure.input(targetInput.extend({ projectId: external_exports.string().min(1) })).mutation(async ({ input: input2 }) => {
|
|
30638
|
-
const { fs:
|
|
30758
|
+
const { fs: fs8, resolveComputer } = getWorkspaceDeps();
|
|
30639
30759
|
const computerId = await resolveComputer(input2);
|
|
30640
|
-
await
|
|
30760
|
+
await fs8.forgetProjectPath(computerId, input2.projectId);
|
|
30641
30761
|
return { computerId, ok: true };
|
|
30642
30762
|
}),
|
|
30643
30763
|
/**
|
|
@@ -30649,10 +30769,10 @@ var workspaceRouter = router({
|
|
|
30649
30769
|
* "No repository path configured" for a path that was fine.
|
|
30650
30770
|
*/
|
|
30651
30771
|
pathExists: publicProcedure.input(targetInput.extend({ path: external_exports.string().min(1) })).query(async ({ input: input2 }) => {
|
|
30652
|
-
const { fs:
|
|
30772
|
+
const { fs: fs8, resolveComputer } = getWorkspaceDeps();
|
|
30653
30773
|
const computerId = await resolveComputer(input2);
|
|
30654
30774
|
try {
|
|
30655
|
-
return { computerId, exists: await
|
|
30775
|
+
return { computerId, exists: await fs8.pathExists(computerId, input2.path), reachable: true };
|
|
30656
30776
|
} catch (err) {
|
|
30657
30777
|
return {
|
|
30658
30778
|
computerId,
|
|
@@ -30676,13 +30796,13 @@ function createFsHandlers(ctx) {
|
|
|
30676
30796
|
};
|
|
30677
30797
|
const watches = /* @__PURE__ */ new Map();
|
|
30678
30798
|
function pathExists(rawParams) {
|
|
30679
|
-
const { path:
|
|
30680
|
-
const resolved = allow(
|
|
30799
|
+
const { path: path11 } = fsPathExistsParamsSchema.parse(rawParams);
|
|
30800
|
+
const resolved = allow(path11);
|
|
30681
30801
|
return { exists: (0, import_node_fs7.existsSync)(resolved) };
|
|
30682
30802
|
}
|
|
30683
30803
|
async function removeDir(rawParams) {
|
|
30684
|
-
const { path:
|
|
30685
|
-
const resolved = allow(
|
|
30804
|
+
const { path: path11 } = fsRemoveDirParamsSchema.parse(rawParams);
|
|
30805
|
+
const resolved = allow(path11, true);
|
|
30686
30806
|
await (0, import_promises7.rm)(resolved, { recursive: true, force: true });
|
|
30687
30807
|
ctx.log("fs removeDir", { path: resolved });
|
|
30688
30808
|
return { ok: true };
|
|
@@ -30745,8 +30865,8 @@ function createFsHandlers(ctx) {
|
|
|
30745
30865
|
return { path: abs, parent: isRoot ? null : (0, import_node_path10.dirname)(abs), entries };
|
|
30746
30866
|
}
|
|
30747
30867
|
async function mkdirHandler(rawParams) {
|
|
30748
|
-
const { path:
|
|
30749
|
-
const abs = allow(
|
|
30868
|
+
const { path: path11 } = fsMkdirParamsSchema.parse(rawParams);
|
|
30869
|
+
const abs = allow(path11);
|
|
30750
30870
|
await (0, import_promises7.mkdir)(abs, { recursive: true });
|
|
30751
30871
|
ctx.log("fs mkdir", { path: abs });
|
|
30752
30872
|
return { path: import_node_fs7.realpathSync.native(abs) };
|
|
@@ -30906,11 +31026,132 @@ function createGhHandlers(ctx) {
|
|
|
30906
31026
|
return { [HubToComputerMethods.ghExec]: ghExec };
|
|
30907
31027
|
}
|
|
30908
31028
|
|
|
31029
|
+
// src/handlers/claude-session.ts
|
|
31030
|
+
var import_node_fs8 = require("node:fs");
|
|
31031
|
+
var import_node_os7 = require("node:os");
|
|
31032
|
+
var import_node_path11 = require("node:path");
|
|
31033
|
+
var import_node_readline = require("node:readline");
|
|
31034
|
+
var LARGE_RECORD_BYTES = 32 * 1024;
|
|
31035
|
+
var KEEP_TOOL_TEXT = 8 * 1024;
|
|
31036
|
+
function encodeProjectDir(cwd) {
|
|
31037
|
+
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
31038
|
+
}
|
|
31039
|
+
function claudeConfigDir() {
|
|
31040
|
+
return process.env.CLAUDE_CONFIG_DIR || (0, import_node_path11.join)((0, import_node_os7.homedir)(), ".claude");
|
|
31041
|
+
}
|
|
31042
|
+
function sessionFile(cwd, sessionId) {
|
|
31043
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
31044
|
+
try {
|
|
31045
|
+
candidates.add((0, import_node_fs8.realpathSync)(cwd));
|
|
31046
|
+
} catch {
|
|
31047
|
+
}
|
|
31048
|
+
candidates.add(cwd);
|
|
31049
|
+
for (const dir of candidates) {
|
|
31050
|
+
const file2 = (0, import_node_path11.join)(claudeConfigDir(), "projects", encodeProjectDir(dir), `${sessionId}.jsonl`);
|
|
31051
|
+
if ((0, import_node_fs8.existsSync)(file2)) return file2;
|
|
31052
|
+
}
|
|
31053
|
+
return null;
|
|
31054
|
+
}
|
|
31055
|
+
async function* records(file2) {
|
|
31056
|
+
const input2 = (0, import_node_fs8.createReadStream)(file2, { encoding: "utf8" });
|
|
31057
|
+
const rl = (0, import_node_readline.createInterface)({ input: input2, crlfDelay: Infinity });
|
|
31058
|
+
try {
|
|
31059
|
+
for await (const line of rl) {
|
|
31060
|
+
const trimmed = line.trim();
|
|
31061
|
+
if (!trimmed) continue;
|
|
31062
|
+
try {
|
|
31063
|
+
const rec = JSON.parse(trimmed);
|
|
31064
|
+
if (rec && typeof rec === "object" && !Array.isArray(rec)) {
|
|
31065
|
+
yield rec;
|
|
31066
|
+
}
|
|
31067
|
+
} catch {
|
|
31068
|
+
}
|
|
31069
|
+
}
|
|
31070
|
+
} finally {
|
|
31071
|
+
rl.close();
|
|
31072
|
+
input2.destroy();
|
|
31073
|
+
}
|
|
31074
|
+
}
|
|
31075
|
+
function isContent(rec) {
|
|
31076
|
+
if (rec.isSidechain === true) return false;
|
|
31077
|
+
if (rec.type === "user" || rec.type === "assistant") return true;
|
|
31078
|
+
return rec.type === "system" && rec.subtype === "compact_boundary";
|
|
31079
|
+
}
|
|
31080
|
+
function shortened(rec) {
|
|
31081
|
+
if (JSON.stringify(rec).length <= LARGE_RECORD_BYTES) return rec;
|
|
31082
|
+
const message = rec.message;
|
|
31083
|
+
if (!message || !Array.isArray(message.content)) return rec;
|
|
31084
|
+
const cut = (text) => text.length > KEEP_TOOL_TEXT ? `${text.slice(0, KEEP_TOOL_TEXT)}
|
|
31085
|
+
\u2026 (shortened)` : text;
|
|
31086
|
+
const content = message.content.map((block) => {
|
|
31087
|
+
const b = block;
|
|
31088
|
+
if (b?.type !== "tool_result") return block;
|
|
31089
|
+
if (typeof b.content === "string") return { ...b, content: cut(b.content) };
|
|
31090
|
+
if (Array.isArray(b.content)) {
|
|
31091
|
+
return {
|
|
31092
|
+
...b,
|
|
31093
|
+
content: b.content.map((part) => {
|
|
31094
|
+
const p = part;
|
|
31095
|
+
return p?.type === "text" && typeof p.text === "string" ? { ...p, text: cut(p.text) } : part;
|
|
31096
|
+
})
|
|
31097
|
+
};
|
|
31098
|
+
}
|
|
31099
|
+
return block;
|
|
31100
|
+
});
|
|
31101
|
+
const { toolUseResult: _structured, ...rest } = rec;
|
|
31102
|
+
void _structured;
|
|
31103
|
+
return { ...rest, message: { ...message, content } };
|
|
31104
|
+
}
|
|
31105
|
+
function createClaudeSessionHandlers(ctx, getProjectPaths) {
|
|
31106
|
+
async function read(rawParams) {
|
|
31107
|
+
const params = claudeSessionReadParamsSchema.parse(rawParams);
|
|
31108
|
+
const resolved = params.cwd ?? (params.projectId ? getProjectPaths()?.get(params.projectId)?.path : void 0);
|
|
31109
|
+
if (!resolved) throw new Error("claudeSession.read: no cwd for this session");
|
|
31110
|
+
const cwd = assertPathAllowed(resolved, ctx.config.allowedRoots);
|
|
31111
|
+
const file2 = sessionFile(cwd, params.sessionId);
|
|
31112
|
+
if (!file2) return { found: false, records: [], omitted: 0 };
|
|
31113
|
+
const links = /* @__PURE__ */ new Map();
|
|
31114
|
+
let leaf = null;
|
|
31115
|
+
for await (const rec of records(file2)) {
|
|
31116
|
+
if (typeof rec.uuid !== "string") continue;
|
|
31117
|
+
const parent = typeof rec.parentUuid === "string" ? rec.parentUuid : typeof rec.logicalParentUuid === "string" ? rec.logicalParentUuid : null;
|
|
31118
|
+
const content = isContent(rec);
|
|
31119
|
+
links.set(rec.uuid, { parent, content });
|
|
31120
|
+
if (content && rec.type !== "system") leaf = rec.uuid;
|
|
31121
|
+
}
|
|
31122
|
+
const branch = [];
|
|
31123
|
+
const seen = /* @__PURE__ */ new Set();
|
|
31124
|
+
for (let at = leaf; at && !seen.has(at); at = links.get(at)?.parent ?? null) {
|
|
31125
|
+
seen.add(at);
|
|
31126
|
+
if (links.get(at)?.content) branch.push(at);
|
|
31127
|
+
}
|
|
31128
|
+
branch.reverse();
|
|
31129
|
+
const wanted = new Set(branch.slice(-params.maxRecords));
|
|
31130
|
+
const byUuid = /* @__PURE__ */ new Map();
|
|
31131
|
+
for await (const rec of records(file2)) {
|
|
31132
|
+
if (typeof rec.uuid === "string" && wanted.has(rec.uuid)) byUuid.set(rec.uuid, shortened(rec));
|
|
31133
|
+
}
|
|
31134
|
+
const picked = [];
|
|
31135
|
+
let bytes = 0;
|
|
31136
|
+
for (let i = branch.length - 1; i >= 0 && picked.length < params.maxRecords; i--) {
|
|
31137
|
+
const rec = byUuid.get(branch[i]);
|
|
31138
|
+
if (!rec) continue;
|
|
31139
|
+
const size = JSON.stringify(rec).length;
|
|
31140
|
+
if (bytes + size > params.maxBytes) break;
|
|
31141
|
+
bytes += size;
|
|
31142
|
+
picked.push(rec);
|
|
31143
|
+
}
|
|
31144
|
+
picked.reverse();
|
|
31145
|
+
return { found: true, records: picked, omitted: branch.length - picked.length };
|
|
31146
|
+
}
|
|
31147
|
+
return { [HubToComputerMethods.claudeSessionRead]: read };
|
|
31148
|
+
}
|
|
31149
|
+
|
|
30909
31150
|
// src/handlers/git.ts
|
|
30910
31151
|
var import_node_child_process7 = require("node:child_process");
|
|
30911
|
-
var
|
|
31152
|
+
var import_node_fs9 = require("node:fs");
|
|
30912
31153
|
var import_promises8 = require("node:fs/promises");
|
|
30913
|
-
var
|
|
31154
|
+
var import_node_path12 = require("node:path");
|
|
30914
31155
|
|
|
30915
31156
|
// src/handlers/exec.ts
|
|
30916
31157
|
var import_node_child_process6 = require("node:child_process");
|
|
@@ -30968,9 +31209,9 @@ var SETUP_SCRIPT_TIMEOUT_MS = 5 * 6e4;
|
|
|
30968
31209
|
function createGitHandlers(ctx) {
|
|
30969
31210
|
const allow = (candidate) => assertPathAllowed(candidate, ctx.config.allowedRoots);
|
|
30970
31211
|
async function isGitRepo(rawParams) {
|
|
30971
|
-
const { path:
|
|
30972
|
-
const repoPath = allow(
|
|
30973
|
-
if (!(0,
|
|
31212
|
+
const { path: path11 } = isGitRepoParams.parse(rawParams);
|
|
31213
|
+
const repoPath = allow(path11);
|
|
31214
|
+
if (!(0, import_node_fs9.existsSync)(repoPath)) return { isGitRepo: false };
|
|
30974
31215
|
const result = await execCapture("git", ["rev-parse", "--git-dir"], { cwd: repoPath });
|
|
30975
31216
|
if (result.spawnError) throw new Error(`Could not start git: ${result.spawnError}`);
|
|
30976
31217
|
return { isGitRepo: result.status === 0 };
|
|
@@ -31003,7 +31244,7 @@ function createGitHandlers(ctx) {
|
|
|
31003
31244
|
try {
|
|
31004
31245
|
await execGit(["worktree", "remove", worktreePath, "--force"], repoPath);
|
|
31005
31246
|
} catch (err) {
|
|
31006
|
-
if (!(0,
|
|
31247
|
+
if (!(0, import_node_fs9.existsSync)(worktreePath)) {
|
|
31007
31248
|
await execGit(["worktree", "prune"], repoPath);
|
|
31008
31249
|
} else {
|
|
31009
31250
|
throw err;
|
|
@@ -31031,13 +31272,13 @@ function createGitHandlers(ctx) {
|
|
|
31031
31272
|
const params = runWorktreeSetupScriptParams.parse(rawParams);
|
|
31032
31273
|
const worktreePath = allow(params.worktreePath);
|
|
31033
31274
|
const repoPath = allow(params.repoPath);
|
|
31034
|
-
const scriptPath = (0,
|
|
31035
|
-
if (!(0,
|
|
31275
|
+
const scriptPath = (0, import_node_path12.resolve)(worktreePath, SETUP_SCRIPT);
|
|
31276
|
+
if (!(0, import_node_fs9.existsSync)(scriptPath)) return Promise.resolve({ ran: false });
|
|
31036
31277
|
try {
|
|
31037
|
-
(0,
|
|
31278
|
+
(0, import_node_fs9.accessSync)(scriptPath, import_node_fs9.constants.X_OK);
|
|
31038
31279
|
} catch {
|
|
31039
31280
|
try {
|
|
31040
|
-
(0,
|
|
31281
|
+
(0, import_node_fs9.chmodSync)(scriptPath, 493);
|
|
31041
31282
|
} catch {
|
|
31042
31283
|
return Promise.resolve({ ran: false });
|
|
31043
31284
|
}
|
|
@@ -31088,19 +31329,19 @@ function createGitHandlers(ctx) {
|
|
|
31088
31329
|
} else {
|
|
31089
31330
|
relPaths = params.customPaths ?? [];
|
|
31090
31331
|
}
|
|
31091
|
-
const repoRoot = (0,
|
|
31092
|
-
const wtRoot = (0,
|
|
31332
|
+
const repoRoot = (0, import_node_path12.resolve)(repoPath);
|
|
31333
|
+
const wtRoot = (0, import_node_path12.resolve)(worktreePath);
|
|
31093
31334
|
let copied = 0;
|
|
31094
31335
|
for (const rel of relPaths) {
|
|
31095
|
-
const src = (0,
|
|
31096
|
-
const dest = (0,
|
|
31336
|
+
const src = (0, import_node_path12.resolve)(repoPath, rel);
|
|
31337
|
+
const dest = (0, import_node_path12.resolve)(worktreePath, rel);
|
|
31097
31338
|
if (!isInside2(src, repoRoot) || !isInside2(dest, wtRoot)) {
|
|
31098
31339
|
ctx.log("copyIgnoredFiles skipped traversal", { rel });
|
|
31099
31340
|
continue;
|
|
31100
31341
|
}
|
|
31101
|
-
if (!(0,
|
|
31342
|
+
if (!(0, import_node_fs9.existsSync)(src)) continue;
|
|
31102
31343
|
try {
|
|
31103
|
-
await (0, import_promises8.mkdir)((0,
|
|
31344
|
+
await (0, import_promises8.mkdir)((0, import_node_path12.dirname)(dest), { recursive: true });
|
|
31104
31345
|
await (0, import_promises8.cp)(src, dest, { recursive: true, verbatimSymlinks: true });
|
|
31105
31346
|
copied += 1;
|
|
31106
31347
|
} catch (err) {
|
|
@@ -31119,12 +31360,13 @@ function createGitHandlers(ctx) {
|
|
|
31119
31360
|
};
|
|
31120
31361
|
}
|
|
31121
31362
|
function isInside2(child, root) {
|
|
31122
|
-
const c = (0,
|
|
31123
|
-
return c === root || c.startsWith(root +
|
|
31363
|
+
const c = (0, import_node_path12.resolve)(child);
|
|
31364
|
+
return c === root || c.startsWith(root + import_node_path12.sep);
|
|
31124
31365
|
}
|
|
31125
31366
|
|
|
31126
31367
|
// src/handlers/proc.ts
|
|
31127
31368
|
var import_node_child_process8 = require("node:child_process");
|
|
31369
|
+
var import_node_string_decoder = require("node:string_decoder");
|
|
31128
31370
|
|
|
31129
31371
|
// src/exit-tombstones.ts
|
|
31130
31372
|
var TOMBSTONE_TTL_MS = 10 * 6e4;
|
|
@@ -31223,6 +31465,153 @@ var RingBuffer = class {
|
|
|
31223
31465
|
}
|
|
31224
31466
|
};
|
|
31225
31467
|
|
|
31468
|
+
// src/spawn-admission.ts
|
|
31469
|
+
var import_node_os8 = require("node:os");
|
|
31470
|
+
var DEFAULT_START_CAP_MS = 5e3;
|
|
31471
|
+
var DEFAULT_WARM_QUIET_MS = 3e3;
|
|
31472
|
+
function defaultAdmissionConcurrency(cores = (0, import_node_os8.availableParallelism)()) {
|
|
31473
|
+
return Math.max(2, Math.min(4, Math.floor(cores / 2)));
|
|
31474
|
+
}
|
|
31475
|
+
var LANE_RANK = { foreground: 0, background: 1, warm: 2 };
|
|
31476
|
+
function createSpawnAdmission(opts = {}) {
|
|
31477
|
+
const concurrency = Math.max(1, opts.concurrency ?? defaultAdmissionConcurrency());
|
|
31478
|
+
const startCapMs = opts.startCapMs ?? DEFAULT_START_CAP_MS;
|
|
31479
|
+
const warmQuietMs = opts.warmQuietMs ?? DEFAULT_WARM_QUIET_MS;
|
|
31480
|
+
const now = opts.now ?? Date.now;
|
|
31481
|
+
const setTimer = opts.setTimer ?? ((fn, ms) => {
|
|
31482
|
+
const t2 = setTimeout(fn, ms);
|
|
31483
|
+
t2.unref?.();
|
|
31484
|
+
return t2;
|
|
31485
|
+
});
|
|
31486
|
+
const clearTimer = opts.clearTimer ?? ((h) => clearTimeout(h));
|
|
31487
|
+
const queue = [];
|
|
31488
|
+
const active = /* @__PURE__ */ new Set();
|
|
31489
|
+
let arrivals = 0;
|
|
31490
|
+
let promotions = 0;
|
|
31491
|
+
let lastAgentActivity = Number.NEGATIVE_INFINITY;
|
|
31492
|
+
let warmRetry = null;
|
|
31493
|
+
let pumping = false;
|
|
31494
|
+
let pumpAgain = false;
|
|
31495
|
+
const activeAgents = () => [...active].filter((s) => !s.warm).length;
|
|
31496
|
+
const activeWarm = () => [...active].filter((s) => s.warm).length;
|
|
31497
|
+
function next() {
|
|
31498
|
+
if (active.size >= concurrency || queue.length === 0) return null;
|
|
31499
|
+
let best = null;
|
|
31500
|
+
for (const t2 of queue) {
|
|
31501
|
+
if (!best || LANE_RANK[t2.lane] < LANE_RANK[best.lane] || t2.lane === best.lane && t2.order < best.order) {
|
|
31502
|
+
best = t2;
|
|
31503
|
+
}
|
|
31504
|
+
}
|
|
31505
|
+
if (!best || best.lane !== "warm") return best;
|
|
31506
|
+
if (activeAgents() > 0 || activeWarm() > 0) return null;
|
|
31507
|
+
const quietLeft = lastAgentActivity + warmQuietMs - now();
|
|
31508
|
+
if (quietLeft > 0) {
|
|
31509
|
+
if (warmRetry === null) {
|
|
31510
|
+
warmRetry = setTimer(() => {
|
|
31511
|
+
warmRetry = null;
|
|
31512
|
+
pump();
|
|
31513
|
+
}, quietLeft);
|
|
31514
|
+
}
|
|
31515
|
+
return null;
|
|
31516
|
+
}
|
|
31517
|
+
return best;
|
|
31518
|
+
}
|
|
31519
|
+
function admit(ticket) {
|
|
31520
|
+
queue.splice(queue.indexOf(ticket), 1);
|
|
31521
|
+
const warm = ticket.lane === "warm";
|
|
31522
|
+
const held = { warm, released: false, cap: null };
|
|
31523
|
+
const release = () => {
|
|
31524
|
+
if (held.released) return;
|
|
31525
|
+
held.released = true;
|
|
31526
|
+
clearTimer(held.cap);
|
|
31527
|
+
active.delete(held);
|
|
31528
|
+
if (!warm) lastAgentActivity = now();
|
|
31529
|
+
pump();
|
|
31530
|
+
};
|
|
31531
|
+
held.cap = setTimer(release, startCapMs);
|
|
31532
|
+
active.add(held);
|
|
31533
|
+
try {
|
|
31534
|
+
ticket.start({ release });
|
|
31535
|
+
} catch {
|
|
31536
|
+
release();
|
|
31537
|
+
}
|
|
31538
|
+
}
|
|
31539
|
+
function pump() {
|
|
31540
|
+
if (pumping) {
|
|
31541
|
+
pumpAgain = true;
|
|
31542
|
+
return;
|
|
31543
|
+
}
|
|
31544
|
+
pumping = true;
|
|
31545
|
+
try {
|
|
31546
|
+
do {
|
|
31547
|
+
pumpAgain = false;
|
|
31548
|
+
for (let t2 = next(); t2; t2 = next()) admit(t2);
|
|
31549
|
+
} while (pumpAgain);
|
|
31550
|
+
} finally {
|
|
31551
|
+
pumping = false;
|
|
31552
|
+
}
|
|
31553
|
+
}
|
|
31554
|
+
return {
|
|
31555
|
+
enqueue(lane, start) {
|
|
31556
|
+
const ticket = { lane, order: ++arrivals, start };
|
|
31557
|
+
queue.push(ticket);
|
|
31558
|
+
if (lane !== "warm") lastAgentActivity = now();
|
|
31559
|
+
pump();
|
|
31560
|
+
return ticket;
|
|
31561
|
+
},
|
|
31562
|
+
cancel(ticket) {
|
|
31563
|
+
const i = queue.indexOf(ticket);
|
|
31564
|
+
if (i < 0) return false;
|
|
31565
|
+
queue.splice(i, 1);
|
|
31566
|
+
pump();
|
|
31567
|
+
return true;
|
|
31568
|
+
},
|
|
31569
|
+
prioritize(ticket) {
|
|
31570
|
+
const t2 = ticket;
|
|
31571
|
+
if (!queue.includes(t2)) return false;
|
|
31572
|
+
t2.lane = "foreground";
|
|
31573
|
+
t2.order = -++promotions;
|
|
31574
|
+
pump();
|
|
31575
|
+
return true;
|
|
31576
|
+
},
|
|
31577
|
+
isQueued(ticket) {
|
|
31578
|
+
return queue.includes(ticket);
|
|
31579
|
+
},
|
|
31580
|
+
stats() {
|
|
31581
|
+
return { queued: queue.length, active: active.size, concurrency };
|
|
31582
|
+
}
|
|
31583
|
+
};
|
|
31584
|
+
}
|
|
31585
|
+
|
|
31586
|
+
// src/handlers/resolve-command.ts
|
|
31587
|
+
var import_node_fs10 = require("node:fs");
|
|
31588
|
+
var import_node_path13 = require("node:path");
|
|
31589
|
+
function isExecutableFile(file2) {
|
|
31590
|
+
try {
|
|
31591
|
+
if (!(0, import_node_fs10.statSync)(file2).isFile()) return false;
|
|
31592
|
+
if (process.platform !== "win32") (0, import_node_fs10.accessSync)(file2, import_node_fs10.constants.X_OK);
|
|
31593
|
+
return true;
|
|
31594
|
+
} catch {
|
|
31595
|
+
return false;
|
|
31596
|
+
}
|
|
31597
|
+
}
|
|
31598
|
+
function resolveCommand(command, env, cwd) {
|
|
31599
|
+
const suffixes = process.platform === "win32" ? ["", ...(env.PATHEXT ?? process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";")] : [""];
|
|
31600
|
+
const hasDir = command.includes("/") || process.platform === "win32" && command.includes("\\");
|
|
31601
|
+
if (hasDir) {
|
|
31602
|
+
const base = (0, import_node_path13.isAbsolute)(command) ? command : (0, import_node_path13.join)(cwd ?? process.cwd(), command);
|
|
31603
|
+
return suffixes.map((s) => base + s).find(isExecutableFile) ?? null;
|
|
31604
|
+
}
|
|
31605
|
+
for (const dir of (env.PATH ?? env.Path ?? "").split(import_node_path13.delimiter)) {
|
|
31606
|
+
if (!dir) continue;
|
|
31607
|
+
for (const suffix of suffixes) {
|
|
31608
|
+
const candidate = (0, import_node_path13.join)(dir, command + suffix);
|
|
31609
|
+
if (isExecutableFile(candidate)) return candidate;
|
|
31610
|
+
}
|
|
31611
|
+
}
|
|
31612
|
+
return null;
|
|
31613
|
+
}
|
|
31614
|
+
|
|
31226
31615
|
// src/handlers/spawn-env.ts
|
|
31227
31616
|
function buildSpawnEnv(ctx, overrides) {
|
|
31228
31617
|
const merged = overrides ? { ...sanitizeSpawnEnv(process.env), ...overrides } : sanitizeSpawnEnv(process.env);
|
|
@@ -31231,6 +31620,9 @@ function buildSpawnEnv(ctx, overrides) {
|
|
|
31231
31620
|
delete merged.SLAYZONE_HUB_TOKEN;
|
|
31232
31621
|
}
|
|
31233
31622
|
if (ctx.hubAddress) merged.SLAYZONE_HUB_ADDRESS = ctx.hubAddress;
|
|
31623
|
+
if (ctx.config.binOverrideDir) {
|
|
31624
|
+
merged.PATH = mergePathLists(ctx.config.binOverrideDir, merged.PATH);
|
|
31625
|
+
}
|
|
31234
31626
|
return merged;
|
|
31235
31627
|
}
|
|
31236
31628
|
|
|
@@ -31247,14 +31639,67 @@ var ProcNotifications = {
|
|
|
31247
31639
|
procData: ComputerNotificationMethods.procData,
|
|
31248
31640
|
procExit: ComputerNotificationMethods.procExit
|
|
31249
31641
|
};
|
|
31250
|
-
|
|
31642
|
+
var WRITE_ID_MEMORY = 256;
|
|
31643
|
+
function refuse2(reason, message, data = {}) {
|
|
31644
|
+
return new RpcError(ComputerTransportErrorCodes.refusedByComputer, message, {
|
|
31645
|
+
reason,
|
|
31646
|
+
...data
|
|
31647
|
+
});
|
|
31648
|
+
}
|
|
31649
|
+
function createProcHandlers(ctx, getProjectPaths, options = {}) {
|
|
31251
31650
|
const procs = /* @__PURE__ */ new Map();
|
|
31252
31651
|
const tombstones = new ExitTombstones();
|
|
31652
|
+
const admission = options.admission ?? createSpawnAdmission();
|
|
31653
|
+
const queued = /* @__PURE__ */ new Map();
|
|
31253
31654
|
function killTree(child, signal = "SIGTERM") {
|
|
31254
31655
|
if (typeof child.pid === "number") killPidTree(child.pid, signal);
|
|
31255
31656
|
}
|
|
31657
|
+
function releaseSlot(session) {
|
|
31658
|
+
const slot = session.slot;
|
|
31659
|
+
session.slot = null;
|
|
31660
|
+
slot?.release();
|
|
31661
|
+
}
|
|
31256
31662
|
function procSpawn(rawParams) {
|
|
31257
31663
|
const params = procSpawnParamsSchema.parse(rawParams);
|
|
31664
|
+
if (!params.admission) return startProc(params, null);
|
|
31665
|
+
const prior = queued.get(params.sessionId);
|
|
31666
|
+
if (prior && params.spawnId !== void 0 && prior.spawnId === params.spawnId) {
|
|
31667
|
+
return prior.promise;
|
|
31668
|
+
}
|
|
31669
|
+
let resolve9;
|
|
31670
|
+
let reject;
|
|
31671
|
+
const promise2 = new Promise((res, rej) => {
|
|
31672
|
+
resolve9 = res;
|
|
31673
|
+
reject = rej;
|
|
31674
|
+
});
|
|
31675
|
+
const item = {
|
|
31676
|
+
...params.spawnId !== void 0 ? { spawnId: params.spawnId } : {},
|
|
31677
|
+
ticket: void 0,
|
|
31678
|
+
promise: promise2,
|
|
31679
|
+
resolve: resolve9,
|
|
31680
|
+
reject
|
|
31681
|
+
};
|
|
31682
|
+
if (prior) {
|
|
31683
|
+
admission.cancel(prior.ticket);
|
|
31684
|
+
prior.resolve(promise2);
|
|
31685
|
+
}
|
|
31686
|
+
queued.set(params.sessionId, item);
|
|
31687
|
+
item.ticket = admission.enqueue(params.admission, (slot) => {
|
|
31688
|
+
if (queued.get(params.sessionId) !== item) {
|
|
31689
|
+
slot.release();
|
|
31690
|
+
return;
|
|
31691
|
+
}
|
|
31692
|
+
queued.delete(params.sessionId);
|
|
31693
|
+
try {
|
|
31694
|
+
item.resolve(startProc(params, slot));
|
|
31695
|
+
} catch (err) {
|
|
31696
|
+
slot.release();
|
|
31697
|
+
item.reject(err);
|
|
31698
|
+
}
|
|
31699
|
+
});
|
|
31700
|
+
return promise2;
|
|
31701
|
+
}
|
|
31702
|
+
function startProc(params, slot) {
|
|
31258
31703
|
if (params.spawnId !== void 0) {
|
|
31259
31704
|
const live = procs.get(params.sessionId);
|
|
31260
31705
|
if (live && live.spawnId === params.spawnId) return { pid: live.child.pid ?? null };
|
|
@@ -31264,17 +31709,29 @@ function createProcHandlers(ctx, getProjectPaths) {
|
|
|
31264
31709
|
);
|
|
31265
31710
|
}
|
|
31266
31711
|
}
|
|
31267
|
-
|
|
31712
|
+
let resolved = params.cwd || void 0;
|
|
31713
|
+
if (!resolved && params.projectId) {
|
|
31714
|
+
resolved = getProjectPaths?.()?.get(params.projectId)?.path;
|
|
31715
|
+
if (!resolved) throw projectNotPlacedError(params.projectId);
|
|
31716
|
+
}
|
|
31268
31717
|
const cwd = spawnCwd(resolved, ctx.config.allowedRoots);
|
|
31269
31718
|
const existing = procs.get(params.sessionId);
|
|
31270
31719
|
if (existing) {
|
|
31271
31720
|
killTree(existing.child);
|
|
31272
31721
|
procs.delete(params.sessionId);
|
|
31273
31722
|
}
|
|
31723
|
+
const env = buildSpawnEnv(ctx, params.env);
|
|
31724
|
+
if (!params.shell && resolveCommand(params.command, env, cwd) === null) {
|
|
31725
|
+
throw refuse2(
|
|
31726
|
+
ProcRefusalReasons.binaryNotFound,
|
|
31727
|
+
`${params.command} was not found on this computer's PATH`,
|
|
31728
|
+
{ binary: params.command }
|
|
31729
|
+
);
|
|
31730
|
+
}
|
|
31274
31731
|
const invocation = params.shell ? buildShellInvocation(params.command) : { file: params.command, args: params.args ?? [] };
|
|
31275
31732
|
const child = (0, import_node_child_process8.spawn)(invocation.file, invocation.args, {
|
|
31276
31733
|
...cwd ? { cwd } : {},
|
|
31277
|
-
env
|
|
31734
|
+
env,
|
|
31278
31735
|
// stdin PIPED (was 'ignore') so `proc.write` can reach the child.
|
|
31279
31736
|
stdio: ["pipe", "pipe", "pipe"],
|
|
31280
31737
|
// Its own process group, so a kill reaches everything it started (`pnpm dev`
|
|
@@ -31285,14 +31742,24 @@ function createProcHandlers(ctx, getProjectPaths) {
|
|
|
31285
31742
|
const session = {
|
|
31286
31743
|
child,
|
|
31287
31744
|
buffer,
|
|
31288
|
-
...params.spawnId !== void 0 ? { spawnId: params.spawnId } : {}
|
|
31745
|
+
...params.spawnId !== void 0 ? { spawnId: params.spawnId } : {},
|
|
31746
|
+
stdinBroken: null,
|
|
31747
|
+
writeIds: [],
|
|
31748
|
+
slot
|
|
31289
31749
|
};
|
|
31290
31750
|
procs.set(params.sessionId, session);
|
|
31751
|
+
const tag = params.spawnId !== void 0 ? { spawnId: params.spawnId } : {};
|
|
31752
|
+
child.stdin?.on("error", (err) => {
|
|
31753
|
+
session.stdinBroken = err.message;
|
|
31754
|
+
ctx.log("proc stdin error", { sessionId: params.sessionId, error: err.message });
|
|
31755
|
+
});
|
|
31291
31756
|
const settle2 = (payload) => {
|
|
31757
|
+
releaseSlot(session);
|
|
31292
31758
|
if (procs.get(params.sessionId) !== session) return;
|
|
31293
31759
|
procs.delete(params.sessionId);
|
|
31294
31760
|
const delivered = ctx.dialer.notify(ProcNotifications.procExit, {
|
|
31295
31761
|
sessionId: params.sessionId,
|
|
31762
|
+
...tag,
|
|
31296
31763
|
...payload
|
|
31297
31764
|
});
|
|
31298
31765
|
tombstones.add(params.sessionId, {
|
|
@@ -31304,26 +31771,39 @@ function createProcHandlers(ctx, getProjectPaths) {
|
|
|
31304
31771
|
...delivered ? {} : { buffer: session.buffer }
|
|
31305
31772
|
});
|
|
31306
31773
|
};
|
|
31307
|
-
|
|
31308
|
-
|
|
31309
|
-
|
|
31774
|
+
const stdoutDecoder = new import_node_string_decoder.StringDecoder("utf8");
|
|
31775
|
+
const stderrDecoder = new import_node_string_decoder.StringDecoder("utf8");
|
|
31776
|
+
const emitStdout = (data) => {
|
|
31777
|
+
if (!data || procs.get(params.sessionId) !== session) return;
|
|
31310
31778
|
const seq = buffer.append(data);
|
|
31311
31779
|
ctx.dialer.notify(ProcNotifications.procData, {
|
|
31312
31780
|
sessionId: params.sessionId,
|
|
31781
|
+
...tag,
|
|
31313
31782
|
seq,
|
|
31314
31783
|
stream: "stdout",
|
|
31315
31784
|
data
|
|
31316
31785
|
});
|
|
31317
|
-
}
|
|
31318
|
-
|
|
31319
|
-
if (procs.get(params.sessionId) !== session) return;
|
|
31786
|
+
};
|
|
31787
|
+
const emitStderr = (data) => {
|
|
31788
|
+
if (!data || procs.get(params.sessionId) !== session) return;
|
|
31320
31789
|
ctx.dialer.notify(ProcNotifications.procData, {
|
|
31321
31790
|
sessionId: params.sessionId,
|
|
31791
|
+
...tag,
|
|
31322
31792
|
stream: "stderr",
|
|
31323
|
-
data
|
|
31793
|
+
data
|
|
31324
31794
|
});
|
|
31795
|
+
};
|
|
31796
|
+
child.stdout?.on("data", (d) => {
|
|
31797
|
+
releaseSlot(session);
|
|
31798
|
+
emitStdout(stdoutDecoder.write(d));
|
|
31799
|
+
});
|
|
31800
|
+
child.stderr?.on("data", (d) => {
|
|
31801
|
+
releaseSlot(session);
|
|
31802
|
+
emitStderr(stderrDecoder.write(d));
|
|
31325
31803
|
});
|
|
31326
31804
|
child.on("close", (code, signal) => {
|
|
31805
|
+
emitStdout(stdoutDecoder.end());
|
|
31806
|
+
emitStderr(stderrDecoder.end());
|
|
31327
31807
|
settle2({
|
|
31328
31808
|
exitCode: typeof code === "number" ? code : null,
|
|
31329
31809
|
signal: signal != null ? String(signal) : null
|
|
@@ -31346,6 +31826,10 @@ function createProcHandlers(ctx, getProjectPaths) {
|
|
|
31346
31826
|
ctx.log("proc kill on unknown session", { sessionId: params.sessionId });
|
|
31347
31827
|
return { ok: true };
|
|
31348
31828
|
}
|
|
31829
|
+
if (params.spawnId !== void 0 && session.spawnId !== params.spawnId) {
|
|
31830
|
+
ctx.log("proc kill for a replaced attempt", { sessionId: params.sessionId });
|
|
31831
|
+
return { ok: true };
|
|
31832
|
+
}
|
|
31349
31833
|
killTree(session.child, params.signal ?? "SIGTERM");
|
|
31350
31834
|
return { ok: true };
|
|
31351
31835
|
}
|
|
@@ -31354,14 +31838,55 @@ function createProcHandlers(ctx, getProjectPaths) {
|
|
|
31354
31838
|
const session = procs.get(params.sessionId);
|
|
31355
31839
|
if (!session) {
|
|
31356
31840
|
ctx.log("proc write on unknown session", { sessionId: params.sessionId });
|
|
31357
|
-
return
|
|
31841
|
+
return Promise.reject(
|
|
31842
|
+
refuse2(ProcRefusalReasons.unknownSession, `proc.write: no process ${params.sessionId}`)
|
|
31843
|
+
);
|
|
31358
31844
|
}
|
|
31359
|
-
|
|
31360
|
-
|
|
31361
|
-
|
|
31362
|
-
|
|
31845
|
+
if (params.spawnId !== void 0 && session.spawnId !== params.spawnId) {
|
|
31846
|
+
return Promise.reject(
|
|
31847
|
+
refuse2(
|
|
31848
|
+
ProcRefusalReasons.staleSpawn,
|
|
31849
|
+
`proc.write: ${params.sessionId} now runs a different process`
|
|
31850
|
+
)
|
|
31851
|
+
);
|
|
31363
31852
|
}
|
|
31364
|
-
|
|
31853
|
+
if (params.writeId !== void 0 && session.writeIds.includes(params.writeId)) {
|
|
31854
|
+
return Promise.resolve({ ok: true, delivered: true, duplicate: true });
|
|
31855
|
+
}
|
|
31856
|
+
const stdin2 = session.child.stdin;
|
|
31857
|
+
if (!stdin2 || session.stdinBroken !== null || stdin2.destroyed || stdin2.writableEnded) {
|
|
31858
|
+
return Promise.reject(
|
|
31859
|
+
refuse2(
|
|
31860
|
+
ProcRefusalReasons.stdinClosed,
|
|
31861
|
+
`proc.write: ${params.sessionId} stdin is closed${session.stdinBroken ? ` (${session.stdinBroken})` : ""}`
|
|
31862
|
+
)
|
|
31863
|
+
);
|
|
31864
|
+
}
|
|
31865
|
+
if (params.writeId !== void 0) {
|
|
31866
|
+
session.writeIds.push(params.writeId);
|
|
31867
|
+
if (session.writeIds.length > WRITE_ID_MEMORY) session.writeIds.shift();
|
|
31868
|
+
}
|
|
31869
|
+
return new Promise((resolve9, reject) => {
|
|
31870
|
+
const fail = (err) => {
|
|
31871
|
+
if (params.writeId !== void 0) {
|
|
31872
|
+
session.writeIds = session.writeIds.filter((id) => id !== params.writeId);
|
|
31873
|
+
}
|
|
31874
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
31875
|
+
session.stdinBroken ??= message;
|
|
31876
|
+
ctx.log("proc write failed", { sessionId: params.sessionId, error: message });
|
|
31877
|
+
reject(
|
|
31878
|
+
refuse2(ProcRefusalReasons.stdinClosed, `proc.write: ${params.sessionId}: ${message}`)
|
|
31879
|
+
);
|
|
31880
|
+
};
|
|
31881
|
+
try {
|
|
31882
|
+
stdin2.write(
|
|
31883
|
+
params.data,
|
|
31884
|
+
(err) => err ? fail(err) : resolve9({ ok: true, delivered: true })
|
|
31885
|
+
);
|
|
31886
|
+
} catch (err) {
|
|
31887
|
+
fail(err);
|
|
31888
|
+
}
|
|
31889
|
+
});
|
|
31365
31890
|
}
|
|
31366
31891
|
function procGetBufferSince(rawParams) {
|
|
31367
31892
|
const params = procGetBufferSinceParamsSchema.parse(rawParams);
|
|
@@ -31383,7 +31908,13 @@ function createProcHandlers(ctx, getProjectPaths) {
|
|
|
31383
31908
|
return { sessions, exited: tombstones.list() };
|
|
31384
31909
|
}
|
|
31385
31910
|
function disposeAll() {
|
|
31911
|
+
for (const item of queued.values()) {
|
|
31912
|
+
admission.cancel(item.ticket);
|
|
31913
|
+
item.reject(new Error("computer shutting down"));
|
|
31914
|
+
}
|
|
31915
|
+
queued.clear();
|
|
31386
31916
|
for (const [sessionId, session] of procs) {
|
|
31917
|
+
releaseSlot(session);
|
|
31387
31918
|
killTree(session.child);
|
|
31388
31919
|
ctx.log("proc disposed on shutdown", { sessionId });
|
|
31389
31920
|
}
|
|
@@ -31400,7 +31931,7 @@ function createProcHandlers(ctx, getProjectPaths) {
|
|
|
31400
31931
|
}
|
|
31401
31932
|
|
|
31402
31933
|
// src/handlers/project.ts
|
|
31403
|
-
var
|
|
31934
|
+
var import_node_fs11 = require("node:fs");
|
|
31404
31935
|
function createProjectHandlers(ctx, getStore) {
|
|
31405
31936
|
const allow = (candidate) => assertPathAllowed(candidate, ctx.config.allowedRoots);
|
|
31406
31937
|
const store = () => {
|
|
@@ -31412,11 +31943,11 @@ function createProjectHandlers(ctx, getStore) {
|
|
|
31412
31943
|
const { projectId } = projectResolvePathParamsSchema.parse(rawParams);
|
|
31413
31944
|
const entry = store().get(projectId);
|
|
31414
31945
|
if (!entry) return { path: null };
|
|
31415
|
-
return { path: entry.path, exists: (0,
|
|
31946
|
+
return { path: entry.path, exists: (0, import_node_fs11.existsSync)(entry.path) };
|
|
31416
31947
|
}
|
|
31417
31948
|
async function setPath(rawParams) {
|
|
31418
|
-
const { projectId, path:
|
|
31419
|
-
const resolved = allow(
|
|
31949
|
+
const { projectId, path: path11 } = projectSetPathParamsSchema.parse(rawParams);
|
|
31950
|
+
const resolved = allow(path11);
|
|
31420
31951
|
const entry = await store().set(projectId, resolved);
|
|
31421
31952
|
ctx.log("project path recorded", { projectId, path: entry.path });
|
|
31422
31953
|
return { path: entry.path };
|
|
@@ -31433,7 +31964,7 @@ function createProjectHandlers(ctx, getStore) {
|
|
|
31433
31964
|
projects: store().list().map((e) => ({
|
|
31434
31965
|
projectId: e.projectId,
|
|
31435
31966
|
path: e.path,
|
|
31436
|
-
exists: (0,
|
|
31967
|
+
exists: (0, import_node_fs11.existsSync)(e.path)
|
|
31437
31968
|
}))
|
|
31438
31969
|
};
|
|
31439
31970
|
}
|
|
@@ -31446,8 +31977,77 @@ function createProjectHandlers(ctx, getStore) {
|
|
|
31446
31977
|
}
|
|
31447
31978
|
|
|
31448
31979
|
// src/handlers/pty.ts
|
|
31980
|
+
var import_node_module = require("node:module");
|
|
31981
|
+
var path8 = __toESM(require("node:path"), 1);
|
|
31449
31982
|
var pty = __toESM(require("node-pty"), 1);
|
|
31450
31983
|
|
|
31984
|
+
// ../../shared/platform/src/node-pty-install.ts
|
|
31985
|
+
var import_node_fs12 = __toESM(require("node:fs"), 1);
|
|
31986
|
+
var import_node_path14 = __toESM(require("node:path"), 1);
|
|
31987
|
+
function pendingBuildsFrom(modulesYaml) {
|
|
31988
|
+
try {
|
|
31989
|
+
const parsed = JSON.parse(modulesYaml);
|
|
31990
|
+
const pending = parsed?.pendingBuilds;
|
|
31991
|
+
return Array.isArray(pending) && pending.every((p) => typeof p === "string") ? pending : null;
|
|
31992
|
+
} catch {
|
|
31993
|
+
return null;
|
|
31994
|
+
}
|
|
31995
|
+
}
|
|
31996
|
+
function spawnHelperCandidates(nodePtyDir2, platform3 = process.platform, arch = process.arch) {
|
|
31997
|
+
if (platform3 === "win32") return [];
|
|
31998
|
+
return ["build/Release", "build/Debug", `prebuilds/${platform3}-${arch}`].map(
|
|
31999
|
+
(dir) => import_node_path14.default.join(nodePtyDir2, dir, "spawn-helper")
|
|
32000
|
+
);
|
|
32001
|
+
}
|
|
32002
|
+
function unpackedAsarPath(file2) {
|
|
32003
|
+
return file2.replace(/app\.asar(?!\.unpacked)/, "app.asar.unpacked").replace(/node_modules\.asar(?!\.unpacked)/, "node_modules.asar.unpacked");
|
|
32004
|
+
}
|
|
32005
|
+
var shellQuote = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
32006
|
+
function installProblems(state) {
|
|
32007
|
+
const problems = [];
|
|
32008
|
+
if (state.repoRoot !== null && state.pendingBuilds && state.pendingBuilds.length > 0) {
|
|
32009
|
+
problems.push({
|
|
32010
|
+
check: "Install scripts ran",
|
|
32011
|
+
detail: `pnpm skipped the install scripts of: ${state.pendingBuilds.join(", ")}.`,
|
|
32012
|
+
fix: `cd ${shellQuote(state.repoRoot)} && pnpm rebuild --pending`
|
|
32013
|
+
});
|
|
32014
|
+
}
|
|
32015
|
+
const broken = state.helpers.filter((h) => !h.executable).map((h) => h.path);
|
|
32016
|
+
if (broken.length > 0) {
|
|
32017
|
+
problems.push({
|
|
32018
|
+
check: "spawn-helper executable",
|
|
32019
|
+
detail: `${broken.join(", ")} ${broken.length === 1 ? "is" : "are"} not executable, so every terminal fails to start ("posix_spawnp failed").`,
|
|
32020
|
+
fix: `chmod +x ${broken.map(shellQuote).join(" ")}`
|
|
32021
|
+
});
|
|
32022
|
+
}
|
|
32023
|
+
return problems;
|
|
32024
|
+
}
|
|
32025
|
+
function readNodePtyInstall(nodePtyDir2) {
|
|
32026
|
+
const nodeModules = import_node_path14.default.dirname(nodePtyDir2);
|
|
32027
|
+
let pendingBuilds = null;
|
|
32028
|
+
let repoRoot = null;
|
|
32029
|
+
try {
|
|
32030
|
+
pendingBuilds = pendingBuildsFrom(
|
|
32031
|
+
import_node_fs12.default.readFileSync(import_node_path14.default.join(nodeModules, ".modules.yaml"), "utf8")
|
|
32032
|
+
);
|
|
32033
|
+
repoRoot = import_node_path14.default.dirname(nodeModules);
|
|
32034
|
+
} catch {
|
|
32035
|
+
}
|
|
32036
|
+
const helpers = spawnHelperCandidates(nodePtyDir2).map(unpackedAsarPath).filter((p) => import_node_fs12.default.existsSync(p)).map((p) => ({ path: p, executable: isExecutable(p) }));
|
|
32037
|
+
return { repoRoot, pendingBuilds, helpers };
|
|
32038
|
+
}
|
|
32039
|
+
function nodePtyInstallProblems(nodePtyDir2) {
|
|
32040
|
+
return installProblems(readNodePtyInstall(nodePtyDir2));
|
|
32041
|
+
}
|
|
32042
|
+
function isExecutable(file2) {
|
|
32043
|
+
try {
|
|
32044
|
+
import_node_fs12.default.accessSync(file2, import_node_fs12.default.constants.X_OK);
|
|
32045
|
+
return true;
|
|
32046
|
+
} catch {
|
|
32047
|
+
return false;
|
|
32048
|
+
}
|
|
32049
|
+
}
|
|
32050
|
+
|
|
31451
32051
|
// ../../shared/platform/src/startup-deadline.ts
|
|
31452
32052
|
function armStartupDeadline({
|
|
31453
32053
|
timeoutMs,
|
|
@@ -31515,7 +32115,7 @@ function matchLiveJobs(jobs, descendants, stdoutByPid) {
|
|
|
31515
32115
|
const alive = [];
|
|
31516
32116
|
for (const job of jobs) {
|
|
31517
32117
|
const outputFile = `/tasks/${job.id}.output`;
|
|
31518
|
-
const byOutput = job.kind === "shell" && [...outputs].some((
|
|
32118
|
+
const byOutput = job.kind === "shell" && [...outputs].some((path11) => path11.endsWith(outputFile));
|
|
31519
32119
|
const evalArg = job.command ? `eval ${claudeEvalArg(job.command)}` : null;
|
|
31520
32120
|
const byCommand = evalArg !== null && descendants.some((d) => d.args.includes(evalArg));
|
|
31521
32121
|
if (byOutput || byCommand) alive.push(job.id);
|
|
@@ -31529,7 +32129,7 @@ async function readStdoutPaths(pids) {
|
|
|
31529
32129
|
await Promise.all(
|
|
31530
32130
|
pids.map(
|
|
31531
32131
|
(pid2) => (0, import_promises9.readlink)(`/proc/${pid2}/fd/1`).then(
|
|
31532
|
-
(
|
|
32132
|
+
(path11) => void out.set(pid2, path11),
|
|
31533
32133
|
() => void 0
|
|
31534
32134
|
)
|
|
31535
32135
|
)
|
|
@@ -31564,141 +32164,26 @@ async function probeBackgroundJobs(rootPid, jobs) {
|
|
|
31564
32164
|
return matchLiveJobs(jobs, descendants, stdoutByPid);
|
|
31565
32165
|
}
|
|
31566
32166
|
|
|
31567
|
-
// src/spawn-admission.ts
|
|
31568
|
-
var import_node_os7 = require("node:os");
|
|
31569
|
-
var DEFAULT_START_CAP_MS = 5e3;
|
|
31570
|
-
var DEFAULT_WARM_QUIET_MS = 3e3;
|
|
31571
|
-
function defaultAdmissionConcurrency(cores = (0, import_node_os7.availableParallelism)()) {
|
|
31572
|
-
return Math.max(2, Math.min(4, Math.floor(cores / 2)));
|
|
31573
|
-
}
|
|
31574
|
-
var LANE_RANK = { foreground: 0, background: 1, warm: 2 };
|
|
31575
|
-
function createSpawnAdmission(opts = {}) {
|
|
31576
|
-
const concurrency = Math.max(1, opts.concurrency ?? defaultAdmissionConcurrency());
|
|
31577
|
-
const startCapMs = opts.startCapMs ?? DEFAULT_START_CAP_MS;
|
|
31578
|
-
const warmQuietMs = opts.warmQuietMs ?? DEFAULT_WARM_QUIET_MS;
|
|
31579
|
-
const now = opts.now ?? Date.now;
|
|
31580
|
-
const setTimer = opts.setTimer ?? ((fn, ms) => {
|
|
31581
|
-
const t2 = setTimeout(fn, ms);
|
|
31582
|
-
t2.unref?.();
|
|
31583
|
-
return t2;
|
|
31584
|
-
});
|
|
31585
|
-
const clearTimer = opts.clearTimer ?? ((h) => clearTimeout(h));
|
|
31586
|
-
const queue = [];
|
|
31587
|
-
const active = /* @__PURE__ */ new Set();
|
|
31588
|
-
let arrivals = 0;
|
|
31589
|
-
let promotions = 0;
|
|
31590
|
-
let lastAgentActivity = Number.NEGATIVE_INFINITY;
|
|
31591
|
-
let warmRetry = null;
|
|
31592
|
-
let pumping = false;
|
|
31593
|
-
let pumpAgain = false;
|
|
31594
|
-
const activeAgents = () => [...active].filter((s) => !s.warm).length;
|
|
31595
|
-
const activeWarm = () => [...active].filter((s) => s.warm).length;
|
|
31596
|
-
function next() {
|
|
31597
|
-
if (active.size >= concurrency || queue.length === 0) return null;
|
|
31598
|
-
let best = null;
|
|
31599
|
-
for (const t2 of queue) {
|
|
31600
|
-
if (!best || LANE_RANK[t2.lane] < LANE_RANK[best.lane] || t2.lane === best.lane && t2.order < best.order) {
|
|
31601
|
-
best = t2;
|
|
31602
|
-
}
|
|
31603
|
-
}
|
|
31604
|
-
if (!best || best.lane !== "warm") return best;
|
|
31605
|
-
if (activeAgents() > 0 || activeWarm() > 0) return null;
|
|
31606
|
-
const quietLeft = lastAgentActivity + warmQuietMs - now();
|
|
31607
|
-
if (quietLeft > 0) {
|
|
31608
|
-
if (warmRetry === null) {
|
|
31609
|
-
warmRetry = setTimer(() => {
|
|
31610
|
-
warmRetry = null;
|
|
31611
|
-
pump();
|
|
31612
|
-
}, quietLeft);
|
|
31613
|
-
}
|
|
31614
|
-
return null;
|
|
31615
|
-
}
|
|
31616
|
-
return best;
|
|
31617
|
-
}
|
|
31618
|
-
function admit(ticket) {
|
|
31619
|
-
queue.splice(queue.indexOf(ticket), 1);
|
|
31620
|
-
const warm = ticket.lane === "warm";
|
|
31621
|
-
const held = { warm, released: false, cap: null };
|
|
31622
|
-
const release = () => {
|
|
31623
|
-
if (held.released) return;
|
|
31624
|
-
held.released = true;
|
|
31625
|
-
clearTimer(held.cap);
|
|
31626
|
-
active.delete(held);
|
|
31627
|
-
if (!warm) lastAgentActivity = now();
|
|
31628
|
-
pump();
|
|
31629
|
-
};
|
|
31630
|
-
held.cap = setTimer(release, startCapMs);
|
|
31631
|
-
active.add(held);
|
|
31632
|
-
try {
|
|
31633
|
-
ticket.start({ release });
|
|
31634
|
-
} catch {
|
|
31635
|
-
release();
|
|
31636
|
-
}
|
|
31637
|
-
}
|
|
31638
|
-
function pump() {
|
|
31639
|
-
if (pumping) {
|
|
31640
|
-
pumpAgain = true;
|
|
31641
|
-
return;
|
|
31642
|
-
}
|
|
31643
|
-
pumping = true;
|
|
31644
|
-
try {
|
|
31645
|
-
do {
|
|
31646
|
-
pumpAgain = false;
|
|
31647
|
-
for (let t2 = next(); t2; t2 = next()) admit(t2);
|
|
31648
|
-
} while (pumpAgain);
|
|
31649
|
-
} finally {
|
|
31650
|
-
pumping = false;
|
|
31651
|
-
}
|
|
31652
|
-
}
|
|
31653
|
-
return {
|
|
31654
|
-
enqueue(lane, start) {
|
|
31655
|
-
const ticket = { lane, order: ++arrivals, start };
|
|
31656
|
-
queue.push(ticket);
|
|
31657
|
-
if (lane !== "warm") lastAgentActivity = now();
|
|
31658
|
-
pump();
|
|
31659
|
-
return ticket;
|
|
31660
|
-
},
|
|
31661
|
-
cancel(ticket) {
|
|
31662
|
-
const i = queue.indexOf(ticket);
|
|
31663
|
-
if (i < 0) return false;
|
|
31664
|
-
queue.splice(i, 1);
|
|
31665
|
-
pump();
|
|
31666
|
-
return true;
|
|
31667
|
-
},
|
|
31668
|
-
prioritize(ticket) {
|
|
31669
|
-
const t2 = ticket;
|
|
31670
|
-
if (!queue.includes(t2)) return false;
|
|
31671
|
-
t2.lane = "foreground";
|
|
31672
|
-
t2.order = -++promotions;
|
|
31673
|
-
pump();
|
|
31674
|
-
return true;
|
|
31675
|
-
},
|
|
31676
|
-
isQueued(ticket) {
|
|
31677
|
-
return queue.includes(ticket);
|
|
31678
|
-
},
|
|
31679
|
-
stats() {
|
|
31680
|
-
return { queued: queue.length, active: active.size, concurrency };
|
|
31681
|
-
}
|
|
31682
|
-
};
|
|
31683
|
-
}
|
|
31684
|
-
|
|
31685
32167
|
// src/handlers/pty.ts
|
|
31686
32168
|
var MAX_BUFFER_SIZE2 = 750 * 1024;
|
|
31687
32169
|
var STARTUP_KILL_REAP_MS = 2e3;
|
|
32170
|
+
function nodePtyDir() {
|
|
32171
|
+
const resolve9 = typeof require === "function" ? require.resolve : (0, import_node_module.createRequire)(process.argv[1] ?? path8.join(process.cwd(), "index.js")).resolve;
|
|
32172
|
+
return path8.dirname(resolve9("node-pty/package.json"));
|
|
32173
|
+
}
|
|
32174
|
+
var installProblemsOnDisk = () => nodePtyInstallProblems(nodePtyDir());
|
|
31688
32175
|
function createPtyHandlers(ctx, getProjectPaths, options = {}) {
|
|
31689
32176
|
const sessions = /* @__PURE__ */ new Map();
|
|
31690
32177
|
const tombstones = new ExitTombstones();
|
|
31691
32178
|
const admission = options.admission ?? createSpawnAdmission();
|
|
32179
|
+
const spawnPty = options.spawnPty ?? pty.spawn;
|
|
32180
|
+
const installProblems2 = options.nodePtyInstallProblems ?? installProblemsOnDisk;
|
|
31692
32181
|
const queued = /* @__PURE__ */ new Map();
|
|
31693
32182
|
function resolveCwd(opts) {
|
|
31694
32183
|
if (opts.cwd) return spawnCwd(opts.cwd, ctx.config.allowedRoots);
|
|
31695
32184
|
if (!opts.projectId) throw new Error("pty.spawn needs either cwd or projectId");
|
|
31696
32185
|
const entry = getProjectPaths?.()?.get(opts.projectId);
|
|
31697
|
-
if (!entry)
|
|
31698
|
-
throw new Error(
|
|
31699
|
-
`project ${opts.projectId} is not checked out on this computer \u2014 adopt a folder or enable remote git for it`
|
|
31700
|
-
);
|
|
31701
|
-
}
|
|
32186
|
+
if (!entry) throw projectNotPlacedError(opts.projectId);
|
|
31702
32187
|
return spawnCwd(entry.path, ctx.config.allowedRoots);
|
|
31703
32188
|
}
|
|
31704
32189
|
function spawnSession(id, opts) {
|
|
@@ -31713,13 +32198,18 @@ function createPtyHandlers(ctx, getProjectPaths, options = {}) {
|
|
|
31713
32198
|
}
|
|
31714
32199
|
sessions.delete(id);
|
|
31715
32200
|
}
|
|
31716
|
-
|
|
31717
|
-
|
|
31718
|
-
|
|
31719
|
-
|
|
31720
|
-
|
|
31721
|
-
|
|
31722
|
-
|
|
32201
|
+
let proc;
|
|
32202
|
+
try {
|
|
32203
|
+
proc = spawnPty(opts.command, opts.args ?? [], {
|
|
32204
|
+
name: "xterm-color",
|
|
32205
|
+
cwd,
|
|
32206
|
+
env: buildSpawnEnv(ctx, opts.env),
|
|
32207
|
+
cols: opts.cols ?? 80,
|
|
32208
|
+
rows: opts.rows ?? 24
|
|
32209
|
+
});
|
|
32210
|
+
} catch (err) {
|
|
32211
|
+
throw explainSpawnFailure(err);
|
|
32212
|
+
}
|
|
31723
32213
|
const buffer = new RingBuffer(MAX_BUFFER_SIZE2);
|
|
31724
32214
|
const session = {
|
|
31725
32215
|
proc,
|
|
@@ -31756,6 +32246,18 @@ function createPtyHandlers(ctx, getProjectPaths, options = {}) {
|
|
|
31756
32246
|
});
|
|
31757
32247
|
return session;
|
|
31758
32248
|
}
|
|
32249
|
+
function explainSpawnFailure(err) {
|
|
32250
|
+
const original = err instanceof Error ? err : new Error(String(err));
|
|
32251
|
+
let problems;
|
|
32252
|
+
try {
|
|
32253
|
+
problems = installProblems2();
|
|
32254
|
+
} catch {
|
|
32255
|
+
return original;
|
|
32256
|
+
}
|
|
32257
|
+
if (problems.length === 0) return original;
|
|
32258
|
+
const why = problems.map((p) => `${p.detail} Fix: ${p.fix}`).join(" ");
|
|
32259
|
+
return new Error(`${original.message} ${why}`, { cause: original });
|
|
32260
|
+
}
|
|
31759
32261
|
function reap(session, exitCode, signal) {
|
|
31760
32262
|
if (sessions.get(session.id) !== session) return;
|
|
31761
32263
|
sessions.delete(session.id);
|
|
@@ -31938,6 +32440,20 @@ function createPtyHandlers(ctx, getProjectPaths, options = {}) {
|
|
|
31938
32440
|
const alive = await probeBackgroundJobs(pid, params.jobs);
|
|
31939
32441
|
return alive === null ? { ok: true, supported: false, alive: [] } : { ok: true, supported: true, alive };
|
|
31940
32442
|
}
|
|
32443
|
+
async function doctor(rawParams) {
|
|
32444
|
+
const params = ptyDoctorParamsSchema.parse(rawParams);
|
|
32445
|
+
await options.pathReady;
|
|
32446
|
+
const env = buildSpawnEnv(ctx);
|
|
32447
|
+
const binaries = await Promise.all(
|
|
32448
|
+
params.binaries.map(async (binary) => ({ binary, path: await findOnPath(binary, env) }))
|
|
32449
|
+
);
|
|
32450
|
+
return {
|
|
32451
|
+
ok: true,
|
|
32452
|
+
problems: installProblems2(),
|
|
32453
|
+
shellExists: shellExists(params.shell),
|
|
32454
|
+
binaries
|
|
32455
|
+
};
|
|
32456
|
+
}
|
|
31941
32457
|
function dropQueued(reason) {
|
|
31942
32458
|
for (const id of [...queued.keys()]) cancelQueued(id, reason);
|
|
31943
32459
|
}
|
|
@@ -32117,6 +32633,7 @@ function createPtyHandlers(ctx, getProjectPaths, options = {}) {
|
|
|
32117
32633
|
[HubToComputerMethods.ptyList]: list,
|
|
32118
32634
|
[HubToComputerMethods.ptyPrioritize]: prioritize,
|
|
32119
32635
|
[HubToComputerMethods.ptyBackgroundJobs]: backgroundJobs,
|
|
32636
|
+
[HubToComputerMethods.ptyDoctor]: doctor,
|
|
32120
32637
|
[HubToComputerMethods.ptyWarmSpawn]: warmSpawn,
|
|
32121
32638
|
[HubToComputerMethods.ptyWarmAdopt]: warmAdopt,
|
|
32122
32639
|
[HubToComputerMethods.ptyWarmKill]: warmKill,
|
|
@@ -32126,19 +32643,19 @@ function createPtyHandlers(ctx, getProjectPaths, options = {}) {
|
|
|
32126
32643
|
}
|
|
32127
32644
|
|
|
32128
32645
|
// src/handlers/computer-config.ts
|
|
32129
|
-
var
|
|
32130
|
-
var
|
|
32646
|
+
var import_node_fs13 = require("node:fs");
|
|
32647
|
+
var import_node_path15 = require("node:path");
|
|
32131
32648
|
function canonicalRoots(roots) {
|
|
32132
32649
|
const applied = [];
|
|
32133
32650
|
const rejected = [];
|
|
32134
32651
|
for (const root of roots) {
|
|
32135
|
-
if (!(0,
|
|
32652
|
+
if (!(0, import_node_path15.isAbsolute)(root)) {
|
|
32136
32653
|
rejected.push({ path: root, reason: "not an absolute path" });
|
|
32137
32654
|
continue;
|
|
32138
32655
|
}
|
|
32139
32656
|
let real;
|
|
32140
32657
|
try {
|
|
32141
|
-
real =
|
|
32658
|
+
real = import_node_fs13.realpathSync.native((0, import_node_path15.resolve)(root));
|
|
32142
32659
|
} catch {
|
|
32143
32660
|
rejected.push({ path: root, reason: "does not exist on this computer" });
|
|
32144
32661
|
continue;
|
|
@@ -32183,12 +32700,13 @@ function createComputerConfigHandlers(ctx) {
|
|
|
32183
32700
|
|
|
32184
32701
|
// src/project-paths.ts
|
|
32185
32702
|
var import_promises10 = require("node:fs/promises");
|
|
32186
|
-
var
|
|
32187
|
-
var
|
|
32703
|
+
var import_node_crypto3 = require("node:crypto");
|
|
32704
|
+
var import_node_os9 = require("node:os");
|
|
32705
|
+
var import_node_path16 = require("node:path");
|
|
32188
32706
|
function slayzoneRootDir3() {
|
|
32189
32707
|
if (process.env.SLAYZONE_ROOT) return process.env.SLAYZONE_ROOT;
|
|
32190
|
-
const home = process.env.HOME ?? process.env.USERPROFILE ?? (0,
|
|
32191
|
-
return (0,
|
|
32708
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? (0, import_node_os9.homedir)();
|
|
32709
|
+
return (0, import_node_path16.join)(home, ".slayzone");
|
|
32192
32710
|
}
|
|
32193
32711
|
var projectPathEntrySchema = external_exports.object({
|
|
32194
32712
|
/** Absolute, realpath-resolved at write time. */
|
|
@@ -32197,7 +32715,7 @@ var projectPathEntrySchema = external_exports.object({
|
|
|
32197
32715
|
});
|
|
32198
32716
|
var projectMapSchema = external_exports.record(external_exports.string(), projectPathEntrySchema);
|
|
32199
32717
|
function projectsFilePath(baseDir) {
|
|
32200
|
-
return (0,
|
|
32718
|
+
return (0, import_node_path16.join)(baseDir ?? slayzoneRootDir3(), "computer.projects.json");
|
|
32201
32719
|
}
|
|
32202
32720
|
var fileSchema = external_exports.record(external_exports.string(), projectMapSchema);
|
|
32203
32721
|
async function readFileMap(filePath) {
|
|
@@ -32228,8 +32746,8 @@ async function readFileMap(filePath) {
|
|
|
32228
32746
|
return fileSchema.parse(out);
|
|
32229
32747
|
}
|
|
32230
32748
|
async function writeFileMap(filePath, map2) {
|
|
32231
|
-
await (0, import_promises10.mkdir)((0,
|
|
32232
|
-
const tmpPath = `${filePath}.tmp-${process.pid}-${
|
|
32749
|
+
await (0, import_promises10.mkdir)((0, import_node_path16.dirname)(filePath), { recursive: true, mode: 448 });
|
|
32750
|
+
const tmpPath = `${filePath}.tmp-${process.pid}-${(0, import_node_crypto3.randomUUID)()}`;
|
|
32233
32751
|
await (0, import_promises10.writeFile)(tmpPath, `${JSON.stringify(map2, null, 2)}
|
|
32234
32752
|
`, { mode: 384 });
|
|
32235
32753
|
try {
|
|
@@ -32239,6 +32757,16 @@ async function writeFileMap(filePath, map2) {
|
|
|
32239
32757
|
throw err;
|
|
32240
32758
|
}
|
|
32241
32759
|
}
|
|
32760
|
+
var writeQueues = /* @__PURE__ */ new Map();
|
|
32761
|
+
function serialized(filePath, write) {
|
|
32762
|
+
const previous = writeQueues.get(filePath) ?? Promise.resolve();
|
|
32763
|
+
const next = previous.then(write, write);
|
|
32764
|
+
writeQueues.set(
|
|
32765
|
+
filePath,
|
|
32766
|
+
next.catch(() => void 0)
|
|
32767
|
+
);
|
|
32768
|
+
return next;
|
|
32769
|
+
}
|
|
32242
32770
|
async function createProjectPathStore(hubHost, options = {}) {
|
|
32243
32771
|
if (!hubHost.trim()) throw new Error(`invalid hub host for project map: '${hubHost}'`);
|
|
32244
32772
|
const filePath = projectsFilePath(options.baseDir);
|
|
@@ -32248,21 +32776,25 @@ async function createProjectPathStore(hubHost, options = {}) {
|
|
|
32248
32776
|
get(projectId) {
|
|
32249
32777
|
return cache[projectId] ?? null;
|
|
32250
32778
|
},
|
|
32251
|
-
|
|
32252
|
-
|
|
32253
|
-
|
|
32254
|
-
|
|
32255
|
-
|
|
32256
|
-
|
|
32257
|
-
|
|
32779
|
+
set(projectId, path11) {
|
|
32780
|
+
return serialized(filePath, async () => {
|
|
32781
|
+
const entry = { path: path11, updatedAt: Date.now() };
|
|
32782
|
+
const all = await readFileMap(filePath);
|
|
32783
|
+
all[hubHost] = { ...all[hubHost] ?? {}, [projectId]: entry };
|
|
32784
|
+
await writeFileMap(filePath, all);
|
|
32785
|
+
cache = all[hubHost];
|
|
32786
|
+
return entry;
|
|
32787
|
+
});
|
|
32258
32788
|
},
|
|
32259
|
-
|
|
32260
|
-
|
|
32261
|
-
|
|
32262
|
-
|
|
32263
|
-
|
|
32264
|
-
|
|
32265
|
-
|
|
32789
|
+
forget(projectId) {
|
|
32790
|
+
return serialized(filePath, async () => {
|
|
32791
|
+
const all = await readFileMap(filePath);
|
|
32792
|
+
const forHub = { ...all[hubHost] ?? {} };
|
|
32793
|
+
delete forHub[projectId];
|
|
32794
|
+
all[hubHost] = forHub;
|
|
32795
|
+
await writeFileMap(filePath, all);
|
|
32796
|
+
cache = forHub;
|
|
32797
|
+
});
|
|
32266
32798
|
},
|
|
32267
32799
|
list() {
|
|
32268
32800
|
return Object.entries(cache).map(([projectId, entry]) => ({ projectId, ...entry }));
|
|
@@ -32282,13 +32814,16 @@ function createHubRequestHandler(deps2) {
|
|
|
32282
32814
|
...deps2.agentHookUrl ? { agentHookUrl: deps2.agentHookUrl } : {},
|
|
32283
32815
|
...deps2.hubAddress ? { hubAddress: deps2.hubAddress } : {}
|
|
32284
32816
|
};
|
|
32285
|
-
const pty2 = createPtyHandlers(
|
|
32817
|
+
const pty2 = createPtyHandlers(ctx, deps2.getProjectPaths, {
|
|
32818
|
+
...deps2.admission ? { admission: deps2.admission } : {},
|
|
32819
|
+
...deps2.pathReady ? { pathReady: deps2.pathReady } : {}
|
|
32820
|
+
});
|
|
32821
|
+
const proc = createProcHandlers(
|
|
32286
32822
|
ctx,
|
|
32287
32823
|
deps2.getProjectPaths,
|
|
32288
32824
|
deps2.admission ? { admission: deps2.admission } : {}
|
|
32289
32825
|
);
|
|
32290
|
-
const
|
|
32291
|
-
const fs7 = createFsHandlers(ctx);
|
|
32826
|
+
const fs8 = createFsHandlers(ctx);
|
|
32292
32827
|
const shutdownHandler = async (params) => {
|
|
32293
32828
|
const parsed = computerShutdownParamsSchema.safeParse(params ?? {});
|
|
32294
32829
|
const reason = parsed.success ? parsed.data.reason ?? "hub-requested" : "hub-requested";
|
|
@@ -32300,9 +32835,10 @@ function createHubRequestHandler(deps2) {
|
|
|
32300
32835
|
...pty2.handlers,
|
|
32301
32836
|
...proc.handlers,
|
|
32302
32837
|
...createGitHandlers(ctx),
|
|
32303
|
-
...
|
|
32838
|
+
...fs8.handlers,
|
|
32304
32839
|
...createComputerConfigHandlers(ctx),
|
|
32305
32840
|
...createGhHandlers(ctx),
|
|
32841
|
+
...createClaudeSessionHandlers(ctx, deps2.getProjectPaths ?? (() => null)),
|
|
32306
32842
|
...createProjectHandlers(ctx, deps2.getProjectPaths ?? (() => null))
|
|
32307
32843
|
};
|
|
32308
32844
|
const hub = deps2.hubHost ?? "unknown";
|
|
@@ -32360,7 +32896,7 @@ function createHubRequestHandler(deps2) {
|
|
|
32360
32896
|
const dispose = () => {
|
|
32361
32897
|
pty2.disposeAll();
|
|
32362
32898
|
proc.disposeAll();
|
|
32363
|
-
|
|
32899
|
+
fs8.disposeAll();
|
|
32364
32900
|
};
|
|
32365
32901
|
const setAgentHookUrl = (url2) => {
|
|
32366
32902
|
ctx.agentHookUrl = url2;
|
|
@@ -32389,14 +32925,14 @@ function startComputer(config2, deps2 = {}) {
|
|
|
32389
32925
|
});
|
|
32390
32926
|
});
|
|
32391
32927
|
let handle;
|
|
32392
|
-
const stateDir = deps2.stateDir ?? (0,
|
|
32393
|
-
const configFile = (0,
|
|
32928
|
+
const stateDir = deps2.stateDir ?? (0, import_node_path17.dirname)(getComputerConfigFilePath());
|
|
32929
|
+
const configFile = (0, import_node_path17.join)(stateDir, "computer.config.json");
|
|
32394
32930
|
setProtectedPaths([
|
|
32395
32931
|
configFile,
|
|
32396
32932
|
// The legacy file computer.config.json falls back to when absent.
|
|
32397
|
-
(0,
|
|
32933
|
+
(0, import_node_path17.join)(stateDir, "config.json"),
|
|
32398
32934
|
credentialsFilePath(stateDir),
|
|
32399
|
-
(0,
|
|
32935
|
+
(0, import_node_path17.join)(stateDir, REQUEST_LOG_DIR_NAME)
|
|
32400
32936
|
]);
|
|
32401
32937
|
const requestLog = createRequestLog({
|
|
32402
32938
|
stateDir,
|
|
@@ -32405,7 +32941,7 @@ function startComputer(config2, deps2 = {}) {
|
|
|
32405
32941
|
log("local request log", { file: requestLog.filePath });
|
|
32406
32942
|
const watchLocalRoots = !config2.hubMayEditRoots;
|
|
32407
32943
|
if (watchLocalRoots) {
|
|
32408
|
-
(0,
|
|
32944
|
+
(0, import_node_fs14.watchFile)(configFile, { interval: 2e3, persistent: false }, () => {
|
|
32409
32945
|
const declared = loadComputerConfigFile(configFile).allowedRoots;
|
|
32410
32946
|
const applied = reloadLocalRoots(config2, declared);
|
|
32411
32947
|
if (!applied) return;
|
|
@@ -32505,7 +33041,7 @@ function startComputer(config2, deps2 = {}) {
|
|
|
32505
33041
|
dialers: connections.map((c) => c.dialer),
|
|
32506
33042
|
stop: async () => {
|
|
32507
33043
|
hostIdStop?.();
|
|
32508
|
-
if (watchLocalRoots) (0,
|
|
33044
|
+
if (watchLocalRoots) (0, import_node_fs14.unwatchFile)(configFile);
|
|
32509
33045
|
await Promise.all(connections.map((c) => c.dispose()));
|
|
32510
33046
|
}
|
|
32511
33047
|
};
|
|
@@ -32547,7 +33083,7 @@ async function maybeInteractiveSetup() {
|
|
|
32547
33083
|
default: defaultRoot,
|
|
32548
33084
|
transform: (raw) => {
|
|
32549
33085
|
const roots = raw.split(",").map((r) => r.trim()).filter((r) => r.length > 0);
|
|
32550
|
-
return roots.length > 0 ? { config: roots, env: roots.join(
|
|
33086
|
+
return roots.length > 0 ? { config: roots, env: roots.join(import_node_path18.delimiter) } : null;
|
|
32551
33087
|
}
|
|
32552
33088
|
},
|
|
32553
33089
|
{
|
|
@@ -32559,7 +33095,7 @@ async function maybeInteractiveSetup() {
|
|
|
32559
33095
|
configKey: "computerName",
|
|
32560
33096
|
envKey: "SLAYZONE_COMPUTER_NAME",
|
|
32561
33097
|
label: "Computer display name",
|
|
32562
|
-
hint: `default: ${(0,
|
|
33098
|
+
hint: `default: ${(0, import_node_os10.hostname)()}`
|
|
32563
33099
|
}
|
|
32564
33100
|
]
|
|
32565
33101
|
});
|