@gotgenes/pi-subagents 18.0.0 → 18.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +22 -31
- 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/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/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 -45
- package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
- 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/src/observation/notification-state.ts +0 -27
- package/vitest.config.ts +0 -14
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 72
|
|
3
|
-
issue_title: "refactor: dependency-inject AgentManager's collaborators"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Dependency-inject AgentManager's collaborators
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
`AgentManager` directly imports and calls `runAgent`, `resumeAgent`, `createWorktree`, `cleanupWorktree`, and `pruneWorktrees`.
|
|
11
|
-
Any test of `AgentManager` must mock entire modules via `vi.mock()`, coupling the test to the internal structure of `agent-runner.ts` and `worktree.ts` rather than to `AgentManager`'s own behavior.
|
|
12
|
-
|
|
13
|
-
## Goals
|
|
14
|
-
|
|
15
|
-
- Define an `AgentRunner` interface (execution boundary) and a `WorktreeManager` interface (real object with state) for the operations `AgentManager` actually needs.
|
|
16
|
-
- Inject both into `AgentManager` via a constructor options bag, replacing the current 6-positional-parameter constructor.
|
|
17
|
-
- Remove all runtime imports of `agent-runner.ts` and `worktree.ts` from `agent-manager.ts`.
|
|
18
|
-
- Migrate `agent-manager.test.ts` from `vi.mock()` module stubs to `vi.fn()` interface stubs.
|
|
19
|
-
- No behavior change.
|
|
20
|
-
|
|
21
|
-
## Non-Goals
|
|
22
|
-
|
|
23
|
-
- Changing `AgentManager`'s public method surface (`spawn`, `spawnAndWait`, `resume`, `abort`, etc.).
|
|
24
|
-
- Refactoring `agent-runner.ts` internals (done in #71).
|
|
25
|
-
- Capturing `pi: ExtensionAPI` inside the runner — `pi` stays per-call in `SpawnArgs` for now.
|
|
26
|
-
- Extracting the notification system or widget (done in #54).
|
|
27
|
-
|
|
28
|
-
## Background
|
|
29
|
-
|
|
30
|
-
### Prerequisites
|
|
31
|
-
|
|
32
|
-
| Issue | Title | Status |
|
|
33
|
-
| ----- | --------------------------------------------------- | ------- |
|
|
34
|
-
| #69 | Create `SubagentRuntime` | ✓ Done |
|
|
35
|
-
| #71 | Extract pure agent-session assembler | ✓ Done |
|
|
36
|
-
| #76 | Inject `cwd` into `AgentManager` | ✓ Done |
|
|
37
|
-
| #80 | Consolidate `getConfig`/`getAgentConfig` | ✓ Done |
|
|
38
|
-
| #84 | Extract `GitWorktreeManager` class from worktree.ts | ✓ Done |
|
|
39
|
-
|
|
40
|
-
### Prior art
|
|
41
|
-
|
|
42
|
-
`pi-permission-system` `PermissionManager` takes a `PolicyLoader` via constructor injection.
|
|
43
|
-
The interface is defined in `policy-loader.ts` alongside the default `FilePolicyLoader` implementation.
|
|
44
|
-
`PermissionManager` imports the interface type-only — no runtime coupling to the loader module.
|
|
45
|
-
|
|
46
|
-
### Current imports in `agent-manager.ts`
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
import { resumeAgent, runAgent, type ToolActivity } from "./agent-runner.js"; // runtime + type
|
|
50
|
-
import { addUsage } from "./usage.js"; // runtime (pure utility, stays)
|
|
51
|
-
import { cleanupWorktree, createWorktree, pruneWorktrees } from "./worktree.js"; // runtime
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
After this refactor:
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
import type { AgentRunner } from "./agent-runner.js"; // type-only (erased at compile)
|
|
58
|
-
import type { WorktreeManager } from "./worktree.js"; // type-only (erased at compile)
|
|
59
|
-
import { addUsage } from "./usage.js"; // runtime (pure utility, stays)
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Relevant constraints from AGENTS.md
|
|
63
|
-
|
|
64
|
-
- Keep modules focused and composable (one concern per file).
|
|
65
|
-
- Prefer explicit configuration over hidden behavior.
|
|
66
|
-
- When a shared interface references a collaborator, use a narrow interface type — not the concrete class.
|
|
67
|
-
|
|
68
|
-
## Design Overview
|
|
69
|
-
|
|
70
|
-
### Two collaborators, different natures
|
|
71
|
-
|
|
72
|
-
#### WorktreeManager — real object with state
|
|
73
|
-
|
|
74
|
-
The three worktree functions all operate on git worktrees relative to a repository root.
|
|
75
|
-
Today `cwd` is threaded to each call — `createWorktree(ctx.cwd, id)`, `cleanupWorktree(ctx.cwd, wt, desc)`, `pruneWorktrees(this.cwd)`.
|
|
76
|
-
In practice `ctx.cwd` and `this.cwd` are always the same value (the process working directory set at extension init).
|
|
77
|
-
|
|
78
|
-
A `WorktreeManager` class captures `cwd` at construction, eliminating the per-call threading:
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
// In worktree.ts
|
|
82
|
-
export interface WorktreeManager {
|
|
83
|
-
create(id: string): WorktreeInfo | undefined;
|
|
84
|
-
cleanup(wt: WorktreeInfo, description: string): WorktreeCleanupResult;
|
|
85
|
-
prune(): void;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export class GitWorktreeManager implements WorktreeManager {
|
|
89
|
-
constructor(private readonly cwd: string) {}
|
|
90
|
-
create(id: string): WorktreeInfo | undefined { return createWorktree(this.cwd, id); }
|
|
91
|
-
cleanup(wt: WorktreeInfo, description: string): WorktreeCleanupResult { return cleanupWorktree(this.cwd, wt, description); }
|
|
92
|
-
prune(): void { pruneWorktrees(this.cwd); }
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
The existing free functions stay as the internal implementation and for any direct callers.
|
|
97
|
-
|
|
98
|
-
#### AgentRunner — execution boundary interface
|
|
99
|
-
|
|
100
|
-
`runAgent` and `resumeAgent` are stateless IO orchestrators.
|
|
101
|
-
They have no natural state to capture — `pi` is constant per extension but already flows through `SpawnArgs`.
|
|
102
|
-
The interface exists to decouple `AgentManager` (lifecycle management: queuing, concurrency, abort) from the execution engine (SDK sessions, prompt loops, event wiring):
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
// In agent-runner.ts
|
|
106
|
-
export interface AgentRunner {
|
|
107
|
-
run(ctx: ExtensionContext, type: SubagentType, prompt: string, options: RunOptions): Promise<RunResult>;
|
|
108
|
-
resume(session: AgentSession, prompt: string, options?: ResumeOptions): Promise<string>;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export interface ResumeOptions {
|
|
112
|
-
onToolActivity?: (activity: ToolActivity) => void;
|
|
113
|
-
onAssistantUsage?: (usage: { input: number; output: number; cacheWrite: number }) => void;
|
|
114
|
-
onCompaction?: (info: { reason: "manual" | "threshold" | "overflow"; tokensBefore: number }) => void;
|
|
115
|
-
signal?: AbortSignal;
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
The existing `{ run: runAgent, resume: resumeAgent }` structurally satisfies the interface — no wrapper class needed.
|
|
120
|
-
|
|
121
|
-
### Constructor options bag
|
|
122
|
-
|
|
123
|
-
The current 6-positional-parameter constructor becomes an options bag:
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
export interface AgentManagerOptions {
|
|
127
|
-
cwd: string;
|
|
128
|
-
runner: AgentRunner;
|
|
129
|
-
worktrees: WorktreeManager;
|
|
130
|
-
maxConcurrent?: number;
|
|
131
|
-
getRunConfig?: () => RunConfig;
|
|
132
|
-
onStart?: OnAgentStart;
|
|
133
|
-
onComplete?: OnAgentComplete;
|
|
134
|
-
onCompact?: OnAgentCompact;
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
All fields are used by `AgentManager` — no subset concern.
|
|
139
|
-
|
|
140
|
-
### Wiring in index.ts
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
import { runAgent, resumeAgent } from "./agent-runner.js";
|
|
144
|
-
import { GitWorktreeManager } from "./worktree.js";
|
|
145
|
-
|
|
146
|
-
const worktrees = new GitWorktreeManager(process.cwd());
|
|
147
|
-
const manager = new AgentManager({
|
|
148
|
-
cwd: process.cwd(),
|
|
149
|
-
runner: { run: runAgent, resume: resumeAgent },
|
|
150
|
-
worktrees,
|
|
151
|
-
onComplete: (record) => { /* ... */ },
|
|
152
|
-
onStart: (record) => { /* ... */ },
|
|
153
|
-
onCompact: (record, info) => { /* ... */ },
|
|
154
|
-
getRunConfig: () => ({ defaultMaxTurns: runtime.defaultMaxTurns, graceTurns: runtime.graceTurns }),
|
|
155
|
-
});
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### `cwd` on AgentManager after WorktreeManager captures it
|
|
159
|
-
|
|
160
|
-
`AgentManager.cwd` was previously used for two purposes:
|
|
161
|
-
|
|
162
|
-
1. Worktree operations (`createWorktree(ctx.cwd, ...)`, `pruneWorktrees(this.cwd)`) — now handled by the injected `WorktreeManager`.
|
|
163
|
-
2. No other use remains inside `AgentManager` itself.
|
|
164
|
-
|
|
165
|
-
However, `cwd` is still passed as part of `AgentManagerOptions` because `dispose()` calls `this.worktrees.prune()` — the `WorktreeManager` now owns the `cwd` for that call.
|
|
166
|
-
The `cwd` field on `AgentManagerOptions` can be dropped if no other internal use remains after the refactor.
|
|
167
|
-
A grep in step 8 will confirm whether `this.cwd` has any remaining readers; if not, it is removed.
|
|
168
|
-
|
|
169
|
-
### Test pattern after DI
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
function createManager(overrides?: Partial<AgentManagerOptions>) {
|
|
173
|
-
const runner: AgentRunner = {
|
|
174
|
-
run: vi.fn().mockResolvedValue({
|
|
175
|
-
responseText: "done", session: { dispose: vi.fn() }, aborted: false, steered: false,
|
|
176
|
-
}),
|
|
177
|
-
resume: vi.fn().mockResolvedValue("resumed"),
|
|
178
|
-
};
|
|
179
|
-
const worktrees: WorktreeManager = {
|
|
180
|
-
create: vi.fn(),
|
|
181
|
-
cleanup: vi.fn(() => ({ hasChanges: false })),
|
|
182
|
-
prune: vi.fn(),
|
|
183
|
-
};
|
|
184
|
-
return {
|
|
185
|
-
manager: new AgentManager({ cwd: "/test-cwd", runner, worktrees, ...overrides }),
|
|
186
|
-
runner,
|
|
187
|
-
worktrees,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
Tests access the mock stubs directly — no `vi.mocked(runAgent)` needed:
|
|
193
|
-
|
|
194
|
-
```typescript
|
|
195
|
-
const { manager, runner } = createManager({ onComplete: (r) => { /* ... */ } });
|
|
196
|
-
manager.spawn(mockPi, mockCtx, "general-purpose", "test", { description: "test", isBackground: true });
|
|
197
|
-
expect(runner.run).toHaveBeenCalled();
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Module-Level Changes
|
|
201
|
-
|
|
202
|
-
### `src/worktree.ts` (no changes in this issue)
|
|
203
|
-
|
|
204
|
-
`WorktreeManager` interface and `GitWorktreeManager` class were added by #84.
|
|
205
|
-
|
|
206
|
-
### `src/agent-runner.ts` (modified)
|
|
207
|
-
|
|
208
|
-
- Add `AgentRunner` interface (2 methods: `run`, `resume`).
|
|
209
|
-
- Extract `ResumeOptions` as a named type from the inline parameter type in `resumeAgent`.
|
|
210
|
-
- Export both.
|
|
211
|
-
- No changes to `runAgent()` or `resumeAgent()` implementations.
|
|
212
|
-
|
|
213
|
-
### `src/agent-manager.ts` (modified)
|
|
214
|
-
|
|
215
|
-
- Add `AgentManagerOptions` interface.
|
|
216
|
-
- Replace 6-positional-parameter constructor with single `options: AgentManagerOptions` parameter.
|
|
217
|
-
- Replace `runAgent(ctx, ...)` with `this.runner.run(ctx, ...)`.
|
|
218
|
-
- Replace `resumeAgent(session, ...)` with `this.runner.resume(session, ...)`.
|
|
219
|
-
- Replace `createWorktree(ctx.cwd, id)` with `this.worktrees.create(id)`.
|
|
220
|
-
- Replace `cleanupWorktree(ctx.cwd, wt, desc)` with `this.worktrees.cleanup(wt, desc)`.
|
|
221
|
-
- Replace `pruneWorktrees(this.cwd)` with `this.worktrees.prune()`.
|
|
222
|
-
- Remove runtime imports from `agent-runner.ts` and `worktree.ts`; keep `import type` only.
|
|
223
|
-
- Remove `this.cwd` if grep confirms no remaining readers after the worktree delegation.
|
|
224
|
-
|
|
225
|
-
### `src/index.ts` (modified)
|
|
226
|
-
|
|
227
|
-
- Import `GitWorktreeManager` from `worktree.ts`.
|
|
228
|
-
- Construct `new GitWorktreeManager(process.cwd())`.
|
|
229
|
-
- Pass options bag to `new AgentManager({ ... })`.
|
|
230
|
-
|
|
231
|
-
### `test/agent-manager.test.ts` (modified)
|
|
232
|
-
|
|
233
|
-
- Remove `vi.mock("../src/agent-runner.js", ...)` block.
|
|
234
|
-
- Remove `vi.mock("../src/worktree.js", ...)` block.
|
|
235
|
-
- Remove `import { runAgent } from "../src/agent-runner.js"` and `import { pruneWorktrees } from "../src/worktree.js"`.
|
|
236
|
-
- Add `createManager()` test helper factory.
|
|
237
|
-
- Replace all 19 `new AgentManager(...)` calls with `createManager(...)`.
|
|
238
|
-
- Update assertions from `vi.mocked(runAgent)` to `runner.run` / `runner.resume`.
|
|
239
|
-
- Update assertions from `vi.mocked(pruneWorktrees)` to `worktrees.prune`.
|
|
240
|
-
- Update assertions from `vi.mocked(createWorktree)` to `worktrees.create`.
|
|
241
|
-
|
|
242
|
-
## Test Impact Analysis
|
|
243
|
-
|
|
244
|
-
### New unit tests enabled by DI
|
|
245
|
-
|
|
246
|
-
1. Queueing behavior — verify that excess background agents are queued and started in order when running agents complete, without needing module-level mocks.
|
|
247
|
-
2. Concurrency limit enforcement — verify `maxConcurrent` is respected with controlled stub resolution.
|
|
248
|
-
3. Abort semantics — verify that aborting a queued agent removes it from the queue and sets status, using stubs that never resolve.
|
|
249
|
-
4. Lifecycle callback ordering — verify `onStart`, `onComplete`, `onCompact` fire at the right moments with correct record state.
|
|
250
|
-
5. Worktree failure modes — verify that `create` returning `undefined` throws and leaves no orphan record, via a simple `vi.fn().mockReturnValue(undefined)`.
|
|
251
|
-
|
|
252
|
-
### Existing tests that are migrated (not removed)
|
|
253
|
-
|
|
254
|
-
All 19 test sites in `agent-manager.test.ts` are migrated from `vi.mock()` + `vi.mocked()` to the `createManager()` helper with injected stubs.
|
|
255
|
-
The test logic stays identical — only the mock setup mechanism changes.
|
|
256
|
-
|
|
257
|
-
### Existing tests that stay as-is
|
|
258
|
-
|
|
259
|
-
Tests in `agent-runner.test.ts`, `agent-runner-extension-tools.test.ts`, `agent-runner-settings.test.ts`, and `session-config.test.ts` are unaffected — they test the execution engine, not the lifecycle manager.
|
|
260
|
-
|
|
261
|
-
## TDD Order
|
|
262
|
-
|
|
263
|
-
Issue #84 (extract `GitWorktreeManager`) must land first.
|
|
264
|
-
This plan assumes `WorktreeManager` interface and `GitWorktreeManager` class already exist in `worktree.ts`.
|
|
265
|
-
|
|
266
|
-
### Phase A: Define AgentRunner interface
|
|
267
|
-
|
|
268
|
-
1. Add `AgentRunner` interface and named `ResumeOptions` type in `agent-runner.ts`.
|
|
269
|
-
Export both.
|
|
270
|
-
Run existing tests.
|
|
271
|
-
Commit: `feat: define AgentRunner interface in agent-runner.ts`
|
|
272
|
-
|
|
273
|
-
### Phase B: Lift-and-shift test migration
|
|
274
|
-
|
|
275
|
-
2. Create `createManager()` test helper factory in `agent-manager.test.ts`.
|
|
276
|
-
The factory constructs `AgentManager` using the **old** positional constructor, wrapping the same `vi.mock()` stubs in a consistent helper.
|
|
277
|
-
Migrate all 19 `new AgentManager(...)` call sites to use the factory.
|
|
278
|
-
All tests pass unchanged.
|
|
279
|
-
Commit: `test: add createManager helper and migrate call sites`
|
|
280
|
-
|
|
281
|
-
### Phase C: Constructor conversion + DI
|
|
282
|
-
|
|
283
|
-
3. RED: Add a test that calls `createManager()` with `runner` and `worktrees` overrides and asserts `runner.run` is called when spawning an agent.
|
|
284
|
-
This fails because the constructor does not accept the options bag yet.
|
|
285
|
-
Commit: `test: add agent-manager test with injected AgentRunner`
|
|
286
|
-
|
|
287
|
-
4. GREEN: Convert `AgentManager` constructor to accept `AgentManagerOptions`.
|
|
288
|
-
Replace internal calls to `runAgent`/`resumeAgent`/`createWorktree`/`cleanupWorktree`/`pruneWorktrees` with `this.runner.*`/`this.worktrees.*`.
|
|
289
|
-
Remove runtime imports from `agent-runner.ts` and `worktree.ts`.
|
|
290
|
-
Update `createManager()` factory to pass injected stubs via the options bag.
|
|
291
|
-
Remove `vi.mock()` blocks for `agent-runner.js` and `worktree.js`.
|
|
292
|
-
Update all test assertions that referenced `vi.mocked(runAgent)` etc. to reference the injected stubs.
|
|
293
|
-
All tests pass.
|
|
294
|
-
Commit: `feat: convert AgentManager to options-bag constructor with DI`
|
|
295
|
-
|
|
296
|
-
### Phase D: Wiring and verification
|
|
297
|
-
|
|
298
|
-
5. Wire `index.ts`: construct `GitWorktreeManager`, pass options bag to `AgentManager`.
|
|
299
|
-
Run full test suite.
|
|
300
|
-
Commit: `refactor: wire injected deps into AgentManager (#72)`
|
|
301
|
-
|
|
302
|
-
6. Add new tests enabled by DI: queueing order, concurrency enforcement, abort-from-queue, lifecycle callback timing.
|
|
303
|
-
Commit: `test: add DI-enabled agent-manager tests`
|
|
304
|
-
|
|
305
|
-
7. Verify acceptance criteria.
|
|
306
|
-
Grep `agent-manager.ts` for runtime imports from `agent-runner.ts` and `worktree.ts` (expect none).
|
|
307
|
-
Grep for `this.cwd` — if no readers remain, remove the field and the `cwd` option.
|
|
308
|
-
Run `pnpm run check` for type safety.
|
|
309
|
-
Commit: `refactor: finalize AgentManager DI (#72)`
|
|
310
|
-
|
|
311
|
-
## Risks and Mitigations
|
|
312
|
-
|
|
313
|
-
| Risk | Mitigation |
|
|
314
|
-
| ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
315
|
-
| `ctx.cwd` and `this.cwd` differ for worktree operations, causing `GitWorktreeManager` to use the wrong directory | In practice both are `process.cwd()` — verified by tracing `session_start` and constructor call sites. If a difference surfaces, `WorktreeManager` can accept `cwd` per-call as a fallback. |
|
|
316
|
-
| Migrating 19 test call sites introduces test regressions | Phase B (step 3) migrates under the old constructor first, proving the helper factory works before any behavioral change. Phase C (step 5) changes the constructor and stubs atomically. |
|
|
317
|
-
| `import type` from `agent-runner.ts`/`worktree.ts` is considered a "top-level import" by reviewers | `import type` is erased by TypeScript at compile time and creates zero runtime dependency. The compiled JS will have no import from these modules. This matches the `PolicyLoader` pattern in `pi-permission-system`. |
|
|
318
|
-
| New options bag breaks the `AgentManagerLike` interface in `service-adapter.ts` | `AgentManagerLike` references `AgentManager`'s public methods (`spawn`, `getRecord`, etc.), not its constructor. The constructor change is invisible to the adapter. |
|
|
319
|
-
| `addUsage` remains as a direct runtime import from `usage.ts` | Intentional — `addUsage` is a pure accumulator function with no IO. The issue targets `agent-runner.ts` and `worktree.ts` specifically. |
|
|
320
|
-
|
|
321
|
-
## Open Questions
|
|
322
|
-
|
|
323
|
-
- Should `AgentRunner` eventually capture `pi: ExtensionAPI` to eliminate the `pi` parameter from `spawn()` and `SpawnArgs`?
|
|
324
|
-
Deferred — `pi` is already threaded through the call chain and removing it would change `AgentManager`'s public method signatures, which is a non-goal.
|
|
325
|
-
- Does the `WorktreeManager` abstraction surface further opportunities (e.g., non-git isolation strategies)?
|
|
326
|
-
Noted for future consideration — the interface makes alternative implementations possible without changing `AgentManager`.
|
|
327
|
-
- The `AgentRunner` interface is a testability seam, not a stateful object.
|
|
328
|
-
As the codebase continues untangling, a more natural execution abstraction may emerge.
|
|
329
|
-
This interface is intentionally minimal to avoid premature abstraction.
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 76
|
|
3
|
-
issue_title: "refactor: inject cwd into AgentManager constructor instead of reading process.cwd() in dispose()"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Inject cwd into AgentManager constructor
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
`AgentManager.dispose()` calls `pruneWorktrees(process.cwd())` directly — the only place in the class that reads a process global instead of accepting `cwd` from the caller.
|
|
11
|
-
Every other code path that needs a working directory receives it via the per-spawn invocation context (`ctx.cwd`).
|
|
12
|
-
This implicit dependency makes the class harder to test and inconsistent with its own conventions.
|
|
13
|
-
|
|
14
|
-
## Goals
|
|
15
|
-
|
|
16
|
-
- Add `cwd: string` as the first parameter of the `AgentManager` constructor and store it as a private field.
|
|
17
|
-
- Replace `pruneWorktrees(process.cwd())` in `dispose()` with `pruneWorktrees(this.cwd)`.
|
|
18
|
-
- Update the single production call site in `index.ts` to pass `process.cwd()`.
|
|
19
|
-
- Update all 18 test-file constructor calls to pass a test directory string.
|
|
20
|
-
|
|
21
|
-
## Non-Goals
|
|
22
|
-
|
|
23
|
-
- Removing other `process.cwd()` calls elsewhere in the extension (e.g., `loadCustomAgents` in `index.ts`).
|
|
24
|
-
- Changing how per-spawn `ctx.cwd` flows through `agent-runner.ts`.
|
|
25
|
-
- Refactoring the constructor's callback-heavy signature into an options object (potential follow-up).
|
|
26
|
-
|
|
27
|
-
## Background
|
|
28
|
-
|
|
29
|
-
### Relevant modules
|
|
30
|
-
|
|
31
|
-
| Module | Role |
|
|
32
|
-
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
33
|
-
| `agent-manager.ts` | Owns `AgentManager` class; constructor at line 83, `dispose()` at line 479 with the `process.cwd()` call. |
|
|
34
|
-
| `index.ts` | Extension entry point; constructs `AgentManager` at line 64. Already calls `process.cwd()` at line 43 for `loadCustomAgents`. |
|
|
35
|
-
| `worktree.ts` | Exports `pruneWorktrees(cwd: string)` consumed by `dispose()`. |
|
|
36
|
-
| `service-adapter.ts` | Depends on `AgentManagerLike` interface, which does not expose the constructor — unaffected. |
|
|
37
|
-
|
|
38
|
-
### Constraints
|
|
39
|
-
|
|
40
|
-
From AGENTS.md / code-style skill:
|
|
41
|
-
|
|
42
|
-
> Do not read `process.env`, `process.cwd()`, or `process.platform` inside library/utility functions — accept the value as a parameter.
|
|
43
|
-
|
|
44
|
-
This refactoring directly enforces that rule.
|
|
45
|
-
|
|
46
|
-
`AgentManager` is internal — the public API surface (`exports` in `package.json`) is `service.ts` only, so this is a non-breaking change for consumers.
|
|
47
|
-
|
|
48
|
-
## Design Overview
|
|
49
|
-
|
|
50
|
-
The change is mechanical:
|
|
51
|
-
|
|
52
|
-
1. Prepend `cwd: string` to the constructor parameter list.
|
|
53
|
-
2. Store it as `private readonly cwd: string`.
|
|
54
|
-
3. Replace `process.cwd()` in `dispose()` with `this.cwd`.
|
|
55
|
-
4. At the call site in `index.ts`, pass `process.cwd()` as the first argument.
|
|
56
|
-
5. In tests, pass a fixed string like `"/test-cwd"` to every `new AgentManager(...)` call.
|
|
57
|
-
|
|
58
|
-
No new types, no interface changes, no export changes.
|
|
59
|
-
|
|
60
|
-
## Module-Level Changes
|
|
61
|
-
|
|
62
|
-
### `src/agent-manager.ts`
|
|
63
|
-
|
|
64
|
-
- Add `private readonly cwd: string` field.
|
|
65
|
-
- Constructor: add `cwd: string` as the first parameter, assign `this.cwd = cwd`.
|
|
66
|
-
- `dispose()`: change `pruneWorktrees(process.cwd())` → `pruneWorktrees(this.cwd)`.
|
|
67
|
-
- Remove the `process` global dependency (no more `process.cwd()` import needed in this file).
|
|
68
|
-
|
|
69
|
-
### `src/index.ts`
|
|
70
|
-
|
|
71
|
-
- Pass `process.cwd()` as the first argument to `new AgentManager(...)`.
|
|
72
|
-
|
|
73
|
-
### `test/agent-manager.test.ts`
|
|
74
|
-
|
|
75
|
-
- All 18 `new AgentManager(...)` calls gain `"/test-cwd"` as the first argument.
|
|
76
|
-
- No other test logic changes — `pruneWorktrees` is already mocked.
|
|
77
|
-
|
|
78
|
-
## Test Impact Analysis
|
|
79
|
-
|
|
80
|
-
1. No new unit tests are needed — the existing `dispose()` test already exercises `pruneWorktrees` via the mock; it will now verify the injected `cwd` is forwarded instead of the process global.
|
|
81
|
-
2. No existing tests become redundant.
|
|
82
|
-
3. All 18 constructor calls must be updated with the new first argument, but the test assertions remain valid.
|
|
83
|
-
|
|
84
|
-
## TDD Order
|
|
85
|
-
|
|
86
|
-
1. **Red → Green: update constructor and dispose** — change the `AgentManager` constructor to accept `cwd` as the first parameter, store it, and use `this.cwd` in `dispose()`.
|
|
87
|
-
Update all 18 test constructor calls to pass `"/test-cwd"`.
|
|
88
|
-
Update `index.ts` call site to pass `process.cwd()`.
|
|
89
|
-
Commit message: `refactor: inject cwd into AgentManager constructor (#76)`
|
|
90
|
-
|
|
91
|
-
This is a single-step refactoring — splitting it further would leave the codebase in a broken intermediate state since the constructor signature change must be applied atomically across production code and tests.
|
|
92
|
-
|
|
93
|
-
## Risks and Mitigations
|
|
94
|
-
|
|
95
|
-
| Risk | Mitigation |
|
|
96
|
-
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
97
|
-
| Missing a constructor call site | `grep 'new AgentManager'` across the entire repo confirms only `index.ts` (1 call) and `agent-manager.test.ts` (18 calls). |
|
|
98
|
-
| Accidentally changing behavior | `pruneWorktrees` is already mocked in tests; production call site passes `process.cwd()` which is the same value `dispose()` read before. |
|
|
99
|
-
|
|
100
|
-
## Open Questions
|
|
101
|
-
|
|
102
|
-
None — the issue's proposed change section is unambiguous and the refactoring is mechanical.
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 77
|
|
3
|
-
issue_title: "refactor: add projectAgentsDir to AgentMenuDeps instead of reading process.cwd() inline"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Inject projectAgentsDir into AgentMenuDeps
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
`createAgentsMenuHandler` computes the project agents directory by reading `process.cwd()` inline via a lambda on line 63 of `ui/agent-menu.ts`:
|
|
11
|
-
|
|
12
|
-
```typescript
|
|
13
|
-
const projectAgentsDir = () => join(process.cwd(), ".pi", "agents");
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
The `AgentMenuDeps` interface already carries `personalAgentsDir: string` as an explicit field, but the project-side equivalent bypasses the injection boundary entirely.
|
|
17
|
-
`projectAgentsDir()` is called in at least five places inside the handler (`findAgentFile`, `ejectAgent`, `disableAgent`, `showCreateWizard`, `showManualWizard`).
|
|
18
|
-
This violates the code-style rule: "Do not read `process.cwd()` inside library/utility functions — accept the value as a parameter."
|
|
19
|
-
|
|
20
|
-
## Goals
|
|
21
|
-
|
|
22
|
-
- Add `projectAgentsDir: string` to `AgentMenuDeps`.
|
|
23
|
-
- Remove the inline `projectAgentsDir` lambda from `createAgentsMenuHandler`.
|
|
24
|
-
- Replace all five call sites with `deps.projectAgentsDir`.
|
|
25
|
-
- Wire the value at the call site in `index.ts` as `join(process.cwd(), ".pi", "agents")`.
|
|
26
|
-
- Update the test helper `makeDeps()` in `agent-menu.test.ts` to supply the new field.
|
|
27
|
-
|
|
28
|
-
## Non-Goals
|
|
29
|
-
|
|
30
|
-
- Removing other `process.cwd()` calls in `index.ts` (e.g., `loadCustomAgents`, `GitWorktreeManager`).
|
|
31
|
-
Those are separate concerns tracked or already addressed elsewhere (e.g., #76 for `AgentManager`).
|
|
32
|
-
- Changing `personalAgentsDir` wiring or any other `AgentMenuDeps` fields.
|
|
33
|
-
|
|
34
|
-
## Background
|
|
35
|
-
|
|
36
|
-
### Relevant modules
|
|
37
|
-
|
|
38
|
-
| Module | Role |
|
|
39
|
-
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
40
|
-
| `src/ui/agent-menu.ts` | Contains `AgentMenuDeps` interface and `createAgentsMenuHandler` factory. Owns the inline `projectAgentsDir` lambda. |
|
|
41
|
-
| `src/index.ts` | Extension entry point. Constructs the `AgentMenuDeps` object at line 228. Already passes `personalAgentsDir`. |
|
|
42
|
-
| `test/ui/agent-menu.test.ts` | Tests for the menu handler. Has a `makeDeps()` helper that constructs `AgentMenuDeps`. |
|
|
43
|
-
|
|
44
|
-
### Constraints
|
|
45
|
-
|
|
46
|
-
From code-style skill:
|
|
47
|
-
|
|
48
|
-
> Do not read `process.env`, `process.cwd()`, or `process.platform` inside library/utility functions — accept the value as a parameter.
|
|
49
|
-
|
|
50
|
-
This is the same pattern applied in #76 (inject `cwd` into `AgentManager`), now applied to the UI layer.
|
|
51
|
-
|
|
52
|
-
`AgentMenuDeps` is internal — the public API surface (`exports` in `package.json`) is `service.ts` only, so this is a non-breaking change for consumers.
|
|
53
|
-
|
|
54
|
-
## Design Overview
|
|
55
|
-
|
|
56
|
-
The change is mechanical — add a field, remove a lambda, replace call sites:
|
|
57
|
-
|
|
58
|
-
1. Add `projectAgentsDir: string` to `AgentMenuDeps` (mirrors the existing `personalAgentsDir` field).
|
|
59
|
-
2. Delete the `const projectAgentsDir = () => join(process.cwd(), ".pi", "agents");` lambda inside `createAgentsMenuHandler`.
|
|
60
|
-
3. Replace all five `projectAgentsDir()` call sites with `deps.projectAgentsDir`:
|
|
61
|
-
- `findAgentFile` (line 68)
|
|
62
|
-
- `ejectAgent` (line 312)
|
|
63
|
-
- `disableAgent` (line 378)
|
|
64
|
-
- `showCreateWizard` (line 416)
|
|
65
|
-
- `showManualWizard` — uses the `targetDir` value from `showCreateWizard`, so not a direct call site
|
|
66
|
-
4. At the call site in `index.ts`, add `projectAgentsDir: join(process.cwd(), ".pi", "agents")` to the deps object.
|
|
67
|
-
5. In `makeDeps()`, add `projectAgentsDir: "/test-project/.pi/agents"`.
|
|
68
|
-
|
|
69
|
-
No new types, no interface changes beyond the one added field.
|
|
70
|
-
|
|
71
|
-
## Module-Level Changes
|
|
72
|
-
|
|
73
|
-
### `src/ui/agent-menu.ts`
|
|
74
|
-
|
|
75
|
-
- Add `projectAgentsDir: string` to the `AgentMenuDeps` interface.
|
|
76
|
-
- Remove the `const projectAgentsDir = () => join(process.cwd(), ".pi", "agents");` lambda.
|
|
77
|
-
- Replace `projectAgentsDir()` with `deps.projectAgentsDir` at all call sites inside the factory closure.
|
|
78
|
-
- The `join` import from `node:path` may become unused in this file if no other call uses it — verify and remove if so.
|
|
79
|
-
|
|
80
|
-
### `src/index.ts`
|
|
81
|
-
|
|
82
|
-
- Add `projectAgentsDir: join(process.cwd(), ".pi", "agents")` to the `createAgentsMenuHandler({...})` call.
|
|
83
|
-
- Import `join` from `node:path` if not already imported.
|
|
84
|
-
|
|
85
|
-
### `test/ui/agent-menu.test.ts`
|
|
86
|
-
|
|
87
|
-
- Add `projectAgentsDir: "/test-project/.pi/agents"` to `makeDeps()`.
|
|
88
|
-
- No other test logic changes.
|
|
89
|
-
|
|
90
|
-
## Test Impact Analysis
|
|
91
|
-
|
|
92
|
-
1. No new unit tests are strictly required — the refactoring is mechanical and preserves behavior.
|
|
93
|
-
However, a targeted test verifying that `findAgentFile` uses the injected `projectAgentsDir` (not `process.cwd()`) is valuable to prevent regression.
|
|
94
|
-
2. No existing tests become redundant.
|
|
95
|
-
3. All existing tests stay as-is; only the `makeDeps()` helper needs the new field.
|
|
96
|
-
|
|
97
|
-
## TDD Order
|
|
98
|
-
|
|
99
|
-
1. **Red: test that the injected projectAgentsDir is used** — add a test in `agent-menu.test.ts` that mocks `existsSync` and verifies `findAgentFile` (exercised via the menu handler) checks a path under the injected `projectAgentsDir`, not under `process.cwd()`.
|
|
100
|
-
Commit message: `test: verify projectAgentsDir injection in agent menu (#77)`
|
|
101
|
-
|
|
102
|
-
2. **Green: add projectAgentsDir to AgentMenuDeps and wire it** — add the field to `AgentMenuDeps`, remove the inline lambda, replace all call sites with `deps.projectAgentsDir`, wire the value in `index.ts`, and update `makeDeps()` in the test helper.
|
|
103
|
-
Commit message: `refactor: inject projectAgentsDir into AgentMenuDeps (#77)`
|
|
104
|
-
|
|
105
|
-
## Risks and Mitigations
|
|
106
|
-
|
|
107
|
-
| Risk | Mitigation |
|
|
108
|
-
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
109
|
-
| Missing a `projectAgentsDir()` call site | `grep 'projectAgentsDir'` in `agent-menu.ts` confirms exactly five call sites (one definition + four usages). After the change, grep again to verify no `process.cwd()` calls remain. |
|
|
110
|
-
| `join` import becomes unused in `agent-menu.ts` | Check whether `join` is used elsewhere in the file (it is — `findAgentFile` uses `join` for the personal path). The import stays. |
|
|
111
|
-
| Behavioral change | Production call site passes `join(process.cwd(), ".pi", "agents")`, which produces the same value the lambda computed. No behavioral change. |
|
|
112
|
-
|
|
113
|
-
## Open Questions
|
|
114
|
-
|
|
115
|
-
None — the issue's proposed change is unambiguous and mirrors the established `personalAgentsDir` pattern.
|