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
@@ -11,7 +11,7 @@ import {
11
11
  projectTimeoutRecovery,
12
12
  readAsyncRecoveryDescriptor,
13
13
  utf8Tail
14
- } from "./chunk-NNLASTQE.js";
14
+ } from "./chunk-6XJB7PIX.js";
15
15
  import {
16
16
  MAX_ARGS_BYTES,
17
17
  MAX_ARGS_DEPTH,
@@ -24,13 +24,13 @@ import {
24
24
  resultFilePath,
25
25
  resultPayloadMatchesSessionRun,
26
26
  resultPayloadPathForSessionRun
27
- } from "./chunk-VJHOELQP.js";
27
+ } from "./chunk-46XKCPJR.js";
28
28
  import {
29
29
  shouldUseNativeFsWatch
30
30
  } from "./chunk-NIXWDZZV.js";
31
31
  import {
32
32
  PROJECT_SUBAGENTS_RELATIVE_DIR
33
- } from "./chunk-3DC5KBVP.js";
33
+ } from "./chunk-5TYMSZX3.js";
34
34
  import {
35
35
  listBackgroundWorkWakeChannels,
36
36
  snapshotBackgroundWork
@@ -55,7 +55,7 @@ import {
55
55
  withSettingsFileLease,
56
56
  writeAtomicJson,
57
57
  writePrivateAtomicJson
58
- } from "./chunk-ZBC44JJ3.js";
58
+ } from "./chunk-CIZQXJ5Q.js";
59
59
  import {
60
60
  ASYNC_DIR,
61
61
  DIRS,
@@ -213,6 +213,7 @@ async function waitForReply(channelDir, requestId, initialDeadline, signal) {
213
213
  if (fs.existsSync(file)) {
214
214
  const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
215
215
  if (parsed.type === "subagent.supervisor.reply" && parsed.requestId === requestId && typeof parsed.message === "string") {
216
+ if (typeof parsed.error === "string") throw new Error(parsed.error);
216
217
  return parsed;
217
218
  }
218
219
  }
@@ -748,6 +749,24 @@ function createNativeSupervisorChannel(pi, state, deps = {}) {
748
749
  cleanupRequestLifecycle(request, lifecycle);
749
750
  continue;
750
751
  }
752
+ if (request.expectsReply && runState(request).blockingWorkflowChildren?.has(request.runId)) {
753
+ try {
754
+ writePrivateAtomicJson(replyPath(channelDir, request.id), {
755
+ type: "subagent.supervisor.reply",
756
+ requestId: request.id,
757
+ createdAt: now,
758
+ message: "",
759
+ error: "Supervisor unavailable: the parent is blocked in an async:false workflow and cannot answer this request. Report the blocker and any partial results, then stop. Relaunch the workflow with async:true to allow supervisor replies."
760
+ });
761
+ } catch (error) {
762
+ console.error(`Failed to report unreachable supervisor request ${request.id}; will retry:`, error);
763
+ continue;
764
+ }
765
+ seenFiles.add(file);
766
+ observeRequestLifecycle(request, "resolved");
767
+ cleanupRequestLifecycle(request, "resolved");
768
+ continue;
769
+ }
751
770
  seenFiles.add(file);
752
771
  if (!request.expectsReply) {
753
772
  removeRequestFile(request.requestFile);
@@ -1037,14 +1056,34 @@ function createNativeSupervisorChannel(pi, state, deps = {}) {
1037
1056
  }
1038
1057
 
1039
1058
  // src/shared/session-identity.ts
1059
+ import * as fs2 from "node:fs";
1040
1060
  function resolveCurrentSessionId(sessionManager) {
1041
1061
  const sessionId = sessionManager.getSessionFile() ?? sessionManager.getSessionId();
1042
1062
  if (!sessionId) throw new Error("Current session identity is unavailable.");
1043
1063
  return sessionId;
1044
1064
  }
1065
+ function resolvePiSessionId(sessionFile) {
1066
+ if (!sessionFile) return void 0;
1067
+ try {
1068
+ const fd = fs2.openSync(sessionFile, "r");
1069
+ try {
1070
+ const buffer = Buffer.alloc(16 * 1024);
1071
+ const bytes = fs2.readSync(fd, buffer, 0, buffer.length, 0);
1072
+ const line = buffer.toString("utf-8", 0, bytes).split("\n", 1)[0];
1073
+ if (!line) return void 0;
1074
+ const header = JSON.parse(line);
1075
+ if (header.type === "session" && typeof header.id === "string" && /^[A-Za-z0-9-]{8,}$/.test(header.id)) return header.id;
1076
+ return void 0;
1077
+ } finally {
1078
+ fs2.closeSync(fd);
1079
+ }
1080
+ } catch {
1081
+ return void 0;
1082
+ }
1083
+ }
1045
1084
 
1046
1085
  // src/watchdog/settings.ts
1047
- import * as fs2 from "node:fs";
1086
+ import * as fs3 from "node:fs";
1048
1087
  import * as path2 from "node:path";
1049
1088
  var DEFAULT_WATCHDOG_CONFIG = {
1050
1089
  enabled: false,
@@ -1294,10 +1333,10 @@ function parseSettingsObject(settings, meta) {
1294
1333
  return parseWatchdogPatch(subagents.watchdog, "subagents.watchdog", meta);
1295
1334
  }
1296
1335
  function readSettingsFileStrict(filePath) {
1297
- if (!fs2.existsSync(filePath)) return {};
1336
+ if (!fs3.existsSync(filePath)) return {};
1298
1337
  let raw;
1299
1338
  try {
1300
- raw = fs2.readFileSync(filePath, "utf-8");
1339
+ raw = fs3.readFileSync(filePath, "utf-8");
1301
1340
  } catch (error) {
1302
1341
  const message2 = error instanceof Error ? error.message : String(error);
1303
1342
  throw new Error(`Failed to read settings file '${filePath}': ${message2}`, { cause: error });
@@ -1316,7 +1355,7 @@ function readSettingsFileStrict(filePath) {
1316
1355
  }
1317
1356
  function isDirectory(dir) {
1318
1357
  try {
1319
- return fs2.statSync(dir).isDirectory();
1358
+ return fs3.statSync(dir).isDirectory();
1320
1359
  } catch {
1321
1360
  return false;
1322
1361
  }
@@ -1383,8 +1422,8 @@ function targetSettingsObject(watchdog, target, meta) {
1383
1422
  return ensureObjectField(overrides, target.agent.trim(), `subagents.watchdog.children.overrides.${target.agent.trim()}`, meta);
1384
1423
  }
1385
1424
  function writeSettingsFile(settingsPath, settings) {
1386
- fs2.mkdirSync(path2.dirname(settingsPath), { recursive: true });
1387
- fs2.writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
1425
+ fs3.mkdirSync(path2.dirname(settingsPath), { recursive: true });
1426
+ fs3.writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
1388
1427
  `, "utf-8");
1389
1428
  return settingsPath;
1390
1429
  }
@@ -1423,7 +1462,7 @@ function resolveWatchdogConfig(cwd2, options = {}) {
1423
1462
  ];
1424
1463
  for (const source of sourceSpecs) {
1425
1464
  if (!source.path) continue;
1426
- sources.push({ scope: source.scope, path: source.path, exists: fs2.existsSync(source.path) });
1465
+ sources.push({ scope: source.scope, path: source.path, exists: fs3.existsSync(source.path) });
1427
1466
  try {
1428
1467
  patch = deepMerge(patch, parseSourceFile(source.path, source.scope));
1429
1468
  } catch (error) {
@@ -1747,7 +1786,7 @@ var SubagentParamProperties = {
1747
1786
  description: "true: run the one ```js workflow block written in this same reply (false invalid). String with '/': script file read from request cwd. Other string: named workflow resource. Raw scripts (true or path) have no runs.host."
1748
1787
  })),
1749
1788
  args: Type2.Optional(Type2.Unsafe({ type: "object", maxProperties: MAX_ARGS_FIELDS, additionalProperties: true, description: `Plain-JSON args for workflow; ${MAX_ARGS_FIELDS} fields/object, ${MAX_ARGS_ITEMS} items/array, depth ${MAX_ARGS_DEPTH}, ${MAX_ARGS_BYTES / 1024} KiB total; raw-script args are exposed deeply frozen and persisted, so do not include secrets.` })),
1750
- reuseFrom: Type2.Optional(Type2.String({ minLength: 1, description: "Exact id of a workflow run stopped by a session handoff or reload; this async workflow reuses its finished children and re-attaches to its running ones." })),
1789
+ reuseFrom: Type2.Optional(Type2.String({ minLength: 1, description: "Exact id of a workflow run ended by a reload, handoff or Pi exit; this async workflow reuses its finished children and re-attaches to its running ones." })),
1751
1790
  globalConcurrencyLimit: Type2.Optional(Type2.Integer({ minimum: 1 })),
1752
1791
  maxSubagentSpawnsPerRun: Type2.Optional(Type2.Integer({ minimum: 1 })),
1753
1792
  preflight: Type2.Optional(WorkflowPreflightOverride),
@@ -1769,7 +1808,7 @@ var SubagentParamProperties = {
1769
1808
  usageBudget: Type2.Optional(UsageBudgetOverride),
1770
1809
  agentScope: Type2.Optional(Type2.String({ description: "user/project/both (default); project wins collisions." })),
1771
1810
  cwd: Type2.Optional(Type2.String({ description: "Execution/project-pane directory." })),
1772
- machine: Type2.Optional(Type2.String({ minLength: 1, maxLength: 128, description: "Herdr saved machine id or label; runs an external CLI agent there. cwd then means the directory on that machine." })),
1811
+ machine: Type2.Optional(Type2.String({ minLength: 1, maxLength: 128, description: 'Herdr saved machine id or label (runs an external CLI agent), a Rex host named in settings (runs a Pi child), or "local" (a Pi child in a Rex pane here). On another machine, cwd is a directory there.' })),
1773
1812
  artifacts: Type2.Optional(Type2.Boolean({ description: "Debug artifacts; default true." })),
1774
1813
  includeProgress: Type2.Optional(Type2.Boolean({ description: "Full result progress; default false." })),
1775
1814
  share: Type2.Optional(Type2.Boolean({ description: "Upload session to GitHub Gist; default false." })),
@@ -1851,7 +1890,7 @@ var SubagentWaitParamsSchema = Type2.Object({
1851
1890
  nonBlocking: Type2.Optional(Type2.Boolean({ description: "Subscribe to id's wake and return immediately; requires id, not with all." })),
1852
1891
  all: Type2.Optional(Type2.Boolean({ description: "Wait for all work active at call time." })),
1853
1892
  timeoutMs: Type2.Optional(Type2.Integer({ minimum: 1, description: "Max wait; default waitTool.defaultTimeoutMs, then 30 min." })),
1854
- stopOnAttention: Type2.Optional(Type2.Boolean({ description: "false: keep waiting through idle or long-thinking attention." }))
1893
+ stopOnAttention: Type2.Optional(Type2.Boolean({ description: "false: keep waiting through all attention except supervisor requests." }))
1855
1894
  });
1856
1895
  var SubagentWaitParams = keepTopLevelParameterDescriptions(SubagentWaitParamsSchema);
1857
1896
 
@@ -1896,14 +1935,14 @@ function resolveWaitToolConfig(config, env = process.env) {
1896
1935
  }
1897
1936
 
1898
1937
  // src/runs/background/subagent-wait.ts
1899
- import * as fs6 from "node:fs";
1938
+ import * as fs7 from "node:fs";
1900
1939
  import * as path4 from "node:path";
1901
1940
 
1902
1941
  // src/runs/background/wait-completions.ts
1903
- import * as fs4 from "node:fs";
1942
+ import * as fs5 from "node:fs";
1904
1943
 
1905
1944
  // src/runs/background/completion-replay.ts
1906
- import * as fs3 from "node:fs";
1945
+ import * as fs4 from "node:fs";
1907
1946
  import * as path3 from "node:path";
1908
1947
  var REPLAY_VERSION = 1;
1909
1948
  var ARCHIVE_VERSION = 1;
@@ -1928,7 +1967,7 @@ function existingFile(value) {
1928
1967
  const filePath = nonEmptyString(value);
1929
1968
  if (!filePath) return void 0;
1930
1969
  try {
1931
- return fs3.statSync(filePath).isFile() ? filePath : void 0;
1970
+ return fs4.statSync(filePath).isFile() ? filePath : void 0;
1932
1971
  } catch {
1933
1972
  return void 0;
1934
1973
  }
@@ -2013,7 +2052,7 @@ function runIdFromReplayFile(file) {
2013
2052
  }
2014
2053
  function removeBestEffort(filePath) {
2015
2054
  try {
2016
- fs3.rmSync(filePath, { force: true });
2055
+ fs4.rmSync(filePath, { force: true });
2017
2056
  } catch {
2018
2057
  }
2019
2058
  }
@@ -2056,7 +2095,7 @@ function readCompletionReplay(resultsDir, runId, options = {}) {
2056
2095
  const replayPath = completionReplayPath(resultsDir, runId);
2057
2096
  let parsed;
2058
2097
  try {
2059
- parsed = parseReplay(JSON.parse(fs3.readFileSync(replayPath, "utf-8")));
2098
+ parsed = parseReplay(JSON.parse(fs4.readFileSync(replayPath, "utf-8")));
2060
2099
  } catch (error) {
2061
2100
  if (error.code === "ENOENT") return void 0;
2062
2101
  throw error;
@@ -2078,7 +2117,7 @@ function readCompletionReplay(resultsDir, runId, options = {}) {
2078
2117
  }
2079
2118
  function readCompletionArchive(archivePath) {
2080
2119
  try {
2081
- const archive = parseArchive(JSON.parse(fs3.readFileSync(archivePath, "utf-8")));
2120
+ const archive = parseArchive(JSON.parse(fs4.readFileSync(archivePath, "utf-8")));
2082
2121
  if (!archive) throw new Error("Completion archive is malformed.");
2083
2122
  return archive;
2084
2123
  } catch (error) {
@@ -2096,20 +2135,20 @@ function cleanupCompletionReplayIfDue(resultsDir, now, maxAgeMs, intervalMs = CL
2096
2135
  function cleanupCompletionReplay(resultsDir, now, maxAgeMs) {
2097
2136
  const replayDir = path3.join(resultsDir, REPLAY_DIR_NAME);
2098
2137
  try {
2099
- for (const file of fs3.readdirSync(replayDir)) {
2138
+ for (const file of fs4.readdirSync(replayDir)) {
2100
2139
  const runId = runIdFromReplayFile(file);
2101
2140
  if (!runId) continue;
2102
2141
  const filePath = path3.join(replayDir, file);
2103
2142
  try {
2104
- const record = parseReplay(JSON.parse(fs3.readFileSync(filePath, "utf-8")));
2143
+ const record = parseReplay(JSON.parse(fs4.readFileSync(filePath, "utf-8")));
2105
2144
  const safeRecord = record ? validateReplayRecord(resultsDir, runId, record) : void 0;
2106
2145
  if (record && !safeRecord) {
2107
- fs3.rmSync(filePath, { force: true });
2146
+ fs4.rmSync(filePath, { force: true });
2108
2147
  } else if (safeRecord && safeRecord.expiresAt <= now) {
2109
- fs3.rmSync(filePath, { force: true });
2110
- fs3.rmSync(safeRecord.archivePath, { force: true });
2111
- } else if (!record && now - fs3.statSync(filePath).mtimeMs > maxAgeMs) {
2112
- fs3.rmSync(filePath, { force: true });
2148
+ fs4.rmSync(filePath, { force: true });
2149
+ fs4.rmSync(safeRecord.archivePath, { force: true });
2150
+ } else if (!record && now - fs4.statSync(filePath).mtimeMs > maxAgeMs) {
2151
+ fs4.rmSync(filePath, { force: true });
2113
2152
  }
2114
2153
  } catch {
2115
2154
  }
@@ -2118,10 +2157,10 @@ function cleanupCompletionReplay(resultsDir, now, maxAgeMs) {
2118
2157
  }
2119
2158
  const archiveDir = path3.join(resultsDir, ARCHIVE_DIR_NAME);
2120
2159
  try {
2121
- for (const file of fs3.readdirSync(archiveDir)) {
2160
+ for (const file of fs4.readdirSync(archiveDir)) {
2122
2161
  const filePath = path3.join(archiveDir, file);
2123
2162
  try {
2124
- if (now - fs3.statSync(filePath).mtimeMs > maxAgeMs) fs3.rmSync(filePath, { force: true });
2163
+ if (now - fs4.statSync(filePath).mtimeMs > maxAgeMs) fs4.rmSync(filePath, { force: true });
2125
2164
  } catch {
2126
2165
  }
2127
2166
  }
@@ -2173,7 +2212,7 @@ function waitResultPayloadCandidate(resultsDir, run) {
2173
2212
  }
2174
2213
  function readWaitResultPayload(candidatePath, run) {
2175
2214
  if (!run.sessionId) return void 0;
2176
- const payload = JSON.parse(fs4.readFileSync(candidatePath, "utf-8"));
2215
+ const payload = JSON.parse(fs5.readFileSync(candidatePath, "utf-8"));
2177
2216
  if (!resultPayloadMatchesSessionRun(payload, run.sessionId, run.id)) return void 0;
2178
2217
  return payload;
2179
2218
  }
@@ -2333,7 +2372,7 @@ function collectWaitCompletions(terminal, state, resultsDir, onReference) {
2333
2372
  }
2334
2373
 
2335
2374
  // src/runs/background/resume-guidance.ts
2336
- import * as fs5 from "node:fs";
2375
+ import * as fs6 from "node:fs";
2337
2376
  var INTERCOM_DETACH_ERROR = "detached for intercom coordination";
2338
2377
  function isIntercomDetached(run) {
2339
2378
  return run.steps.some((step) => step.execution?.status === "detached" || errorWithoutReplyText(step.error)?.toLowerCase().includes(INTERCOM_DETACH_ERROR) === true) || errorWithoutReplyText(run.error)?.toLowerCase().includes(INTERCOM_DETACH_ERROR) === true;
@@ -2345,7 +2384,7 @@ function formatIntercomDetachGuidance(run) {
2345
2384
  function formatAsyncReviveCommand(run) {
2346
2385
  const step = run.steps.find((candidate) => candidate.status === "failed");
2347
2386
  const sessionFile = step?.sessionFile ?? (run.steps.length === 1 ? run.sessionFile : void 0);
2348
- if (!step || !sessionFile || !fs5.existsSync(sessionFile)) return void 0;
2387
+ if (!step || !sessionFile || !fs6.existsSync(sessionFile)) return void 0;
2349
2388
  try {
2350
2389
  const descriptor = readAsyncRecoveryDescriptor(run.asyncDir);
2351
2390
  if (!descriptor || descriptor.sourceRunId !== run.id || descriptor.agent !== step.agent) return void 0;
@@ -2670,13 +2709,13 @@ function readTranscriptActivity(transcriptPath) {
2670
2709
  if (!transcriptPath) return void 0;
2671
2710
  let fd;
2672
2711
  try {
2673
- const stat = fs6.statSync(transcriptPath);
2712
+ const stat = fs7.statSync(transcriptPath);
2674
2713
  if (!stat.isFile() || stat.size <= 0) return void 0;
2675
2714
  const start = Math.max(0, stat.size - TRANSCRIPT_TAIL_BYTES);
2676
2715
  const length = stat.size - start;
2677
2716
  const buffer = Buffer.allocUnsafe(length);
2678
- fd = fs6.openSync(transcriptPath, "r");
2679
- const bytesRead = fs6.readSync(fd, buffer, 0, length, start);
2717
+ fd = fs7.openSync(transcriptPath, "r");
2718
+ const bytesRead = fs7.readSync(fd, buffer, 0, length, start);
2680
2719
  let lines = buffer.subarray(0, bytesRead).toString("utf-8").split(/\r?\n/);
2681
2720
  if (start > 0) lines = lines.slice(1);
2682
2721
  let currentTool;
@@ -2721,7 +2760,7 @@ function readTranscriptActivity(transcriptPath) {
2721
2760
  } finally {
2722
2761
  if (fd !== void 0) {
2723
2762
  try {
2724
- fs6.closeSync(fd);
2763
+ fs7.closeSync(fd);
2725
2764
  } catch {
2726
2765
  }
2727
2766
  }
@@ -2974,7 +3013,8 @@ ${references2.join("\n")}` : ""}`,
2974
3013
  }
2975
3014
  const relevantAttention = attention.filter((run) => initialAsyncIds.has(run.id));
2976
3015
  const supervisorAttentionHint = relevantAttention.some(hasSupervisorTool) ? ' Reply to any pending supervisor request. If subagent_supervisor({ action: "pending" }) is empty, check intercom({ action: "pending" }) because an external intercom tool may own the request.' : "";
2977
- const attentionNote = relevantAttention.length > 0 ? ` ${relevantAttention.length} run(s) need attention: ${relevantAttention.map((run) => run.id).join(", ")} \u2014${supervisorAttentionHint} inspect with subagent({ action: "status" }) then steer a top-level live async child, resume a paused/completed/failed child, or interrupt explicitly.` : "";
3016
+ const keepWaitingHint = stopOnAttention && supervisorAttentionHint === "" && (waitForAll || finishedAsyncCount + providerFinishedCount === 0) ? " These runs are still running and none is waiting on a supervisor reply. To keep waiting through this kind of attention, call bg_wait again with stopOnAttention: false; supervisor requests still end that wait." : "";
3017
+ const attentionNote = relevantAttention.length > 0 ? ` ${relevantAttention.length} run(s) need attention: ${relevantAttention.map((run) => run.id).join(", ")} \u2014${supervisorAttentionHint} inspect with subagent({ action: "status" }) then steer a top-level live async child, resume a paused/completed/failed child, or interrupt explicitly.${keepWaitingHint}` : "";
2978
3018
  const stillRunning = active.filter((run) => initialAsyncIds.has(run.id)).length + providerActive.filter((item) => initialProviderIds.has(backgroundWorkIdentity(item))).length;
2979
3019
  const elapsed = formatDuration(now() - startedAt);
2980
3020
  const outcome = terminalSummary ? ` Outcome: ${terminalSummary}.` : "";
@@ -3368,7 +3408,7 @@ import { createHash as createHash3 } from "node:crypto";
3368
3408
  // src/watchdog/change-signature.ts
3369
3409
  import { spawnSync as spawnSync2 } from "node:child_process";
3370
3410
  import { createHash } from "node:crypto";
3371
- import * as fs7 from "node:fs";
3411
+ import * as fs8 from "node:fs";
3372
3412
  import * as os from "node:os";
3373
3413
  import * as path6 from "node:path";
3374
3414
  var IGNORED_CHANGE_PREFIXES = [`${PROJECT_SUBAGENTS_RELATIVE_DIR}/`, "tmp/", "node_modules/"];
@@ -3399,7 +3439,7 @@ function git(cwd2, args2) {
3399
3439
  function comparablePath(value) {
3400
3440
  let resolved = path6.resolve(value);
3401
3441
  try {
3402
- resolved = fs7.realpathSync.native(resolved);
3442
+ resolved = fs8.realpathSync.native(resolved);
3403
3443
  } catch {
3404
3444
  }
3405
3445
  return process.platform === "win32" ? resolved.toLowerCase() : resolved;
@@ -3431,7 +3471,7 @@ function useHashEntryBudget(budget) {
3431
3471
  return true;
3432
3472
  }
3433
3473
  function hashFile(filePath) {
3434
- return createHash("sha256").update(fs7.readFileSync(filePath)).digest("hex");
3474
+ return createHash("sha256").update(fs8.readFileSync(filePath)).digest("hex");
3435
3475
  }
3436
3476
  function largeFileHash(stat) {
3437
3477
  return "large:" + stat.size + ":" + Math.floor(stat.mtimeMs);
@@ -3471,17 +3511,17 @@ function hashPath(root, relPath, budget) {
3471
3511
  const fullPath = path6.join(root, normalized);
3472
3512
  let stat;
3473
3513
  try {
3474
- stat = fs7.lstatSync(fullPath);
3514
+ stat = fs8.lstatSync(fullPath);
3475
3515
  } catch (error) {
3476
3516
  if (error.code === "ENOENT") return { path: normalized, state: "deleted" };
3477
3517
  throw error;
3478
3518
  }
3479
3519
  if (stat.isSymbolicLink()) {
3480
- return { path: normalized, state: "symlink", target: fs7.readlinkSync(fullPath) };
3520
+ return { path: normalized, state: "symlink", target: fs8.readlinkSync(fullPath) };
3481
3521
  }
3482
3522
  if (stat.isDirectory()) {
3483
- if (fs7.existsSync(path6.join(fullPath, ".git"))) return gitWorktreeEntry(normalized, fullPath);
3484
- const entries = fs7.readdirSync(fullPath).map((entry) => normalizeRelPath(path6.posix.join(normalized, entry))).filter((entry) => !ignoredRelPath(entry)).sort();
3523
+ if (fs8.existsSync(path6.join(fullPath, ".git"))) return gitWorktreeEntry(normalized, fullPath);
3524
+ const entries = fs8.readdirSync(fullPath).map((entry) => normalizeRelPath(path6.posix.join(normalized, entry))).filter((entry) => !ignoredRelPath(entry)).sort();
3485
3525
  const remainingEntries = Math.max(0, budget.maxEntries - budget.entries);
3486
3526
  const selectedEntries = entries.slice(0, remainingEntries);
3487
3527
  const childEntries = selectedEntries.map((entry) => hashPath(root, entry, budget));
@@ -3659,7 +3699,7 @@ var WatchdogEmissionGuard = class {
3659
3699
  // src/watchdog/lsp-diagnostics.ts
3660
3700
  import { spawn } from "node:child_process";
3661
3701
  import { createHash as createHash2 } from "node:crypto";
3662
- import * as fs8 from "node:fs";
3702
+ import * as fs9 from "node:fs";
3663
3703
  import * as path7 from "node:path";
3664
3704
  import { pathToFileURL } from "node:url";
3665
3705
  var TS_JS_EXTENSIONS = /* @__PURE__ */ new Map([
@@ -3698,10 +3738,10 @@ function severityFromLsp(value) {
3698
3738
  }
3699
3739
  function pathExecutable(filePath) {
3700
3740
  try {
3701
- const stat = fs8.statSync(filePath);
3741
+ const stat = fs9.statSync(filePath);
3702
3742
  if (!stat.isFile()) return false;
3703
3743
  if (process.platform === "win32") return true;
3704
- fs8.accessSync(filePath, fs8.constants.X_OK);
3744
+ fs9.accessSync(filePath, fs9.constants.X_OK);
3705
3745
  return true;
3706
3746
  } catch {
3707
3747
  return false;
@@ -3738,7 +3778,7 @@ function collectTargetFiles(root, changedPaths, maxFiles) {
3738
3778
  }
3739
3779
  let stat;
3740
3780
  try {
3741
- stat = fs8.statSync(absPath);
3781
+ stat = fs9.statSync(absPath);
3742
3782
  } catch (error) {
3743
3783
  if (error.code === "ENOENT") {
3744
3784
  skippedPaths.push(relPath);
@@ -4032,7 +4072,7 @@ async function collectWithTypeScriptLanguageServer(input) {
4032
4072
  await client.request("initialize", initializeParams(input.root), remaining(), input.signal);
4033
4073
  client.notify("initialized", {});
4034
4074
  for (const target of input.targets) {
4035
- const text = fs8.readFileSync(target.absPath, "utf-8");
4075
+ const text = fs9.readFileSync(target.absPath, "utf-8");
4036
4076
  client.notify("textDocument/didOpen", {
4037
4077
  textDocument: { uri: target.uri, languageId: target.languageId, version: 1, text }
4038
4078
  });
@@ -5069,12 +5109,12 @@ import { createReadOnlyTools, convertToLlm } from "@earendil-works/pi-coding-age
5069
5109
  import { Type as Type4 } from "typebox";
5070
5110
 
5071
5111
  // src/watchdog/guidance.ts
5072
- import * as fs9 from "node:fs";
5112
+ import * as fs10 from "node:fs";
5073
5113
  import * as path8 from "node:path";
5074
5114
  var WATCHDOG_GUIDANCE_MAX_CHARS = 8e3;
5075
5115
  function readOptional(filePath) {
5076
5116
  try {
5077
- return fs9.readFileSync(filePath, "utf-8").trim();
5117
+ return fs10.readFileSync(filePath, "utf-8").trim();
5078
5118
  } catch {
5079
5119
  return "";
5080
5120
  }
@@ -5381,6 +5421,7 @@ export {
5381
5421
  registerNativeSupervisorClient,
5382
5422
  createNativeSupervisorChannel,
5383
5423
  resolveCurrentSessionId,
5424
+ resolvePiSessionId,
5384
5425
  WATCHDOG_DIFF_TOOL_NAME,
5385
5426
  captureWatchdogDiffBaseline,
5386
5427
  startWatchdogDiffBaselineCapture,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-7F6RKT6W.js";
4
4
  import {
5
5
  getAgentDir
6
- } from "./chunk-ZBC44JJ3.js";
6
+ } from "./chunk-CIZQXJ5Q.js";
7
7
 
8
8
  // src/intercom/intercom-bridge.ts
9
9
  import * as fs from "node:fs";
@@ -8,7 +8,7 @@ import {
8
8
  validateCodeOwnedProfileRunner,
9
9
  validatePermissionRules,
10
10
  validateToolBudgetConfig
11
- } from "./chunk-ZBC44JJ3.js";
11
+ } from "./chunk-CIZQXJ5Q.js";
12
12
 
13
13
  // src/agents/runtime-agent-registry.ts
14
14
  var RUNTIME_AGENT_REGISTRY_KEY = "pi-subagents.runtime-agents.v1";