@gotgenes/pi-subagents 18.0.0 → 18.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +22 -31
- package/docs/architecture/architecture.md +157 -204
- package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
- package/package.json +5 -6
- package/src/lifecycle/subagent.ts +5 -9
- package/src/observation/notification.ts +23 -10
- package/src/observation/subagent-events-observer.ts +1 -3
- package/src/tools/get-result-report.ts +60 -0
- package/src/tools/get-result-tool.ts +25 -40
- package/src/types.ts +1 -1
- package/src/ui/session-navigator.ts +0 -2
- package/.prettierignore +0 -5
- package/AGENTS.md +0 -7
- package/docs/plans/0048-implement-subagents-api.md +0 -304
- package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
- package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
- package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
- package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
- package/docs/plans/0054-decompose-index-into-modules.md +0 -302
- package/docs/plans/0057-structured-debug-logging.md +0 -154
- package/docs/plans/0061-session-format-transcript.md +0 -284
- package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
- package/docs/plans/0069-create-subagent-runtime.md +0 -345
- package/docs/plans/0070-extract-event-handlers.md +0 -306
- package/docs/plans/0071-extract-session-config-assembler.md +0 -362
- package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
- package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
- package/docs/plans/0077-inject-project-agents-dir.md +0 -115
- package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
- package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
- package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
- package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
- package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
- package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
- package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
- package/docs/plans/0108-extract-agent-type-registry.md +0 -322
- package/docs/plans/0109-extract-settings-manager.md +0 -276
- package/docs/plans/0110-agent-activity-tracker.md +0 -297
- package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
- package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
- package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
- package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
- package/docs/plans/0115-decompose-agent-tool.md +0 -337
- package/docs/plans/0116-type-housekeeping.md +0 -351
- package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
- package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
- package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
- package/docs/plans/0132-inject-io-into-session-config.md +0 -219
- package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
- package/docs/plans/0134-reduce-as-any-casts.md +0 -366
- package/docs/plans/0135-extract-display-helpers.md +0 -182
- package/docs/plans/0136-decompose-agent-menu.md +0 -300
- package/docs/plans/0144-consolidate-observation-model.md +0 -263
- package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
- package/docs/plans/0146-narrow-ui-context.md +0 -319
- package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
- package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
- package/docs/plans/0152-add-prompt-snippet.md +0 -91
- package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
- package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
- package/docs/plans/0166-extract-parent-session-info.md +0 -231
- package/docs/plans/0167-narrow-runner-io.md +0 -150
- package/docs/plans/0168-extract-tool-filter-config.md +0 -173
- package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
- package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
- package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
- package/docs/plans/0172-extract-turn-formatting.md +0 -206
- package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
- package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
- package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
- package/docs/plans/0192-define-session-context-interface.md +0 -107
- package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
- package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
- package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
- package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
- package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
- package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
- package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
- package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
- package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
- package/docs/plans/0215-decompose-build-parent-context.md +0 -166
- package/docs/plans/0216-decompose-start-agent.md +0 -255
- package/docs/plans/0217-extract-overwrite-guard.md +0 -176
- package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
- package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
- package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
- package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
- package/docs/plans/0229-agent-born-complete.md +0 -564
- package/docs/plans/0230-extract-concurrency-queue.md +0 -265
- package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
- package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
- package/docs/plans/0237-remove-disallowed-tools.md +0 -180
- package/docs/plans/0238-remove-extensions-filtering.md +0 -191
- package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
- package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
- package/docs/plans/0256-extract-worktree-isolation.md +0 -256
- package/docs/plans/0257-extract-child-session-factory.md +0 -285
- package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
- package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
- package/docs/plans/0265-born-complete-subagent-session.md +0 -333
- package/docs/plans/0270-type-consumable-public-surface.md +0 -204
- package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
- package/docs/plans/0277-encapsulate-agent-session.md +0 -304
- package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
- package/docs/plans/0360-custom-agents-default-append.md +0 -132
- package/docs/plans/0373-extract-subagent-state.md +0 -250
- package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
- package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
- package/docs/plans/0376-extract-manager-observer.md +0 -232
- package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
- package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
- package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
- package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
- package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
- package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
- package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
- package/docs/plans/0412-unify-session-mock-builders.md +0 -146
- package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
- package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
- package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
- package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
- package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
- package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
- package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
- package/docs/plans/0427-reconsider-ui-direction.md +0 -212
- package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
- package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
- package/docs/plans/0444-shrink-widget-to-background-agents.md +0 -156
- package/docs/plans/0445-native-session-navigation.md +0 -365
- package/docs/plans/0446-spike-session-navigation-entry-criteria.md +0 -171
- package/docs/plans/0447-extract-subagents-settings-command.md +0 -220
- package/docs/plans/0448-block-disabled-agent-spawn.md +0 -207
- package/docs/plans/0462-navigation-renderer-tui-components.md +0 -338
- package/docs/plans/0463-file-snapshot-source-evicted-agents.md +0 -306
- package/docs/retro/0048-implement-subagents-api.md +0 -44
- package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
- package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
- package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
- package/docs/retro/0054-decompose-index-into-modules.md +0 -53
- package/docs/retro/0057-structured-debug-logging.md +0 -77
- package/docs/retro/0061-session-format-transcript.md +0 -41
- package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
- package/docs/retro/0069-create-subagent-runtime.md +0 -43
- package/docs/retro/0070-extract-event-handlers.md +0 -49
- package/docs/retro/0071-extract-session-config-assembler.md +0 -60
- package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
- package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
- package/docs/retro/0077-inject-project-agents-dir.md +0 -33
- package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
- package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
- package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
- package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
- package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
- package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
- package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
- package/docs/retro/0108-extract-agent-type-registry.md +0 -41
- package/docs/retro/0109-extract-settings-manager.md +0 -55
- package/docs/retro/0110-agent-activity-tracker.md +0 -44
- package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
- package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
- package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
- package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
- package/docs/retro/0115-decompose-agent-tool.md +0 -51
- package/docs/retro/0116-type-housekeeping.md +0 -42
- package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
- package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
- package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
- package/docs/retro/0132-inject-io-into-session-config.md +0 -33
- package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
- package/docs/retro/0134-reduce-as-any-casts.md +0 -56
- package/docs/retro/0135-extract-display-helpers.md +0 -38
- package/docs/retro/0136-decompose-agent-menu.md +0 -43
- package/docs/retro/0144-consolidate-observation-model.md +0 -39
- package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
- package/docs/retro/0146-narrow-ui-context.md +0 -70
- package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
- package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
- package/docs/retro/0152-add-prompt-snippet.md +0 -34
- package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
- package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
- package/docs/retro/0166-extract-parent-session-info.md +0 -66
- package/docs/retro/0167-narrow-runner-io.md +0 -63
- package/docs/retro/0168-extract-tool-filter-config.md +0 -76
- package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
- package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
- package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
- package/docs/retro/0172-extract-turn-formatting.md +0 -80
- package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
- package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
- package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
- package/docs/retro/0192-define-session-context-interface.md +0 -59
- package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
- package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
- package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
- package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
- package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
- package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
- package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
- package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
- package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
- package/docs/retro/0215-decompose-build-parent-context.md +0 -61
- package/docs/retro/0216-decompose-start-agent.md +0 -80
- package/docs/retro/0217-extract-overwrite-guard.md +0 -63
- package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
- package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
- package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
- package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
- package/docs/retro/0229-agent-born-complete.md +0 -89
- package/docs/retro/0230-extract-concurrency-queue.md +0 -38
- package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
- package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
- package/docs/retro/0237-remove-disallowed-tools.md +0 -78
- package/docs/retro/0238-remove-extensions-filtering.md +0 -72
- package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
- package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
- package/docs/retro/0256-extract-worktree-isolation.md +0 -89
- package/docs/retro/0257-extract-child-session-factory.md +0 -33
- package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
- package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
- package/docs/retro/0265-born-complete-subagent-session.md +0 -97
- package/docs/retro/0270-type-consumable-public-surface.md +0 -108
- package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
- package/docs/retro/0277-encapsulate-agent-session.md +0 -80
- package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
- package/docs/retro/0360-custom-agents-default-append.md +0 -81
- package/docs/retro/0373-extract-subagent-state.md +0 -94
- package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
- package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
- package/docs/retro/0376-extract-manager-observer.md +0 -81
- package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
- package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
- package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
- package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
- package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
- package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
- package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
- package/docs/retro/0412-unify-session-mock-builders.md +0 -80
- package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
- package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
- package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
- package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
- package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
- package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
- package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
- package/docs/retro/0427-reconsider-ui-direction.md +0 -102
- package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -45
- package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
- package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
- package/docs/retro/0445-native-session-navigation.md +0 -122
- package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
- package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
- package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
- package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
- package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
- package/src/observation/notification-state.ts +0 -27
- package/vitest.config.ts +0 -14
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 463
|
|
3
|
-
issue_title: "pi-subagents: add file-snapshot source to /subagent-sessions for evicted agents"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# File-snapshot source for evicted agents in `/subagent-sessions`
|
|
7
|
-
|
|
8
|
-
## Release Recommendation
|
|
9
|
-
|
|
10
|
-
**Release:** ship independently
|
|
11
|
-
|
|
12
|
-
Architecture roadmap Phase 19 Step 4b ([#463]) carries `Release: independent`.
|
|
13
|
-
This is a new capability the bespoke viewer never had — it gates nothing and is not a Step 5 prerequisite — so it ships on its own once landed.
|
|
14
|
-
|
|
15
|
-
## Problem Statement
|
|
16
|
-
|
|
17
|
-
The [#445] native-session-navigation slice sources transcripts live, from `manager.listAgents()` only.
|
|
18
|
-
The manager's cleanup sweep (`SubagentManager.cleanup()`, every 60 s) disposes a completed/stopped/errored record 10 minutes after it finishes — `disposeSession()` frees the heavy in-memory session (its message history included) and the record is deleted from the map.
|
|
19
|
-
The lightweight session JSONL persists on disk at `Subagent.outputFile`, but with no live record the agent is unreachable from `/subagent-sessions`.
|
|
20
|
-
|
|
21
|
-
This step makes a fully-evicted agent navigable: it adds the file-snapshot `TranscriptSource` branch the #445 seam was designed for, and broadens the picker's candidate set to include evicted agents.
|
|
22
|
-
|
|
23
|
-
## Goals
|
|
24
|
-
|
|
25
|
-
- Implement `fileSnapshotSource(outputFile, readFile)` in `src/ui/session-navigation.ts`: `parseSessionEntries(readFile(outputFile))` → drop the `SessionHeader` → `buildSessionContext(...).messages` → a static (no-subscribe, no-streaming) `TranscriptSource`.
|
|
26
|
-
- Broaden the `/subagent-sessions` candidate set to include evicted agents, deduped against live records.
|
|
27
|
-
- Render an evicted agent's transcript read-only from its persisted file when picked; the renderer (`buildTranscriptComponents`) and overlay (`TranscriptOverlay`) are untouched.
|
|
28
|
-
- Inject `readFile` as a parameter so the pure module performs no `fs` calls.
|
|
29
|
-
|
|
30
|
-
This change is **not** breaking: it is additive (a new source branch and a broadened candidate set); no existing behavior, output shape, or default changes for a tracked agent.
|
|
31
|
-
|
|
32
|
-
## Non-Goals
|
|
33
|
-
|
|
34
|
-
- No directory scan of the tasks directory and no surfacing of prior-process orphan session files (see Design Overview → Candidate-set decision).
|
|
35
|
-
- No change to the cleanup sweep's 10-minute eviction policy or to `disposeSession()`.
|
|
36
|
-
- No renderer or overlay changes — `session-navigator.ts`'s `buildTranscriptComponents` / `TranscriptOverlay` / `addMessageComponents` are unchanged (Step 4a, [#462], already brought them to parity).
|
|
37
|
-
- No `switchSession` / `loadEntriesFromFile` (rejected by the Step 1 spike, [#446]).
|
|
38
|
-
- No live re-read or file-watching of the snapshot — a file source is a static snapshot by design.
|
|
39
|
-
|
|
40
|
-
## Background
|
|
41
|
-
|
|
42
|
-
Relevant modules:
|
|
43
|
-
|
|
44
|
-
- `src/ui/session-navigation.ts` — the pure, unit-testable core: `NavigableSubagent` (narrow record view), `NavigationEntry`, `TranscriptSource`, `listNavigableAgents(agents, registry)`, `liveSource(record)`, `buildLabel(record, registry)`.
|
|
45
|
-
It imports SDK *types* only (`ToolDefinition`) and the lifecycle type `SubagentStatus`.
|
|
46
|
-
- `src/ui/session-navigator.ts` — the SDK/TUI consumer half: `SessionNavigatorHandler` (picker + source selection) and `TranscriptOverlay` (read-only scrollable renderer).
|
|
47
|
-
The handler already calls `liveSource(entry.record)`; the source is the only seam that varies.
|
|
48
|
-
- `src/lifecycle/subagent-manager.ts` — `listAgents()` (sorted live records), `cleanup()` (the 10-minute sweep), `clearCompleted()` (new-session wipe, called from `handlers/lifecycle.ts` on `session_start` / `session_before_switch`), `removeRecord()` (`disposeSession()` + `agents.delete`).
|
|
49
|
-
- `src/lifecycle/subagent.ts` — `Subagent` exposes `id`, `type`, `description` (readonly), and getters `status`, `startedAt`, `completedAt`, `toolUses`, `outputFile`.
|
|
50
|
-
- `src/index.ts` — registers `subagent-sessions`, calling `sessionNavigator.handle({ ui, agents: manager.listAgents(), registry, cwd })`.
|
|
51
|
-
|
|
52
|
-
SDK functions (`@earendil-works/pi-coding-agent`): `parseSessionEntries(content): FileEntry[]`, `buildSessionContext(entries: SessionEntry[]): { messages: AgentMessage[]; … }`, and the types `SessionEntry` / `SessionHeader`.
|
|
53
|
-
`FileEntry = SessionHeader | SessionEntry`; only the header has `type: "session"`, so `entries.filter((e): e is SessionEntry => e.type !== "session")` is a sound type guard.
|
|
54
|
-
`SessionMessage` (the navigator's message type) is `SessionContext["messages"][number]` = `AgentMessage`, so `buildSessionContext(...).messages` matches `TranscriptSource.getMessages()` with no cast.
|
|
55
|
-
|
|
56
|
-
Constraints from AGENTS.md / skills that apply:
|
|
57
|
-
|
|
58
|
-
- `code-design` SDK-boundary guideline: pure helpers should avoid SDK *runtime* imports.
|
|
59
|
-
`fileSnapshotSource` calls the SDK runtime functions `parseSessionEntries` / `buildSessionContext` directly (see Design Overview → SDK-runtime decision); there is no `no-restricted-imports` lint rule, and the module already depends on SDK types.
|
|
60
|
-
- `testing`: components used by `session-navigator.ts` need `initTheme(undefined, false)` in `beforeAll` (already present in `session-navigator.test.ts`).
|
|
61
|
-
- `fallow dead-code`: a new export with no caller fails the gate.
|
|
62
|
-
Producers (`fileSnapshotSource`, `listEvicted`) gain their caller in the integration step within the same push; the pushed tip is dead-code-clean (see Risks).
|
|
63
|
-
|
|
64
|
-
## Design Overview
|
|
65
|
-
|
|
66
|
-
### Candidate-set decision — manager-retained descriptors (not a directory scan)
|
|
67
|
-
|
|
68
|
-
The issue proposes enumerating persisted JSONL files in the tasks directory.
|
|
69
|
-
The persisted child session carries **no** subagent `type` or `description` — those live only on the in-memory `Subagent` record; the file holds only the conversation plus a header (`id`, `timestamp`, `cwd`, `parentSession`).
|
|
70
|
-
A directory scan therefore yields degraded labels (agent type → generic placeholder; curated `description` → a raw first-prompt snippet or filename) and must parse every file on every picker open.
|
|
71
|
-
|
|
72
|
-
Decision (confirmed with the operator): the manager retains a lightweight **descriptor** at eviction time instead.
|
|
73
|
-
When `cleanup()` disposes a record that has a persisted file, it first copies the record's label fields plus `outputFile` into a separate `evicted` map (no messages — the heavy state is still freed, so memory stays bounded by the number of subagents spawned, not their transcripts).
|
|
74
|
-
The picker's candidate set is `live ∪ evicted`, deduped by id, with identical rich labels for both.
|
|
75
|
-
|
|
76
|
-
Coverage: this surfaces agents evicted **in the current root session** — which are the cleanup sweep's only targets.
|
|
77
|
-
A fresh `SubagentManager` is created per session and `clearCompleted()` runs on `session_start`, so prior-process subagents are never reloaded into the manager; the only files a directory scan would *additionally* surface are old-session orphans, which are exactly the ones with degraded labels.
|
|
78
|
-
Picking an evicted agent still reads its file to render (the messages are gone from memory regardless) — so `fileSnapshotSource` is required either way; the descriptor only feeds the *label*.
|
|
79
|
-
|
|
80
|
-
### SDK-runtime decision — call `parseSessionEntries` / `buildSessionContext` directly
|
|
81
|
-
|
|
82
|
-
`fileSnapshotSource` imports and calls these SDK runtime functions directly rather than injecting them.
|
|
83
|
-
Rationale: they are deterministic parsers of Pi's own session format; the injected `readFile` already provides the unit-test seam (a fake `readFile` returning fixture JSONL fully exercises parse → drop-header → build → messages), so injecting the parsers adds wiring without testability gain.
|
|
84
|
-
There is no `no-restricted-imports` rule, and `session-navigation.ts` already imports SDK types.
|
|
85
|
-
|
|
86
|
-
### Data shapes
|
|
87
|
-
|
|
88
|
-
`EvictedSubagent` — the descriptor, owned by lifecycle (the manager constructs it), imported as a type by the UI (the UI already imports `SubagentStatus` from lifecycle):
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
// src/lifecycle/subagent-manager.ts
|
|
92
|
-
export interface EvictedSubagent {
|
|
93
|
-
readonly id: string;
|
|
94
|
-
readonly type: SubagentType;
|
|
95
|
-
readonly description: string;
|
|
96
|
-
readonly status: SubagentStatus;
|
|
97
|
-
readonly startedAt: number;
|
|
98
|
-
readonly completedAt: number | undefined;
|
|
99
|
-
readonly toolUses: number;
|
|
100
|
-
readonly outputFile: string;
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
`NavigationEntry` changes from `{ record, label }` to a discriminated union so the handler can pick the source by kind:
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
// src/ui/session-navigation.ts
|
|
108
|
-
export type NavigationEntry =
|
|
109
|
-
| { readonly kind: "live"; readonly label: string; readonly record: NavigableSubagent }
|
|
110
|
-
| { readonly kind: "evicted"; readonly label: string; readonly outputFile: string };
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
`buildLabel` is narrowed to a per-call interface (ISP) that both a `NavigableSubagent` and an `EvictedSubagent` satisfy, and gains an `evicted` marker:
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
interface LabelFields {
|
|
117
|
-
readonly type: SubagentType;
|
|
118
|
-
readonly description: string;
|
|
119
|
-
readonly status: SubagentStatus;
|
|
120
|
-
readonly startedAt: number;
|
|
121
|
-
readonly completedAt: number | undefined;
|
|
122
|
-
readonly toolUses: number;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function buildLabel(fields: LabelFields, registry: AgentConfigLookup, evicted = false): string {
|
|
126
|
-
const name = getDisplayName(fields.type, registry);
|
|
127
|
-
const duration = formatDuration(fields.startedAt, fields.completedAt);
|
|
128
|
-
const marker = evicted ? " · evicted (snapshot)" : "";
|
|
129
|
-
return `${name} (${fields.description}) · ${fields.toolUses} tools · ${fields.status} · ${duration}${marker}`;
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### `fileSnapshotSource`
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
export function fileSnapshotSource(
|
|
137
|
-
outputFile: string,
|
|
138
|
-
readFile: (path: string) => string,
|
|
139
|
-
): TranscriptSource {
|
|
140
|
-
const entries = parseSessionEntries(readFile(outputFile));
|
|
141
|
-
const sessionEntries = entries.filter(
|
|
142
|
-
(entry): entry is SessionEntry => entry.type !== "session",
|
|
143
|
-
);
|
|
144
|
-
const { messages } = buildSessionContext(sessionEntries);
|
|
145
|
-
return {
|
|
146
|
-
getMessages: () => messages,
|
|
147
|
-
subscribe: () => undefined, // static snapshot — no live updates
|
|
148
|
-
streaming: () => undefined, // never streaming
|
|
149
|
-
getToolDefinition: () => undefined, // no live tool registry off disk
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### `listNavigableAgents` (broadened) and the handler call site
|
|
155
|
-
|
|
156
|
-
```typescript
|
|
157
|
-
export function listNavigableAgents(
|
|
158
|
-
agents: readonly NavigableSubagent[],
|
|
159
|
-
evicted: readonly EvictedSubagent[],
|
|
160
|
-
registry: AgentConfigLookup,
|
|
161
|
-
): NavigationEntry[] {
|
|
162
|
-
const live = agents
|
|
163
|
-
.filter((record) => record.isSessionReady())
|
|
164
|
-
.map((record): NavigationEntry => ({ kind: "live", record, label: buildLabel(record, registry) }));
|
|
165
|
-
const liveIds = new Set(agents.map((record) => record.id));
|
|
166
|
-
const evictedEntries = evicted
|
|
167
|
-
.filter((d) => !liveIds.has(d.id))
|
|
168
|
-
.map((d): NavigationEntry => ({ kind: "evicted", outputFile: d.outputFile, label: buildLabel(d, registry, true) }));
|
|
169
|
-
return [...live, ...evictedEntries];
|
|
170
|
-
}
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Dedup is keyed by `id` (both shapes carry it) rather than `outputFile`: a record leaves `listAgents()` at the same instant its descriptor is captured, so the sets cannot overlap; the filter is defensive.
|
|
174
|
-
Order is live-then-evicted, which is already recency-ordered (evicted agents completed > 10 min ago).
|
|
175
|
-
|
|
176
|
-
Handler consumer sketch (Tell-Don't-Ask: the entry tells the handler its kind; the handler asks the right source constructor — no reach-through into the record's internals):
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
const entry = entries.find((candidate) => candidate.label === choice);
|
|
180
|
-
if (!entry) return;
|
|
181
|
-
let source: TranscriptSource;
|
|
182
|
-
try {
|
|
183
|
-
source = entry.kind === "live" ? liveSource(entry.record) : fileSnapshotSource(entry.outputFile, readFile);
|
|
184
|
-
} catch {
|
|
185
|
-
ui.notify("Could not read the session transcript file.", "error");
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
// …unchanged: getMarkdownTheme(), ui.custom(new TranscriptOverlay({ source, … }))
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### Manager retention sketch
|
|
192
|
-
|
|
193
|
-
```typescript
|
|
194
|
-
private readonly evicted = new Map<string, EvictedSubagent>();
|
|
195
|
-
|
|
196
|
-
private cleanup() {
|
|
197
|
-
const cutoff = Date.now() - 10 * 60_000;
|
|
198
|
-
for (const [id, record] of this.agents) {
|
|
199
|
-
if (record.status === "running" || record.status === "queued") continue;
|
|
200
|
-
if ((record.completedAt ?? 0) >= cutoff) continue;
|
|
201
|
-
if (record.outputFile) this.evicted.set(id, toEvictedSubagent(record));
|
|
202
|
-
this.removeRecord(id, record);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
listEvicted(): EvictedSubagent[] {
|
|
207
|
-
return [...this.evicted.values()].sort((a, b) => b.startedAt - a.startedAt);
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
`clearCompleted()` and `dispose()` also `this.evicted.clear()` — descriptors belong to the session that evicted them, so a new session starts empty.
|
|
212
|
-
`toEvictedSubagent(record)` copies the eight fields; it is a private helper (or a free function in the module) and reads `record.outputFile` only after the `if (record.outputFile)` guard, so the `outputFile` field is always a defined `string`.
|
|
213
|
-
|
|
214
|
-
### Edge cases
|
|
215
|
-
|
|
216
|
-
- **`outputFile` undefined at eviction** (headless / never-persisted session) → no descriptor captured; nothing to navigate.
|
|
217
|
-
- **File deleted/unreadable after eviction** → `fileSnapshotSource`'s eager read throws; the handler's `try/catch` notifies and returns without opening the overlay.
|
|
218
|
-
- **Empty or header-only JSONL** → `buildSessionContext` returns `messages: []`; the overlay renders an empty transcript (no crash).
|
|
219
|
-
- **No navigable sessions at all** (no live, no evicted) → existing `ui.notify("No subagent sessions to view.", "info")` path, unchanged.
|
|
220
|
-
|
|
221
|
-
## Module-Level Changes
|
|
222
|
-
|
|
223
|
-
- `src/lifecycle/subagent-manager.ts` — add the `EvictedSubagent` interface (exported), the `evicted` map field, descriptor capture in `cleanup()`, `evicted.clear()` in `clearCompleted()` and `dispose()`, the `listEvicted()` method, and the `toEvictedSubagent` helper.
|
|
224
|
-
Import `SubagentType` (already in `#src/types`) and `SubagentStatus` (`#src/lifecycle/subagent-state`) for the interface.
|
|
225
|
-
- `src/ui/session-navigation.ts` — add `fileSnapshotSource`; import `EvictedSubagent` (type), and the SDK runtime `parseSessionEntries` / `buildSessionContext` plus the `SessionEntry` type; change `NavigationEntry` to the discriminated union; broaden `listNavigableAgents` to `(agents, evicted, registry)`; narrow `buildLabel` to `LabelFields` + `evicted` flag.
|
|
226
|
-
- `src/ui/session-navigator.ts` — `SessionNavigatorParams` gains `evicted: readonly EvictedSubagent[]` and `readFile: (path: string) => string`; the handler selects the source by `entry.kind` inside a `try/catch`.
|
|
227
|
-
No change to `TranscriptOverlay`, `buildTranscriptComponents`, `addMessageComponents`, or `addUserComponents`.
|
|
228
|
-
- `src/index.ts` — add `import { readFileSync } from "node:fs"`; the `subagent-sessions` handler passes `evicted: manager.listEvicted()` and `readFile: (path) => readFileSync(path, "utf8")`.
|
|
229
|
-
- `docs/architecture/architecture.md` — mark Step 4b ([#463]) **Landed** with a note recording the descriptor-vs-scan decision and that ADR-0004 Addendum 2's dual-source design is now realized; flip the `S4b` node label in the step-dependency Mermaid diagram to ✅.
|
|
230
|
-
- `docs/decisions/0004-reconsider-ui-direction.md` — optional one-line note under Addendum 2 that Step 4b chose manager-retained descriptors over a directory scan (the addendum's "evicted/untracked" wording said file snapshot for *rendering*, which still holds; only the *candidate-set* mechanism is being pinned down).
|
|
231
|
-
|
|
232
|
-
No SKILL update: the package SKILL's UI section references no session-navigation internals and the file/domain counts are unchanged (no new module — `fileSnapshotSource` joins the existing `session-navigation.ts`).
|
|
233
|
-
The architecture LOC/complexity tables are explicit end-of-phase snapshots, not per-file inventories, so a ~30-LOC addition does not update them.
|
|
234
|
-
|
|
235
|
-
## Test Impact Analysis
|
|
236
|
-
|
|
237
|
-
1. **New unit tests enabled by this change:**
|
|
238
|
-
- `fileSnapshotSource` (pure, in `session-navigation.test.ts`): fixture JSONL via a fake `readFile` → assert `getMessages()` equals the parsed messages, the `SessionHeader` is dropped, and `subscribe()` / `streaming()` / `getToolDefinition()` return `undefined`.
|
|
239
|
-
- `listNavigableAgents` with evicted descriptors: evicted entries appear with the `· evicted (snapshot)` marker; an evicted descriptor whose id matches a live record is deduped out.
|
|
240
|
-
- `SubagentManager.listEvicted()` (in `subagent-manager.test.ts`): after advancing fake timers past the cutoff, a completed agent with an `outputFile` produces a descriptor; one without an `outputFile` does not; `clearCompleted()` empties the set.
|
|
241
|
-
- `SessionNavigatorHandler` evicted path (in `session-navigator.test.ts`): picking an evicted label opens an overlay sourced from `readFile`; a throwing `readFile` notifies and skips the overlay.
|
|
242
|
-
2. **Tests that become redundant:** none — the live-source tests still exercise the tracked-agent branch.
|
|
243
|
-
3. **Tests that must stay as-is:** the existing `liveSource`, `listNavigableAgents` (live-only), `TranscriptOverlay`, and live-source handler tests — they pin the tracked-agent behavior this change must not regress.
|
|
244
|
-
|
|
245
|
-
## Invariants at risk
|
|
246
|
-
|
|
247
|
-
Step 4 (#445) and Step 4a (#462) established invariants on the navigation surface; this step must preserve them:
|
|
248
|
-
|
|
249
|
-
- **Handler is a reactive consumer with no inbound call into the core** (Invariant #423/#445).
|
|
250
|
-
Pinned by the existing `session-navigator.test.ts` assertion `expect(record.getToolDefinition).not.toHaveBeenCalled()` in the live-source handler test.
|
|
251
|
-
The evicted path reads only `entry.outputFile` (a string) + the injected `readFile`; it makes no inbound call into a record.
|
|
252
|
-
- **Read-only, non-interactive overlay** (#445/#446).
|
|
253
|
-
The file source returns `subscribe: () => undefined` and `streaming: () => undefined`; the overlay's existing read-only behavior is unchanged.
|
|
254
|
-
Pinned by the existing overlay tests.
|
|
255
|
-
- **Renderer parity via Pi per-entry components** (#462).
|
|
256
|
-
The renderer is untouched; both sources still yield `SessionMessage[]` into the same `buildTranscriptComponents`.
|
|
257
|
-
Pinned by the existing `TranscriptOverlay` render tests.
|
|
258
|
-
|
|
259
|
-
No new test is needed for these — existing tests already pin them; the integration step keeps them green.
|
|
260
|
-
|
|
261
|
-
## TDD Order
|
|
262
|
-
|
|
263
|
-
1. **`fileSnapshotSource` (pure, additive).**
|
|
264
|
-
Surface: `test/ui/session-navigation.test.ts`.
|
|
265
|
-
Red: a `describe("fileSnapshotSource")` with a fake `readFile` returning fixture JSONL (a `session` header line + a couple of `message` entries) — assert messages parsed, header dropped, and the three static-source methods return `undefined`.
|
|
266
|
-
Green: implement `fileSnapshotSource` and the SDK runtime imports.
|
|
267
|
-
Commit: `test(pi-subagents): cover file-snapshot transcript source` then `feat(pi-subagents): add file-snapshot transcript source` (or a single `feat` commit with test + impl).
|
|
268
|
-
2. **Manager evicted-descriptor retention (additive).**
|
|
269
|
-
Surface: `test/lifecycle/subagent-manager.test.ts`.
|
|
270
|
-
Red: with fake timers, advance past the 10-minute cutoff and assert `listEvicted()` returns a descriptor for a completed agent with an `outputFile`, none for one without, and an empty set after `clearCompleted()`.
|
|
271
|
-
Green: add `EvictedSubagent`, the `evicted` map, capture in `cleanup()`, `clear()` in `clearCompleted()`/`dispose()`, `listEvicted()`, and `toEvictedSubagent`.
|
|
272
|
-
Run `pnpm run check` after this commit (new exported interface).
|
|
273
|
-
Commit: `feat(pi-subagents): retain evicted-agent descriptors in the manager`.
|
|
274
|
-
3. **Integrate: broaden the candidate set and dual-source the handler (breaking the `NavigationEntry` shape).**
|
|
275
|
-
This step changes `NavigationEntry` and `listNavigableAgents`'s signature, so the handler, `index.ts` call site, and both UI test files break and are updated together.
|
|
276
|
-
Surfaces: `src/ui/session-navigation.ts`, `src/ui/session-navigator.ts`, `src/index.ts`, `test/ui/session-navigation.test.ts`, `test/ui/session-navigator.test.ts`.
|
|
277
|
-
Red: update `listNavigableAgents` tests to the union shape and add the evicted-entry (marker + dedup) cases; add the handler evicted-path tests (file source + throwing-`readFile` notify).
|
|
278
|
-
Green: change `NavigationEntry` to the union, broaden `listNavigableAgents`, narrow `buildLabel`, add `evicted` + `readFile` to `SessionNavigatorParams`, switch the handler source by kind inside `try/catch`, and wire `manager.listEvicted()` + `readFileSync` in `index.ts`.
|
|
279
|
-
Run `pnpm run check` (shared interface change with a single non-test call site).
|
|
280
|
-
Commit: `feat(pi-subagents): source evicted-agent transcripts from disk in /subagent-sessions`.
|
|
281
|
-
4. **Docs.**
|
|
282
|
-
Update `docs/architecture/architecture.md` Step 4b to Landed (descriptor decision + dual-source realized) and the `S4b` diagram node to ✅; add the optional Addendum 2 note in `docs/decisions/0004-reconsider-ui-direction.md`.
|
|
283
|
-
Commit: `docs(pi-subagents): mark Phase 19 Step 4b landed (#463)`.
|
|
284
|
-
|
|
285
|
-
## Risks and Mitigations
|
|
286
|
-
|
|
287
|
-
- **Transient dead code between steps 1–2 and 3.**
|
|
288
|
-
`fileSnapshotSource` and `listEvicted()` have no caller until step 3.
|
|
289
|
-
CI / pre-completion `fallow dead-code` runs on the pushed tip, which is clean once step 3 lands; all steps ship in one push.
|
|
290
|
-
Mitigation: do not run `/ship-issue` before step 3 is committed.
|
|
291
|
-
- **`buildSessionContext` / `parseSessionEntries` behavior on malformed JSONL.**
|
|
292
|
-
Mitigation: the handler `try/catch` covers a throwing read/parse; a TDD fixture exercises a valid header-plus-messages file, and an empty-messages case confirms a graceful empty render.
|
|
293
|
-
- **Memory: the `evicted` map grows over a long session.**
|
|
294
|
-
Each descriptor is eight scalar fields (no messages), bounded by subagents spawned; the heavy session objects are still disposed.
|
|
295
|
-
`clearCompleted()` resets it per session.
|
|
296
|
-
- **Divergence from the issue's "enumerate persisted JSONL files" wording.**
|
|
297
|
-
Documented and operator-confirmed (descriptors over scan, for rich labels and bounded IO); the architecture/ADR notes record the rationale so the file-scan option is not silently lost.
|
|
298
|
-
|
|
299
|
-
## Open Questions
|
|
300
|
-
|
|
301
|
-
None — the candidate-set strategy and the evicted-entry marker were resolved with the operator during planning.
|
|
302
|
-
|
|
303
|
-
[#445]: https://github.com/gotgenes/pi-packages/issues/445
|
|
304
|
-
[#446]: https://github.com/gotgenes/pi-packages/issues/446
|
|
305
|
-
[#462]: https://github.com/gotgenes/pi-packages/issues/462
|
|
306
|
-
[#463]: https://github.com/gotgenes/pi-packages/issues/463
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 48
|
|
3
|
-
issue_title: "feat: implement and publish SubagentsService at extension init"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Retro: #48 — implement and publish SubagentsService at extension init
|
|
7
|
-
|
|
8
|
-
## Final Retrospective (2026-05-17T15:30:00Z)
|
|
9
|
-
|
|
10
|
-
### Session summary
|
|
11
|
-
|
|
12
|
-
Planned and implemented a typed `SubagentsService` interface with `Symbol.for()` accessor functions, an adapter wrapping `AgentManager` with model resolution and record serialization, and wired it into the extension init.
|
|
13
|
-
Released as `@gotgenes/pi-subagents@4.0.0` (breaking: old untyped global removed).
|
|
14
|
-
The plan was revised mid-session to align naming with `pi-permission-system`'s established conventions after the user flagged the discrepancy.
|
|
15
|
-
|
|
16
|
-
### Observations
|
|
17
|
-
|
|
18
|
-
#### What went well
|
|
19
|
-
|
|
20
|
-
- TDD execution was clean: 8 steps, zero rework, all 33 new tests green on first pass.
|
|
21
|
-
- The adapter design was well-scoped — `index.ts` wiring was +16/−12 lines, and the narrow `AgentManagerLike` interface made test mocks trivial.
|
|
22
|
-
- The allowlist serialization pattern (`toSubagentRecord`) prevents future leaks of non-serializable fields by default.
|
|
23
|
-
|
|
24
|
-
#### What caused friction (agent side)
|
|
25
|
-
|
|
26
|
-
- `missing-context` — The initial plan adopted the issue body's naming verbatim (`SubagentsAPI`, `api.ts`, `pi:service:subagents`, `(globalThis as any)`) without checking `pi-permission-system` for the established convention (`SubagentsService`, `service.ts`, `@gotgenes/<pkg>:service`, `Record<symbol, unknown>`).
|
|
27
|
-
The user had to explicitly ask "Does this structure follow the pattern set forth by pi-permission-system?"
|
|
28
|
-
Impact: full plan rewrite (replaced entire file), issue title update, issue body update — ~15 minutes of rework across 3 user turns.
|
|
29
|
-
This was **user-caught**.
|
|
30
|
-
|
|
31
|
-
- `missing-context` — Same pattern as the #49 retro: following the issue spec literally without checking the codebase.
|
|
32
|
-
The architecture doc also used the stale naming, reinforcing the wrong choice.
|
|
33
|
-
Root cause: the "Gather context" step in `/plan-issue` didn't include a cross-package convention check.
|
|
34
|
-
|
|
35
|
-
#### What caused friction (user side)
|
|
36
|
-
|
|
37
|
-
- The user had to perform mechanical oversight ("Does this follow the pi-permission-system pattern?") that the planner should have caught independently.
|
|
38
|
-
If the `/plan-issue` prompt included a step to grep sibling packages for established API patterns, this would have been a design decision surfaced during planning rather than a correction after the fact.
|
|
39
|
-
|
|
40
|
-
### Changes made
|
|
41
|
-
|
|
42
|
-
1. Created `packages/pi-subagents/docs/retro/0048-implement-subagents-api.md` (this file).
|
|
43
|
-
2. Updated `.pi/skills/package-pi-subagents/SKILL.md` — changed `SubagentsAPI` → `SubagentsService` in Implementation Priorities; added `service.ts` and `service-adapter.ts` to module dependency graph and descriptions.
|
|
44
|
-
3. Updated `.pi/prompts/plan-issue.md` — added step 7 to Gather context: check sibling packages for established API patterns before adopting issue body naming.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 49
|
|
3
|
-
issue_title: "feat: remove group-join, output-file, and ad-hoc RPC"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Retro: #49 — remove group-join, output-file, and ad-hoc RPC
|
|
7
|
-
|
|
8
|
-
## Final Retrospective (2026-05-17T15:15:00Z)
|
|
9
|
-
|
|
10
|
-
### Session summary
|
|
11
|
-
|
|
12
|
-
Planned and implemented the removal of group-join and ad-hoc RPC from `pi-subagents`, releasing v3.0.0.
|
|
13
|
-
The original scope included `output-file.ts` removal, but the user intervened to retain it for post-hoc debugging value.
|
|
14
|
-
A new issue (#61) was filed to port the output-file format to Pi's official JSONL session schema.
|
|
15
|
-
|
|
16
|
-
### Observations
|
|
17
|
-
|
|
18
|
-
#### What went well
|
|
19
|
-
|
|
20
|
-
- User intervention produced a materially better outcome — retaining debugging transcripts and identifying a format conformance gap that became #61.
|
|
21
|
-
- TDD execution was clean: 6 steps, zero rework, all tests green on first pass after each step.
|
|
22
|
-
- The `feat!:` → release-please → v3.0.0 pipeline worked smoothly end-to-end.
|
|
23
|
-
|
|
24
|
-
#### What caused friction (agent side)
|
|
25
|
-
|
|
26
|
-
- `missing-context` — Included `output-file.ts` removal in the initial plan without questioning its debugging value, despite AGENTS.md's rule "Ask before removing functionality or changing defaults."
|
|
27
|
-
The issue body explicitly listed it for removal so I followed the spec literally.
|
|
28
|
-
Impact: required plan revision (amend commit), scope-narrowing comment on issue, and filing #61 — roughly 10 minutes of rework, but produced a better design.
|
|
29
|
-
|
|
30
|
-
- `missing-context` — When asked whether output-file adheres to Pi's session format, searched the web (`web_search` for "Claude Code session JSONL format") instead of checking the local `~/development/pi/pi` monorepo.
|
|
31
|
-
The user had to explicitly say "~/development/pi/pi has the code for Pi's JSONL format."
|
|
32
|
-
Impact: one extra round-trip and less authoritative initial answer (Claude Code's format vs Pi's `SessionManager`).
|
|
33
|
-
Self-identified after user redirect.
|
|
34
|
-
|
|
35
|
-
- `instruction-violation` (self-identified) — Shell-escaped the `gh issue comment` body incorrectly; backtick-wrapped `src/output-file.ts` was interpreted by bash.
|
|
36
|
-
Caught immediately via `gh issue view` and fixed with `--edit-last`.
|
|
37
|
-
Impact: trivial — one extra command.
|
|
38
|
-
|
|
39
|
-
#### What caused friction (user side)
|
|
40
|
-
|
|
41
|
-
- The issue body listed output-file for removal without noting its debugging value.
|
|
42
|
-
The user's "How confident are we in getting rid of the logging system?"
|
|
43
|
-
intervention was the correction.
|
|
44
|
-
If the issue had marked output-file removal as "tentative pending debugging value assessment," the plan would have surfaced it as a design decision from the start.
|
|
45
|
-
Minor — the discussion was quick and productive.
|
|
46
|
-
|
|
47
|
-
### Changes made
|
|
48
|
-
|
|
49
|
-
1. Created `packages/pi-subagents/docs/retro/0049-remove-group-join-output-file-rpc.md` (this file).
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 51
|
|
3
|
-
issue_title: "docs: update ADR 0001 to reflect hard-fork decision"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Retro: #51 — docs: update ADR-0001 to reflect hard-fork decision
|
|
7
|
-
|
|
8
|
-
## Final Retrospective (2026-05-16)
|
|
9
|
-
|
|
10
|
-
### Session summary
|
|
11
|
-
|
|
12
|
-
Updated [ADR-0001] to reflect the hard-fork decision documented in `docs/architecture/architecture.md`.
|
|
13
|
-
The change was planned, implemented, shipped, and released as `pi-subagents-v1.0.2` in a single clean pass with no rework.
|
|
14
|
-
|
|
15
|
-
### Observations
|
|
16
|
-
|
|
17
|
-
#### What went well
|
|
18
|
-
|
|
19
|
-
- The entire plan→build→ship pipeline completed with zero corrections, zero CI failures, and zero user interventions.
|
|
20
|
-
- Parallel context gathering (issue body, `AGENTS.md`, ADR file, architecture doc, two skill files) in one tool call made the planning phase efficient.
|
|
21
|
-
- The 4-edit approach (`Edit` with a single call containing four `edits[]` entries) was well-matched to the task — each edit was small, unique, and non-overlapping.
|
|
22
|
-
|
|
23
|
-
#### What caused friction (agent side)
|
|
24
|
-
|
|
25
|
-
- No friction observed.
|
|
26
|
-
The task was unambiguous and the tooling well-suited.
|
|
27
|
-
|
|
28
|
-
#### What caused friction (user side)
|
|
29
|
-
|
|
30
|
-
- No friction observed.
|
|
31
|
-
The session required no user input beyond invoking the three slash commands.
|
|
32
|
-
|
|
33
|
-
### Follow-ups identified
|
|
34
|
-
|
|
35
|
-
- The `package-pi-subagents` skill (`.pi/skills/package-pi-subagents/SKILL.md`) still frames the fork as "a friendly fork… carrying a small number of patches" with priorities like "stays as close to upstream as possible."
|
|
36
|
-
This framing is now stale given the hard-fork commitment.
|
|
37
|
-
A separate issue should update the skill to reflect the architecture document's posture.
|
|
38
|
-
|
|
39
|
-
[ADR-0001]: ../decisions/0001-deferred-patches.md
|
|
@@ -1,40 +0,0 @@
|
|
|
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.
|
|
21
|
-
Verified as pre-existing (reproduced on prior commit via `git stash`), cleanly isolated into its own `fix:` commit.
|
|
22
|
-
This was a genuine find — the lint had been silently broken.
|
|
23
|
-
|
|
24
|
-
#### What caused friction (agent side)
|
|
25
|
-
|
|
26
|
-
- `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.
|
|
27
|
-
Two other call sites (`createSubagentsService` at line 386 and `getModelLabel` at line 1043) still needed it.
|
|
28
|
-
The plan explicitly listed `getModelLabel` as a non-goal that continues using `resolveModel`, so the information was available.
|
|
29
|
-
Caught immediately via `grep` after the edit and fixed in the same commit.
|
|
30
|
-
Impact: one extra edit + grep cycle, no rework.
|
|
31
|
-
|
|
32
|
-
- `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.
|
|
33
|
-
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.
|
|
34
|
-
Changed to `model: any` to match the existing `resolveModel` return type.
|
|
35
|
-
Impact: one extra edit cycle within the same commit, no rework.
|
|
36
|
-
|
|
37
|
-
#### What caused friction (user side)
|
|
38
|
-
|
|
39
|
-
- None observed.
|
|
40
|
-
The issue was well-scoped with clear acceptance criteria, making planning and execution straightforward.
|
|
@@ -1,53 +0,0 @@
|
|
|
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.
|
|
22
|
-
Each step left the repo green with no cascading breakage.
|
|
23
|
-
- The `createNotificationSystem` factory pattern with arrow-closure capture of `widget` (assigned after `AgentManager` construction) preserved the existing deferred-reference semantics without restructuring initialization order.
|
|
24
|
-
|
|
25
|
-
#### What caused friction (agent side)
|
|
26
|
-
|
|
27
|
-
- `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.
|
|
28
|
-
Used `unknown` for `ExtensionContext`, `AgentSession`, `ModelRegistry` in factory dep interfaces, requiring 9 `as any` casts in `index.ts`.
|
|
29
|
-
User caught this post-ship.
|
|
30
|
-
Impact: filed #66 as a follow-up cleanup; the casts are cosmetic (no runtime effect) but degrade type safety.
|
|
31
|
-
Fixed the code-style skill to clarify the boundary. (user-caught)
|
|
32
|
-
|
|
33
|
-
- `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.
|
|
34
|
-
Caught at the final `pnpm run check` step, not during test writing.
|
|
35
|
-
The testing skill already says "grep for ALL test files that construct a compatible mock."
|
|
36
|
-
Impact: one extra fix cycle delegated to a subagent, no rework beyond that step. (self-identified)
|
|
37
|
-
|
|
38
|
-
- `other` — `Edit` tool failed 3 times matching the UTF-8 middle dot (`·`, U+00B7) in the steer tool's `stateParts.join(" · ")` line.
|
|
39
|
-
The third attempt produced a partial match that left the file in a broken state (dangling orphan code after the replacement anchor).
|
|
40
|
-
Required `git restore` and a fallback to `python3` line-range replacement.
|
|
41
|
-
The same `python3` approach for the menu extraction lost the closing `}` of the default export function.
|
|
42
|
-
Impact: ~5 minutes of rework across the two extraction steps, plus one `git restore`.
|
|
43
|
-
|
|
44
|
-
#### What caused friction (user side)
|
|
45
|
-
|
|
46
|
-
- The `as any` casts could have been caught earlier if the user had flagged the `unknown` types during the planning phase.
|
|
47
|
-
However, the plan didn't prescribe exact interface types — that was an implementation decision.
|
|
48
|
-
The user's post-ship review ("Why did we have to cast `as any`?
|
|
49
|
-
Take a look at `packages/pi-permission-system/` as a model") was an efficient redirect that immediately scoped the investigation.
|
|
50
|
-
|
|
51
|
-
### Changes made
|
|
52
|
-
|
|
53
|
-
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.
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 57
|
|
3
|
-
issue_title: "feat: structured debug logging for silenced catch blocks"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Retro: #57 — structured debug logging for silenced catch blocks
|
|
7
|
-
|
|
8
|
-
## Final Retrospective (2026-05-19T10:30:00Z)
|
|
9
|
-
|
|
10
|
-
### Session summary
|
|
11
|
-
|
|
12
|
-
Added `src/debug.ts` with `debugLog` and `isDebug()`, then threaded `debugLog` into ~20 silent `catch` blocks across 9 files.
|
|
13
|
-
All 7 TDD cycles went green on the first pass with no rework.
|
|
14
|
-
Shipped as `pi-subagents-v5.1.0`, then followed up with a `refactor:` commit converting `DEBUG` (module-level constant) to `isDebug()` (function getter) during the retro.
|
|
15
|
-
|
|
16
|
-
### Observations
|
|
17
|
-
|
|
18
|
-
#### What went well
|
|
19
|
-
|
|
20
|
-
- The plan's "Non-Goals" section correctly excluded `usage.ts` and `settings.ts` before implementation started, and a post-TDD `grep -rn 'catch\s*{'` confirmed only those two in-scope-excluded files remained.
|
|
21
|
-
Closing the loop with a verification query is worth repeating.
|
|
22
|
-
- The scope of the change was so well-defined (the issue listed exact file names) that no `ask_user` call was needed during planning.
|
|
23
|
-
|
|
24
|
-
#### What caused friction (agent side)
|
|
25
|
-
|
|
26
|
-
- `missing-context` — When loading the `ask-user` skill I guessed `.pi/skills/ask-user/SKILL.md` before reading the actual `<location>` tag in `AGENTS.md`, triggering an ENOENT error and a follow-up `find` call.
|
|
27
|
-
Impact: 2 extra tool calls, no rework. (self-identified)
|
|
28
|
-
|
|
29
|
-
- `other` — The plan's TDD Order step 1 stated *"the test skill documents this pattern"* for `vi.resetModules()` + dynamic import when testing module-level env constants — but the testing skill does not have that entry.
|
|
30
|
-
The aspiration was recorded rather than verified.
|
|
31
|
-
During the retro, the user's question ("should that be a function getter instead?") led to a better outcome: replace the module-level constant with `isDebug()` so `vi.stubEnv()` alone works, consistent with how every other `process.env` read in this codebase is structured.
|
|
32
|
-
Impact: one retro-phase `refactor:` commit; the approach shipped in `v5.1.0` was technically correct but unnecessarily complex to test.
|
|
33
|
-
|
|
34
|
-
#### What caused friction (user side)
|
|
35
|
-
|
|
36
|
-
- The initial issue proposal chose the module-level-constant pattern (common in Node.js tooling like the `debug` package).
|
|
37
|
-
A note in the issue or plan about preferring function-based env reads for testability would have caught this at design time rather than post-ship.
|
|
38
|
-
That said, the retro question was efficient — a single targeted redirect resolved it cleanly.
|
|
39
|
-
|
|
40
|
-
### Changes made
|
|
41
|
-
|
|
42
|
-
1. `packages/pi-subagents/src/debug.ts` — replaced `export const DEBUG` with `export function isDebug()`.
|
|
43
|
-
2. `packages/pi-subagents/test/debug.test.ts` — simplified to static import + `vi.stubEnv()` only; removed all `vi.resetModules()` + dynamic `import()` calls.
|
|
44
|
-
3. `.pi/skills/testing/SKILL.md` — added bullet: prefer reading `process.env` inside functions; `vi.stubEnv()` alone is insufficient for module-level constants.
|
|
45
|
-
|
|
46
|
-
## Follow-up Retrospective (2026-05-19T11:15:00Z)
|
|
47
|
-
|
|
48
|
-
### Session summary
|
|
49
|
-
|
|
50
|
-
The user asked how many `process.*` reads exist in `pi-subagents`.
|
|
51
|
-
Audit found 9 sites: 4 acceptable (wiring layer, detection functions, injectable defaults), 2 genuine injection gaps, and 1 mild case.
|
|
52
|
-
Filed #76 (`AgentManager.dispose()` reads `process.cwd()` without a stored `cwd`) and #77 (`createAgentsMenuHandler` hardcodes `process.cwd()` when `AgentMenuDeps` already injects the personal-side equivalent).
|
|
53
|
-
|
|
54
|
-
### Observations
|
|
55
|
-
|
|
56
|
-
#### What went well
|
|
57
|
-
|
|
58
|
-
- The `isDebug()` refactor naturally led the user to ask a broader design question about `process.*` access patterns, producing two well-scoped follow-up issues without manual triage.
|
|
59
|
-
- The audit categorization (genuinely problematic vs. acceptable) was clean — presenting a table with verdicts per site let the user decide scope without re-reading source.
|
|
60
|
-
|
|
61
|
-
#### What caused friction (agent side)
|
|
62
|
-
|
|
63
|
-
- `premature-convergence` — The original plan accepted the module-level `DEBUG` constant without checking how the rest of the codebase reads `process.env`.
|
|
64
|
-
The code-style skill said "keep IO at the edges" but didn't name `process.*` specifically, so the rule wasn't applied.
|
|
65
|
-
Impact: one post-ship `refactor:` commit to replace `DEBUG` with `isDebug()`; the pattern was technically correct but inconsistent with codebase conventions. (user-caught)
|
|
66
|
-
|
|
67
|
-
#### What caused friction (user side)
|
|
68
|
-
|
|
69
|
-
- Nothing notable.
|
|
70
|
-
The user's two redirecting questions ("should that be a function?"
|
|
71
|
-
and "how many places access `process.*`?") were well-timed interventions that broadened scope productively.
|
|
72
|
-
|
|
73
|
-
### Changes made
|
|
74
|
-
|
|
75
|
-
1. `.pi/skills/code-style/SKILL.md` — added bullet: do not read `process.env`, `process.cwd()`, or `process.platform` inside library/utility functions; accept the value as a parameter.
|
|
76
|
-
2. Filed #76 — inject `cwd` into `AgentManager` constructor.
|
|
77
|
-
3. Filed #77 — add `projectAgentsDir` to `AgentMenuDeps`.
|