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
@@ -153,15 +153,18 @@ function resetExtensionCacheOnReload(loader) {
153
153
  loader.loaded = true;
154
154
  return true;
155
155
  }
156
+ /** Applies `values` to `process.env` and returns a function that puts back the values they replaced. */
156
157
  function applyProcessEnv(values) {
157
158
  if (!values)
158
- return;
159
+ return () => { };
160
+ const previous = Object.fromEntries(Object.keys(values).map((name) => [name, process.env[name]]));
159
161
  for (const [name, value] of Object.entries(values)) {
160
162
  if (value === undefined)
161
163
  delete process.env[name];
162
164
  else
163
165
  process.env[name] = value;
164
166
  }
167
+ return () => applyProcessEnv(previous);
165
168
  }
166
169
  /**
167
170
  * Pi's built-in MCP extension registers server tools with the configured exposure, `codemode` by
@@ -458,7 +461,11 @@ export function createDefaultChildSessionFactory(options = {}) {
458
461
  await commands?.shutdown();
459
462
  const runner = session.extensionRunner;
460
463
  if (runner.hasHandlers("session_shutdown")) {
461
- await Promise.race([runner.emit({ type: "session_shutdown", reason: "quit" }), new Promise((resolve) => setTimeout(resolve, shutdownTimeoutMs).unref?.())]);
464
+ // Ref'd so a detached runner with nothing else pending stays alive until the bound
465
+ // ends and still publishes its result; cleared as soon as the handlers finish.
466
+ let bound;
467
+ await Promise.race([runner.emit({ type: "session_shutdown", reason: "quit" }), new Promise((resolve) => { bound = setTimeout(resolve, shutdownTimeoutMs); })])
468
+ .finally(() => clearTimeout(bound));
462
469
  }
463
470
  }
464
471
  catch (error) {
@@ -469,8 +476,7 @@ export function createDefaultChildSessionFactory(options = {}) {
469
476
  }
470
477
  };
471
478
  let inheritedProviders = new Set();
472
- const open = async () => {
473
- applyProcessEnv(launch.processEnv);
479
+ const openSession = async () => {
474
480
  if (!resetExtensionCacheOnReload(loader) && (launch.ambientExtensions || launch.extensionPaths.length))
475
481
  launch.onExtensionError?.({ extensionPath: "<loader>", event: "load", error: new Error("pi's extension cache reset is unavailable; extensions loaded into this child share module state with other sessions in this process.") });
476
482
  await loader.reload();
@@ -559,6 +565,16 @@ export function createDefaultChildSessionFactory(options = {}) {
559
565
  }
560
566
  return session;
561
567
  };
568
+ const open = async () => {
569
+ const restoreEnv = applyProcessEnv(launch.processEnv);
570
+ try {
571
+ return await openSession();
572
+ }
573
+ finally {
574
+ if (launch.restoreProcessEnv)
575
+ restoreEnv();
576
+ }
577
+ };
562
578
  const opened = loading.catch(() => { }).then(open);
563
579
  loading = opened;
564
580
  const session = await opened;
@@ -42,6 +42,8 @@ export interface PreparedHerdrMachineExternalCliRun {
42
42
  export declare function resolveHerdrMachinePlacement(input: ResolveHerdrMachinePlacementInput): HerdrMachinePlacement;
43
43
  /** `local` resolves to a Rex pane on this machine; a name with a `rex` entry in user settings to a Rex pane on that SSH host; any other value to a Herdr saved machine. */
44
44
  export declare function resolveMachinePlacement(input: ResolveHerdrMachinePlacementInput): MachinePlacement;
