pi-subagents 0.81.0 → 0.82.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/bundle/agents.js +3 -3
- package/bundle/child-tool-plan.js +2 -2
- package/bundle/{chunk-LSRUTHT7.js → chunk-43SCHIMD.js} +1 -1
- package/bundle/{chunk-G5DKFLLI.js → chunk-4SDU2BZX.js} +15 -10
- package/bundle/{chunk-V2JWDB5U.js → chunk-52UBALJL.js} +2 -2
- package/bundle/{chunk-3DC5KBVP.js → chunk-5TYMSZX3.js} +1 -1
- package/bundle/{chunk-CEKS3TFO.js → chunk-7IVSUMQQ.js} +6 -6
- package/bundle/{chunk-KSWQVGDW.js → chunk-7PCKZHR5.js} +225 -18
- package/bundle/{chunk-563BHAZ5.js → chunk-7YMXOYEU.js} +33 -25
- package/bundle/{chunk-XMFLCKMQ.js → chunk-B5EKXDHE.js} +336 -130
- package/bundle/{chunk-ZBC44JJ3.js → chunk-CIZQXJ5Q.js} +22 -9
- package/bundle/{chunk-L5ZHE4L4.js → chunk-GC4DSPMH.js} +4 -4
- package/bundle/{chunk-ARRKBB2B.js → chunk-GJECHSAR.js} +2 -2
- package/bundle/{chunk-2ZSNH26H.js → chunk-M2CTFYT3.js} +7 -7
- package/bundle/{chunk-TUWLXTAM.js → chunk-MHZ4G23A.js} +681 -320
- package/bundle/{chunk-WSBNENFS.js → chunk-NGGAFDL6.js} +14 -4
- package/bundle/{chunk-VJHOELQP.js → chunk-NRQ75MGH.js} +160 -78
- package/bundle/{chunk-BJN5LUQY.js → chunk-OYF6AFDY.js} +1 -1
- package/bundle/{chunk-EYNJ6VL6.js → chunk-PLCCBLPY.js} +2 -2
- package/bundle/{chunk-74RT5YQE.js → chunk-RMQFMMAT.js} +123 -33
- package/bundle/{chunk-V6MR5TOQ.js → chunk-SIJ4S3EN.js} +25 -19
- package/bundle/{chunk-NNLASTQE.js → chunk-VH5OAWVG.js} +19 -5
- package/bundle/{chunk-BPS2AGBZ.js → chunk-W2SZ22EM.js} +93 -52
- package/bundle/{chunk-V3BIUPLU.js → chunk-WVD4UEL4.js} +256 -52
- package/bundle/{chunk-ZP3HODFH.js → chunk-XSWOTIA3.js} +1 -1
- package/bundle/{chunk-3IF2PGW7.js → chunk-YKEWIB4M.js} +1 -1
- package/bundle/{chunk-26C3WLYQ.js → chunk-ZLINIYTP.js} +497 -272
- package/bundle/{chunk-2XYWN7QJ.js → chunk-ZQGSDHL6.js} +2 -2
- package/bundle/control-channel.js +2 -2
- package/bundle/index.js +1 -1
- package/bundle/intercom-bridge.js +2 -2
- package/bundle/preflight.js +8 -8
- package/bundle/project-panes.js +3 -3
- package/docs/agents.md +31 -0
- package/docs/configuration.md +9 -1
- package/docs/tool-reference.md +3 -1
- package/docs/workflows.md +16 -0
- package/package.json +2 -2
- package/skills/pi-subagents/references/execution-controls.md +5 -4
- package/src/agents/agent-management.js +3 -3
- package/src/agents/agent-memory.js +3 -1
- package/src/agents/agents.js +6 -6
- package/src/agents/frontmatter.d.ts +2 -0
- package/src/agents/frontmatter.js +15 -1
- package/src/agents/skills.js +2 -1
- package/src/extension/config.js +3 -0
- package/src/extension/herdr-pi-bridge.js +17 -10
- package/src/extension/index.js +82 -2
- package/src/extension/schemas.js +3 -3
- package/src/intercom/native-supervisor-channel.js +20 -0
- package/src/missions/lifecycle.js +7 -1
- package/src/runs/background/active-async-capacity.d.ts +1 -0
- package/src/runs/background/active-async-capacity.js +9 -3
- package/src/runs/background/async-execution.js +20 -10
- package/src/runs/background/async-job-tracker.d.ts +6 -1
- package/src/runs/background/async-job-tracker.js +9 -4
- package/src/runs/background/async-status.d.ts +2 -0
- package/src/runs/background/async-status.js +21 -2
- package/src/runs/background/await-async-run.js +3 -7
- package/src/runs/background/boot-id.d.ts +12 -0
- package/src/runs/background/boot-id.js +47 -0
- package/src/runs/background/interrupted-elsewhere.d.ts +22 -0
- package/src/runs/background/interrupted-elsewhere.js +68 -0
- package/src/runs/background/notify.d.ts +2 -0
- package/src/runs/background/notify.js +13 -0
- package/src/runs/background/result-delivery-ownership.d.ts +6 -0
- package/src/runs/background/result-delivery-ownership.js +19 -1
- package/src/runs/background/result-watcher.d.ts +3 -1
- package/src/runs/background/result-watcher.js +24 -8
- package/src/runs/background/run-child-session.d.ts +1 -6
- package/src/runs/background/run-child-session.js +1 -1
- package/src/runs/background/run-status.js +2 -1
- package/src/runs/background/stale-run-reconciler.d.ts +25 -0
- package/src/runs/background/stale-run-reconciler.js +52 -13
- package/src/runs/background/subagent-runner-bootstrap.js +3 -0
- package/src/runs/background/subagent-runner.d.ts +4 -0
- package/src/runs/background/subagent-runner.js +13 -5
- package/src/runs/background/subagent-wait.d.ts +1 -1
- package/src/runs/background/subagent-wait.js +6 -1
- package/src/runs/background/terminal-run-index.d.ts +1 -0
- package/src/runs/background/terminal-run-index.js +4 -2
- package/src/runs/foreground/async-stop-action.js +3 -1
- package/src/runs/foreground/execution.js +6 -3
- package/src/runs/foreground/foreground-history.d.ts +16 -2
- package/src/runs/foreground/foreground-history.js +133 -31
- package/src/runs/foreground/subagent-executor.d.ts +11 -0
- package/src/runs/foreground/subagent-executor.js +277 -74
- package/src/runs/shared/child-launch.d.ts +2 -2
- package/src/runs/shared/child-session.d.ts +3 -2
- package/src/runs/shared/child-session.js +51 -8
- package/src/runs/shared/child-tool-plan.d.ts +7 -0
- package/src/runs/shared/child-tool-plan.js +21 -6
- package/src/runs/shared/herdr-connection.d.ts +17 -8
- package/src/runs/shared/herdr-connection.js +19 -7
- package/src/runs/shared/herdr-external-adapters.d.ts +3 -2
- package/src/runs/shared/herdr-external-adapters.js +1 -1
- package/src/runs/shared/herdr-machine.d.ts +12 -2
- package/src/runs/shared/herdr-machine.js +55 -9
- package/src/runs/shared/herdr-pane-host.d.ts +88 -0
- package/src/runs/shared/herdr-pane-host.js +155 -0
- package/src/runs/shared/herdr-placed-run.d.ts +27 -150
- package/src/runs/shared/herdr-placed-run.js +48 -395
- package/src/runs/shared/local-machine-access.d.ts +5 -0
- package/src/runs/shared/local-machine-access.js +28 -0
- package/src/runs/shared/orca-progress-tabs.d.ts +0 -1
- package/src/runs/shared/orca-progress-tabs.js +1 -24
- package/src/runs/shared/parallel-utils.d.ts +1 -1
- package/src/runs/shared/placed-run-owner.d.ts +49 -0
- package/src/runs/shared/placed-run-owner.js +93 -0
- package/src/runs/shared/placement-host.d.ts +99 -0
- package/src/runs/shared/placement-host.js +157 -0
- package/src/runs/shared/rex-machine.d.ts +25 -0
- package/src/runs/shared/rex-machine.js +83 -0
- package/src/runs/shared/rex-pane-host.d.ts +62 -0
- package/src/runs/shared/rex-pane-host.js +327 -0
- package/src/shared/completion-owner.d.ts +5 -0
- package/src/shared/completion-owner.js +5 -0
- package/src/shared/session-identity.d.ts +2 -0
- package/src/shared/session-identity.js +26 -0
- package/src/shared/types.d.ts +45 -6
- package/src/tui/fleet.d.ts +1 -0
- package/src/tui/fleet.js +24 -15
- package/src/tui/render.d.ts +6 -0
- package/src/tui/render.js +3 -3
- package/src/tui/subagent-messages.js +1 -0
- package/src/workflows/scripted-workflow.d.ts +1 -1
- package/src/workflows/workflow-auto-resume.d.ts +32 -0
- package/src/workflows/workflow-auto-resume.js +102 -0
- package/src/workflows/workflow-launch-record.d.ts +27 -0
- package/src/workflows/workflow-launch-record.js +48 -0
- package/src/workflows/workflow-resume-claim.d.ts +82 -0
- package/src/workflows/workflow-resume-claim.js +210 -0
- package/src/workflows/workflow-resume.d.ts +56 -0
- package/src/workflows/workflow-resume.js +106 -0
- package/src/workflows/workflow-reuse.d.ts +15 -9
- package/src/workflows/workflow-reuse.js +77 -14
- package/src/workflows/workflow-revival.d.ts +2 -0
- package/src/workflows/workflow-revival.js +2 -1
- package/src/workflows/workflow-stop-cause.d.ts +6 -0
- package/src/workflows/workflow-stop-cause.js +8 -0
|
@@ -1,9 +1,78 @@
|
|
|
1
|
-
// src/runs/shared/
|
|
2
|
-
import {
|
|
1
|
+
// src/runs/shared/rex-machine.ts
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
|
-
import * as net from "node:net";
|
|
5
4
|
import * as os from "node:os";
|
|
6
5
|
import * as path from "node:path";
|
|
6
|
+
var REX_LOCAL_MACHINE = "local";
|
|
7
|
+
var REX_EXIT_GONE = 3;
|
|
8
|
+
var REX_EXIT_UNREACHABLE = 4;
|
|
9
|
+
function isRexLocalMachine(machine) {
|
|
10
|
+
return machine?.provider === "rex" && !("target" in machine);
|
|
11
|
+
}
|
|
12
|
+
var REX_BUNDLE_BIN = "Library/Application Support/com.superlogical.rex/RexServer/Versions/Current/Rex Server.app/Contents/MacOS/rex";
|
|
13
|
+
var REX_CALL_TIMEOUT_MS = 15e3;
|
|
14
|
+
var REX_MAX_OUTPUT = 1024 * 1024;
|
|
15
|
+
function rexGlobalArgs(server) {
|
|
16
|
+
return server ? ["--autostart=false", "-S", server] : ["--autostart=false"];
|
|
17
|
+
}
|
|
18
|
+
function executable(file) {
|
|
19
|
+
try {
|
|
20
|
+
fs.accessSync(file, fs.constants.X_OK);
|
|
21
|
+
return fs.statSync(file).isFile();
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function resolveRexBinary(env = process.env) {
|
|
27
|
+
const fromDir = env.REX_BIN_DIR ? [path.join(env.REX_BIN_DIR, "rex")] : [];
|
|
28
|
+
const fromPath = (env.PATH ?? "").split(path.delimiter).filter((dir) => path.isAbsolute(dir)).map((dir) => path.join(dir, "rex"));
|
|
29
|
+
const found = [...fromDir, ...fromPath, path.join(os.homedir(), REX_BUNDLE_BIN)].find(executable);
|
|
30
|
+
if (!found) throw new Error("The Rex CLI was not found: set REX_BIN_DIR, put rex on PATH, or install Rex.");
|
|
31
|
+
return found;
|
|
32
|
+
}
|
|
33
|
+
function rexCommandEnv(source = process.env) {
|
|
34
|
+
const { REX_SESSION: _session, REX_BLOCK: _block, REX_SERVER: _server, ...env } = source;
|
|
35
|
+
return env;
|
|
36
|
+
}
|
|
37
|
+
function sessionConfirmed(stdout, session) {
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(stdout);
|
|
40
|
+
return parsed?.session_id === session;
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function resolveRexLocalPlacement(input) {
|
|
46
|
+
if (process.platform === "win32") throw new Error("Machine 'local' runs the child in a Rex pane, which is not supported on Windows.");
|
|
47
|
+
const env = input.env ?? process.env, session = env.REX_SESSION?.trim(), server = env.REX_SERVER?.trim();
|
|
48
|
+
if (!session) throw new Error("Machine 'local' opens the child in a new tab of this Rex session, but this Pi is not running inside Rex (REX_SESSION is not set).");
|
|
49
|
+
const result = spawnSync(resolveRexBinary(env), [...rexGlobalArgs(server), "session", "inspect", session, "--json"], { encoding: "utf8", env: rexCommandEnv(env), timeout: REX_CALL_TIMEOUT_MS, maxBuffer: REX_MAX_OUTPUT, windowsHide: true });
|
|
50
|
+
if (result.error) throw new Error(`Could not ask Rex about this session: ${result.error.message}`, { cause: result.error });
|
|
51
|
+
if (result.status === REX_EXIT_GONE) throw new Error(`Machine 'local' needs this Pi's Rex session, but the Rex server does not know session ${session}.`);
|
|
52
|
+
if (result.status === REX_EXIT_UNREACHABLE) throw new Error("Machine 'local' needs the Rex server, but it is unreachable.");
|
|
53
|
+
if (result.status !== 0) throw new Error(`rex session inspect exited with code ${result.status}: ${(result.stderr || result.stdout).trim().slice(0, 512)}`);
|
|
54
|
+
if (!sessionConfirmed(result.stdout, session)) throw new Error(`The Rex server did not confirm session ${session}.`);
|
|
55
|
+
const stepCwd = input.stepCwd?.trim();
|
|
56
|
+
const home = stepCwd === "~" || stepCwd?.startsWith("~/") ? path.join(os.homedir(), stepCwd.slice(1)) : void 0;
|
|
57
|
+
const requested = home ?? (stepCwd ? path.resolve(input.cwd, stepCwd) : input.cwd);
|
|
58
|
+
let cwd;
|
|
59
|
+
try {
|
|
60
|
+
cwd = fs.realpathSync(requested);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw new Error(`Machine 'local' cwd does not exist: ${requested}.`, { cause: error });
|
|
63
|
+
}
|
|
64
|
+
if (!fs.statSync(cwd).isDirectory()) throw new Error(`Machine 'local' cwd is not a directory: ${requested}.`);
|
|
65
|
+
const machine = { provider: "rex", id: REX_LOCAL_MACHINE, session, cwd };
|
|
66
|
+
if (server) machine.server = server;
|
|
67
|
+
return machine;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// src/runs/shared/herdr-connection.ts
|
|
71
|
+
import { spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
72
|
+
import * as fs2 from "node:fs";
|
|
73
|
+
import * as net from "node:net";
|
|
74
|
+
import * as os2 from "node:os";
|
|
75
|
+
import * as path2 from "node:path";
|
|
7
76
|
var MAX_DISCOVERY_BYTES = 256 * 1024;
|
|
8
77
|
var MAX_RPC_BYTES = 4 * 1024 * 1024;
|
|
9
78
|
var SUBSCRIPTION_ACK_TIMEOUT_MS = 15e3;
|
|
@@ -52,11 +121,14 @@ function sshEnvCommand(session, command) {
|
|
|
52
121
|
return `/usr/bin/env -u HERDR_SOCKET_PATH -u HERDR_SESSION${assignment} ${remoteShellCommand(command)}`;
|
|
53
122
|
}
|
|
54
123
|
function runHerdrRemoteCommand(machine, command, options = {}) {
|
|
55
|
-
return
|
|
124
|
+
return spawnSync2(options.sshBin ?? "ssh", [...herdrSshArgs(options.env), machine.target, command], { encoding: "utf8", env: hardenedSshEnv(options.env), timeout: options.timeout ?? 15e3, maxBuffer: options.maxBuffer ?? MAX_DISCOVERY_BYTES, windowsHide: true });
|
|
56
125
|
}
|
|
57
126
|
function runHerdrRemoteCommandAsync(machine, command, options = {}) {
|
|
58
|
-
return
|
|
59
|
-
|
|
127
|
+
return runBoundedCommand(options.sshBin ?? "ssh", [...herdrSshArgs(options.env), machine.target, command], { env: hardenedSshEnv(options.env), timeout: options.timeout, maxBuffer: options.maxBuffer });
|
|
128
|
+
}
|
|
129
|
+
function runBoundedCommand(file, args, options) {
|
|
130
|
+
return new Promise((resolve2) => {
|
|
131
|
+
const child = spawn(file, args, { env: options.env, stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
|
|
60
132
|
const stdout = [], stderr = [], maxBuffer = options.maxBuffer ?? MAX_DISCOVERY_BYTES;
|
|
61
133
|
let stdoutBytes = 0, stderrBytes = 0, error, settled = false, escalation;
|
|
62
134
|
const finish = (status, spawnError = error) => {
|
|
@@ -64,7 +136,7 @@ function runHerdrRemoteCommandAsync(machine, command, options = {}) {
|
|
|
64
136
|
settled = true;
|
|
65
137
|
clearTimeout(timer);
|
|
66
138
|
if (escalation) clearTimeout(escalation);
|
|
67
|
-
|
|
139
|
+
resolve2({ status, stdout: Buffer.concat(stdout).toString("utf8"), stderr: Buffer.concat(stderr).toString("utf8"), ...spawnError ? { error: spawnError } : {} });
|
|
68
140
|
};
|
|
69
141
|
const terminate = () => {
|
|
70
142
|
child.kill("SIGTERM");
|
|
@@ -100,7 +172,7 @@ function parseHerdrEndpoint(value, expectedSession) {
|
|
|
100
172
|
}
|
|
101
173
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("Remote Herdr endpoint discovery returned no endpoint.");
|
|
102
174
|
const p = parsed;
|
|
103
|
-
if (typeof p.socket !== "string" || !
|
|
175
|
+
if (typeof p.socket !== "string" || !path2.posix.isAbsolute(p.socket) || typeof p.version !== "string" || typeof p.protocol !== "number") throw new Error("Remote Herdr endpoint discovery returned incomplete identity.");
|
|
104
176
|
const session = canonicalHerdrSession(typeof p.session === "string" ? p.session : null), expected = canonicalHerdrSession(expectedSession);
|
|
105
177
|
if (expected !== session) throw new Error(`Remote Herdr session identity mismatch: expected ${expected ?? "default"}, received ${session ?? "default"}.`);
|
|
106
178
|
if (p.running !== true || p.compatible !== true || p.endpoint_compatible === false) throw new Error("The selected remote Herdr session is stopped or incompatible.");
|
|
@@ -122,7 +194,7 @@ var SocketRpcClient = class {
|
|
|
122
194
|
this.#subscriptionAckTimeoutMs = subscriptionAckTimeoutMs;
|
|
123
195
|
}
|
|
124
196
|
call(method, params = {}, timeoutMs = 15e3) {
|
|
125
|
-
return new Promise((
|
|
197
|
+
return new Promise((resolve2, reject) => {
|
|
126
198
|
const socket = net.createConnection(this.#socketPath);
|
|
127
199
|
let bytes = 0;
|
|
128
200
|
let data = Buffer.alloc(0);
|
|
@@ -135,7 +207,7 @@ var SocketRpcClient = class {
|
|
|
135
207
|
finished = true;
|
|
136
208
|
clearTimeout(timer);
|
|
137
209
|
socket.destroy();
|
|
138
|
-
error ? reject(error) :
|
|
210
|
+
error ? reject(error) : resolve2(value);
|
|
139
211
|
};
|
|
140
212
|
socket.on("connect", () => socket.write(`${JSON.stringify({ id, method, params })}
|
|
141
213
|
`));
|
|
@@ -172,8 +244,8 @@ var SocketRpcClient = class {
|
|
|
172
244
|
const id = String(++this.#next);
|
|
173
245
|
let buffer = Buffer.alloc(0), bytes = 0, acknowledged = false, intentional = false, notified = false, settled = false;
|
|
174
246
|
let resolveAck, rejectAck;
|
|
175
|
-
const acknowledgement = new Promise((
|
|
176
|
-
resolveAck =
|
|
247
|
+
const acknowledgement = new Promise((resolve2, reject) => {
|
|
248
|
+
resolveAck = resolve2;
|
|
177
249
|
rejectAck = reject;
|
|
178
250
|
});
|
|
179
251
|
const failHandshake = (error) => {
|
|
@@ -260,19 +332,19 @@ async function waitForSocket(socketPath, child) {
|
|
|
260
332
|
for (let attempt = 0; attempt < 100; attempt++) {
|
|
261
333
|
if (child.exitCode !== null) throw new Error(`SSH StreamLocal forwarding exited with code ${child.exitCode}.`);
|
|
262
334
|
try {
|
|
263
|
-
const stat =
|
|
335
|
+
const stat = fs2.lstatSync(socketPath);
|
|
264
336
|
if (stat.isSocket()) {
|
|
265
|
-
|
|
337
|
+
fs2.chmodSync(socketPath, 384);
|
|
266
338
|
return;
|
|
267
339
|
}
|
|
268
340
|
} catch {
|
|
269
341
|
}
|
|
270
|
-
await new Promise((
|
|
342
|
+
await new Promise((resolve2) => setTimeout(resolve2, 25));
|
|
271
343
|
}
|
|
272
344
|
throw new Error("SSH StreamLocal forwarding did not create its local socket.");
|
|
273
345
|
}
|
|
274
346
|
async function terminateChild(child) {
|
|
275
|
-
const wait = (ms) => child.exitCode !== null || child.signalCode !== null ? Promise.resolve() : Promise.race([new Promise((
|
|
347
|
+
const wait = (ms) => child.exitCode !== null || child.signalCode !== null ? Promise.resolve() : Promise.race([new Promise((resolve2) => child.once("exit", () => resolve2())), new Promise((resolve2) => setTimeout(resolve2, ms))]);
|
|
276
348
|
if (child.exitCode === null && child.signalCode === null) child.kill("SIGTERM");
|
|
277
349
|
await wait(1e3);
|
|
278
350
|
if (child.exitCode === null && child.signalCode === null) {
|
|
@@ -280,22 +352,20 @@ async function terminateChild(child) {
|
|
|
280
352
|
await wait(1e3);
|
|
281
353
|
}
|
|
282
354
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-herdr-"));
|
|
287
|
-
fs.chmodSync(dir, 448);
|
|
355
|
+
function openSshSockets(machine, options) {
|
|
356
|
+
const dir = fs2.mkdtempSync(path2.join(os2.tmpdir(), "pi-subagents-herdr-"));
|
|
357
|
+
fs2.chmodSync(dir, 448);
|
|
288
358
|
const children = /* @__PURE__ */ new Set();
|
|
289
359
|
const forward = async (remotePath, name) => {
|
|
290
|
-
if (!
|
|
291
|
-
const local =
|
|
360
|
+
if (!path2.posix.isAbsolute(remotePath)) throw new Error("Remote socket path must be absolute.");
|
|
361
|
+
const local = path2.join(dir, `${name}.sock`);
|
|
292
362
|
const child = spawn(options.sshBin ?? "ssh", [...herdrSshArgs(options.env), "-N", "-o", "StreamLocalBindUnlink=yes", "-L", `${local}:${remotePath}`, machine.target], { env: hardenedSshEnv(options.env), stdio: "ignore", windowsHide: true });
|
|
293
363
|
children.add(child);
|
|
294
364
|
const stop = async () => {
|
|
295
365
|
await terminateChild(child);
|
|
296
366
|
children.delete(child);
|
|
297
367
|
try {
|
|
298
|
-
|
|
368
|
+
fs2.rmSync(local, { force: true });
|
|
299
369
|
} catch {
|
|
300
370
|
}
|
|
301
371
|
};
|
|
@@ -307,20 +377,40 @@ async function connectHerdrMachine(machine, options = {}) {
|
|
|
307
377
|
}
|
|
308
378
|
return { socketPath: local, close: stop };
|
|
309
379
|
};
|
|
310
|
-
|
|
311
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
312
|
-
throw error;
|
|
313
|
-
});
|
|
314
|
-
return { endpoint, socketPath: primary.socketPath, client: new SocketRpcClient(primary.socketPath), forwardRemoteSocket: forward, close: async () => {
|
|
380
|
+
return { forwardRemoteSocket: forward, close: async () => {
|
|
315
381
|
await Promise.all([...children].map(terminateChild));
|
|
316
382
|
children.clear();
|
|
317
|
-
|
|
383
|
+
fs2.rmSync(dir, { recursive: true, force: true });
|
|
318
384
|
} };
|
|
319
385
|
}
|
|
386
|
+
function sshMachineAccess(machine, options = {}) {
|
|
387
|
+
return { shellCommand: remoteShellCommand, run: (command, limits = {}) => runHerdrRemoteCommand(machine, command, { ...options, ...limits }), runAsync: (command, limits = {}) => runHerdrRemoteCommandAsync(machine, command, { ...options, ...limits }), openSockets: () => openSshSockets(machine, options) };
|
|
388
|
+
}
|
|
389
|
+
async function connectHerdrMachine(machine, options = {}) {
|
|
390
|
+
if (process.platform === "win32") throw new Error("Pane-native Herdr placement requires OpenSSH StreamLocal forwarding and is not supported on Windows.");
|
|
391
|
+
const endpoint = await discoverHerdrEndpoint(machine, options);
|
|
392
|
+
const sockets = sshMachineAccess(machine, options).openSockets();
|
|
393
|
+
const primary = await sockets.forwardRemoteSocket(endpoint.socket, "herdr").catch(async (error) => {
|
|
394
|
+
await sockets.close();
|
|
395
|
+
throw error;
|
|
396
|
+
});
|
|
397
|
+
return { endpoint, socketPath: primary.socketPath, client: new SocketRpcClient(primary.socketPath), forwardRemoteSocket: sockets.forwardRemoteSocket, close: sockets.close };
|
|
398
|
+
}
|
|
320
399
|
|
|
321
400
|
export {
|
|
322
401
|
remoteShellCommand,
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
connectHerdrMachine
|
|
402
|
+
runBoundedCommand,
|
|
403
|
+
sshMachineAccess,
|
|
404
|
+
connectHerdrMachine,
|
|
405
|
+
REX_LOCAL_MACHINE,
|
|
406
|
+
REX_EXIT_GONE,
|
|
407
|
+
REX_EXIT_UNREACHABLE,
|
|
408
|
+
isRexLocalMachine,
|
|
409
|
+
REX_BUNDLE_BIN,
|
|
410
|
+
REX_CALL_TIMEOUT_MS,
|
|
411
|
+
REX_MAX_OUTPUT,
|
|
412
|
+
rexGlobalArgs,
|
|
413
|
+
resolveRexBinary,
|
|
414
|
+
rexCommandEnv,
|
|
415
|
+
resolveRexLocalPlacement
|
|
326
416
|
};
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
2
|
rewriteSubagentPrompt
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GC4DSPMH.js";
|
|
4
4
|
import {
|
|
5
5
|
package_default
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-ZQGSDHL6.js";
|
|
7
|
+
import "./chunk-W2SZ22EM.js";
|
|
8
8
|
import {
|
|
9
9
|
MODEL_ONLY_TOOL
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-VH5OAWVG.js";
|
|
11
11
|
import "./chunk-NF7IEKBH.js";
|
|
12
12
|
import {
|
|
13
13
|
appendAgentRefinementOverlay
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-PLCCBLPY.js";
|
|
15
|
+
import "./chunk-NRQ75MGH.js";
|
|
16
16
|
import "./chunk-NIXWDZZV.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-XSWOTIA3.js";
|
|
18
18
|
import "./chunk-7F6RKT6W.js";
|
|
19
|
+
import {
|
|
20
|
+
assertNoToolModifierEntries
|
|
21
|
+
} from "./chunk-4SDU2BZX.js";
|
|
19
22
|
import "./chunk-CTPAE36Y.js";
|
|
20
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-5TYMSZX3.js";
|
|
21
24
|
import {
|
|
22
25
|
HERDR_PI_MAX_FRAME_BYTES,
|
|
23
26
|
HERDR_PI_PROTOCOL,
|
|
@@ -34,7 +37,7 @@ import {
|
|
|
34
37
|
discoverAgents,
|
|
35
38
|
resolveExistingReadPaths,
|
|
36
39
|
resolveSkills
|
|
37
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-CIZQXJ5Q.js";
|
|
38
41
|
import "./chunk-5LFLVSTM.js";
|
|
39
42
|
import "./chunk-YFCK7H2S.js";
|
|
40
43
|
import "./chunk-Z7KVHQHL.js";
|
|
@@ -70,6 +73,7 @@ function resolveRemoteHerdrResources(cwd, resources, remoteDefaultTools = []) {
|
|
|
70
73
|
${skillPrompt}` : ""}${readPaths.length ? `
|
|
71
74
|
|
|
72
75
|
[Read from: ${readPaths.join(", ")}]` : ""}`, { cwd, agentName: agent.name });
|
|
76
|
+
assertNoToolModifierEntries(agent.name, agent.tools ?? []);
|
|
73
77
|
const denied = new Set(agent.excludeTools ?? []);
|
|
74
78
|
const tools = (agent.tools === void 0 ? remoteDefaultTools : agent.tools).filter((tool) => !denied.has(tool) && (!resources.toolCeiling || resources.toolCeiling.includes(tool)));
|
|
75
79
|
if (agent.tools === void 0 && !tools.length) throw new Error(`Remote agent '${agent.name}' resolved no default active tools within the inherited ceiling.`);
|
|
@@ -117,7 +121,6 @@ function registerHerdrPiBridge(pi) {
|
|
|
117
121
|
client.write(encodeHerdrPiFrame(record));
|
|
118
122
|
};
|
|
119
123
|
const sessionId = (ctx) => ctx.sessionManager?.getSessionId?.();
|
|
120
|
-
const activeTools = (ctx) => ctx.getActiveTools?.() ?? [];
|
|
121
124
|
pi.registerTool({
|
|
122
125
|
name: "contact_supervisor",
|
|
123
126
|
...MODEL_ONLY_TOOL,
|
|
@@ -129,11 +132,11 @@ function registerHerdrPiBridge(pi) {
|
|
|
129
132
|
const id = `sup_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
130
133
|
send({ type: "supervisor-request", requestId: id, reason: input.reason, message: input.message?.slice(0, 65536) ?? "", ...input.interview !== void 0 ? { interview: input.interview } : {}, expectsReply: input.reason !== "progress_update", nativeSessionId });
|
|
131
134
|
if (input.reason === "progress_update") {
|
|
132
|
-
await new Promise((resolve) => supervisor.set(id, { reason: input.reason, resolve }));
|
|
135
|
+
await new Promise((resolve, reject) => supervisor.set(id, { reason: input.reason, resolve, reject }));
|
|
133
136
|
return { content: [{ type: "text", text: "Supervisor progress update queued." }], details: { delivered: true, requestId: id, reason: input.reason } };
|
|
134
137
|
}
|
|
135
138
|
const reason = input.reason;
|
|
136
|
-
const answer = await new Promise((resolve) => supervisor.set(id, { reason, resolve }));
|
|
139
|
+
const answer = await new Promise((resolve, reject) => supervisor.set(id, { reason, resolve, reject }));
|
|
137
140
|
const details = { requestId: id, reason };
|
|
138
141
|
if (reason === "interview_request") try {
|
|
139
142
|
details.structuredReply = JSON.parse(answer.replace(/^```(?:json)?\s*|\s*```$/giu, ""));
|
|
@@ -162,7 +165,8 @@ ${answer}` }], details };
|
|
|
162
165
|
const entry = request.supervisorId ? supervisor.get(request.supervisorId) : void 0;
|
|
163
166
|
if (!entry) throw new Error("Unknown supervisor request.");
|
|
164
167
|
supervisor.delete(request.supervisorId);
|
|
165
|
-
|
|
168
|
+
if (request.error !== void 0) entry.reject(new Error(request.error));
|
|
169
|
+
else entry.resolve(request.text ?? "");
|
|
166
170
|
}
|
|
167
171
|
send({ type: "control-ack", requestId, operation: request.operation, nativeSessionId });
|
|
168
172
|
};
|
|
@@ -182,7 +186,7 @@ ${resolvedSystemPrompt}` } : void 0;
|
|
|
182
186
|
nativeSessionId = sessionId(ctx);
|
|
183
187
|
if (!nativeSessionId) throw new Error("Pane-native Pi bridge requires a persisted native session identity.");
|
|
184
188
|
fs.writeFileSync(manifestPath, JSON.stringify({ protocol: HERDR_PI_PROTOCOL, packageVersion: package_default.version, runId, socketPath, nativeSessionId, pid: process.pid }), { mode: 384, flag: "wx" });
|
|
185
|
-
send({ type: "ready", packageVersion: package_default.version, nativeSessionId, sessionFile: ctx.sessionManager?.getSessionFile?.(), cwd: process.cwd(), tools:
|
|
189
|
+
send({ type: "ready", packageVersion: package_default.version, nativeSessionId, sessionFile: ctx.sessionManager?.getSessionFile?.(), cwd: process.cwd(), tools: pi.getActiveTools(), model: ctx.model?.provider && ctx.model.id ? `${ctx.model.provider}/${ctx.model.id}` : void 0, configured, activeRequestId, evidenceCursor, evidenceFloor: journal[0]?.cursor ?? evidenceCursor + 1, initialGit: gitEvidence(process.cwd()) });
|
|
186
190
|
});
|
|
187
191
|
on("message_end", (event) => {
|
|
188
192
|
const message = event.message;
|
|
@@ -233,11 +237,11 @@ ${resolvedSystemPrompt}` } : void 0;
|
|
|
233
237
|
const invalidSkills = resources.skills !== void 0 && (!Array.isArray(resources.skills) || resources.skills.some((name) => typeof name !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(name)));
|
|
234
238
|
const invalidReads = resources.reads !== void 0 && resources.reads !== false && (!Array.isArray(resources.reads) || resources.reads.some((name) => typeof name !== "string"));
|
|
235
239
|
if (typeof resources.agent !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(resources.agent) || invalidSkills || invalidReads) throw new Error("Remote logical resource names are invalid.");
|
|
236
|
-
const resolved = resolveRemoteHerdrResources(process.cwd(), { agent: resources.agent, ...resources.skills ? { skills: resources.skills } : {}, ...resources.toolCeiling ? { toolCeiling: resources.toolCeiling } : {}, ...resources.reads !== void 0 ? { reads: resources.reads } : {} }, context ?
|
|
240
|
+
const resolved = resolveRemoteHerdrResources(process.cwd(), { agent: resources.agent, ...resources.skills ? { skills: resources.skills } : {}, ...resources.toolCeiling ? { toolCeiling: resources.toolCeiling } : {}, ...resources.reads !== void 0 ? { reads: resources.reads } : {} }, context ? pi.getActiveTools() : []);
|
|
237
241
|
resolvedSystemPrompt = resolved.systemPrompt;
|
|
238
242
|
resolvedContextPolicy = resolved;
|
|
239
|
-
pi.setActiveTools
|
|
240
|
-
const acknowledged = context ?
|
|
243
|
+
pi.setActiveTools(resolved.tools);
|
|
244
|
+
const acknowledged = context ? pi.getActiveTools() : [];
|
|
241
245
|
if (acknowledged.some((tool) => !resolved.tools.includes(tool)) || resolved.tools.some((tool) => !acknowledged.includes(tool))) throw new Error("Remote Pi did not apply the resolved active-tool set exactly.");
|
|
242
246
|
configured = true;
|
|
243
247
|
send({ type: "configured", requestId: frame.requestId, nativeSessionId, agent: resolved.agent, skills: resolved.skills, model: context?.model?.provider && context.model.id ? `${context.model.provider}/${context.model.id}` : void 0, tools: acknowledged });
|
|
@@ -248,7 +252,9 @@ ${resolvedSystemPrompt}` } : void 0;
|
|
|
248
252
|
if (!["prompt", "steer", "follow-up", "abort", "supervisor-reply"].includes(operation)) throw new Error("Unsupported bridge operation.");
|
|
249
253
|
const text = frame.text;
|
|
250
254
|
if (text !== void 0 && (typeof text !== "string" || Buffer.byteLength(text) > 256 * 1024)) throw new Error("Bridge request text is invalid or too large.");
|
|
251
|
-
|
|
255
|
+
const error = frame.error;
|
|
256
|
+
if (error !== void 0 && (operation !== "supervisor-reply" || typeof error !== "string" || Buffer.byteLength(error) > 256 * 1024)) throw new Error("Bridge supervisor error is invalid or too large.");
|
|
257
|
+
pending.set(frame.requestId, { operation, ...text !== void 0 ? { text } : {}, ...typeof frame.supervisorId === "string" ? { supervisorId: frame.supervisorId } : {}, ...error !== void 0 ? { error } : {} });
|
|
252
258
|
send({ type: "prepared", requestId: frame.requestId, nativeSessionId });
|
|
253
259
|
}
|
|
254
260
|
} catch (error) {
|
|
@@ -258,7 +264,7 @@ ${resolvedSystemPrompt}` } : void 0;
|
|
|
258
264
|
socket.on("close", () => {
|
|
259
265
|
if (client === socket) client = void 0;
|
|
260
266
|
});
|
|
261
|
-
if (context && nativeSessionId) send({ type: "ready", packageVersion: package_default.version, nativeSessionId, sessionFile: context.sessionManager?.getSessionFile?.(), cwd: process.cwd(), tools:
|
|
267
|
+
if (context && nativeSessionId) send({ type: "ready", packageVersion: package_default.version, nativeSessionId, sessionFile: context.sessionManager?.getSessionFile?.(), cwd: process.cwd(), tools: pi.getActiveTools(), model: context.model?.provider && context.model.id ? `${context.model.provider}/${context.model.id}` : void 0, configured, activeRequestId, evidenceCursor, evidenceFloor: journal[0]?.cursor ?? evidenceCursor + 1, initialGit: gitEvidence(process.cwd()) });
|
|
262
268
|
});
|
|
263
269
|
server.listen(socketPath, () => {
|
|
264
270
|
fs.chmodSync(socketPath, 384);
|
|
@@ -39,10 +39,10 @@ import {
|
|
|
39
39
|
validateModelResponseAliases,
|
|
40
40
|
withWorkflowChildRunModel,
|
|
41
41
|
withWorktreeTransaction
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-NRQ75MGH.js";
|
|
43
43
|
import {
|
|
44
44
|
validateIntercomBridgeConfig
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-XSWOTIA3.js";
|
|
46
46
|
import {
|
|
47
47
|
stableJsonDigest
|
|
48
48
|
} from "./chunk-7F6RKT6W.js";
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
validateToolBudgetConfig,
|
|
74
74
|
waitForFileSystemRetry,
|
|
75
75
|
writeAtomicJson
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-CIZQXJ5Q.js";
|
|
77
77
|
import {
|
|
78
78
|
DIRS,
|
|
79
79
|
RUNNER_LAUNCHER_NAME_PATTERN,
|
|
@@ -2133,6 +2133,7 @@ function isAsyncStatusIsolationError(asyncDir, error) {
|
|
|
2133
2133
|
const message = getErrorMessage(error);
|
|
2134
2134
|
return /^(?:Failed to (?:inspect|read|parse|validate) async status file|Invalid async status file) '/.test(message) || message.startsWith(`Invalid async status '${statusPath}'`) || message.startsWith(`Invalid host step '${statusPath}`) || /^(workflowChildren|Invalid workflowChildren)/.test(message);
|
|
2135
2135
|
}
|
|
2136
|
+
var reportedCorruptStatus = /* @__PURE__ */ new Map();
|
|
2136
2137
|
function isolateCorruptActiveRun(asyncDir, runId, error, now) {
|
|
2137
2138
|
const statusPath = path3.join(asyncDir, "status.json");
|
|
2138
2139
|
const processTerminal = readProcessTerminal(asyncDir, { runId });
|
|
@@ -2152,7 +2153,18 @@ function isolateCorruptActiveRun(asyncDir, runId, error, now) {
|
|
|
2152
2153
|
markerAction = `failed to release active marker: ${getErrorMessage(releaseError)}`;
|
|
2153
2154
|
}
|
|
2154
2155
|
}
|
|
2155
|
-
|
|
2156
|
+
const line = `[pi-subagents] Skipping corrupt active async run '${runId}' at '${statusPath}': ${getErrorMessage(error)}; ${markerAction}.`;
|
|
2157
|
+
let fileSignature = "";
|
|
2158
|
+
try {
|
|
2159
|
+
const stat = fs3.statSync(statusPath);
|
|
2160
|
+
fileSignature = `${stat.size}:${stat.mtimeMs}`;
|
|
2161
|
+
} catch {
|
|
2162
|
+
}
|
|
2163
|
+
const signature = `${fileSignature}
|
|
2164
|
+
${line}`;
|
|
2165
|
+
if (reportedCorruptStatus.get(statusPath) === signature) return;
|
|
2166
|
+
reportedCorruptStatus.set(statusPath, signature);
|
|
2167
|
+
console.error(line);
|
|
2156
2168
|
}
|
|
2157
2169
|
function isNotFoundError(error) {
|
|
2158
2170
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
@@ -2467,14 +2479,16 @@ function listAsyncRuns(asyncDirRoot, options = {}, observeStatus) {
|
|
|
2467
2479
|
const asyncDir = path3.join(asyncDirRoot, entry);
|
|
2468
2480
|
let status;
|
|
2469
2481
|
try {
|
|
2482
|
+
let owned = false;
|
|
2470
2483
|
if (owners) {
|
|
2471
2484
|
const stored = readStatus(asyncDir);
|
|
2472
2485
|
if (stored && !owners.has(stored.sessionId)) {
|
|
2473
2486
|
observeStatus?.(stored);
|
|
2474
2487
|
continue;
|
|
2475
2488
|
}
|
|
2489
|
+
owned = stored !== null;
|
|
2476
2490
|
}
|
|
2477
|
-
const reconciliation = options.reconcile === false ? void 0 : reconcileAsyncRun(asyncDir, { resultsDir: options.resultsDir, kill: options.kill, now: options.now }, observeStatus);
|
|
2491
|
+
const reconciliation = options.reconcile === false ? void 0 : reconcileAsyncRun(asyncDir, { resultsDir: options.resultsDir, kill: options.kill, now: options.now, adoptCompletionOwnerId: owned ? options.adoptCompletionOwnerId : void 0 }, observeStatus);
|
|
2478
2492
|
status = reconciliation?.status ?? readStatus(asyncDir);
|
|
2479
2493
|
if (options.reconcile === false) observeStatus?.(status);
|
|
2480
2494
|
} catch (error) {
|