@gotgenes/pi-subagents 18.0.1 → 18.0.3

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 (268) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/docs/architecture/architecture.md +165 -203
  3. package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
  4. package/package.json +6 -7
  5. package/src/config/default-agents.ts +3 -0
  6. package/src/lifecycle/subagent.ts +25 -14
  7. package/src/observation/notification.ts +23 -10
  8. package/src/observation/subagent-events-observer.ts +1 -3
  9. package/src/runtime.ts +2 -1
  10. package/src/service/service-adapter.ts +20 -17
  11. package/src/session/model-resolver.ts +31 -30
  12. package/src/tools/agent-tool.ts +17 -13
  13. package/src/tools/get-result-report.ts +60 -0
  14. package/src/tools/get-result-tool.ts +25 -40
  15. package/src/tools/helpers.ts +21 -5
  16. package/src/tools/spawn-config.ts +5 -5
  17. package/src/tools/steer-tool.ts +37 -27
  18. package/src/types.ts +4 -1
  19. package/src/ui/session-navigator.ts +0 -2
  20. package/.prettierignore +0 -5
  21. package/AGENTS.md +0 -7
  22. package/docs/plans/0048-implement-subagents-api.md +0 -304
  23. package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
  24. package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
  25. package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
  26. package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
  27. package/docs/plans/0054-decompose-index-into-modules.md +0 -302
  28. package/docs/plans/0057-structured-debug-logging.md +0 -154
  29. package/docs/plans/0061-session-format-transcript.md +0 -284
  30. package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
  31. package/docs/plans/0069-create-subagent-runtime.md +0 -345
  32. package/docs/plans/0070-extract-event-handlers.md +0 -306
  33. package/docs/plans/0071-extract-session-config-assembler.md +0 -362
  34. package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
  35. package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
  36. package/docs/plans/0077-inject-project-agents-dir.md +0 -115
  37. package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
  38. package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
  39. package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
  40. package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
  41. package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
  42. package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
  43. package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
  44. package/docs/plans/0108-extract-agent-type-registry.md +0 -322
  45. package/docs/plans/0109-extract-settings-manager.md +0 -276
  46. package/docs/plans/0110-agent-activity-tracker.md +0 -297
  47. package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
  48. package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
  49. package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
  50. package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
  51. package/docs/plans/0115-decompose-agent-tool.md +0 -337
  52. package/docs/plans/0116-type-housekeeping.md +0 -351
  53. package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
  54. package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
  55. package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
  56. package/docs/plans/0132-inject-io-into-session-config.md +0 -219
  57. package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
  58. package/docs/plans/0134-reduce-as-any-casts.md +0 -366
  59. package/docs/plans/0135-extract-display-helpers.md +0 -182
  60. package/docs/plans/0136-decompose-agent-menu.md +0 -300
  61. package/docs/plans/0144-consolidate-observation-model.md +0 -263
  62. package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
  63. package/docs/plans/0146-narrow-ui-context.md +0 -319
  64. package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
  65. package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
  66. package/docs/plans/0152-add-prompt-snippet.md +0 -91
  67. package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
  68. package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
  69. package/docs/plans/0166-extract-parent-session-info.md +0 -231
  70. package/docs/plans/0167-narrow-runner-io.md +0 -150
  71. package/docs/plans/0168-extract-tool-filter-config.md +0 -173
  72. package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
  73. package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
  74. package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
  75. package/docs/plans/0172-extract-turn-formatting.md +0 -206
  76. package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
  77. package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
  78. package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
  79. package/docs/plans/0192-define-session-context-interface.md +0 -107
  80. package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
  81. package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
  82. package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
  83. package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
  84. package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
  85. package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
  86. package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
  87. package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
  88. package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
  89. package/docs/plans/0215-decompose-build-parent-context.md +0 -166
  90. package/docs/plans/0216-decompose-start-agent.md +0 -255
  91. package/docs/plans/0217-extract-overwrite-guard.md +0 -176
  92. package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
  93. package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
  94. package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
  95. package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
  96. package/docs/plans/0229-agent-born-complete.md +0 -564
  97. package/docs/plans/0230-extract-concurrency-queue.md +0 -265
  98. package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
  99. package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
  100. package/docs/plans/0237-remove-disallowed-tools.md +0 -180
  101. package/docs/plans/0238-remove-extensions-filtering.md +0 -191
  102. package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
  103. package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
  104. package/docs/plans/0256-extract-worktree-isolation.md +0 -256
  105. package/docs/plans/0257-extract-child-session-factory.md +0 -285
  106. package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
  107. package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
  108. package/docs/plans/0265-born-complete-subagent-session.md +0 -333
  109. package/docs/plans/0270-type-consumable-public-surface.md +0 -204
  110. package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
  111. package/docs/plans/0277-encapsulate-agent-session.md +0 -304
  112. package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
  113. package/docs/plans/0360-custom-agents-default-append.md +0 -132
  114. package/docs/plans/0373-extract-subagent-state.md +0 -250
  115. package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
  116. package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
  117. package/docs/plans/0376-extract-manager-observer.md +0 -232
  118. package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
  119. package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
  120. package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
  121. package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
  122. package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
  123. package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
  124. package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
  125. package/docs/plans/0412-unify-session-mock-builders.md +0 -146
  126. package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
  127. package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
  128. package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
  129. package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
  130. package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
  131. package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
  132. package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
  133. package/docs/plans/0427-reconsider-ui-direction.md +0 -212
  134. package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
  135. package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
  136. package/docs/plans/0443-consolidate-remaining-test-clone-families.md +0 -268
  137. package/docs/plans/0444-shrink-widget-to-background-agents.md +0 -156
  138. package/docs/plans/0445-native-session-navigation.md +0 -365
  139. package/docs/plans/0446-spike-session-navigation-entry-criteria.md +0 -171
  140. package/docs/plans/0447-extract-subagents-settings-command.md +0 -220
  141. package/docs/plans/0448-block-disabled-agent-spawn.md +0 -207
  142. package/docs/plans/0462-navigation-renderer-tui-components.md +0 -338
  143. package/docs/plans/0463-file-snapshot-source-evicted-agents.md +0 -306
  144. package/docs/plans/0470-refresh-readme-command-surface.md +0 -159
  145. package/docs/retro/0048-implement-subagents-api.md +0 -44
  146. package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
  147. package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
  148. package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
  149. package/docs/retro/0054-decompose-index-into-modules.md +0 -53
  150. package/docs/retro/0057-structured-debug-logging.md +0 -77
  151. package/docs/retro/0061-session-format-transcript.md +0 -41
  152. package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
  153. package/docs/retro/0069-create-subagent-runtime.md +0 -43
  154. package/docs/retro/0070-extract-event-handlers.md +0 -49
  155. package/docs/retro/0071-extract-session-config-assembler.md +0 -60
  156. package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
  157. package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
  158. package/docs/retro/0077-inject-project-agents-dir.md +0 -33
  159. package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
  160. package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
  161. package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
  162. package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
  163. package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
  164. package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
  165. package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
  166. package/docs/retro/0108-extract-agent-type-registry.md +0 -41
  167. package/docs/retro/0109-extract-settings-manager.md +0 -55
  168. package/docs/retro/0110-agent-activity-tracker.md +0 -44
  169. package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
  170. package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
  171. package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
  172. package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
  173. package/docs/retro/0115-decompose-agent-tool.md +0 -51
  174. package/docs/retro/0116-type-housekeeping.md +0 -42
  175. package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
  176. package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
  177. package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
  178. package/docs/retro/0132-inject-io-into-session-config.md +0 -33
  179. package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
  180. package/docs/retro/0134-reduce-as-any-casts.md +0 -56
  181. package/docs/retro/0135-extract-display-helpers.md +0 -38
  182. package/docs/retro/0136-decompose-agent-menu.md +0 -43
  183. package/docs/retro/0144-consolidate-observation-model.md +0 -39
  184. package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
  185. package/docs/retro/0146-narrow-ui-context.md +0 -70
  186. package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
  187. package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
  188. package/docs/retro/0152-add-prompt-snippet.md +0 -34
  189. package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
  190. package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
  191. package/docs/retro/0166-extract-parent-session-info.md +0 -66
  192. package/docs/retro/0167-narrow-runner-io.md +0 -63
  193. package/docs/retro/0168-extract-tool-filter-config.md +0 -76
  194. package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
  195. package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
  196. package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
  197. package/docs/retro/0172-extract-turn-formatting.md +0 -80
  198. package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
  199. package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
  200. package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
  201. package/docs/retro/0192-define-session-context-interface.md +0 -59
  202. package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
  203. package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
  204. package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
  205. package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
  206. package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
  207. package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
  208. package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
  209. package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
  210. package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
  211. package/docs/retro/0215-decompose-build-parent-context.md +0 -61
  212. package/docs/retro/0216-decompose-start-agent.md +0 -80
  213. package/docs/retro/0217-extract-overwrite-guard.md +0 -63
  214. package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
  215. package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
  216. package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
  217. package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
  218. package/docs/retro/0229-agent-born-complete.md +0 -89
  219. package/docs/retro/0230-extract-concurrency-queue.md +0 -38
  220. package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
  221. package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
  222. package/docs/retro/0237-remove-disallowed-tools.md +0 -78
  223. package/docs/retro/0238-remove-extensions-filtering.md +0 -72
  224. package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
  225. package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
  226. package/docs/retro/0256-extract-worktree-isolation.md +0 -89
  227. package/docs/retro/0257-extract-child-session-factory.md +0 -33
  228. package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
  229. package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
  230. package/docs/retro/0265-born-complete-subagent-session.md +0 -97
  231. package/docs/retro/0270-type-consumable-public-surface.md +0 -108
  232. package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
  233. package/docs/retro/0277-encapsulate-agent-session.md +0 -80
  234. package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
  235. package/docs/retro/0360-custom-agents-default-append.md +0 -81
  236. package/docs/retro/0373-extract-subagent-state.md +0 -94
  237. package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
  238. package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
  239. package/docs/retro/0376-extract-manager-observer.md +0 -81
  240. package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
  241. package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
  242. package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
  243. package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
  244. package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
  245. package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
  246. package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
  247. package/docs/retro/0412-unify-session-mock-builders.md +0 -80
  248. package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
  249. package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
  250. package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
  251. package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
  252. package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
  253. package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
  254. package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
  255. package/docs/retro/0427-reconsider-ui-direction.md +0 -102
  256. package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -97
  257. package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
  258. package/docs/retro/0443-consolidate-remaining-test-clone-families.md +0 -28
  259. package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
  260. package/docs/retro/0445-native-session-navigation.md +0 -122
  261. package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
  262. package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
  263. package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
  264. package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
  265. package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
  266. package/docs/retro/0470-refresh-readme-command-surface.md +0 -40
  267. package/src/observation/notification-state.ts +0 -27
  268. package/vitest.config.ts +0 -14
