@gotgenes/pi-subagents 18.0.0 → 18.0.2

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 (257) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +22 -31
  3. package/docs/architecture/architecture.md +157 -204
  4. package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
  5. package/package.json +5 -6
  6. package/src/lifecycle/subagent.ts +5 -9
  7. package/src/observation/notification.ts +23 -10
  8. package/src/observation/subagent-events-observer.ts +1 -3
  9. package/src/tools/get-result-report.ts +60 -0
  10. package/src/tools/get-result-tool.ts +25 -40
  11. package/src/types.ts +1 -1
  12. package/src/ui/session-navigator.ts +0 -2
  13. package/.prettierignore +0 -5
  14. package/AGENTS.md +0 -7
  15. package/docs/plans/0048-implement-subagents-api.md +0 -304
  16. package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
  17. package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
  18. package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
  19. package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
  20. package/docs/plans/0054-decompose-index-into-modules.md +0 -302
  21. package/docs/plans/0057-structured-debug-logging.md +0 -154
  22. package/docs/plans/0061-session-format-transcript.md +0 -284
  23. package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
  24. package/docs/plans/0069-create-subagent-runtime.md +0 -345
  25. package/docs/plans/0070-extract-event-handlers.md +0 -306
  26. package/docs/plans/0071-extract-session-config-assembler.md +0 -362
  27. package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
  28. package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
  29. package/docs/plans/0077-inject-project-agents-dir.md +0 -115
  30. package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
  31. package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
  32. package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
  33. package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
  34. package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
  35. package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
  36. package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
  37. package/docs/plans/0108-extract-agent-type-registry.md +0 -322
  38. package/docs/plans/0109-extract-settings-manager.md +0 -276
  39. package/docs/plans/0110-agent-activity-tracker.md +0 -297
  40. package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
  41. package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
  42. package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
  43. package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
  44. package/docs/plans/0115-decompose-agent-tool.md +0 -337
  45. package/docs/plans/0116-type-housekeeping.md +0 -351
  46. package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
  47. package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
  48. package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
  49. package/docs/plans/0132-inject-io-into-session-config.md +0 -219
  50. package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
  51. package/docs/plans/0134-reduce-as-any-casts.md +0 -366
  52. package/docs/plans/0135-extract-display-helpers.md +0 -182
  53. package/docs/plans/0136-decompose-agent-menu.md +0 -300
  54. package/docs/plans/0144-consolidate-observation-model.md +0 -263
  55. package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
  56. package/docs/plans/0146-narrow-ui-context.md +0 -319
  57. package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
  58. package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
  59. package/docs/plans/0152-add-prompt-snippet.md +0 -91
  60. package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
  61. package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
  62. package/docs/plans/0166-extract-parent-session-info.md +0 -231
  63. package/docs/plans/0167-narrow-runner-io.md +0 -150
  64. package/docs/plans/0168-extract-tool-filter-config.md +0 -173
  65. package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
  66. package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
  67. package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
  68. package/docs/plans/0172-extract-turn-formatting.md +0 -206
  69. package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
  70. package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
  71. package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
  72. package/docs/plans/0192-define-session-context-interface.md +0 -107
  73. package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
  74. package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
  75. package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
  76. package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
  77. package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
  78. package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
  79. package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
  80. package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
  81. package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
  82. package/docs/plans/0215-decompose-build-parent-context.md +0 -166
  83. package/docs/plans/0216-decompose-start-agent.md +0 -255
  84. package/docs/plans/0217-extract-overwrite-guard.md +0 -176
  85. package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
  86. package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
  87. package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
  88. package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
  89. package/docs/plans/0229-agent-born-complete.md +0 -564
  90. package/docs/plans/0230-extract-concurrency-queue.md +0 -265
  91. package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
  92. package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
  93. package/docs/plans/0237-remove-disallowed-tools.md +0 -180
  94. package/docs/plans/0238-remove-extensions-filtering.md +0 -191
  95. package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
  96. package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
  97. package/docs/plans/0256-extract-worktree-isolation.md +0 -256
  98. package/docs/plans/0257-extract-child-session-factory.md +0 -285
  99. package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
  100. package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
  101. package/docs/plans/0265-born-complete-subagent-session.md +0 -333
  102. package/docs/plans/0270-type-consumable-public-surface.md +0 -204
  103. package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
  104. package/docs/plans/0277-encapsulate-agent-session.md +0 -304
  105. package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
  106. package/docs/plans/0360-custom-agents-default-append.md +0 -132
  107. package/docs/plans/0373-extract-subagent-state.md +0 -250
  108. package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
  109. package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
  110. package/docs/plans/0376-extract-manager-observer.md +0 -232
  111. package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
  112. package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
  113. package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
  114. package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
  115. package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
  116. package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
  117. package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
  118. package/docs/plans/0412-unify-session-mock-builders.md +0 -146
  119. package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
  120. package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
  121. package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
  122. package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
  123. package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
  124. package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
  125. package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
  126. package/docs/plans/0427-reconsider-ui-direction.md +0 -212
  127. package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
  128. package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
  129. package/docs/plans/0444-shrink-widget-to-background-agents.md +0 -156
  130. package/docs/plans/0445-native-session-navigation.md +0 -365
  131. package/docs/plans/0446-spike-session-navigation-entry-criteria.md +0 -171
  132. package/docs/plans/0447-extract-subagents-settings-command.md +0 -220
  133. package/docs/plans/0448-block-disabled-agent-spawn.md +0 -207
  134. package/docs/plans/0462-navigation-renderer-tui-components.md +0 -338
  135. package/docs/plans/0463-file-snapshot-source-evicted-agents.md +0 -306
  136. package/docs/retro/0048-implement-subagents-api.md +0 -44
  137. package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
  138. package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
  139. package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
  140. package/docs/retro/0054-decompose-index-into-modules.md +0 -53
  141. package/docs/retro/0057-structured-debug-logging.md +0 -77
  142. package/docs/retro/0061-session-format-transcript.md +0 -41
  143. package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
  144. package/docs/retro/0069-create-subagent-runtime.md +0 -43
  145. package/docs/retro/0070-extract-event-handlers.md +0 -49
  146. package/docs/retro/0071-extract-session-config-assembler.md +0 -60
  147. package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
  148. package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
  149. package/docs/retro/0077-inject-project-agents-dir.md +0 -33
  150. package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
  151. package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
  152. package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
  153. package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
  154. package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
  155. package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
  156. package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
  157. package/docs/retro/0108-extract-agent-type-registry.md +0 -41
  158. package/docs/retro/0109-extract-settings-manager.md +0 -55
  159. package/docs/retro/0110-agent-activity-tracker.md +0 -44
  160. package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
  161. package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
  162. package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
  163. package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
  164. package/docs/retro/0115-decompose-agent-tool.md +0 -51
  165. package/docs/retro/0116-type-housekeeping.md +0 -42
  166. package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
  167. package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
  168. package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
  169. package/docs/retro/0132-inject-io-into-session-config.md +0 -33
  170. package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
  171. package/docs/retro/0134-reduce-as-any-casts.md +0 -56
  172. package/docs/retro/0135-extract-display-helpers.md +0 -38
  173. package/docs/retro/0136-decompose-agent-menu.md +0 -43
  174. package/docs/retro/0144-consolidate-observation-model.md +0 -39
  175. package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
  176. package/docs/retro/0146-narrow-ui-context.md +0 -70
  177. package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
  178. package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
  179. package/docs/retro/0152-add-prompt-snippet.md +0 -34
  180. package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
  181. package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
  182. package/docs/retro/0166-extract-parent-session-info.md +0 -66
  183. package/docs/retro/0167-narrow-runner-io.md +0 -63
  184. package/docs/retro/0168-extract-tool-filter-config.md +0 -76
  185. package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
  186. package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
  187. package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
  188. package/docs/retro/0172-extract-turn-formatting.md +0 -80
  189. package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
  190. package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
  191. package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
  192. package/docs/retro/0192-define-session-context-interface.md +0 -59
  193. package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
  194. package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
  195. package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
  196. package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
  197. package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
  198. package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
  199. package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
  200. package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
  201. package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
  202. package/docs/retro/0215-decompose-build-parent-context.md +0 -61
  203. package/docs/retro/0216-decompose-start-agent.md +0 -80
  204. package/docs/retro/0217-extract-overwrite-guard.md +0 -63
  205. package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
  206. package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
  207. package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
  208. package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
  209. package/docs/retro/0229-agent-born-complete.md +0 -89
  210. package/docs/retro/0230-extract-concurrency-queue.md +0 -38
  211. package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
  212. package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
  213. package/docs/retro/0237-remove-disallowed-tools.md +0 -78
  214. package/docs/retro/0238-remove-extensions-filtering.md +0 -72
  215. package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
  216. package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
  217. package/docs/retro/0256-extract-worktree-isolation.md +0 -89
  218. package/docs/retro/0257-extract-child-session-factory.md +0 -33
  219. package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
  220. package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
  221. package/docs/retro/0265-born-complete-subagent-session.md +0 -97
  222. package/docs/retro/0270-type-consumable-public-surface.md +0 -108
  223. package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
  224. package/docs/retro/0277-encapsulate-agent-session.md +0 -80
  225. package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
  226. package/docs/retro/0360-custom-agents-default-append.md +0 -81
  227. package/docs/retro/0373-extract-subagent-state.md +0 -94
  228. package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
  229. package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
  230. package/docs/retro/0376-extract-manager-observer.md +0 -81
  231. package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
  232. package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
  233. package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
  234. package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
  235. package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
  236. package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
  237. package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
  238. package/docs/retro/0412-unify-session-mock-builders.md +0 -80
  239. package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
  240. package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
  241. package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
  242. package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
  243. package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
  244. package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
  245. package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
  246. package/docs/retro/0427-reconsider-ui-direction.md +0 -102
  247. package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -45
  248. package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
  249. package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
  250. package/docs/retro/0445-native-session-navigation.md +0 -122
  251. package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
  252. package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
  253. package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
  254. package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
  255. package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
  256. package/src/observation/notification-state.ts +0 -27
  257. package/vitest.config.ts +0 -14
