@gotgenes/pi-subagents 18.0.1 → 18.0.3

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