@@ -1,337 +0,0 @@
1
- ---
2
- issue: 115
3
- issue_title: "refactor(pi-subagents): decompose agent-tool.ts into foreground/background modules"
4
- ---
5
-
6
- # Decompose agent-tool.ts into foreground/background modules
7
-
8
- ## Problem Statement
9
-
10
- `tools/agent-tool.ts` is the largest file in the package at 579 lines.
11
- The `execute` function handles three distinct execution paths — resume, background spawn, and foreground streaming — each with different dependencies.
12
- Before those paths can be cleanly extracted, two upstream API gaps force the tool to work around the manager:
13
-
14
- 1. The foreground `onSessionCreated` callback loops through `manager.listAgents()` matching by session object just to discover the agent's ID — because `onSessionCreated` only receives the session, not the record.
15
- 2. The background path mutates `record.notification` after spawn — reaching into the record returned by `getRecord()` to attach a `NotificationState` — because the manager has no way to wire notification state at spawn time.
16
-
17
- These workarounds would simply move into the extracted modules unchanged.
18
- Fixing the API gaps first makes the extraction clean: each extracted module receives what it actually needs from the manager, without reaching through or reverse-searching.
19
-
20
- ## Goals
21
-
22
- - Widen `onSessionCreated` to `(session, record)` so callers receive the agent ID and record directly.
23
- - Accept `toolCallId` in `AgentSpawnConfig` so the manager wires `record.notification` internally for background agents.
24
- - Extract the foreground execution loop into `tools/foreground-runner.ts`.
25
- - Extract the background spawn path into `tools/background-spawner.ts`.
26
- - Move `getStatusNote` and `buildDetails` to `tools/helpers.ts`.
27
- - Keep `agent-tool.ts` as the orchestrator (~250 lines): tool definition, parameter validation, shared setup, dispatch, resume.
28
- - Preserve all existing behavior.
29
-
30
- ## Non-Goals
31
-
32
- - Extracting the resume path (~27 lines) — too small to warrant a separate file.
33
- - Extracting `renderCall`/`renderResult` — tightly coupled to the tool definition.
34
- - Changing `AgentToolDeps` shape — #114 already narrowed it.
35
- - Removing `onSessionCreated` from `AgentSpawnConfig` entirely — it is still useful for UI observer wiring that the manager should not own.
36
-
37
- ## Background
38
-
39
- ### Prerequisite status
40
-
41
- | Issue | Title | Status |
42
- | ----- | ------------------------------------------ | ------- |
43
- | #114 | Narrow `AgentToolDeps` and `AgentMenuDeps` | ✅ Done |
44
-
45
- ### Current API gaps
46
-
47
- #### Gap 1: foreground ID discovery
48
-
49
- The foreground path needs the agent ID *during* execution (inside `onSessionCreated`, before `spawnAndWait` resolves) to register the activity tracker in the widget.
50
- The manager's internal `onSessionCreated` handler already has `id` and `record` in scope but passes only `session` to the caller's callback.
51
- The tool works around this by iterating `listAgents()` and matching by session identity:
52
-
53
- ```typescript
54
- onSessionCreated: (session) => {
55
- for (const a of deps.manager.listAgents()) {
56
- if (a.execution?.session === session) {
57
- fgId = a.id;
58
- deps.agentActivity.set(a.id, fgState);
59
- // ...
60
- }
61
- }
62
- }
63
- ```
64
-
65
- This is a violation of Tell-Don't-Ask: the tool asks the manager for data it already has.
66
-
67
- #### Gap 2: post-spawn notification mutation
68
-
69
- The background path calls `manager.spawn()`, then immediately calls `manager.getRecord(id)` to mutate `record.notification`:
70
-
71
- ```typescript
72
- const id = deps.manager.spawn(ctx, subagentType, prompt, { ... });
73
- const record = deps.manager.getRecord(id);
74
- if (record) {
75
- record.notification = new NotificationState(toolCallId);
76
- }
77
- ```
78
-
79
- This is an output argument — the tool writes back into a record it doesn't own.
80
- The notification could be wired at spawn time if the manager accepted a `toolCallId`.
81
-
82
- ### Relevant design principles
83
-
84
- - **Tell-Don't-Ask** (code-design skill): the `listAgents()` loop asks the manager for data it already has.
85
- - **Output arguments** (code-design skill): writing `record.notification` after spawn mutates an object owned by the manager.
86
- - **SRP**: foreground streaming and background spawning are independent concerns.
87
- - **One concern per file** (AGENTS.md): the file mixes orchestration, streaming, spawning, and formatting.
88
-
89
- ## Design Overview
90
-
91
- ### Phase 1: Fix manager API gaps
92
-
93
- #### Widen `onSessionCreated` to include record
94
-
95
- Change the callback signature in both `AgentSpawnConfig` and the runner's `RunOptions`:
96
-
97
- ```typescript
98
- // agent-manager.ts — AgentSpawnConfig
99
- onSessionCreated?: (session: AgentSession, record: AgentRecord) => void;
100
- ```
101
-
102
- The manager's internal handler already has `record` in scope — pass it through:
103
-
104
- ```typescript
105
- // In startAgent(), existing line:
106
- options.onSessionCreated?.(session);
107
- // Becomes:
108
- options.onSessionCreated?.(session, record);
109
- ```
110
-
111
- The runner's `onSessionCreated` stays `(session: AgentSession) => void` — it doesn't know about records.
112
- The manager wraps the runner callback and adds `record` before forwarding to the caller.
113
-
114
- This lets the foreground tool callback access `record.id` directly, eliminating the `listAgents()` loop.
115
-
116
- #### Accept `toolCallId` in `AgentSpawnConfig`
117
-
118
- Add an optional `toolCallId` field to `AgentSpawnConfig`:
119
-
120
- ```typescript
121
- export interface AgentSpawnConfig {
122
- // ... existing fields ...
123
- /** Tool call ID for background notification wiring. When set, spawn attaches NotificationState. */
124
- toolCallId?: string;
125
- }
126
- ```
127
-
128
- In `AgentManager.spawn()`, after creating the record:
129
-
130
- ```typescript
131
- if (options.toolCallId) {
132
- record.notification = new NotificationState(options.toolCallId);
133
- }
134
- ```
135
-
136
- This moves the notification wiring into the manager, eliminating the post-spawn mutation in the tool.
137
-
138
- ### Phase 2: Extract modules
139
-
140
- With the API gaps fixed, the extracted modules no longer need `listAgents` or `getRecord` or post-spawn record mutation.
141
-
142
- #### Foreground runner
143
-
144
- After the `onSessionCreated` widening, the foreground callback simplifies to:
145
-
146
- ```typescript
147
- onSessionCreated: (session, record) => {
148
- fgState.setSession(session);
149
- unsubUI = subscribeUIObserver(session, fgState, streamUpdate);
150
- fgId = record.id;
151
- deps.agentActivity.set(record.id, fgState);
152
- deps.widget.ensureTimer();
153
- }
154
- ```
155
-
156
- The `runForeground` function receives narrow deps:
157
-
158
- ```typescript
159
- export interface ForegroundDeps {
160
- manager: { spawnAndWait: AgentToolManager["spawnAndWait"] };
161
- widget: { ensureTimer(): void; markFinished(id: string): void };
162
- agentActivity: AgentActivityAccess;
163
- }
164
- ```
165
-
166
- No `listAgents` needed — the record is delivered by the callback.
167
-
168
- #### Background spawner
169
-
170
- After the `toolCallId` change, the background path simplifies to:
171
-
172
- ```typescript
173
- const id = deps.manager.spawn(ctx, subagentType, prompt, {
174
- ...spawnConfig,
175
- toolCallId,
176
- });
177
- // No getRecord + mutation needed — notification already wired
178
- ```
179
-
180
- The `spawnBackground` function receives narrow deps:
181
-
182
- ```typescript
183
- export interface BackgroundDeps {
184
- manager: { spawn: AgentToolManager["spawn"]; getRecord: AgentToolManager["getRecord"]; getMaxConcurrent: AgentToolManager["getMaxConcurrent"] };
185
- widget: { ensureTimer(): void; update(): void };
186
- agentActivity: AgentActivityAccess;
187
- }
188
- ```
189
-
190
- `getRecord` is still needed for building the result message (checking `status`, `execution.outputFile`), but not for mutation.
191
-
192
- #### What stays in agent-tool.ts
193
-
194
- - `AgentToolDeps`, `AgentToolManager`, `AgentToolWidget`, `AgentActivityAccess` interfaces.
195
- - `createAgentTool` factory: tool name/label/description, parameters schema, `renderCall`, `renderResult`.
196
- - Execute's shared setup: registry reload, type resolution, model resolution, config assembly, detail base.
197
- - Resume path (~27 lines).
198
- - Dispatch to `spawnBackground()` or `runForeground()`.
199
-
200
- #### Helpers relocation
201
-
202
- `getStatusNote` and `buildDetails` move to `tools/helpers.ts`.
203
- Both are pure formatting functions with no dependency on `AgentToolDeps`.
204
-
205
- ### Post-extraction file sizes (estimated)
206
-
207
- | File | Lines |
208
- | ----------------------- | -------------- |
209
- | `agent-tool.ts` | ~250 (was 579) |
210
- | `foreground-runner.ts` | ~110 |
211
- | `background-spawner.ts` | ~70 |
212
- | `helpers.ts` additions | ~50 |
213
-
214
- ## Module-Level Changes
215
-
216
- ### Modified files
217
-
218
- 1. **`src/agent-manager.ts`**
219
- - Change `onSessionCreated` in `AgentSpawnConfig` to `(session: AgentSession, record: AgentRecord) => void`.
220
- - Pass `record` as second argument in `startAgent`'s internal `onSessionCreated` call.
221
- - Add optional `toolCallId?: string` to `AgentSpawnConfig`.
222
- - Wire `record.notification = new NotificationState(options.toolCallId)` in `spawn()` when present.
223
- - Add `NotificationState` import.
224
-
225
- 2. **`src/tools/agent-tool.ts`**
226
- - Update `onSessionCreated` callbacks to accept `(session, record)`.
227
- - Remove `listAgents()` loop in foreground callback — use `record.id` directly.
228
- - Pass `toolCallId` in background spawn config — remove post-spawn `getRecord` + mutation.
229
- - Remove foreground block → `runForeground()` call.
230
- - Remove background block → `spawnBackground()` call.
231
- - Remove `getStatusNote`, `buildDetails` → imported from `helpers.ts`.
232
- - Remove `listAgents` from `AgentToolManager` interface (no longer needed).
233
- - Remove unused imports: `NotificationState`, `describeActivity`, `SPINNER`, `formatMs`.
234
-
235
- 3. **`src/tools/helpers.ts`**
236
- - Add `getStatusNote()` and `buildDetails()` (relocated from `agent-tool.ts`).
237
-
238
- ### New files
239
-
240
- 4. **`src/tools/foreground-runner.ts`**
241
- - `ForegroundDeps` interface, `runForeground()` function.
242
- - Owns: spinner interval, `AgentActivityTracker` creation, `subscribeUIObserver`, streaming `onUpdate`, cleanup, result formatting via `buildDetails`/`getStatusNote`.
243
-
244
- 5. **`src/tools/background-spawner.ts`**
245
- - `BackgroundDeps` interface, `spawnBackground()` function.
246
- - Owns: `AgentActivityTracker` creation, `subscribeUIObserver`, activity map registration, widget update, launch message formatting.
247
-
248
- ### Test files
249
-
250
- 6. **`test/agent-manager.test.ts`**
251
- - Update mock runner calls to pass `record` in `onSessionCreated`.
252
- - Add test: `spawn` wires `NotificationState` when `toolCallId` is provided.
253
- - Add test: `spawn` does not wire `NotificationState` when `toolCallId` is absent.
254
-
255
- 7. **`test/tools/agent-tool.test.ts`**
256
- - Update `onSessionCreated` mock signatures if needed (structural — tests call through `execute`).
257
- - Existing tests remain as integration tests for the dispatch path.
258
-
259
- 8. **`test/tools/helpers.test.ts`** (new or extended)
260
- - Unit tests for `getStatusNote` (all status branches) and `buildDetails`.
261
-
262
- 9. **`test/tools/foreground-runner.test.ts`** (new)
263
- - Spinner lifecycle, streaming updates, cleanup on success/error, result formatting, fallback note.
264
-
265
- 10. **`test/tools/background-spawner.test.ts`** (new)
266
- - Activity tracker registered, widget updated, queued message, launch message format.
267
-
268
- ## Test Impact Analysis
269
-
270
- 1. **New unit tests enabled:**
271
- - `foreground-runner.test.ts` tests spinner lifecycle and streaming with narrow mocks (no full `AgentToolDeps`).
272
- - `background-spawner.test.ts` tests activity registration and message formatting in isolation.
273
- - `helpers.test.ts` tests `getStatusNote` and `buildDetails` as pure functions.
274
- - `agent-manager.test.ts` tests notification wiring at the manager level — moved from tool-level integration.
275
-
276
- 2. **Existing tests that simplify:**
277
- - `agent-tool.test.ts` background tests no longer need to verify notification wiring (now the manager's job).
278
- - The "registers activity in agentActivity map" test stays but becomes a dispatch-level integration test.
279
-
280
- 3. **Existing tests that must stay:**
281
- - All `agent-tool.test.ts` tests exercise the full dispatch path and remain valuable as integration tests.
282
- - All `agent-manager.test.ts` tests that fire `onSessionCreated` must update the mock signature to `(session, record)`.
283
-
284
- ## TDD Order
285
-
286
- 1. **Widen `onSessionCreated` callback to include record.**
287
- Change `AgentSpawnConfig.onSessionCreated` signature to `(session, record)`.
288
- Update `startAgent` to pass `record` as second argument.
289
- Update `agent-tool.ts` foreground callback to use `record.id` instead of `listAgents()` loop.
290
- Remove `listAgents` from `AgentToolManager` interface.
291
- Update `agent-manager.test.ts` mock runner calls.
292
- Test: verify foreground callback receives `record.id` (existing integration tests pass).
293
- Commit: `refactor: widen onSessionCreated to include record`
294
-
295
- 2. **Accept `toolCallId` in `AgentSpawnConfig`.**
296
- Add `toolCallId?: string` to `AgentSpawnConfig`.
297
- Wire `NotificationState` in `spawn()` when `toolCallId` is provided.
298
- Update `agent-tool.ts` background path to pass `toolCallId` instead of post-spawn mutation.
299
- Test: `agent-manager.test.ts` — `spawn` wires notification when `toolCallId` present, skips when absent.
300
- Commit: `refactor: wire NotificationState at spawn time via toolCallId`
301
-
302
- 3. **Relocate `getStatusNote` and `buildDetails` to `tools/helpers.ts`.**
303
- Move both functions.
304
- Update imports in `agent-tool.ts`.
305
- Test: unit tests for `getStatusNote` (all branches) and `buildDetails`.
306
- Commit: `refactor: move getStatusNote and buildDetails to tools/helpers`
307
-
308
- 4. **Extract `spawnBackground` into `tools/background-spawner.ts`.**
309
- Define `BackgroundDeps` interface and `spawnBackground()` function.
310
- Replace background block in `execute` with a call to `spawnBackground()`.
311
- Remove unused imports from `agent-tool.ts`.
312
- Test: `background-spawner.test.ts` — activity registration, widget update, launch message.
313
- Commit: `refactor: extract background spawn to tools/background-spawner`
314
-
315
- 5. **Extract `runForeground` into `tools/foreground-runner.ts`.**
316
- Define `ForegroundDeps` interface and `runForeground()` function.
317
- Replace foreground block in `execute` with a call to `runForeground()`.
318
- Remove unused imports from `agent-tool.ts`.
319
- Test: `foreground-runner.test.ts` — spinner lifecycle, streaming, cleanup, result formatting.
320
- Commit: `refactor: extract foreground execution to tools/foreground-runner`
321
-
322
- 6. **Verify integration.**
323
- Run full test suite and `pnpm run check`.
324
- Commit: `test: verify agent-tool decomposition integration`
325
-
326
- ## Risks and Mitigations
327
-
328
- | Risk | Mitigation |
329
- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
330
- | Widening `onSessionCreated` signature is a breaking change to `AgentSpawnConfig` | `AgentSpawnConfig` is internal (not in package `exports`). The only external caller is `agent-tool.ts`. All test mocks update in the same step. |
331
- | `toolCallId` on `AgentSpawnConfig` couples the manager to notification concerns | The manager already owns the record lifecycle. `NotificationState` is a record collaborator like `execution` and `worktreeState` — the manager already wires those. `toolCallId` is a data-in, not a behavior coupling. |
332
- | Runner's `onSessionCreated` signature stays `(session)` while manager's is `(session, record)` | The manager wraps the runner's callback — the runner never sees the record. No change to runner interface. |
333
- | Circular imports between new modules and `helpers.ts` | `helpers.ts` is a leaf module. The new modules import from it but it imports nothing from them. |
334
-
335
- ## Open Questions
336
-
337
- None — the design is unambiguous after resolving the two API gaps.