@gotgenes/pi-subagents 18.0.1 → 18.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/docs/architecture/architecture.md +157 -204
- package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
- package/package.json +5 -6
- package/src/lifecycle/subagent.ts +5 -9
- package/src/observation/notification.ts +23 -10
- package/src/observation/subagent-events-observer.ts +1 -3
- package/src/tools/get-result-report.ts +60 -0
- package/src/tools/get-result-tool.ts +25 -40
- package/src/types.ts +1 -1
- package/src/ui/session-navigator.ts +0 -2
- package/.prettierignore +0 -5
- package/AGENTS.md +0 -7
- package/docs/plans/0048-implement-subagents-api.md +0 -304
- package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
- package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
- package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
- package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
- package/docs/plans/0054-decompose-index-into-modules.md +0 -302
- package/docs/plans/0057-structured-debug-logging.md +0 -154
- package/docs/plans/0061-session-format-transcript.md +0 -284
- package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
- package/docs/plans/0069-create-subagent-runtime.md +0 -345
- package/docs/plans/0070-extract-event-handlers.md +0 -306
- package/docs/plans/0071-extract-session-config-assembler.md +0 -362
- package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
- package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
- package/docs/plans/0077-inject-project-agents-dir.md +0 -115
- package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
- package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
- package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
- package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
- package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
- package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
- package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
- package/docs/plans/0108-extract-agent-type-registry.md +0 -322
- package/docs/plans/0109-extract-settings-manager.md +0 -276
- package/docs/plans/0110-agent-activity-tracker.md +0 -297
- package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
- package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
- package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
- package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
- package/docs/plans/0115-decompose-agent-tool.md +0 -337
- package/docs/plans/0116-type-housekeeping.md +0 -351
- package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
- package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
- package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
- package/docs/plans/0132-inject-io-into-session-config.md +0 -219
- package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
- package/docs/plans/0134-reduce-as-any-casts.md +0 -366
- package/docs/plans/0135-extract-display-helpers.md +0 -182
- package/docs/plans/0136-decompose-agent-menu.md +0 -300
- package/docs/plans/0144-consolidate-observation-model.md +0 -263
- package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
- package/docs/plans/0146-narrow-ui-context.md +0 -319
- package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
- package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
- package/docs/plans/0152-add-prompt-snippet.md +0 -91
- package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
- package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
- package/docs/plans/0166-extract-parent-session-info.md +0 -231
- package/docs/plans/0167-narrow-runner-io.md +0 -150
- package/docs/plans/0168-extract-tool-filter-config.md +0 -173
- package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
- package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
- package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
- package/docs/plans/0172-extract-turn-formatting.md +0 -206
- package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
- package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
- package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
- package/docs/plans/0192-define-session-context-interface.md +0 -107
- package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
- package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
- package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
- package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
- package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
- package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
- package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
- package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
- package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
- package/docs/plans/0215-decompose-build-parent-context.md +0 -166
- package/docs/plans/0216-decompose-start-agent.md +0 -255
- package/docs/plans/0217-extract-overwrite-guard.md +0 -176
- package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
- package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
- package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
- package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
- package/docs/plans/0229-agent-born-complete.md +0 -564
- package/docs/plans/0230-extract-concurrency-queue.md +0 -265
- package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
- package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
- package/docs/plans/0237-remove-disallowed-tools.md +0 -180
- package/docs/plans/0238-remove-extensions-filtering.md +0 -191
- package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
- package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
- package/docs/plans/0256-extract-worktree-isolation.md +0 -256
- package/docs/plans/0257-extract-child-session-factory.md +0 -285
- package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
- package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
- package/docs/plans/0265-born-complete-subagent-session.md +0 -333
- package/docs/plans/0270-type-consumable-public-surface.md +0 -204
- package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
- package/docs/plans/0277-encapsulate-agent-session.md +0 -304
- package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
- package/docs/plans/0360-custom-agents-default-append.md +0 -132
- package/docs/plans/0373-extract-subagent-state.md +0 -250
- package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
- package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
- package/docs/plans/0376-extract-manager-observer.md +0 -232
- package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
- package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
- package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
- package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
- package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
- package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
- package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
- package/docs/plans/0412-unify-session-mock-builders.md +0 -146
- package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
- package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
- package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
- package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
- package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
- package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
- package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
- package/docs/plans/0427-reconsider-ui-direction.md +0 -212
- package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
- package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
- package/docs/plans/0443-consolidate-remaining-test-clone-families.md +0 -268
- package/docs/plans/0444-shrink-widget-to-background-agents.md +0 -156
- package/docs/plans/0445-native-session-navigation.md +0 -365
- package/docs/plans/0446-spike-session-navigation-entry-criteria.md +0 -171
- package/docs/plans/0447-extract-subagents-settings-command.md +0 -220
- package/docs/plans/0448-block-disabled-agent-spawn.md +0 -207
- package/docs/plans/0462-navigation-renderer-tui-components.md +0 -338
- package/docs/plans/0463-file-snapshot-source-evicted-agents.md +0 -306
- package/docs/plans/0470-refresh-readme-command-surface.md +0 -159
- package/docs/retro/0048-implement-subagents-api.md +0 -44
- package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
- package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
- package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
- package/docs/retro/0054-decompose-index-into-modules.md +0 -53
- package/docs/retro/0057-structured-debug-logging.md +0 -77
- package/docs/retro/0061-session-format-transcript.md +0 -41
- package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
- package/docs/retro/0069-create-subagent-runtime.md +0 -43
- package/docs/retro/0070-extract-event-handlers.md +0 -49
- package/docs/retro/0071-extract-session-config-assembler.md +0 -60
- package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
- package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
- package/docs/retro/0077-inject-project-agents-dir.md +0 -33
- package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
- package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
- package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
- package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
- package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
- package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
- package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
- package/docs/retro/0108-extract-agent-type-registry.md +0 -41
- package/docs/retro/0109-extract-settings-manager.md +0 -55
- package/docs/retro/0110-agent-activity-tracker.md +0 -44
- package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
- package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
- package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
- package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
- package/docs/retro/0115-decompose-agent-tool.md +0 -51
- package/docs/retro/0116-type-housekeeping.md +0 -42
- package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
- package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
- package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
- package/docs/retro/0132-inject-io-into-session-config.md +0 -33
- package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
- package/docs/retro/0134-reduce-as-any-casts.md +0 -56
- package/docs/retro/0135-extract-display-helpers.md +0 -38
- package/docs/retro/0136-decompose-agent-menu.md +0 -43
- package/docs/retro/0144-consolidate-observation-model.md +0 -39
- package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
- package/docs/retro/0146-narrow-ui-context.md +0 -70
- package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
- package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
- package/docs/retro/0152-add-prompt-snippet.md +0 -34
- package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
- package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
- package/docs/retro/0166-extract-parent-session-info.md +0 -66
- package/docs/retro/0167-narrow-runner-io.md +0 -63
- package/docs/retro/0168-extract-tool-filter-config.md +0 -76
- package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
- package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
- package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
- package/docs/retro/0172-extract-turn-formatting.md +0 -80
- package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
- package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
- package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
- package/docs/retro/0192-define-session-context-interface.md +0 -59
- package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
- package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
- package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
- package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
- package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
- package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
- package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
- package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
- package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
- package/docs/retro/0215-decompose-build-parent-context.md +0 -61
- package/docs/retro/0216-decompose-start-agent.md +0 -80
- package/docs/retro/0217-extract-overwrite-guard.md +0 -63
- package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
- package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
- package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
- package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
- package/docs/retro/0229-agent-born-complete.md +0 -89
- package/docs/retro/0230-extract-concurrency-queue.md +0 -38
- package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
- package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
- package/docs/retro/0237-remove-disallowed-tools.md +0 -78
- package/docs/retro/0238-remove-extensions-filtering.md +0 -72
- package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
- package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
- package/docs/retro/0256-extract-worktree-isolation.md +0 -89
- package/docs/retro/0257-extract-child-session-factory.md +0 -33
- package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
- package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
- package/docs/retro/0265-born-complete-subagent-session.md +0 -97
- package/docs/retro/0270-type-consumable-public-surface.md +0 -108
- package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
- package/docs/retro/0277-encapsulate-agent-session.md +0 -80
- package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
- package/docs/retro/0360-custom-agents-default-append.md +0 -81
- package/docs/retro/0373-extract-subagent-state.md +0 -94
- package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
- package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
- package/docs/retro/0376-extract-manager-observer.md +0 -81
- package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
- package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
- package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
- package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
- package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
- package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
- package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
- package/docs/retro/0412-unify-session-mock-builders.md +0 -80
- package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
- package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
- package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
- package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
- package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
- package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
- package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
- package/docs/retro/0427-reconsider-ui-direction.md +0 -102
- package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -97
- package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
- package/docs/retro/0443-consolidate-remaining-test-clone-families.md +0 -28
- package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
- package/docs/retro/0445-native-session-navigation.md +0 -122
- package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
- package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
- package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
- package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
- package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
- package/docs/retro/0470-refresh-readme-command-surface.md +0 -40
- package/src/observation/notification-state.ts +0 -27
- package/vitest.config.ts +0 -14
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 80
|
|
3
|
-
issue_title: "refactor: consolidate getConfig / getAgentConfig into a single resolution path"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Consolidate agent config lookup into resolveAgentConfig
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
`agent-types.ts` exports two overlapping lookup functions:
|
|
11
|
-
|
|
12
|
-
- `getConfig(type)` — returns a narrow shape (`displayName`, `description`, `builtinToolNames`, `extensions`, `skills`, `promptMode`) with a guaranteed-non-null fallback chain (unknown → general-purpose → absolute fallback).
|
|
13
|
-
- `getAgentConfig(type)` — returns the full `AgentConfig | undefined`.
|
|
14
|
-
|
|
15
|
-
Every field `getConfig()` returns also exists on `AgentConfig`.
|
|
16
|
-
Callers that need both must call both and keep them in sync:
|
|
17
|
-
|
|
18
|
-
```typescript
|
|
19
|
-
const config = getConfig(type);
|
|
20
|
-
const agentConfig = getAgentConfig(type);
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
This showed up concretely in `session-config.ts` (extracted in #71), where the assembler calls both, then handles the `agentConfig === undefined` fallback separately — duplicating the same fallback chain that `getConfig()` already handles internally.
|
|
24
|
-
Test mocks must also set up both `mockGetConfig` and `mockGetAgentConfig` with compatible values, which is error-prone.
|
|
25
|
-
|
|
26
|
-
## Goals
|
|
27
|
-
|
|
28
|
-
- Add a single `resolveAgentConfig(type): AgentConfig` function that returns a guaranteed-non-null `AgentConfig`, handling the fallback chain internally (unknown → general-purpose → absolute fallback).
|
|
29
|
-
- Migrate all callers of `getConfig()` and `getAgentConfig()` to `resolveAgentConfig()`.
|
|
30
|
-
- Remove `getConfig()` and `getAgentConfig()`.
|
|
31
|
-
- Simplify test mocks from two compatible stubs to one.
|
|
32
|
-
|
|
33
|
-
This is a pure internal refactor — no behavior change, no public API impact (the package's `exports` only expose `service.ts`).
|
|
34
|
-
|
|
35
|
-
## Non-Goals
|
|
36
|
-
|
|
37
|
-
- Changing the `AgentConfig` type shape.
|
|
38
|
-
- Refactoring `getToolNamesForType()` (it has its own lookup logic and is a separate concern).
|
|
39
|
-
- Modifying the public API surface (`service.ts`).
|
|
40
|
-
- Changing the fallback semantics (the chain stays: type → general-purpose → absolute fallback).
|
|
41
|
-
|
|
42
|
-
## Background
|
|
43
|
-
|
|
44
|
-
### Relevant modules
|
|
45
|
-
|
|
46
|
-
| Module | Role |
|
|
47
|
-
| --------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
48
|
-
| `agent-types.ts` | Unified agent type registry — owns `getConfig`, `getAgentConfig`, `resolveType`, `getToolNamesForType`, `isValidType` |
|
|
49
|
-
| `session-config.ts` | Pure configuration assembler — calls both `getConfig` + `getAgentConfig` |
|
|
50
|
-
| `ui/agent-widget.ts` | Widget rendering — calls `getConfig` via `getDisplayName()` and `getPromptModeLabel()` helpers |
|
|
51
|
-
| `index.ts` | Extension entry point — calls `getAgentConfig` (3 sites) for type listing and model label |
|
|
52
|
-
| `tools/agent-tool.ts` | Agent tool handler — calls `getAgentConfig` (1 site) after `resolveType()` |
|
|
53
|
-
| `ui/agent-menu.ts` | Agent menu UI — calls `getAgentConfig` (5 sites) for listing, detail, and existence checks |
|
|
54
|
-
|
|
55
|
-
### Current caller inventory
|
|
56
|
-
|
|
57
|
-
Source files that import `getConfig` or `getAgentConfig`:
|
|
58
|
-
|
|
59
|
-
| File | `getConfig` calls | `getAgentConfig` calls | Notes |
|
|
60
|
-
| --------------------- | ----------------- | ---------------------- | --------------------------------------------- |
|
|
61
|
-
| `session-config.ts` | 1 | 1 | Primary motivation; dual-call pattern |
|
|
62
|
-
| `ui/agent-widget.ts` | 2 (via helpers) | 0 | `getDisplayName()`, `getPromptModeLabel()` |
|
|
63
|
-
| `index.ts` | 0 | 3 | Iterates known names; `?.` is defensive |
|
|
64
|
-
| `tools/agent-tool.ts` | 0 | 1 | After `resolveType()` — guaranteed to exist |
|
|
65
|
-
| `ui/agent-menu.ts` | 0 | 5 | 3 iterate known names; 2 are existence guards |
|
|
66
|
-
|
|
67
|
-
Test files that mock `agent-types.js` with both functions:
|
|
68
|
-
|
|
69
|
-
| Test file | Mocks `getConfig` | Mocks `getAgentConfig` |
|
|
70
|
-
| -------------------------------------- | ----------------- | ---------------------- |
|
|
71
|
-
| `session-config.test.ts` | ✓ | ✓ |
|
|
72
|
-
| `agent-runner.test.ts` | ✓ | ✓ |
|
|
73
|
-
| `agent-runner-extension-tools.test.ts` | ✓ | ✓ |
|
|
74
|
-
|
|
75
|
-
### Caller migration notes
|
|
76
|
-
|
|
77
|
-
- **`session-config.ts`**: Replace both calls with one `resolveAgentConfig(type)`.
|
|
78
|
-
Read `extensions` and `skills` directly from the returned `AgentConfig` instead of the narrow shape.
|
|
79
|
-
The prompt-building fallback (`agentConfig` null → use `DEFAULT_AGENTS.get("general-purpose")`) collapses into the single call since `resolveAgentConfig` already handles the fallback.
|
|
80
|
-
- **`ui/agent-widget.ts`**: `getDisplayName()` becomes `resolveAgentConfig(type).displayName ?? resolveAgentConfig(type).name` (or cache the result).
|
|
81
|
-
`getPromptModeLabel()` reads `.promptMode` from the resolved config.
|
|
82
|
-
- **`index.ts`**: All 3 call sites iterate names from `getDefaultAgentNames()` or `getUserAgentNames()` — configs are guaranteed to exist.
|
|
83
|
-
Direct replacement with `resolveAgentConfig()`.
|
|
84
|
-
- **`tools/agent-tool.ts`**: Called after `resolveType()` — config guaranteed.
|
|
85
|
-
Direct replacement.
|
|
86
|
-
- **`ui/agent-menu.ts`**: 3 of 5 calls iterate `getAllTypes()` — configs guaranteed.
|
|
87
|
-
The 2 defensive existence guards (lines 187, 248) switch to `resolveType(name) != null` checks, then use `resolveAgentConfig()` for the config.
|
|
88
|
-
|
|
89
|
-
### Constraints from AGENTS.md
|
|
90
|
-
|
|
91
|
-
- Keep modules focused and composable (one concern per file).
|
|
92
|
-
- Prefer explicit configuration over hidden behavior.
|
|
93
|
-
- Use `vi.hoisted()` for module-level mocks, `.mockClear()` when the factory provides a default.
|
|
94
|
-
- Run `pnpm run check` after interface changes.
|
|
95
|
-
|
|
96
|
-
## Design Overview
|
|
97
|
-
|
|
98
|
-
### `resolveAgentConfig` semantics
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
export function resolveAgentConfig(type: string): AgentConfig
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
1. Case-insensitive key lookup via `resolveKey(type)`.
|
|
105
|
-
2. If found and `enabled !== false`, return the `AgentConfig`.
|
|
106
|
-
3. Fallback to `general-purpose` (if present and enabled).
|
|
107
|
-
4. Absolute fallback: a synthetic `AgentConfig` with safe defaults (same values as today's `getConfig` absolute fallback, plus the missing `AgentConfig` fields like `name`, `systemPrompt`).
|
|
108
|
-
|
|
109
|
-
The function is pure (reads from the module-level `agents` map) and deterministic.
|
|
110
|
-
|
|
111
|
-
### Absolute fallback shape
|
|
112
|
-
|
|
113
|
-
The absolute fallback is a complete `AgentConfig` synthesized inline, matching the current `getConfig` absolute fallback values plus required `AgentConfig` fields:
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
{
|
|
117
|
-
name: type,
|
|
118
|
-
displayName: "Agent",
|
|
119
|
-
description: "General-purpose agent for complex, multi-step tasks",
|
|
120
|
-
builtinToolNames: BUILTIN_TOOL_NAMES,
|
|
121
|
-
extensions: true,
|
|
122
|
-
skills: true,
|
|
123
|
-
systemPrompt: "",
|
|
124
|
-
promptMode: "append",
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### session-config.ts simplification
|
|
129
|
-
|
|
130
|
-
Before (two calls, two variables, null-check branching):
|
|
131
|
-
|
|
132
|
-
```typescript
|
|
133
|
-
const config = getConfig(type);
|
|
134
|
-
const agentConfig = getAgentConfig(type);
|
|
135
|
-
// ...
|
|
136
|
-
const extensions = options.isolated ? false : config.extensions;
|
|
137
|
-
const skills = options.isolated ? false : config.skills;
|
|
138
|
-
// ...
|
|
139
|
-
if (agentConfig) {
|
|
140
|
-
systemPrompt = buildAgentPrompt(agentConfig, ...);
|
|
141
|
-
} else {
|
|
142
|
-
const fallback = DEFAULT_AGENTS.get("general-purpose");
|
|
143
|
-
systemPrompt = buildAgentPrompt({ ...fallback, name: type }, ...);
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
After (one call, no null checks):
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
const agentConfig = resolveAgentConfig(type);
|
|
151
|
-
// ...
|
|
152
|
-
const extensions = options.isolated ? false : agentConfig.extensions;
|
|
153
|
-
const skills = options.isolated ? false : agentConfig.skills;
|
|
154
|
-
// ...
|
|
155
|
-
systemPrompt = buildAgentPrompt(agentConfig, ...);
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
The `DEFAULT_AGENTS` import in `session-config.ts` becomes unnecessary.
|
|
159
|
-
|
|
160
|
-
## Module-Level Changes
|
|
161
|
-
|
|
162
|
-
### `src/agent-types.ts`
|
|
163
|
-
|
|
164
|
-
- **Add** `resolveAgentConfig(type: string): AgentConfig` — guaranteed-non-null lookup with fallback chain.
|
|
165
|
-
- **Remove** `getConfig(type)` — replaced by `resolveAgentConfig`.
|
|
166
|
-
- **Remove** `getAgentConfig(type)` — replaced by `resolveAgentConfig`.
|
|
167
|
-
|
|
168
|
-
### `src/session-config.ts`
|
|
169
|
-
|
|
170
|
-
- **Change** imports: replace `getConfig`, `getAgentConfig` with `resolveAgentConfig`.
|
|
171
|
-
- **Remove** `DEFAULT_AGENTS` import (no longer needed for the unknown-type fallback prompt path).
|
|
172
|
-
- **Simplify** `assembleSessionConfig()`: one `resolveAgentConfig(type)` call replaces two; remove the `if (agentConfig)` / `else` branch for prompt building.
|
|
173
|
-
|
|
174
|
-
### `src/ui/agent-widget.ts`
|
|
175
|
-
|
|
176
|
-
- **Change** import: replace `getConfig` with `resolveAgentConfig`.
|
|
177
|
-
- **Update** `getDisplayName()`: `const config = resolveAgentConfig(type); return config.displayName ?? config.name;`.
|
|
178
|
-
- **Update** `getPromptModeLabel()`: read `promptMode` from resolved config.
|
|
179
|
-
|
|
180
|
-
### `src/index.ts`
|
|
181
|
-
|
|
182
|
-
- **Change** import: replace `getAgentConfig` with `resolveAgentConfig`.
|
|
183
|
-
- **Update** 3 call sites: direct replacement (all iterate known names).
|
|
184
|
-
|
|
185
|
-
### `src/tools/agent-tool.ts`
|
|
186
|
-
|
|
187
|
-
- **Change** import: replace `getAgentConfig` with `resolveAgentConfig`.
|
|
188
|
-
- **Update** 1 call site: direct replacement (type already resolved via `resolveType()`).
|
|
189
|
-
|
|
190
|
-
### `src/ui/agent-menu.ts`
|
|
191
|
-
|
|
192
|
-
- **Change** import: replace `getAgentConfig` with `resolveAgentConfig`, add `resolveType` if not already imported.
|
|
193
|
-
- **Update** 5 call sites: 3 are direct replacements; 2 existence guards switch to `resolveType(name) != null` before calling `resolveAgentConfig()`.
|
|
194
|
-
|
|
195
|
-
### Test files
|
|
196
|
-
|
|
197
|
-
- **`test/agent-types.test.ts`**: Add tests for `resolveAgentConfig`; remove tests for `getConfig` and `getAgentConfig`.
|
|
198
|
-
- **`test/session-config.test.ts`**: Replace `mockGetConfig` + `mockGetAgentConfig` with a single `mockResolveAgentConfig`; remove all `mockGetConfig` usages.
|
|
199
|
-
- **`test/agent-runner.test.ts`**: Update `vi.mock("../src/agent-types.js")` factory: replace `getConfig` + `getAgentConfig` with `resolveAgentConfig`.
|
|
200
|
-
- **`test/agent-runner-extension-tools.test.ts`**: Same mock update as above.
|
|
201
|
-
|
|
202
|
-
## Test Impact Analysis
|
|
203
|
-
|
|
204
|
-
1. **New unit tests enabled**: `resolveAgentConfig` gets focused tests for the fallback chain (unknown → general-purpose → absolute fallback), case-insensitive lookup, and disabled-type fallback.
|
|
205
|
-
These replace the scattered `getConfig` fallback tests in `agent-types.test.ts`.
|
|
206
|
-
2. **Redundant tests**: `getConfig`-specific tests (return shape, fallback, extension allowlist) become redundant since `resolveAgentConfig` returns the full `AgentConfig` directly.
|
|
207
|
-
Remove them.
|
|
208
|
-
3. **Tests that must stay**: `agent-types.test.ts` tests for `registerAgents`, `resolveType`, `isValidType`, `getAvailableTypes`, `getAllTypes`, `getToolNamesForType`, `getMemoryToolNames`, `getReadOnlyMemoryToolNames` are unaffected.
|
|
209
|
-
`session-config.test.ts` tests all stay — they test assembler behavior, just with a simpler mock setup.
|
|
210
|
-
|
|
211
|
-
## TDD Order
|
|
212
|
-
|
|
213
|
-
1. **Add `resolveAgentConfig` with tests** — add the function to `agent-types.ts` alongside existing functions.
|
|
214
|
-
Tests: known type returns config; unknown type falls back to general-purpose; disabled type falls back; absolute fallback when general-purpose is missing; case-insensitive lookup.
|
|
215
|
-
Commit: `feat: add resolveAgentConfig with guaranteed-non-null fallback chain`.
|
|
216
|
-
|
|
217
|
-
2. **Migrate `session-config.ts` and its tests** — replace `getConfig` + `getAgentConfig` imports with `resolveAgentConfig`; remove `DEFAULT_AGENTS` import; simplify the assembler body (one call, no null-check branch).
|
|
218
|
-
Update `session-config.test.ts`: replace `mockGetConfig` + `mockGetAgentConfig` with single `mockResolveAgentConfig`; update all test setups.
|
|
219
|
-
Commit: `refactor: migrate session-config to resolveAgentConfig`.
|
|
220
|
-
|
|
221
|
-
3. **Migrate `agent-widget.ts`** — update `getDisplayName()` and `getPromptModeLabel()` to use `resolveAgentConfig`.
|
|
222
|
-
Commit: `refactor: migrate agent-widget to resolveAgentConfig`.
|
|
223
|
-
|
|
224
|
-
4. **Migrate remaining source callers** — update `index.ts` (3 sites), `tools/agent-tool.ts` (1 site), `ui/agent-menu.ts` (5 sites, including 2 existence-guard rewrites).
|
|
225
|
-
Commit: `refactor: migrate remaining callers to resolveAgentConfig`.
|
|
226
|
-
|
|
227
|
-
5. **Update transitive test mocks** — update `agent-runner.test.ts` and `agent-runner-extension-tools.test.ts` mock factories to export `resolveAgentConfig` instead of `getConfig` + `getAgentConfig`.
|
|
228
|
-
Commit: `test: update agent-runner test mocks for resolveAgentConfig`.
|
|
229
|
-
|
|
230
|
-
6. **Remove `getConfig` and `getAgentConfig`** — delete both functions from `agent-types.ts`; remove their tests from `agent-types.test.ts`.
|
|
231
|
-
Run `pnpm run check` to verify no remaining references.
|
|
232
|
-
Commit: `refactor: remove getConfig and getAgentConfig`.
|
|
233
|
-
|
|
234
|
-
## Risks and Mitigations
|
|
235
|
-
|
|
236
|
-
| Risk | Mitigation |
|
|
237
|
-
| ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
238
|
-
| Overlooked caller of removed functions | Grep all `src/` and `test/` files for `getConfig` and `getAgentConfig` before the removal step; `pnpm run check` catches any remaining imports. |
|
|
239
|
-
| `agent-menu.ts` existence guards behave differently with `resolveType()` | `resolveType()` is already the canonical existence check used by `agent-tool.ts`; the guard semantics are identical. |
|
|
240
|
-
| Absolute fallback `AgentConfig` shape drift | The absolute fallback is a single inline literal — any future `AgentConfig` field additions will cause a type error at the definition site. |
|
|
241
|
-
| Test mock compatibility during migration | Lift-and-shift: `resolveAgentConfig` coexists with old functions until all callers are migrated; each step leaves tests green. |
|
|
242
|
-
|
|
243
|
-
## Open Questions
|
|
244
|
-
|
|
245
|
-
- `getToolNamesForType()` does its own lookup with similar fallback logic.
|
|
246
|
-
It could be simplified to delegate to `resolveAgentConfig()`, but that is out of scope for this issue.
|
|
247
|
-
Consider a follow-up if the duplication becomes a maintenance concern.
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 84
|
|
3
|
-
issue_title: "refactor: extract GitWorktreeManager class from worktree.ts free functions"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Extract GitWorktreeManager class
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
`worktree.ts` exports three free functions — `createWorktree(cwd, id)`, `cleanupWorktree(cwd, wt, desc)`, and `pruneWorktrees(cwd)` — that all operate on git worktrees relative to a repository root.
|
|
11
|
-
Every caller threads `cwd` as the first argument.
|
|
12
|
-
These functions form a cohesive unit with natural shared state (the repo root), but today there is no object to capture it.
|
|
13
|
-
|
|
14
|
-
Issue #72 (dependency-inject `AgentManager`'s collaborators) needs a `WorktreeManager` interface to inject.
|
|
15
|
-
Extracting the class first keeps #72 a clean DI + constructor refactor instead of mixing object extraction with dependency injection.
|
|
16
|
-
|
|
17
|
-
## Goals
|
|
18
|
-
|
|
19
|
-
- Define a `WorktreeManager` interface in `worktree.ts` with three methods: `create(id)`, `cleanup(wt, desc)`, `prune()` — no `cwd` parameter.
|
|
20
|
-
- Add a `GitWorktreeManager` class that captures `cwd` at construction and delegates to the existing free functions.
|
|
21
|
-
- Export both the interface and the class.
|
|
22
|
-
- Existing free functions stay exported and unchanged.
|
|
23
|
-
- No behavior change.
|
|
24
|
-
|
|
25
|
-
## Non-Goals
|
|
26
|
-
|
|
27
|
-
- Changing `AgentManager` to use the new class (that is #72).
|
|
28
|
-
- Refactoring the internal implementation of `createWorktree`, `cleanupWorktree`, or `pruneWorktrees`.
|
|
29
|
-
- Publishing `WorktreeManager` as a cross-extension API via `Symbol.for()` — it is internal to this package.
|
|
30
|
-
|
|
31
|
-
## Background
|
|
32
|
-
|
|
33
|
-
### Prerequisites
|
|
34
|
-
|
|
35
|
-
None — this is the first step in the #72 dependency chain.
|
|
36
|
-
|
|
37
|
-
### Relevant modules
|
|
38
|
-
|
|
39
|
-
| Module | Role |
|
|
40
|
-
| ----------------------- | ---------------------------------------------------------- |
|
|
41
|
-
| `src/worktree.ts` | Free functions for git worktree create/cleanup/prune |
|
|
42
|
-
| `test/worktree.test.ts` | Integration tests that create real git repos and worktrees |
|
|
43
|
-
| `src/agent-manager.ts` | Only consumer of the three free functions (6 call sites) |
|
|
44
|
-
|
|
45
|
-
### Constraints from AGENTS.md / code-style
|
|
46
|
-
|
|
47
|
-
- Keep modules focused and composable (one concern per file).
|
|
48
|
-
- When a shared interface references a collaborator, use a narrow interface type — not the concrete class.
|
|
49
|
-
- Business logic should be pure functions wherever possible — keep IO at the edges.
|
|
50
|
-
|
|
51
|
-
The free functions are IO (they shell out to `git`), so wrapping them in a class that captures `cwd` is the right level of abstraction — the class is a thin adapter, not business logic.
|
|
52
|
-
|
|
53
|
-
## Design Overview
|
|
54
|
-
|
|
55
|
-
### Interface and class
|
|
56
|
-
|
|
57
|
-
Added at the bottom of `worktree.ts`, after the existing free functions:
|
|
58
|
-
|
|
59
|
-
```typescript
|
|
60
|
-
export interface WorktreeManager {
|
|
61
|
-
create(id: string): WorktreeInfo | undefined;
|
|
62
|
-
cleanup(wt: WorktreeInfo, description: string): WorktreeCleanupResult;
|
|
63
|
-
prune(): void;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export class GitWorktreeManager implements WorktreeManager {
|
|
67
|
-
constructor(private readonly cwd: string) {}
|
|
68
|
-
|
|
69
|
-
create(id: string): WorktreeInfo | undefined {
|
|
70
|
-
return createWorktree(this.cwd, id);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
cleanup(wt: WorktreeInfo, description: string): WorktreeCleanupResult {
|
|
74
|
-
return cleanupWorktree(this.cwd, wt, description);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
prune(): void {
|
|
78
|
-
pruneWorktrees(this.cwd);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Why the interface lives in `worktree.ts`
|
|
84
|
-
|
|
85
|
-
The `WorktreeManager` interface references `WorktreeInfo` and `WorktreeCleanupResult`, which are already defined in `worktree.ts`.
|
|
86
|
-
Co-locating avoids a separate file for a 5-line interface.
|
|
87
|
-
This matches the #72 plan's expectation: `import type { WorktreeManager } from "./worktree.js"`.
|
|
88
|
-
|
|
89
|
-
### No changes to callers
|
|
90
|
-
|
|
91
|
-
`agent-manager.ts` continues importing and calling the free functions directly.
|
|
92
|
-
Issue #72 handles the migration to the injected `WorktreeManager`.
|
|
93
|
-
|
|
94
|
-
## Module-Level Changes
|
|
95
|
-
|
|
96
|
-
### `src/worktree.ts` (modified)
|
|
97
|
-
|
|
98
|
-
- Add `WorktreeManager` interface (3 methods).
|
|
99
|
-
- Add `GitWorktreeManager` class implementing the interface.
|
|
100
|
-
- Existing free functions, types, and imports unchanged.
|
|
101
|
-
|
|
102
|
-
### `test/worktree.test.ts` (modified)
|
|
103
|
-
|
|
104
|
-
- Add a new `describe("GitWorktreeManager")` block with tests for the class.
|
|
105
|
-
- Existing free-function tests stay as-is.
|
|
106
|
-
|
|
107
|
-
## Test Impact Analysis
|
|
108
|
-
|
|
109
|
-
### New unit tests enabled
|
|
110
|
-
|
|
111
|
-
1. `GitWorktreeManager.create` — delegates to `createWorktree` with the captured `cwd`.
|
|
112
|
-
2. `GitWorktreeManager.cleanup` — delegates to `cleanupWorktree` with the captured `cwd`.
|
|
113
|
-
3. `GitWorktreeManager.prune` — delegates to `pruneWorktrees` with the captured `cwd`.
|
|
114
|
-
|
|
115
|
-
These are thin delegation tests that verify the class wires `cwd` correctly.
|
|
116
|
-
They reuse the same real-git-repo test infrastructure already in `worktree.test.ts`.
|
|
117
|
-
|
|
118
|
-
### Existing tests
|
|
119
|
-
|
|
120
|
-
All existing tests in `worktree.test.ts` stay unchanged — they test the free functions directly.
|
|
121
|
-
|
|
122
|
-
## TDD Order
|
|
123
|
-
|
|
124
|
-
1. **RED:** Add `describe("GitWorktreeManager")` with tests for `create`, `cleanup`, and `prune`.
|
|
125
|
-
Tests import `GitWorktreeManager` which does not exist yet — compilation fails.
|
|
126
|
-
Commit: `test: add GitWorktreeManager tests`
|
|
127
|
-
|
|
128
|
-
2. **GREEN:** Add `WorktreeManager` interface and `GitWorktreeManager` class to `worktree.ts`.
|
|
129
|
-
All tests pass.
|
|
130
|
-
Run `pnpm run check` to verify types.
|
|
131
|
-
Commit: `feat: extract WorktreeManager interface and GitWorktreeManager class (#84)`
|
|
132
|
-
|
|
133
|
-
## Risks and Mitigations
|
|
134
|
-
|
|
135
|
-
| Risk | Mitigation |
|
|
136
|
-
| ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
137
|
-
| Class delegation tests are slow because they create real git repos | The existing test suite already does this; the new tests reuse the same `initGitRepo()` helper and add ~3 test cases to an already-fast suite. |
|
|
138
|
-
| Future callers bypass the interface and use `GitWorktreeManager` directly | The #72 plan types `AgentManager`'s constructor parameter as `WorktreeManager` (the interface), not the class. Code review enforces this. |
|
|
139
|
-
|
|
140
|
-
## Open Questions
|
|
141
|
-
|
|
142
|
-
None — the interface shape is specified by the issue and matches the #72 plan exactly.
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 87
|
|
3
|
-
issue_title: "refactor: evolve SubagentRuntime from data bag to object with methods"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Evolve SubagentRuntime from data bag to object with methods
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
`SubagentRuntime` (introduced in #69) consolidates all mutable extension state into one object, but it remains a plain data bag — an interface with public mutable fields and no methods.
|
|
11
|
-
This causes two structural smells in `index.ts`:
|
|
12
|
-
|
|
13
|
-
1. **Output arguments** — handlers write raw fields on the runtime instead of calling methods:
|
|
14
|
-
`runtime.currentCtx = { pi, ctx }` and `runtime.currentCtx = undefined`.
|
|
15
|
-
2. **Law of Demeter violations** — 8 occurrences of `runtime.widget!.method()` across 4 call sites in `index.ts`, where callers reach through the runtime to talk to the widget with unsafe `!` non-null assertions.
|
|
16
|
-
|
|
17
|
-
Issue #70 (extract event handlers) explicitly lists this issue as a prerequisite.
|
|
18
|
-
Without these methods, extracted handlers would just move the output-argument and LoD smells from `index.ts` into handler classes.
|
|
19
|
-
|
|
20
|
-
## Goals
|
|
21
|
-
|
|
22
|
-
- Convert `SubagentRuntime` from an interface + factory to a class with methods.
|
|
23
|
-
- Add session-context methods: `setSessionContext(pi, ctx)` and `clearSessionContext()`.
|
|
24
|
-
- Add widget delegation methods that absorb the `runtime.widget!` reach-throughs: `setUICtx()`, `onTurnStart()`, `markFinished()`, `updateWidget()`, `ensureTimer()`.
|
|
25
|
-
- Update all 10 call sites in `index.ts` to use the new methods — eliminate raw `currentCtx` field writes and `widget!` assertions.
|
|
26
|
-
- No behavior change; pure structural refactor.
|
|
27
|
-
|
|
28
|
-
## Non-Goals
|
|
29
|
-
|
|
30
|
-
- Extracting event handlers into separate files (that is #70).
|
|
31
|
-
- Adding methods for `defaultMaxTurns` / `graceTurns` writes — those field writes remain as-is; the issue scope covers `currentCtx` and `widget!` only.
|
|
32
|
-
- Changing the `SubagentsService` interface.
|
|
33
|
-
- Making `widget` private — `index.ts` still assigns `runtime.widget = new AgentWidget(...)` after construction.
|
|
34
|
-
- Adding new features.
|
|
35
|
-
|
|
36
|
-
## Background
|
|
37
|
-
|
|
38
|
-
### Prior art
|
|
39
|
-
|
|
40
|
-
`pi-permission-system`'s `PermissionSession` is a class with lifecycle methods (`refreshConfig`, `resetForNewSession`, `shutdown`).
|
|
41
|
-
Lifecycle handlers in `src/handlers/lifecycle.ts` call those methods instead of writing fields.
|
|
42
|
-
This issue brings `SubagentRuntime` to the same level.
|
|
43
|
-
|
|
44
|
-
### Current runtime shape
|
|
45
|
-
|
|
46
|
-
`src/runtime.ts` exports a `SubagentRuntime` interface and a `createSubagentRuntime()` factory:
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
export interface SubagentRuntime {
|
|
50
|
-
defaultMaxTurns: number | undefined;
|
|
51
|
-
graceTurns: number;
|
|
52
|
-
currentCtx: { pi: unknown; ctx: unknown } | undefined;
|
|
53
|
-
readonly agentActivity: Map<string, AgentActivity>;
|
|
54
|
-
widget: AgentWidget | null;
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Call sites to migrate
|
|
59
|
-
|
|
60
|
-
Two `currentCtx` writes (output arguments):
|
|
61
|
-
|
|
62
|
-
| Line | Current | After |
|
|
63
|
-
| ---- | ---------------------------------- | ------------------------------------ |
|
|
64
|
-
| 126 | `runtime.currentCtx = { pi, ctx }` | `runtime.setSessionContext(pi, ctx)` |
|
|
65
|
-
| 138 | `runtime.currentCtx = undefined` | `runtime.clearSessionContext()` |
|
|
66
|
-
|
|
67
|
-
Eight `widget!` reach-throughs (LoD violations):
|
|
68
|
-
|
|
69
|
-
| Line | Current | After |
|
|
70
|
-
| ---- | ------------------------------------------- | ----------------------------------- |
|
|
71
|
-
| 60 | `runtime.widget!.markFinished(id)` | `runtime.markFinished(id)` |
|
|
72
|
-
| 61 | `runtime.widget!.update()` | `runtime.updateWidget()` |
|
|
73
|
-
| 149 | `runtime.widget!.setUICtx(ctx.ui as UICtx)` | `runtime.setUICtx(ctx.ui as UICtx)` |
|
|
74
|
-
| 150 | `runtime.widget!.onTurnStart()` | `runtime.onTurnStart()` |
|
|
75
|
-
| 204 | `runtime.widget!.setUICtx(ctx as UICtx)` | `runtime.setUICtx(ctx as UICtx)` |
|
|
76
|
-
| 205 | `runtime.widget!.ensureTimer()` | `runtime.ensureTimer()` |
|
|
77
|
-
| 206 | `runtime.widget!.update()` | `runtime.updateWidget()` |
|
|
78
|
-
| 207 | `runtime.widget!.markFinished(id)` | `runtime.markFinished(id)` |
|
|
79
|
-
|
|
80
|
-
### Dependency chain
|
|
81
|
-
|
|
82
|
-
Issue #69 (SubagentRuntime) is closed/implemented.
|
|
83
|
-
This issue (#87) is a prerequisite for #70 (extract event handlers).
|
|
84
|
-
The #70 plan defines narrow handler interfaces (`LifecycleRuntime`, `ToolStartRuntime`) that the runtime class satisfies structurally.
|
|
85
|
-
|
|
86
|
-
### Relevant constraints from AGENTS.md / code-style skill
|
|
87
|
-
|
|
88
|
-
- Keep modules focused and composable (one concern per file).
|
|
89
|
-
- Do not pass a shared dependency bag to functions that only use a subset — define narrow interfaces per consumer.
|
|
90
|
-
- Do not write back into a received dependency bag (output arguments).
|
|
91
|
-
- Do not reach through an injected collaborator to talk to a stranger (Law of Demeter).
|
|
92
|
-
- When multiple callers perform the same reach-through, the missing abstraction is a method on the intermediate object that delegates internally.
|
|
93
|
-
|
|
94
|
-
## Design Overview
|
|
95
|
-
|
|
96
|
-
### Class conversion
|
|
97
|
-
|
|
98
|
-
Convert `SubagentRuntime` from an interface to a class.
|
|
99
|
-
Public fields stay as-is — callers that read `runtime.defaultMaxTurns`, `runtime.currentCtx`, `runtime.agentActivity`, etc. continue to work.
|
|
100
|
-
The `createSubagentRuntime()` factory becomes a thin alias returning `new SubagentRuntime()`, preserving backward compatibility for `index.ts` and existing tests during the transition.
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
export class SubagentRuntime {
|
|
104
|
-
defaultMaxTurns: number | undefined = undefined;
|
|
105
|
-
graceTurns: number = 5;
|
|
106
|
-
currentCtx: { pi: unknown; ctx: unknown } | undefined = undefined;
|
|
107
|
-
readonly agentActivity: Map<string, AgentActivity> = new Map();
|
|
108
|
-
widget: AgentWidget | null = null;
|
|
109
|
-
|
|
110
|
-
setSessionContext(pi: unknown, ctx: unknown): void {
|
|
111
|
-
this.currentCtx = { pi, ctx };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
clearSessionContext(): void {
|
|
115
|
-
this.currentCtx = undefined;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
setUICtx(ctx: UICtx): void {
|
|
119
|
-
this.widget?.setUICtx(ctx);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
onTurnStart(): void {
|
|
123
|
-
this.widget?.onTurnStart();
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
markFinished(id: string): void {
|
|
127
|
-
this.widget?.markFinished(id);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
updateWidget(): void {
|
|
131
|
-
this.widget?.update();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
ensureTimer(): void {
|
|
135
|
-
this.widget?.ensureTimer();
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### Widget delegation null safety
|
|
141
|
-
|
|
142
|
-
Current code uses `runtime.widget!.method()` — an unsafe non-null assertion that would throw if widget were null.
|
|
143
|
-
The delegation methods use optional chaining (`this.widget?.method()`), which silently no-ops when widget is null.
|
|
144
|
-
This is safe and intentional: widget is always assigned before any agent can complete, so the null path is unreachable in practice, but the delegation removes the assertion smell.
|
|
145
|
-
The #70 plan explicitly expects this behavior: "Widget null safety: after #87, the runtime's delegation methods handle null internally."
|
|
146
|
-
|
|
147
|
-
### UICtx type import
|
|
148
|
-
|
|
149
|
-
`runtime.ts` already imports `AgentActivity` and `AgentWidget` from `ui/agent-widget.ts`.
|
|
150
|
-
Adding `UICtx` to the same type import is consistent with the existing dependency.
|
|
151
|
-
`UICtx` is a lean local interface (two method signatures), not a Pi SDK type.
|
|
152
|
-
|
|
153
|
-
### What stays unchanged
|
|
154
|
-
|
|
155
|
-
- `RunConfig` interface — remains as-is.
|
|
156
|
-
- `defaultMaxTurns` / `graceTurns` field writes from settings appliers — out of scope per non-goals.
|
|
157
|
-
- `runtime.currentCtx` reads via getter callbacks (`getCtx: () => runtime.currentCtx`) — reads are not output arguments.
|
|
158
|
-
- `runtime.widget = new AgentWidget(...)` assignment — `widget` stays public.
|
|
159
|
-
- `agentActivity` map usage across notification, tool, and menu deps — unchanged.
|
|
160
|
-
|
|
161
|
-
## Module-Level Changes
|
|
162
|
-
|
|
163
|
-
### `src/runtime.ts` (modified)
|
|
164
|
-
|
|
165
|
-
- Convert `SubagentRuntime` from `export interface` to `export class` with field initializers.
|
|
166
|
-
- Add `setSessionContext(pi, ctx)` and `clearSessionContext()` methods.
|
|
167
|
-
- Add `setUICtx(ctx)`, `onTurnStart()`, `markFinished(id)`, `updateWidget()`, `ensureTimer()` delegation methods.
|
|
168
|
-
- Add `UICtx` to the existing type import from `./ui/agent-widget.js`.
|
|
169
|
-
- Keep `createSubagentRuntime()` as `() => new SubagentRuntime()` for backward compat.
|
|
170
|
-
- Keep `RunConfig` interface unchanged.
|
|
171
|
-
|
|
172
|
-
### `src/index.ts` (modified)
|
|
173
|
-
|
|
174
|
-
- Replace `runtime.currentCtx = { pi, ctx }` with `runtime.setSessionContext(pi, ctx)` (line 126).
|
|
175
|
-
- Replace `runtime.currentCtx = undefined` with `runtime.clearSessionContext()` (line 138).
|
|
176
|
-
- Replace all 8 `runtime.widget!.method()` reach-throughs with `runtime.method()` delegation calls (lines 60, 61, 149, 150, 204–207).
|
|
177
|
-
- No import changes needed — `runtime` is already imported via the factory.
|
|
178
|
-
|
|
179
|
-
### `test/runtime.test.ts` (modified)
|
|
180
|
-
|
|
181
|
-
- Add tests for `setSessionContext` / `clearSessionContext` methods.
|
|
182
|
-
- Add tests for each widget delegation method using duck-typed widget stubs.
|
|
183
|
-
- Add test verifying delegation methods no-op when widget is null.
|
|
184
|
-
- Existing tests remain — factory defaults, field mutability, instance isolation, and widget assignment all still apply.
|
|
185
|
-
|
|
186
|
-
## Test Impact Analysis
|
|
187
|
-
|
|
188
|
-
### New unit tests enabled
|
|
189
|
-
|
|
190
|
-
1. `test/runtime.test.ts` additions — `setSessionContext` sets `currentCtx` correctly; `clearSessionContext` resets it to `undefined`.
|
|
191
|
-
2. `test/runtime.test.ts` additions — Each widget delegation method forwards to the widget's corresponding method; all delegation methods silently no-op when widget is null.
|
|
192
|
-
|
|
193
|
-
### Existing tests that become redundant
|
|
194
|
-
|
|
195
|
-
None.
|
|
196
|
-
The existing `runtime.test.ts` tests cover factory defaults, field mutability, and instance isolation — all still valid with the class conversion.
|
|
197
|
-
The "fields are independently mutable" test exercises direct field writes, which remain supported.
|
|
198
|
-
|
|
199
|
-
### Existing tests that stay as-is
|
|
200
|
-
|
|
201
|
-
- `test/runtime.test.ts` — All 5 existing tests pass unchanged (the class satisfies the same structural contract as the previous interface-based object).
|
|
202
|
-
- `test/print-mode.test.ts` — Calls `session_shutdown` via the extension's handler map; transparent to runtime internals.
|
|
203
|
-
- All other test files — No dependency on `SubagentRuntime` fields or methods.
|
|
204
|
-
|
|
205
|
-
## TDD Order
|
|
206
|
-
|
|
207
|
-
1. **Convert `SubagentRuntime` to a class; add session-context methods.**
|
|
208
|
-
Convert the interface to a class with field initializers matching current defaults.
|
|
209
|
-
Add `setSessionContext(pi, ctx)` and `clearSessionContext()` methods.
|
|
210
|
-
Update `createSubagentRuntime()` to return `new SubagentRuntime()`.
|
|
211
|
-
Add tests in `runtime.test.ts`: `setSessionContext` sets `currentCtx`; `clearSessionContext` resets to `undefined`; round-trip set→clear.
|
|
212
|
-
Run existing tests to verify no regressions.
|
|
213
|
-
Commit: `feat: add session-context methods to SubagentRuntime`
|
|
214
|
-
|
|
215
|
-
2. **Add widget delegation methods; add tests.**
|
|
216
|
-
Add `setUICtx(ctx)`, `onTurnStart()`, `markFinished(id)`, `updateWidget()`, `ensureTimer()` methods to the class.
|
|
217
|
-
Add `UICtx` to the type import from `./ui/agent-widget.js`.
|
|
218
|
-
Add tests in `runtime.test.ts`: each delegation method forwards to the widget stub; all methods no-op when widget is null.
|
|
219
|
-
Commit: `feat: add widget delegation methods to SubagentRuntime`
|
|
220
|
-
|
|
221
|
-
3. **Migrate all call sites in `index.ts` to use the new methods.**
|
|
222
|
-
Replace the 2 `currentCtx` writes with `setSessionContext` / `clearSessionContext`.
|
|
223
|
-
Replace the 8 `widget!` reach-throughs with delegation methods.
|
|
224
|
-
Run full test suite and `pnpm run check`.
|
|
225
|
-
Commit: `refactor: use SubagentRuntime methods in extension factory (#87)`
|
|
226
|
-
|
|
227
|
-
## Risks and Mitigations
|
|
228
|
-
|
|
229
|
-
| Risk | Mitigation |
|
|
230
|
-
| ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
231
|
-
| Class conversion breaks code that constructs `SubagentRuntime` as a plain object | Only `createSubagentRuntime()` constructs runtime instances (in `index.ts` and tests). The factory is updated to return `new SubagentRuntime()`. No code constructs a `{ ... } as SubagentRuntime` literal. |
|
|
232
|
-
| Widget delegation silently swallows errors when widget is null (changes behavior from throw to no-op) | The null path is unreachable in practice — widget is always assigned before any agent completes. The silent no-op is strictly safer than the `!` assertion. The #70 plan explicitly expects this behavior. |
|
|
233
|
-
| Adding `UICtx` import to `runtime.ts` increases coupling to the widget module | `runtime.ts` already imports `AgentActivity` and `AgentWidget` from the same module. `UICtx` is a lean 2-method interface, not a Pi SDK type. Coupling is minimal and consistent. |
|
|
234
|
-
| Remaining output-argument writes (`defaultMaxTurns`, `graceTurns`) are left unaddressed | Explicitly out of scope per the issue's acceptance criteria. Can be addressed in a follow-up if the pattern becomes painful. |
|
|
235
|
-
|
|
236
|
-
## Open Questions
|
|
237
|
-
|
|
238
|
-
- Should `createSubagentRuntime()` be removed in favor of `new SubagentRuntime()` directly?
|
|
239
|
-
The factory adds no value over a no-arg constructor, but removing it widens the blast radius without benefit.
|
|
240
|
-
Defer — remove it as part of #70 or a future cleanup if it feels redundant.
|