@@ -1,241 +0,0 @@
1
- ---
2
- issue: 112
3
- issue_title: "refactor(pi-subagents): replace AgentManager callbacks with observer interface"
4
- ---
5
-
6
- # Replace AgentManager callbacks with observer interface
7
-
8
- ## Problem Statement
9
-
10
- `AgentManagerOptions` accepts three fire-and-forget callbacks — `onStart`, `onComplete`, `onCompact` — that `index.ts` wires as closure lambdas capturing `runtime`, `pi`, `notifications`, and other extension state.
11
- This is the same callback-threading pattern that was replaced with direct session subscriptions in #100, but one level up.
12
- The callbacks are notification-style (fire-and-forget, no return value) and match the observer pattern exactly.
13
-
14
- ## Goals
15
-
16
- - Replace the three callback parameters on `AgentManagerOptions` with a single `observer?: AgentManagerObserver` interface.
17
- - `index.ts` constructs one observer object instead of three independent closure lambdas.
18
- - `AgentManagerOptions` shrinks by two net fields (remove 3 callbacks, add 1 observer).
19
- - Preserve all existing behavior: lifecycle events, record persistence, notification dispatch, compaction events.
20
- - Non-breaking refactor — no public API changes (the callbacks are internal to the package).
21
-
22
- ## Non-Goals
23
-
24
- - Extracting the observer implementation from `index.ts` into its own module — that can follow if the object grows.
25
- - Changing `RecordObserverOptions` (session-level observer) — it remains a separate concern at a different layer.
26
- - Narrowing `AgentToolDeps` or `AgentMenuDeps` — tracked in #114.
27
- - Disambiguating `SpawnOptions` — tracked in #113.
28
-
29
- ## Background
30
-
31
- ### Current callback wiring
32
-
33
- `agent-manager.ts` defines three callback type aliases and stores them as private fields:
34
-
35
- ```typescript
36
- export type OnAgentStart = (record: AgentRecord) => void;
37
- export type OnAgentComplete = (record: AgentRecord) => void;
38
- export type OnAgentCompact = (record: AgentRecord, info: CompactionInfo) => void;
39
- ```
40
-
41
- `AgentManager` invokes them at three points:
42
-
43
- 1. `onStart` — called in `startAgent()` after `record.markRunning()`.
44
- 2. `onComplete` — called in `startAgent()`'s `.then()` and `.catch()` handlers for background agents, and in `drainQueue()` on late failure.
45
- 3. `onCompact` — relayed through `subscribeRecordObserver()` → `RecordObserverOptions.onCompact`.
46
-
47
- `index.ts` builds ~30 lines of closure lambdas (lines 73–116) that capture `pi`, `notifications`, and `buildEventData`.
48
-
49
- ### Observer pattern already established
50
-
51
- `record-observer.ts` and `ui/ui-observer.ts` are session-level observers that subscribe directly to session events.
52
- This refactoring applies the same principle at the manager level — grouping related notification callbacks into a single interface.
53
-
54
- ### Dependency: issue #111 (AgentRecord lifecycle split)
55
-
56
- Issue #111 is closed.
57
- The observer interface is designed against the current record shape, which reflects the post-#111 lifecycle split.
58
-
59
- ### Architecture reference
60
-
61
- Phase 7, Step C in `docs/architecture/architecture.md`.
62
-
63
- ## Design Overview
64
-
65
- ### Observer interface
66
-
67
- ```typescript
68
- export interface AgentManagerObserver {
69
- onAgentStarted(record: AgentRecord): void;
70
- onAgentCompleted(record: AgentRecord): void;
71
- onAgentCompacted(record: AgentRecord, info: CompactionInfo): void;
72
- }
73
- ```
74
-
75
- All three methods are fire-and-forget (void return, no async).
76
- The interface uses past-tense naming (`Started`, `Completed`, `Compacted`) to signal that these are after-the-fact notifications, not hooks that influence the operation.
77
-
78
- ### `AgentManagerOptions` change
79
-
80
- ```typescript
81
- export interface AgentManagerOptions {
82
- runner: AgentRunner;
83
- worktrees: WorktreeManager;
84
- exec: ShellExec;
85
- registry: AgentTypeRegistry;
86
- getMaxConcurrent?: () => number;
87
- getRunConfig?: () => RunConfig;
88
- observer?: AgentManagerObserver; // replaces onStart, onComplete, onCompact
89
- }
90
- ```
91
-
92
- Fields go from 9 → 7 (remove 3 callbacks, add 1 observer).
93
-
94
- ### AgentManager internal changes
95
-
96
- The three private fields (`onStart`, `onComplete`, `onCompact`) become one: `private observer?: AgentManagerObserver`.
97
- Call sites change from `this.onStart?.(record)` to `this.observer?.onAgentStarted(record)`.
98
-
99
- The `onCompact` relay into `subscribeRecordObserver` changes from:
100
-
101
- ```typescript
102
- onCompact: (r, info) => this.onCompact?.(r, info),
103
- ```
104
-
105
- to:
106
-
107
- ```typescript
108
- onCompact: (r, info) => this.observer?.onAgentCompacted(r, info),
109
- ```
110
-
111
- ### `CompactionInfo` stays in `agent-manager.ts`
112
-
113
- `CompactionInfo` is a data shape consumed by the observer interface and already defined in `agent-manager.ts`.
114
- It stays co-located since both `AgentManagerObserver` and `CompactionInfo` are exported from the same module.
115
- `record-observer.ts` continues to import `CompactionInfo` from `agent-manager.ts`.
116
-
117
- ### Observer construction in `index.ts`
118
-
119
- The three closure lambdas collapse into one object literal:
120
-
121
- ```typescript
122
- const observer: AgentManagerObserver = {
123
- onAgentStarted(record) {
124
- pi.events.emit("subagents:started", {
125
- id: record.id, type: record.type, description: record.description,
126
- });
127
- },
128
- onAgentCompleted(record) {
129
- const isError = record.status === "error" || record.status === "stopped" || record.status === "aborted";
130
- const eventData = buildEventData(record);
131
- if (isError) pi.events.emit("subagents:failed", eventData);
132
- else pi.events.emit("subagents:completed", eventData);
133
-
134
- pi.appendEntry("subagents:record", { /* same fields as today */ });
135
-
136
- if (record.notification?.resultConsumed) {
137
- notifications.cleanupCompleted(record.id);
138
- return;
139
- }
140
- notifications.sendCompletion(record);
141
- },
142
- onAgentCompacted(record, info) {
143
- pi.events.emit("subagents:compacted", {
144
- id: record.id, type: record.type, description: record.description,
145
- reason: info.reason, tokensBefore: info.tokensBefore,
146
- compactionCount: record.compactionCount,
147
- });
148
- },
149
- };
150
- ```
151
-
152
- Passed as `observer` to `new AgentManager({ ..., observer })`.
153
-
154
- ### Removed exports
155
-
156
- The three callback type aliases are removed:
157
-
158
- - `OnAgentStart`
159
- - `OnAgentComplete`
160
- - `OnAgentCompact`
161
-
162
- These are only imported in `agent-manager.test.ts` — no production consumers outside `agent-manager.ts`.
163
-
164
- ## Module-Level Changes
165
-
166
- ### `src/agent-manager.ts`
167
-
168
- - Add `AgentManagerObserver` interface (3 methods).
169
- - Remove `OnAgentStart`, `OnAgentComplete`, `OnAgentCompact` type aliases.
170
- - Replace `onStart`, `onComplete`, `onCompact` fields in `AgentManagerOptions` with `observer?: AgentManagerObserver`.
171
- - Replace three private fields with `private observer?: AgentManagerObserver`.
172
- - Update constructor to assign `this.observer = options.observer`.
173
- - Update all call sites: `this.onStart?.(record)` → `this.observer?.onAgentStarted(record)`, etc.
174
- - The `onCompact` relay to `subscribeRecordObserver` uses `this.observer?.onAgentCompacted`.
175
-
176
- ### `src/index.ts`
177
-
178
- - Replace the three closure-lambda properties (`onComplete:`, `onStart:`, `onCompact:`) with a single `observer` object literal.
179
- - Import `AgentManagerObserver` from `agent-manager.ts`.
180
- - Remove any now-unused callback type imports.
181
-
182
- ### `src/record-observer.ts`
183
-
184
- - No changes.
185
- `RecordObserverOptions.onCompact` stays as-is — it is the session-level relay, not the manager-level observer.
186
- `CompactionInfo` import from `agent-manager.ts` stays unchanged.
187
-
188
- ### `test/agent-manager.test.ts`
189
-
190
- - Update imports: remove `OnAgentStart`, `OnAgentComplete`, `OnAgentCompact`; add `AgentManagerObserver`.
191
- - Update `createManager` helper: replace the three callback overrides with `observer?: Partial<AgentManagerObserver>`.
192
- The factory spreads a no-op default observer with test-provided overrides.
193
- - Update each test that wires a callback to construct an observer object instead.
194
-
195
- ## Test Impact Analysis
196
-
197
- 1. No new unit tests are enabled by this refactoring — it's a 1:1 shape change.
198
- 2. No existing tests become redundant — each test exercises a specific lifecycle scenario (race condition, foreground vs background, error handling, queue drain).
199
- 3. All existing `agent-manager.test.ts` tests stay, with mechanical updates to the observer wiring.
200
- The assertions remain the same (e.g., "observer.onAgentCompleted fires with `resultConsumed=false` when `markConsumed` called after await").
201
-
202
- ## TDD Order
203
-
204
- ### Step 1: Introduce `AgentManagerObserver` interface alongside existing callbacks
205
-
206
- Add the interface to `agent-manager.ts`.
207
- No production behavior changes — the interface is unused at this point.
208
-
209
- - Commit: `refactor: add AgentManagerObserver interface`
210
-
211
- ### Step 2: Switch `AgentManager` internals to observer
212
-
213
- 1. Replace the three `onStart`/`onComplete`/`onCompact` fields on `AgentManagerOptions` with `observer?: AgentManagerObserver`.
214
- 2. Replace the three private fields with one `private observer?: AgentManagerObserver`.
215
- 3. Update all internal call sites (`this.onStart?.(record)` → `this.observer?.onAgentStarted(record)`, etc.).
216
- 4. Remove the three callback type aliases (`OnAgentStart`, `OnAgentComplete`, `OnAgentCompact`).
217
- 5. Update `test/agent-manager.test.ts`: change imports, update `createManager` helper and all test call sites to construct observer objects instead of individual callbacks.
218
- 6. Run `pnpm run check` to verify types.
219
-
220
- - Commit: `refactor: replace AgentManager callbacks with observer interface (#112)`
221
-
222
- ### Step 3: Update `index.ts` to construct observer
223
-
224
- 1. Replace the three closure-lambda properties in the `new AgentManager({...})` call with a single `observer` object.
225
- 2. Import `AgentManagerObserver` type.
226
- 3. Remove unused callback type imports.
227
- 4. Run full test suite.
228
-
229
- - Commit: `refactor: construct AgentManagerObserver in index.ts (#112)`
230
-
231
- ## Risks and Mitigations
232
-
233
- | Risk | Mitigation |
234
- | ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
235
- | Tests break silently because esbuild ignores excess properties — old `onComplete` fields pass through without error | Step 2 removes the type aliases, so TypeScript catches any test still using the old shape via `pnpm run check` |
236
- | `onComplete` error-swallowing behavior changes | The `try/catch` around `this.onComplete?.(record)` in the `.then()` path moves exactly to `this.observer?.onAgentCompleted(record)` — same guard, same catch, same debugLog |
237
- | `Partial<AgentManagerObserver>` in test factory silently drops required methods | Tests that need a specific method construct it explicitly; the factory only provides a convenient default for tests that don't care about any observer method |
238
-
239
- ## Open Questions
240
-
241
- - None — the issue's proposed design is unambiguous and aligns with the established session-observer pattern.
@@ -1,155 +0,0 @@
1
- ---
2
- issue: 113
3
- issue_title: "refactor(pi-subagents): disambiguate SpawnOptions (public vs internal)"
4
- ---
5
-
6
- # Disambiguate SpawnOptions (public vs internal)
7
-
8
- ## Problem Statement
9
-
10
- `SpawnOptions` is defined in two places with the same name but incompatible shapes:
11
-
12
- - `service.ts` (public API): 8 fields, JSON-friendly (`model` is `string`, `thinkingLevel` is `string`, uses `foreground` not `isBackground`).
13
- - `agent-manager.ts` (internal): 13 fields, runtime types (`model` is `Model<any>`, `thinkingLevel` is `ThinkingLevel`, includes `signal`, `onSessionCreated`, `invocation`).
14
-
15
- The name collision makes it ambiguous which type a reader is working with when they see `SpawnOptions` in a signature.
16
- `service-adapter.ts` manually converts between the two shapes.
17
-
18
- ## Goals
19
-
20
- - Rename the internal `SpawnOptions` in `agent-manager.ts` to `AgentSpawnConfig`.
21
- - Keep the public `SpawnOptions` in `service.ts` unchanged — it's the published API.
22
- - Update all internal consumers (`agent-tool.ts`, `agent-menu.ts`, `agent-manager.ts`) to use the new name.
23
- - Update the `SpawnArgs` internal interface in `agent-manager.ts` to reference `AgentSpawnConfig`.
24
- - Non-breaking refactor — the public API surface is unchanged.
25
-
26
- ## Non-Goals
27
-
28
- - Splitting `AgentSpawnConfig` into agent-configuration fields vs execution/lifecycle fields — the issue mentions this as a "consider" item; defer to a follow-up if the type grows further.
29
- - Narrowing `AgentToolDeps` or `AgentMenuDeps` — tracked in #114.
30
- - Removing `onSessionCreated` — it's a legitimate per-spawn callback used by `agent-tool.ts` for UI streaming, structurally different from the lifecycle observer (#112).
31
-
32
- ## Background
33
-
34
- ### Current consumers of internal `SpawnOptions`
35
-
36
- | File | How it references `SpawnOptions` |
37
- | --------------------- | ------------------------------------------------------------------------------------------- |
38
- | `agent-manager.ts` | Defines the type; uses it in `spawn()`, `spawnAndWait()`, and `SpawnArgs` |
39
- | `tools/agent-tool.ts` | Imports and uses in `AgentToolManager.spawn` and `AgentToolManager.spawnAndWait` signatures |
40
- | `ui/agent-menu.ts` | Imports and uses in `AgentMenuManager.spawnAndWait` signature |
41
-
42
- ### Public `SpawnOptions` in `service.ts`
43
-
44
- Defined alongside `SubagentsService`.
45
- Used by `service-adapter.ts` at the conversion boundary.
46
- Published via `package.json` exports — **not touched by this change**.
47
-
48
- ### Dependency: issue #112 (observer refactor)
49
-
50
- Issue #112 is closed.
51
- The observer eliminated `onStart`/`onComplete`/`onCompact` from `AgentManagerOptions`.
52
- `onSessionCreated` remains on the internal `SpawnOptions` (now `AgentSpawnConfig`) — it's per-spawn, not per-manager.
53
-
54
- ### Architecture reference
55
-
56
- Phase 7, Step D1 in `docs/architecture/architecture.md`.
57
-
58
- ## Design Overview
59
-
60
- This is a pure rename — no structural or behavioral changes.
61
- The internal `SpawnOptions` becomes `AgentSpawnConfig`.
62
- Every `import type { SpawnOptions }` from `"../agent-manager.js"` or `"./agent-manager.js"` becomes `import type { AgentSpawnConfig }`.
63
-
64
- The name `AgentSpawnConfig` was chosen because:
65
-
66
- 1. It disambiguates from the public `SpawnOptions`.
67
- 2. It follows the established naming convention in this package (`AgentRecord`, `AgentInvocation`, `AgentTypeRegistry`).
68
- 3. "Config" conveys that this is a configuration bag assembled by the caller and consumed by the manager — not a service-level options type.
69
-
70
- ### Type shape (unchanged)
71
-
72
- ```typescript
73
- export interface AgentSpawnConfig {
74
- description: string;
75
- model?: Model<any>;
76
- maxTurns?: number;
77
- isolated?: boolean;
78
- inheritContext?: boolean;
79
- thinkingLevel?: ThinkingLevel;
80
- isBackground?: boolean;
81
- bypassQueue?: boolean;
82
- isolation?: IsolationMode;
83
- invocation?: AgentInvocation;
84
- signal?: AbortSignal;
85
- onSessionCreated?: (session: AgentSession) => void;
86
- parentSessionFile?: string;
87
- parentSessionId?: string;
88
- }
89
- ```
90
-
91
- ## Module-Level Changes
92
-
93
- ### `src/agent-manager.ts`
94
-
95
- - Rename `export interface SpawnOptions` → `export interface AgentSpawnConfig`.
96
- - Update `SpawnArgs.options` type from `SpawnOptions` to `AgentSpawnConfig`.
97
- - Update `spawn()` parameter type from `SpawnOptions` to `AgentSpawnConfig`.
98
- - Update `spawnAndWait()` parameter type from `Omit<SpawnOptions, "isBackground">` to `Omit<AgentSpawnConfig, "isBackground">`.
99
-
100
- ### `src/tools/agent-tool.ts`
101
-
102
- - Change import from `SpawnOptions` to `AgentSpawnConfig`.
103
- - Update `AgentToolManager.spawn` and `AgentToolManager.spawnAndWait` signatures.
104
-
105
- ### `src/ui/agent-menu.ts`
106
-
107
- - Change import from `SpawnOptions` to `AgentSpawnConfig`.
108
- - Update `AgentMenuManager.spawnAndWait` signature.
109
-
110
- ### `src/service.ts`
111
-
112
- - No changes — the public `SpawnOptions` stays as-is.
113
-
114
- ### `src/service-adapter.ts`
115
-
116
- - No changes — it already uses `unknown` for the spawn options parameter in `AgentManagerLike`.
117
-
118
- ### `test/agent-manager.test.ts`
119
-
120
- - No import changes needed — the test file does not import `SpawnOptions`.
121
- - One test description string mentions "SpawnOptions" → update to "AgentSpawnConfig" for accuracy.
122
-
123
- ## Test Impact Analysis
124
-
125
- 1. No new tests are enabled by this rename — it's a 1:1 name substitution.
126
- 2. No existing tests become redundant.
127
- 3. All existing tests stay as-is — they construct raw object literals that structurally satisfy the type regardless of its name.
128
-
129
- ## TDD Order
130
-
131
- ### Step 1: Rename `SpawnOptions` to `AgentSpawnConfig` and update all consumers
132
-
133
- 1. Rename the interface in `agent-manager.ts`.
134
- 2. Update `SpawnArgs`, `spawn()`, and `spawnAndWait()` in `agent-manager.ts`.
135
- 3. Update the import and signatures in `tools/agent-tool.ts`.
136
- 4. Update the import and signature in `ui/agent-menu.ts`.
137
- 5. Update the test description string in `test/agent-manager.test.ts`.
138
- 6. Run `pnpm run check` to verify types.
139
- 7. Run `pnpm vitest run` to verify all tests pass.
140
-
141
- - Commit: `refactor: rename internal SpawnOptions to AgentSpawnConfig (#113)`
142
-
143
- This is a single-step refactor because the rename is mechanical and all consumers must be updated atomically for the type checker to stay green.
144
-
145
- ## Risks and Mitigations
146
-
147
- | Risk | Mitigation |
148
- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
149
- | Missed consumer still references old name | `pnpm run check` will catch any unresolved `SpawnOptions` import from `agent-manager.ts` since the export no longer exists |
150
- | Test descriptions become misleading | Grep for "SpawnOptions" in test files and update any description strings that reference the old name |
151
- | Confusion with `service.ts` `SpawnOptions` during review | The plan is scoped to internal-only changes; `service.ts` is explicitly listed as "no changes" |
152
-
153
- ## Open Questions
154
-
155
- - None — the rename is unambiguous and aligns with both the issue proposal and the architecture doc.
@@ -1,279 +0,0 @@
1
- ---
2
- issue: 114
3
- issue_title: "refactor(pi-subagents): narrow AgentToolDeps and AgentMenuDeps"
4
- ---
5
-
6
- # Narrow AgentToolDeps and AgentMenuDeps
7
-
8
- ## Problem Statement
9
-
10
- With the foundational extractions complete — `AgentTypeRegistry` (#108), `SettingsManager` (#109), `AgentActivityTracker` (#110), and `AgentManagerObserver` (#112) — the two widest dependency bags in the extension still carry fields that belong on their collaborators.
11
-
12
- `AgentToolDeps` has 9 fields: 3 are description-text strings derivable from the registry, 1 is a raw `emitEvent` callback that the observer should own, and the `agentActivity` Map is passed as raw mutable state.
13
- `AgentMenuDeps` has 8 fields: `emitEvent` is defined but never referenced in the module (dead field).
14
-
15
- Each excess field inflates test mock construction and obscures the real dependency surface.
16
-
17
- ## Goals
18
-
19
- - Remove `emitEvent` from both `AgentToolDeps` and `AgentMenuDeps`.
20
- - Remove `typeListText` and `availableTypesText` from `AgentToolDeps` — derive them from `registry` inside `createAgentTool`.
21
- - Add `onAgentCreated` to `AgentManagerObserver` so the `subagents:created` event is emitted by the observer, not the tool.
22
- - Narrow `agentActivity` in both interfaces to a typed read/write interface instead of raw `Map`.
23
- - Final counts: `AgentToolDeps` 9 → 6, `AgentMenuDeps` 8 → 7.
24
-
25
- ## Non-Goals
26
-
27
- - Removing `agentDir` from `AgentToolDeps` — it is not derivable from the registry (it comes from the Pi SDK's `getAgentDir()`).
28
- - Adding presentation methods to `AgentTypeRegistry` — that would mix SRP concerns.
29
- - Splitting `agent-tool.ts` foreground/background (tracked in #115).
30
- - Removing `personalAgentsDir` / `projectAgentsDir` from `AgentMenuDeps` — they are genuine menu-level concerns (file management UI).
31
-
32
- ## Background
33
-
34
- ### Prerequisite status
35
-
36
- All prerequisites are implemented and merged:
37
-
38
- | Issue | Title | Status |
39
- | ----- | ---------------------------------------------- | ------- |
40
- | #108 | Extract `AgentTypeRegistry` | ✅ Done |
41
- | #109 | Extract `SettingsManager` | ✅ Done |
42
- | #110 | `AgentActivityTracker` | ✅ Done |
43
- | #112 | Replace `AgentManager` callbacks with observer | ✅ Done |
44
- | #113 | Disambiguate `SpawnOptions` | ✅ Done |
45
- | #118 | `SettingsManager` apply methods | ✅ Done |
46
-
47
- ### Current interfaces
48
-
49
- ```typescript
50
- // tools/agent-tool.ts — 9 fields
51
- interface AgentToolDeps {
52
- manager: AgentToolManager;
53
- widget: AgentToolWidget;
54
- agentActivity: Map<string, AgentActivityTracker>;
55
- emitEvent: (name: string, data: unknown) => void;
56
- registry: AgentTypeRegistry;
57
- typeListText: string;
58
- availableTypesText: string;
59
- agentDir: string;
60
- settings: { readonly defaultMaxTurns: number | undefined };
61
- }
62
-
63
- // ui/agent-menu.ts — 8 fields
64
- interface AgentMenuDeps {
65
- manager: AgentMenuManager;
66
- registry: AgentTypeRegistry;
67
- agentActivity: Map<string, AgentActivityTracker>;
68
- getModelLabel: (type: string, registry?: ModelRegistry) => string;
69
- settings: AgentMenuSettings;
70
- emitEvent: (name: string, data: unknown) => void; // ← dead field
71
- personalAgentsDir: string;
72
- projectAgentsDir: string;
73
- }
74
- ```
75
-
76
- ### Relevant design principles
77
-
78
- - **Dependency width** (code-design skill): do not pass a shared bag to functions that only use a subset.
79
- - **Output arguments**: `agentActivity` is a raw `Map` mutated via `.set()` and `.delete()` — encapsulate behind methods.
80
- - **ISP**: consumers should depend on the narrowest interface they need.
81
-
82
- ## Design Overview
83
-
84
- ### 1. Move `subagents:created` to observer
85
-
86
- The `AgentManagerObserver` interface gains an `onAgentCreated` method.
87
- `AgentManager.spawn()` calls `observer.onAgentCreated(record)` after creating the record.
88
- The observer implementation in `index.ts` emits `pi.events.emit("subagents:created", ...)`.
89
- The tool no longer calls `deps.emitEvent(...)`.
90
-
91
- The event payload includes `id`, `type`, `description`, and `isBackground`.
92
- Since `isBackground` is known at spawn-time (it's part of the spawn config), the observer has all needed data.
93
-
94
- ```typescript
95
- interface AgentManagerObserver {
96
- onAgentStarted(record: AgentRecord): void;
97
- onAgentCompleted(record: AgentRecord): void;
98
- onAgentCompacted(record: AgentRecord, info: CompactionInfo): void;
99
- onAgentCreated(record: AgentRecord): void; // ← new
100
- }
101
- ```
102
-
103
- ### 2. Derive description text from registry
104
-
105
- Move `buildTypeListText()` from `index.ts` to `tools/helpers.ts` as a pure function that accepts the registry and `agentDir`:
106
-
107
- ```typescript
108
- function buildTypeListText(
109
- registry: AgentConfigLookup & { getDefaultAgentNames(): string[]; getUserAgentNames(): string[] },
110
- agentDir: string,
111
- ): string;
112
- ```
113
-
114
- Inside `createAgentTool`, compute both strings from `deps.registry` and `deps.agentDir`:
115
-
116
- ```typescript
117
- const typeListText = buildTypeListText(deps.registry, deps.agentDir);
118
- const availableTypesText = deps.registry.getAvailableTypes().join(", ");
119
- ```
120
-
121
- This removes `typeListText` and `availableTypesText` from the interface.
122
- The helper requires `getModelLabelFromConfig`, which already lives in `tools/helpers.ts`.
123
-
124
- ### 3. Narrow agentActivity to a typed interface
125
-
126
- Instead of `Map<string, AgentActivityTracker>`, both interfaces accept a narrow typed interface matching their actual usage:
127
-
128
- ```typescript
129
- /** Read/write interface for agent-tool's activity tracking needs. */
130
- interface AgentActivityAccess {
131
- get(id: string): AgentActivityTracker | undefined;
132
- set(id: string, tracker: AgentActivityTracker): void;
133
- delete(id: string): void;
134
- }
135
- ```
136
-
137
- The `AgentMenuDeps` only reads (`.get()`), so it gets a narrower read-only type:
138
-
139
- ```typescript
140
- /** Read-only interface for menu's conversation viewer. */
141
- interface AgentActivityReader {
142
- get(id: string): AgentActivityTracker | undefined;
143
- }
144
- ```
145
-
146
- The runtime's `Map<string, AgentActivityTracker>` satisfies both interfaces structurally.
147
- No wrapper class is needed — `Map` already implements `get/set/delete`.
148
- The benefit is that the type signature communicates the actual usage pattern.
149
-
150
- ### 4. Remove dead `emitEvent` from `AgentMenuDeps`
151
-
152
- This field is defined in the interface but never referenced inside `agent-menu.ts`.
153
- Remove it from the interface and from the construction site in `index.ts`.
154
-
155
- ### Final interfaces
156
-
157
- ```typescript
158
- // tools/agent-tool.ts — 6 fields (was 9)
159
- interface AgentToolDeps {
160
- manager: AgentToolManager;
161
- widget: AgentToolWidget;
162
- agentActivity: AgentActivityAccess;
163
- registry: AgentTypeRegistry;
164
- agentDir: string;
165
- settings: { readonly defaultMaxTurns: number | undefined };
166
- }
167
-
168
- // ui/agent-menu.ts — 7 fields (was 8)
169
- interface AgentMenuDeps {
170
- manager: AgentMenuManager;
171
- registry: AgentTypeRegistry;
172
- agentActivity: AgentActivityReader;
173
- getModelLabel: (type: string, registry?: ModelRegistry) => string;
174
- settings: AgentMenuSettings;
175
- personalAgentsDir: string;
176
- projectAgentsDir: string;
177
- }
178
- ```
179
-
180
- ## Module-Level Changes
181
-
182
- ### Modified files
183
-
184
- 1. **`src/agent-manager.ts`** — Call `observer.onAgentCreated(record)` in `spawn()` after creating the record.
185
- Update `AgentManagerObserver` interface to include `onAgentCreated`.
186
-
187
- 2. **`src/tools/agent-tool.ts`** — Remove `emitEvent`, `typeListText`, `availableTypesText` from `AgentToolDeps`.
188
- Add `AgentActivityAccess` interface.
189
- Derive description text from `registry` + `agentDir` inside `createAgentTool`.
190
- Remove `deps.emitEvent(...)` call.
191
- Replace `Map<string, AgentActivityTracker>` with `AgentActivityAccess`.
192
-
193
- 3. **`src/tools/helpers.ts`** — Add `buildTypeListText(registry, agentDir)` extracted from `index.ts`.
194
-
195
- 4. **`src/ui/agent-menu.ts`** — Remove `emitEvent` from `AgentMenuDeps`.
196
- Add `AgentActivityReader` interface.
197
- Replace `Map<string, AgentActivityTracker>` with `AgentActivityReader`.
198
-
199
- 5. **`src/index.ts`** — Remove `buildTypeListText` closure.
200
- Remove `typeListText`, `availableTypesText`, `emitEvent` from the `AgentToolDeps` construction.
201
- Remove `emitEvent` from the `AgentMenuDeps` construction.
202
- Add `onAgentCreated` to the observer object.
203
-
204
- 6. **`test/tools/agent-tool.test.ts`** — Update `makeDeps` factory: remove `emitEvent`, `typeListText`, `availableTypesText`.
205
- Update assertions that check `emitEvent` was called.
206
-
207
- 7. **`test/ui/agent-menu.test.ts`** — Update `makeDeps` factory: remove `emitEvent`.
208
-
209
- 8. **`test/agent-manager.test.ts`** — Add test for `observer.onAgentCreated` being called during spawn.
210
-
211
- ## Test Impact Analysis
212
-
213
- 1. **New tests enabled**: `observer.onAgentCreated` can be tested in `agent-manager.test.ts` — verify it fires during `spawn()` with the correct record.
214
-
215
- 2. **Tests that simplify**: `agent-tool.test.ts` mock factory drops 3 fields (`emitEvent`, `typeListText`, `availableTypesText`).
216
- Tests asserting `deps.emitEvent` was called become assertions that the observer was invoked (tested at the manager level instead).
217
- `agent-menu.test.ts` mock factory drops 1 field (`emitEvent`).
218
-
219
- 3. **Tests that stay**: all tool-behavior tests (spawn paths, resume, error handling) remain — they test the tool's own logic, not the narrowed plumbing.
220
-
221
- ## TDD Order
222
-
223
- 1. **Add `onAgentCreated` to observer interface and manager.**
224
- Add the method to `AgentManagerObserver`.
225
- Call it in `AgentManager.spawn()`.
226
- Test: verify `observer.onAgentCreated` fires with the created record.
227
- Commit: `feat: add onAgentCreated to AgentManagerObserver`
228
-
229
- 2. **Extract `buildTypeListText` to helpers.**
230
- Move the function from `index.ts` to `tools/helpers.ts` as a pure function.
231
- Test: unit test `buildTypeListText` with a mock registry.
232
- Update `index.ts` to import and call the extracted helper.
233
- Commit: `refactor: extract buildTypeListText to tools/helpers`
234
-
235
- 3. **Derive description text inside `createAgentTool`.**
236
- Remove `typeListText` and `availableTypesText` from `AgentToolDeps`.
237
- Compute them from `deps.registry` + `deps.agentDir` inside `createAgentTool`.
238
- Update `index.ts` construction site.
239
- Update `agent-tool.test.ts` mock factory.
240
- Test: verify tool description still contains expected text.
241
- Commit: `refactor: derive description text from registry in createAgentTool`
242
-
243
- 4. **Remove `emitEvent` from `AgentToolDeps`.**
244
- Remove the field from the interface.
245
- Remove the `deps.emitEvent(...)` call in the background spawn path.
246
- Wire `onAgentCreated` in the `index.ts` observer to emit `subagents:created`.
247
- Update `agent-tool.test.ts` (remove `emitEvent` from factory, remove/update related assertions).
248
- Commit: `refactor: remove emitEvent from AgentToolDeps`
249
-
250
- 5. **Remove dead `emitEvent` from `AgentMenuDeps`.**
251
- Remove the field from the interface.
252
- Remove from `index.ts` construction site.
253
- Update `agent-menu.test.ts` mock factory.
254
- Commit: `refactor: remove dead emitEvent from AgentMenuDeps`
255
-
256
- 6. **Narrow `agentActivity` to typed interfaces.**
257
- Add `AgentActivityAccess` interface to `agent-tool.ts`.
258
- Add `AgentActivityReader` interface to `agent-menu.ts`.
259
- Replace `Map<string, AgentActivityTracker>` with the narrow type in both interfaces.
260
- Update test factories (no functional change — `Map` satisfies both interfaces).
261
- Commit: `refactor: narrow agentActivity to typed interfaces`
262
-
263
- ## Risks and Mitigations
264
-
265
- | Risk | Mitigation |
266
- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
267
- | `subagents:created` event data changes shape when moved to observer | Observer receives the full `AgentRecord` which contains `id`, `type`, `description`. `isBackground` must be derivable from the record or spawn config — verify the record carries this at spawn time. |
268
- | `buildTypeListText` depends on `getModelLabelFromConfig` which is in `tools/helpers.ts` | This is already the target file — no circular dependency risk. |
269
- | Third-party consumers rely on `emitEvent` presence in `AgentToolDeps` | `AgentToolDeps` is not in the public `exports` — it's internal. No external API breakage. |
270
- | `AgentActivityAccess` interface is structurally identical to a subset of `Map` | This is intentional — the `Map` satisfies it without a wrapper. If a non-Map implementation is needed later, the interface is already in place. |
271
-
272
- ## Open Questions
273
-
274
- 1. Should `onAgentCreated` receive the full `AgentRecord` or a narrow payload?
275
- The other observer methods receive `AgentRecord` — consistency suggests the same.
276
- The `isBackground` flag is needed for the event payload; verify it's available on the record at creation time (it should be, since background is set at spawn).
277
- 2. Should `steer-tool.ts`'s `emitEvent` (emits `subagents:steered`) also move to the observer?
278
- It's a separate concern (tool-level steering) and a different event.
279
- Defer to a follow-up if desired.