@gotgenes/pi-subagents 18.0.1 → 18.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/docs/architecture/architecture.md +165 -203
  3. package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
  4. package/package.json +6 -7
  5. package/src/config/default-agents.ts +3 -0
  6. package/src/lifecycle/subagent.ts +25 -14
  7. package/src/observation/notification.ts +23 -10
  8. package/src/observation/subagent-events-observer.ts +1 -3
  9. package/src/runtime.ts +2 -1
  10. package/src/service/service-adapter.ts +20 -17
  11. package/src/session/model-resolver.ts +31 -30
  12. package/src/tools/agent-tool.ts +17 -13
  13. package/src/tools/get-result-report.ts +60 -0
  14. package/src/tools/get-result-tool.ts +25 -40
  15. package/src/tools/helpers.ts +21 -5
  16. package/src/tools/spawn-config.ts +5 -5
  17. package/src/tools/steer-tool.ts +37 -27
  18. package/src/types.ts +4 -1
  19. package/src/ui/session-navigator.ts +0 -2
  20. package/.prettierignore +0 -5
  21. package/AGENTS.md +0 -7
  22. package/docs/plans/0048-implement-subagents-api.md +0 -304
  23. package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
  24. package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
  25. package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
  26. package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
  27. package/docs/plans/0054-decompose-index-into-modules.md +0 -302
  28. package/docs/plans/0057-structured-debug-logging.md +0 -154
  29. package/docs/plans/0061-session-format-transcript.md +0 -284
  30. package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
  31. package/docs/plans/0069-create-subagent-runtime.md +0 -345
  32. package/docs/plans/0070-extract-event-handlers.md +0 -306
  33. package/docs/plans/0071-extract-session-config-assembler.md +0 -362
  34. package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
  35. package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
  36. package/docs/plans/0077-inject-project-agents-dir.md +0 -115
  37. package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
  38. package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
  39. package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
  40. package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
  41. package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
  42. package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
  43. package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
  44. package/docs/plans/0108-extract-agent-type-registry.md +0 -322
  45. package/docs/plans/0109-extract-settings-manager.md +0 -276
  46. package/docs/plans/0110-agent-activity-tracker.md +0 -297
  47. package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
  48. package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
  49. package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
  50. package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
  51. package/docs/plans/0115-decompose-agent-tool.md +0 -337
  52. package/docs/plans/0116-type-housekeeping.md +0 -351
  53. package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
  54. package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
  55. package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
  56. package/docs/plans/0132-inject-io-into-session-config.md +0 -219
  57. package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
  58. package/docs/plans/0134-reduce-as-any-casts.md +0 -366
  59. package/docs/plans/0135-extract-display-helpers.md +0 -182
  60. package/docs/plans/0136-decompose-agent-menu.md +0 -300
  61. package/docs/plans/0144-consolidate-observation-model.md +0 -263
  62. package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
  63. package/docs/plans/0146-narrow-ui-context.md +0 -319
  64. package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
  65. package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
  66. package/docs/plans/0152-add-prompt-snippet.md +0 -91
  67. package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
  68. package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
  69. package/docs/plans/0166-extract-parent-session-info.md +0 -231
  70. package/docs/plans/0167-narrow-runner-io.md +0 -150
  71. package/docs/plans/0168-extract-tool-filter-config.md +0 -173
  72. package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
  73. package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
  74. package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
  75. package/docs/plans/0172-extract-turn-formatting.md +0 -206
  76. package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
  77. package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
  78. package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
  79. package/docs/plans/0192-define-session-context-interface.md +0 -107
  80. package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
  81. package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
  82. package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
  83. package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
  84. package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
  85. package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
  86. package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
  87. package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
  88. package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
  89. package/docs/plans/0215-decompose-build-parent-context.md +0 -166
  90. package/docs/plans/0216-decompose-start-agent.md +0 -255
  91. package/docs/plans/0217-extract-overwrite-guard.md +0 -176
  92. package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
  93. package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
  94. package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
  95. package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
  96. package/docs/plans/0229-agent-born-complete.md +0 -564
  97. package/docs/plans/0230-extract-concurrency-queue.md +0 -265
  98. package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
  99. package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
  100. package/docs/plans/0237-remove-disallowed-tools.md +0 -180
  101. package/docs/plans/0238-remove-extensions-filtering.md +0 -191
  102. package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
  103. package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
  104. package/docs/plans/0256-extract-worktree-isolation.md +0 -256
  105. package/docs/plans/0257-extract-child-session-factory.md +0 -285
  106. package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
  107. package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
  108. package/docs/plans/0265-born-complete-subagent-session.md +0 -333
  109. package/docs/plans/0270-type-consumable-public-surface.md +0 -204
  110. package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
  111. package/docs/plans/0277-encapsulate-agent-session.md +0 -304
  112. package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
  113. package/docs/plans/0360-custom-agents-default-append.md +0 -132
  114. package/docs/plans/0373-extract-subagent-state.md +0 -250
  115. package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
  116. package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
  117. package/docs/plans/0376-extract-manager-observer.md +0 -232
  118. package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
  119. package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
  120. package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
  121. package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
  122. package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
  123. package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
  124. package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
  125. package/docs/plans/0412-unify-session-mock-builders.md +0 -146
  126. package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
  127. package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
  128. package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
  129. package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
  130. package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
  131. package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
  132. package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
  133. package/docs/plans/0427-reconsider-ui-direction.md +0 -212
  134. package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
  135. package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
  136. package/docs/plans/0443-consolidate-remaining-test-clone-families.md +0 -268
  137. package/docs/plans/0444-shrink-widget-to-background-agents.md +0 -156
  138. package/docs/plans/0445-native-session-navigation.md +0 -365
  139. package/docs/plans/0446-spike-session-navigation-entry-criteria.md +0 -171
  140. package/docs/plans/0447-extract-subagents-settings-command.md +0 -220
  141. package/docs/plans/0448-block-disabled-agent-spawn.md +0 -207
  142. package/docs/plans/0462-navigation-renderer-tui-components.md +0 -338
  143. package/docs/plans/0463-file-snapshot-source-evicted-agents.md +0 -306
  144. package/docs/plans/0470-refresh-readme-command-surface.md +0 -159
  145. package/docs/retro/0048-implement-subagents-api.md +0 -44
  146. package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
  147. package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
  148. package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
  149. package/docs/retro/0054-decompose-index-into-modules.md +0 -53
  150. package/docs/retro/0057-structured-debug-logging.md +0 -77
  151. package/docs/retro/0061-session-format-transcript.md +0 -41
  152. package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
  153. package/docs/retro/0069-create-subagent-runtime.md +0 -43
  154. package/docs/retro/0070-extract-event-handlers.md +0 -49
  155. package/docs/retro/0071-extract-session-config-assembler.md +0 -60
  156. package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
  157. package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
  158. package/docs/retro/0077-inject-project-agents-dir.md +0 -33
  159. package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
  160. package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
  161. package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
  162. package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
  163. package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
  164. package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
  165. package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
  166. package/docs/retro/0108-extract-agent-type-registry.md +0 -41
  167. package/docs/retro/0109-extract-settings-manager.md +0 -55
  168. package/docs/retro/0110-agent-activity-tracker.md +0 -44
  169. package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
  170. package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
  171. package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
  172. package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
  173. package/docs/retro/0115-decompose-agent-tool.md +0 -51
  174. package/docs/retro/0116-type-housekeeping.md +0 -42
  175. package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
  176. package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
  177. package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
  178. package/docs/retro/0132-inject-io-into-session-config.md +0 -33
  179. package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
  180. package/docs/retro/0134-reduce-as-any-casts.md +0 -56
  181. package/docs/retro/0135-extract-display-helpers.md +0 -38
  182. package/docs/retro/0136-decompose-agent-menu.md +0 -43
  183. package/docs/retro/0144-consolidate-observation-model.md +0 -39
  184. package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
  185. package/docs/retro/0146-narrow-ui-context.md +0 -70
  186. package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
  187. package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
  188. package/docs/retro/0152-add-prompt-snippet.md +0 -34
  189. package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
  190. package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
  191. package/docs/retro/0166-extract-parent-session-info.md +0 -66
  192. package/docs/retro/0167-narrow-runner-io.md +0 -63
  193. package/docs/retro/0168-extract-tool-filter-config.md +0 -76
  194. package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
  195. package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
  196. package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
  197. package/docs/retro/0172-extract-turn-formatting.md +0 -80
  198. package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
  199. package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
  200. package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
  201. package/docs/retro/0192-define-session-context-interface.md +0 -59
  202. package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
  203. package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
  204. package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
  205. package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
  206. package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
  207. package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
  208. package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
  209. package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
  210. package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
  211. package/docs/retro/0215-decompose-build-parent-context.md +0 -61
  212. package/docs/retro/0216-decompose-start-agent.md +0 -80
  213. package/docs/retro/0217-extract-overwrite-guard.md +0 -63
  214. package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
  215. package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
  216. package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
  217. package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
  218. package/docs/retro/0229-agent-born-complete.md +0 -89
  219. package/docs/retro/0230-extract-concurrency-queue.md +0 -38
  220. package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
  221. package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
  222. package/docs/retro/0237-remove-disallowed-tools.md +0 -78
  223. package/docs/retro/0238-remove-extensions-filtering.md +0 -72
  224. package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
  225. package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
  226. package/docs/retro/0256-extract-worktree-isolation.md +0 -89
  227. package/docs/retro/0257-extract-child-session-factory.md +0 -33
  228. package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
  229. package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
  230. package/docs/retro/0265-born-complete-subagent-session.md +0 -97
  231. package/docs/retro/0270-type-consumable-public-surface.md +0 -108
  232. package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
  233. package/docs/retro/0277-encapsulate-agent-session.md +0 -80
  234. package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
  235. package/docs/retro/0360-custom-agents-default-append.md +0 -81
  236. package/docs/retro/0373-extract-subagent-state.md +0 -94
  237. package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
  238. package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
  239. package/docs/retro/0376-extract-manager-observer.md +0 -81
  240. package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
  241. package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
  242. package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
  243. package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
  244. package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
  245. package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
  246. package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
  247. package/docs/retro/0412-unify-session-mock-builders.md +0 -80
  248. package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
  249. package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
  250. package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
  251. package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
  252. package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
  253. package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
  254. package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
  255. package/docs/retro/0427-reconsider-ui-direction.md +0 -102
  256. package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -97
  257. package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
  258. package/docs/retro/0443-consolidate-remaining-test-clone-families.md +0 -28
  259. package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
  260. package/docs/retro/0445-native-session-navigation.md +0 -122
  261. package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
  262. package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
  263. package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
  264. package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
  265. package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
  266. package/docs/retro/0470-refresh-readme-command-surface.md +0 -40
  267. package/src/observation/notification-state.ts +0 -27
  268. package/vitest.config.ts +0 -14
