@gotgenes/pi-subagents 18.0.1 → 18.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/docs/architecture/architecture.md +165 -203
- package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
- package/package.json +6 -7
- package/src/config/default-agents.ts +3 -0
- package/src/lifecycle/subagent.ts +25 -14
- package/src/observation/notification.ts +23 -10
- package/src/observation/subagent-events-observer.ts +1 -3
- package/src/runtime.ts +2 -1
- package/src/service/service-adapter.ts +20 -17
- package/src/session/model-resolver.ts +31 -30
- package/src/tools/agent-tool.ts +17 -13
- package/src/tools/get-result-report.ts +60 -0
- package/src/tools/get-result-tool.ts +25 -40
- package/src/tools/helpers.ts +21 -5
- package/src/tools/spawn-config.ts +5 -5
- package/src/tools/steer-tool.ts +37 -27
- package/src/types.ts +4 -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,172 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 218
|
|
3
|
-
issue_title: "Push SDK boundary in settings.ts (Phase 13, Step 5)"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Push SDK boundary in settings.ts
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
`settings.ts` imports `getAgentDir` from the Pi SDK (`@earendil-works/pi-coding-agent`) and calls it inside `globalPath()` at invocation time.
|
|
11
|
-
This hides a platform dependency inside a module that is otherwise pure configuration logic — violating the project's SDK-boundary rule that pure helpers and domain modules should remain SDK-independent.
|
|
12
|
-
The SDK call also forces tests to redirect the env var `PI_CODING_AGENT_DIR` to control `getAgentDir()` output, rather than passing the value directly.
|
|
13
|
-
|
|
14
|
-
## Goals
|
|
15
|
-
|
|
16
|
-
- Remove the `getAgentDir` import from `settings.ts` (0 Pi SDK imports).
|
|
17
|
-
- Inject `agentDir: string` into `SettingsManager` constructor deps.
|
|
18
|
-
- Make `loadSettings` accept `agentDir` as an explicit parameter.
|
|
19
|
-
- Eliminate `PI_CODING_AGENT_DIR` env var manipulation from all settings tests.
|
|
20
|
-
|
|
21
|
-
## Non-Goals
|
|
22
|
-
|
|
23
|
-
- Removing `process.cwd()` defaults from `loadSettings`/`saveSettings` — that's a separate concern (Node.js API, not Pi SDK).
|
|
24
|
-
- Pushing SDK boundaries in other files (`skill-loader.ts`, `custom-agents.ts`, `agent-runner.ts`) — tracked separately in the Phase 13 roadmap.
|
|
25
|
-
- Changing the `saveSettings` signature — it only calls `projectPath(cwd)` and has no SDK dependency.
|
|
26
|
-
|
|
27
|
-
## Background
|
|
28
|
-
|
|
29
|
-
`settings.ts` exports a `SettingsManager` class and two free functions (`loadSettings`, `saveSettings`).
|
|
30
|
-
The only SDK import is `getAgentDir`, used in the private `globalPath()` helper to compute the global settings file path (`~/.pi/agent/subagents.json`).
|
|
31
|
-
|
|
32
|
-
The `SettingsManager` constructor already accepts a deps bag `{ emit, cwd, onMaxConcurrentChanged? }`.
|
|
33
|
-
Adding `agentDir` to this bag follows the established injection pattern.
|
|
34
|
-
|
|
35
|
-
In `index.ts`, `getAgentDir` is already imported for several other call sites (agent runner IO, agent tool, `/agents` menu).
|
|
36
|
-
Adding one more usage to the `SettingsManager` construction is zero new imports.
|
|
37
|
-
|
|
38
|
-
### Relevant AGENTS.md constraints
|
|
39
|
-
|
|
40
|
-
- **Pi SDK boundaries:** Keep Pi SDK imports out of business-logic modules; accept the value as a parameter or callback.
|
|
41
|
-
- **Code-design skill, DIP:** Default to dependency injection for non-trivial dependencies.
|
|
42
|
-
|
|
43
|
-
## Design Overview
|
|
44
|
-
|
|
45
|
-
### Change to `globalPath()`
|
|
46
|
-
|
|
47
|
-
Currently:
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
function globalPath(): string {
|
|
51
|
-
return join(getAgentDir(), "subagents.json");
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
After:
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
function globalPath(agentDir: string): string {
|
|
59
|
-
return join(agentDir, "subagents.json");
|
|
60
|
-
}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Change to `loadSettings()`
|
|
64
|
-
|
|
65
|
-
Currently:
|
|
66
|
-
|
|
67
|
-
```typescript
|
|
68
|
-
export function loadSettings(cwd: string = process.cwd()): SubagentsSettings {
|
|
69
|
-
return { ...readSettingsFile(globalPath()), ...readSettingsFile(projectPath(cwd)) };
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
After:
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
export function loadSettings(agentDir: string, cwd: string = process.cwd()): SubagentsSettings {
|
|
77
|
-
return { ...readSettingsFile(globalPath(agentDir)), ...readSettingsFile(projectPath(cwd)) };
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Change to `SettingsManager` constructor
|
|
82
|
-
|
|
83
|
-
Add `agentDir: string` to the deps bag:
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
constructor(deps: { emit: SettingsEmit; cwd: string; agentDir: string; onMaxConcurrentChanged?: () => void }) {
|
|
87
|
-
this.emit = deps.emit;
|
|
88
|
-
this.cwd = deps.cwd;
|
|
89
|
-
this.agentDir = deps.agentDir;
|
|
90
|
-
this.onMaxConcurrentChanged = deps.onMaxConcurrentChanged;
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
`SettingsManager.load()` passes `this.agentDir` to `loadSettings`:
|
|
95
|
-
|
|
96
|
-
```typescript
|
|
97
|
-
load(): SubagentsSettings {
|
|
98
|
-
const settings = loadSettings(this.agentDir, this.cwd);
|
|
99
|
-
// ... rest unchanged
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Wiring in `index.ts`
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
const settings = new SettingsManager({
|
|
107
|
-
emit: (event, payload) => pi.events.emit(event, payload),
|
|
108
|
-
cwd: process.cwd(),
|
|
109
|
-
agentDir: getAgentDir(),
|
|
110
|
-
onMaxConcurrentChanged: () => manager.notifyConcurrencyChanged(),
|
|
111
|
-
});
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Module-Level Changes
|
|
115
|
-
|
|
116
|
-
### `src/settings.ts`
|
|
117
|
-
|
|
118
|
-
1. Remove `import { getAgentDir } from "@earendil-works/pi-coding-agent"`.
|
|
119
|
-
2. Add `agentDir: string` field to the `SettingsManager` constructor deps interface.
|
|
120
|
-
3. Store `this.agentDir = deps.agentDir` as a private readonly field.
|
|
121
|
-
4. Change `globalPath()` signature to `globalPath(agentDir: string)`.
|
|
122
|
-
5. Change `loadSettings` signature to `loadSettings(agentDir: string, cwd?: string)`.
|
|
123
|
-
6. Update `SettingsManager.load()` to call `loadSettings(this.agentDir, this.cwd)`.
|
|
124
|
-
7. Update the header comment to reflect the new injection pattern.
|
|
125
|
-
|
|
126
|
-
### `src/index.ts`
|
|
127
|
-
|
|
128
|
-
1. Add `agentDir: getAgentDir()` to the `SettingsManager` constructor deps object.
|
|
129
|
-
|
|
130
|
-
### `test/settings.test.ts`
|
|
131
|
-
|
|
132
|
-
1. Remove all `PI_CODING_AGENT_DIR` env manipulation (`originalAgentDirEnv`, `beforeEach`/`afterEach` stubs).
|
|
133
|
-
2. Pass `globalDir` directly to `loadSettings(globalDir, projectDir)` in free-function tests.
|
|
134
|
-
3. Add `agentDir: globalDir` (or a dummy string for non-load tests) to all `new SettingsManager(...)` calls.
|
|
135
|
-
4. In `SettingsManager.load()` tests, pass `agentDir: globalDir` to the constructor.
|
|
136
|
-
5. In tests that don't exercise `load()`, use `agentDir: "/nonexistent"` or similar — the value is unused.
|
|
137
|
-
|
|
138
|
-
## Test Impact Analysis
|
|
139
|
-
|
|
140
|
-
1. **New capability:** Free-function tests (`loadSettings`, `saveSettings`) become pure — pass `globalDir` directly instead of manipulating `PI_CODING_AGENT_DIR`.
|
|
141
|
-
This is simpler and more reliable.
|
|
142
|
-
2. **Redundant cleanup:** The `originalAgentDirEnv` save/restore pattern in `beforeEach`/`afterEach` can be removed from all `describe` blocks that use it.
|
|
143
|
-
3. **Existing tests stay:** All existing test scenarios remain valid; only their setup mechanics change.
|
|
144
|
-
|
|
145
|
-
## TDD Order
|
|
146
|
-
|
|
147
|
-
1. **Red → Green:** Change `loadSettings` signature to accept `agentDir` parameter; update `globalPath` to accept it.
|
|
148
|
-
Update all free-function tests to pass `globalDir` directly instead of env var.
|
|
149
|
-
Remove env-var manipulation from the `settings persistence` describe block.
|
|
150
|
-
Commit: `feat: inject agentDir into loadSettings to remove SDK dependency`
|
|
151
|
-
|
|
152
|
-
2. **Red → Green:** Add `agentDir` to `SettingsManager` constructor deps; store as private field; thread into `load()`.
|
|
153
|
-
Update all `new SettingsManager(...)` call sites in tests.
|
|
154
|
-
Remove env-var manipulation from `SettingsManager` describe blocks.
|
|
155
|
-
Remove `getAgentDir` import from `settings.ts`.
|
|
156
|
-
Commit: `feat: inject agentDir into SettingsManager constructor`
|
|
157
|
-
|
|
158
|
-
3. **Green:** Wire `agentDir: getAgentDir()` into `SettingsManager` construction in `index.ts`.
|
|
159
|
-
Run `pnpm run check` to confirm no type errors across the package.
|
|
160
|
-
Commit: `feat: wire agentDir from SDK boundary in index.ts (#218)`
|
|
161
|
-
|
|
162
|
-
## Risks and Mitigations
|
|
163
|
-
|
|
164
|
-
| Risk | Mitigation |
|
|
165
|
-
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
166
|
-
| Breaking the `loadSettings` export signature for hypothetical external callers | The function is only called from `SettingsManager.load()` and tests; no external consumers exist. |
|
|
167
|
-
| Test count is high (~35 constructor sites) — mechanical updates could introduce typos | Steps 1 and 2 are focused; run `pnpm vitest run test/settings.test.ts` after each to confirm. |
|
|
168
|
-
| Forgetting a test site that still manipulates `PI_CODING_AGENT_DIR` | Grep for `PI_CODING_AGENT_DIR` after step 2 to confirm zero remaining references in `test/settings.test.ts`. |
|
|
169
|
-
|
|
170
|
-
## Open Questions
|
|
171
|
-
|
|
172
|
-
None — the issue's proposed change is unambiguous and follows the established injection pattern used in prior Phase 13 steps.
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 219
|
|
3
|
-
issue_title: "Reduce test duplication — top 3 clone families (Phase 13, Step 6)"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Reduce test duplication — top 3 clone families
|
|
7
|
-
|
|
8
|
-
## Problem statement
|
|
9
|
-
|
|
10
|
-
After Phase 12, three test files carry the heaviest remaining clone families in pi-subagents:
|
|
11
|
-
|
|
12
|
-
1. `test/lifecycle/agent-manager.test.ts` (929 lines) — 16 clone groups, ~160 duplicated lines.
|
|
13
|
-
Repeated inline runner stubs, worktree stubs, and manager-lifecycle boilerplate.
|
|
14
|
-
2. `test/conversation-viewer.test.ts` (307 lines) — 8 clone groups, ~91 duplicated lines.
|
|
15
|
-
Near-identical `ConversationViewer` construction in every test, plus repeated width-loop assertion patterns.
|
|
16
|
-
3. `test/ui/agent-config-editor.test.ts` (471 lines) — 5 clone groups, ~42 duplicated lines.
|
|
17
|
-
Repeated `makeEditor()` + `makeMenuUI()` + `fileOps.findAgentFile.mockReturnValue(...)` setup.
|
|
18
|
-
|
|
19
|
-
Total target: reduce test duplication by ~200 lines (from ~1,046 combined test-setup lines to < 850).
|
|
20
|
-
|
|
21
|
-
## Goals
|
|
22
|
-
|
|
23
|
-
- Extract shared setup and assertion helpers for the three target test files.
|
|
24
|
-
- Reduce test duplication by ~200 lines without changing test semantics.
|
|
25
|
-
- Follow the existing `test/helpers/` convention (factory + matching `.test.ts` file).
|
|
26
|
-
|
|
27
|
-
## Non-goals
|
|
28
|
-
|
|
29
|
-
- No production code changes.
|
|
30
|
-
- No new test coverage — this is purely a refactoring of existing test infrastructure.
|
|
31
|
-
- Not consolidating clone families in other test files beyond the top 3.
|
|
32
|
-
- Not changing any assertion logic or test structure beyond replacing inline stubs with factory calls.
|
|
33
|
-
|
|
34
|
-
## Background
|
|
35
|
-
|
|
36
|
-
The project already has several shared test helpers in `test/helpers/`: `make-record.ts`, `mock-session.ts`, `ui-stubs.ts`, `runner-io.ts`, `stub-ctx.ts`, `make-deps.ts`.
|
|
37
|
-
Each helper has a companion `.test.ts` file — this convention must be followed.
|
|
38
|
-
|
|
39
|
-
Dependencies #214 (closure-to-class conversions) and #216 (startAgent decomposition) are both closed, so the production code these tests cover is stable.
|
|
40
|
-
|
|
41
|
-
## Design overview
|
|
42
|
-
|
|
43
|
-
### File 1: `agent-manager.test.ts` — extract to `test/helpers/manager-stubs.ts`
|
|
44
|
-
|
|
45
|
-
Five clone families to extract:
|
|
46
|
-
|
|
47
|
-
1. **Never-resolving runner** — `{ run: vi.fn().mockImplementation(() => new Promise(() => {})), resume: vi.fn() }` appears 5 times.
|
|
48
|
-
Extract as `createBlockingRunner(): AgentRunner`.
|
|
49
|
-
|
|
50
|
-
2. **Session-creating runner** — runner that calls `opts.onSessionCreated?.(session)` and resolves.
|
|
51
|
-
Appears 5+ times with minor variations (some emit events through the session, some don't).
|
|
52
|
-
Extract as `createSessionRunner(session?: MockSession): AgentRunner` that calls `onSessionCreated` and returns a standard result.
|
|
53
|
-
|
|
54
|
-
3. **Worktree stubs with path+branch** — `{ create: vi.fn().mockReturnValue({ path, branch }), cleanup: vi.fn(() => ({ hasChanges: false })), prune: vi.fn() }` appears 4 times identically, plus 1 variant with `create` returning `undefined`.
|
|
55
|
-
Extract as `createMockWorktrees(overrides?)`.
|
|
56
|
-
|
|
57
|
-
4. **Standard run result shape** — `{ responseText: "done", session, aborted: false, steered: false }` is repeated in many runner factories.
|
|
58
|
-
Extract as `createRunResult(overrides?)`.
|
|
59
|
-
|
|
60
|
-
5. **Gated runner** — uses `Promise.withResolvers` to control when the runner completes.
|
|
61
|
-
Appears 2 times.
|
|
62
|
-
Keep inline — too tightly coupled to individual test flow-control to generalize cleanly.
|
|
63
|
-
|
|
64
|
-
Tests that construct custom runners with unique behavior (event-emitting runners in the `lifetimeUsage` and `compactionCount` tests) keep their inline stubs — those encode test-specific emission sequences that a shared factory would obscure.
|
|
65
|
-
|
|
66
|
-
### File 2: `conversation-viewer.test.ts` — inline factory + assertion helper
|
|
67
|
-
|
|
68
|
-
Two clone families to extract:
|
|
69
|
-
|
|
70
|
-
1. **`ConversationViewer` construction** — 15 near-identical constructor calls with the same 8 fields.
|
|
71
|
-
Extract as an inline `createTestViewer(overrides?)` factory at the top of the test file.
|
|
72
|
-
The factory provides defaults for `tui`, `session`, `record`, `activity`, `theme`, `done`, `registry`, and `wrapText`, and accepts overrides including a convenience `width` and `messages` parameter.
|
|
73
|
-
|
|
74
|
-
2. **Width-loop assertion** — the `for (const w of widths) { create viewer; assertAllLinesFit(viewer.render(w), w) }` pattern repeats in 10 "render width safety" tests.
|
|
75
|
-
Extract as an inline `assertRenderFitsWidths(messages, widths?, viewerOverrides?)` helper.
|
|
76
|
-
|
|
77
|
-
These helpers stay inline (not in `test/helpers/`) because they depend on file-local helpers (`mockTui`, `mockSession`, `ansiTheme`) and are only used by this one test file.
|
|
78
|
-
|
|
79
|
-
### File 3: `agent-config-editor.test.ts` — inline setup helper
|
|
80
|
-
|
|
81
|
-
One clone family to extract:
|
|
82
|
-
|
|
83
|
-
1. **Detail-test setup** — `makeEditor()` + `makeMenuUI([...])` + `fileOps.findAgentFile.mockReturnValue(...)` + optional `fileOps.read.mockReturnValue(...)` appears in ~18 tests.
|
|
84
|
-
Extract as an inline `setupDetail(selectResults, options?)` factory that returns `{ fileOps, editor, ui }` with pre-configured mocks.
|
|
85
|
-
Options: `filePath`, `fileContent`, `config` (merged into default via `createTestAgentConfig`).
|
|
86
|
-
|
|
87
|
-
This stays inline because it's specific to the `showAgentDetail` test suite and depends on file-local `testRegistry` setup.
|
|
88
|
-
|
|
89
|
-
## Module-level changes
|
|
90
|
-
|
|
91
|
-
### New files
|
|
92
|
-
|
|
93
|
-
| File | Purpose |
|
|
94
|
-
| ------------------------------------ | --------------------------------------------------------------------------------------- |
|
|
95
|
-
| `test/helpers/manager-stubs.ts` | `createBlockingRunner`, `createSessionRunner`, `createMockWorktrees`, `createRunResult` |
|
|
96
|
-
| `test/helpers/manager-stubs.test.ts` | Smoke tests for the factories |
|
|
97
|
-
|
|
98
|
-
### Modified files
|
|
99
|
-
|
|
100
|
-
| File | Change |
|
|
101
|
-
| -------------------------------------- | --------------------------------------------------------------------------- |
|
|
102
|
-
| `test/lifecycle/agent-manager.test.ts` | Replace inline runner/worktree stubs with `manager-stubs` factories |
|
|
103
|
-
| `test/conversation-viewer.test.ts` | Add `createTestViewer` + `assertRenderFitsWidths` inline, migrate all tests |
|
|
104
|
-
| `test/ui/agent-config-editor.test.ts` | Add `setupDetail` inline, migrate `showAgentDetail` tests |
|
|
105
|
-
|
|
106
|
-
### Unchanged files
|
|
107
|
-
|
|
108
|
-
No production source files are modified.
|
|
109
|
-
No other test files are modified.
|
|
110
|
-
|
|
111
|
-
## Test impact analysis
|
|
112
|
-
|
|
113
|
-
1. **New unit tests**: `manager-stubs.test.ts` adds smoke tests verifying factory return shapes (blocking runner never resolves, session runner calls `onSessionCreated`, worktree factory returns the expected interface, run result contains the correct fields).
|
|
114
|
-
2. **Simplified tests**: ~30 tests across the three files replace 3–6 lines of inline stub construction with 1-line factory calls.
|
|
115
|
-
3. **Unchanged tests**: All existing test assertions remain identical — only the setup code changes.
|
|
116
|
-
Tests with custom runner behavior (event-emitting, gated, error-throwing) keep their inline stubs.
|
|
117
|
-
|
|
118
|
-
## TDD order
|
|
119
|
-
|
|
120
|
-
1. **Create `test/helpers/manager-stubs.ts` + `manager-stubs.test.ts`** Add `createBlockingRunner`, `createSessionRunner`, `createMockWorktrees`, `createRunResult`.
|
|
121
|
-
Add smoke tests verifying each factory's return shape and basic behavior.
|
|
122
|
-
Commit: `test: add manager-stubs helper factories (#219)`
|
|
123
|
-
|
|
124
|
-
2. **Migrate `agent-manager.test.ts` to use manager-stubs** Replace 5 inline never-resolving runners with `createBlockingRunner()`.
|
|
125
|
-
Replace 4 identical worktree stubs with `createMockWorktrees()` / `createMockWorktrees({ create: ... })`.
|
|
126
|
-
Replace inline session-creating runners with `createSessionRunner(session)` where the test only needs `onSessionCreated` wiring.
|
|
127
|
-
Replace inline run-result objects with `createRunResult()` where the default shape suffices.
|
|
128
|
-
Run `pnpm vitest run test/lifecycle/agent-manager.test.ts` to verify green.
|
|
129
|
-
Commit: `test: migrate agent-manager tests to manager-stubs (#219)`
|
|
130
|
-
|
|
131
|
-
3. **Add inline factories to `conversation-viewer.test.ts` and migrate** Add `createTestViewer(overrides?)` inline factory with defaults for all 8 constructor fields.
|
|
132
|
-
Add `assertRenderFitsWidths(messages, widths?, overrides?)` inline helper.
|
|
133
|
-
Migrate all 10 "render width safety" tests to use `assertRenderFitsWidths`.
|
|
134
|
-
Migrate all 5 "safety net" tests to use `createTestViewer`.
|
|
135
|
-
Run `pnpm vitest run test/conversation-viewer.test.ts` to verify green.
|
|
136
|
-
Commit: `test: reduce conversation-viewer test duplication (#219)`
|
|
137
|
-
|
|
138
|
-
4. **Add inline `setupDetail` to `agent-config-editor.test.ts` and migrate** Add `setupDetail(selectResults, options?)` returning `{ fileOps, editor, ui }`.
|
|
139
|
-
Migrate `showAgentDetail` tests to use `setupDetail`.
|
|
140
|
-
Run `pnpm vitest run test/ui/agent-config-editor.test.ts` to verify green.
|
|
141
|
-
Commit: `test: reduce agent-config-editor test duplication (#219)`
|
|
142
|
-
|
|
143
|
-
5. **Final verification** Run `pnpm vitest run` (full suite) to confirm no regressions.
|
|
144
|
-
Run `pnpm run check` to confirm no type errors.
|
|
145
|
-
Commit is not needed — this is a verification-only step.
|
|
146
|
-
|
|
147
|
-
## Risks and mitigations
|
|
148
|
-
|
|
149
|
-
1. **Factory defaults diverge from test intent** — If a shared factory's defaults don't match what an individual test expects, assertions silently pass or fail for the wrong reason.
|
|
150
|
-
Mitigation: diff all inline stubs against the proposed factory defaults before writing the factory.
|
|
151
|
-
Keep tests with unique mock behavior inline rather than force-fitting them into a factory.
|
|
152
|
-
|
|
153
|
-
2. **Over-abstraction obscures test intent** — Extracting too many details into helpers makes tests harder to read.
|
|
154
|
-
Mitigation: only extract truly duplicated boilerplate (stub construction); keep test-specific setup and assertions inline.
|
|
155
|
-
The gated runner pattern stays inline for this reason.
|
|
156
|
-
|
|
157
|
-
3. **Intermediate broken state** — Partially migrated test files may have import conflicts.
|
|
158
|
-
Mitigation: each TDD step fully migrates one file before committing.
|
|
159
|
-
|
|
160
|
-
## Open questions
|
|
161
|
-
|
|
162
|
-
None — the issue scope is well-defined and the dependencies are resolved.
|
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 227
|
|
3
|
-
issue_title: "Evolve AgentRecord into Agent with behavior (Phase 15, Step 1)"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Evolve AgentRecord into Agent with behavior
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
`AgentRecord` is an anemic domain model — it holds identity, status transitions, and stats but no behavior.
|
|
11
|
-
`AgentManager` reaches into records 37 times, performing work that belongs on the agent:
|
|
12
|
-
|
|
13
|
-
- **abort**: `AgentManager.abort()` checks `record.status`, calls `record.abortController?.abort()`, calls `record.markStopped()` — this is the agent aborting itself, but the logic lives on the manager.
|
|
14
|
-
- **pending steers**: per-agent steer buffers live in a manager-level `Map<string, string[]>`, not on the agent.
|
|
15
|
-
- **steer flushing**: `flushPendingSteers(id, session)` iterates the manager map — should be `agent.flushPendingSteers(session)`.
|
|
16
|
-
- **worktree setup**: `setupWorktree()` creates a worktree and attaches it to the record — the agent should set up its own worktree.
|
|
17
|
-
|
|
18
|
-
## Goals
|
|
19
|
-
|
|
20
|
-
- Move per-agent behavior (`abort`, `queueSteer`/`flushPendingSteers`, `setupWorktree`) from `AgentManager` to the agent.
|
|
21
|
-
- `AgentManager` delegates to agents via Tell-Don't-Ask instead of reaching into records.
|
|
22
|
-
- Rename `AgentRecord` → `Agent`, `AgentRecordStatus` → `AgentStatus`, `AgentRecordInit` → `AgentInit` across the codebase.
|
|
23
|
-
- All changes are internal — the public `SubagentsService` API (`service.ts`) is unaffected.
|
|
24
|
-
|
|
25
|
-
## Non-Goals
|
|
26
|
-
|
|
27
|
-
- **`RunHandle` ownership** — moves to `Agent` in #228, not here.
|
|
28
|
-
- **Async `startAgent`** — deferred to #228.
|
|
29
|
-
- **`onSessionCreated` observer** — deferred to #229.
|
|
30
|
-
- **`ConcurrencyQueue` extraction** — deferred to #230.
|
|
31
|
-
Queue removal logic stays on `AgentManager.abort()` until then.
|
|
32
|
-
- **Relay deps** — deferred to #231.
|
|
33
|
-
- **Resume unification** — deferred to #232.
|
|
34
|
-
|
|
35
|
-
## Background
|
|
36
|
-
|
|
37
|
-
### Relevant modules
|
|
38
|
-
|
|
39
|
-
| Module | Responsibility | Relationship to this change |
|
|
40
|
-
| ------------------------------------------ | ------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
41
|
-
| `src/lifecycle/agent-record.ts` (201 LOC) | Status state machine, stats accumulation | Gains behavior methods, renames to `agent.ts` |
|
|
42
|
-
| `src/lifecycle/agent-manager.ts` (541 LOC) | Agent collection, spawn, abort, queue, steer buffering | Loses private methods, delegates to agent |
|
|
43
|
-
| `src/lifecycle/worktree.ts` | `WorktreeManager` interface and git worktree operations | Agent calls `worktrees.create()` directly |
|
|
44
|
-
| `src/lifecycle/worktree-state.ts` | Per-agent worktree lifecycle state | Already attached to agent — `setupWorktree` formalizes this |
|
|
45
|
-
| `src/tools/steer-tool.ts` | LLM-facing steer tool | Calls `record.queueSteer()` directly instead of `manager.queueSteer()` |
|
|
46
|
-
| `src/service/service-adapter.ts` | Cross-extension API adapter | Calls `record.queueSteer()` directly; `queueSteer` removed from `AgentManagerLike` |
|
|
47
|
-
| `src/observation/record-observer.ts` | Session event → agent stats accumulation | Import rename only |
|
|
48
|
-
| `src/types.ts` | Internal re-exports | Re-export updates |
|
|
49
|
-
| `test/helpers/make-record.ts` | Shared test factory | Renames to `make-agent.ts`, factory → `createTestAgent()` |
|
|
50
|
-
|
|
51
|
-
### Constraints
|
|
52
|
-
|
|
53
|
-
- The public export from `package.json` is `"./src/service.ts"` only — `AgentRecord` is internal, so the rename is not breaking for consumers.
|
|
54
|
-
- `WorktreeManager` is injected via the manager's constructor — `Agent.setupWorktree()` receives it as a parameter (no new constructor dependency).
|
|
55
|
-
- Queue removal in `abort()` stays on `AgentManager` because the queue is manager-owned until #230 extracts `ConcurrencyQueue`.
|
|
56
|
-
|
|
57
|
-
## Design Overview
|
|
58
|
-
|
|
59
|
-
### New methods on Agent
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
class Agent {
|
|
63
|
-
// Existing: markRunning, markCompleted, markAborted, markSteered, markError, markStopped,
|
|
64
|
-
// incrementToolUses, addUsage, incrementCompactions, resetForResume
|
|
65
|
-
|
|
66
|
-
// --- New behavior ---
|
|
67
|
-
|
|
68
|
-
/** Buffer a steer message for delivery once the session is ready. */
|
|
69
|
-
queueSteer(message: string): void;
|
|
70
|
-
|
|
71
|
-
/** Flush buffered steers to the session and clear the buffer. */
|
|
72
|
-
flushPendingSteers(session: AgentSession): void;
|
|
73
|
-
|
|
74
|
-
/** Abort a running agent: fire AbortController, transition to stopped. */
|
|
75
|
-
abort(): boolean;
|
|
76
|
-
|
|
77
|
-
/** Create a worktree for isolated execution. Throws if impossible. */
|
|
78
|
-
setupWorktree(worktrees: WorktreeManager, isolation: IsolationMode | undefined): string | undefined;
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Steer buffering moves to agent
|
|
83
|
-
|
|
84
|
-
Before: `AgentManager` owns `pendingSteers: Map<string, string[]>` and exposes `queueSteer(id, msg)`.
|
|
85
|
-
After: each `Agent` owns `private pendingSteers: string[] = []`.
|
|
86
|
-
Callers that already hold a record reference (steer tool, service adapter) call `agent.queueSteer(msg)` directly — the manager's `queueSteer` method and the `pendingSteers` map are removed.
|
|
87
|
-
|
|
88
|
-
Consumer call-site (steer tool):
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
// Before:
|
|
92
|
-
this.manager.queueSteer(record.id, params.message);
|
|
93
|
-
// After:
|
|
94
|
-
record.queueSteer(params.message);
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Abort moves to agent
|
|
98
|
-
|
|
99
|
-
`Agent.abort()` encapsulates the running-check + controller.abort + markStopped sequence:
|
|
100
|
-
|
|
101
|
-
```typescript
|
|
102
|
-
abort(): boolean {
|
|
103
|
-
if (this._status !== "running") return false;
|
|
104
|
-
this.abortController?.abort();
|
|
105
|
-
this.markStopped();
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
`AgentManager.abort(id)` retains queue-removal logic (queue is manager-owned until #230) and delegates the running case to `agent.abort()`.
|
|
111
|
-
`AgentManager.abortAll()` calls `agent.abort()` for running agents.
|
|
112
|
-
|
|
113
|
-
### Worktree setup moves to agent
|
|
114
|
-
|
|
115
|
-
`Agent.setupWorktree(worktrees, isolation)` replaces `AgentManager.setupWorktree(id, record, isolation)`.
|
|
116
|
-
The agent creates the worktree, sets `this.worktreeState`, and returns the worktree path.
|
|
117
|
-
The error message for impossible worktree creation stays identical.
|
|
118
|
-
|
|
119
|
-
### Rename strategy
|
|
120
|
-
|
|
121
|
-
The rename (`AgentRecord` → `Agent`) is the final step — a purely mechanical search-and-replace with no behavior change.
|
|
122
|
-
This keeps behavior-adding commits small and reviewable, then consolidates the rename noise into one commit.
|
|
123
|
-
|
|
124
|
-
Files affected by the rename:
|
|
125
|
-
|
|
126
|
-
| Layer | Files |
|
|
127
|
-
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
128
|
-
| Source (lifecycle) | `agent-record.ts` → `agent.ts`, `agent-manager.ts`, `execution-state.ts` |
|
|
129
|
-
| Source (observation) | `record-observer.ts`, `notification.ts` |
|
|
130
|
-
| Source (tools) | `agent-tool.ts`, `steer-tool.ts`, `get-result-tool.ts`, `background-spawner.ts`, `foreground-runner.ts` |
|
|
131
|
-
| Source (UI) | `agent-menu.ts`, `agent-creation-wizard.ts`, `conversation-viewer.ts` |
|
|
132
|
-
| Source (service) | `service-adapter.ts` |
|
|
133
|
-
| Source (types) | `types.ts` |
|
|
134
|
-
| Tests | `agent-record.test.ts` → `agent.test.ts`, `agent-manager.test.ts`, `record-observer.test.ts`, `steer-tool.test.ts`, `get-result-tool.test.ts`, `service-adapter.test.ts` |
|
|
135
|
-
| Test helpers | `make-record.ts` → `make-agent.ts` |
|
|
136
|
-
|
|
137
|
-
## Module-Level Changes
|
|
138
|
-
|
|
139
|
-
### `src/lifecycle/agent-record.ts` → `src/lifecycle/agent.ts`
|
|
140
|
-
|
|
141
|
-
1. Add `private pendingSteers: string[] = []` field.
|
|
142
|
-
2. Add `queueSteer(message: string): void` — pushes to `pendingSteers`.
|
|
143
|
-
3. Add `flushPendingSteers(session: AgentSession): void` — iterates buffer, calls `session.steer()`, clears array.
|
|
144
|
-
4. Add `abort(): boolean` — if running, fires controller and marks stopped.
|
|
145
|
-
5. Add `setupWorktree(worktrees: WorktreeManager, isolation: IsolationMode | undefined): string | undefined` — creates worktree, sets `worktreeState`, returns path.
|
|
146
|
-
6. Add import for `WorktreeState`, `WorktreeManager`, `IsolationMode`.
|
|
147
|
-
7. Rename class `AgentRecord` → `Agent`, type `AgentRecordStatus` → `AgentStatus`, interface `AgentRecordInit` → `AgentInit`.
|
|
148
|
-
|
|
149
|
-
### `src/lifecycle/agent-manager.ts`
|
|
150
|
-
|
|
151
|
-
1. Remove `private pendingSteers = new Map<string, string[]>()`.
|
|
152
|
-
2. Remove `queueSteer(id, message)` public method.
|
|
153
|
-
3. Remove `private flushPendingSteers(id, session)` method.
|
|
154
|
-
4. In `startAgent`'s `onSessionCreated` callback: replace `this.flushPendingSteers(id, session)` with `record.flushPendingSteers(session)`.
|
|
155
|
-
5. Remove `private setupWorktree(id, record, isolation)` method.
|
|
156
|
-
6. In `startAgent`: replace `this.setupWorktree(id, record, options.isolation)` with `record.setupWorktree(this.worktrees, options.isolation)`.
|
|
157
|
-
7. Simplify `abort(id)`: delegate running case to `record.abort()`.
|
|
158
|
-
8. Simplify `abortAll()`: call `record.abort()` for running agents.
|
|
159
|
-
9. In `removeRecord`: remove `this.pendingSteers.delete(id)`.
|
|
160
|
-
10. Update imports: `AgentRecord` → `Agent`, `AgentRecordInit` → `AgentInit` (if used).
|
|
161
|
-
|
|
162
|
-
### `src/tools/steer-tool.ts`
|
|
163
|
-
|
|
164
|
-
1. Remove `queueSteer` from `SteerToolManager` interface.
|
|
165
|
-
2. Replace `this.manager.queueSteer(record.id, params.message)` with `record.queueSteer(params.message)`.
|
|
166
|
-
3. Update import: `AgentRecord` → `Agent`.
|
|
167
|
-
|
|
168
|
-
### `src/service/service-adapter.ts`
|
|
169
|
-
|
|
170
|
-
1. Remove `queueSteer` from `AgentManagerLike` interface.
|
|
171
|
-
2. In `steer()`: replace `this.manager.queueSteer(id, message)` with `record.queueSteer(message)` and return `true`.
|
|
172
|
-
3. Update import: `AgentRecord` → `Agent`.
|
|
173
|
-
|
|
174
|
-
### `src/types.ts`
|
|
175
|
-
|
|
176
|
-
1. Update re-export: `AgentRecord` → `Agent`, source path `#src/lifecycle/agent-record` → `#src/lifecycle/agent`.
|
|
177
|
-
|
|
178
|
-
### `src/observation/record-observer.ts`
|
|
179
|
-
|
|
180
|
-
1. Update import and parameter types: `AgentRecord` → `Agent`.
|
|
181
|
-
|
|
182
|
-
### `src/observation/notification.ts`
|
|
183
|
-
|
|
184
|
-
1. Update import and parameter types: `AgentRecord` → `Agent`.
|
|
185
|
-
|
|
186
|
-
### `src/tools/*.ts` (agent-tool, get-result-tool, background-spawner, foreground-runner)
|
|
187
|
-
|
|
188
|
-
1. Update imports and type annotations: `AgentRecord` → `Agent`.
|
|
189
|
-
|
|
190
|
-
### `src/ui/*.ts` (agent-menu, agent-creation-wizard, conversation-viewer)
|
|
191
|
-
|
|
192
|
-
1. Update imports and type annotations: `AgentRecord` → `Agent`.
|
|
193
|
-
|
|
194
|
-
### `test/helpers/make-record.ts` → `test/helpers/make-agent.ts`
|
|
195
|
-
|
|
196
|
-
1. Rename file.
|
|
197
|
-
2. Update imports: `AgentRecord` → `Agent`, `AgentRecordInit` → `AgentInit`.
|
|
198
|
-
3. Rename factory: `createTestRecord` → `createTestAgent`.
|
|
199
|
-
4. Update return type annotation.
|
|
200
|
-
|
|
201
|
-
### `test/lifecycle/agent-record.test.ts` → `test/lifecycle/agent.test.ts`
|
|
202
|
-
|
|
203
|
-
1. Rename file.
|
|
204
|
-
2. Update import: `AgentRecord` → `Agent`.
|
|
205
|
-
3. Update all `describe` block names and `new AgentRecord(...)` calls.
|
|
206
|
-
4. Add new test blocks for `queueSteer`, `flushPendingSteers`, `abort`, `setupWorktree`.
|
|
207
|
-
|
|
208
|
-
### `test/lifecycle/agent-manager.test.ts`
|
|
209
|
-
|
|
210
|
-
1. Remove tests for `AgentManager.queueSteer` (behavior moved to agent).
|
|
211
|
-
2. Update `abort()` tests to verify delegation.
|
|
212
|
-
3. Update imports if `AgentRecord` type is referenced.
|
|
213
|
-
|
|
214
|
-
### `test/tools/steer-tool.test.ts`
|
|
215
|
-
|
|
216
|
-
1. Remove `queueSteer` from mock manager.
|
|
217
|
-
2. Update "session not ready" test to verify `record.queueSteer()` is called.
|
|
218
|
-
|
|
219
|
-
### `test/service/service-adapter.test.ts`
|
|
220
|
-
|
|
221
|
-
1. Remove `queueSteer` from mock managers.
|
|
222
|
-
2. Update steer tests to verify `record.queueSteer()`.
|
|
223
|
-
|
|
224
|
-
### `packages/pi-subagents/docs/architecture/architecture.md`
|
|
225
|
-
|
|
226
|
-
1. Update file listing: `agent-record.ts` → `agent.ts`.
|
|
227
|
-
2. Update `AgentRecordInit` reference in interface width table.
|
|
228
|
-
|
|
229
|
-
## Test Impact Analysis
|
|
230
|
-
|
|
231
|
-
### New unit tests enabled by the extraction
|
|
232
|
-
|
|
233
|
-
1. **`Agent.queueSteer()` / `Agent.flushPendingSteers()`** — isolated tests for steer buffering without needing a full `AgentManager` setup.
|
|
234
|
-
Previously the steer buffering was only testable via `AgentManager` integration tests.
|
|
235
|
-
2. **`Agent.abort()`** — isolated tests for the abort state machine (running → stopped, not-running → no-op) without needing manager scaffolding.
|
|
236
|
-
3. **`Agent.setupWorktree()`** — isolated tests for worktree creation and error handling with a mock `WorktreeManager`, without full spawn infrastructure.
|
|
237
|
-
|
|
238
|
-
### Existing tests that become redundant
|
|
239
|
-
|
|
240
|
-
1. `AgentManager — queueSteer` tests — the behavior is now tested directly on `Agent`.
|
|
241
|
-
The manager no longer has a `queueSteer` method.
|
|
242
|
-
2. Parts of `AgentManager — abort` tests that verify controller.abort + markStopped — these are now `Agent.abort()` tests.
|
|
243
|
-
The manager abort tests should focus on queue-removal logic and delegation.
|
|
244
|
-
|
|
245
|
-
### Existing tests that must stay
|
|
246
|
-
|
|
247
|
-
1. `AgentManager — abort` tests for the "queued" case (queue removal is still manager-owned).
|
|
248
|
-
2. `AgentManager — abortAll` tests (orchestrates both queue clearing and agent abort).
|
|
249
|
-
3. All `AgentManager — spawn/spawnAndWait` tests — the spawn flow still lives on the manager.
|
|
250
|
-
4. `steer-tool` and `service-adapter` tests for the steer path — updated to verify the new call pattern.
|
|
251
|
-
|
|
252
|
-
## TDD Order
|
|
253
|
-
|
|
254
|
-
1. **Red/Green: add `queueSteer()` and `flushPendingSteers()` to `AgentRecord`**
|
|
255
|
-
- Add tests in `agent-record.test.ts` for buffering and flushing steers.
|
|
256
|
-
- Implement the methods on `AgentRecord`.
|
|
257
|
-
- Commit: `feat(pi-subagents): add steer buffering to AgentRecord`
|
|
258
|
-
|
|
259
|
-
2. **Refactor: delegate steer buffering from manager to agent**
|
|
260
|
-
- Remove `pendingSteers` map, `queueSteer()`, `flushPendingSteers()` from `AgentManager`.
|
|
261
|
-
- In `startAgent`'s `onSessionCreated`: call `record.flushPendingSteers(session)`.
|
|
262
|
-
- In `removeRecord`: remove `pendingSteers.delete(id)`.
|
|
263
|
-
- Update `steer-tool.ts`: remove `queueSteer` from `SteerToolManager`, call `record.queueSteer()`.
|
|
264
|
-
- Update `service-adapter.ts`: remove `queueSteer` from `AgentManagerLike`, call `record.queueSteer()`.
|
|
265
|
-
- Remove `AgentManager — queueSteer` tests; update steer-tool and service-adapter tests.
|
|
266
|
-
- Run `pnpm run check` to verify no type errors.
|
|
267
|
-
- Commit: `refactor(pi-subagents): delegate steer buffering from manager to agent`
|
|
268
|
-
|
|
269
|
-
3. **Red/Green: add `abort()` to `AgentRecord`**
|
|
270
|
-
- Add tests in `agent-record.test.ts`: running → aborts and returns true; non-running → returns false; no controller → still marks stopped.
|
|
271
|
-
- Implement the method.
|
|
272
|
-
- Commit: `feat(pi-subagents): add abort() to AgentRecord`
|
|
273
|
-
|
|
274
|
-
4. **Refactor: delegate abort from manager to agent**
|
|
275
|
-
- Simplify `AgentManager.abort()`: queued case stays, running case delegates to `record.abort()`.
|
|
276
|
-
- Simplify `AgentManager.abortAll()`: call `record.abort()` for running agents.
|
|
277
|
-
- Update manager abort tests to focus on queue removal and delegation.
|
|
278
|
-
- Commit: `refactor(pi-subagents): delegate abort from manager to agent`
|
|
279
|
-
|
|
280
|
-
5. **Red/Green: add `setupWorktree()` to `AgentRecord`**
|
|
281
|
-
- Add tests in `agent-record.test.ts`: non-worktree returns undefined; worktree created → sets `worktreeState` and returns path; creation fails → throws.
|
|
282
|
-
- Implement the method (import `WorktreeState`, `WorktreeManager`, `IsolationMode`).
|
|
283
|
-
- Commit: `feat(pi-subagents): add setupWorktree() to AgentRecord`
|
|
284
|
-
|
|
285
|
-
6. **Refactor: delegate worktree setup from manager to agent**
|
|
286
|
-
- Remove `private setupWorktree()` from `AgentManager`.
|
|
287
|
-
- In `startAgent`: replace `this.setupWorktree(id, record, options.isolation)` with `record.setupWorktree(this.worktrees, options.isolation)`.
|
|
288
|
-
- Update any tests that verify worktree setup delegation.
|
|
289
|
-
- Commit: `refactor(pi-subagents): delegate worktree setup from manager to agent`
|
|
290
|
-
|
|
291
|
-
7. **Rename `AgentRecord` → `Agent` across codebase**
|
|
292
|
-
- Rename `src/lifecycle/agent-record.ts` → `src/lifecycle/agent.ts`.
|
|
293
|
-
- Rename class `AgentRecord` → `Agent`, type `AgentRecordStatus` → `AgentStatus`, interface `AgentRecordInit` → `AgentInit`.
|
|
294
|
-
- Update all source imports and type references (~20 source files).
|
|
295
|
-
- Rename `test/lifecycle/agent-record.test.ts` → `test/lifecycle/agent.test.ts`.
|
|
296
|
-
- Rename `test/helpers/make-record.ts` → `test/helpers/make-agent.ts`, factory `createTestRecord` → `createTestAgent`.
|
|
297
|
-
- Update all test imports and references (~10 test files).
|
|
298
|
-
- Rename `subscribeRecordObserver` → `subscribeAgentObserver` and `RecordObserverOptions` → `AgentObserverOptions` in `record-observer.ts`.
|
|
299
|
-
- Run `pnpm run check` and full test suite.
|
|
300
|
-
- Commit: `refactor(pi-subagents): rename AgentRecord to Agent`
|
|
301
|
-
|
|
302
|
-
8. **Update architecture docs**
|
|
303
|
-
- Update `docs/architecture/architecture.md` file listing: `agent-record.ts` → `agent.ts`.
|
|
304
|
-
- Update `AgentRecordInit` → `AgentInit` in the interface width table.
|
|
305
|
-
- Update the Phase 15 Step 1 entry to reflect completion.
|
|
306
|
-
- Commit: `docs(pi-subagents): update architecture for Agent rename`
|
|
307
|
-
|
|
308
|
-
## Risks and Mitigations
|
|
309
|
-
|
|
310
|
-
1. **Large rename diff in step 7** — The rename touches ~30 files.
|
|
311
|
-
Mitigated by making it a purely mechanical change (no behavior change) in a dedicated commit, so reviewers can verify it's a clean rename.
|
|
312
|
-
2. **Queue-removal leaks into agent** — `Agent.abort()` must NOT remove from the manager's queue (that's #230's concern).
|
|
313
|
-
Mitigated by scoping `Agent.abort()` to only handle the running case; `AgentManager.abort()` retains queue removal.
|
|
314
|
-
3. **Interface changes cascade** — Removing `queueSteer` from `SteerToolManager` and `AgentManagerLike` requires updating test mocks.
|
|
315
|
-
Mitigated by handling interface changes and test updates in the same step (step 2).
|
|
316
|
-
4. **Test factory rename ripple** — `createTestRecord` → `createTestAgent` touches many test files.
|
|
317
|
-
Mitigated by including this in the rename step (step 7), which is already a mechanical change.
|
|
318
|
-
|
|
319
|
-
## Open Questions
|
|
320
|
-
|
|
321
|
-
None — the issue's proposed change is unambiguous and scoped.
|
|
322
|
-
`RunHandle` ownership and other Phase 15 steps are explicitly deferred to their own issues.
|