@gotgenes/pi-subagents 18.0.0 → 18.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +22 -31
  3. package/docs/architecture/architecture.md +157 -204
  4. package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
  5. package/package.json +5 -6
  6. package/src/lifecycle/subagent.ts +5 -9
  7. package/src/observation/notification.ts +23 -10
  8. package/src/observation/subagent-events-observer.ts +1 -3
  9. package/src/tools/get-result-report.ts +60 -0
  10. package/src/tools/get-result-tool.ts +25 -40
  11. package/src/types.ts +1 -1
  12. package/src/ui/session-navigator.ts +0 -2
  13. package/.prettierignore +0 -5
  14. package/AGENTS.md +0 -7
  15. package/docs/plans/0048-implement-subagents-api.md +0 -304
  16. package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
  17. package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
  18. package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
  19. package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
  20. package/docs/plans/0054-decompose-index-into-modules.md +0 -302
  21. package/docs/plans/0057-structured-debug-logging.md +0 -154
  22. package/docs/plans/0061-session-format-transcript.md +0 -284
  23. package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
  24. package/docs/plans/0069-create-subagent-runtime.md +0 -345
  25. package/docs/plans/0070-extract-event-handlers.md +0 -306
  26. package/docs/plans/0071-extract-session-config-assembler.md +0 -362
  27. package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
  28. package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
  29. package/docs/plans/0077-inject-project-agents-dir.md +0 -115
  30. package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
  31. package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
  32. package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
  33. package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
  34. package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
  35. package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
  36. package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
  37. package/docs/plans/0108-extract-agent-type-registry.md +0 -322
  38. package/docs/plans/0109-extract-settings-manager.md +0 -276
  39. package/docs/plans/0110-agent-activity-tracker.md +0 -297
  40. package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
  41. package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
  42. package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
  43. package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
  44. package/docs/plans/0115-decompose-agent-tool.md +0 -337
  45. package/docs/plans/0116-type-housekeeping.md +0 -351
  46. package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
  47. package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
  48. package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
  49. package/docs/plans/0132-inject-io-into-session-config.md +0 -219
  50. package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
  51. package/docs/plans/0134-reduce-as-any-casts.md +0 -366
  52. package/docs/plans/0135-extract-display-helpers.md +0 -182
  53. package/docs/plans/0136-decompose-agent-menu.md +0 -300
  54. package/docs/plans/0144-consolidate-observation-model.md +0 -263
  55. package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
  56. package/docs/plans/0146-narrow-ui-context.md +0 -319
  57. package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
  58. package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
  59. package/docs/plans/0152-add-prompt-snippet.md +0 -91
  60. package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
  61. package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
  62. package/docs/plans/0166-extract-parent-session-info.md +0 -231
  63. package/docs/plans/0167-narrow-runner-io.md +0 -150
  64. package/docs/plans/0168-extract-tool-filter-config.md +0 -173
  65. package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
  66. package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
  67. package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
  68. package/docs/plans/0172-extract-turn-formatting.md +0 -206
  69. package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
  70. package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
  71. package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
  72. package/docs/plans/0192-define-session-context-interface.md +0 -107
  73. package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
  74. package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
  75. package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
  76. package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
  77. package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
  78. package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
  79. package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
  80. package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
  81. package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
  82. package/docs/plans/0215-decompose-build-parent-context.md +0 -166
  83. package/docs/plans/0216-decompose-start-agent.md +0 -255
  84. package/docs/plans/0217-extract-overwrite-guard.md +0 -176
  85. package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
  86. package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
  87. package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
  88. package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
  89. package/docs/plans/0229-agent-born-complete.md +0 -564
  90. package/docs/plans/0230-extract-concurrency-queue.md +0 -265
  91. package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
  92. package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
  93. package/docs/plans/0237-remove-disallowed-tools.md +0 -180
  94. package/docs/plans/0238-remove-extensions-filtering.md +0 -191
  95. package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
  96. package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
  97. package/docs/plans/0256-extract-worktree-isolation.md +0 -256
  98. package/docs/plans/0257-extract-child-session-factory.md +0 -285
  99. package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
  100. package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
  101. package/docs/plans/0265-born-complete-subagent-session.md +0 -333
  102. package/docs/plans/0270-type-consumable-public-surface.md +0 -204
  103. package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
  104. package/docs/plans/0277-encapsulate-agent-session.md +0 -304
  105. package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
  106. package/docs/plans/0360-custom-agents-default-append.md +0 -132
  107. package/docs/plans/0373-extract-subagent-state.md +0 -250
  108. package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
  109. package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
  110. package/docs/plans/0376-extract-manager-observer.md +0 -232
  111. package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
  112. package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
  113. package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
  114. package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
  115. package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
  116. package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
  117. package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
  118. package/docs/plans/0412-unify-session-mock-builders.md +0 -146
  119. package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
  120. package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
  121. package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
  122. package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
  123. package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
  124. package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
  125. package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
  126. package/docs/plans/0427-reconsider-ui-direction.md +0 -212
  127. package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
  128. package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
  129. package/docs/plans/0444-shrink-widget-to-background-agents.md +0 -156
  130. package/docs/plans/0445-native-session-navigation.md +0 -365
  131. package/docs/plans/0446-spike-session-navigation-entry-criteria.md +0 -171
  132. package/docs/plans/0447-extract-subagents-settings-command.md +0 -220
  133. package/docs/plans/0448-block-disabled-agent-spawn.md +0 -207
  134. package/docs/plans/0462-navigation-renderer-tui-components.md +0 -338
  135. package/docs/plans/0463-file-snapshot-source-evicted-agents.md +0 -306
  136. package/docs/retro/0048-implement-subagents-api.md +0 -44
  137. package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
  138. package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
  139. package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
  140. package/docs/retro/0054-decompose-index-into-modules.md +0 -53
  141. package/docs/retro/0057-structured-debug-logging.md +0 -77
  142. package/docs/retro/0061-session-format-transcript.md +0 -41
  143. package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
  144. package/docs/retro/0069-create-subagent-runtime.md +0 -43
  145. package/docs/retro/0070-extract-event-handlers.md +0 -49
  146. package/docs/retro/0071-extract-session-config-assembler.md +0 -60
  147. package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
  148. package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
  149. package/docs/retro/0077-inject-project-agents-dir.md +0 -33
  150. package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
  151. package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
  152. package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
  153. package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
  154. package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
  155. package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
  156. package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
  157. package/docs/retro/0108-extract-agent-type-registry.md +0 -41
  158. package/docs/retro/0109-extract-settings-manager.md +0 -55
  159. package/docs/retro/0110-agent-activity-tracker.md +0 -44
  160. package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
  161. package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
  162. package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
  163. package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
  164. package/docs/retro/0115-decompose-agent-tool.md +0 -51
  165. package/docs/retro/0116-type-housekeeping.md +0 -42
  166. package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
  167. package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
  168. package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
  169. package/docs/retro/0132-inject-io-into-session-config.md +0 -33
  170. package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
  171. package/docs/retro/0134-reduce-as-any-casts.md +0 -56
  172. package/docs/retro/0135-extract-display-helpers.md +0 -38
  173. package/docs/retro/0136-decompose-agent-menu.md +0 -43
  174. package/docs/retro/0144-consolidate-observation-model.md +0 -39
  175. package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
  176. package/docs/retro/0146-narrow-ui-context.md +0 -70
  177. package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
  178. package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
  179. package/docs/retro/0152-add-prompt-snippet.md +0 -34
  180. package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
  181. package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
  182. package/docs/retro/0166-extract-parent-session-info.md +0 -66
  183. package/docs/retro/0167-narrow-runner-io.md +0 -63
  184. package/docs/retro/0168-extract-tool-filter-config.md +0 -76
  185. package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
  186. package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
  187. package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
  188. package/docs/retro/0172-extract-turn-formatting.md +0 -80
  189. package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
  190. package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
  191. package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
  192. package/docs/retro/0192-define-session-context-interface.md +0 -59
  193. package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
  194. package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
  195. package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
  196. package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
  197. package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
  198. package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
  199. package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
  200. package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
  201. package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
  202. package/docs/retro/0215-decompose-build-parent-context.md +0 -61
  203. package/docs/retro/0216-decompose-start-agent.md +0 -80
  204. package/docs/retro/0217-extract-overwrite-guard.md +0 -63
  205. package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
  206. package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
  207. package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
  208. package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
  209. package/docs/retro/0229-agent-born-complete.md +0 -89
  210. package/docs/retro/0230-extract-concurrency-queue.md +0 -38
  211. package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
  212. package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
  213. package/docs/retro/0237-remove-disallowed-tools.md +0 -78
  214. package/docs/retro/0238-remove-extensions-filtering.md +0 -72
  215. package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
  216. package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
  217. package/docs/retro/0256-extract-worktree-isolation.md +0 -89
  218. package/docs/retro/0257-extract-child-session-factory.md +0 -33
  219. package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
  220. package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
  221. package/docs/retro/0265-born-complete-subagent-session.md +0 -97
  222. package/docs/retro/0270-type-consumable-public-surface.md +0 -108
  223. package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
  224. package/docs/retro/0277-encapsulate-agent-session.md +0 -80
  225. package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
  226. package/docs/retro/0360-custom-agents-default-append.md +0 -81
  227. package/docs/retro/0373-extract-subagent-state.md +0 -94
  228. package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
  229. package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
  230. package/docs/retro/0376-extract-manager-observer.md +0 -81
  231. package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
  232. package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
  233. package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
  234. package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
  235. package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
  236. package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
  237. package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
  238. package/docs/retro/0412-unify-session-mock-builders.md +0 -80
  239. package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
  240. package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
  241. package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
  242. package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
  243. package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
  244. package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
  245. package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
  246. package/docs/retro/0427-reconsider-ui-direction.md +0 -102
  247. package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -45
  248. package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
  249. package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
  250. package/docs/retro/0445-native-session-navigation.md +0 -122
  251. package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
  252. package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
  253. package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
  254. package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
  255. package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
  256. package/src/observation/notification-state.ts +0 -27
  257. package/vitest.config.ts +0 -14