@@ -1,217 +0,0 @@
1
- ---
2
- issue: 239
3
- issue_title: "Collapse filterActiveTools to recursion guard (Phase 14, Step 3)"
4
- ---
5
-
6
- # Collapse `filterActiveTools` to recursion guard
7
-
8
- ## Problem Statement
9
-
10
- With `disallowed_tools` (#237) and `extensions` filtering (#238) removed, `filterActiveTools` retains two branches that no longer justify a config bag or two-pass pre-bind/post-bind dance:
11
-
12
- 1. The `extensions === false` early return — a passthrough that belongs at the callsite.
13
- 2. The `EXCLUDED_TOOL_NAMES` recursion guard — the function's sole essential purpose.
14
-
15
- The `builtinToolNameSet` membership check always returns `true` now (no string-array `extensions` filtering remains), making it dead logic.
16
- `ToolFilterConfig` exists only to carry two fields (`toolNames`, `extensions`) through the assembler→runner boundary, but after this change they travel independently: `toolNames` feeds `createSession`, `extensions` feeds the resource loader's `noExtensions` flag, and neither is consumed by the filter function.
17
-
18
- ## Goals
19
-
20
- - Reduce `filterActiveTools` to a one-liner: filter out `EXCLUDED_TOOL_NAMES`.
21
- - Delete the `ToolFilterConfig` interface.
22
- - Flatten `SessionConfig.toolFilter` back into two top-level fields: `toolNames` and `extensions`.
23
- - Remove the pre-bind filter call — without denylist/allowlist logic, filtering before `bindExtensions` serves no purpose.
24
- - Keep a single post-bind filter call for the recursion guard.
25
- - Update tests to reflect the simplified flow.
26
-
27
- ## Non-Goals
28
-
29
- - Removing `extensions` from `SessionConfig` entirely — it's still needed for the `noExtensions` flag on the resource loader.
30
- - Renaming `EXCLUDED_TOOL_NAMES` or moving it to a separate module.
31
- - Phase 15 domain model changes (#227–#232) — those operate on the simplified codebase this change produces.
32
-
33
- ## Background
34
-
35
- `filterActiveTools` was extracted as part of Phase 10 (#168) to group `toolNames`, `disallowedSet`, and `extensions` into a `ToolFilterConfig` bag.
36
- Issue #237 removed `disallowedSet`; #238 narrowed `extensions` from `true | string[] | false` to `boolean`.
37
- Both are now closed.
38
-
39
- The two-pass filter dance (Patch 2, RepOne #443) exists to catch extension-registered tools that join the active set during `bindExtensions`.
40
- With the only remaining filter logic being the `EXCLUDED_TOOL_NAMES` guard, a single post-bind pass suffices.
41
-
42
- Current `filterActiveTools` body:
43
-
44
- ```typescript
45
- function filterActiveTools(
46
- activeTools: string[],
47
- config: ToolFilterConfig,
48
- ): string[] {
49
- const { toolNames, extensions } = config;
50
- if (!extensions) {
51
- return activeTools;
52
- }
53
- const builtinToolNameSet = new Set(toolNames);
54
- return activeTools.filter((t) => {
55
- if (EXCLUDED_TOOL_NAMES.includes(t)) return false;
56
- if (builtinToolNameSet.has(t)) return true;
57
- return true;
58
- });
59
- }
60
- ```
61
-
62
- The `builtinToolNameSet` check is dead — both branches return `true`.
63
- The `!extensions` early return belongs at the callsite.
64
-
65
- ### Affected files
66
-
67
- - `src/lifecycle/agent-runner.ts` — `filterActiveTools`, pre-bind/post-bind calls, `ToolFilterConfig` import
68
- - `src/session/session-config.ts` — `ToolFilterConfig` interface, `SessionConfig.toolFilter` field, assembler return literal
69
- - `test/lifecycle/agent-runner-extension-tools.test.ts` — pre-bind/post-bind assertions
70
- - `test/session/session-config.test.ts` — `toolFilter.*` assertions
71
- - `test/lifecycle/agent-runner.test.ts` — session mock (`setActiveToolsByName` calls)
72
- - `docs/architecture/architecture.md` — references to `ToolFilterConfig`, `filterActiveTools`, Phase 14 status
73
-
74
- ## Design Overview
75
-
76
- ### `filterActiveTools` simplification
77
-
78
- The function reduces to:
79
-
80
- ```typescript
81
- function filterActiveTools(activeTools: string[]): string[] {
82
- return activeTools.filter((t) => !EXCLUDED_TOOL_NAMES.includes(t));
83
- }
84
- ```
85
-
86
- No config parameter.
87
- The `extensions === false` guard moves to the callsite: `if (cfg.extensions)`.
88
-
89
- ### `SessionConfig` flattening
90
-
91
- ```typescript
92
- export interface SessionConfig {
93
- effectiveCwd: string;
94
- systemPrompt: string;
95
- toolNames: string[]; // was toolFilter.toolNames
96
- extensions: boolean; // was toolFilter.extensions
97
- model: unknown;
98
- thinkingLevel: ThinkingLevel | undefined;
99
- noSkills: boolean;
100
- extras: PromptExtras;
101
- agentMaxTurns: number | undefined;
102
- }
103
- ```
104
-
105
- ### `runAgent` callsite changes
106
-
107
- Before (two-pass):
108
-
109
- ```typescript
110
- if (cfg.toolFilter.extensions) {
111
- const filtered = filterActiveTools(session.getActiveToolNames(), cfg.toolFilter);
112
- session.setActiveToolsByName(filtered);
113
- }
114
- // ... bindExtensions ...
115
- if (cfg.toolFilter.extensions) {
116
- const refiltered = filterActiveTools(session.getActiveToolNames(), cfg.toolFilter);
117
- session.setActiveToolsByName(refiltered);
118
- }
119
- ```
120
-
121
- After (single post-bind pass):
122
-
123
- ```typescript
124
- // ... bindExtensions ...
125
- if (cfg.extensions) {
126
- const filtered = filterActiveTools(session.getActiveToolNames());
127
- session.setActiveToolsByName(filtered);
128
- }
129
- ```
130
-
131
- Other `cfg.toolFilter.*` references update to `cfg.toolNames` and `cfg.extensions`.
132
-
133
- ## Module-Level Changes
134
-
135
- ### `src/session/session-config.ts`
136
-
137
- 1. Delete the `ToolFilterConfig` interface.
138
- 2. Replace `toolFilter: ToolFilterConfig` on `SessionConfig` with two flat fields: `toolNames: string[]` and `extensions: boolean`.
139
- 3. Update the return literal in `assembleSessionConfig` from `toolFilter: { toolNames, extensions }` to `toolNames, extensions`.
140
- 4. Update the JSDoc on `SessionConfig` — remove "Tool filtering cluster" comment.
141
-
142
- ### `src/lifecycle/agent-runner.ts`
143
-
144
- 1. Remove the `ToolFilterConfig` import.
145
- 2. Simplify `filterActiveTools` to `(activeTools: string[]) => string[]` — just the `EXCLUDED_TOOL_NAMES` filter.
146
- 3. Remove the pre-bind filter block (the first `if (cfg.toolFilter.extensions)` block).
147
- 4. Update the post-bind filter block: `cfg.toolFilter.extensions` → `cfg.extensions`, remove the config argument from the `filterActiveTools` call.
148
- 5. Update `noExtensions: !cfg.toolFilter.extensions` → `noExtensions: !cfg.extensions`.
149
- 6. Update `tools: cfg.toolFilter.toolNames` → `tools: cfg.toolNames`.
150
- 7. Update or remove the Patch 2 comments — the two-pass dance is gone; the remaining call is just a recursion guard.
151
-
152
- ### `test/lifecycle/agent-runner-extension-tools.test.ts`
153
-
154
- 1. Remove the pre-bind/post-bind ordering assertions — there is only one post-bind call now.
155
- 2. Update `setActiveToolsByName` call count expectations from 2 to 1.
156
- 3. Update assertions to check `setActiveToolsByName.mock.calls[0][0]` (was `calls[1][0]` for the second call).
157
- 4. The `extensions: false` test continues to assert that `setActiveToolsByName` is not called.
158
-
159
- ### `test/session/session-config.test.ts`
160
-
161
- 1. Update `result.toolFilter.toolNames` → `result.toolNames`.
162
- 2. Update `result.toolFilter.extensions` → `result.extensions`.
163
-
164
- ### `test/lifecycle/agent-runner.test.ts`
165
-
166
- 1. No structural changes needed — the session mock already has `setActiveToolsByName: vi.fn()`, and the default test config has `extensions: false` (so the filter doesn't run).
167
- If any test asserts on `setActiveToolsByName` call counts, verify they still pass.
168
-
169
- ### `docs/architecture/architecture.md`
170
-
171
- 1. Update the Phase 14 Step 3 entry to mark it complete.
172
- 2. Update the structural analysis table: `SessionConfig` field count changes, `ToolFilterConfig` is removed.
173
- 3. Update the smell table to mark the two-pass filter and `ToolFilterConfig` smells as resolved.
174
-
175
- ## Test Impact Analysis
176
-
177
- 1. **New tests enabled:** None — the simplification doesn't introduce new testable surface.
178
- 2. **Tests that become redundant:** The pre-bind/post-bind ordering test in `agent-runner-extension-tools.test.ts` — the pre-bind call is removed.
179
- The test that the post-bind filter includes extension tools stays; it verifies the recursion guard runs after `bindExtensions`.
180
- 3. **Tests that stay as-is:** The `extensions: false` skip test, the `EXCLUDED_TOOL_NAMES` exclusion test, all `session-config.test.ts` tests (with property path updates).
181
-
182
- ## TDD Order
183
-
184
- 1. **Flatten `SessionConfig` and delete `ToolFilterConfig`** — Replace `toolFilter: ToolFilterConfig` with `toolNames: string[]` and `extensions: boolean` on `SessionConfig`.
185
- Delete the `ToolFilterConfig` interface.
186
- Update the assembler return literal.
187
- Update `session-config.test.ts` property paths (`result.toolFilter.toolNames` → `result.toolNames`, `result.toolFilter.extensions` → `result.extensions`).
188
- Run `pnpm run check` to verify downstream compile errors (expected in `agent-runner.ts`).
189
- Commit: `refactor: flatten SessionConfig and remove ToolFilterConfig`
190
-
191
- 2. **Simplify `filterActiveTools` and remove pre-bind call** — Reduce `filterActiveTools` to `(activeTools: string[]) => string[]`.
192
- Remove the `ToolFilterConfig` import.
193
- Remove the pre-bind filter block.
194
- Update the post-bind filter block to use `cfg.extensions` and pass no config to `filterActiveTools`.
195
- Update `noExtensions` and `tools` references to `cfg.extensions` and `cfg.toolNames`.
196
- Update `agent-runner-extension-tools.test.ts`: change `setActiveToolsByName` call count from 2 to 1, update assertion indices from `calls[1]` to `calls[0]`, remove the pre-bind/post-bind ordering test, update comments.
197
- Verify `agent-runner.test.ts` still passes.
198
- Commit: `refactor: simplify filterActiveTools to recursion guard`
199
-
200
- 3. **Update architecture docs** — Mark Phase 14 Step 3 as complete.
201
- Update `SessionConfig` field count and remove `ToolFilterConfig` references from the structural analysis.
202
- Mark the two-pass filter and `ToolFilterConfig` smells as resolved.
203
- Commit: `docs: mark Phase 14 Step 3 complete in architecture`
204
-
205
- ## Risks and Mitigations
206
-
207
- 1. **Pre-bind filter removal may miss a recursion-guard edge case** — If a subagent's own tools (`subagent`, `get_subagent_result`, `steer_subagent`) were in the built-in tool set before `bindExtensions`, removing the pre-bind filter could leave them active during the bind phase.
208
- Mitigation: These tools are registered by this extension during `bindExtensions`, not before.
209
- They cannot be in the pre-bind active set.
210
- The post-bind filter is sufficient.
211
-
212
- 2. **Flattening `SessionConfig` may break external consumers** — `SessionConfig` is not exported from the package entry point; it's an internal interface between `session-config.ts` and `agent-runner.ts`.
213
- No external consumers exist.
214
-
215
- ## Open Questions
216
-
217
- None — the issue's changes are unambiguous and all dependencies are complete.
@@ -1,165 +0,0 @@
1
- ---
2
- issue: 242
3
- issue_title: "Rename `Agent` tool to `subagent`"
4
- ---
5
-
6
- # Rename `Agent` tool to `subagent`
7
-
8
- ## Problem Statement
9
-
10
- The `Agent` tool is the only PascalCase tool name in the Pi ecosystem.
11
- Pi's built-in tools are all lowercase (`read`, `bash`, `write`, `edit`, `find`, `grep`, `ls`), and the companion tools in this package already use lowercase snake_case (`get_subagent_result`, `steer_subagent`).
12
- The PascalCase name was inherited from tintinweb/pi-subagents, which mimicked Claude Code's convention rather than Pi's.
13
-
14
- ## Goals
15
-
16
- - Rename the tool from `"Agent"` to `"subagent"` — a **breaking change** (`feat!:`).
17
- - Update `label`, `promptSnippet`, and `description` text to reference `subagent` instead of `Agent`.
18
- - Update `EXCLUDED_TOOL_NAMES` in `agent-runner.ts`.
19
- - Update the fallback display name in `agent-tool.ts` `renderCall`.
20
- - Update architecture docs that reference the `Agent` tool name.
21
- - Update `README.md` tool-name references.
22
- - Update all affected tests.
23
-
24
- ## Non-Goals
25
-
26
- - Renaming the `displayName` of the general-purpose agent type (`"Agent"` in `default-agents.ts` and `agent-types.ts` fallback) — that is a UI display name for the agent *type*, not the tool name.
27
- The widget shows "Agent" as the display name for general-purpose agents; this is a separate concern.
28
- - Renaming the companion tools `get_subagent_result` and `steer_subagent` — they already follow the lowercase convention.
29
- - Updating the companion tools' `label` fields (`"Steer Agent"`, `"Get Agent Result"`) — these use "Agent" in the human-readable sense, not as the tool name.
30
- - Collapsing `filterActiveTools` (#239) — that step is independent within Phase 14.
31
- - Updating pi-permission-system docs — verified that no docs there reference the `Agent` tool name specifically.
32
- All "Agent" references in that package's docs refer to the agent-name concept (per-agent overrides, agent frontmatter), not the tool.
33
-
34
- ## Background
35
-
36
- Phase 14 of the architecture roadmap strips policy enforcement from pi-subagents.
37
- Steps 1 and 2 (#237, #238) are complete; Step 3 (#239, collapse `filterActiveTools`) is open but independent of this rename.
38
- This is Step 4 — the final convention-alignment step in Phase 14.
39
-
40
- ### Files affected
41
-
42
- | File | Current `"Agent"` references |
43
- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
44
- | `src/tools/agent-tool.ts` | `name`, `label`, `promptSnippet`, description text, `renderCall` fallback (line 247) |
45
- | `src/lifecycle/agent-runner.ts` | `EXCLUDED_TOOL_NAMES` array (line 22) |
46
- | `README.md` | Tool name references, usage examples, tool parameter table heading |
47
- | `docs/architecture/architecture.md` | Directory listing comment, findings table, Step 4 description |
48
- | `test/tools/agent-tool.test.ts` | `name` and `label` assertions |
49
- | `test/lifecycle/agent-runner-extension-tools.test.ts` | `"Agent"` in active-tools arrays and `not.toContain` assertion |
50
- | `test/print-mode.test.ts` | `tools.get("Agent")` lookup |
51
- | `test/widget-renderer.test.ts` | `"Agent"` in display-name comment and assertion |
52
- | `test/tools/spawn-config.test.ts` | `displayName: "Agent"` assertions (general-purpose type display name — **no change**, these test the agent type's displayName, not the tool name) |
53
- | `test/tools/foreground-runner.test.ts` | `displayName: "Agent"` in fixture data (**no change** — tests general-purpose type displayName) |
54
- | `test/tools/helpers.test.ts` | `displayName: "Agent"` in fixture data (**no change** — tests result rendering, not tool name) |
55
- | `test/display.test.ts` | `"Agent"` display name assertion (**no change** — tests `getDisplayName` for general-purpose type) |
56
-
57
- ## Design Overview
58
-
59
- This is a straightforward string-replacement change with no logic or type changes.
60
- The tool's `name` field drives Pi's tool registration, system-prompt toolbox, and LLM invocations.
61
-
62
- ### Tool definition changes
63
-
64
- ```typescript
65
- // Before
66
- name: "Agent" as const,
67
- label: "Agent",
68
- promptSnippet: "Agent: Launch a specialized agent for complex, multi-step tasks.",
69
-
70
- // After
71
- name: "subagent" as const,
72
- label: "Subagent",
73
- promptSnippet: "subagent: Launch a specialized agent for complex, multi-step tasks.",
74
- ```
75
-
76
- The description body changes `"The Agent tool launches"` → `"The subagent tool launches"` and `"Agent results are returned"` → `"Subagent results are returned"`.
77
-
78
- ### renderCall fallback
79
-
80
- ```typescript
81
- // Before
82
- : "Agent";
83
- // After
84
- : "Subagent";
85
- ```
86
-
87
- This fallback shows when no `subagent_type` is provided.
88
- Using `"Subagent"` (capitalized for display) is appropriate — it mirrors the tool's identity without conflating with the general-purpose agent type's `displayName`.
89
-
90
- ### EXCLUDED_TOOL_NAMES
91
-
92
- ```typescript
93
- // Before
94
- const EXCLUDED_TOOL_NAMES = ["Agent", "get_subagent_result", "steer_subagent"];
95
- // After
96
- const EXCLUDED_TOOL_NAMES = ["subagent", "get_subagent_result", "steer_subagent"];
97
- ```
98
-
99
- ## Module-Level Changes
100
-
101
- ### `src/tools/agent-tool.ts`
102
-
103
- 1. Change `name: "Agent" as const` → `name: "subagent" as const`.
104
- 2. Change `label: "Agent"` → `label: "Subagent"`.
105
- 3. Change `promptSnippet` to start with `subagent:` instead of `Agent:`.
106
- 4. Change `"The Agent tool launches"` → `"The subagent tool launches"` in description.
107
- 5. Change `"Agent results are returned"` → `"Subagent results are returned"` in description guidelines.
108
- 6. Change fallback `"Agent"` → `"Subagent"` in `renderCall`.
109
-
110
- ### `src/lifecycle/agent-runner.ts`
111
-
112
- 1. Change `"Agent"` → `"subagent"` in `EXCLUDED_TOOL_NAMES`.
113
-
114
- ### `README.md`
115
-
116
- 1. Update tool name references in the "features" bullet (`` `Agent` `` → `` `subagent` ``).
117
- 2. Update usage example heading and code block (`Agent({` → `subagent({`).
118
- 3. Update tool parameter table heading (`### \`Agent\`` → `### \`subagent\``).
119
- 4. Update prose references to the `Agent` tool ("`Agent` tool parameters", "`Agent` tool returns").
120
- 5. Update widget example display — the widget shows `Agent` because the general-purpose type's `displayName` is `"Agent"`, so those lines stay as-is.
121
-
122
- ### `docs/architecture/architecture.md`
123
-
124
- 1. Update the directory listing comment: `agent-tool.ts` description → `subagent tool definition`.
125
- 2. Update the findings table row to mark the item as resolved.
126
- 3. Update Step 4 description to indicate completion.
127
- 4. The `(née \`Agent\`)` parenthetical in the "What the core owns" section already anticipates the rename — keep it as-is for historical context.
128
-
129
- ### Test files
130
-
131
- 1. `test/tools/agent-tool.test.ts` — update `name` and `label` assertions.
132
- 2. `test/lifecycle/agent-runner-extension-tools.test.ts` — update `"Agent"` in active-tools arrays and `.not.toContain("Agent")` → `.not.toContain("subagent")`.
133
- 3. `test/print-mode.test.ts` — update `tools.get("Agent")` → `tools.get("subagent")`.
134
- 4. `test/widget-renderer.test.ts` — update the comment text (the assertion tests general-purpose displayName, which stays `"Agent"`).
135
-
136
- ## Test Impact Analysis
137
-
138
- 1. No new tests are needed — this is a string-value change.
139
- 2. Existing tests that assert the tool name `"Agent"` must be updated to assert `"subagent"`.
140
- 3. Tests that assert the general-purpose agent type's `displayName` (`"Agent"`) are **not affected** — the `displayName` is an agent-type property, not the tool name.
141
-
142
- ## TDD Order
143
-
144
- 1. **Update tool definition and runner constant.**
145
- Change `name`, `label`, `promptSnippet`, description text, and `renderCall` fallback in `agent-tool.ts`.
146
- Change `EXCLUDED_TOOL_NAMES` in `agent-runner.ts`.
147
- Update affected tests in `agent-tool.test.ts`, `agent-runner-extension-tools.test.ts`, `print-mode.test.ts`, and `widget-renderer.test.ts`.
148
- Commit: `feat!: rename Agent tool to subagent (#242)`
149
-
150
- 2. **Update documentation.**
151
- Update `README.md` tool-name references and usage examples.
152
- Update `docs/architecture/architecture.md` directory listing, findings table, and Step 4 status.
153
- Commit: `docs: update tool name references after Agent → subagent rename (#242)`
154
-
155
- ## Risks and Mitigations
156
-
157
- | Risk | Mitigation |
158
- | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
159
- | Breaking change for users referencing `Agent` in AGENTS.md, prompt templates, or custom configs | This is intentional and documented in the issue. Fits within the Phase 14 breaking-change window. Use `feat!:` commit prefix. |
160
- | Forgetting a test reference to `"Agent"` | Grep all test files for `"Agent"` before committing. Distinguish tool-name references from agent-type displayName references. |
161
- | Companion tool labels (`"Steer Agent"`, `"Get Agent Result"`) use "Agent" | These use "Agent" in the human-readable sense. They are not affected by the tool-name rename and remain consistent. |
162
-
163
- ## Open Questions
164
-
165
- None — the issue scope is unambiguous.
@@ -1,256 +0,0 @@
1
- ---
2
- issue: 256
3
- issue_title: "Extract WorktreeIsolation collaborator"
4
- ---
5
-
6
- # Extract WorktreeIsolation collaborator
7
-
8
- ## Problem Statement
9
-
10
- `Agent` currently holds three separate worktree-related members — `_worktrees` (a shared `WorktreeManager`), `_isolation` (the `IsolationMode`), and `worktreeState` (a `WorktreeState` phase object) — and orchestrates the worktree internals itself.
11
- It checks `this._isolation !== "worktree"`, calls `this._worktrees.create()`, constructs the `WorktreeState`, and drives `worktreeState.performCleanup(this._worktrees, ...)` from both `completeRun()` and `failRun()`.
12
- This is Ask-Don't-Tell: `Agent` asks its collaborators for raw materials and does the worktree work itself rather than telling a single collaborator to handle its own lifecycle.
13
-
14
- This is Phase 16, Step 1 of the agent-collaborator architecture (`docs/architecture/architecture.md`).
15
-
16
- ## Goals
17
-
18
- - Introduce a `WorktreeIsolation` collaborator that owns the entire worktree lifecycle: `setup()`, `path` access, and `cleanup(description)`.
19
- - `AgentManager` constructs the collaborator only when `isolation === "worktree"` and passes it to `Agent` ready to go.
20
- - Replace `Agent`'s mode check (`this._isolation !== "worktree"`) with a null check (`this.worktree?.setup()`).
21
- - Fold the existing `WorktreeState` value object into `WorktreeIsolation` (delete `worktree-state.ts`), matching the architecture's target table which lists `WorktreeIsolation` as absorbing `worktrees` + `isolation` + `worktreeState`.
22
- - Shrink `Agent`: remove `_worktrees`, `_isolation`, `worktreeState`, and `setupWorktree()`; add a single `worktree?: WorktreeIsolation` collaborator.
23
-
24
- This change is **not** breaking to any published API — `WorktreeManager`, `WorktreeState`, and `AgentInit` are all internal to the package.
25
-
26
- ## Non-Goals
27
-
28
- - No changes to the runner, session creation, or `ChildSessionFactory` — that is Step 2 (#257).
29
- - No changes to `Agent.run()`'s session-interaction logic, turn-limit enforcement, or response collection — that is Step 3 (#258).
30
- - No changes to the low-level git plumbing in `worktree.ts` (`createWorktree`, `cleanupWorktree`, `pruneWorktrees`, `GitWorktreeManager`) — those free functions and the `WorktreeManager` interface stay as-is.
31
- - No change to the `worktreeResult` shape exposed by `service-adapter.ts` — only the access path changes.
32
-
33
- ## Background
34
-
35
- Relevant modules:
36
-
37
- - `src/lifecycle/agent.ts` — the `Agent` class.
38
- Holds `_worktrees: WorktreeManager`, `_isolation: IsolationMode`, `worktreeState?: WorktreeState`; defines `setupWorktree()`; reads `this.worktreeState?.path` for the runner `cwd`; drives cleanup in `completeRun()` / `failRun()`.
39
- - `src/lifecycle/agent-manager.ts` — `AgentManager` holds the shared `WorktreeManager` (`this.worktrees`), passes `worktrees` + `isolation` into each `Agent` via `AgentInit`, and calls `this.worktrees.prune()` on `dispose()`.
40
- - `src/lifecycle/worktree.ts` — `WorktreeManager` interface + `GitWorktreeManager` impl + free functions.
41
- `WorktreeManager.cleanup(wt, description)` mutates `wt.branch` in place (in `cleanupWorktree`), so the object passed must carry a writable `branch`.
42
- - `src/lifecycle/worktree-state.ts` — `WorktreeState`: holds `path`/`branch`, tracks `cleanupResult`, exposes `performCleanup(worktrees, description)`.
43
- Re-exports `WorktreeCleanupResult` and `WorktreeInfo` (no external consumer imports those two from this path — verified by grep).
44
- - `src/service/service-adapter.ts:131` — reads `record.worktreeState?.cleanupResult` to populate `worktreeResult`.
45
- - `src/index.ts:167` — constructs `new GitWorktreeManager(process.cwd())` and passes it to `AgentManager`.
46
-
47
- AGENTS.md constraints that apply:
48
-
49
- - This package targets ES2024; Biome (not Prettier) formats.
50
- - Tests use `vi.hoisted(...)` patterns; the full vitest suite must pass before publishing.
51
- - When a barrel/module gains exports, verify a consumer imports them — fallow flags speculative re-exports.
52
- Here we are removing a module, not adding one, so the risk is dangling imports rather than dead exports.
53
-
54
- ## Design Overview
55
-
56
- ### Decision model
57
-
58
- `AgentManager` owns the shared `WorktreeManager` (one instance, repo-root-bound).
59
- Per spawn, when `isolation === "worktree"`, it constructs a per-agent `WorktreeIsolation` bound to that `WorktreeManager` and the agent id, and hands it to `Agent`.
60
- When isolation is not requested, no collaborator is created and `Agent.worktree` is `undefined`.
61
-
62
- `Agent` no longer knows the isolation mode or the `WorktreeManager`.
63
- The presence/absence of the collaborator *is* the mode: `this.worktree?.setup()` and `this.worktree?.cleanup(...)`.
64
-
65
- ### WorktreeIsolation shape
66
-
67
- ```typescript
68
- // src/lifecycle/worktree-isolation.ts
69
- import type { WorktreeCleanupResult, WorktreeInfo, WorktreeManager } from "#src/lifecycle/worktree";
70
-
71
- export class WorktreeIsolation {
72
- private _info?: WorktreeInfo;
73
- private _cleanupResult?: WorktreeCleanupResult;
74
-
75
- constructor(
76
- private readonly worktrees: WorktreeManager,
77
- private readonly agentId: string,
78
- ) {}
79
-
80
- /** Absolute worktree path — undefined before setup(). */
81
- get path(): string | undefined {
82
- return this._info?.path;
83
- }
84
-
85
- /** Cleanup outcome — undefined until cleanup() runs. */
86
- get cleanupResult(): WorktreeCleanupResult | undefined {
87
- return this._cleanupResult;
88
- }
89
-
90
- /**
91
- * Create the git worktree and store its info.
92
- * Throws on failure (strict isolation — no silent fallback).
93
- */
94
- setup(): void {
95
- const wt = this.worktrees.create(this.agentId);
96
- if (!wt) {
97
- throw new Error(
98
- 'Cannot run with isolation: "worktree" — not a git repo, no commits yet, or `git worktree add` failed. ' +
99
- "Initialize git and commit at least once, or omit `isolation`.",
100
- );
101
- }
102
- this._info = wt;
103
- }
104
-
105
- /** Perform cleanup and record the result. No-op ({ hasChanges: false }) if setup never ran. */
106
- cleanup(description: string): WorktreeCleanupResult {
107
- if (!this._info) return { hasChanges: false };
108
- const result = this.worktrees.cleanup(this._info, description);
109
- this._cleanupResult = result;
110
- return result;
111
- }
112
- }
113
- ```
114
-
115
- Notes:
116
-
117
- - `_info` is a mutable `WorktreeInfo`, so `WorktreeManager.cleanup` mutating `branch` in place keeps working (the same behavior `WorktreeState` relied on today).
118
- - The `missing worktrees dependency` error from `setupWorktree()` disappears: the collaborator is only ever created with a `WorktreeManager`, so that defensive branch is structurally impossible.
119
- - `cleanup()` returns `{ hasChanges: false }` when `setup()` never ran, so `Agent`'s `completeRun()`/`failRun()` can call it unconditionally via the optional-chain without a separate guard.
120
-
121
- ### Agent call sites (Tell-Don't-Ask)
122
-
123
- `Agent.run()` setup:
124
-
125
- ```typescript
126
- try {
127
- this.worktree?.setup(); // was: this.setupWorktree() with internal mode check
128
- } catch (err) {
129
- this.markError(err);
130
- this.releaseListeners();
131
- this.observer?.onRunFinished?.(this);
132
- return;
133
- }
134
- // ...
135
- cwd: this.worktree?.path, // was: this.worktreeState?.path
136
- ```
137
-
138
- `Agent.completeRun()`:
139
-
140
- ```typescript
141
- let finalResult = result.responseText;
142
- const wtResult = this.worktree?.cleanup(this.description);
143
- if (wtResult?.hasChanges && wtResult.branch) {
144
- finalResult += `\n\n---\nChanges saved to branch \`${wtResult.branch}\`. Merge with: \`git merge ${wtResult.branch}\``;
145
- }
146
- ```
147
-
148
- `Agent.failRun()`:
149
-
150
- ```typescript
151
- try {
152
- this.worktree?.cleanup(this.description);
153
- } catch (cleanupErr) {
154
- debugLog("cleanupWorktree on agent error", cleanupErr);
155
- }
156
- ```
157
-
158
- `AgentManager.spawn()`:
159
-
160
- ```typescript
161
- const worktree = options.isolation === "worktree"
162
- ? new WorktreeIsolation(this.worktrees, id)
163
- : undefined;
164
- const record = new Agent({ /* ... */, worktree /* was: worktrees + isolation */ });
165
- ```
166
-
167
- The reach-through `agent.worktreeState.cleanupResult` in `service-adapter.ts` becomes `agent.worktree?.cleanupResult` — the collaborator owns the result, so this is a single-hop access, not a reach-through into a phase object.
168
-
169
- ### Edge cases
170
-
171
- - Isolation not requested → `worktree` is `undefined` → `setup()`/`cleanup()` are skipped via optional chaining; behavior identical to today's `_isolation !== "worktree"` early-return.
172
- - `create()` returns `undefined` (not a git repo) → `setup()` throws; `Agent.run()` catches, marks error, releases listeners, fires `onRunFinished`.
173
- The existing AgentManager regression test (worktree fails loud, no silent fallback) is preserved.
174
- - Cleanup throws in `failRun()` → caught and logged best-effort, identical to today.
175
-
176
- ## Module-Level Changes
177
-
178
- - New: `src/lifecycle/worktree-isolation.ts` — the `WorktreeIsolation` class (shape above).
179
- - Changed: `src/lifecycle/agent.ts`
180
- - Remove imports of `WorktreeManager` (type) and `WorktreeState`; add import of `WorktreeIsolation`.
181
- - `AgentInit`: remove `worktrees?: WorktreeManager` and `isolation?: IsolationMode`; add `worktree?: WorktreeIsolation`.
182
- (`IsolationMode` may remain imported if still referenced elsewhere in the file; grep confirms it is only used for the removed field — remove the now-unused import.)
183
- - Remove instance fields `_worktrees`, `_isolation`, `worktreeState`; add `worktree?: WorktreeIsolation`.
184
- - Remove the `setupWorktree()` method.
185
- - Constructor: replace the `_worktrees`/`_isolation` assignments with `this.worktree = init.worktree`.
186
- - `run()`: `this.worktree?.setup()`; `cwd: this.worktree?.path`.
187
- - `completeRun()` / `failRun()`: replace the 4-line `worktreeState && _worktrees` blocks with `this.worktree?.cleanup(this.description)`.
188
- - Update the file header doc comment (lists `worktreeState` as a phase-specific collaborator).
189
- - Changed: `src/lifecycle/agent-manager.ts`
190
- - Import `WorktreeIsolation`.
191
- - `spawn()`: construct the per-agent `WorktreeIsolation` when `options.isolation === "worktree"`; pass `worktree` to `Agent` instead of `worktrees` + `isolation`.
192
- - Keep `this.worktrees` field, `AgentManagerOptions.worktrees`, and the `dispose()` → `this.worktrees.prune()` call unchanged.
193
- - Changed: `src/service/service-adapter.ts`
194
- - `record.worktreeState?.cleanupResult` → `record.worktree?.cleanupResult`.
195
- - Removed: `src/lifecycle/worktree-state.ts` (folded into `WorktreeIsolation`).
196
- - Doc updates (`docs/architecture/architecture.md`):
197
- - Class diagram (line ~115): `+worktreeState?: WorktreeState` → `+worktree?: WorktreeIsolation`; remove the `+setupWorktree(...)` method line.
198
- - Layout listing (lines ~279–280): replace `worktree-state.ts worktree phase state` with `worktree-isolation.ts worktree lifecycle collaborator`.
199
- - Doc update (`.pi/skills/package-pi-subagents/SKILL.md`): Lifecycle domain row — replace `worktree-state.ts` with `worktree-isolation.ts` (module count stays 9).
200
-
201
- Symbols removed and their consumers (grepped across `src/` and `test/`):
202
-
203
- - `WorktreeState` (class): `src/lifecycle/agent.ts` (removed in this plan), `test/lifecycle/agent.test.ts`, `test/service/service-adapter.test.ts`, `test/lifecycle/worktree-state.test.ts` — all updated/removed below.
204
- - `Agent.setupWorktree()`: only `test/lifecycle/agent.test.ts` — removed below.
205
- - `Agent.worktreeState`: `service-adapter.ts` + several tests — all migrated to `worktree`.
206
- - The `WorktreeCleanupResult`/`WorktreeInfo` re-exports from `worktree-state.ts`: no external importer (verified) — safe to drop.
207
-
208
- ## Test Impact Analysis
209
-
210
- 1. New unit tests enabled by the extraction: `WorktreeIsolation` is now independently testable without an `Agent` — `worktree-isolation.test.ts` covers `setup()` (success stores path; failure throws), `cleanup()` (delegates to `worktrees.cleanup` with stored info + description, records `cleanupResult`; no-op before setup), and `path`/`cleanupResult` getters.
211
- These absorb the existing `worktree-state.test.ts` coverage (constructor, `recordCleanup`, `performCleanup`) at the same granularity.
212
- 2. Existing tests that become redundant / simplified: `test/lifecycle/worktree-state.test.ts` is removed (its behavior is covered by the new collaborator tests).
213
- The `Agent — setupWorktree` describe block in `agent.test.ts` is removed (the method is gone); its intent migrates to the `WorktreeIsolation` unit tests plus the existing `Agent.run() — worktree` integration tests.
214
- 3. Existing tests that must stay (genuinely exercise the layer):
215
- `test/lifecycle/worktree.test.ts` (git plumbing + `GitWorktreeManager`) is untouched.
216
- `Agent.run() — worktree` integration tests stay but switch their assertions from `agent.worktreeState` to `agent.worktree` and construct the agent with a `WorktreeIsolation`.
217
- `agent-manager.test.ts` worktree tests stay but assert via `record.worktree?.path` / `record.worktree?.cleanupResult`.
218
-
219
- ## TDD Order
220
-
221
- 1. Add `WorktreeIsolation` with unit tests — new module, no consumers yet.
222
- Surface: `test/lifecycle/worktree-isolation.test.ts`.
223
- Covers: `setup()` success/failure, `cleanup()` delegation + result recording + pre-setup no-op, `path`/`cleanupResult` getters (migrating `worktree-state.test.ts` coverage).
224
- Commit: `test: add WorktreeIsolation collaborator tests` then `feat(pi-subagents): add WorktreeIsolation collaborator`. (May be a single `feat` commit with the test if preferred — the module is self-contained.)
225
- 2. Wire `WorktreeIsolation` into `Agent` and `AgentManager`; drop the old fields.
226
- This is one commit because TypeScript will not accept `AgentInit` losing `worktrees`/`isolation` while call sites still pass them.
227
- Changes: `agent.ts` (remove `_worktrees`/`_isolation`/`worktreeState`/`setupWorktree`, add `worktree`, update `run`/`completeRun`/`failRun`), `agent-manager.ts` (construct collaborator in `spawn`), `service-adapter.ts` (`record.worktree?.cleanupResult`), and their tests (`agent.test.ts` helpers `createRunnableAgent`/`createAgentWithWorktrees` + worktree describe blocks; remove the `setupWorktree` block; `agent-manager.test.ts` worktree assertions; `service-adapter.test.ts` setup).
228
- Commit: `refactor(pi-subagents): Agent delegates worktree lifecycle to WorktreeIsolation`.
229
- 3. Delete the now-orphaned `WorktreeState`.
230
- Remove `src/lifecycle/worktree-state.ts` and `test/lifecycle/worktree-state.test.ts`; remove any remaining `WorktreeState` imports.
231
- Run `pnpm fallow dead-code` to confirm no dangling exports.
232
- Commit: `refactor(pi-subagents): remove WorktreeState, folded into WorktreeIsolation`.
233
- 4. Update architecture doc + package skill.
234
- `docs/architecture/architecture.md` class diagram + layout listing; `SKILL.md` Lifecycle domain row.
235
- Commit: `docs(pi-subagents): reflect WorktreeIsolation extraction in architecture`.
236
-
237
- After all steps: `pnpm run check`, `pnpm run lint`, `pnpm -r run test`, `pnpm fallow dead-code`.
238
-
239
- ## Risks and Mitigations
240
-
241
- - Risk: `WorktreeManager.cleanup` mutates `branch` in place; folding `WorktreeState` could lose that behavior.
242
- Mitigation: `WorktreeIsolation` stores a mutable `WorktreeInfo` (`_info`) and passes it directly to `cleanup`, preserving the in-place mutation.
243
- - Risk: a hidden consumer imports `WorktreeCleanupResult`/`WorktreeInfo` from `worktree-state.ts`.
244
- Mitigation: grep confirms all consumers import those types from `worktree.ts`; the deletion step re-runs the grep and `pnpm run check`.
245
- - Risk: the combined Step 2 commit touches several test files at once.
246
- Mitigation: the changes are mechanical and localized to worktree-specific helpers/describe blocks; the type checker pinpoints every call site.
247
- The bulk of `agent.test.ts` is untouched.
248
- - Risk: AgentManager's `dispose()` prune path relies on `this.worktrees`.
249
- Mitigation: `AgentManager` keeps ownership of the shared `WorktreeManager`; only per-agent collaborator construction is added.
250
-
251
- ## Open Questions
252
-
253
- - Whether `setup()` should return the path (as `setupWorktree()` did) for symmetry.
254
- Deferred: no caller needs the return value once `Agent` reads `this.worktree?.path`; keep `setup(): void` until a consumer needs otherwise.
255
- - Whether `WorktreeIsolation` should later absorb the parent `cwd`/repo-root concern from `GitWorktreeManager`.
256
- Deferred to the broader Phase 16 collaborator work; out of scope for Step 1.