@gotgenes/pi-subagents 18.0.1 → 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 (260) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/docs/architecture/architecture.md +157 -204
  3. package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
  4. package/package.json +5 -6
  5. package/src/lifecycle/subagent.ts +5 -9
  6. package/src/observation/notification.ts +23 -10
  7. package/src/observation/subagent-events-observer.ts +1 -3
  8. package/src/tools/get-result-report.ts +60 -0
  9. package/src/tools/get-result-tool.ts +25 -40
  10. package/src/types.ts +1 -1
  11. package/src/ui/session-navigator.ts +0 -2
  12. package/.prettierignore +0 -5
  13. package/AGENTS.md +0 -7
  14. package/docs/plans/0048-implement-subagents-api.md +0 -304
  15. package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
  16. package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
  17. package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
  18. package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
  19. package/docs/plans/0054-decompose-index-into-modules.md +0 -302
  20. package/docs/plans/0057-structured-debug-logging.md +0 -154
  21. package/docs/plans/0061-session-format-transcript.md +0 -284
  22. package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
  23. package/docs/plans/0069-create-subagent-runtime.md +0 -345
  24. package/docs/plans/0070-extract-event-handlers.md +0 -306
  25. package/docs/plans/0071-extract-session-config-assembler.md +0 -362
  26. package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
  27. package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
  28. package/docs/plans/0077-inject-project-agents-dir.md +0 -115
  29. package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
  30. package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
  31. package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
  32. package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
  33. package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
  34. package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
  35. package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
  36. package/docs/plans/0108-extract-agent-type-registry.md +0 -322
  37. package/docs/plans/0109-extract-settings-manager.md +0 -276
  38. package/docs/plans/0110-agent-activity-tracker.md +0 -297
  39. package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
  40. package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
  41. package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
  42. package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
  43. package/docs/plans/0115-decompose-agent-tool.md +0 -337
  44. package/docs/plans/0116-type-housekeeping.md +0 -351
  45. package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
  46. package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
  47. package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
  48. package/docs/plans/0132-inject-io-into-session-config.md +0 -219
  49. package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
  50. package/docs/plans/0134-reduce-as-any-casts.md +0 -366
  51. package/docs/plans/0135-extract-display-helpers.md +0 -182
  52. package/docs/plans/0136-decompose-agent-menu.md +0 -300
  53. package/docs/plans/0144-consolidate-observation-model.md +0 -263
  54. package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
  55. package/docs/plans/0146-narrow-ui-context.md +0 -319
  56. package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
  57. package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
  58. package/docs/plans/0152-add-prompt-snippet.md +0 -91
  59. package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
  60. package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
  61. package/docs/plans/0166-extract-parent-session-info.md +0 -231
  62. package/docs/plans/0167-narrow-runner-io.md +0 -150
  63. package/docs/plans/0168-extract-tool-filter-config.md +0 -173
  64. package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
  65. package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
  66. package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
  67. package/docs/plans/0172-extract-turn-formatting.md +0 -206
  68. package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
  69. package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
  70. package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
  71. package/docs/plans/0192-define-session-context-interface.md +0 -107
  72. package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
  73. package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
  74. package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
  75. package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
  76. package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
  77. package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
  78. package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
  79. package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
  80. package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
  81. package/docs/plans/0215-decompose-build-parent-context.md +0 -166
  82. package/docs/plans/0216-decompose-start-agent.md +0 -255
  83. package/docs/plans/0217-extract-overwrite-guard.md +0 -176
  84. package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
  85. package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
  86. package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
  87. package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
  88. package/docs/plans/0229-agent-born-complete.md +0 -564
  89. package/docs/plans/0230-extract-concurrency-queue.md +0 -265
  90. package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
  91. package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
  92. package/docs/plans/0237-remove-disallowed-tools.md +0 -180
  93. package/docs/plans/0238-remove-extensions-filtering.md +0 -191
  94. package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
  95. package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
  96. package/docs/plans/0256-extract-worktree-isolation.md +0 -256
  97. package/docs/plans/0257-extract-child-session-factory.md +0 -285
  98. package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
  99. package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
  100. package/docs/plans/0265-born-complete-subagent-session.md +0 -333
  101. package/docs/plans/0270-type-consumable-public-surface.md +0 -204
  102. package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
  103. package/docs/plans/0277-encapsulate-agent-session.md +0 -304
  104. package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
  105. package/docs/plans/0360-custom-agents-default-append.md +0 -132
  106. package/docs/plans/0373-extract-subagent-state.md +0 -250
  107. package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
  108. package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
  109. package/docs/plans/0376-extract-manager-observer.md +0 -232
  110. package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
  111. package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
  112. package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
  113. package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
  114. package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
  115. package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
  116. package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
  117. package/docs/plans/0412-unify-session-mock-builders.md +0 -146
  118. package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
  119. package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
  120. package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
  121. package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
  122. package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
  123. package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
  124. package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
  125. package/docs/plans/0427-reconsider-ui-direction.md +0 -212
  126. package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
  127. package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
  128. package/docs/plans/0443-consolidate-remaining-test-clone-families.md +0 -268
  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/plans/0470-refresh-readme-command-surface.md +0 -159
  137. package/docs/retro/0048-implement-subagents-api.md +0 -44
  138. package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
  139. package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
  140. package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
  141. package/docs/retro/0054-decompose-index-into-modules.md +0 -53
  142. package/docs/retro/0057-structured-debug-logging.md +0 -77
  143. package/docs/retro/0061-session-format-transcript.md +0 -41
  144. package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
  145. package/docs/retro/0069-create-subagent-runtime.md +0 -43
  146. package/docs/retro/0070-extract-event-handlers.md +0 -49
  147. package/docs/retro/0071-extract-session-config-assembler.md +0 -60
  148. package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
  149. package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
  150. package/docs/retro/0077-inject-project-agents-dir.md +0 -33
  151. package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
  152. package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
  153. package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
  154. package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
  155. package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
  156. package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
  157. package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
  158. package/docs/retro/0108-extract-agent-type-registry.md +0 -41
  159. package/docs/retro/0109-extract-settings-manager.md +0 -55
  160. package/docs/retro/0110-agent-activity-tracker.md +0 -44
  161. package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
  162. package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
  163. package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
  164. package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
  165. package/docs/retro/0115-decompose-agent-tool.md +0 -51
  166. package/docs/retro/0116-type-housekeeping.md +0 -42
  167. package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
  168. package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
  169. package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
  170. package/docs/retro/0132-inject-io-into-session-config.md +0 -33
  171. package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
  172. package/docs/retro/0134-reduce-as-any-casts.md +0 -56
  173. package/docs/retro/0135-extract-display-helpers.md +0 -38
  174. package/docs/retro/0136-decompose-agent-menu.md +0 -43
  175. package/docs/retro/0144-consolidate-observation-model.md +0 -39
  176. package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
  177. package/docs/retro/0146-narrow-ui-context.md +0 -70
  178. package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
  179. package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
  180. package/docs/retro/0152-add-prompt-snippet.md +0 -34
  181. package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
  182. package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
  183. package/docs/retro/0166-extract-parent-session-info.md +0 -66
  184. package/docs/retro/0167-narrow-runner-io.md +0 -63
  185. package/docs/retro/0168-extract-tool-filter-config.md +0 -76
  186. package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
  187. package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
  188. package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
  189. package/docs/retro/0172-extract-turn-formatting.md +0 -80
  190. package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
  191. package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
  192. package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
  193. package/docs/retro/0192-define-session-context-interface.md +0 -59
  194. package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
  195. package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
  196. package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
  197. package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
  198. package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
  199. package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
  200. package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
  201. package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
  202. package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
  203. package/docs/retro/0215-decompose-build-parent-context.md +0 -61
  204. package/docs/retro/0216-decompose-start-agent.md +0 -80
  205. package/docs/retro/0217-extract-overwrite-guard.md +0 -63
  206. package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
  207. package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
  208. package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
  209. package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
  210. package/docs/retro/0229-agent-born-complete.md +0 -89
  211. package/docs/retro/0230-extract-concurrency-queue.md +0 -38
  212. package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
  213. package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
  214. package/docs/retro/0237-remove-disallowed-tools.md +0 -78
  215. package/docs/retro/0238-remove-extensions-filtering.md +0 -72
  216. package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
  217. package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
  218. package/docs/retro/0256-extract-worktree-isolation.md +0 -89
  219. package/docs/retro/0257-extract-child-session-factory.md +0 -33
  220. package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
  221. package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
  222. package/docs/retro/0265-born-complete-subagent-session.md +0 -97
  223. package/docs/retro/0270-type-consumable-public-surface.md +0 -108
  224. package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
  225. package/docs/retro/0277-encapsulate-agent-session.md +0 -80
  226. package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
  227. package/docs/retro/0360-custom-agents-default-append.md +0 -81
  228. package/docs/retro/0373-extract-subagent-state.md +0 -94
  229. package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
  230. package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
  231. package/docs/retro/0376-extract-manager-observer.md +0 -81
  232. package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
  233. package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
  234. package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
  235. package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
  236. package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
  237. package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
  238. package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
  239. package/docs/retro/0412-unify-session-mock-builders.md +0 -80
  240. package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
  241. package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
  242. package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
  243. package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
  244. package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
  245. package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
  246. package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
  247. package/docs/retro/0427-reconsider-ui-direction.md +0 -102
  248. package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -97
  249. package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
  250. package/docs/retro/0443-consolidate-remaining-test-clone-families.md +0 -28
  251. package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
  252. package/docs/retro/0445-native-session-navigation.md +0 -122
  253. package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
  254. package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
  255. package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
  256. package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
  257. package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
  258. package/docs/retro/0470-refresh-readme-command-surface.md +0 -40
  259. package/src/observation/notification-state.ts +0 -27
  260. 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.