@gotgenes/pi-subagents 18.0.1 → 18.0.2

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