45
+ /** A placed Pi keeps its transcript on the pane's machine, so it can't start from a local one. */
46
+ export declare const PLACED_RESTORE_UNSUPPORTED = "Pane-native remote Pi does not support fork, resume, or revival; use fresh context.";
45
47
  export declare function formatHerdrMachineRunnerUnsupported(input: {
46
48
  machine?: string;
47
49
  agentName: string;
@@ -233,6 +233,8 @@ export function resolveMachinePlacement(input) {
233
233
  return { machine: { provider: "rex", id: requested, target: settings.rex.ssh, cwd: validateRemoteCwd(remoteMachineCwd(input.stepCwd, settings.cwd, requested), requested) } };
234
234
  return resolveHerdrMachinePlacement(input);
235
235
  }
236
+ /** A placed Pi keeps its transcript on the pane's machine, so it can't start from a local one. */
237
+ export const PLACED_RESTORE_UNSUPPORTED = "Pane-native remote Pi does not support fork, resume, or revival; use fresh context.";
236
238
  export function formatHerdrMachineRunnerUnsupported(input) {
237
239
  if (input.machine === undefined)
238
240
  return undefined;
@@ -8,6 +8,7 @@ import { encodeHerdrPiFrame, HERDR_PI_MODE_ENV, HERDR_PI_PROTOCOL, HERDR_PI_RUN_
8
8
  import { discoverPlacedBridgeManifest } from "./placed-run-owner.js";
9
9
  import { RexPlacedRunOwner } from "./rex-pane-host.js";
10
10
  import { isRexLocalMachine } from "./rex-machine.js";
11
+ import { PLACED_RESTORE_UNSUPPORTED } from "./herdr-machine.js";
11
12
  /** The pane half comes from the host; the bridge half (run, package, protocol, native session, evidence cursor) is host-neutral. */
12
13
  export function reconcileHerdrReconnect(identity, candidate, lastEvidenceCursor, host = herdrPaneHost) {
13
14
  return host.reconcile(identity, candidate, () => { const bridge = candidate.bridge; if (bridge.runId !== identity.runId || bridge.nativeSessionId !== identity.nativeSessionId || bridge.packageVersion !== packageJson.version || bridge.protocol !== HERDR_PI_PROTOCOL)
@@ -35,16 +36,18 @@ export async function boundedHerdrReconnect(identity, lastEvidenceCursor, attemp
35
36
  }
36
37
  function safeRunId(value) { const prefix = value?.replace(/[^A-Za-z0-9_-]/gu, "_").slice(0, 48) ?? "run"; return validateHerdrPiRunId(`${prefix}_${randomBytes(8).toString("hex")}`); }
37
38
  export function serializeHerdrPiLaunch(launch) {
38
- if (launch.storage.kind === "file")
39
- throw new Error("Pane-native remote Pi does not support fork, resume, or revival; use fresh context.");
39
+ // Every child is handed a local session file path; only one that already exists (a fork or a
40
+ // resumed transcript) asks the pane to restore history. A fresh child's path is never written.
41
+ if (launch.storage.kind === "file" && fs.existsSync(launch.storage.sessionFile))
42
+ throw new Error(PLACED_RESTORE_UNSUPPORTED);
40
43
  if (launch.extensionPaths.length || launch.requiredExtensions?.length)
41
44
  throw new Error("Pane-native remote Pi cannot transfer local extension paths; install/configure pi-subagents on the remote machine.");
42
45
  if (launch.processEnv && Object.values(launch.processEnv).some((value) => value !== undefined && value !== "__none__"))
43
46
  throw new Error("Pane-native remote Pi cannot transfer local bindings, MCP selections, or process environment.");
44
47
  if (launch.runtime.nestedRoute || launch.runtime.fanoutChild || launch.runtime.depth > 1)
45
48
  throw new Error("Nested delegation from a pane-native remote Pi is not supported.");
46
- if (launch.excludeTools?.length || launch.runtime.permissions || launch.runtime.toolBudget || launch.runtime.requiredExtensions || launch.runtime.requiredTools?.length || launch.runtime.mcpDirectTools?.length)
47
- throw new Error("Pane-native remote Pi cannot yet represent exclusions, permission rules, tool budgets, MCP direct tools, or required-tool/extension contracts; remove machine placement.");
49
+ if (launch.excludeTools?.length || launch.runtime.permissions || launch.runtime.toolBudget || launch.runtime.requiredExtensions || launch.runtime.mcpDirectTools?.length)
50
+ throw new Error("Pane-native remote Pi cannot yet represent exclusions, permission rules, tool budgets, MCP direct tools, or required-extension contracts; remove machine placement.");
48
51
  const resources = launch.remoteResources;
49
52
  if (!resources || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(resources.agent) || resources.skills?.some((name) => !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(name)) || resources.toolCeiling?.some((name) => !/^[A-Za-z0-9_-]{1,64}$/u.test(name)) || (resources.reads !== undefined && resources.reads !== false && resources.reads.some((read) => typeof read !== "string" || Buffer.byteLength(read) > 4096)))
50
53
  throw new Error("Pane-native remote resources require bounded logical agent, skill, tool, and read names.");
@@ -350,6 +353,10 @@ async function startPlacedPiSession(launch, owner, policy) {
350
353
  throw new Error("Remote Pi resource resolution identity mismatch.");
351
354
  if (!Array.isArray(configured.tools) || (policy.resources.toolCeiling && configured.tools.some((tool) => !policy.resources.toolCeiling.includes(String(tool)))))
352
355
  throw new Error("Remote Pi active-tool ceiling acknowledgement mismatch.");
356
+ // The remote Pi never receives the runtime contract, so required tools are checked here, against what it activated.
357
+ const missingRequired = (launch.runtime.requiredTools ?? []).filter((tool) => !configured.tools.includes(tool));
358
+ if (missingRequired.length)
359
+ throw new Error(`Remote Pi agent '${policy.resources.agent}' did not activate required tools: ${missingRequired.join(", ")}.`);
353
360
  if (launch.model && configured.model !== launch.model.split(":")[0])
354
361
  throw new Error(`Remote Pi model '${launch.model}' did not resolve to the requested provider/model.`);
355
362
  const identity = { runId, machineId: machine.id, target: isRexLocalMachine(machine) ? machine.id : machine.target, session: owner.host.sessionOf(connection), workspaceId: owned.workspaceId, tabId: owned.tabId, paneId: owned.paneId, terminalId, agentName, nativeSessionId: manifest.nativeSessionId, cwd: machine.cwd, runtimeDir };
@@ -23,7 +23,7 @@ export declare function resolveParallelHandoffChild(input: {
23
23
  child: ParallelHandoffGroup["children"][number];
24
24
  } | undefined;
25
25
  export declare function protectRetainedWorktreeForResume(manifestPath: string, runId: string, childIndex: number, signal?: AbortSignal): Promise<string>;
26
- export declare function resolveRetainedWorktreeCwd(manifestPath: string, runId: string, childIndex: number): string | undefined;
26
+ export declare function resolveRetainedWorktreeCwd(manifestPath: string, runId: string, childIndex: number, recordedWorktreePath?: string): string | undefined;
27
27
  export declare function isTerminalParallelHandoffChildStatus(status: unknown): boolean;
28
28
  export declare function formatStoredParallelHandoffCleanup(manifestPath: string, manifest?: ParallelHandoffManifest): string;
29
29
  export interface ParallelHandoffEvidenceResult {
@@ -165,17 +165,18 @@ export async function protectRetainedWorktreeForResume(manifestPath, runId, chil
165
165
  return cwd;
166
166
  }), { signal }));
167
167
  }
168
- export function resolveRetainedWorktreeCwd(manifestPath, runId, childIndex) {
168
+ export function resolveRetainedWorktreeCwd(manifestPath, runId, childIndex, recordedWorktreePath) {
169
169
  const manifest = readParallelHandoffManifest(manifestPath);
170
- if (!manifest)
171
- return undefined;
172
- if (manifest.runId !== runId)
170
+ if (manifest && manifest.runId !== runId)
173
171
  throw new Error(`Managed worktree handoff belongs to run '${manifest.runId}', not '${runId}'.`);
174
- const match = manifest.groups
172
+ const match = manifest?.groups
175
173
  .flatMap((group) => group.children.map((child) => ({ group, child })))
176
174
  .find(({ child }) => child.index === childIndex);
177
- if (!match)
175
+ if (!manifest || !match) {
176
+ if (recordedWorktreePath)
177
+ 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}.`);
178
178
  return undefined;
179
+ }
179
180
  const cleanup = match.group.cleanup.tasks.find((task) => task.index === match.child.taskIndex);
180
181
  if (!cleanup)
181
182
  throw new Error(`Async run '${runId}' child ${childIndex} has no managed worktree cleanup record.`);
@@ -185,6 +186,9 @@ export function resolveRetainedWorktreeCwd(manifestPath, runId, childIndex) {
185
186
  const requiredCwd = path.join(cleanup.path, relativeCwd);
186
187
  if (cleanup.worktreeRemoved || cleanup.branchRemoved)
187
188
  throw new Error(`Async run '${runId}' required managed worktree was removed: ${requiredCwd}`);
189
+ // The runner removes the worktree right after this marker, without the locks that guard resume admission.
190
+ if (cleanup.reason?.includes("pending durable handoff capture"))
191
+ 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}.`);
188
192
  let worktreeRoot = "";
189
193
  let resolvedRequiredCwd = "";
190
194
  try {
@@ -669,6 +669,7 @@ export default function registerSubagentPromptRuntime(pi, config, drainObservati
669
669
  onRuntimeEvent("session_start", (_event, ctx) => {
670
670
  const sessionManager = ctx?.sessionManager;
671
671
  waitState.currentSessionId = sessionManager ? resolveCurrentSessionId(sessionManager) : null;
672
+ waitState.supervisorOwnerSessionId = sessionManager?.getSessionId() || null;
672
673
  registerNativeSupervisorClientOnce();
673
674
  });
674
675
  onRuntimeEvent("agent_start", () => {
@@ -724,30 +725,23 @@ export default function registerSubagentPromptRuntime(pi, config, drainObservati
724
725
  onRuntimeEvent("before_provider_headers", (event, ctx) => {
725
726
  applyForkSessionAffinity(event?.headers, ctx?.model, config.parentSessionId, readInherited(ctx)?.model);
726
727
  });
727
- if (config.forkCacheKey)
728
- onRuntimeEvent("context_with_system", (event, ctx) => {
729
- if (!event || typeof event !== "object" || !("messages" in event) || !Array.isArray(event.messages))
730
- return undefined;
731
- const fork = readInherited(ctx);
732
- if (!fork)
733
- return undefined;
734
- const messages = projectForkRequest(event.messages, fork.system, fork.forkedAt, { boundary });
735
- return messages === event.messages ? undefined : { messages };
736
- });
737
- onRuntimeEvent("context", (event, ctx) => {
728
+ // The strip runs on context_with_system, not context: Pi treats any change a context handler
729
+ // makes to the message list as a rewritten conversation and folds every mid-conversation system
730
+ // message into the leading one, so every later request would miss the prompt cache. The strip
731
+ // passes system messages through unchanged.
732
+ onRuntimeEvent("context_with_system", (event, ctx) => {
738
733
  if (!event || typeof event !== "object" || !("messages" in event) || !Array.isArray(event.messages))
739
734
  return undefined;
740
- const forkedAt = config.forkCacheKey ? Date.parse(ctx?.sessionManager?.getHeader()?.timestamp ?? "") : Number.NaN;
741
- const messages = stripParentOnlySubagentMessages(event.messages, {
735
+ const fork = config.forkCacheKey ? readInherited(ctx) : undefined;
736
+ const stripped = stripParentOnlySubagentMessages(event.messages, {
742
737
  sanitizeToolIds: !COMPOSITE_TOOL_ID_APIS.has(ctx?.model?.api ?? ""),
743
738
  // Providers that reuse the Codex Responses wire under their own api id (e.g. cliproxyapi-codex-responses) split call_id|item_id the same way.
744
739
  preserveBoundedCompositeToolIds: ctx?.model?.api?.endsWith("-codex-responses") === true,
745
740
  preserveFanoutToolHistory: config.fanoutChild,
746
- ...(Number.isFinite(forkedAt) ? { inheritedBefore: forkedAt } : {}),
741
+ ...(fork ? { inheritedBefore: fork.forkedAt } : {}),
747
742
  });
748
- if (messages === event.messages)
749
- return undefined;
750
- return { messages };
743
+ const messages = fork ? projectForkRequest(stripped, fork.system, fork.forkedAt, { boundary }) : stripped;
744
+ return messages === event.messages ? undefined : { messages };
751
745
  });
752
746
  // pi-intercom asks at session start for this session's intercom ID. Claiming
753
747
  // the route there frees the session name for the readable label. An older
@@ -86,6 +86,8 @@ interface FeatureConfig {
86
86
  export declare function resolveDisabledFeatureSurface(config: FeatureConfig): DisabledFeatureSurface;
87
87
  /** Returns why a request uses a disabled feature, or undefined when every requested field is enabled. */
88
88
  export declare function disabledFeatureUseError(request: object, surface: DisabledFeatureSurface, label?: string): string | undefined;
89
- /** Lists what config disabled, for prepending to static reference docs that describe the full tool. */
89
+ /** Lists what config disabled, for prepending to static guide docs that describe the full tool. */
90
90
  export declare function disabledFeatureNotice(surface: DisabledFeatureSurface): string | undefined;
91
+ /** One-line form for guide sections, which are capped at 8,000 chars. */
92
+ export declare function disabledFeatureSectionNotice(surface: DisabledFeatureSurface): string | undefined;
91
93
  export {};
@@ -99,14 +99,22 @@ export function disabledFeatureUseError(request, surface, label = "subagent") {
99
99
  }
100
100
  return undefined;
101
101
  }
102
- /** Lists what config disabled, for prepending to static reference docs that describe the full tool. */
102
+ const WORKFLOW_SCRIPTS_REPLACEMENT = "Instead of workflow scripts, use the top-level tasks or chain fields.";
103
+ /** Lists what config disabled, for prepending to static guide docs that describe the full tool. */
103
104
  export function disabledFeatureNotice(surface) {
104
105
  if (surface.features.size === 0)
105
106
  return undefined;
106
107
  const lines = [...surface.features].map((feature) => {
107
108
  const { actions, params, disabledBy } = featureSurface(feature);
108
109
  const parts = [`options ${params.join(", ")}`, ...(actions.length > 0 ? [`actions ${actions.join(", ")}`] : [])];
109
- return `- ${disabledBy}: ${parts.join("; ")}`;
110
+ return `- ${disabledBy}: ${parts.join("; ")}${feature === "workflow-scripts" ? `. ${WORKFLOW_SCRIPTS_REPLACEMENT}` : ""}`;
110
111
  });
111
- return `Disabled by config in this session. The reference below still lists these, but calls that use them are rejected:\n${lines.join("\n")}`;
112
+ return `Disabled by config in this session. The guide below may still describe these, but calls that use them are rejected:\n${lines.join("\n")}`;
113
+ }
114
+ /** One-line form for guide sections, which are capped at 8,000 chars. */
115
+ export function disabledFeatureSectionNotice(surface) {
116
+ if (surface.features.size === 0)
117
+ return undefined;
118
+ const replacement = surface.features.has("workflow-scripts") ? ` ${WORKFLOW_SCRIPTS_REPLACEMENT}` : "";
119
+ return `Some options and actions are disabled by config in this session; guide topic tool-reference lists them.${replacement}`;
112
120
  }
@@ -1936,7 +1936,7 @@ export interface AsyncStatus {
1936
1936
  label?: string;
1937
1937
  workflowKey?: string;
1938
1938
  lane?: WorkflowLaneMetadata;
1939
- /** Display-only worktree path copied at launch; handoff remains authoritative. */
1939
+ /** Worktree path copied at setup; the handoff stays authoritative for the cwd. */
1940
1940
  worktreePath?: string;
1941
1941
  /** Display-only branch copied at launch; handoff remains authoritative. */
1942
1942
  branch?: string;
@@ -2278,7 +2278,7 @@ export interface ActiveAsyncCapacitySnapshot {
2278
2278
  export interface SubagentState {
2279
2279
  baseCwd: string;
2280
2280
  currentSessionId: string | null;
2281
- /** Exact SDK runtime session ID for supervisor ownership; never a session file path. */
2281
+ /** Exact SDK runtime session ID (`getSessionId()`) for supervisor ownership and background-work matching; never a session file path. */
2282
2282
  supervisorOwnerSessionId?: string | null;
2283
2283
  /** Session for which active status projections were restored successfully. */
2284
2284
  statusProjectionSessionId?: string | null;
@@ -2410,6 +2410,8 @@ export declare const SUBAGENT_CONTROL_EVENT = "subagent:control-event";
2410
2410
  export declare const SUBAGENT_CONTROL_INTERCOM_EVENT = "subagent:control-intercom";
2411
2411
  export declare const SUBAGENT_STEERING_NOTICE_EVENT = "subagent:steering-notice";
2412
2412
  export declare const SUBAGENT_CHILD_STATUS_EVENT = "subagent:child-status";
2413
+ /** Payload is only `{ version: 1 }`: a hint for hosts to read `status` again, not a description of the change. */
2414
+ export declare const SUBAGENT_JOBS_CHANGED_EVENT = "subagent:jobs-changed";
2413
2415
  export declare const SUBAGENT_RESULT_INTERCOM_EVENT = "subagent:result-intercom";
2414
2416
  export declare const SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT = "subagent:result-intercom-delivery";
2415
2417
  export interface SubagentChildStatusEvent {
@@ -19,6 +19,8 @@ export const SUBAGENT_CONTROL_EVENT = "subagent:control-event";
19
19
  export const SUBAGENT_CONTROL_INTERCOM_EVENT = "subagent:control-intercom";
20
20
  export const SUBAGENT_STEERING_NOTICE_EVENT = "subagent:steering-notice";
21
21
  export const SUBAGENT_CHILD_STATUS_EVENT = "subagent:child-status";
22
+ /** Payload is only `{ version: 1 }`: a hint for hosts to read `status` again, not a description of the change. */
23
+ export const SUBAGENT_JOBS_CHANGED_EVENT = "subagent:jobs-changed";
22
24
  export const SUBAGENT_RESULT_INTERCOM_EVENT = "subagent:result-intercom";
23
25
  export const SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT = "subagent:result-intercom-delivery";
24
26
  export const FLEET_KEYBINDING_ACTIONS = [