pi-subagents 0.81.0 → 0.82.1

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.
Files changed (152) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +1 -1
  3. package/bundle/agents.js +3 -3
  4. package/bundle/child-tool-plan.js +2 -2
  5. package/bundle/{chunk-L5ZHE4L4.js → chunk-3JCDWF4V.js} +4 -4
  6. package/bundle/{chunk-LSRUTHT7.js → chunk-43SCHIMD.js} +1 -1
  7. package/bundle/{chunk-VJHOELQP.js → chunk-46XKCPJR.js} +193 -81
  8. package/bundle/{chunk-G5DKFLLI.js → chunk-4SDU2BZX.js} +15 -10
  9. package/bundle/{chunk-2ZSNH26H.js → chunk-4Y2ROR7L.js} +7 -7
  10. package/bundle/{chunk-V2JWDB5U.js → chunk-52UBALJL.js} +2 -2
  11. package/bundle/{chunk-3DC5KBVP.js → chunk-5TYMSZX3.js} +1 -1
  12. package/bundle/{chunk-NNLASTQE.js → chunk-6XJB7PIX.js} +20 -6
  13. package/bundle/{chunk-ZBC44JJ3.js → chunk-CIZQXJ5Q.js} +22 -9
  14. package/bundle/{chunk-KSWQVGDW.js → chunk-FXUXCX2K.js} +225 -18
  15. package/bundle/{chunk-563BHAZ5.js → chunk-G4GZD3OJ.js} +35 -26
  16. package/bundle/{chunk-ARRKBB2B.js → chunk-GJECHSAR.js} +2 -2
  17. package/bundle/{chunk-V3BIUPLU.js → chunk-IVAE5Z6Q.js} +256 -52
  18. package/bundle/{chunk-V6MR5TOQ.js → chunk-JYUKW2SY.js} +25 -19
  19. package/bundle/{chunk-BJN5LUQY.js → chunk-OYF6AFDY.js} +1 -1
  20. package/bundle/{chunk-CEKS3TFO.js → chunk-PBK2I7WY.js} +6 -6
  21. package/bundle/{chunk-TUWLXTAM.js → chunk-PDZWJCHD.js} +681 -320
  22. package/bundle/{chunk-EYNJ6VL6.js → chunk-PLCCBLPY.js} +2 -2
  23. package/bundle/{chunk-XMFLCKMQ.js → chunk-QE4AGIMG.js} +339 -132
  24. package/bundle/{chunk-74RT5YQE.js → chunk-RMQFMMAT.js} +123 -33
  25. package/bundle/{chunk-WSBNENFS.js → chunk-UCPP4GNU.js} +14 -4
  26. package/bundle/{chunk-2XYWN7QJ.js → chunk-UTT254JE.js} +2 -2
  27. package/bundle/{chunk-BPS2AGBZ.js → chunk-VSUSLDNW.js} +93 -52
  28. package/bundle/{chunk-ZP3HODFH.js → chunk-XSWOTIA3.js} +1 -1
  29. package/bundle/{chunk-3IF2PGW7.js → chunk-YKEWIB4M.js} +1 -1
  30. package/bundle/{chunk-26C3WLYQ.js → chunk-ZIV4J4HG.js} +498 -274
  31. package/bundle/control-channel.js +2 -2
  32. package/bundle/index.js +1 -1
  33. package/bundle/intercom-bridge.js +2 -2
  34. package/bundle/preflight.js +8 -8
  35. package/bundle/project-panes.js +3 -3
  36. package/docs/agents.md +37 -7
  37. package/docs/configuration.md +9 -1
  38. package/docs/tool-reference.md +3 -1
  39. package/docs/workflows.md +16 -0
  40. package/package.json +2 -2
  41. package/skills/council-mode/SKILL.md +1 -4
  42. package/skills/pi-subagents/SKILL.md +130 -107
  43. package/skills/pi-subagents/references/orchestration.md +124 -0
  44. package/skills/pi-subagents/references/prompting-and-roles.md +96 -295
  45. package/src/agents/agent-management.js +3 -3
  46. package/src/agents/agent-memory.js +3 -1
  47. package/src/agents/agents.js +6 -6
  48. package/src/agents/frontmatter.d.ts +2 -0
  49. package/src/agents/frontmatter.js +15 -1
  50. package/src/agents/skills.js +2 -1
  51. package/src/extension/config.js +3 -0
  52. package/src/extension/herdr-pi-bridge.js +17 -10
  53. package/src/extension/index.js +82 -2
  54. package/src/extension/reply-workflow-script.js +5 -2
  55. package/src/extension/schemas.js +3 -3
  56. package/src/extension/subagent-guide.js +1 -2
  57. package/src/intercom/native-supervisor-channel.js +20 -0
  58. package/src/missions/lifecycle.js +7 -1
  59. package/src/runs/background/active-async-capacity.d.ts +1 -0
  60. package/src/runs/background/active-async-capacity.js +9 -3
  61. package/src/runs/background/async-execution.js +20 -10
  62. package/src/runs/background/async-job-tracker.d.ts +6 -1
  63. package/src/runs/background/async-job-tracker.js +9 -4
  64. package/src/runs/background/async-status.d.ts +4 -0
  65. package/src/runs/background/async-status.js +22 -3
  66. package/src/runs/background/await-async-run.js +3 -7
  67. package/src/runs/background/boot-id.d.ts +12 -0
  68. package/src/runs/background/boot-id.js +47 -0
  69. package/src/runs/background/interrupted-elsewhere.d.ts +22 -0
  70. package/src/runs/background/interrupted-elsewhere.js +68 -0
  71. package/src/runs/background/notify.d.ts +2 -0
  72. package/src/runs/background/notify.js +13 -0
  73. package/src/runs/background/result-delivery-ownership.d.ts +6 -0
  74. package/src/runs/background/result-delivery-ownership.js +19 -1
  75. package/src/runs/background/result-watcher.d.ts +3 -1
  76. package/src/runs/background/result-watcher.js +24 -8
  77. package/src/runs/background/run-child-session.d.ts +1 -6
  78. package/src/runs/background/run-child-session.js +1 -1
  79. package/src/runs/background/run-status.js +2 -1
  80. package/src/runs/background/stale-run-reconciler.d.ts +25 -0
  81. package/src/runs/background/stale-run-reconciler.js +52 -13
  82. package/src/runs/background/subagent-runner-bootstrap.js +3 -0
  83. package/src/runs/background/subagent-runner.d.ts +4 -0
  84. package/src/runs/background/subagent-runner.js +13 -5
  85. package/src/runs/background/subagent-wait.d.ts +1 -1
  86. package/src/runs/background/subagent-wait.js +6 -1
  87. package/src/runs/background/terminal-run-index.d.ts +2 -0
  88. package/src/runs/background/terminal-run-index.js +44 -3
  89. package/src/runs/foreground/async-stop-action.js +3 -1
  90. package/src/runs/foreground/execution.js +6 -3
  91. package/src/runs/foreground/foreground-history.d.ts +16 -2
  92. package/src/runs/foreground/foreground-history.js +133 -31
  93. package/src/runs/foreground/subagent-executor.d.ts +11 -0
  94. package/src/runs/foreground/subagent-executor.js +277 -74
  95. package/src/runs/shared/child-launch.d.ts +2 -2
  96. package/src/runs/shared/child-session.d.ts +3 -2
  97. package/src/runs/shared/child-session.js +51 -8
  98. package/src/runs/shared/child-tool-plan.d.ts +7 -0
  99. package/src/runs/shared/child-tool-plan.js +21 -6
  100. package/src/runs/shared/herdr-connection.d.ts +17 -8
  101. package/src/runs/shared/herdr-connection.js +19 -7
  102. package/src/runs/shared/herdr-external-adapters.d.ts +3 -2
  103. package/src/runs/shared/herdr-external-adapters.js +1 -1
  104. package/src/runs/shared/herdr-machine.d.ts +12 -2
  105. package/src/runs/shared/herdr-machine.js +55 -9
  106. package/src/runs/shared/herdr-pane-host.d.ts +88 -0
  107. package/src/runs/shared/herdr-pane-host.js +155 -0
  108. package/src/runs/shared/herdr-placed-run.d.ts +27 -150
  109. package/src/runs/shared/herdr-placed-run.js +48 -395
  110. package/src/runs/shared/local-machine-access.d.ts +5 -0
  111. package/src/runs/shared/local-machine-access.js +28 -0
  112. package/src/runs/shared/orca-progress-tabs.d.ts +0 -1
  113. package/src/runs/shared/orca-progress-tabs.js +1 -24
  114. package/src/runs/shared/parallel-utils.d.ts +1 -1
  115. package/src/runs/shared/placed-run-owner.d.ts +49 -0
  116. package/src/runs/shared/placed-run-owner.js +93 -0
  117. package/src/runs/shared/placement-host.d.ts +99 -0
  118. package/src/runs/shared/placement-host.js +157 -0
  119. package/src/runs/shared/rex-machine.d.ts +25 -0
  120. package/src/runs/shared/rex-machine.js +83 -0
  121. package/src/runs/shared/rex-pane-host.d.ts +62 -0
  122. package/src/runs/shared/rex-pane-host.js +327 -0
  123. package/src/shared/completion-owner.d.ts +5 -0
  124. package/src/shared/completion-owner.js +5 -0
  125. package/src/shared/session-identity.d.ts +2 -0
  126. package/src/shared/session-identity.js +26 -0
  127. package/src/shared/types.d.ts +45 -6
  128. package/src/tui/fleet.d.ts +1 -0
  129. package/src/tui/fleet.js +25 -15
  130. package/src/tui/render.d.ts +6 -0
  131. package/src/tui/render.js +3 -3
  132. package/src/tui/subagent-messages.js +1 -0
  133. package/src/workflows/scripted-workflow.d.ts +1 -1
  134. package/src/workflows/workflow-auto-resume.d.ts +32 -0
  135. package/src/workflows/workflow-auto-resume.js +102 -0
  136. package/src/workflows/workflow-launch-record.d.ts +27 -0
  137. package/src/workflows/workflow-launch-record.js +48 -0
  138. package/src/workflows/workflow-resume-claim.d.ts +82 -0
  139. package/src/workflows/workflow-resume-claim.js +210 -0
  140. package/src/workflows/workflow-resume.d.ts +56 -0
  141. package/src/workflows/workflow-resume.js +106 -0
  142. package/src/workflows/workflow-reuse.d.ts +15 -9
  143. package/src/workflows/workflow-reuse.js +77 -14
  144. package/src/workflows/workflow-revival.d.ts +2 -0
  145. package/src/workflows/workflow-revival.js +2 -1
  146. package/src/workflows/workflow-stop-cause.d.ts +6 -0
  147. package/src/workflows/workflow-stop-cause.js +8 -0
  148. package/skills/pi-subagents/references/constraints-and-recipes.md +0 -74
  149. package/skills/pi-subagents/references/execution-controls.md +0 -563
  150. package/skills/pi-subagents/references/management-authoring-rpc.md +0 -165
  151. package/skills/pi-subagents/references/multi-lane-orchestration.md +0 -61
  152. package/skills/pi-subagents/references/review-and-validation.md +0 -73
