pi-subagents 0.82.1 → 0.83.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 (94) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/bundle/agents.js +5 -5
  3. package/bundle/background-work.js +1 -1
  4. package/bundle/capability-ceiling.js +1 -1
  5. package/bundle/child-tool-plan.js +4 -4
  6. package/bundle/{chunk-RMQFMMAT.js → chunk-2D52JFLF.js} +231 -10
  7. package/bundle/{chunk-52UBALJL.js → chunk-2DHZTCOL.js} +2 -2
  8. package/bundle/{chunk-43SCHIMD.js → chunk-2S4K53MV.js} +1 -1
  9. package/bundle/{chunk-IVAE5Z6Q.js → chunk-5YIITCPD.js} +31 -27
  10. package/bundle/{chunk-JYUKW2SY.js → chunk-AHIFYGR3.js} +13 -13
  11. package/bundle/{chunk-XSWOTIA3.js → chunk-C5P5CHYK.js} +1 -1
  12. package/bundle/{chunk-PDZWJCHD.js → chunk-C7JMPU5F.js} +10 -7
  13. package/bundle/{chunk-5TYMSZX3.js → chunk-D3JAFGMO.js} +2 -2
  14. package/bundle/{chunk-OYF6AFDY.js → chunk-F4ASL6OV.js} +2 -2
  15. package/bundle/{chunk-ZIV4J4HG.js → chunk-F5DBXJ2G.js} +51 -34
  16. package/bundle/{chunk-YKEWIB4M.js → chunk-G2Z6ZH26.js} +1 -1
  17. package/bundle/{chunk-G4GZD3OJ.js → chunk-IPGZMQXV.js} +11 -11
  18. package/bundle/{chunk-5LFLVSTM.js → chunk-JEZOSEWG.js} +2 -0
  19. package/bundle/{chunk-PLCCBLPY.js → chunk-LFDBD4PW.js} +2 -2
  20. package/bundle/{chunk-CIZQXJ5Q.js → chunk-LNRJCP2Y.js} +56 -20
  21. package/bundle/{chunk-UTT254JE.js → chunk-MABL3FUM.js} +8 -4
  22. package/bundle/{chunk-3JCDWF4V.js → chunk-NPIYWVOD.js} +12 -18
  23. package/bundle/{chunk-UCPP4GNU.js → chunk-QP5ZWNIS.js} +12 -5
  24. package/bundle/{chunk-Z7KVHQHL.js → chunk-QXASAHIA.js} +2 -2
  25. package/bundle/{chunk-46XKCPJR.js → chunk-RNIZLSEA.js} +2221 -3260
  26. package/bundle/{chunk-GJECHSAR.js → chunk-SSG7IEP5.js} +2 -2
  27. package/bundle/{chunk-VSUSLDNW.js → chunk-UFL7IYCW.js} +10 -8
  28. package/bundle/{chunk-QE4AGIMG.js → chunk-UUP372DR.js} +482 -705
  29. package/bundle/{chunk-6XJB7PIX.js → chunk-UYK5MZWE.js} +16 -12
  30. package/bundle/{chunk-4SDU2BZX.js → chunk-V2BZYLEP.js} +3 -3
  31. package/bundle/{chunk-FXUXCX2K.js → chunk-VLFZIN6D.js} +6 -6
  32. package/bundle/{chunk-N2BN7BF5.js → chunk-XA3DY6UG.js} +7 -5
  33. package/bundle/{chunk-PBK2I7WY.js → chunk-YXFJVCOL.js} +6 -6
  34. package/bundle/{chunk-4Y2ROR7L.js → chunk-ZVOAMTUQ.js} +5 -5
  35. package/bundle/control-channel.js +4 -4
  36. package/bundle/index.js +1 -1
  37. package/bundle/intercom-bridge.js +4 -4
  38. package/bundle/preflight.js +10 -10
  39. package/bundle/project-panes.js +5 -5
  40. package/bundle/shared-types.js +1 -1
  41. package/docs/configuration.md +13 -2
  42. package/docs/extension-api.md +21 -4
  43. package/docs/missions.md +2 -0
  44. package/docs/observability.md +1 -0
  45. package/docs/tool-reference.md +2 -2
  46. package/package.json +1 -1
  47. package/skills/pi-subagents/SKILL.md +6 -6
  48. package/src/agents/agent-management.d.ts +1 -1
  49. package/src/agents/agent-management.js +10 -16
  50. package/src/agents/agent-serializer.js +1 -2
  51. package/src/agents/agents.js +20 -5
  52. package/src/agents/frontmatter.js +22 -18
  53. package/src/api/background-work.d.ts +9 -6
  54. package/src/api/background-work.js +14 -7
  55. package/src/extension/index.js +6 -3
  56. package/src/extension/public-execution.d.ts +2 -2
  57. package/src/extension/public-execution.js +3 -3
  58. package/src/extension/reply-workflow-script.js +4 -5
  59. package/src/extension/rpc.js +3 -1
  60. package/src/extension/subagent-options.js +17 -4
  61. package/src/missions/actions.js +7 -2
  62. package/src/missions/lifecycle.d.ts +11 -0
  63. package/src/missions/lifecycle.js +37 -6
  64. package/src/missions/store.js +1 -0
  65. package/src/missions/types.d.ts +2 -0
  66. package/src/runs/background/async-execution.d.ts +1 -1
  67. package/src/runs/background/async-execution.js +7 -4
  68. package/src/runs/background/async-job-tracker.js +2 -1
  69. package/src/runs/background/async-resume.js +3 -2
  70. package/src/runs/background/auto-drain.js +2 -3
  71. package/src/runs/background/fleet-view.js +1 -1
  72. package/src/runs/background/retained-children.js +1 -1
  73. package/src/runs/background/run-child-session.js +22 -6
  74. package/src/runs/background/subagent-wait.d.ts +2 -1
  75. package/src/runs/background/subagent-wait.js +5 -2
  76. package/src/runs/foreground/execution.js +22 -6
  77. package/src/runs/foreground/subagent-executor.js +26 -56
  78. package/src/runs/shared/capability-ceiling.d.ts +2 -1
  79. package/src/runs/shared/capability-ceiling.js +3 -2
  80. package/src/runs/shared/child-launch.js +5 -2
  81. package/src/runs/shared/child-session.d.ts +6 -0
  82. package/src/runs/shared/child-session.js +20 -4
  83. package/src/runs/shared/herdr-machine.d.ts +2 -0
  84. package/src/runs/shared/herdr-machine.js +2 -0
  85. package/src/runs/shared/herdr-placed-run.js +11 -4
  86. package/src/runs/shared/parallel-handoff.d.ts +1 -1
  87. package/src/runs/shared/parallel-handoff.js +10 -6
  88. package/src/runs/shared/subagent-prompt-runtime.js +11 -17
  89. package/src/shared/disabled-features.d.ts +3 -1
  90. package/src/shared/disabled-features.js +11 -3
  91. package/src/shared/types.d.ts +4 -2
  92. package/src/shared/types.js +2 -0
  93. package/src/workflows/scripted-workflow.js +13 -1071
  94. package/workflow-script-worker.cjs +1068 -0
