@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.
- package/CHANGELOG.md +7 -0
- package/docs/architecture/architecture.md +157 -204
- package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
- package/package.json +5 -6
- package/src/lifecycle/subagent.ts +5 -9
- package/src/observation/notification.ts +23 -10
- package/src/observation/subagent-events-observer.ts +1 -3
- package/src/tools/get-result-report.ts +60 -0
- package/src/tools/get-result-tool.ts +25 -40
- package/src/types.ts +1 -1
- package/src/ui/session-navigator.ts +0 -2
- package/.prettierignore +0 -5
- package/AGENTS.md +0 -7
- package/docs/plans/0048-implement-subagents-api.md +0 -304
- package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
- package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
- package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
- package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
- package/docs/plans/0054-decompose-index-into-modules.md +0 -302
- package/docs/plans/0057-structured-debug-logging.md +0 -154
- package/docs/plans/0061-session-format-transcript.md +0 -284
- package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
- package/docs/plans/0069-create-subagent-runtime.md +0 -345
- package/docs/plans/0070-extract-event-handlers.md +0 -306
- package/docs/plans/0071-extract-session-config-assembler.md +0 -362
- package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
- package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
- package/docs/plans/0077-inject-project-agents-dir.md +0 -115
- package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
- package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
- package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
- package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
- package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
- package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
- package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
- package/docs/plans/0108-extract-agent-type-registry.md +0 -322
- package/docs/plans/0109-extract-settings-manager.md +0 -276
- package/docs/plans/0110-agent-activity-tracker.md +0 -297
- package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
- package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
- package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
- package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
- package/docs/plans/0115-decompose-agent-tool.md +0 -337
- package/docs/plans/0116-type-housekeeping.md +0 -351
- package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
- package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
- package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
- package/docs/plans/0132-inject-io-into-session-config.md +0 -219
- package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
- package/docs/plans/0134-reduce-as-any-casts.md +0 -366
- package/docs/plans/0135-extract-display-helpers.md +0 -182
- package/docs/plans/0136-decompose-agent-menu.md +0 -300
- package/docs/plans/0144-consolidate-observation-model.md +0 -263
- package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
- package/docs/plans/0146-narrow-ui-context.md +0 -319
- package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
- package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
- package/docs/plans/0152-add-prompt-snippet.md +0 -91
- package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
- package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
- package/docs/plans/0166-extract-parent-session-info.md +0 -231
- package/docs/plans/0167-narrow-runner-io.md +0 -150
- package/docs/plans/0168-extract-tool-filter-config.md +0 -173
- package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
- package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
- package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
- package/docs/plans/0172-extract-turn-formatting.md +0 -206
- package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
- package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
- package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
- package/docs/plans/0192-define-session-context-interface.md +0 -107
- package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
- package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
- package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
- package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
- package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
- package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
- package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
- package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
- package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
- package/docs/plans/0215-decompose-build-parent-context.md +0 -166
- package/docs/plans/0216-decompose-start-agent.md +0 -255
- package/docs/plans/0217-extract-overwrite-guard.md +0 -176
- package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
- package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
- package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
- package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
- package/docs/plans/0229-agent-born-complete.md +0 -564
- package/docs/plans/0230-extract-concurrency-queue.md +0 -265
- package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
- package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
- package/docs/plans/0237-remove-disallowed-tools.md +0 -180
- package/docs/plans/0238-remove-extensions-filtering.md +0 -191
- package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
- package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
- package/docs/plans/0256-extract-worktree-isolation.md +0 -256
- package/docs/plans/0257-extract-child-session-factory.md +0 -285
- package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
- package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
- package/docs/plans/0265-born-complete-subagent-session.md +0 -333
- package/docs/plans/0270-type-consumable-public-surface.md +0 -204
- package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
- package/docs/plans/0277-encapsulate-agent-session.md +0 -304
- package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
- package/docs/plans/0360-custom-agents-default-append.md +0 -132
- package/docs/plans/0373-extract-subagent-state.md +0 -250
- package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
- package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
- package/docs/plans/0376-extract-manager-observer.md +0 -232
- package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
- package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
- package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
- package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
- package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
- package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
- package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
- package/docs/plans/0412-unify-session-mock-builders.md +0 -146
- package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
- package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
- package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
- package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
- package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
- package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
- package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
- package/docs/plans/0427-reconsider-ui-direction.md +0 -212
- package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
- package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
- package/docs/plans/0443-consolidate-remaining-test-clone-families.md +0 -268
- package/docs/plans/0444-shrink-widget-to-background-agents.md +0 -156
- package/docs/plans/0445-native-session-navigation.md +0 -365
- package/docs/plans/0446-spike-session-navigation-entry-criteria.md +0 -171
- package/docs/plans/0447-extract-subagents-settings-command.md +0 -220
- package/docs/plans/0448-block-disabled-agent-spawn.md +0 -207
- package/docs/plans/0462-navigation-renderer-tui-components.md +0 -338
- package/docs/plans/0463-file-snapshot-source-evicted-agents.md +0 -306
- package/docs/plans/0470-refresh-readme-command-surface.md +0 -159
- package/docs/retro/0048-implement-subagents-api.md +0 -44
- package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
- package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
- package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
- package/docs/retro/0054-decompose-index-into-modules.md +0 -53
- package/docs/retro/0057-structured-debug-logging.md +0 -77
- package/docs/retro/0061-session-format-transcript.md +0 -41
- package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
- package/docs/retro/0069-create-subagent-runtime.md +0 -43
- package/docs/retro/0070-extract-event-handlers.md +0 -49
- package/docs/retro/0071-extract-session-config-assembler.md +0 -60
- package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
- package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
- package/docs/retro/0077-inject-project-agents-dir.md +0 -33
- package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
- package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
- package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
- package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
- package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
- package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
- package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
- package/docs/retro/0108-extract-agent-type-registry.md +0 -41
- package/docs/retro/0109-extract-settings-manager.md +0 -55
- package/docs/retro/0110-agent-activity-tracker.md +0 -44
- package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
- package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
- package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
- package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
- package/docs/retro/0115-decompose-agent-tool.md +0 -51
- package/docs/retro/0116-type-housekeeping.md +0 -42
- package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
- package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
- package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
- package/docs/retro/0132-inject-io-into-session-config.md +0 -33
- package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
- package/docs/retro/0134-reduce-as-any-casts.md +0 -56
- package/docs/retro/0135-extract-display-helpers.md +0 -38
- package/docs/retro/0136-decompose-agent-menu.md +0 -43
- package/docs/retro/0144-consolidate-observation-model.md +0 -39
- package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
- package/docs/retro/0146-narrow-ui-context.md +0 -70
- package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
- package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
- package/docs/retro/0152-add-prompt-snippet.md +0 -34
- package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
- package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
- package/docs/retro/0166-extract-parent-session-info.md +0 -66
- package/docs/retro/0167-narrow-runner-io.md +0 -63
- package/docs/retro/0168-extract-tool-filter-config.md +0 -76
- package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
- package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
- package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
- package/docs/retro/0172-extract-turn-formatting.md +0 -80
- package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
- package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
- package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
- package/docs/retro/0192-define-session-context-interface.md +0 -59
- package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
- package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
- package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
- package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
- package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
- package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
- package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
- package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
- package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
- package/docs/retro/0215-decompose-build-parent-context.md +0 -61
- package/docs/retro/0216-decompose-start-agent.md +0 -80
- package/docs/retro/0217-extract-overwrite-guard.md +0 -63
- package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
- package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
- package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
- package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
- package/docs/retro/0229-agent-born-complete.md +0 -89
- package/docs/retro/0230-extract-concurrency-queue.md +0 -38
- package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
- package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
- package/docs/retro/0237-remove-disallowed-tools.md +0 -78
- package/docs/retro/0238-remove-extensions-filtering.md +0 -72
- package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
- package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
- package/docs/retro/0256-extract-worktree-isolation.md +0 -89
- package/docs/retro/0257-extract-child-session-factory.md +0 -33
- package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
- package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
- package/docs/retro/0265-born-complete-subagent-session.md +0 -97
- package/docs/retro/0270-type-consumable-public-surface.md +0 -108
- package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
- package/docs/retro/0277-encapsulate-agent-session.md +0 -80
- package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
- package/docs/retro/0360-custom-agents-default-append.md +0 -81
- package/docs/retro/0373-extract-subagent-state.md +0 -94
- package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
- package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
- package/docs/retro/0376-extract-manager-observer.md +0 -81
- package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
- package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
- package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
- package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
- package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
- package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
- package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
- package/docs/retro/0412-unify-session-mock-builders.md +0 -80
- package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
- package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
- package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
- package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
- package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
- package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
- package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
- package/docs/retro/0427-reconsider-ui-direction.md +0 -102
- package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -97
- package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
- package/docs/retro/0443-consolidate-remaining-test-clone-families.md +0 -28
- package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
- package/docs/retro/0445-native-session-navigation.md +0 -122
- package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
- package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
- package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
- package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
- package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
- package/docs/retro/0470-refresh-readme-command-surface.md +0 -40
- package/src/observation/notification-state.ts +0 -27
- 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.
|