@@ -1,9 +1,78 @@
1
- // src/runs/shared/herdr-connection.ts
2
- import { spawn, spawnSync } from "node:child_process";
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 spawnSync(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 });
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 new Promise((resolve) => {
59
- const child = spawn(options.sshBin ?? "ssh", [...herdrSshArgs(options.env), machine.target, command], { env: hardenedSshEnv(options.env), stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
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
- resolve({ status, stdout: Buffer.concat(stdout).toString("utf8"), stderr: Buffer.concat(stderr).toString("utf8"), ...spawnError ? { error: spawnError } : {} });
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" || !path.posix.isAbsolute(p.socket) || typeof p.version !== "string" || typeof p.protocol !== "number") throw new Error("Remote Herdr endpoint discovery returned incomplete identity.");
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((resolve, reject) => {
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) : resolve(value);
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((resolve, reject) => {
176
- resolveAck = resolve;
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 = fs.lstatSync(socketPath);
335
+ const stat = fs2.lstatSync(socketPath);
264
336
  if (stat.isSocket()) {
265
- fs.chmodSync(socketPath, 384);
337
+ fs2.chmodSync(socketPath, 384);
266
338
  return;
267
339
  }
268
340
  } catch {
269
341
  }
270
- await new Promise((resolve) => setTimeout(resolve, 25));
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((resolve) => child.once("exit", () => resolve())), new Promise((resolve) => setTimeout(resolve, ms))]);
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
- async function connectHerdrMachine(machine, options = {}) {
284
- if (process.platform === "win32") throw new Error("Pane-native Herdr placement requires OpenSSH StreamLocal forwarding and is not supported on Windows.");
285
- const endpoint = await discoverHerdrEndpoint(machine, options);
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 (!path.posix.isAbsolute(remotePath)) throw new Error("Remote socket path must be absolute.");
291
- const local = path.join(dir, `${name}.sock`);
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
- fs.rmSync(local, { force: true });
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
- const primary = await forward(endpoint.socket, "herdr").catch((error) => {
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
- fs.rmSync(dir, { recursive: true, force: true });
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
- runHerdrRemoteCommand,
324
- runHerdrRemoteCommandAsync,
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,5 +1,7 @@
1
1
  import {
2
2
  checkPidLiveness,
3
+ checkRecordedPidLiveness,
4
+ currentBootId,
3
5
  currentPidNamespaceScope,
4
6
  isTerminalAsyncState,
5
7
  normalizeWorktreeBranchPrefix,
@@ -9,13 +11,13 @@ import {
9
11
  validateAuthorityPolicy,
10
12
  validateMissionStoreConfig,
11
13
  validateModelResponseAliases
12
- } from "./chunk-VJHOELQP.js";
14
+ } from "./chunk-46XKCPJR.js";
13
15
  import {
14
16
  getAgentDir,
15
17
  readStatus,
16
18
  validatePermissionConfig,
17
19
  writePrivateAtomicJson
18
- } from "./chunk-ZBC44JJ3.js";
20
+ } from "./chunk-CIZQXJ5Q.js";
19
21
  import {
20
22
  FLEET_KEYBINDING_ACTIONS,
21
23
  RUNNER_LAUNCHER_NAME_PATTERN,
@@ -252,8 +254,13 @@ function abandonedRunnerReleaseVerdict(status, proofState, options, anyTerminalS
252
254
  if (thresholdMs === false) return { state: "retained", reason: `${proofReason}; abandoned-timeout policy is disabled` };
253
255
  if (anyTerminalState ? !isTerminalAsyncState(status.state) : status.state !== "failed") return { state: "retained", reason: `${proofReason}; abandoned-timeout policy requires a ${anyTerminalState ? "terminal" : "failed"} run, not ${status.state}` };
254
256
  if (typeof status.pid !== "number" || !Number.isInteger(status.pid) || status.pid < 1) return { state: "retained", reason: `${proofReason}; runner PID is missing or invalid` };
255
- if (status.pidNamespaceScope !== void 0 && status.pidNamespaceScope !== (options.pidNamespaceScope ?? currentPidNamespaceScope)()) return { state: "retained", reason: `${proofReason}; runner PID namespace differs from this process, so liveness is unknown` };
256
- const liveness = (options.pidLiveness ?? checkPidLiveness)(status.pid);
257
+ const observedScope = (options.pidNamespaceScope ?? currentPidNamespaceScope)();
258
+ if (status.pidNamespaceScope !== void 0 && status.pidNamespaceScope !== observedScope) return { state: "retained", reason: `${proofReason}; runner PID namespace differs from this process, so liveness is unknown` };
259
+ const liveness = checkRecordedPidLiveness({ pid: status.pid, pidNamespaceScope: status.pidNamespaceScope, bootId: status.bootId }, {
260
+ observedScope,
261
+ observedBootId: (options.bootId ?? currentBootId)(),
262
+ probe: options.pidLiveness ?? ((pid) => checkPidLiveness(pid))
263
+ });
257
264
  if (liveness !== "dead") return { state: "retained", reason: `${proofReason}; runner PID liveness is ${liveness}` };
258
265
  const lastActivityAt = status.lastActivityAt ?? status.lastUpdate ?? status.endedAt;
259
266
  if (typeof lastActivityAt !== "number" || !Number.isFinite(lastActivityAt)) return { state: "retained", reason: `${proofReason}; last activity timestamp is missing or invalid` };
@@ -666,6 +673,9 @@ function validateConfig(config) {
666
673
  if (config.enableSlashCommands !== void 0 && typeof config.enableSlashCommands !== "boolean") {
667
674
  throw new Error("config.enableSlashCommands must be a boolean");
668
675
  }
676
+ if (config.autoResume !== void 0 && typeof config.autoResume !== "boolean") {
677
+ throw new Error("config.autoResume must be a boolean");
678
+ }
669
679
  if (config.toolActivation !== void 0 && config.toolActivation !== "auto" && config.toolActivation !== "dynamic" && config.toolActivation !== "eager") {
670
680
  throw new Error('config.toolActivation must be "auto", "dynamic", or "eager"');
671
681
  }
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "pi-subagents",
4
- version: "0.81.0",
4
+ version: "0.82.1",
5
5
  private: true,
6
6
  description: "Pi extension for single-agent delegation and scripted multi-agent workflows",
7
7
  author: "Nico Bailon",
@@ -106,7 +106,7 @@ var package_default = {
106
106
  "@js-temporal/polyfill": "0.5.1",
107
107
  acorn: "8.18.0",
108
108
  jiti: "2.7.0",
109
- undici: "8.10.2",
109
+ undici: "8.12.3",
110
110
  yaml: "2.8.3"
111
111
  },
112
112
  devDependencies: {