@@ -39,10 +39,10 @@ import {
39
39
  validateModelResponseAliases,
40
40
  withWorkflowChildRunModel,
41
41
  withWorktreeTransaction
42
- } from "./chunk-46XKCPJR.js";
42
+ } from "./chunk-RNIZLSEA.js";
43
43
  import {
44
44
  validateIntercomBridgeConfig
45
- } from "./chunk-XSWOTIA3.js";
45
+ } from "./chunk-C5P5CHYK.js";
46
46
  import {
47
47
  stableJsonDigest
48
48
  } from "./chunk-7F6RKT6W.js";
@@ -73,12 +73,12 @@ import {
73
73
  validateToolBudgetConfig,
74
74
  waitForFileSystemRetry,
75
75
  writeAtomicJson
76
- } from "./chunk-CIZQXJ5Q.js";
76
+ } from "./chunk-LNRJCP2Y.js";
77
77
  import {
78
78
  DIRS,
79
79
  RUNNER_LAUNCHER_NAME_PATTERN,
80
80
  TEMP_ROOT_DIR
81
- } from "./chunk-5LFLVSTM.js";
81
+ } from "./chunk-JEZOSEWG.js";
82
82
  import {
83
83
  previewDisplayText,
84
84
  sanitizeDisplayText,
@@ -88,7 +88,7 @@ import {
88
88
  intersectSubagentCapabilityCeilings,
89
89
  normalizeCapabilityCeilingAllowedAgents,
90
90
  parseSubagentCapabilityCeiling
91
- } from "./chunk-Z7KVHQHL.js";
91
+ } from "./chunk-QXASAHIA.js";
92
92
 
93
93
  // src/shared/session-succession.ts
94
94
  var SUCCESSION_KEY = /* @__PURE__ */ Symbol.for("pi-subagents.session-succession");
@@ -2850,18 +2850,21 @@ async function protectRetainedWorktreeForResume(manifestPath, runId, childIndex,
2850
2850
  return cwd;
2851
2851
  }), { signal }));
2852
2852
  }