@@ -1,172 +0,0 @@
1
- ---
2
- issue: 218
3
- issue_title: "Push SDK boundary in settings.ts (Phase 13, Step 5)"
4
- ---
5
-
6
- # Push SDK boundary in settings.ts
7
-
8
- ## Problem Statement
9
-
10
- `settings.ts` imports `getAgentDir` from the Pi SDK (`@earendil-works/pi-coding-agent`) and calls it inside `globalPath()` at invocation time.
11
- This hides a platform dependency inside a module that is otherwise pure configuration logic — violating the project's SDK-boundary rule that pure helpers and domain modules should remain SDK-independent.
12
- The SDK call also forces tests to redirect the env var `PI_CODING_AGENT_DIR` to control `getAgentDir()` output, rather than passing the value directly.
13
-
14
- ## Goals
15
-
16
- - Remove the `getAgentDir` import from `settings.ts` (0 Pi SDK imports).
17
- - Inject `agentDir: string` into `SettingsManager` constructor deps.
18
- - Make `loadSettings` accept `agentDir` as an explicit parameter.
19
- - Eliminate `PI_CODING_AGENT_DIR` env var manipulation from all settings tests.
20
-
21
- ## Non-Goals
22
-
23
- - Removing `process.cwd()` defaults from `loadSettings`/`saveSettings` — that's a separate concern (Node.js API, not Pi SDK).
24
- - Pushing SDK boundaries in other files (`skill-loader.ts`, `custom-agents.ts`, `agent-runner.ts`) — tracked separately in the Phase 13 roadmap.
25
- - Changing the `saveSettings` signature — it only calls `projectPath(cwd)` and has no SDK dependency.
26
-
27
- ## Background
28
-
29
- `settings.ts` exports a `SettingsManager` class and two free functions (`loadSettings`, `saveSettings`).
30
- The only SDK import is `getAgentDir`, used in the private `globalPath()` helper to compute the global settings file path (`~/.pi/agent/subagents.json`).
31
-
32
- The `SettingsManager` constructor already accepts a deps bag `{ emit, cwd, onMaxConcurrentChanged? }`.
33
- Adding `agentDir` to this bag follows the established injection pattern.
34
-
35
- In `index.ts`, `getAgentDir` is already imported for several other call sites (agent runner IO, agent tool, `/agents` menu).
36
- Adding one more usage to the `SettingsManager` construction is zero new imports.
37
-
38
- ### Relevant AGENTS.md constraints
39
-
40
- - **Pi SDK boundaries:** Keep Pi SDK imports out of business-logic modules; accept the value as a parameter or callback.
41
- - **Code-design skill, DIP:** Default to dependency injection for non-trivial dependencies.
42
-
43
- ## Design Overview
44
-
45
- ### Change to `globalPath()`
46
-
47
- Currently:
48
-
49
- ```typescript
50
- function globalPath(): string {
51
- return join(getAgentDir(), "subagents.json");
52
- }
53
- ```
54
-
55
- After:
56
-
57
- ```typescript
58
- function globalPath(agentDir: string): string {
59
- return join(agentDir, "subagents.json");
60
- }
61
- ```
62
-
63
- ### Change to `loadSettings()`
64
-
65
- Currently:
66
-
67
- ```typescript
68
- export function loadSettings(cwd: string = process.cwd()): SubagentsSettings {
69
- return { ...readSettingsFile(globalPath()), ...readSettingsFile(projectPath(cwd)) };
70
- }
71
- ```
72
-
73
- After:
74
-
75
- ```typescript
76
- export function loadSettings(agentDir: string, cwd: string = process.cwd()): SubagentsSettings {
77
- return { ...readSettingsFile(globalPath(agentDir)), ...readSettingsFile(projectPath(cwd)) };
78
- }
79
- ```
80
-
81
- ### Change to `SettingsManager` constructor
82
-
83
- Add `agentDir: string` to the deps bag:
84
-
85
- ```typescript
86
- constructor(deps: { emit: SettingsEmit; cwd: string; agentDir: string; onMaxConcurrentChanged?: () => void }) {
87
- this.emit = deps.emit;
88
- this.cwd = deps.cwd;
89
- this.agentDir = deps.agentDir;
90
- this.onMaxConcurrentChanged = deps.onMaxConcurrentChanged;
91
- }
92
- ```
93
-
94
- `SettingsManager.load()` passes `this.agentDir` to `loadSettings`:
95
-
96
- ```typescript
97
- load(): SubagentsSettings {
98
- const settings = loadSettings(this.agentDir, this.cwd);
99
- // ... rest unchanged
100
- }
101
- ```
102
-
103
- ### Wiring in `index.ts`
104
-
105
- ```typescript
106
- const settings = new SettingsManager({
107
- emit: (event, payload) => pi.events.emit(event, payload),
108
- cwd: process.cwd(),
109
- agentDir: getAgentDir(),
110
- onMaxConcurrentChanged: () => manager.notifyConcurrencyChanged(),
111
- });
112
- ```
113
-
114
- ## Module-Level Changes
115
-
116
- ### `src/settings.ts`
117
-
118
- 1. Remove `import { getAgentDir } from "@earendil-works/pi-coding-agent"`.
119
- 2. Add `agentDir: string` field to the `SettingsManager` constructor deps interface.
120
- 3. Store `this.agentDir = deps.agentDir` as a private readonly field.
121
- 4. Change `globalPath()` signature to `globalPath(agentDir: string)`.
122
- 5. Change `loadSettings` signature to `loadSettings(agentDir: string, cwd?: string)`.
123
- 6. Update `SettingsManager.load()` to call `loadSettings(this.agentDir, this.cwd)`.
124
- 7. Update the header comment to reflect the new injection pattern.
125
-
126
- ### `src/index.ts`
127
-
128
- 1. Add `agentDir: getAgentDir()` to the `SettingsManager` constructor deps object.
129
-
130
- ### `test/settings.test.ts`
131
-
132
- 1. Remove all `PI_CODING_AGENT_DIR` env manipulation (`originalAgentDirEnv`, `beforeEach`/`afterEach` stubs).
133
- 2. Pass `globalDir` directly to `loadSettings(globalDir, projectDir)` in free-function tests.
134
- 3. Add `agentDir: globalDir` (or a dummy string for non-load tests) to all `new SettingsManager(...)` calls.
135
- 4. In `SettingsManager.load()` tests, pass `agentDir: globalDir` to the constructor.
136
- 5. In tests that don't exercise `load()`, use `agentDir: "/nonexistent"` or similar — the value is unused.
137
-
138
- ## Test Impact Analysis
139
-
140
- 1. **New capability:** Free-function tests (`loadSettings`, `saveSettings`) become pure — pass `globalDir` directly instead of manipulating `PI_CODING_AGENT_DIR`.
141
- This is simpler and more reliable.
142
- 2. **Redundant cleanup:** The `originalAgentDirEnv` save/restore pattern in `beforeEach`/`afterEach` can be removed from all `describe` blocks that use it.
143
- 3. **Existing tests stay:** All existing test scenarios remain valid; only their setup mechanics change.
144
-
145
- ## TDD Order
146
-
147
- 1. **Red → Green:** Change `loadSettings` signature to accept `agentDir` parameter; update `globalPath` to accept it.
148
- Update all free-function tests to pass `globalDir` directly instead of env var.
149
- Remove env-var manipulation from the `settings persistence` describe block.
150
- Commit: `feat: inject agentDir into loadSettings to remove SDK dependency`
151
-
152
- 2. **Red → Green:** Add `agentDir` to `SettingsManager` constructor deps; store as private field; thread into `load()`.
153
- Update all `new SettingsManager(...)` call sites in tests.
154
- Remove env-var manipulation from `SettingsManager` describe blocks.
155
- Remove `getAgentDir` import from `settings.ts`.
156
- Commit: `feat: inject agentDir into SettingsManager constructor`
157
-
158
- 3. **Green:** Wire `agentDir: getAgentDir()` into `SettingsManager` construction in `index.ts`.
159
- Run `pnpm run check` to confirm no type errors across the package.
160
- Commit: `feat: wire agentDir from SDK boundary in index.ts (#218)`
161
-
162
- ## Risks and Mitigations
163
-
164
- | Risk | Mitigation |
165
- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
166
- | Breaking the `loadSettings` export signature for hypothetical external callers | The function is only called from `SettingsManager.load()` and tests; no external consumers exist. |
167
- | Test count is high (~35 constructor sites) — mechanical updates could introduce typos | Steps 1 and 2 are focused; run `pnpm vitest run test/settings.test.ts` after each to confirm. |
168
- | Forgetting a test site that still manipulates `PI_CODING_AGENT_DIR` | Grep for `PI_CODING_AGENT_DIR` after step 2 to confirm zero remaining references in `test/settings.test.ts`. |
169
-
170
- ## Open Questions
171
-
172
- None — the issue's proposed change is unambiguous and follows the established injection pattern used in prior Phase 13 steps.
@@ -1,162 +0,0 @@
1
- ---
2
- issue: 219
3
- issue_title: "Reduce test duplication — top 3 clone families (Phase 13, Step 6)"
4
- ---
5
-
6
- # Reduce test duplication — top 3 clone families
7
-
8
- ## Problem statement
9
-
10
- After Phase 12, three test files carry the heaviest remaining clone families in pi-subagents:
11
-
12
- 1. `test/lifecycle/agent-manager.test.ts` (929 lines) — 16 clone groups, ~160 duplicated lines.
13
- Repeated inline runner stubs, worktree stubs, and manager-lifecycle boilerplate.
14
- 2. `test/conversation-viewer.test.ts` (307 lines) — 8 clone groups, ~91 duplicated lines.
15
- Near-identical `ConversationViewer` construction in every test, plus repeated width-loop assertion patterns.
16
- 3. `test/ui/agent-config-editor.test.ts` (471 lines) — 5 clone groups, ~42 duplicated lines.
17
- Repeated `makeEditor()` + `makeMenuUI()` + `fileOps.findAgentFile.mockReturnValue(...)` setup.
18
-
19
- Total target: reduce test duplication by ~200 lines (from ~1,046 combined test-setup lines to < 850).
20
-
21
- ## Goals
22
-
23
- - Extract shared setup and assertion helpers for the three target test files.
24
- - Reduce test duplication by ~200 lines without changing test semantics.
25
- - Follow the existing `test/helpers/` convention (factory + matching `.test.ts` file).
26
-
27
- ## Non-goals
28
-
29
- - No production code changes.
30
- - No new test coverage — this is purely a refactoring of existing test infrastructure.
31
- - Not consolidating clone families in other test files beyond the top 3.
32
- - Not changing any assertion logic or test structure beyond replacing inline stubs with factory calls.
33
-
34
- ## Background
35
-
36
- The project already has several shared test helpers in `test/helpers/`: `make-record.ts`, `mock-session.ts`, `ui-stubs.ts`, `runner-io.ts`, `stub-ctx.ts`, `make-deps.ts`.
37
- Each helper has a companion `.test.ts` file — this convention must be followed.
38
-
39
- Dependencies #214 (closure-to-class conversions) and #216 (startAgent decomposition) are both closed, so the production code these tests cover is stable.
40
-
41
- ## Design overview
42
-
43
- ### File 1: `agent-manager.test.ts` — extract to `test/helpers/manager-stubs.ts`
44
-
45
- Five clone families to extract:
46
-
47
- 1. **Never-resolving runner** — `{ run: vi.fn().mockImplementation(() => new Promise(() => {})), resume: vi.fn() }` appears 5 times.
48
- Extract as `createBlockingRunner(): AgentRunner`.
49
-
50
- 2. **Session-creating runner** — runner that calls `opts.onSessionCreated?.(session)` and resolves.
51
- Appears 5+ times with minor variations (some emit events through the session, some don't).
52
- Extract as `createSessionRunner(session?: MockSession): AgentRunner` that calls `onSessionCreated` and returns a standard result.
53
-
54
- 3. **Worktree stubs with path+branch** — `{ create: vi.fn().mockReturnValue({ path, branch }), cleanup: vi.fn(() => ({ hasChanges: false })), prune: vi.fn() }` appears 4 times identically, plus 1 variant with `create` returning `undefined`.
55
- Extract as `createMockWorktrees(overrides?)`.
56
-
57
- 4. **Standard run result shape** — `{ responseText: "done", session, aborted: false, steered: false }` is repeated in many runner factories.
58
- Extract as `createRunResult(overrides?)`.
59
-
60
- 5. **Gated runner** — uses `Promise.withResolvers` to control when the runner completes.
61
- Appears 2 times.
62
- Keep inline — too tightly coupled to individual test flow-control to generalize cleanly.
63
-
64
- Tests that construct custom runners with unique behavior (event-emitting runners in the `lifetimeUsage` and `compactionCount` tests) keep their inline stubs — those encode test-specific emission sequences that a shared factory would obscure.
65
-
66
- ### File 2: `conversation-viewer.test.ts` — inline factory + assertion helper
67
-
68
- Two clone families to extract:
69
-
70
- 1. **`ConversationViewer` construction** — 15 near-identical constructor calls with the same 8 fields.
71
- Extract as an inline `createTestViewer(overrides?)` factory at the top of the test file.
72
- The factory provides defaults for `tui`, `session`, `record`, `activity`, `theme`, `done`, `registry`, and `wrapText`, and accepts overrides including a convenience `width` and `messages` parameter.
73
-
74
- 2. **Width-loop assertion** — the `for (const w of widths) { create viewer; assertAllLinesFit(viewer.render(w), w) }` pattern repeats in 10 "render width safety" tests.
75
- Extract as an inline `assertRenderFitsWidths(messages, widths?, viewerOverrides?)` helper.
76
-
77
- These helpers stay inline (not in `test/helpers/`) because they depend on file-local helpers (`mockTui`, `mockSession`, `ansiTheme`) and are only used by this one test file.
78
-
79
- ### File 3: `agent-config-editor.test.ts` — inline setup helper
80
-
81
- One clone family to extract:
82
-
83
- 1. **Detail-test setup** — `makeEditor()` + `makeMenuUI([...])` + `fileOps.findAgentFile.mockReturnValue(...)` + optional `fileOps.read.mockReturnValue(...)` appears in ~18 tests.
84
- Extract as an inline `setupDetail(selectResults, options?)` factory that returns `{ fileOps, editor, ui }` with pre-configured mocks.
85
- Options: `filePath`, `fileContent`, `config` (merged into default via `createTestAgentConfig`).
86
-
87
- This stays inline because it's specific to the `showAgentDetail` test suite and depends on file-local `testRegistry` setup.
88
-
89
- ## Module-level changes
90
-
91
- ### New files
92
-
93
- | File | Purpose |
94
- | ------------------------------------ | --------------------------------------------------------------------------------------- |
95
- | `test/helpers/manager-stubs.ts` | `createBlockingRunner`, `createSessionRunner`, `createMockWorktrees`, `createRunResult` |
96
- | `test/helpers/manager-stubs.test.ts` | Smoke tests for the factories |
97
-
98
- ### Modified files
99
-
100
- | File | Change |
101
- | -------------------------------------- | --------------------------------------------------------------------------- |
102
- | `test/lifecycle/agent-manager.test.ts` | Replace inline runner/worktree stubs with `manager-stubs` factories |
103
- | `test/conversation-viewer.test.ts` | Add `createTestViewer` + `assertRenderFitsWidths` inline, migrate all tests |
104
- | `test/ui/agent-config-editor.test.ts` | Add `setupDetail` inline, migrate `showAgentDetail` tests |
105
-
106
- ### Unchanged files
107
-
108
- No production source files are modified.
109
- No other test files are modified.
110
-
111
- ## Test impact analysis
112
-
113
- 1. **New unit tests**: `manager-stubs.test.ts` adds smoke tests verifying factory return shapes (blocking runner never resolves, session runner calls `onSessionCreated`, worktree factory returns the expected interface, run result contains the correct fields).
114
- 2. **Simplified tests**: ~30 tests across the three files replace 3–6 lines of inline stub construction with 1-line factory calls.
115
- 3. **Unchanged tests**: All existing test assertions remain identical — only the setup code changes.
116
- Tests with custom runner behavior (event-emitting, gated, error-throwing) keep their inline stubs.
117
-
118
- ## TDD order
119
-
120
- 1. **Create `test/helpers/manager-stubs.ts` + `manager-stubs.test.ts`** Add `createBlockingRunner`, `createSessionRunner`, `createMockWorktrees`, `createRunResult`.
121
- Add smoke tests verifying each factory's return shape and basic behavior.
122
- Commit: `test: add manager-stubs helper factories (#219)`
123
-
124
- 2. **Migrate `agent-manager.test.ts` to use manager-stubs** Replace 5 inline never-resolving runners with `createBlockingRunner()`.
125
- Replace 4 identical worktree stubs with `createMockWorktrees()` / `createMockWorktrees({ create: ... })`.
126
- Replace inline session-creating runners with `createSessionRunner(session)` where the test only needs `onSessionCreated` wiring.
127
- Replace inline run-result objects with `createRunResult()` where the default shape suffices.
128
- Run `pnpm vitest run test/lifecycle/agent-manager.test.ts` to verify green.
129
- Commit: `test: migrate agent-manager tests to manager-stubs (#219)`
130
-
131
- 3. **Add inline factories to `conversation-viewer.test.ts` and migrate** Add `createTestViewer(overrides?)` inline factory with defaults for all 8 constructor fields.
132
- Add `assertRenderFitsWidths(messages, widths?, overrides?)` inline helper.
133
- Migrate all 10 "render width safety" tests to use `assertRenderFitsWidths`.
134
- Migrate all 5 "safety net" tests to use `createTestViewer`.
135
- Run `pnpm vitest run test/conversation-viewer.test.ts` to verify green.
136
- Commit: `test: reduce conversation-viewer test duplication (#219)`
137
-
138
- 4. **Add inline `setupDetail` to `agent-config-editor.test.ts` and migrate** Add `setupDetail(selectResults, options?)` returning `{ fileOps, editor, ui }`.
139
- Migrate `showAgentDetail` tests to use `setupDetail`.
140
- Run `pnpm vitest run test/ui/agent-config-editor.test.ts` to verify green.
141
- Commit: `test: reduce agent-config-editor test duplication (#219)`
142
-
143
- 5. **Final verification** Run `pnpm vitest run` (full suite) to confirm no regressions.
144
- Run `pnpm run check` to confirm no type errors.
145
- Commit is not needed — this is a verification-only step.
146
-
147
- ## Risks and mitigations
148
-
149
- 1. **Factory defaults diverge from test intent** — If a shared factory's defaults don't match what an individual test expects, assertions silently pass or fail for the wrong reason.
150
- Mitigation: diff all inline stubs against the proposed factory defaults before writing the factory.
151
- Keep tests with unique mock behavior inline rather than force-fitting them into a factory.
152
-
153
- 2. **Over-abstraction obscures test intent** — Extracting too many details into helpers makes tests harder to read.
154
- Mitigation: only extract truly duplicated boilerplate (stub construction); keep test-specific setup and assertions inline.
155
- The gated runner pattern stays inline for this reason.
156
-
157
- 3. **Intermediate broken state** — Partially migrated test files may have import conflicts.
158
- Mitigation: each TDD step fully migrates one file before committing.
159
-
160
- ## Open questions
161
-
162
- None — the issue scope is well-defined and the dependencies are resolved.
@@ -1,322 +0,0 @@
1
- ---
2
- issue: 227
3
- issue_title: "Evolve AgentRecord into Agent with behavior (Phase 15, Step 1)"
4
- ---
5
-
6
- # Evolve AgentRecord into Agent with behavior
7
-
8
- ## Problem Statement
9
-
10
- `AgentRecord` is an anemic domain model — it holds identity, status transitions, and stats but no behavior.
11
- `AgentManager` reaches into records 37 times, performing work that belongs on the agent:
12
-
13
- - **abort**: `AgentManager.abort()` checks `record.status`, calls `record.abortController?.abort()`, calls `record.markStopped()` — this is the agent aborting itself, but the logic lives on the manager.
14
- - **pending steers**: per-agent steer buffers live in a manager-level `Map<string, string[]>`, not on the agent.
15
- - **steer flushing**: `flushPendingSteers(id, session)` iterates the manager map — should be `agent.flushPendingSteers(session)`.
16
- - **worktree setup**: `setupWorktree()` creates a worktree and attaches it to the record — the agent should set up its own worktree.
17
-
18
- ## Goals
19
-
20
- - Move per-agent behavior (`abort`, `queueSteer`/`flushPendingSteers`, `setupWorktree`) from `AgentManager` to the agent.
21
- - `AgentManager` delegates to agents via Tell-Don't-Ask instead of reaching into records.
22
- - Rename `AgentRecord` → `Agent`, `AgentRecordStatus` → `AgentStatus`, `AgentRecordInit` → `AgentInit` across the codebase.
23
- - All changes are internal — the public `SubagentsService` API (`service.ts`) is unaffected.
24
-
25
- ## Non-Goals
26
-
27
- - **`RunHandle` ownership** — moves to `Agent` in #228, not here.
28
- - **Async `startAgent`** — deferred to #228.
29
- - **`onSessionCreated` observer** — deferred to #229.
30
- - **`ConcurrencyQueue` extraction** — deferred to #230.
31
- Queue removal logic stays on `AgentManager.abort()` until then.
32
- - **Relay deps** — deferred to #231.
33
- - **Resume unification** — deferred to #232.
34
-
35
- ## Background
36
-
37
- ### Relevant modules
38
-
39
- | Module | Responsibility | Relationship to this change |
40
- | ------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------------------------------------------- |
41
- | `src/lifecycle/agent-record.ts` (201 LOC) | Status state machine, stats accumulation | Gains behavior methods, renames to `agent.ts` |
42
- | `src/lifecycle/agent-manager.ts` (541 LOC) | Agent collection, spawn, abort, queue, steer buffering | Loses private methods, delegates to agent |
43
- | `src/lifecycle/worktree.ts` | `WorktreeManager` interface and git worktree operations | Agent calls `worktrees.create()` directly |
44
- | `src/lifecycle/worktree-state.ts` | Per-agent worktree lifecycle state | Already attached to agent — `setupWorktree` formalizes this |
45
- | `src/tools/steer-tool.ts` | LLM-facing steer tool | Calls `record.queueSteer()` directly instead of `manager.queueSteer()` |
46
- | `src/service/service-adapter.ts` | Cross-extension API adapter | Calls `record.queueSteer()` directly; `queueSteer` removed from `AgentManagerLike` |
47
- | `src/observation/record-observer.ts` | Session event → agent stats accumulation | Import rename only |
48
- | `src/types.ts` | Internal re-exports | Re-export updates |
49
- | `test/helpers/make-record.ts` | Shared test factory | Renames to `make-agent.ts`, factory → `createTestAgent()` |
50
-
51
- ### Constraints
52
-
53
- - The public export from `package.json` is `"./src/service.ts"` only — `AgentRecord` is internal, so the rename is not breaking for consumers.
54
- - `WorktreeManager` is injected via the manager's constructor — `Agent.setupWorktree()` receives it as a parameter (no new constructor dependency).
55
- - Queue removal in `abort()` stays on `AgentManager` because the queue is manager-owned until #230 extracts `ConcurrencyQueue`.
56
-
57
- ## Design Overview
58
-
59
- ### New methods on Agent
60
-
61
- ```typescript
62
- class Agent {
63
- // Existing: markRunning, markCompleted, markAborted, markSteered, markError, markStopped,
64
- // incrementToolUses, addUsage, incrementCompactions, resetForResume
65
-
66
- // --- New behavior ---
67
-
68
- /** Buffer a steer message for delivery once the session is ready. */
69
- queueSteer(message: string): void;
70
-
71
- /** Flush buffered steers to the session and clear the buffer. */
72
- flushPendingSteers(session: AgentSession): void;
73
-
74
- /** Abort a running agent: fire AbortController, transition to stopped. */
75
- abort(): boolean;
76
-
77
- /** Create a worktree for isolated execution. Throws if impossible. */
78
- setupWorktree(worktrees: WorktreeManager, isolation: IsolationMode | undefined): string | undefined;
79
- }
80
- ```
81
-
82
- ### Steer buffering moves to agent
83
-
84
- Before: `AgentManager` owns `pendingSteers: Map<string, string[]>` and exposes `queueSteer(id, msg)`.
85
- After: each `Agent` owns `private pendingSteers: string[] = []`.
86
- Callers that already hold a record reference (steer tool, service adapter) call `agent.queueSteer(msg)` directly — the manager's `queueSteer` method and the `pendingSteers` map are removed.
87
-
88
- Consumer call-site (steer tool):
89
-
90
- ```typescript
91
- // Before:
92
- this.manager.queueSteer(record.id, params.message);
93
- // After:
94
- record.queueSteer(params.message);
95
- ```
96
-
97
- ### Abort moves to agent
98
-
99
- `Agent.abort()` encapsulates the running-check + controller.abort + markStopped sequence:
100
-
101
- ```typescript
102
- abort(): boolean {
103
- if (this._status !== "running") return false;
104
- this.abortController?.abort();
105
- this.markStopped();
106
- return true;
107
- }
108
- ```
109
-
110
- `AgentManager.abort(id)` retains queue-removal logic (queue is manager-owned until #230) and delegates the running case to `agent.abort()`.
111
- `AgentManager.abortAll()` calls `agent.abort()` for running agents.
112
-
113
- ### Worktree setup moves to agent
114
-
115
- `Agent.setupWorktree(worktrees, isolation)` replaces `AgentManager.setupWorktree(id, record, isolation)`.
116
- The agent creates the worktree, sets `this.worktreeState`, and returns the worktree path.
117
- The error message for impossible worktree creation stays identical.
118
-
119
- ### Rename strategy
120
-
121
- The rename (`AgentRecord` → `Agent`) is the final step — a purely mechanical search-and-replace with no behavior change.
122
- This keeps behavior-adding commits small and reviewable, then consolidates the rename noise into one commit.
123
-
124
- Files affected by the rename:
125
-
126
- | Layer | Files |
127
- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
128
- | Source (lifecycle) | `agent-record.ts` → `agent.ts`, `agent-manager.ts`, `execution-state.ts` |
129
- | Source (observation) | `record-observer.ts`, `notification.ts` |
130
- | Source (tools) | `agent-tool.ts`, `steer-tool.ts`, `get-result-tool.ts`, `background-spawner.ts`, `foreground-runner.ts` |
131
- | Source (UI) | `agent-menu.ts`, `agent-creation-wizard.ts`, `conversation-viewer.ts` |
132
- | Source (service) | `service-adapter.ts` |
133
- | Source (types) | `types.ts` |
134
- | Tests | `agent-record.test.ts` → `agent.test.ts`, `agent-manager.test.ts`, `record-observer.test.ts`, `steer-tool.test.ts`, `get-result-tool.test.ts`, `service-adapter.test.ts` |
135
- | Test helpers | `make-record.ts` → `make-agent.ts` |
136
-
137
- ## Module-Level Changes
138
-
139
- ### `src/lifecycle/agent-record.ts` → `src/lifecycle/agent.ts`
140
-
141
- 1. Add `private pendingSteers: string[] = []` field.
142
- 2. Add `queueSteer(message: string): void` — pushes to `pendingSteers`.
143
- 3. Add `flushPendingSteers(session: AgentSession): void` — iterates buffer, calls `session.steer()`, clears array.
144
- 4. Add `abort(): boolean` — if running, fires controller and marks stopped.
145
- 5. Add `setupWorktree(worktrees: WorktreeManager, isolation: IsolationMode | undefined): string | undefined` — creates worktree, sets `worktreeState`, returns path.
146
- 6. Add import for `WorktreeState`, `WorktreeManager`, `IsolationMode`.
147
- 7. Rename class `AgentRecord` → `Agent`, type `AgentRecordStatus` → `AgentStatus`, interface `AgentRecordInit` → `AgentInit`.
148
-
149
- ### `src/lifecycle/agent-manager.ts`
150
-
151
- 1. Remove `private pendingSteers = new Map<string, string[]>()`.
152
- 2. Remove `queueSteer(id, message)` public method.
153
- 3. Remove `private flushPendingSteers(id, session)` method.
154
- 4. In `startAgent`'s `onSessionCreated` callback: replace `this.flushPendingSteers(id, session)` with `record.flushPendingSteers(session)`.
155
- 5. Remove `private setupWorktree(id, record, isolation)` method.
156
- 6. In `startAgent`: replace `this.setupWorktree(id, record, options.isolation)` with `record.setupWorktree(this.worktrees, options.isolation)`.
157
- 7. Simplify `abort(id)`: delegate running case to `record.abort()`.
158
- 8. Simplify `abortAll()`: call `record.abort()` for running agents.
159
- 9. In `removeRecord`: remove `this.pendingSteers.delete(id)`.
160
- 10. Update imports: `AgentRecord` → `Agent`, `AgentRecordInit` → `AgentInit` (if used).
161
-
162
- ### `src/tools/steer-tool.ts`
163
-
164
- 1. Remove `queueSteer` from `SteerToolManager` interface.
165
- 2. Replace `this.manager.queueSteer(record.id, params.message)` with `record.queueSteer(params.message)`.
166
- 3. Update import: `AgentRecord` → `Agent`.
167
-
168
- ### `src/service/service-adapter.ts`
169
-
170
- 1. Remove `queueSteer` from `AgentManagerLike` interface.
171
- 2. In `steer()`: replace `this.manager.queueSteer(id, message)` with `record.queueSteer(message)` and return `true`.
172
- 3. Update import: `AgentRecord` → `Agent`.
173
-
174
- ### `src/types.ts`
175
-
176
- 1. Update re-export: `AgentRecord` → `Agent`, source path `#src/lifecycle/agent-record` → `#src/lifecycle/agent`.
177
-
178
- ### `src/observation/record-observer.ts`
179
-
180
- 1. Update import and parameter types: `AgentRecord` → `Agent`.
181
-
182
- ### `src/observation/notification.ts`
183
-
184
- 1. Update import and parameter types: `AgentRecord` → `Agent`.
185
-
186
- ### `src/tools/*.ts` (agent-tool, get-result-tool, background-spawner, foreground-runner)
187
-
188
- 1. Update imports and type annotations: `AgentRecord` → `Agent`.
189
-
190
- ### `src/ui/*.ts` (agent-menu, agent-creation-wizard, conversation-viewer)
191
-
192
- 1. Update imports and type annotations: `AgentRecord` → `Agent`.
193
-
194
- ### `test/helpers/make-record.ts` → `test/helpers/make-agent.ts`
195
-
196
- 1. Rename file.
197
- 2. Update imports: `AgentRecord` → `Agent`, `AgentRecordInit` → `AgentInit`.
198
- 3. Rename factory: `createTestRecord` → `createTestAgent`.
199
- 4. Update return type annotation.
200
-
201
- ### `test/lifecycle/agent-record.test.ts` → `test/lifecycle/agent.test.ts`
202
-
203
- 1. Rename file.
204
- 2. Update import: `AgentRecord` → `Agent`.
205
- 3. Update all `describe` block names and `new AgentRecord(...)` calls.
206
- 4. Add new test blocks for `queueSteer`, `flushPendingSteers`, `abort`, `setupWorktree`.
207
-
208
- ### `test/lifecycle/agent-manager.test.ts`
209
-
210
- 1. Remove tests for `AgentManager.queueSteer` (behavior moved to agent).
211
- 2. Update `abort()` tests to verify delegation.
212
- 3. Update imports if `AgentRecord` type is referenced.
213
-
214
- ### `test/tools/steer-tool.test.ts`
215
-
216
- 1. Remove `queueSteer` from mock manager.
217
- 2. Update "session not ready" test to verify `record.queueSteer()` is called.
218
-
219
- ### `test/service/service-adapter.test.ts`
220
-
221
- 1. Remove `queueSteer` from mock managers.
222
- 2. Update steer tests to verify `record.queueSteer()`.
223
-
224
- ### `packages/pi-subagents/docs/architecture/architecture.md`
225
-
226
- 1. Update file listing: `agent-record.ts` → `agent.ts`.
227
- 2. Update `AgentRecordInit` reference in interface width table.
228
-
229
- ## Test Impact Analysis
230
-
231
- ### New unit tests enabled by the extraction
232
-
233
- 1. **`Agent.queueSteer()` / `Agent.flushPendingSteers()`** — isolated tests for steer buffering without needing a full `AgentManager` setup.
234
- Previously the steer buffering was only testable via `AgentManager` integration tests.
235
- 2. **`Agent.abort()`** — isolated tests for the abort state machine (running → stopped, not-running → no-op) without needing manager scaffolding.
236
- 3. **`Agent.setupWorktree()`** — isolated tests for worktree creation and error handling with a mock `WorktreeManager`, without full spawn infrastructure.
237
-
238
- ### Existing tests that become redundant
239
-
240
- 1. `AgentManager — queueSteer` tests — the behavior is now tested directly on `Agent`.
241
- The manager no longer has a `queueSteer` method.
242
- 2. Parts of `AgentManager — abort` tests that verify controller.abort + markStopped — these are now `Agent.abort()` tests.
243
- The manager abort tests should focus on queue-removal logic and delegation.
244
-
245
- ### Existing tests that must stay
246
-
247
- 1. `AgentManager — abort` tests for the "queued" case (queue removal is still manager-owned).
248
- 2. `AgentManager — abortAll` tests (orchestrates both queue clearing and agent abort).
249
- 3. All `AgentManager — spawn/spawnAndWait` tests — the spawn flow still lives on the manager.
250
- 4. `steer-tool` and `service-adapter` tests for the steer path — updated to verify the new call pattern.
251
-
252
- ## TDD Order
253
-
254
- 1. **Red/Green: add `queueSteer()` and `flushPendingSteers()` to `AgentRecord`**
255
- - Add tests in `agent-record.test.ts` for buffering and flushing steers.
256
- - Implement the methods on `AgentRecord`.
257
- - Commit: `feat(pi-subagents): add steer buffering to AgentRecord`
258
-
259
- 2. **Refactor: delegate steer buffering from manager to agent**
260
- - Remove `pendingSteers` map, `queueSteer()`, `flushPendingSteers()` from `AgentManager`.
261
- - In `startAgent`'s `onSessionCreated`: call `record.flushPendingSteers(session)`.
262
- - In `removeRecord`: remove `pendingSteers.delete(id)`.
263
- - Update `steer-tool.ts`: remove `queueSteer` from `SteerToolManager`, call `record.queueSteer()`.
264
- - Update `service-adapter.ts`: remove `queueSteer` from `AgentManagerLike`, call `record.queueSteer()`.
265
- - Remove `AgentManager — queueSteer` tests; update steer-tool and service-adapter tests.
266
- - Run `pnpm run check` to verify no type errors.
267
- - Commit: `refactor(pi-subagents): delegate steer buffering from manager to agent`
268
-
269
- 3. **Red/Green: add `abort()` to `AgentRecord`**
270
- - Add tests in `agent-record.test.ts`: running → aborts and returns true; non-running → returns false; no controller → still marks stopped.
271
- - Implement the method.
272
- - Commit: `feat(pi-subagents): add abort() to AgentRecord`
273
-
274
- 4. **Refactor: delegate abort from manager to agent**
275
- - Simplify `AgentManager.abort()`: queued case stays, running case delegates to `record.abort()`.
276
- - Simplify `AgentManager.abortAll()`: call `record.abort()` for running agents.
277
- - Update manager abort tests to focus on queue removal and delegation.
278
- - Commit: `refactor(pi-subagents): delegate abort from manager to agent`
279
-
280
- 5. **Red/Green: add `setupWorktree()` to `AgentRecord`**
281
- - Add tests in `agent-record.test.ts`: non-worktree returns undefined; worktree created → sets `worktreeState` and returns path; creation fails → throws.
282
- - Implement the method (import `WorktreeState`, `WorktreeManager`, `IsolationMode`).
283
- - Commit: `feat(pi-subagents): add setupWorktree() to AgentRecord`
284
-
285
- 6. **Refactor: delegate worktree setup from manager to agent**
286
- - Remove `private setupWorktree()` from `AgentManager`.
287
- - In `startAgent`: replace `this.setupWorktree(id, record, options.isolation)` with `record.setupWorktree(this.worktrees, options.isolation)`.
288
- - Update any tests that verify worktree setup delegation.
289
- - Commit: `refactor(pi-subagents): delegate worktree setup from manager to agent`
290
-
291
- 7. **Rename `AgentRecord` → `Agent` across codebase**
292
- - Rename `src/lifecycle/agent-record.ts` → `src/lifecycle/agent.ts`.
293
- - Rename class `AgentRecord` → `Agent`, type `AgentRecordStatus` → `AgentStatus`, interface `AgentRecordInit` → `AgentInit`.
294
- - Update all source imports and type references (~20 source files).
295
- - Rename `test/lifecycle/agent-record.test.ts` → `test/lifecycle/agent.test.ts`.
296
- - Rename `test/helpers/make-record.ts` → `test/helpers/make-agent.ts`, factory `createTestRecord` → `createTestAgent`.
297
- - Update all test imports and references (~10 test files).
298
- - Rename `subscribeRecordObserver` → `subscribeAgentObserver` and `RecordObserverOptions` → `AgentObserverOptions` in `record-observer.ts`.
299
- - Run `pnpm run check` and full test suite.
300
- - Commit: `refactor(pi-subagents): rename AgentRecord to Agent`
301
-
302
- 8. **Update architecture docs**
303
- - Update `docs/architecture/architecture.md` file listing: `agent-record.ts` → `agent.ts`.
304
- - Update `AgentRecordInit` → `AgentInit` in the interface width table.
305
- - Update the Phase 15 Step 1 entry to reflect completion.
306
- - Commit: `docs(pi-subagents): update architecture for Agent rename`
307
-
308
- ## Risks and Mitigations
309
-
310
- 1. **Large rename diff in step 7** — The rename touches ~30 files.
311
- Mitigated by making it a purely mechanical change (no behavior change) in a dedicated commit, so reviewers can verify it's a clean rename.
312
- 2. **Queue-removal leaks into agent** — `Agent.abort()` must NOT remove from the manager's queue (that's #230's concern).
313
- Mitigated by scoping `Agent.abort()` to only handle the running case; `AgentManager.abort()` retains queue removal.
314
- 3. **Interface changes cascade** — Removing `queueSteer` from `SteerToolManager` and `AgentManagerLike` requires updating test mocks.
315
- Mitigated by handling interface changes and test updates in the same step (step 2).
316
- 4. **Test factory rename ripple** — `createTestRecord` → `createTestAgent` touches many test files.
317
- Mitigated by including this in the rename step (step 7), which is already a mechanical change.
318
-
319
- ## Open Questions
320
-
321
- None — the issue's proposed change is unambiguous and scoped.
322
- `RunHandle` ownership and other Phase 15 steps are explicitly deferred to their own issues.