@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,220 +0,0 @@
1
- ---
2
- issue: 447
3
- issue_title: "pi-subagents: extract subagent settings to a focused /subagents-settings command"
4
- ---
5
-
6
- # Extract subagent settings to a focused `/subagents-settings` command
7
-
8
- ## Release Recommendation
9
-
10
- **Release:** ship independently
11
-
12
- Phase 19 Step 2 ([#447]) carries `Release: independent` in the architecture roadmap, and the only batch defined there is "dissolve-agents" (Steps 5–6, [#442]/[#441]).
13
- This step is purely additive — it stands up the new command without touching `agent-menu.ts` — so it ships on its own with no batch coupling.
14
-
15
- ## Problem Statement
16
-
17
- The `/agents` command bundles four unrelated jobs (running-agent visibility, agent-type browsing, the creation wizard, and operational settings).
18
- ADR-0004 Decision C splits them.
19
- Settings has standalone value but does not belong buried inside an agent-management menu — a focused, top-level command is discoverable on its own without navigating a multi-purpose menu.
20
-
21
- This step is deliberately **additive**: it stands up the new command without touching `agent-menu.ts`.
22
- The old in-menu Settings option keeps working until Phase 19 Step 5 ([#442]) deletes `agent-menu.ts` wholesale.
23
- Keeping the work additive avoids surgery on the doomed module and lets this step run in parallel with the rest of the Phase 19 replacement track.
24
-
25
- ## Goals
26
-
27
- - Add `src/ui/subagents-settings.ts` — a `SubagentsSettingsHandler` lifted verbatim from `AgentsMenuHandler.showSettings`, carrying its own narrow manager interface (the three `apply*` methods and three readonly accessors only) and a narrow UI interface (only `select`, `input`, `notify`).
28
- - Register the `/subagents-settings` command in `src/index.ts`, passing the existing `settings` (`SettingsManager`) directly.
29
- - Add `test/ui/subagents-settings.test.ts` covering the extracted handler's behavior.
30
-
31
- Non-breaking: this is pure addition.
32
- No existing export, command, or behavior changes.
33
-
34
- ## Non-Goals
35
-
36
- - Do **not** remove `showSettings` or `AgentMenuSettings` from `agent-menu.ts` — that file is deleted whole in Phase 19 Step 5 ([#442]).
37
- - Do **not** modify the `/agents` command, its handler, or any wiring in `index.ts` beyond adding the new registration block.
38
- - Do **not** add a settings re-show loop or any new settings behavior — the lift preserves the single-selection-then-return semantics of `showSettings` (see Design Overview).
39
- - Defer the background widget ([#444]), native session navigation ([#445]), and the `/agents` dissolution ([#442]/[#441]) to their own Phase 19 steps.
40
-
41
- ## Background
42
-
43
- Relevant existing modules:
44
-
45
- - `src/ui/agent-menu.ts` — `AgentsMenuHandler.showSettings(ui)` is the source of the lift.
46
- It depends solely on `this.settings` (typed `AgentMenuSettings`) and the `ui` parameter (`MenuUI`).
47
- It calls `ui.select` once, then `ui.input` + one `settings.apply*` + `ui.notify` for the chosen field.
48
- It does not loop: it shows the settings list once, applies one change (or none), and returns.
49
- The re-show in the live menu comes from `showAgentsMenu` re-invoking *itself* after `showSettings` returns — not from `showSettings` looping.
50
- - `AgentMenuSettings` (in `agent-menu.ts`) — the narrow settings shape `showSettings` reads: `readonly maxConcurrent`, `readonly defaultMaxTurns: number | undefined`, `readonly graceTurns`, plus `applyMaxConcurrent`/`applyDefaultMaxTurns`/`applyGraceTurns`, each returning `{ message: string; level: "info" | "warning" }`.
51
- - `MenuUI` (in `agent-menu.ts`) — the wide menu UI interface; `showSettings` uses only `select`, `input`, and `notify` from it.
52
- - `src/settings.ts` — `SettingsManager` is the concrete settings object constructed in `index.ts`.
53
- It already exposes all six members of `AgentMenuSettings` (the three getters and three `apply*` methods), so it structurally satisfies the new narrow manager interface and can be passed directly.
54
- - `src/index.ts` — constructs `settings = new SettingsManager(...)`, then `new AgentsMenuHandler(manager, registry, settings, ...)` and `registerCommand("agents", ...)`.
55
- Sibling commands register flat, hyphenated names (`agents`, `colgrep-reindex`, `permission-system`) — no `:` namespace.
56
- - `docs/decisions/0004-reconsider-ui-direction.md` — the addendum (2026-06-20) confirms the command name **`/subagents-settings`** (Criterion 4) and rejects `/subagents:settings` and `/agents-settings`.
57
-
58
- AGENTS.md / package constraints:
59
-
60
- - pi-subagents is a minimal core; the surviving UI is an in-core reactive consumer.
61
- This extraction adds a command surface only — no policy, no new core dependency.
62
- - Modules marked `← removing` (the `/agents` subtree) must not gain features — this plan adds nothing to `agent-menu.ts`.
63
-
64
- ## Design Overview
65
-
66
- `SubagentsSettingsHandler` is a faithful lift of `showSettings` into a standalone, independently-registered command.
67
- It owns the settings UI interaction and depends on two narrow interfaces it declares itself (ISP — neither carries a field the handler does not use).
68
-
69
- ### Narrow interfaces
70
-
71
- ```typescript
72
- /** Narrow settings interface required by the subagents-settings command. */
73
- export interface SubagentsSettingsManager {
74
- readonly maxConcurrent: number;
75
- readonly defaultMaxTurns: number | undefined;
76
- readonly graceTurns: number;
77
- applyMaxConcurrent(n: number): { message: string; level: "info" | "warning" };
78
- applyDefaultMaxTurns(n: number): { message: string; level: "info" | "warning" };
79
- applyGraceTurns(n: number): { message: string; level: "info" | "warning" };
80
- }
81
-
82
- /** Narrow UI interface — only the ctx.ui methods the settings handler calls. */
83
- export interface SubagentsSettingsUI {
84
- select(title: string, options: string[]): Promise<string | undefined>;
85
- input(title: string, defaultValue?: string): Promise<string | undefined>;
86
- notify(message: string, level: "info" | "warning" | "error"): void;
87
- }
88
- ```
89
-
90
- `SubagentsSettingsManager` is shape-identical to `AgentMenuSettings` but owned by the new module (zero import from `agent-menu.ts`, which is doomed).
91
- `SubagentsSettingsUI` is narrower than `MenuUI` — it drops `confirm`, `editor`, and `custom`, which `showSettings` never calls.
92
-
93
- ### Handler
94
-
95
- ```typescript
96
- export class SubagentsSettingsHandler {
97
- constructor(private readonly settings: SubagentsSettingsManager) {}
98
-
99
- async handle({ ui }: { ui: SubagentsSettingsUI }): Promise<void> {
100
- // verbatim lift of showSettings: one select → input → apply* → notify
101
- }
102
- }
103
- ```
104
-
105
- The body is copied character-for-character from `showSettings` (the same three `if` branches, the same `parseInt` / validation / toast wiring), with `this.settings` resolving against the new narrow interface.
106
-
107
- ### Registration call site (index.ts)
108
-
109
- ```typescript
110
- const subagentsSettings = new SubagentsSettingsHandler(settings);
111
- pi.registerCommand("subagents-settings", {
112
- description: "Configure subagent settings (concurrency, turn limits)",
113
- handler: async (_args, ctx) => {
114
- await subagentsSettings.handle({ ui: ctx.ui });
115
- },
116
- });
117
- ```
118
-
119
- `settings` (the `SettingsManager` instance) is passed directly — it structurally satisfies `SubagentsSettingsManager`.
120
- The command handler needs only `ctx.ui` (no `modelRegistry`, no `parentSnapshot`), so its params are narrower than the `/agents` handler's.
121
-
122
- ### Design-review findings
123
-
124
- | Smell | Location | Evidence | Result |
125
- | --------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
126
- | Wide interface | `SubagentsSettingsManager` (6 members) | `handle` reads all 3 accessors and calls all 3 apply methods | None — 100% usage |
127
- | Wide interface | `SubagentsSettingsUI` (3 methods) | `handle` calls `select`, `input`, `notify` | None — 100% usage |
128
- | LoD violation | `subagents-settings.ts` | `this.settings.applyMaxConcurrent(n)` is a direct call; `ui.notify(toast.message, toast.level)` reads a returned value, not a reach-through | None |
129
- | Output argument | `subagents-settings.ts` | handler reads accessors + calls apply methods; never writes back into `settings` or `ui` | None |
130
-
131
- The extraction introduces a genuine new collaborator (a focused command handler owning the settings interaction) with its own narrow contracts — it is not procedure-splitting.
132
-
133
- ### Edge cases (preserved verbatim from `showSettings`)
134
-
135
- - `select` returns `undefined` (operator cancels) → return early, no change.
136
- - `input` returns falsy (empty / cancel) → no apply call.
137
- - `maxConcurrent` / `graceTurns`: reject `n < 1` with `"Must be a positive integer."` warning.
138
- - `defaultMaxTurns`: accept `n >= 0` (0 = unlimited); reject `n < 0` with `"Must be 0 (unlimited) or a positive integer."` warning.
139
- - Single selection then return — no settings re-show loop (matches current `showSettings`).
140
-
141
- ## Module-Level Changes
142
-
143
- - **New** `src/ui/subagents-settings.ts` — `SubagentsSettingsHandler` class, `SubagentsSettingsManager` interface, `SubagentsSettingsUI` interface.
144
- ~80 LOC.
145
- - **Changed** `src/index.ts` — add the `SubagentsSettingsHandler` import, construct it, and register the `subagents-settings` command.
146
- No other lines change; the `/agents` block stays intact.
147
- - **New** `test/ui/subagents-settings.test.ts` — unit tests for the handler.
148
- - **No change** to `src/ui/agent-menu.ts` (and its `AgentMenuSettings` / `showSettings` / `MenuUI` stay as-is — deleted later in [#442]).
149
-
150
- Doc / skill grep results (no stale references to update in this step):
151
-
152
- - `architecture.md` Step 2 already names `src/ui/subagents-settings.ts`, `SubagentsSettingsHandler`, `SubagentsSettingsManager`, and the `/subagents-settings` command with `Outcome: new subagents-settings.ts (~80 LOC) and focused command registered; agent-menu.ts untouched` — the file appears as a *planned* addition, so no doc edit is needed now; its status line flips to ✅ at ship time only if the operator wants it folded in.
153
- - The package skill (`.pi/skills/package-pi-subagents/SKILL.md`) lists the UI domain by count (`ui/` = 10 modules); adding one file makes it 11, but the table is a coarse summary that is not maintained per-file — leave it for a later Phase 19 doc-sync unless the operator asks otherwise.
154
- - `settings.ts` comments reference `/agents → Settings` as the writer of project settings; those are still accurate (the in-menu path keeps working), so no edit.
155
- They become stale only when [#442] deletes `agent-menu.ts`; do not pre-edit them here.
156
-
157
- ## Test Impact Analysis
158
-
159
- 1. **New tests enabled by the extraction.**
160
- `test/ui/subagents-settings.test.ts` can unit-test the settings flow in isolation against the standalone handler — no `AgentsMenuHandler` construction (registry, fileOps, two agent dirs) required.
161
- This is strictly more focused than the current `agent-menu.test.ts` "agent menu — settings" describe block, which has to drive the full top menu (`"Settings"` from the main menu) before reaching the settings list.
162
- 2. **Existing tests that become redundant.**
163
- None are removed in this step.
164
- The "agent menu — settings" tests in `agent-menu.test.ts` still genuinely exercise the live in-menu path, which keeps working until [#442].
165
- They are superseded only when `agent-menu.ts` is deleted in Step 5 — removing them now would drop coverage of a still-shipping surface.
166
- 3. **Existing tests that must stay as-is.**
167
- All of `agent-menu.test.ts` stays unchanged — this step does not touch `agent-menu.ts`.
168
-
169
- ## Invariants at risk
170
-
171
- This step adds a new module and one registration; it does not touch the Phase 18 spine that prior steps refactored.
172
- The ADR-0004 / Phase 18 invariants (runtime holds zero UI state [#422]; widget is a reactive consumer with no inbound core calls [#423]; the `subagent` tool depends only on manager/runtime/settings/registry [#424]; declared event channels equal emitted channels [#425]) are untouched and stay pinned by their existing suites.
173
- The new handler adds no inbound call into the core and emits no events — it reads/applies through the existing `SettingsManager` surface only, so it preserves these invariants by construction.
174
-
175
- ## TDD Order
176
-
177
- 1. **Red→Green: extract `SubagentsSettingsHandler` with its narrow interfaces.**
178
- Test surface: `test/ui/subagents-settings.test.ts`.
179
- Write tests against a `makeSettings()`-style manager stub (lift the stub shape from `agent-menu.test.ts`) and a narrow UI stub (lift `makeMenuUI`, or reuse it — it already provides `select`/`input`/`notify`):
180
- - constructable;
181
- - cancel at the settings list (`select` → `undefined`) → no apply call;
182
- - `maxConcurrent`: valid input delegates to `applyMaxConcurrent(n)` and notifies the returned toast; `n < 1` notifies the positive-integer warning and does not apply;
183
- - `defaultMaxTurns`: `0` delegates `applyDefaultMaxTurns(0)`; a positive value delegates; `n < 0` notifies the warning;
184
- - `graceTurns`: valid input delegates to `applyGraceTurns(n)`; `n < 1` notifies the warning;
185
- - empty/cancelled `input` → no apply call.
186
- Implementation: create `src/ui/subagents-settings.ts` with the class and both interfaces; body lifted verbatim from `showSettings`.
187
- Commit: `feat: add SubagentsSettingsHandler for focused settings command (#447)`.
188
- 2. **Green: register the `/subagents-settings` command in `index.ts`.**
189
- Test surface: none new (command registration in `index.ts` is exercised by the package's existing index-level wiring tests if present; otherwise verify by `pnpm run check` and the suite).
190
- Implementation: import `SubagentsSettingsHandler`, construct it with `settings`, and `registerCommand("subagents-settings", ...)` passing `{ ui: ctx.ui }`.
191
- Run `pnpm run check` immediately (the registration is the only call site of the new export — it must compile alongside the new module).
192
- Commit: `feat: register /subagents-settings command (#447)`.
193
-
194
- Both steps may be folded into one commit if preferred — the export and its single call site are small — but keeping the handler (with its tests) separate from the wiring keeps each commit self-contained and reviewable.
195
-
196
- ## Risks and Mitigations
197
-
198
- - **Risk: the lift diverges from `showSettings`, causing the standalone command to behave differently from the in-menu option while both ship.**
199
- Mitigation: copy the body verbatim and assert the same validation/toast behavior in the new test file; the two surfaces share the same `SettingsManager`, so applied values are identical.
200
- - **Risk: passing `SettingsManager` directly fails structural typing against the new narrow interface.**
201
- Mitigation: `SettingsManager` already declares all six members with matching signatures (verified in `src/settings.ts`); `pnpm run check` in Step 2 confirms it.
202
- - **Risk: command-name drift from the ADR.**
203
- Mitigation: the name `subagents-settings` is fixed by the ADR-0004 addendum (Criterion 4) and the roadmap Step 2; use it exactly.
204
- - **Risk: an unused-import or dead-export flag if the wiring lands in a separate commit from the handler.**
205
- Mitigation: Step 2 adds the sole call site immediately; run `pnpm fallow dead-code` before pushing.
206
-
207
- ## Open Questions
208
-
209
- - Whether to also flip the `architecture.md` Step 2 status line to ✅ in this issue or defer to a Phase 19 doc-sync — decide at ship time (the architecture entry currently lists the file as planned, which is harmless until then).
210
- - Whether a settings re-show loop (apply one setting → re-show the list) is desirable for the standalone command — deferred; the lift preserves single-selection-then-return to match current behavior, and a loop is a separate UX decision.
211
-
212
- [#441]: https://github.com/gotgenes/pi-packages/issues/441
213
- [#442]: https://github.com/gotgenes/pi-packages/issues/442
214
- [#444]: https://github.com/gotgenes/pi-packages/issues/444
215
- [#445]: https://github.com/gotgenes/pi-packages/issues/445
216
- [#447]: https://github.com/gotgenes/pi-packages/issues/447
217
- [#422]: https://github.com/gotgenes/pi-packages/issues/422
218
- [#423]: https://github.com/gotgenes/pi-packages/issues/423
219
- [#424]: https://github.com/gotgenes/pi-packages/issues/424
220
- [#425]: https://github.com/gotgenes/pi-packages/issues/425
@@ -1,207 +0,0 @@
1
- ---
2
- issue: 448
3
- issue_title: "`enabled: false` does not prevent explicitly spawning disabled agents"
4
- ---
5
-
6
- # Honor `enabled: false` in the spawn path and tool-description list
7
-
8
- ## Release Recommendation
9
-
10
- **Release:** ship independently
11
-
12
- This is a standalone bug fix.
13
- It is not referenced by any step in `packages/pi-subagents/docs/architecture/architecture.md`, so it carries no `Release:` batch tag and should ship on its own.
14
-
15
- ## Problem Statement
16
-
17
- In `@gotgenes/pi-subagents`, setting `enabled: false` on a custom agent override (e.g. `.pi/agents/Plan.md`) hides the agent from `getAvailableTypes()` — so it disappears from the `subagent_type` available-types list — but does **not** prevent it from being spawned when named explicitly via `subagent_type: "Plan"`.
18
-
19
- This contradicts both the README ("disabled per-project with `enabled: false`") and the inline registry comment in `agent-types.ts` ("Disabled agents are kept but excluded from spawning").
20
-
21
- The root cause is that the spawn resolution path (`resolveSpawnConfig`) calls `registry.resolveType()`, which delegates to `resolveKey()` and only checks key existence, never `enabled`.
22
- The registry already has an `isValidType()` method that checks `enabled`, but it is not used in the spawn path.
23
-
24
- A secondary inconsistency: `buildTypeListText()` (the subagent tool description) lists agents via `getDefaultAgentNames()` / `getUserAgentNames()`, which filter by `isDefault` only, not `enabled`.
25
- So a disabled agent still appears in the "Default agents" / "Custom agents" sections of the tool description, even though it is correctly excluded from the `subagent_type` parameter's available-types line.
26
-
27
- ## Goals
28
-
29
- - A disabled agent named explicitly via `subagent_type` is **not** spawned.
30
- Instead, the spawn returns an explicit error: `Agent type "<Name>" is disabled` (operator-confirmed behavior over the fallback alternative).
31
- - The error uses the registry's canonical key for the name, so case-insensitive input (`plan` → `Plan`) reports the canonical casing.
32
- - Disabled agents no longer appear in the "Default agents" / "Custom agents" sections of the subagent tool description, making the tool description consistent with the `subagent_type` available-types line.
33
- - Genuinely unknown types continue to fall back to `general-purpose` (unchanged).
34
- - Enabled types continue to resolve and spawn exactly as before (unchanged).
35
-
36
- This is a **behavior change** but **not a breaking change**: explicit spawning of a disabled agent was buggy, undocumented behavior that contradicted the documented contract.
37
- The fix makes the code match what the README and registry comment already promise.
38
- Commit messages use `fix:`.
39
-
40
- ## Non-Goals
41
-
42
- - No change to the lenient unknown-type fallback (`fellBack` → `general-purpose`).
43
- Disabled is distinct from unknown: a disabled type is a known agent that the operator deliberately turned off, so an explicit error is more informative than a silent fallback.
44
- - No change to `resolveAgentConfig()`'s handling of disabled configs.
45
- The UI (`display.ts`, `agent-menu.ts`, `agent-config-editor.ts`) deliberately resolves disabled configs to display, edit, and re-enable them; that behavior must be preserved.
46
- - No change to the `/agents` menu, which lists disabled agents (marked `✕`) via `getAllTypes()` — intentional and unaffected.
47
- - No README rewrite: the README already states that `enabled: false` disables an agent for spawning, so it is now accurate.
48
- (An optional one-line note documenting the error message is in Open Questions.)
49
-
50
- ## Background
51
-
52
- Relevant modules:
53
-
54
- - `src/config/agent-types.ts` — `AgentTypeRegistry`.
55
- - `resolveType(name)` → `resolveKey(name)`: returns the canonical key for any existing agent, **ignoring `enabled`**.
56
- - `isValidType(type)`: resolves the key and returns `false` when the config has `enabled === false` (or the key is unknown).
57
- Already exists, already tested, **not used in the spawn path**.
58
- - `resolveAgentConfig(type)`: returns the config for an existing key (including disabled) or falls back to `general-purpose`.
59
- Used by both the spawn path and the UI.
60
- - `getDefaultAgentNames()` / `getUserAgentNames()`: filter by `isDefault`, not `enabled`.
61
- Sole consumer is `buildTypeListText` (verified by grep across `src/` and `test/`).
62
- - `src/tools/spawn-config.ts` — `resolveSpawnConfig(params, registry, modelInfo, settings)`.
63
- Pure function returning `ResolvedSpawnConfig | SpawnConfigError`.
64
- Lines 80-83 resolve the type:
65
-
66
- ```typescript
67
- const rawType = params.subagent_type as SubagentType;
68
- const resolved = registry.resolveType(rawType);
69
- const subagentType = resolved ?? "general-purpose";
70
- const fellBack = resolved === undefined;
71
- ```
72
-
73
- - `src/tools/helpers.ts` — `buildTypeListText(registry, agentDir)` and the `TypeListRegistry` interface (extends `AgentConfigLookup`, so `resolveAgentConfig` is already available on it).
74
- - `src/tools/agent-tool.ts` — `AgentTool.execute` already short-circuits on a config error: `if ("error" in config) return textResult(config.error);`.
75
- So returning `SpawnConfigError` from `resolveSpawnConfig` is sufficient to surface the message to the model with no further wiring.
76
-
77
- AGENTS.md / package constraints that apply:
78
-
79
- - Pi-subagents is a minimal core with no policy enforcement.
80
- This fix is **not** policy — it enforces the agent's own `enabled` flag, which is part of the registry's documented contract, not a cross-cutting tool/skill restriction (those live in `@gotgenes/pi-permission-system`).
81
- - Biome handles formatting; no Prettier.
82
-
83
- ## Design Overview
84
-
85
- Two localized, independent changes.
86
- Neither introduces a new collaborator, widens a dependency bag, or changes layer wiring, so the design-review structural checklist finds nothing to flag.
87
-
88
- ### 1. Spawn-path gate (explicit error for disabled types)
89
-
90
- In `resolveSpawnConfig`, after resolving the canonical key, gate on `enabled` before falling back.
91
- The check reuses the registry's existing `isValidType`, which already encodes "exists and enabled":
92
-
93
- ```typescript
94
- const rawType = params.subagent_type as SubagentType;
95
- const resolved = registry.resolveType(rawType);
96
-
97
- // A known-but-disabled type is an explicit error, not a silent fallback.
98
- if (resolved !== undefined && !registry.isValidType(resolved)) {
99
- return { error: `Agent type "${resolved}" is disabled` };
100
- }
101
-
102
- const subagentType = resolved ?? "general-purpose";
103
- const fellBack = resolved === undefined;
104
- ```
105
-
106
- Decision model:
107
-
108
- | `subagent_type` input | `resolveType` | `isValidType(resolved)` | Outcome |
109
- | ------------------------- | ------------- | ----------------------- | -------------------------------------------------------------- |
110
- | enabled agent (`Explore`) | `"Explore"` | `true` | resolves, spawns (unchanged) |
111
- | disabled agent (`Plan`) | `"Plan"` | `false` | error: `Agent type "Plan" is disabled` |
112
- | unknown (`foo`) | `undefined` | not reached | falls back to `general-purpose`, `fellBack = true` (unchanged) |
113
-
114
- `isValidType(resolved)` re-runs `resolveKey` on an already-canonical key — a negligible, correct lookup.
115
- Because the gate runs first, `resolveAgentConfig(subagentType)` downstream is only ever reached for enabled or unknown types, so its disabled-config behavior (kept for the UI) is never exercised on the spawn path.
116
-
117
- This keeps the gate at the spawn boundary and leaves `resolveType` and `resolveAgentConfig` untouched, preserving every UI consumer that relies on resolving disabled agents.
118
-
119
- ### 2. Tool-description list filter
120
-
121
- In `buildTypeListText`, filter both name lists by `enabled` before rendering.
122
- `resolveAgentConfig(name)` returns the disabled config (with `enabled === false`) for a disabled name, so the predicate is straightforward:
123
-
124
- ```typescript
125
- const isEnabled = (name: string) => registry.resolveAgentConfig(name).enabled !== false;
126
- const defaultNames = registry.getDefaultAgentNames().filter(isEnabled);
127
- const userNames = registry.getUserAgentNames().filter(isEnabled);
128
- ```
129
-
130
- This localizes the fix to the one consumer that needs it, preserves the `getDefaultAgentNames` / `getUserAgentNames` method semantics (they still answer "which names are default / user"), and makes the tool description consistent with the `subagent_type` available-types line (both now exclude disabled agents).
131
-
132
- `TypeListRegistry` already extends `AgentConfigLookup`, so `resolveAgentConfig` is in scope; no interface change.
133
-
134
- ## Module-Level Changes
135
-
136
- - `src/tools/spawn-config.ts` — add the disabled-type gate in `resolveSpawnConfig` (3 lines) before the `subagentType` / `fellBack` assignment.
137
- No signature or return-type change (`SpawnConfigError` already supported).
138
- - `src/tools/helpers.ts` — add the `isEnabled` predicate and `.filter(isEnabled)` to the two name lists in `buildTypeListText`.
139
- No signature or interface change.
140
- - `src/config/agent-types.ts` — no code change.
141
- The inline comment "Disabled agents are kept but excluded from spawning" becomes accurate without edit; the `resolveType` JSDoc already says "Returns the canonical key or undefined" (unchanged behavior).
142
-
143
- No architecture-doc, ADR, or SKILL changes:
144
-
145
- - `grep -rn "448" docs/` and the architecture roadmap show no reference to this issue → no roadmap/health-table update.
146
- - No file is added, removed, or moved → no layout-listing update.
147
- - The `package-pi-subagents` SKILL describes domains and phases, not the `resolveType`/`isValidType` mechanics, so the reworded-prose grep (`enabled`, `resolveType`, `spawning`) surfaces nothing that this fix invalidates.
148
- - README is already consistent (see Non-Goals); no edit.
149
-
150
- ## Test Impact Analysis
151
-
152
- This is a small behavior fix, not an extraction, so no existing tests become redundant.
153
-
154
- 1. **New tests enabled** — both target surfaces are pure and already directly tested:
155
- - `resolveSpawnConfig` disabled-type error path (`test/tools/spawn-config.test.ts`).
156
- - `buildTypeListText` disabled-exclusion path (`test/tools/helpers.test.ts`).
157
- 2. **Redundant tests** — none.
158
- The existing `agent-types.test.ts` case "returns config for disabled type (no fallback for existing disabled)" stays as-is: it pins `resolveAgentConfig`'s disabled behavior, which the UI depends on and this fix deliberately does not change.
159
- 3. **Tests that must stay** — `agent-types.test.ts` `isValidType` "returns false for disabled agents" and `getAvailableTypes` "excludes disabled agents" already pin the registry primitives the gate reuses; keep them.
160
-
161
- ## Invariants at risk
162
-
163
- This change touches the spawn-resolution and tool-description surfaces but does not regress any prior phase's documented outcome:
164
-
165
- - `resolveAgentConfig` disabled-config behavior is pinned by `test/config/agent-types.test.ts` → "returns config for disabled type (no fallback for existing disabled)".
166
- The plan leaves `resolveAgentConfig` unchanged; this test must stay green.
167
- - The unknown-type fallback is pinned by `test/tools/spawn-config.test.ts` → "falls back to general-purpose for unknown agent type".
168
- The gate runs only for `resolved !== undefined`, so the unknown path is untouched; this test must stay green.
169
- - The UI's disabled-agent listing (`getAllTypes`) is pinned by `test/config/agent-types.test.ts` → `getAllTypes` "includes disabled agents"; unaffected.
170
-
171
- ## TDD Order
172
-
173
- 1. **Red→Green: spawn-path disabled error.**
174
- Test surface: `test/tools/spawn-config.test.ts`, `resolveSpawnConfig — type resolution` describe block.
175
- Add two cases: (a) a registry with a disabled `Plan` override returns `{ error: 'Agent type "Plan" is disabled' }` for `subagent_type: "Plan"`; (b) case-insensitive input `subagent_type: "plan"` reports the canonical `"Plan"` in the message.
176
- Build the registry with `new AgentTypeRegistry(() => new Map([["Plan", makeAgentConfig({ name: "Plan", enabled: false })]]))` (mirror the `agent-types.test.ts` fixture shape).
177
- Then add the gate to `resolveSpawnConfig`.
178
- Verify the existing "falls back to general-purpose for unknown agent type" and "resolves a known agent type" cases stay green (unknown/enabled paths unchanged).
179
- Commit: `fix(pi-subagents): return an error when spawning a disabled agent type (#448)`.
180
-
181
- 2. **Red→Green: tool-description excludes disabled agents.**
182
- Test surface: `test/tools/helpers.test.ts`, `buildTypeListText` describe block.
183
- Add a case: a registry whose `defaults`/`users` include a name resolving to `{ enabled: false }` omits that name from the rendered list (assert `.not.toContain`).
184
- Extend the `makeRegistry` stub's `resolve` to return `enabled` (the stub currently returns only `description`/`model`; add `enabled` so the predicate can read it).
185
- Then add the `isEnabled` filter to `buildTypeListText`.
186
- Verify the existing "lists default agents", "adds Custom agents section", and "omits Custom agents section" cases stay green (their stubs resolve to enabled configs by default).
187
- Commit: `fix(pi-subagents): exclude disabled agents from the subagent tool description (#448)`.
188
-
189
- 3. **Verify: full check + suite.**
190
- Run `pnpm --filter @gotgenes/pi-subagents run check`, `pnpm --filter @gotgenes/pi-subagents run lint`, `pnpm --filter @gotgenes/pi-subagents run test`, and `pnpm fallow dead-code`.
191
- No new commit unless a fix is needed.
192
-
193
- ## Risks and Mitigations
194
-
195
- - **Risk:** changing `resolveType` directly would break UI consumers (`agent-config-editor.ts`, `agent-menu.ts`) that intentionally resolve disabled agents.
196
- **Mitigation:** the gate lives in `resolveSpawnConfig`, not in `resolveType`; `resolveType` and `resolveAgentConfig` are unchanged.
197
- - **Risk:** an operator currently relying on the buggy behavior (explicitly spawning a disabled agent) gets an error after upgrade.
198
- **Mitigation:** this is the documented, intended contract; the error message is explicit and actionable ("…is disabled"), and the operator can re-enable via the `/agents` menu or by removing `enabled: false`.
199
- - **Risk:** the `buildTypeListText` filter could accidentally hide enabled agents if `resolveAgentConfig` returned a wrong config.
200
- **Mitigation:** `resolveAgentConfig(name)` for a name already in the registry returns that exact config; the predicate only excludes `enabled === false`.
201
- Existing `buildTypeListText` tests (which resolve to enabled configs) guard against over-filtering.
202
-
203
- ## Open Questions
204
-
205
- - Should the README's `## For Extension Authors` or the agent-config table gain a one-line note that an explicit `subagent_type` for a disabled agent now errors?
206
- Deferred — the README already states `enabled: false` disables the agent; the error message is self-explanatory.
207
- Revisit only if a user asks why the spawn errored.