2853
- function resolveRetainedWorktreeCwd(manifestPath, runId, childIndex) {
2853
+ function resolveRetainedWorktreeCwd(manifestPath, runId, childIndex, recordedWorktreePath) {
2854
2854
  const manifest = readParallelHandoffManifest(manifestPath);
2855
- if (!manifest) return void 0;
2856
- if (manifest.runId !== runId) throw new Error(`Managed worktree handoff belongs to run '${manifest.runId}', not '${runId}'.`);
2857
- const match = manifest.groups.flatMap((group) => group.children.map((child) => ({ group, child }))).find(({ child }) => child.index === childIndex);
2858
- if (!match) return void 0;
2855
+ if (manifest && manifest.runId !== runId) throw new Error(`Managed worktree handoff belongs to run '${manifest.runId}', not '${runId}'.`);
2856
+ const match = manifest?.groups.flatMap((group) => group.children.map((child) => ({ group, child }))).find(({ child }) => child.index === childIndex);
2857
+ if (!manifest || !match) {
2858
+ if (recordedWorktreePath) throw new Error(`Async run '${runId}' child ${childIndex} ran in managed worktree ${recordedWorktreePath}, but its handoff has no resumable record yet. Retry after the run settles; if it already ended, inspect ${manifestPath}.`);
2859
+ return void 0;
2860
+ }
2859
2861
  const cleanup = match.group.cleanup.tasks.find((task) => task.index === match.child.taskIndex);
2860
2862
  if (!cleanup) throw new Error(`Async run '${runId}' child ${childIndex} has no managed worktree cleanup record.`);
2861
2863
  const relativeCwd = path5.relative(resolveExistingPath(match.group.repoRoot), resolveExistingPath(manifest.cwd));
2862
2864
  if (path5.isAbsolute(relativeCwd) || relativeCwd === ".." || relativeCwd.startsWith(`..${path5.sep}`)) throw new Error(`Async run '${runId}' has an invalid managed worktree cwd.`);
2863
2865
  const requiredCwd = path5.join(cleanup.path, relativeCwd);
2864
2866
  if (cleanup.worktreeRemoved || cleanup.branchRemoved) throw new Error(`Async run '${runId}' required managed worktree was removed: ${requiredCwd}`);
2867
+ if (cleanup.reason?.includes("pending durable handoff capture")) throw new Error(`Async run '${runId}' child ${childIndex} is still finalizing its managed worktree: ${requiredCwd}. Retry after the run settles; if it already ended, inspect ${manifestPath}.`);
2865
2868
  let worktreeRoot = "";
2866
2869
  let resolvedRequiredCwd = "";
2867
2870
  try {
@@ -3813,7 +3816,8 @@ function resolveAsyncResumeTarget(params, deps = {}, options = {}) {
3813
3816
  const requireSessionFile = options.requireSessionFile ?? true;
3814
3817
  const location = resolveAsyncRunLocation(params, asyncDirRoot, resultsDir);
3815
3818
  if (!location.asyncDir && !location.resultPath) {
3816
- throw new Error("Async run not found. Provide id or dir.");
3819
+ const requested = params.id ?? params.runId;
3820
+ throw new Error(requested ? `Async run not found for '${requested}'.` : "Async run not found. Provide id or dir.");
3817
3821
  }
3818
3822
  const reconciliation = location.asyncDir ? reconcileAsyncRun(location.asyncDir, { resultsDir, kill: deps.kill, now: deps.now }) : void 0;
3819
3823
  const status = reconciliation?.status ?? null;
@@ -3913,7 +3917,7 @@ function resolveAsyncResumeTarget(params, deps = {}, options = {}) {
3913
3917
  const stepThinking = statusSteps[index]?.thinking ?? resultSteps[index]?.thinking ?? (stepCount === 1 ? result?.thinking : void 0);
3914
3918
  const thinkingCeiling = statusSteps[index]?.thinkingCeiling ?? (stepCount === 1 ? recoveryDescriptor?.thinkingCeiling : void 0);
3915
3919
  const capabilityCeiling = mode === "workflow" ? intersectSubagentCapabilityCeilings(status?.admissionCapabilityCeiling, result?.admissionCapabilityCeiling) : intersectSubagentCapabilityCeilings(status?.capabilityCeiling, statusSteps[index]?.capabilityCeiling, result?.capabilityCeiling, resultSteps[index]?.capabilityCeiling);
3916
- const managedWorktreeCwd = location.asyncDir ? resolveRetainedWorktreeCwd(parallelHandoffPath(location.asyncDir), runId, index) : void 0;
3920
+ const managedWorktreeCwd = location.asyncDir ? resolveRetainedWorktreeCwd(parallelHandoffPath(location.asyncDir), runId, index, statusSteps[index]?.worktreePath) : void 0;
3917
3921
  const resumeCwd = validateResumeCwd(runId, managedWorktreeCwd ?? status?.cwd ?? result?.cwd ?? recoveryDescriptor?.cwd);
3918
3922
  return {
3919
3923
  kind: "revive",
@@ -7,15 +7,15 @@ import {
7
7
  getAgentDir,
8
8
  getConfigDirName,
9
9
  getProjectConfigDir
10
- } from "./chunk-CIZQXJ5Q.js";
10
+ } from "./chunk-LNRJCP2Y.js";
11
11
  import {
12
12
  TEMP_ROOT_DIR
13
- } from "./chunk-5LFLVSTM.js";
13
+ } from "./chunk-JEZOSEWG.js";
14
14
  import {
15
15
  capabilityCeilingAgentRestrictionSources,
16
16
  intersectSubagentCapabilityCeilings,
17
17
  isAgentAllowedByCapabilityCeiling
18
- } from "./chunk-Z7KVHQHL.js";
18
+ } from "./chunk-QXASAHIA.js";
19
19
 
20
20
  // src/runs/shared/child-tool-plan.ts
21
21
  import { createHash as createHash2 } from "node:crypto";
@@ -13,7 +13,7 @@ import {
13
13
  summarizeContextModes,
14
14
  utf8Tail,
15
15
  workflowPreflightLaneForRuntimeKey
16
- } from "./chunk-6XJB7PIX.js";
16
+ } from "./chunk-UYK5MZWE.js";
17
17
  import {
18
18
  assertSafeNestedId,
19
19
  checkRecordedPidLiveness,
@@ -32,11 +32,11 @@ import {
32
32
  updateActiveRunIndex,
33
33
  validateModelResponseAliases,
34
34
  writeAsyncResultFile
35
- } from "./chunk-46XKCPJR.js";
35
+ } from "./chunk-RNIZLSEA.js";
36
36
  import {
37
37
  deliverStopRequest,
38
38
  stopInboxClosedPath
39
- } from "./chunk-OYF6AFDY.js";
39
+ } from "./chunk-F4ASL6OV.js";
40
40
  import {
41
41
  SUBAGENT_STOPPED_MESSAGE,
42
42
  formatDuration,
@@ -47,10 +47,10 @@ import {
47
47
  validateAcceptanceInput,
48
48
  writeAtomicJson,
49
49
  writePrivateAtomicJson
50
- } from "./chunk-CIZQXJ5Q.js";
50
+ } from "./chunk-LNRJCP2Y.js";
51
51
  import {
52
52
  DIRS
53
- } from "./chunk-5LFLVSTM.js";
53
+ } from "./chunk-JEZOSEWG.js";
54
54
  import {
55
55
  safeTerminalText,
56
56
  truncateDisplayText
@@ -292,7 +292,7 @@ function sessionMessageParts(record) {
292
292
  }
293
293
  if (entry.type === "toolCall" || entry.type === "tool_call") {
294
294
  const name = typeof entry.name === "string" ? entry.name : typeof entry.toolName === "string" ? entry.toolName : "tool";
295
- parts.push({ role, kind: "toolCall", name, text: `[tool: ${name}${entry.args === void 0 ? "" : ` ${stringifyJsonPreview(entry.args)}`}]` });
295
+ parts.push({ role, kind: "toolCall", name, text: `[tool: ${name}${entry.arguments === void 0 ? "" : ` ${stringifyJsonPreview(entry.arguments)}`}]` });
296
296
  continue;
297
297
  }
298
298
  if (entry.type === "toolResult" || entry.type === "tool_result") {
@@ -104,14 +104,16 @@ function listBackgroundWorkWakeChannels() {
104
104
  }
105
105
  return [...channels];
106
106
  }
107
- function snapshotBackgroundWork(sessionId, nowMs = Date.now()) {
108
- validateString(sessionId, "Background-work snapshot sessionId", MAX_SESSION_ID_LENGTH);
107
+ function snapshotBackgroundWork(sessionIds, nowMs = Date.now()) {
108
+ const accepted = [...new Set(sessionIds.map((value) => validateString(value, "Background-work snapshot sessionId", MAX_SESSION_ID_LENGTH)))];
109
+ const sessionId = accepted[0];
110
+ if (sessionId === void 0) throw new Error("Background-work snapshot needs at least one session id.");
109
111
  const providers = listBackgroundWorkProviders();
110
112
  const items = [];
111
113
  const identities = /* @__PURE__ */ new Set();
112
114
  for (const provider of providers) {
113
115
  try {
114
- provider.reconcile?.({ sessionId, nowMs });
116
+ provider.reconcile?.({ sessionId, sessionIds: [...accepted], nowMs });
115
117
  } catch (error) {
116
118
  throw new Error(
117
119
  `Background-work provider '${provider.name}' reconcile failed: ${error instanceof Error ? error.message : String(error)}`,
@@ -120,7 +122,7 @@ function snapshotBackgroundWork(sessionId, nowMs = Date.now()) {
120
122
  }
121
123
  let active;
122
124
  try {
123
- active = provider.listActiveWork({ sessionId, nowMs });
125
+ active = provider.listActiveWork({ sessionId, sessionIds: [...accepted], nowMs });
124
126
  } catch (error) {
125
127
  throw new Error(
126
128
  `Background-work provider '${provider.name}' listActiveWork failed: ${error instanceof Error ? error.message : String(error)}`,
@@ -140,7 +142,7 @@ function snapshotBackgroundWork(sessionId, nowMs = Date.now()) {
140
142
  throw new Error(`Background-work provider '${provider.name}' returned duplicate item '${item.id}' for session '${item.sessionId}'.`);
141
143
  }
142
144
  identities.add(identity);
143
- if (item.sessionId === sessionId) items.push({ provider: provider.name, ...item });
145
+ if (accepted.includes(item.sessionId)) items.push({ provider: provider.name, ...item });
144
146
  });
145
147
  }
146
148
  return {
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  isTrustedRecordedSessionFile,
3
3
  resolveSubagentRunId
4
- } from "./chunk-FXUXCX2K.js";
4
+ } from "./chunk-VLFZIN6D.js";
5
5
  import {
6
6
  agentStreamOptions,
7
7
  opencodeSessionHeaders,
8
8
  ownsRun,
9
9
  resolveAsyncResumeTarget
10
- } from "./chunk-6XJB7PIX.js";
10
+ } from "./chunk-UYK5MZWE.js";
11
11
  import {
12
12
  currentCompletionOwnerId,
13
13
  listMissions,
@@ -16,12 +16,12 @@ import {
16
16
  reconcileAsyncRun,
17
17
  resolveAuthorityDecision,
18
18
  resolveMissionStoreLocation
19
- } from "./chunk-46XKCPJR.js";
19
+ } from "./chunk-RNIZLSEA.js";
20
20
  import {
21
21
  deliverInterruptRequest,
22
22
  queueRevivalBrief,
23
23
  requestAsyncSteer
24
- } from "./chunk-OYF6AFDY.js";
24
+ } from "./chunk-F4ASL6OV.js";
25
25
  import {
26
26
  formatShellCommand
27
27
  } from "./chunk-7J4ZXMY7.js";
@@ -32,10 +32,10 @@ import {
32
32
  tryLease,
33
33
  writeAtomicJson,
34
34
  writePrivateAtomicJson
35
- } from "./chunk-CIZQXJ5Q.js";
35
+ } from "./chunk-LNRJCP2Y.js";
36
36
  import {
37
37
  DIRS
38
- } from "./chunk-5LFLVSTM.js";
38
+ } from "./chunk-JEZOSEWG.js";
39
39
  import {
40
40
  previewDisplayText,
41
41
  safeTerminalText
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildWorkflowChatProgressRows
3
- } from "./chunk-FXUXCX2K.js";
3
+ } from "./chunk-VLFZIN6D.js";
4
4
  import {
5
5
  aggregateStepStatus,
6
6
  contextModeBadge,
@@ -25,13 +25,13 @@ import {
25
25
  projectWorkflowChecklist,
26
26
  withCachedUiContext,
27
27
  workflowGraphStageNodes
28
- } from "./chunk-6XJB7PIX.js";
28
+ } from "./chunk-UYK5MZWE.js";
29
29
  import {
30
30
  flatToLogicalStepIndex,
31
31
  formatWorkflowJsonPreview,
32
32
  hostStepReportName,
33
33
  hostStepVerdictLabel
34
- } from "./chunk-46XKCPJR.js";
34
+ } from "./chunk-RNIZLSEA.js";
35
35
  import {
36
36
  snapshotExternalRuns
37
37
  } from "./chunk-UKG4V45O.js";
