@gotgenes/pi-subagents 4.1.0 → 5.0.0
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 +29 -0
- package/docs/plans/0054-decompose-index-into-modules.md +302 -0
- package/docs/retro/0053-extract-model-resolution-from-execute.md +30 -0
- package/docs/retro/0054-decompose-index-into-modules.md +38 -0
- package/package.json +6 -6
- package/src/index.ts +88 -1442
- package/src/notification.ts +188 -0
- package/src/renderer.ts +67 -0
- package/src/tools/agent-tool.ts +634 -0
- package/src/tools/get-result-tool.ts +99 -0
- package/src/tools/helpers.ts +21 -0
- package/src/tools/steer-tool.ts +83 -0
- package/src/ui/agent-menu.ts +685 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [5.0.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v4.1.1...pi-subagents-v5.0.0) (2026-05-19)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### ⚠ BREAKING CHANGES
|
|
12
|
+
|
|
13
|
+
* All @earendil-works/pi-* peerDependencies and devDependencies now require >=0.75.0, aligning with Pi's Node 22 minimum.
|
|
14
|
+
* Minimum supported Node.js version is now >=22, aligning with Pi v0.75.0. tsconfig target raised from ES2023 to ES2024.
|
|
15
|
+
- ES2024 APIs (Promise.withResolvers, Object.groupBy, Map.groupBy, Array.fromAsync) are now allowed.
|
|
16
|
+
- @types/node catalog aligned to ^22.15.3.
|
|
17
|
+
- pi-autoformat now declares engines.node for consistency.
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* raise minimum Node.js version to 22 and bump tsconfig target to ES2024 ([98a5b01](https://github.com/gotgenes/pi-packages/commit/98a5b01ca20aa1feed14a60bfa7bb9e082c9914b))
|
|
22
|
+
* raise minimum Pi dependency to v0.75.0 ([1068329](https://github.com/gotgenes/pi-packages/commit/10683290d2a789880848bf7eb093d4307b6eff40))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Documentation
|
|
26
|
+
|
|
27
|
+
* **retro:** add retro notes for issue [#54](https://github.com/gotgenes/pi-packages/issues/54) ([d753eb3](https://github.com/gotgenes/pi-packages/commit/d753eb3f836a28f089197a45dd582dc4be88872d))
|
|
28
|
+
|
|
29
|
+
## [4.1.1](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v4.1.0...pi-subagents-v4.1.1) (2026-05-18)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Documentation
|
|
33
|
+
|
|
34
|
+
* plan decompose index.ts into tool + menu modules ([#54](https://github.com/gotgenes/pi-packages/issues/54)) ([7adf954](https://github.com/gotgenes/pi-packages/commit/7adf954f37800ace0bcc9d5eb65045e2e133e4f2))
|
|
35
|
+
* **retro:** add retro notes for issue [#53](https://github.com/gotgenes/pi-packages/issues/53) ([f8ca910](https://github.com/gotgenes/pi-packages/commit/f8ca9101576eaad8639d1bb2579f0e631a075038))
|
|
36
|
+
|
|
8
37
|
## [4.1.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v4.0.0...pi-subagents-v4.1.0) (2026-05-18)
|
|
9
38
|
|
|
10
39
|
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 54
|
|
3
|
+
issue_title: "refactor: decompose src/index.ts into tool + menu modules"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Decompose index.ts into tool and menu modules
|
|
7
|
+
|
|
8
|
+
## Problem Statement
|
|
9
|
+
|
|
10
|
+
`src/index.ts` is 1,619 lines — the single largest file in the codebase.
|
|
11
|
+
It currently holds the extension entrypoint, all three tool definitions (with full execute callbacks and render functions), the custom message renderer, the entire `/agents` interactive menu with all sub-menus, the notification/nudge system, widget and lifecycle wiring, and ~130 lines of helper functions.
|
|
12
|
+
None of this code is independently testable — it is all nested inside a single default export closure.
|
|
13
|
+
|
|
14
|
+
## Goals
|
|
15
|
+
|
|
16
|
+
- Extract each tool definition into its own module under `src/tools/`.
|
|
17
|
+
- Extract the `/agents` menu and all sub-handlers into `src/ui/agent-menu.ts`.
|
|
18
|
+
- Extract the notification message renderer into `src/renderer.ts`.
|
|
19
|
+
- Extract the completion notification system into `src/notification.ts`.
|
|
20
|
+
- Extract shared pure helpers into `src/tools/helpers.ts`.
|
|
21
|
+
- Reduce `index.ts` to a thin wire-up (~120–150 lines) that imports and assembles pieces.
|
|
22
|
+
- Enable unit testing of each extracted module via narrow dependency interfaces.
|
|
23
|
+
- No behavior change — pure extraction refactoring.
|
|
24
|
+
|
|
25
|
+
## Non-Goals
|
|
26
|
+
|
|
27
|
+
- Refactoring `agent-manager.ts`, `agent-runner.ts`, or other already-separate modules.
|
|
28
|
+
- Adding new features or changing tool behavior.
|
|
29
|
+
- Writing exhaustive test suites for every extracted module — establish foundational coverage, not completeness.
|
|
30
|
+
- Changing any public API surface (`service.ts` exports, `SubagentsService` interface).
|
|
31
|
+
|
|
32
|
+
## Background
|
|
33
|
+
|
|
34
|
+
### Current structure
|
|
35
|
+
|
|
36
|
+
Everything lives inside one `export default function (pi: ExtensionAPI)` closure.
|
|
37
|
+
State (`agentActivity`, `pendingNudges`, `widget`, `manager`, `currentCtx`) is declared as closure variables.
|
|
38
|
+
Helper functions, tool definitions, menu handlers, and lifecycle hooks are all defined in the same scope.
|
|
39
|
+
The only existing test files cover modules that were already separate (`agent-manager.test.ts`, `agent-runner.test.ts`, etc.) — there is no `index.test.ts`.
|
|
40
|
+
|
|
41
|
+
### Architecture reference
|
|
42
|
+
|
|
43
|
+
The SKILL's module dependency graph already shows `tools` and `ui/` as conceptual sub-trees under `index.ts`:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
index.ts ──wires──> agent-manager.ts
|
|
47
|
+
├── tools (Agent, get_subagent_result, steer_subagent)
|
|
48
|
+
├── ui/
|
|
49
|
+
│ ├── agent-widget.ts
|
|
50
|
+
│ └── conversation-viewer.ts
|
|
51
|
+
└── ...
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This plan makes that conceptual structure physical.
|
|
55
|
+
|
|
56
|
+
### Relevant constraints from AGENTS.md
|
|
57
|
+
|
|
58
|
+
- Keep modules focused and composable (one concern per file).
|
|
59
|
+
- Prefer small, reversible changes.
|
|
60
|
+
- Keep Pi SDK imports out of business-logic modules — tool modules are at the SDK boundary and may import SDK types; pure helpers must not.
|
|
61
|
+
- Narrow interfaces per consumer — do not pass a shared dependency bag when a function only uses a subset.
|
|
62
|
+
|
|
63
|
+
### Helper usage trace
|
|
64
|
+
|
|
65
|
+
Traced every helper function in `index.ts` to determine where it belongs:
|
|
66
|
+
|
|
67
|
+
| Helper | Used by | Destination |
|
|
68
|
+
| -------------------------- | --------------------------------------------------------- | --------------------- |
|
|
69
|
+
| `textResult` | All three tools | `tools/helpers.ts` |
|
|
70
|
+
| `formatLifetimeTokens` | All three tools + completion callback | `tools/helpers.ts` |
|
|
71
|
+
| `getModelLabelFromConfig` | `buildTypeListText` (agent tool) + `getModelLabel` (menu) | `tools/helpers.ts` |
|
|
72
|
+
| `createActivityTracker` | Agent tool execute (foreground + background) | `tools/agent-tool.ts` |
|
|
73
|
+
| `buildDetails` | Agent tool execute | `tools/agent-tool.ts` |
|
|
74
|
+
| `getStatusNote` | Agent tool execute | `tools/agent-tool.ts` |
|
|
75
|
+
| `escapeXml` | `formatTaskNotification` | `notification.ts` |
|
|
76
|
+
| `getStatusLabel` | `formatTaskNotification` | `notification.ts` |
|
|
77
|
+
| `formatTaskNotification` | `emitIndividualNudge` | `notification.ts` |
|
|
78
|
+
| `buildNotificationDetails` | `emitIndividualNudge` | `notification.ts` |
|
|
79
|
+
| `buildEventData` | Completion callback | `notification.ts` |
|
|
80
|
+
|
|
81
|
+
## Design Overview
|
|
82
|
+
|
|
83
|
+
### Extraction strategy
|
|
84
|
+
|
|
85
|
+
Each module exports a **factory function** that receives narrow dependencies and returns the tool definition, handler, or system object.
|
|
86
|
+
This follows the established pattern in the codebase (`createSubagentsService` in `service-adapter.ts` already uses this approach).
|
|
87
|
+
Factory functions keep state scoped to the instance (matching the current closure scope) and make dependencies explicit for testing.
|
|
88
|
+
|
|
89
|
+
### New module tree
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
src/
|
|
93
|
+
├── index.ts ← thin wire-up (~120-150 lines)
|
|
94
|
+
├── renderer.ts ← notification message renderer
|
|
95
|
+
├── notification.ts ← completion notification system
|
|
96
|
+
├── tools/
|
|
97
|
+
│ ├── helpers.ts ← shared pure helpers (textResult, formatLifetimeTokens, etc.)
|
|
98
|
+
│ ├── agent-tool.ts ← Agent tool definition + agent-specific helpers
|
|
99
|
+
│ ├── get-result-tool.ts ← get_subagent_result tool definition
|
|
100
|
+
│ └── steer-tool.ts ← steer_subagent tool definition
|
|
101
|
+
├── ui/
|
|
102
|
+
│ ├── agent-menu.ts ← /agents menu + all sub-handlers (NEW)
|
|
103
|
+
│ ├── agent-widget.ts (existing, unchanged)
|
|
104
|
+
│ └── conversation-viewer.ts (existing, unchanged)
|
|
105
|
+
└── ... (other existing modules unchanged)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Dependency design
|
|
109
|
+
|
|
110
|
+
Each factory receives only the methods it calls — not the full `AgentManager`, `AgentWidget`, or `ExtensionAPI`.
|
|
111
|
+
Example narrow interface for the get-result tool:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
interface GetResultDeps {
|
|
115
|
+
getRecord: (id: string) => AgentRecord | undefined;
|
|
116
|
+
cancelNudge: (key: string) => void;
|
|
117
|
+
agentActivity: ReadonlyMap<string, AgentActivity>;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The Agent tool has more dependencies but they remain enumerable — each one maps to a specific method or value the execute callback calls.
|
|
122
|
+
|
|
123
|
+
### Notification system
|
|
124
|
+
|
|
125
|
+
The nudge/notification helpers (`scheduleNudge`, `cancelNudge`, `emitIndividualNudge`, `sendIndividualNudge`) and their associated formatters (`formatTaskNotification`, `buildNotificationDetails`, `buildEventData`, `escapeXml`, `getStatusLabel`) form a cohesive unit.
|
|
126
|
+
They move to `notification.ts` as a factory:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
export function createNotificationSystem(deps: NotificationDeps): NotificationSystem;
|
|
130
|
+
|
|
131
|
+
interface NotificationSystem {
|
|
132
|
+
cancelNudge: (key: string) => void;
|
|
133
|
+
sendCompletion: (record: AgentRecord) => void;
|
|
134
|
+
cleanupCompleted: (id: string) => void;
|
|
135
|
+
buildEventData: (record: AgentRecord) => object;
|
|
136
|
+
dispose: () => void;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The completion callback in `index.ts` becomes a thin orchestrator (~15 lines) that calls `notifications.buildEventData()`, emits lifecycle events, persists the record, and delegates to `notifications.sendCompletion()`.
|
|
141
|
+
|
|
142
|
+
### What remains in index.ts
|
|
143
|
+
|
|
144
|
+
After all extractions, `index.ts` retains only:
|
|
145
|
+
|
|
146
|
+
1. Imports and default export declaration.
|
|
147
|
+
2. `reloadCustomAgents` helper and initial load call.
|
|
148
|
+
3. `agentActivity` map creation.
|
|
149
|
+
4. `createNotificationSystem()` call.
|
|
150
|
+
5. `AgentManager` construction with completion/started/compacted callbacks (~20 lines).
|
|
151
|
+
6. Service creation and publishing.
|
|
152
|
+
7. Lifecycle hooks (`session_start`, `session_before_switch`, `session_shutdown`).
|
|
153
|
+
8. Widget creation and `tool_execution_start` handler.
|
|
154
|
+
9. `buildTypeListText` computation.
|
|
155
|
+
10. Settings application.
|
|
156
|
+
11. Three `pi.registerTool()` calls (importing factories).
|
|
157
|
+
12. `pi.registerCommand("agents", ...)` call.
|
|
158
|
+
|
|
159
|
+
## Module-Level Changes
|
|
160
|
+
|
|
161
|
+
### `src/tools/helpers.ts` (new)
|
|
162
|
+
|
|
163
|
+
- `textResult(msg, details?)` — tool execute return value builder.
|
|
164
|
+
- `formatLifetimeTokens(record)` — format lifetime token total.
|
|
165
|
+
- `getModelLabelFromConfig(model)` — strip provider prefix and date suffix from model string.
|
|
166
|
+
|
|
167
|
+
### `src/renderer.ts` (new)
|
|
168
|
+
|
|
169
|
+
- `registerNotificationRenderer(registerFn)` — accepts `pi.registerMessageRenderer` and registers the `"subagent-notification"` renderer.
|
|
170
|
+
- Contains the full `renderOne` formatting logic currently inline in the `registerMessageRenderer` callback.
|
|
171
|
+
|
|
172
|
+
### `src/notification.ts` (new)
|
|
173
|
+
|
|
174
|
+
- `createNotificationSystem(deps)` factory — returns `NotificationSystem`.
|
|
175
|
+
- Contains: `scheduleNudge`, `cancelNudge`, `emitIndividualNudge`, `sendIndividualNudge`, `formatTaskNotification`, `buildNotificationDetails`, `buildEventData`, `escapeXml`, `getStatusLabel`.
|
|
176
|
+
- Deps interface: narrow accessors for `sendMessage`, `agentActivity`, `widget.markFinished`, `widget.update`.
|
|
177
|
+
|
|
178
|
+
### `src/tools/agent-tool.ts` (new)
|
|
179
|
+
|
|
180
|
+
- `createAgentTool(deps)` factory — returns the tool definition config object.
|
|
181
|
+
- Contains: `renderCall`, `renderResult`, `execute`, plus agent-tool-specific helpers (`createActivityTracker`, `buildDetails`, `getStatusNote`).
|
|
182
|
+
- Deps interface: narrow accessors for manager spawn/wait, widget lifecycle, activity map, event emission, output file wiring, type list text, and `reloadCustomAgents`.
|
|
183
|
+
|
|
184
|
+
### `src/tools/get-result-tool.ts` (new)
|
|
185
|
+
|
|
186
|
+
- `createGetResultTool(deps)` factory — returns the tool definition config object.
|
|
187
|
+
- Deps: `getRecord`, `cancelNudge`, `agentActivity`.
|
|
188
|
+
|
|
189
|
+
### `src/tools/steer-tool.ts` (new)
|
|
190
|
+
|
|
191
|
+
- `createSteerTool(deps)` factory — returns the tool definition config object.
|
|
192
|
+
- Deps: `getRecord`, `emitEvent`.
|
|
193
|
+
|
|
194
|
+
### `src/ui/agent-menu.ts` (new)
|
|
195
|
+
|
|
196
|
+
- `createAgentsMenuHandler(deps)` factory — returns the `/agents` command handler.
|
|
197
|
+
- Contains all menu functions: `showAgentsMenu`, `showAllAgentsList`, `showRunningAgents`, `viewAgentConversation`, `showAgentDetail`, `ejectAgent`, `disableAgent`, `enableAgent`, `showCreateWizard`, `showGenerateWizard`, `showManualWizard`, `showSettings`, `notifyApplied`, `findAgentFile`, `getModelLabel`.
|
|
198
|
+
- Deps: manager list/get methods, `reloadCustomAgents`, `agentActivity`, settings snapshot/save functions, event emission, and `pi` (for generate wizard spawning).
|
|
199
|
+
|
|
200
|
+
### `src/index.ts` (modified — shrinks from ~1,619 to ~120–150 lines)
|
|
201
|
+
|
|
202
|
+
- Remove all helper function definitions.
|
|
203
|
+
- Remove all tool definitions.
|
|
204
|
+
- Remove all menu handler functions.
|
|
205
|
+
- Remove renderer registration logic.
|
|
206
|
+
- Remove nudge/notification helpers.
|
|
207
|
+
- Add imports from new modules.
|
|
208
|
+
- Wire everything together: create deps, call factories, register tools/commands/lifecycle hooks.
|
|
209
|
+
|
|
210
|
+
## Test Impact Analysis
|
|
211
|
+
|
|
212
|
+
### New unit tests enabled by extraction
|
|
213
|
+
|
|
214
|
+
The decomposition enables direct testing of code that was previously locked inside the closure:
|
|
215
|
+
|
|
216
|
+
- `test/tools/helpers.test.ts` — `textResult`, `formatLifetimeTokens`, `getModelLabelFromConfig` with edge cases (zero tokens, empty model strings).
|
|
217
|
+
- `test/renderer.test.ts` — notification renderer formatting for each status (completed, error, stopped, steered, aborted) in collapsed and expanded modes.
|
|
218
|
+
- `test/notification.test.ts` — nudge scheduling/cancellation timing, `buildEventData` shape, `formatTaskNotification` XML output, `buildNotificationDetails` field mapping.
|
|
219
|
+
- `test/tools/get-result-tool.test.ts` — execute paths: agent not found, wait-for-completion, result-consumed suppression, verbose conversation inclusion.
|
|
220
|
+
- `test/tools/steer-tool.test.ts` — execute paths: agent not found, not running, session not ready (queued steer), successful steer.
|
|
221
|
+
- `test/tools/agent-tool.test.ts` — execute paths: foreground completion, background launch, resume, unknown type fallback, model resolution error.
|
|
222
|
+
- `test/ui/agent-menu.test.ts` — menu navigation, settings mutation, eject/disable/enable flows with mock UI context.
|
|
223
|
+
|
|
224
|
+
### Existing tests that become redundant
|
|
225
|
+
|
|
226
|
+
None.
|
|
227
|
+
There are no existing tests for `index.ts` — the extraction creates test coverage where none existed.
|
|
228
|
+
|
|
229
|
+
### Existing tests that stay as-is
|
|
230
|
+
|
|
231
|
+
All 21 existing test files are unaffected.
|
|
232
|
+
They test modules (`agent-manager`, `agent-runner`, `model-resolver`, `invocation-config`, `service-adapter`, etc.) that are not touched by this refactoring.
|
|
233
|
+
|
|
234
|
+
## TDD Order
|
|
235
|
+
|
|
236
|
+
Each step is a self-contained extraction + test cycle.
|
|
237
|
+
The existing test suite (362+ tests) runs after each step as a regression safety net.
|
|
238
|
+
|
|
239
|
+
1. **Extract `src/tools/helpers.ts` — shared pure helpers.**
|
|
240
|
+
Move `textResult`, `formatLifetimeTokens`, `getModelLabelFromConfig` to new module.
|
|
241
|
+
Update `index.ts` imports.
|
|
242
|
+
Write `test/tools/helpers.test.ts` covering each function.
|
|
243
|
+
Commit: `refactor: extract shared tool helpers to tools/helpers`
|
|
244
|
+
|
|
245
|
+
2. **Extract `src/renderer.ts` — notification message renderer.**
|
|
246
|
+
Move renderer callback to `registerNotificationRenderer` export.
|
|
247
|
+
Update `index.ts` to call the new function.
|
|
248
|
+
Write `test/renderer.test.ts` covering status-dependent formatting.
|
|
249
|
+
Commit: `refactor: extract notification renderer to renderer module`
|
|
250
|
+
|
|
251
|
+
3. **Extract `src/notification.ts` — completion notification system.**
|
|
252
|
+
Move nudge system + formatters to `createNotificationSystem` factory.
|
|
253
|
+
Update `index.ts` completion callback to use the notification system.
|
|
254
|
+
Write `test/notification.test.ts` covering nudge timing and event data.
|
|
255
|
+
Commit: `refactor: extract notification system to notification module`
|
|
256
|
+
|
|
257
|
+
4. **Extract `src/tools/get-result-tool.ts` — get_subagent_result tool.**
|
|
258
|
+
Move tool definition to `createGetResultTool` factory with narrow deps.
|
|
259
|
+
Update `index.ts` to call factory and register.
|
|
260
|
+
Write `test/tools/get-result-tool.test.ts` covering execute paths.
|
|
261
|
+
Commit: `refactor: extract get_subagent_result tool`
|
|
262
|
+
|
|
263
|
+
5. **Extract `src/tools/steer-tool.ts` — steer_subagent tool.**
|
|
264
|
+
Move tool definition to `createSteerTool` factory with narrow deps.
|
|
265
|
+
Update `index.ts`.
|
|
266
|
+
Write `test/tools/steer-tool.test.ts` covering execute paths.
|
|
267
|
+
Commit: `refactor: extract steer_subagent tool`
|
|
268
|
+
|
|
269
|
+
6. **Extract `src/tools/agent-tool.ts` — Agent tool.**
|
|
270
|
+
Move tool definition + agent-specific helpers (`createActivityTracker`, `buildDetails`, `getStatusNote`) to `createAgentTool` factory.
|
|
271
|
+
Update `index.ts`.
|
|
272
|
+
Write `test/tools/agent-tool.test.ts` covering foreground, background, resume, and error paths.
|
|
273
|
+
Commit: `refactor: extract Agent tool`
|
|
274
|
+
|
|
275
|
+
7. **Extract `src/ui/agent-menu.ts` — /agents menu handlers.**
|
|
276
|
+
Move all menu functions to `createAgentsMenuHandler` factory.
|
|
277
|
+
Update `index.ts` to register command with factory result.
|
|
278
|
+
Write `test/ui/agent-menu.test.ts` covering key menu navigation flows.
|
|
279
|
+
Commit: `refactor: extract /agents menu handlers`
|
|
280
|
+
|
|
281
|
+
8. **Final index.ts cleanup.**
|
|
282
|
+
Remove any dead imports or vestigial code.
|
|
283
|
+
Verify index.ts is ~120–150 lines of pure wire-up.
|
|
284
|
+
Run `pnpm run check` (typecheck) and full test suite.
|
|
285
|
+
Commit: `refactor: slim index.ts to wire-up entrypoint (#54)`
|
|
286
|
+
|
|
287
|
+
## Risks and Mitigations
|
|
288
|
+
|
|
289
|
+
| Risk | Mitigation |
|
|
290
|
+
| ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
291
|
+
| Closure variable access breaks after extraction — helpers currently close over shared maps (`agentActivity`, `pendingNudges`) | Factory pattern replaces closure access with explicit dependency injection; each factory's deps interface enumerates exactly what it needs. |
|
|
292
|
+
| Narrow dep interfaces diverge from the real objects — test mocks pass but runtime breaks | Run `pnpm run check` (typecheck) after each extraction step; the factory call sites in `index.ts` provide real objects whose types must satisfy the narrow interfaces. |
|
|
293
|
+
| Large number of extraction steps creates merge-conflict risk with parallel PRs | Steps are ordered leaf-first so earlier commits don't touch files later steps modify. Each step is independently committable and revertable. |
|
|
294
|
+
| Agent tool factory has many deps (~8–10) — risks becoming a dependency bag | Deps are individual functions and values, not a monolithic object. Each dep maps to exactly one method call in execute. If the count feels excessive during implementation, group by concern (spawn, widget, events) into 2–3 sub-interfaces. |
|
|
295
|
+
| `buildTypeListText` is called at init time and captures agent types — extraction might change when it runs | `buildTypeListText` stays in `index.ts` as wire-up code (called once, result passed to agent tool factory). Timing is unchanged. |
|
|
296
|
+
|
|
297
|
+
## Open Questions
|
|
298
|
+
|
|
299
|
+
- Should the notification module also own the lifecycle event emission (`subagents:completed`, `subagents:failed`, `subagents:started`, `subagents:compacted`), or should those stay in the completion callback in `index.ts`?
|
|
300
|
+
Defer until step 3 — the answer depends on whether the completion callback shrinks enough to justify the move.
|
|
301
|
+
- Should `buildTypeListText` move into `agent-tool.ts` or stay as wire-up in `index.ts`?
|
|
302
|
+
Defer until step 6 — evaluate once the agent tool factory interface is concrete.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 53
|
|
3
|
+
issue_title: "refactor: extract model resolution from Agent.execute"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Retro: #53 — extract model resolution from Agent.execute
|
|
7
|
+
|
|
8
|
+
## Final Retrospective (2026-05-17T21:00:00Z)
|
|
9
|
+
|
|
10
|
+
### Session summary
|
|
11
|
+
|
|
12
|
+
Planned and executed the extraction of inline model-resolution logic from `Agent.execute` in `index.ts` into a new `resolveInvocationModel()` function in `model-resolver.ts`.
|
|
13
|
+
Released as `pi-subagents-v4.1.0` with +10 new unit tests and no behavior change.
|
|
14
|
+
Also fixed a pre-existing `rumdl` glob-quoting bug in `package.json` discovered during the lint step.
|
|
15
|
+
|
|
16
|
+
### Observations
|
|
17
|
+
|
|
18
|
+
#### What went well
|
|
19
|
+
|
|
20
|
+
- Pre-existing lint bug surfaced and fixed: the `rumdl check '*.md' 'docs/**/*.md'` command in `package.json` used single-quoted globs that prevented shell expansion. Verified as pre-existing (reproduced on prior commit via `git stash`), cleanly isolated into its own `fix:` commit. This was a genuine find — the lint had been silently broken.
|
|
21
|
+
|
|
22
|
+
#### What caused friction (agent side)
|
|
23
|
+
|
|
24
|
+
- `missing-context` — In step 6 (refactoring `index.ts`), replaced the `resolveModel` import with `resolveInvocationModel` without first checking whether `resolveModel` was still used elsewhere in the file. Two other call sites (`createSubagentsService` at line 386 and `getModelLabel` at line 1043) still needed it. The plan explicitly listed `getModelLabel` as a non-goal that continues using `resolveModel`, so the information was available. Caught immediately via `grep` after the edit and fixed in the same commit. Impact: one extra edit + grep cycle, no rework.
|
|
25
|
+
|
|
26
|
+
- `missing-context` — The plan's type definitions specified `model: unknown` for `ModelResolutionResult`, but downstream code in `index.ts` accesses `.id` and `.name` on the model and passes it where `Model<any>` is expected. The plan's risk section flagged this ("reducing but not eliminating the `any`"), yet the implementation went with `unknown` first, requiring a correction after `pnpm run check` failed with 4 type errors. Changed to `model: any` to match the existing `resolveModel` return type. Impact: one extra edit cycle within the same commit, no rework.
|
|
27
|
+
|
|
28
|
+
#### What caused friction (user side)
|
|
29
|
+
|
|
30
|
+
- None observed. The issue was well-scoped with clear acceptance criteria, making planning and execution straightforward.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 54
|
|
3
|
+
issue_title: "refactor: decompose src/index.ts into tool + menu modules"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Retro: #54 — decompose index.ts into tool + menu modules
|
|
7
|
+
|
|
8
|
+
## Final Retrospective (2026-05-18T02:20:00Z)
|
|
9
|
+
|
|
10
|
+
### Session summary
|
|
11
|
+
|
|
12
|
+
Decomposed `src/index.ts` from 1,619 lines to 265 lines across 8 commits.
|
|
13
|
+
Extracted 7 new modules (`tools/helpers.ts`, `renderer.ts`, `notification.ts`, `tools/agent-tool.ts`, `tools/get-result-tool.ts`, `tools/steer-tool.ts`, `ui/agent-menu.ts`) with 66 new tests (379 → 445 total).
|
|
14
|
+
Released as `pi-subagents-v4.1.1`.
|
|
15
|
+
Filed follow-up #66 (replace `as any` casts with proper SDK types) and #67 (flaky `pi-autoformat` acceptance test).
|
|
16
|
+
|
|
17
|
+
### Observations
|
|
18
|
+
|
|
19
|
+
#### What went well
|
|
20
|
+
|
|
21
|
+
- Leaf-first extraction order worked cleanly — helpers, then renderer, then notification, then tools, then menu. Each step left the repo green with no cascading breakage.
|
|
22
|
+
- The `createNotificationSystem` factory pattern with arrow-closure capture of `widget` (assigned after `AgentManager` construction) preserved the existing deferred-reference semantics without restructuring initialization order.
|
|
23
|
+
|
|
24
|
+
#### What caused friction (agent side)
|
|
25
|
+
|
|
26
|
+
- `wrong-abstraction` — Applied the code-style skill's "keep Pi SDK imports out of business-logic modules" rule to tool/menu modules, which are SDK consumers, not business logic. Used `unknown` for `ExtensionContext`, `AgentSession`, `ModelRegistry` in factory dep interfaces, requiring 9 `as any` casts in `index.ts`. User caught this post-ship. Impact: filed #66 as a follow-up cleanup; the casts are cosmetic (no runtime effect) but degrade type safety. Fixed the code-style skill to clarify the boundary. (user-caught)
|
|
27
|
+
|
|
28
|
+
- `missing-context` — Four test files (`notification.test.ts`, `get-result-tool.test.ts`, `steer-tool.test.ts`, `agent-tool.test.ts`) omitted `compactionCount: 0` from `AgentRecord` factories. Caught at the final `pnpm run check` step, not during test writing. The testing skill already says "grep for ALL test files that construct a compatible mock." Impact: one extra fix cycle delegated to a subagent, no rework beyond that step. (self-identified)
|
|
29
|
+
|
|
30
|
+
- `other` — `Edit` tool failed 3 times matching the UTF-8 middle dot (`·`, U+00B7) in the steer tool's `stateParts.join(" · ")` line. The third attempt produced a partial match that left the file in a broken state (dangling orphan code after the replacement anchor). Required `git restore` and a fallback to `python3` line-range replacement. The same `python3` approach for the menu extraction lost the closing `}` of the default export function. Impact: ~5 minutes of rework across the two extraction steps, plus one `git restore`.
|
|
31
|
+
|
|
32
|
+
#### What caused friction (user side)
|
|
33
|
+
|
|
34
|
+
- The `as any` casts could have been caught earlier if the user had flagged the `unknown` types during the planning phase. However, the plan didn't prescribe exact interface types — that was an implementation decision. The user's post-ship review ("Why did we have to cast `as any`? Take a look at `packages/pi-permission-system/` as a model") was an efficient redirect that immediately scoped the investigation.
|
|
35
|
+
|
|
36
|
+
### Changes made
|
|
37
|
+
|
|
38
|
+
1. `.pi/skills/code-style/SKILL.md` — Clarified SDK-boundary guidance: tool definitions, event handlers, and command handlers may import SDK types directly; the restriction targets pure helpers and domain modules.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gotgenes/pi-subagents",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"exports": {
|
|
5
5
|
".": "./src/service.ts"
|
|
6
6
|
},
|
|
@@ -30,20 +30,20 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@earendil-works/pi-ai": ">=0.
|
|
34
|
-
"@earendil-works/pi-coding-agent": ">=0.
|
|
35
|
-
"@earendil-works/pi-tui": ">=0.
|
|
33
|
+
"@earendil-works/pi-ai": ">=0.75.0",
|
|
34
|
+
"@earendil-works/pi-coding-agent": ">=0.75.0",
|
|
35
|
+
"@earendil-works/pi-tui": ">=0.75.0"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@sinclair/typebox": "^0.34.49",
|
|
39
39
|
"nanoid": "^5.0.0"
|
|
40
40
|
},
|
|
41
41
|
"engines": {
|
|
42
|
-
"node": ">=
|
|
42
|
+
"node": ">=22"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@biomejs/biome": "^2.4.14",
|
|
46
|
-
"@types/node": "^
|
|
46
|
+
"@types/node": "^22.15.3",
|
|
47
47
|
"typescript": "^6.0.3",
|
|
48
48
|
"vitest": "^4.1.5",
|
|
49
49
|
"rumdl": "^0.1.93"
|