@@ -49,12 +49,12 @@ import {
49
49
  getSingleResultOutput,
50
50
  shortenPath,
51
51
  unresolvedChildWatchdogBlockers
52
- } from "./chunk-CIZQXJ5Q.js";
52
+ } from "./chunk-LNRJCP2Y.js";
53
53
  import {
54
54
  MAX_WIDGET_JOBS,
55
55
  WIDGET_ANIMATION_INTERVAL_MS,
56
56
  WIDGET_KEY
57
- } from "./chunk-5LFLVSTM.js";
57
+ } from "./chunk-JEZOSEWG.js";
58
58
  import {
59
59
  previewDisplayText,
60
60
  sanitizeDisplayText,
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  requestAsyncStop
3
- } from "./chunk-OYF6AFDY.js";
3
+ } from "./chunk-F4ASL6OV.js";
4
4
  import "./chunk-NIXWDZZV.js";
5
- import "./chunk-CIZQXJ5Q.js";
6
- import "./chunk-5LFLVSTM.js";
5
+ import "./chunk-LNRJCP2Y.js";
6
+ import "./chunk-JEZOSEWG.js";
7
7
  import "./chunk-YFCK7H2S.js";
8
- import "./chunk-Z7KVHQHL.js";
8
+ import "./chunk-QXASAHIA.js";
9
9
  export {
10
10
  requestAsyncStop
11
11
  };
package/bundle/index.js CHANGED
@@ -17,7 +17,7 @@ function readInstalledPackageVersion() {
17
17
  var loadedPackageVersion = readInstalledPackageVersion();
18
18
 
19
19
  // index.ts
20
- var registerExtension = process.env[HERDR_PI_MODE_ENV] === "1" ? (await import("./chunk-JYUKW2SY.js")).default : process.env.PI_SUBAGENT_CHILD === "1" ? void 0 : (await import("./chunk-IVAE5Z6Q.js")).default;
20
+ var registerExtension = process.env[HERDR_PI_MODE_ENV] === "1" ? (await import("./chunk-AHIFYGR3.js")).default : process.env.PI_SUBAGENT_CHILD === "1" ? void 0 : (await import("./chunk-5YIITCPD.js")).default;
21
21
  function registerSubagentExtension(pi) {
22
22
  const installedVersion = readInstalledPackageVersion();
23
23
  if (installedVersion !== loadedPackageVersion) {
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  resolveIntercomSessionTarget
3
- } from "./chunk-XSWOTIA3.js";
3
+ } from "./chunk-C5P5CHYK.js";
4
4
  import "./chunk-7F6RKT6W.js";
5
- import "./chunk-CIZQXJ5Q.js";
6
- import "./chunk-5LFLVSTM.js";
5
+ import "./chunk-LNRJCP2Y.js";
6
+ import "./chunk-JEZOSEWG.js";
7
7
  import "./chunk-YFCK7H2S.js";
8
- import "./chunk-Z7KVHQHL.js";
8
+ import "./chunk-QXASAHIA.js";
9
9
  export {
10
10
  resolveIntercomSessionTarget
11
11
  };
@@ -2,22 +2,22 @@ import {
2
2
  buildEffectiveSystemPrompt,
3
3
  canPreferForkFromSnapshot,
4
4
  resolveSubagentLaunchContext
5
- } from "./chunk-GJECHSAR.js";
6
- import "./chunk-PLCCBLPY.js";
5
+ } from "./chunk-SSG7IEP5.js";
6
+ import "./chunk-LFDBD4PW.js";
7
7
  import {
8
8
  loadConfig
9
- } from "./chunk-UCPP4GNU.js";
9
+ } from "./chunk-QP5ZWNIS.js";
10
10
  import {
11
11
  nestedResultsPath,
12
12
  processTerminalCandidatePath,
13
13
  processTerminalPath,
14
14
  resultFilePath
15
- } from "./chunk-46XKCPJR.js";
15
+ } from "./chunk-RNIZLSEA.js";
16
16
  import {
17
17
  applyIntercomBridgeToAgent,
18
18
  resolveIntercomBridge,
19
19
  validateIntercomBridgeConfig
20
- } from "./chunk-XSWOTIA3.js";
20
+ } from "./chunk-C5P5CHYK.js";
21
21
  import {
22
22
  AGENT_DEFINITION_PROJECTION_VERSION,
23
23
  resolveLaunchBinding,
@@ -26,7 +26,7 @@ import {
26
26
  import {
27
27
  applyThinkingSuffix,
28
28
  resolvePiLaunchToolPlan
29
- } from "./chunk-4SDU2BZX.js";
29
+ } from "./chunk-V2BZYLEP.js";
30
30
  import {
31
31
  assertRequiredChildExtensionsAdmitted,
32
32
  resolveRequiredChildExtensions
@@ -34,7 +34,7 @@ import {
34
34
  import {
35
35
  getArtifactPaths,
36
36
  getArtifactsDir
37
- } from "./chunk-5TYMSZX3.js";
37
+ } from "./chunk-D3JAFGMO.js";
38
38
  import {
39
39
  assertClaudeCodeModelScope,
40
40
  assertThinkingWithinCeiling,
@@ -61,17 +61,17 @@ import {
61
61
  resolveSkillsWithFallback,
62
62
  resolveStepBehavior,
63
63
  unknownAgentDiagnosticContext
64
- } from "./chunk-CIZQXJ5Q.js";
64
+ } from "./chunk-LNRJCP2Y.js";
65
65
  import {
66
66
  DIRS,
67
67
  SUBAGENT_LIFECYCLE_ARTIFACT_VERSION,
68
68
  TEMP_ROOT_DIR
69
- } from "./chunk-5LFLVSTM.js";
69
+ } from "./chunk-JEZOSEWG.js";
70
70
  import "./chunk-YFCK7H2S.js";
71
71
  import {
72
72
  capabilityCeilingAgentRestrictionMessage,
73
73
  intersectSubagentCapabilityCeilings
74
- } from "./chunk-Z7KVHQHL.js";
74
+ } from "./chunk-QXASAHIA.js";
75
75
 
76
76
  // src/api/preflight.ts
77
77
  import * as fs from "node:fs";
@@ -8,13 +8,13 @@ import {
8
8
  openProjectPane,
9
9
  projectPaneBindingPath,
10
10
  readProjectPaneBinding
11
- } from "./chunk-52UBALJL.js";
11
+ } from "./chunk-2DHZTCOL.js";
12
12
  import "./chunk-7J4ZXMY7.js";
13
- import "./chunk-5TYMSZX3.js";
14
- import "./chunk-CIZQXJ5Q.js";
15
- import "./chunk-5LFLVSTM.js";
13
+ import "./chunk-D3JAFGMO.js";
14
+ import "./chunk-LNRJCP2Y.js";
15
+ import "./chunk-JEZOSEWG.js";
16
16
  import "./chunk-YFCK7H2S.js";
17
- import "./chunk-Z7KVHQHL.js";
17
+ import "./chunk-QXASAHIA.js";
18
18
  export {
19
19
  PROJECT_PANES_API_VERSION,
20
20
  PROJECT_PANE_TRUST_STATUS,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DEFAULT_FORK_PREAMBLE,
3
3
  wrapForkTask
4
- } from "./chunk-5LFLVSTM.js";
4
+ } from "./chunk-JEZOSEWG.js";
5
5
  export {
6
6
  DEFAULT_FORK_PREAMBLE,
7
7
  wrapForkTask
@@ -124,7 +124,7 @@ Pi records each tool definition and prompt section a session declares, and decla
124
124
  { "disabledFeatures": ["watchdog", "panes", "preflight", "lane-metadata", "gates"] }
125
125
  ```
126
126
 
127
- Removes feature groups you do not use from the `subagent` tool. Each listed feature loses its top-level parameters from the model-facing schema and its `options` keys are rejected, and any request that still uses one of its parameters or actions fails with an error naming this setting. The check covers the parent tool, fanout-child tools, RPC, slash commands, prompt templates, scheduled launches, delegated launches, and workflow `runs.run`/`runs.all`/`runs.lanes` children, which are rejected before they launch. The built-in tool descriptions, the unknown-action list, the fanout-child tool description, and RPC `ping` no longer mention disabled features, and `{ action: "guide", options: { topic: "tool-reference" } }` starts with a notice listing what is disabled. Custom tool descriptions are not changed. Nothing is disabled by default, and the default schema and description are unchanged. An unknown or duplicate feature name fails config loading rather than silently re-enabling every feature.
127
+ Removes feature groups you do not use from the `subagent` tool. Each listed feature loses its top-level parameters from the model-facing schema and its `options` keys are rejected, and any request that still uses one of its parameters or actions fails with an error naming this setting. The check covers the parent tool, fanout-child tools, RPC, slash commands, prompt templates, scheduled launches, delegated launches, and workflow `runs.run`/`runs.all`/`runs.lanes` children, which are rejected before they launch. The built-in tool descriptions, the unknown-action list, the fanout-child tool description, and RPC `ping` no longer mention disabled features. Every `{ action: "guide" }` response starts with a notice: a topic lists what is disabled, and a section points to the `tool-reference` topic for that list. With `workflow-scripts` disabled, the notice also says to use the top-level `tasks` or `chain` fields instead. Custom tool descriptions are not changed. Nothing is disabled by default, and the default schema and description are unchanged. An unknown or duplicate feature name fails config loading rather than silently re-enabling every feature.
128
128
 
129
129
  | Feature | Parameters removed | Actions rejected |
130
130
  |---|---|---|
@@ -202,7 +202,18 @@ With `"summary"`, a tool result looks like this:
202
202
 
203
203
  Set to `false` to register none of the pi-subagents slash commands (`/run`, `/subagents`, `/subagents-fleet`, `/subagents-watchdog`, `/prompt-workflow`, and the rest) and no [`foregroundDetachShortcut`](#foregrounddetachshortcut). The `subagent` tool, RPC, the async widget, and the extension's other features are unchanged. Prompt templates whose frontmatter has `chain:` launch through `/prompt-workflow`, so they stop working too. Defaults to `true`. Restart Pi or run `/reload` after changing it.
204
204
 
205
- The package's prompt shortcuts, such as `/parallel-review` and `/review-loop`, are Pi prompt templates, not commands, so this setting leaves them alone. Pi's package filter removes them: `{ "packages": [{ "source": "npm:pi-subagents", "prompts": [] }] }` in Pi's `settings.json`, or `pi config`.
205
+ The package's prompt shortcuts, such as `/parallel-review` and `/review-loop`, are Pi prompt templates, not commands, so this setting leaves them alone. The same goes for its skills (`pi-subagents` and `council-mode`) and built-in agents. To turn them off, use Pi's package filter for prompts and skills and `disableBuiltins` for the agents, in Pi's `settings.json`. This turns off every prompt, the `council-mode` skill and every built-in agent:
206
+
207
+ ```json
208
+ {
209
+ "packages": [
210
+ { "source": "npm:pi-subagents", "prompts": [], "skills": ["!council-mode"] }
211
+ ],
212
+ "subagents": { "disableBuiltins": true }
213
+ }
214
+ ```
215
+
216
+ A `!` entry such as `"!review-loop.md"` drops one file, and `[]` drops all of that type. `subagents.agentOverrides.<name>.disabled: true` turns off one built-in agent instead of all of them ([agents.md](agents.md)). `pi config` toggles the package's prompts and skills interactively.
206
217
 
207
218
  ## `foregroundDetachShortcut`
208
219
 
@@ -129,6 +129,7 @@ Method notes:
129
129
  Capability advertisements on `ping`:
130
130
 
131
131
  - `events.asyncComplete` — exact process-local completion correlation after RPC `spawn`.
132
+ - `events.jobsChanged`, `events.asyncStarted`, `events.childStatus`, `events.processTerminal` — the event names a host can listen to instead of polling `status` (see [Refresh a host view without polling](#refresh-a-host-view-without-polling)).
132
133
  - `managementActions` — exact schedule management actions accepted by RPC `manage`.
133
134
  - `launchResolvedExtensions` — the optional launch-resolved extension projection in status details.
134
135
  - `runtimeAcknowledgedExtensions` — the optional child-runtime acknowledgement projection and event name.
@@ -141,6 +142,20 @@ Capability advertisements on `ping`:
141
142
 
142
143
  Structured delegation progress updates carry `runId` as soon as foreground execution allocates it, so a caller can retain the package-owned revival target even if its own tool turn is interrupted before the terminal response. Foreground `details.results[]` rows also include a numeric `index` that is unique within the run and stable across partial progress snapshots and the final result; use `(runId, index)` instead of row position to correlate single, counted parallel, and chain children.
143
144
 
145
+ ### Refresh a host view without polling
146
+
147
+ A host that shows background subagent activity (an editor panel, a footer, a status bar) can read `status` when something changed instead of on a timer:
148
+
149
+ 1. Subscribe to the names under `ping.events`: `jobsChanged`, `asyncStarted`, `childStatus`, `asyncComplete`, and `processTerminal`.
150
+ 2. Read `status` once, when the host starts or reconnects. Events are not replayed after a host restart, and subscribing first means a change during that read still triggers another one.
151
+ 3. When any of the events fires, read `status` again. Events can arrive in bursts and can repeat, so coalesce them in the host, for example one `status` read per 250 ms, and keep a refresh that arrives while a read is in flight for after it ends.
152
+
153
+ `subagent:jobs-changed` carries only `{ version: 1 }`. It fires whenever the parent's background job view changes: a run starts, moves to another step (no other event reports a chain or parallel run's step changes), reports new activity (a tool, a turn, tokens, or output), finishes, or is cleared from the widget. While a child streams output this can be about once per second per run. Starts and finishes fire right away; step and activity changes fire when the parent next reads the run's status file, which on macOS is a check every 5 seconds. It fires only in sessions with a UI, which covers interactive and RPC mode; print mode (`pi -p`) and SDK embeddings without a UI do not get it. It fires even when the async widget is turned off.
154
+
155
+ Foreground children are not background jobs. Their progress arrives as updates to the parent's `subagent` tool call (Pi's `tool_execution_update` events), with the `details.results[]` rows described above.
156
+
157
+ To rebuild what ran in a session after a reload, read the records the session file already holds: the `subagent` tool result's `details.results[]` for foreground runs and the `subagent-notify` message's `details.runs[]` for background runs (see [Host session lifetime and completion wakes](#host-session-lifetime-and-completion-wakes)). The `cost` method returns per-child rows built from the same records.
158
+
144
159
  ### Direct async launch correlation
145
160
 
146
161
  Direct async runs retain their originating `toolCallId` in status and result
@@ -415,6 +430,8 @@ const restriction = registerSubagentCapabilityCeiling({
415
430
  // restriction.dispose() removes only this provider's registration.
416
431
  ```
417
432
 
433
+ Register with **`ctx.sessionManager.getSessionId()`**; a ceiling registered by session file path does not apply.
434
+
418
435
  Semantics:
419
436
 
420
437
  - Active registrations intersect their `allowedTools` and `allowedAgents` sets and OR `denyExtensions`.
@@ -440,16 +457,16 @@ const dispose = registerBackgroundWorkProvider({
440
457
  name: "my-background-extension",
441
458
  wakeChannels: ["my-extension:job-finished"],
442
459
  listActiveWork: (context) => jobs
443
- .filter((job) => job.status === "running" && (!context || job.ownerSessionId === context.sessionId))
460
+ .filter((job) => job.status === "running" && (!context || context.sessionIds.includes(job.ownerSessionId)))
444
461
  .map((job) => ({ id: job.id, sessionId: job.ownerSessionId })),
445
- reconcile: ({ sessionId, nowMs }) => reconcileJobs(sessionId, nowMs),
462
+ reconcile: ({ sessionIds, nowMs }) => reconcileJobs(sessionIds, nowMs),
446
463
  });
447
464
  ```
448
465
 
449
466
  Semantics:
450
467
 
451
- - Each item needs a stable provider-local ID and the exact Pi session ID that owns it. `bg_wait` captures those identities rather than a count, so one job finishing while another starts still satisfies first-completion waits without losing the replacement.
452
- - `listActiveWork` receives an optional `{ sessionId, nowMs }` context during snapshots. Providers can use `sessionId` to avoid scanning unrelated work; existing zero-argument `() => items` providers continue to work, and returned items are still validated and filtered to the exact requested session.
468
+ - Each item needs a stable provider-local ID and the session that owns it, as either `ctx.sessionManager.getSessionId()` or the session file path (`ctx.sessionManager.getSessionFile()`); both are accepted. `bg_wait` captures those identities rather than a count, so one job finishing while another starts still satisfies first-completion waits without losing the replacement.
469
+ - `listActiveWork` receives an optional `{ sessionId, sessionIds, nowMs }` context during snapshots, and `reconcile` receives the same fields. `sessionIds` holds every form of the current session (its file path when it has one, and its session id); `sessionId` is the first of them. Providers can use them to avoid scanning unrelated work; existing zero-argument `() => items` providers continue to work, and returned items are still validated and filtered to the current session. Each provider is called once per snapshot.
453
470
  - It filters snapshots to the active session, fails closed if a provider disappears while its work is tracked, and surfaces malformed snapshots or provider errors with provider context.
454
471
  - Wake channels only shorten polling; validated snapshots remain authoritative.
455
472
  - Providers share a registry through `Symbol.for("pi-subagents.background-work.v1")`, allowing independently loaded extension modules to meet in one Pi process.
package/docs/missions.md CHANGED
@@ -13,6 +13,8 @@ Missions are durable wrappers around runs. The noun map:
13
13
 
14
14
  Ordinary workflow launches create one enclosing mission by default, with detailed JSON records under `~/.pi/agent/missions/projects/<project-hash>/` linking objectives, run ids, lifecycle status, decisions, artifact paths, and delivery receipts. Workflow children do not create separate missions. Each workflow child attempt is stored in the enclosing mission with its stable workflow key, run id when known, agent, task metadata, timestamps, session and artifact paths, and latest status heartbeat.
15
15
 
16
+ A finished run completes a mission you asked for with `mission` or `missionId` only when its result was accepted. If the run, or any workflow child in the mission, ends with acceptance `review-required`, `rejected`, `claimed`, or `pending`, the mission stays `waiting` and `mission.show` lists each child's acceptance status. Check the result and close the mission with `mission.close`. A `gate` or `acceptance.verify` command lets the runtime accept the result, except for writer runs: they require a review by default and stay `review-required` without one. When the command is enough proof, use `acceptance: { level: "verified", verify: [{ id: "check", command: "..." }], review: { required: false } }` instead of `gate`. Missions made by default for ordinary launches still complete when their run finishes.
17
+
16
18
  Records created under the old default `<project>/.pi/subagents/missions` stay on disk. Continue them by setting `missions.directory` to that path for the project or by copying the record into the new agent-dir project store. There is no automatic migration.
17
19
 
18
20
  Behavior:
@@ -334,6 +334,7 @@ Async events:
334
334
 
335
335
  - `subagent:async-started`
336
336
  - `subagent:async-complete`
337
+ - `subagent:jobs-changed` (see [extension-api.md](extension-api.md#refresh-a-host-view-without-polling))
337
338
 
338
339
  For regular async starts, the `subagent:async-started` payload includes redacted `task` and `goal` prompt fields. Async workflow script roots emit the same event with `mode: "workflow"` after their initial `status.json` is durable; workflow roots can omit `task`, and any included prompt fields are redacted. Their keyed children are then announced dynamically through `subagent:child-status`. Companion UI extensions can combine those hints with the authoritative live lifecycle artifacts under `asyncDir` without scraping terminal output.
339
340
 
@@ -110,7 +110,7 @@ The `subagent` tool schema lists `agent`, `task`, `workflow`, `args`, `async`, `
110
110
  | `options.checkpointBeforeDeadlineMs` | number | none | Async single-agent runs only. The runner requests that the child "checkpoint and stop" this many milliseconds before the run deadline (finish the current tool call, report changed files, build/test state, remaining work, commit/PR state; start no new work). This best-effort steer uses the normal steering lifecycle at the next tool boundary, so the receipt is visible in status and events; the ordinary deadline kill still applies. Precedence: call value → config `checkpointBeforeDeadlineMs`. Disarmed when the deadline leaves under one second before the checkpoint. |
111
111
  | `options.toolBudget` | object | none | Optional child tool-call budget `{ soft?, hard, block? }`: `hard` is a positive integer and `soft`, if set, is a positive integer no greater than `hard`. At `soft` the child is nudged to finalize. After `hard`, configured tools are blocked; `block` defaults to `read`, `grep`, `find`, and `ls`, and accepts either a nonempty array of tool names or `"*"` for every tool call. Final assistant text is never blocked. |
112
112
  | `options.usageBudget` | object | none | Optional root-only reported-usage budget `{ tokens?: { soft?, hard }, costUsd?: { soft?, hard } }`. Include at least one metric; each `hard` must be positive and each optional `soft` positive and no greater than its `hard`. Soft limits are status-only. Hard limits prevent later child launches after reported usage is reconciled; already-running children are not stopped and no reservations are made. |
113
- | `options.extensionBindings` | object | none | Child-only plain JSON keyed by namespaces like `package.name/1` (positive version): at most 16 namespaces, nesting depth 16, 256 total object properties, and 16 KiB of canonical UTF-8 JSON. Native Pi launches only; external runners and retained resumes reject it. |
113
+ | `options.extensionBindings` | object | none | Child-only plain JSON keyed by namespaces like `package.name/1` (positive version): at most 16 namespaces, nesting depth 16, 256 total object properties, and 16 KiB of canonical UTF-8 JSON. Native Pi launches only; external runners and retained resumes reject it. A child's extensions read it as canonical JSON from `PI_SUBAGENT_EXTENSION_BINDINGS` in their factory or `session_start`; a foreground child sees it only until its session has started, after which the parent's environment is restored. |
114
114
  | `options.preflight` | object | none | Advisory lane hints for raw scripts (`workflow: true` or a script path) only; not accepted with named workflows or direct children. See [bounded workflows](workflows.md#opt-in-bounded-workflows). |
115
115
  | `cwd` | string | runtime cwd | Override working directory. With `machine`, the directory on that machine. |
116
116
  | `options.machine` | string | - | Herdr saved machine (label or profile id) for external-cli agents; see [agents.md](agents.md#running-external-cli-agents-on-a-herdr-saved-machine). |
@@ -344,7 +344,7 @@ subagent({ action: "doctor" })
344
344
  - `view: "transcript"` tails the selected run's live `output-<index>.log` or persisted session transcript, with `lines` capped at 500.
345
345
  - Nested status shows the root/parent path, nested children, session/artifact paths when known, and nested control commands.
346
346
  - Inside child-safe fanout mode, bare `status` requires an id when no local foreground run is active, so children cannot enumerate unrelated top-level async runs.
347
- - Bare `interrupt` still targets only the visible top-level run; interrupting a nested run requires its explicit nested id.
347
+ - `interrupt` requires an id, like `stop`, `steer`, and `resume`; for a nested run, pass its nested id.
348
348
 
349
349
  ### Command controls
350
350
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "pi-subagents",
4
- "version": "0.82.1",
4
+ "version": "0.83.1",
5
5
  "description": "Pi extension for single-agent delegation and scripted multi-agent workflows",
6
6
  "author": "Nico Bailon",
7
7
  "license": "MIT",
@@ -48,12 +48,12 @@ needs.
48
48
  Use a script when later steps depend on earlier results, or for keyed,
49
49
  retried, aggregated, or resumed children. Write one ```` ```js workflow ````
50
50
  block in the reply and call `subagent({ workflow: true })` in the same reply.
51
- For a long script, or when a `workflow: true` call reports the block missing,
52
- write it to a file and pass `workflow: "./path.js"`. On Claude 5.x models (Opus
53
- 5.5, Sonnet 5.5, Fable 5.1), use the file whenever the turn already made a tool
54
- call: text after one reaches the session as a summary without the block. Calls in one reply run at
55
- the same time, so write the file in one reply and `validate` or launch it in
56
- the next.
51
+ For a long script, write it to a file and pass `workflow: "./path.js"`; calls in
52
+ one reply run at the same time, so write the file in one reply and `validate` or
53
+ launch it in the next. When a `workflow: true` call reports the block missing,
54
+ pass the source as `options: { script: "..." }` in place of `workflow: true` for
55
+ the rest of the turn: on some hosts, text after a tool call reaches the session
56
+ as a summary without the block.
57
57
 
58
58
  ```js workflow
59
59
  const scan = await runs.run("scan", { label: "Map auth flow", agent: "scout", task: "..." });
@@ -6,7 +6,7 @@ import { type RuntimeAgentOwner } from "./runtime-agent-registry.ts";
6
6
  type ManagementContext = Pick<ExtensionContext, "cwd" | "modelRegistry"> & {
7
7
  model?: ExtensionContext["model"];
8
8
  config?: ExtensionConfig;
9
- currentSessionId?: string;
9
+ piSessionId?: string;
10
10
  runtimeAgentOwner?: RuntimeAgentOwner;
11
11
  onAgentsChanged?: () => void;
12
12
  discoverAgentsAll?: typeof discoverAgentsAll;