@gotgenes/pi-subagents 16.4.0 → 16.5.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 +9 -0
- package/dist/public.d.ts +7 -4
- package/docs/architecture/architecture.md +182 -209
- package/docs/architecture/history/phase-17-core-consolidation.md +214 -0
- package/docs/plans/0412-unify-session-mock-builders.md +146 -0
- package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +228 -0
- package/docs/retro/0380-extract-layered-settings-loader.md +49 -0
- package/docs/retro/0412-unify-session-mock-builders.md +80 -0
- package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +45 -0
- package/package.json +1 -1
- package/src/lifecycle/subagent-state.ts +49 -4
- package/src/lifecycle/subagent.ts +4 -0
- package/src/observation/record-observer.ts +25 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@ 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
|
+
## [16.5.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v16.4.0...pi-subagents-v16.5.0) (2026-06-17)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* accumulate live activity in record-observer ([#420](https://github.com/gotgenes/pi-packages/issues/420)) ([c75e7cf](https://github.com/gotgenes/pi-packages/commit/c75e7cf20e44116743fc847238b4364a1edda25a))
|
|
14
|
+
* add live-activity fields to SubagentState ([#420](https://github.com/gotgenes/pi-packages/issues/420)) ([713f19a](https://github.com/gotgenes/pi-packages/commit/713f19aa13306b6c41dc54f3ddfa73fcdfc65427))
|
|
15
|
+
* expose live-activity getters on Subagent ([#420](https://github.com/gotgenes/pi-packages/issues/420)) ([6438d6c](https://github.com/gotgenes/pi-packages/commit/6438d6ca0fdb25b1dfeffa0f76a1eae8630f0cce))
|
|
16
|
+
|
|
8
17
|
## [16.4.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v16.3.1...pi-subagents-v16.4.0) (2026-06-16)
|
|
9
18
|
|
|
10
19
|
|
package/dist/public.d.ts
CHANGED
|
@@ -30,12 +30,15 @@ type LifetimeUsage = {
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* subagent-state.ts — SubagentState value object: lifecycle status and
|
|
33
|
+
* subagent-state.ts — SubagentState value object: lifecycle status, metrics, and live activity.
|
|
34
34
|
*
|
|
35
35
|
* Owns the passive, readable state of a subagent — status, result, error,
|
|
36
|
-
* timestamps,
|
|
37
|
-
*
|
|
38
|
-
* methods (
|
|
36
|
+
* timestamps, stats (toolUses, lifetimeUsage, compactionCount), and live-activity
|
|
37
|
+
* fields (turnCount, activeTools, responseText) — together with the transition
|
|
38
|
+
* methods (markRunning, markCompleted, …), accumulation methods
|
|
39
|
+
* (incrementToolUses, addUsage, incrementCompactions), and live-activity
|
|
40
|
+
* transition methods (incrementTurnCount, addActiveTool, removeActiveTool,
|
|
41
|
+
* resetResponseText, appendResponseText) that mutate them.
|
|
39
42
|
*
|
|
40
43
|
* State is encapsulated behind getters; external code reads through them but
|
|
41
44
|
* mutates only via the transition/accumulation methods. The value object owns
|
|
@@ -271,7 +271,7 @@ sequenceDiagram
|
|
|
271
271
|
|
|
272
272
|
## Module organization
|
|
273
273
|
|
|
274
|
-
The extension has
|
|
274
|
+
The extension has 62 source files organized into six domains plus entry-point wiring.
|
|
275
275
|
All eight domains have directories: `config/`, `session/`, `lifecycle/`, `observation/`, `service/`, `tools/`, `ui/`, and `handlers/`.
|
|
276
276
|
Issue #164 moved the 26 previously flat root-level files into five new domain directories, reducing the root to 5 files + 8 directories.
|
|
277
277
|
|
|
@@ -284,6 +284,7 @@ src/
|
|
|
284
284
|
├── types.ts shared type definitions
|
|
285
285
|
├── settings.ts SettingsManager (persistent operational settings)
|
|
286
286
|
├── debug.ts debug logging utility
|
|
287
|
+
├── layered-settings.ts loadLayeredSettings helper (published as @gotgenes/pi-subagents/settings)
|
|
287
288
|
│
|
|
288
289
|
├── config/ agent type definitions and resolution
|
|
289
290
|
│ ├── agent-types.ts AgentTypeRegistry class
|
|
@@ -320,7 +321,8 @@ src/
|
|
|
320
321
|
│ ├── record-observer.ts session-event stats observer
|
|
321
322
|
│ ├── notification.ts completion nudges
|
|
322
323
|
│ ├── notification-state.ts per-agent notification tracking
|
|
323
|
-
│
|
|
324
|
+
│ ├── renderer.ts notification TUI component
|
|
325
|
+
│ └── subagent-events-observer.ts manager lifecycle observer (event emission + persistence + notification)
|
|
324
326
|
│
|
|
325
327
|
├── service/ cross-extension API boundary
|
|
326
328
|
│ ├── service.ts SubagentsService interface + Symbol.for() accessors
|
|
@@ -520,7 +522,7 @@ The governing rule — **no vacant hooks**: the architecture must _admit_ a seam
|
|
|
520
522
|
A provider seam with no consumer is a speculative abstraction that taxes every reader and that `fallow` flags as dead.
|
|
521
523
|
Latent extensibility is the deliverable; a vacant hook is not.
|
|
522
524
|
|
|
523
|
-
The [first-principles refinement](#first-principles-refinement-the-deeper-target) below sharpens this two-surface split.
|
|
525
|
+
The [first-principles refinement](#first-principles-refinement-and-the-deeper-target) below sharpens this two-surface split.
|
|
524
526
|
The awaited, behavior-affecting lifecycle events (notably `session-created` before `bindExtensions`) are _hooks_ — the child's own extension surface applied recursively, generative because the core waits on the handler before deciding what to do next.
|
|
525
527
|
The observational surface then carries only fire-and-forget broadcasts of immutable snapshots, which no consumer can use to change the core.
|
|
526
528
|
|
|
@@ -554,14 +556,14 @@ In the target state, pi-subagents publishes events and a provider seam; other pa
|
|
|
554
556
|
|
|
555
557
|
- **pi-permission-system** (observational) subscribes to child-session lifecycle events, detects subagent execution context in the child, and gates tool calls at runtime.
|
|
556
558
|
- **pi-subagents-worktrees** (generative) registers a `WorkspaceProvider` that prepares a git worktree at run-start and tears it down after, supplying the child's cwd.
|
|
557
|
-
- **pi-subagents-ui** (future, under reconsideration — see the [first-principles refinement](#first-principles-refinement-the-deeper-target)) subscribes to the broadcast and the query/behavior interfaces; whether the inherited widget, conversation viewer, and `/agents` menu survive is judged on our principles, not preserved by default.
|
|
559
|
+
- **pi-subagents-ui** (future, under reconsideration — see the [first-principles refinement](#first-principles-refinement-and-the-deeper-target)) subscribes to the broadcast and the query/behavior interfaces; whether the inherited widget, conversation viewer, and `/agents` menu survive is judged on our principles, not preserved by default.
|
|
558
560
|
- **Any future extension** (OTel, auditing, cost tracking) subscribes to the same events without pi-subagents knowing.
|
|
559
561
|
|
|
560
562
|
Composition test: install neither extension, only permissions, only workspaces, or both — the core is byte-for-byte identical in all four cases, and the two extensions never reference each other.
|
|
561
563
|
|
|
562
564
|
This is achieved across phases: Phase 14 (strip policy), Phase 16 (invert dependencies — extensions on a minimal core), and Phase 18 (reconsider UI).
|
|
563
565
|
|
|
564
|
-
### First-principles refinement
|
|
566
|
+
### First-principles refinement and the deeper target
|
|
565
567
|
|
|
566
568
|
The two-surface model above is correct but coarse.
|
|
567
569
|
Pushing it against our own principles — construct complete, state owns its mutations, tell-don't-ask, dependency inversion — surfaces sharper boundaries that the current code draws through the middle of classes.
|
|
@@ -646,13 +648,13 @@ That method — testability friction as a boundary probe, with its limits — is
|
|
|
646
648
|
| Metric | Value |
|
|
647
649
|
| -------------------------- | -------------------------------------------- |
|
|
648
650
|
| Health score | 78/100 (B) |
|
|
649
|
-
| Total LOC |
|
|
651
|
+
| Total LOC | 7,751 (62 files, end of Phase 17) |
|
|
650
652
|
| Dead code | 0 files, 0 exports |
|
|
651
653
|
| Maintainability index | 90.8 (good) |
|
|
652
654
|
| Avg cyclomatic complexity | 1.4 |
|
|
653
655
|
| P90 cyclomatic complexity | 2 |
|
|
654
656
|
| Production duplication | 11 lines (1 internal clone group) |
|
|
655
|
-
| Test duplication |
|
|
657
|
+
| Test duplication | 28 clone groups, 503 lines (end of Phase 17) |
|
|
656
658
|
| Fallow refactoring targets | 0 |
|
|
657
659
|
|
|
658
660
|
### Dependency bag inventory
|
|
@@ -877,202 +879,163 @@ All five steps are closed: [#261], [#262], [#263], [#264], [#265].
|
|
|
877
879
|
The earlier "agent collaborator architecture" framing (#256 superseded, #257 parked, #258 and #259 closed not-planned) was abandoned; its structural win was reached cleanly via the workspace seam.
|
|
878
880
|
See [phase-16-invert-dependencies.md](history/phase-16-invert-dependencies.md) for details.
|
|
879
881
|
|
|
880
|
-
##
|
|
882
|
+
## Phase 17 (complete)
|
|
883
|
+
|
|
884
|
+
Phase 17 consolidated the core's remaining structural debt before the UI reconsideration (Phase 18).
|
|
885
|
+
The `Subagent` record/executor duality was resolved by extracting `SubagentState` (status, result, timestamps, metrics) into a private owned value object and making `SubagentExecution` a mandatory constructor collaborator — eliminating ~20 optional fields and the two "not configured for execution" runtime throws.
|
|
886
|
+
The concurrency queue was replaced with a thunk-based `ConcurrencyLimiter` that knows nothing about agents or IDs.
|
|
887
|
+
Run collaborators (`RunListeners`, `WorkspaceBracket`) were extracted from the 455-LOC `Subagent` class.
|
|
888
|
+
The inline `SubagentManagerObserver` literal was promoted to `SubagentEventsObserver`, making its three concerns (event emission, record persistence, notification dispatch) unit-testable in isolation.
|
|
889
|
+
Widget delegation and the post-construction `runtime.widget =` write were removed from `SubagentRuntime` by dissolving the notification→widget cycle via `AgentWidget.seedFinishedAgents`.
|
|
890
|
+
Lifecycle, UI/tools, and cross-package test fixture clones were consolidated.
|
|
891
|
+
`loadLayeredSettings<T>` was extracted to `src/layered-settings.ts` and published via the `@gotgenes/pi-subagents/settings` subpath export, eliminating the 23-line production clone with `pi-subagents-worktrees`.
|
|
892
|
+
All nine steps are closed: [#381], [#373], [#374], [#375], [#376], [#377], [#378], [#379], [#380].
|
|
893
|
+
[#412] unified the overlapping session-mock builders identified during Step 7.
|
|
894
|
+
[#415] migrated `pi-subagents-worktrees` to `loadLayeredSettings` after the Step 9 published release.
|
|
895
|
+
See [phase-17-core-consolidation.md](history/phase-17-core-consolidation.md) for the full findings, step outcomes, dependency diagram, and tracks.
|
|
896
|
+
|
|
897
|
+
## Phase 18 Reconsider UI from first principles
|
|
898
|
+
|
|
899
|
+
After 17 phases the core is in very good shape: health 78/100 (B), zero dead code, zero fallow refactoring targets, average cyclomatic 1.4.
|
|
900
|
+
The one structural debt that remains is not spread thin across the core — it is concentrated in a single place: the UI's live-streaming state (the "activity tier") is woven into the core's runtime, spawn tools, the LLM-facing `subagent` tool, and the notification path.
|
|
901
|
+
This is the entanglement the [first-principles refinement](#first-principles-refinement-and-the-deeper-target) predicted — "the activity/metrics push tier is provisional; its only reactive consumer is the inherited widget" — observed in the code.
|
|
902
|
+
Disentangling it is what lets the core reach a great state, and it is the prerequisite to any "reconsider the UI" decision: today the UI cannot be a clean consumer because the core does its streaming bookkeeping for it.
|
|
903
|
+
|
|
904
|
+
### Findings
|
|
905
|
+
|
|
906
|
+
Six findings tell one story — the activity tier has metastasized out of the UI and into the core.
|
|
907
|
+
|
|
908
|
+
1. **UI state lives on the core runtime.**
|
|
909
|
+
`SubagentRuntime.agentActivity: Map<string, AgentActivityTracker>` puts a UI streaming-state map on the core composition root.
|
|
910
|
+
`SubagentRuntime` owns session-scoped lifecycle state; `AgentActivityTracker` (active tools, response text, turn count) is pure rendering state the core never reads.
|
|
911
|
+
Category C (coupling).
|
|
912
|
+
2. **Core spawn tools wire UI streaming.**
|
|
913
|
+
`foreground-runner.ts` and `background-spawner.ts` construct `AgentActivityTracker`, call `subscribeUIObserver` (a second session subscription parallel to the core's own `record-observer`), call `setSession`, and populate or delete the activity map and drive the widget (`ensureTimer`, `update`, `markFinished`).
|
|
914
|
+
Their own doc comments list "AgentActivityTracker creation, UI observer subscription" as responsibilities.
|
|
915
|
+
Category C (mixed responsibility, parameter relay).
|
|
916
|
+
3. **The LLM-facing tool depends on the widget.**
|
|
917
|
+
`AgentTool` takes a 4-method `widget` dependency plus `runtime.agentActivity` and calls `this.widget.setUICtx(ctx.ui)`.
|
|
918
|
+
Every `AgentTool` unit test must stub the widget and the activity map (`createToolDeps`), although the tool's real concern is dispatch — testability friction marking a domain seam.
|
|
919
|
+
Category C/D.
|
|
920
|
+
4. **Two parallel observers split the run-metric domain.**
|
|
921
|
+
Each child session gets two subscriptions: `record-observer` accumulates `SubagentState` (tool uses, usage, compactions) and `ui-observer` accumulates `AgentActivityTracker` (active tools, response text, turn count).
|
|
922
|
+
`turnCount` is a genuine run metric that lives only in the UI tracker, so `notification.ts` and the foreground result text reach into the tracker to recover it.
|
|
923
|
+
Category C (anemic split, duplication).
|
|
924
|
+
5. **A core observation concern reaches into UI state.**
|
|
925
|
+
`NotificationManager` holds the activity map and reads `turnCount`/`maxTurns` from it to build notification details, and deletes entries from it.
|
|
926
|
+
Category C (Law of Demeter).
|
|
927
|
+
6. **The public event contract is both vacant and incomplete.**
|
|
928
|
+
`SUBAGENT_EVENTS.ACTIVITY = "subagents:activity"` is declared in the service surface and the doc's lifecycle-events table but is never emitted anywhere — a vacant hook the doc's own "no vacant hooks" rule forbids.
|
|
929
|
+
Meanwhile three emitted channels (`subagents:failed`, `subagents:compacted`, `subagents:created`) are absent from the constant map.
|
|
930
|
+
Category A/E.
|
|
881
931
|
|
|
882
|
-
|
|
883
|
-
The findings come from the standard discovery pass — fallow suite, entry-point trace, design-review checklist, and test-constructibility audit — run after Phase 16 landed.
|
|
884
|
-
|
|
885
|
-
Phase 17 is the consolidation slice of the [first-principles refinement](#first-principles-refinement-the-deeper-target), not the full domain split.
|
|
886
|
-
It lands the first cut of the lifecycle-state domain (Step 2's `SubagentState`) plus the wiring, queue, and duplication cleanups.
|
|
887
|
-
The fuller four-domain split — metrics as a projection, result delivery as its own domain, the hook/broadcast reclassification, and the push/pull (DIP) inversion — is recorded in the refinement and sequenced into later phases.
|
|
888
|
-
|
|
889
|
-
### Findings summary
|
|
890
|
-
|
|
891
|
-
Updated health metrics (fallow, package-wide including tests):
|
|
892
|
-
|
|
893
|
-
| Metric | Phase 16 baseline | Current |
|
|
894
|
-
| -------------------------- | ------------------------------ | ------------------------------------------------------------------ |
|
|
895
|
-
| Health score | 78/100 (B) | 78/100 (B) |
|
|
896
|
-
| Source LOC | 7,778 (57 files) | 8,356 (61 files, landed Phase 17 Step 5) |
|
|
897
|
-
| Dead code | 0 files, 0 exports | 0 files, 0 exports |
|
|
898
|
-
| Maintainability index | 90.8 (good) | 90.8 (good) |
|
|
899
|
-
| Avg / P90 cyclomatic | 1.4 / 2 | 1.4 / 2 |
|
|
900
|
-
| Production duplication | 11 lines (1 internal group) | 11 lines (1 internal group; cross-package pair resolved in Step 9) |
|
|
901
|
-
| Test duplication | 42 groups, 661 lines | 44 groups, ~750 lines |
|
|
902
|
-
| Fallow refactoring targets | 0 | 0 |
|
|
903
|
-
| Top churn hotspot | `index.ts` 65.0 ▲ accelerating | `index.ts` 31.3 ▼ cooling |
|
|
904
|
-
|
|
905
|
-
The syntactic metrics are healthy and stable — the remaining debt is structural, mostly invisible to fallow, and concentrated in three places:
|
|
906
|
-
|
|
907
|
-
1. **`Subagent` construction duality.**
|
|
908
|
-
`SubagentInit` carries ~20 fields, nearly all optional with "required for run(), optional for tests" semantics, and `run()` compensates with runtime throws ("not configured for execution").
|
|
909
|
-
This violates principle 8 (construct complete): the class is simultaneously a passive record (tests build display-only snapshots) and an executor (production wires factory, observer, run config, workspace provider).
|
|
910
|
-
The symptoms are in the tests: external writes `record.promise = …` (manager, queue callback, four test files) and `record.notification = new NotificationState(…)` (seven test sites) are output-argument smells on fields the object should own.
|
|
911
|
-
This duality is the two most visible of four domains fused into `Subagent`; Phase 17 resolves it (Step 2) and defers the remaining split (metrics, result delivery) to a later phase per the [first-principles refinement](#first-principles-refinement-the-deeper-target).
|
|
912
|
-
2. **Wiring debt in `index.ts`.**
|
|
913
|
-
Two forward references (settings → queue, queue → manager) are replicated with an `eslint-disable prefer-const` dance in `test/lifecycle/subagent-manager.test.ts`; the queue's start callback (`record.promise = record.run()` after a status check) is duplicated verbatim between `index.ts` and the test helper.
|
|
914
|
-
A ~70-line inline `SubagentManagerObserver` literal mixes three concerns (event emission, `appendEntry` persistence, notification dispatch).
|
|
915
|
-
`runtime.widget` is assigned post-construction behind five relay-only delegation methods on `SubagentRuntime`.
|
|
916
|
-
3. **Duplication.**
|
|
917
|
-
A 23-line cross-package production clone (`settings.ts:198-211` ↔ `pi-subagents-worktrees/src/config.ts:51-73`: the layered global/project settings-file loader) and 44 test clone groups (~750 lines), with clone families concentrated in `test/lifecycle/` and `test/ui/`.
|
|
932
|
+
### Health metrics
|
|
918
933
|
|
|
919
|
-
|
|
934
|
+
| Metric | Value |
|
|
935
|
+
| ---------------------------------------- | ------------------------------------------------------------------ |
|
|
936
|
+
| Health score | 78/100 (B) |
|
|
937
|
+
| Source LOC | 7,751 (62 files) |
|
|
938
|
+
| Dead code | 0 files, 0 exports |
|
|
939
|
+
| Maintainability index | 90.9 (good) |
|
|
940
|
+
| Avg cyclomatic complexity | 1.4 |
|
|
941
|
+
| P90 cyclomatic complexity | 2 |
|
|
942
|
+
| Fallow refactoring targets | 0 |
|
|
943
|
+
| Production duplication | 11 lines (1 internal clone group in `agent-config-editor.ts`) |
|
|
944
|
+
| Test duplication | 28 clone groups, 503 lines |
|
|
945
|
+
| Activity-tier modules slated for removal | `ui-observer.ts` (61) + `agent-activity-tracker.ts` (84) = 145 LOC |
|
|
920
946
|
|
|
921
947
|
### Steps
|
|
922
948
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
`Subagent.wireSignal`, `attachObserver`, and `releaseListeners` are removed.
|
|
981
|
-
`subagent.ts`: 488 → 448 LOC.
|
|
982
|
-
Test count: 982 → 994 (+12: 7 RunListeners + 13 WorkspaceBracket − 8 redundant Subagent listener tests).
|
|
983
|
-
|
|
984
|
-
#### Step 5 — Extract the manager observer from index.ts into a class ([#376]) ✅ Complete
|
|
985
|
-
|
|
986
|
-
- Targets: `src/index.ts` (inline `SubagentManagerObserver` literal, ~70 lines), new module under `src/observation/`.
|
|
987
|
-
- Smell: Category B/E — `index.ts` is the dominant churn hotspot (31.3, 91 commits); the literal mixes event emission, record persistence (`appendEntry`), and notification dispatch; principle 9 (state and behavior belong in classes, not closure-captured literals).
|
|
988
|
-
- Change: extract a class (e.g. `SubagentEventsObserver`) constructed with narrow deps (`emit`, `appendEntry`, the `NotificationSystem`).
|
|
989
|
-
- Outcome: `index.ts` < 170 lines; the observer's three concerns unit-tested directly without booting the extension.
|
|
990
|
-
- Landed: `src/observation/subagent-events-observer.ts` (new, 97 LOC); `index.ts` 226 → 177 lines; 60 → 61 source files; 994 → 1009 tests (+15 covering all four observer methods).
|
|
991
|
-
|
|
992
|
-
#### Step 6 — Split widget delegation out of SubagentRuntime ([#377]) ✅ Complete
|
|
993
|
-
|
|
994
|
-
- Targets: `src/runtime.ts`, `src/tools/agent-tool.ts` (`AgentToolRuntime`), `src/handlers/tool-start.ts` (`ToolStartRuntime`), `src/observation/notification.ts` (`NotificationManager` constructor), `src/ui/agent-widget.ts`, `src/index.ts`.
|
|
995
|
-
- Smell: Category C — relay-only dependency (five delegation methods that only forward to `widget`) and a post-construction `runtime.widget =` write violating principle 8.
|
|
996
|
-
- Constraint discovered in planning: "pass the handle directly to the consumers" is infeasible for `NotificationManager`, which is a _transitive dependency_ of the widget (`NotificationManager → widget → manager → observer → NotificationManager`).
|
|
997
|
-
The `runtime.widget` lazy field exists to break exactly this cycle; removing it forces the one late seam to move, and the operator's principles (no setters, instantiate ready-to-work) rule out relocating it to a setter or forward-ref `let`.
|
|
998
|
-
- Change (tidy-first): first dissolve the cycle by giving `AgentWidget.update()` self-seeding of `finishedTurnAge` for finished agents it observes via `listAgents()`, then drop the `markFinished`/`updateWidget` callbacks from `NotificationManager` (it keeps `agentActivity.delete` + nudge scheduling).
|
|
999
|
-
With the cycle gone, the widget is constructed as a `const` after the manager and injected directly into `AgentTool` and `ToolStartHandler`; the `widget` field, the five relay methods, and the post-construction write delete cleanly, and `AgentToolRuntime` narrows to its context-query slice.
|
|
1000
|
-
- Outcome: `SubagentRuntime` has zero widget knowledge; no post-construction field writes in `index.ts`; the construction graph is a cycle-free DAG (`notifications → observer → manager → widget → {AgentTool, ToolStartHandler}`).
|
|
1001
|
-
- Landed: `AgentWidget.seedFinishedAgents` owns completion detection; `NotificationManager` has no widget dependency (2-arg constructor); `AgentToolWidget` (in `agent-tool.ts`) and `ToolStartWidget` (in `tool-start.ts`) are narrow per-consumer interfaces the real widget satisfies structurally; tool fixtures stub a `widget` separate from the narrowed `runtime` mock.
|
|
1002
|
-
Behavior-preserving: the widget timer runs through every background completion, so self-seeding lands ≤80ms later within the same turn (linger is turn-based).
|
|
1003
|
-
Test count: 1009 → 1005 (+3 widget self-seed tests, −7 removed relay/field tests).
|
|
1004
|
-
|
|
1005
|
-
#### Step 7 — Consolidate lifecycle test fixtures ([#378]) ✅ Complete
|
|
1006
|
-
|
|
1007
|
-
- Targets: `test/lifecycle/subagent-manager.test.ts`, `test/lifecycle/subagent-session.test.ts`, `test/lifecycle/create-subagent-session.test.ts`, `test/lifecycle/create-subagent-session-extension-tools.test.ts` (deleted), `test/helpers/subagent-session-io.ts`.
|
|
1008
|
-
- Smell: Category D — at planning time fallow reported four clone families across the lifecycle tests (the issue's "five" predated Steps 1–6, which renamed the queue and dissolved the `subagent.test.ts`/`concurrency-limiter.test.ts` families).
|
|
1009
|
-
- Change: extract the repeated spawn/run/factory arrangements into shared helpers, migrating incrementally (lift-and-shift, never a single-step rewrite of a large test file).
|
|
1010
|
-
- Outcome: package test duplication below 600 lines; lifecycle clone families reduced, with the residual deliberately left as the visible test subject (see Landed).
|
|
1011
|
-
- Landed: added a shared `createFactorySession` mock-session builder (`test/helpers/subagent-session-io.ts`); grouped the `createSubagentSession` arrange into describe-scoped `beforeEach` hooks with the `createSubagentSession(...)` act kept explicit per test (AAA); extracted a `programTurns` arrange helper for the turn-limit tests; consolidated the manager spawn/queued-pair arrangements; and folded `create-subagent-session-extension-tools.test.ts` (4 post-bind guard tests) into `create-subagent-session.test.ts`, deleting the file and its duplicated scaffolding.
|
|
1012
|
-
Package test duplication: 669 → 512 lines; test files 64 → 63; test count 1005 → 1010 (+5 `createFactorySession` self-tests).
|
|
1013
|
-
Two lifecycle clone families remain (`create-subagent-session.test.ts` ~29 lines, `subagent-manager.test.ts` ~23 lines): both are the repeated `await createSubagentSession(...)` / `spawn(...)` **act** with test-specific arrange, intentionally not extracted because hiding the system-under-test behind a helper is the wrong abstraction for test code (Sandi Metz: "duplication is far cheaper than the wrong abstraction").
|
|
1014
|
-
Lesson: the original "families ≤ 1" target was a weak signal for _test_ code — an early act-wrapping helper that hit the metric was reverted in favour of the AAA structure above; the metric was relaxed deliberately.
|
|
1015
|
-
The three overlapping session-mock builders this surfaced are tracked separately ([#412]).
|
|
1016
|
-
|
|
1017
|
-
#### Step 8 — Consolidate UI and tools test fixtures ([#379]) ✅ Complete
|
|
1018
|
-
|
|
1019
|
-
- Targets: `test/ui/agent-creation-wizard.test.ts`, `test/ui/agent-config-editor.test.ts`, `test/ui/ui-observer.test.ts`, `test/tools/foreground-runner.test.ts`, `test/tools/background-spawner.test.ts`, `test/session/session-config.test.ts`, and `test/service/service-adapter.test.ts` (a seventh non-lifecycle family fallow reports; added to scope in planning).
|
|
1020
|
-
- Smell: Category D — remaining clone families outside the lifecycle tree.
|
|
1021
|
-
- Change: extract per-file repeated arrangements into local helpers or `test/helpers/` where shared across files.
|
|
1022
|
-
- Outcome: each named family's extractable arrange consolidated; resulting fallow figures reported (the roadmap's original "44 → ≤ 25 groups; ≤ 0.6%" target predated Steps 1–7 and used a different baseline, so acceptance was "consolidate and measure," not a binding number).
|
|
1023
|
-
- Landed: promoted the cross-file `ResolvedSpawnConfig` builder to `test/helpers/make-spawn-config.ts` (`createResolvedSpawnConfig`, flat options that derive the mirrored `agentInvocation`/`presentation.detailBase` regions) with a 5-test companion; consolidated the remaining six families with file-local, value-returning arrange builders and `beforeEach` setup (`spawnAndWaitRegistering`, `ui-observer` session/tracker `beforeEach` with `vi.fn()` onUpdate counters, `generateUI`/`manualUI`/`withInputs`, `disabledConfig`, `exploreConfig`, `createManagerStub`).
|
|
1024
|
-
Package test duplication: 512 → 355 lines; clone groups 32 → 24; duplication 2.49% → 1.73%; test files 63 → 64; test count 1010 → 1015 (+5 `createResolvedSpawnConfig` self-tests).
|
|
1025
|
-
Three multi-group families remain: the two lifecycle residuals from Step 7 (`create-subagent-session.test.ts`, `subagent-manager.test.ts`) and `agent-config-editor.test.ts`, whose residual clones are the repeated `await editor.showAgentDetail(...)` **act** plus its `setupDetail` arrange and `ui.select.mock.calls` menu assertion — left inline because wrapping the system-under-test is the wrong abstraction for test code (Step 7 lesson; Sandi Metz: "duplication is far cheaper than the wrong abstraction").
|
|
1026
|
-
|
|
1027
|
-
#### Step 9 — Resolve the cross-package settings-loader duplication ([#380]) ✅
|
|
1028
|
-
|
|
1029
|
-
- Targets: `src/settings.ts:198-211`, `packages/pi-subagents-worktrees/src/config.ts:51-73`.
|
|
1030
|
-
- Smell: Category A — 23-line production clone: the layered global/project JSON read-sanitize-warn-merge loader.
|
|
1031
|
-
- Decision: **extract** — `loadLayeredSettings<T>` added to `src/layered-settings.ts` and published via the `@gotgenes/pi-subagents/settings` dedicated subpath export (`dist/settings.d.ts`); `loadSettings` in `settings.ts` delegates to it internally.
|
|
1032
|
-
Option 2 (fallow suppression) was rejected; the public-API cost is accepted as the right long-term tradeoff for a shared convention in the `@gotgenes/pi-*` family.
|
|
1033
|
-
Worktrees migration (swap `config.ts`'s inlined loader for the shared helper) is deferred to [#415] — worktrees resolves pi-subagents from the registry, so it must wait for a published release carrying the helper.
|
|
1034
|
-
- Outcome: `pnpm fallow:dupes --skip-local` no longer reports the `settings.ts` ↔ `config.ts` pair.
|
|
1035
|
-
The parametrised helper's token sequence diverged sufficiently that the contiguous identical run dropped below the reporting threshold even before the worktrees migration lands.
|
|
1036
|
-
Definitive semantic elimination completes when worktrees adopts the helper in the follow-up.
|
|
1037
|
-
|
|
1038
|
-
### Step dependencies
|
|
949
|
+
The spine (Steps 1–5) removes the activity-tier entanglement, leaving the core a pure orchestrator whose run state lives in one place and whose UI is a reactive consumer of broadcast events plus discrete queries.
|
|
950
|
+
Steps 6–7 are independent hygiene.
|
|
951
|
+
Step 8 is the user-driven UI reconsideration the disentangled core finally makes possible — a decision about the UI's distribution once it is substitutable, not optional.
|
|
952
|
+
|
|
953
|
+
The deeper target in the [first-principles refinement](#first-principles-refinement-and-the-deeper-target) — metrics as a pure observer projection rather than mutable fields — is deliberately **not** forced here.
|
|
954
|
+
Folding the live activity onto the record (the single owner of run state, consistent with Phase 17's `SubagentState`) removes the duplication without inventing the asynchronous-observation seam the `improvement-discovery` skill warns is essential, not structural.
|
|
955
|
+
|
|
956
|
+
1. **Fold run metrics and live activity onto the core record (pure addition).**
|
|
957
|
+
([#420]) Target: `lifecycle/subagent-state.ts`, `observation/record-observer.ts`, `lifecycle/subagent.ts`.
|
|
958
|
+
Extend the single owned run-state value object with `turnCount`, active tools, and response text; have the already-subscribed `record-observer` handle `turn_end`, `tool_execution_start`, `message_start`, `message_update`; expose read-only `turnCount`/`maxTurns`/`activeTools`/`responseText` getters on `Subagent`.
|
|
959
|
+
`AgentActivityTracker` still exists; nothing reads the new getters yet (tidy-first).
|
|
960
|
+
Smell: Category C. Outcome: `Subagent` is the single home for all run state; getters available for migration.
|
|
961
|
+
2. **Migrate every activity reader to the record getters.**
|
|
962
|
+
([#421]) Target: `ui/widget-renderer.ts`, `ui/conversation-viewer.ts`, `ui/agent-menu.ts`, `tools/foreground-runner.ts`, `observation/notification.ts`.
|
|
963
|
+
Switch each reader from `AgentActivityTracker` to the record getters added in Step 1 (widget-renderer reads activity off `listAgents()`; viewer/menu drop the `activity` param; notification reads `turnCount`/`maxTurns` off the record).
|
|
964
|
+
Smell: Category C (Law of Demeter).
|
|
965
|
+
Outcome: no consumer references `AgentActivityTracker`.
|
|
966
|
+
3. **Delete `AgentActivityTracker` and `ui-observer`; drop the activity map from the runtime and spawn tools.**
|
|
967
|
+
([#422]) Target: `ui/agent-activity-tracker.ts` (delete), `ui/ui-observer.ts` (delete), `runtime.ts`, `tools/foreground-runner.ts`, `tools/background-spawner.ts`.
|
|
968
|
+
The spawn tools stop constructing trackers, subscribing, and populating maps; `SubagentRuntime.agentActivity` is removed.
|
|
969
|
+
Smell: Category A + C. Outcome: −145 LOC, one session subscription per child, runtime holds zero UI state.
|
|
970
|
+
4. **Make the widget self-drive from lifecycle events.**
|
|
971
|
+
([#423]) Target: `ui/agent-widget.ts`, `lifecycle/subagent-manager.ts` (observer), `index.ts`.
|
|
972
|
+
The widget starts/stops its timer in response to started/created/completed notifications instead of tool calls; spawn tools no longer call `ensureTimer`/`update`/`markFinished`.
|
|
973
|
+
Smell: Category C (coupling direction).
|
|
974
|
+
Outcome: the widget is a reactive consumer; no inbound calls from core spawn tools.
|
|
975
|
+
5. **Drop the widget and activity-map dependencies from the `subagent` tool.**
|
|
976
|
+
([#424]) Target: `tools/agent-tool.ts`, `test/helpers/make-deps.ts`.
|
|
977
|
+
`AgentTool` loses its `widget` and `agentActivity` constructor params (UICtx capture stays in `ToolStartHandler`); `createToolDeps` sheds the widget and map stubs.
|
|
978
|
+
Smell: Category C/D.
|
|
979
|
+
Outcome: the LLM tool depends only on manager/runtime/settings/registry; fixture drops 2 fields.
|
|
980
|
+
6. **Reconcile the public event contract.**
|
|
981
|
+
([#425]) Target: `service/service.ts`, this document's lifecycle-events table.
|
|
982
|
+
Remove the vacant `ACTIVITY` channel (or emit a real broadcast for it) and add the emitted `failed`/`compacted`/`created` channels so declared constants match emitted events.
|
|
983
|
+
Smell: Category A/E.
|
|
984
|
+
Outcome: declared channels equal emitted channels; no vacant hook.
|
|
985
|
+
7. **Consolidate residual test clone families.**
|
|
986
|
+
([#426]) Target: `test/settings.test.ts` + `test/layered-settings.test.ts`, `test/lifecycle/create-subagent-session.test.ts`, `test/ui/agent-config-editor.test.ts`.
|
|
987
|
+
Extract shared fixtures for the clone families fallow reports that the spine does not already rewrite.
|
|
988
|
+
Smell: Category D. Outcome: test clone groups drop below 15.
|
|
989
|
+
8. **Reconsider the UI direction (first-principles ADR).**
|
|
990
|
+
([#427]) Target: `docs/decisions/`, `ui/`.
|
|
991
|
+
The spine already made the UI _substitutable_; this step decides its _distribution_, not whether the experiment is possible.
|
|
992
|
+
The goal is **substitutable, not optional**: a human needs some surface, but the specific UI is replaceable — the way Pi ships a default TUI built on the same public API any extension targets.
|
|
993
|
+
The disentangled core stays byte-for-byte identical whether or not a given UI consumer is installed (the composition test), so a replacement UI is a downstream concern even though _some_ UI is not.
|
|
994
|
+
Unlike the worktrees provider seam (generative, rationed — one provider the core consults), the UI is an observational consumer (unlimited, the core never waits on it) reading the broadcast-plus-query surface, which is why packaging it is the secondary question and decoupling it was the real win.
|
|
995
|
+
Two standing concerns are the evidence this decision weighs and the better boundaries the reconsideration is meant to surface:
|
|
996
|
+
- **Truncated transcript.**
|
|
997
|
+
The conversation viewer shows a truncated view, yet `Subagent.messages` already exposes the full history and the core already persists each child as a standard Pi session JSONL (`outputFile`) — the limit is the bespoke overlay's rendering, not data access.
|
|
998
|
+
- **Foreground widget redundancy.**
|
|
999
|
+
In foreground the tool's inline `onUpdate` stream already shows progress, so the above-editor widget duplicates it; the widget earns its keep only for background agents — a per-mode judgment the fused UI cannot vary.
|
|
1000
|
+
Candidate redesign to record: replace the bespoke overlay with "open the child session in the same viewer Pi uses for any session," following the recursive-Pi insight and the already-persisted session file.
|
|
1001
|
+
Judge the widget, conversation viewer, and `/agents` menu per component — keep, shrink, extract to `@gotgenes/pi-subagents-ui`, or remove — and capture the decision in an ADR that gateways Phase 19.
|
|
1002
|
+
Smell: Category E (organization / boundary).
|
|
1003
|
+
Outcome: a recorded per-component decision motivated by the two concerns; the inherited UI is substitutable and no longer preserved by default.
|
|
1004
|
+
|
|
1005
|
+
### Step dependency diagram
|
|
1039
1006
|
|
|
1040
1007
|
```mermaid
|
|
1041
1008
|
flowchart TB
|
|
1042
|
-
S1["
|
|
1043
|
-
S2["
|
|
1044
|
-
S3["
|
|
1045
|
-
S4["
|
|
1046
|
-
S5["
|
|
1047
|
-
S6["
|
|
1048
|
-
S7["
|
|
1049
|
-
S8["
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
S3 --> S4
|
|
1055
|
-
S4 --> S7
|
|
1056
|
-
S5 --> S6
|
|
1009
|
+
S1["1 — Fold metrics + activity onto record (#420)"]
|
|
1010
|
+
S2["2 — Migrate readers to record getters (#421)"]
|
|
1011
|
+
S3["3 — Delete tracker + ui-observer, drop activity map (#422)"]
|
|
1012
|
+
S4["4 — Widget self-drives on events (#423)"]
|
|
1013
|
+
S5["5 — Drop widget dep from subagent tool (#424)"]
|
|
1014
|
+
S6["6 — Reconcile public event contract (#425)"]
|
|
1015
|
+
S7["7 — Consolidate test clone families (#426)"]
|
|
1016
|
+
S8["8 — Reconsider UI direction, ADR (#427)"]
|
|
1017
|
+
|
|
1018
|
+
S1 --> S2 --> S3 --> S4 --> S5 --> S8
|
|
1019
|
+
S6
|
|
1020
|
+
S7
|
|
1057
1021
|
```
|
|
1058
1022
|
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
### Tracks
|
|
1062
|
-
|
|
1063
|
-
| Track | Steps | Theme |
|
|
1064
|
-
| ----------------------------- | ------------- | ---------------------------------------------------------------------------------- |
|
|
1065
|
-
| A — Subagent constructibility | 2 → 3 → 4 → 7 | Construct complete; encapsulate run state; then consolidate the tests that churned |
|
|
1066
|
-
| B — Wiring debt | 1, 5 → 6 | Shrink index.ts; eliminate forward references and relay delegation |
|
|
1067
|
-
| C — Test hygiene | 8 | Clone families outside the lifecycle tree |
|
|
1068
|
-
| D — Duplication policy | 9 | Cross-package clone decision |
|
|
1023
|
+
### Parallel tracks
|
|
1069
1024
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1025
|
+
- **Track A — Disentangle the activity tier (spine):** Steps 1, 2, 3.
|
|
1026
|
+
Strictly ordered; each is a safe lift-and-shift over the previous.
|
|
1027
|
+
- **Track B — Decouple widget and tool wiring:** Steps 4, 5.
|
|
1028
|
+
Begins once the activity map is gone (Step 3).
|
|
1029
|
+
- **Track C — Public-contract hygiene:** Step 6.
|
|
1030
|
+
Independent; can land any time.
|
|
1031
|
+
- **Track D — Test consolidation:** Step 7.
|
|
1032
|
+
Independent; can land any time.
|
|
1033
|
+
- **Track E — UI reconsideration:** Step 8.
|
|
1034
|
+
Gated on the spine and Track B (the UI must be a clean consumer first).
|
|
1072
1035
|
|
|
1073
1036
|
## Refactoring history
|
|
1074
1037
|
|
|
1075
|
-
Phases 1–5, 7–
|
|
1038
|
+
Phases 1–5, 7–17 are complete.
|
|
1076
1039
|
Phase 6 (UI extraction to a separate package) is deferred → Phase 18.
|
|
1077
1040
|
Detailed records are preserved in per-phase history files:
|
|
1078
1041
|
|
|
@@ -1094,29 +1057,31 @@ Detailed records are preserved in per-phase history files:
|
|
|
1094
1057
|
| 14 | Strip policy from core | Complete | [phase-14-strip-policy.md](history/phase-14-strip-policy.md) |
|
|
1095
1058
|
| 15 | Domain model evolution | Complete | [phase-15-domain-model-evolution.md](history/phase-15-domain-model-evolution.md) |
|
|
1096
1059
|
| 16 | Invert dependencies (extensions on a minimal core) | Complete | [phase-16-invert-dependencies.md](history/phase-16-invert-dependencies.md) |
|
|
1097
|
-
| 17 | Core consolidation |
|
|
1098
|
-
| 18 | Reconsider UI (first principles) |
|
|
1060
|
+
| 17 | Core consolidation | Complete | [phase-17-core-consolidation.md](history/phase-17-core-consolidation.md) |
|
|
1061
|
+
| 18 | Reconsider UI (first principles) | Proposed | this document, [Phase 18](#phase-18-reconsider-ui-from-first-principles) |
|
|
1099
1062
|
|
|
1100
1063
|
### Structural refactoring issues
|
|
1101
1064
|
|
|
1102
|
-
| Phase | Issue | Summary
|
|
1103
|
-
| -------------------- | ---------------------------------------------------------- |
|
|
1104
|
-
| Foundation | #69, #71, #76, #80 | SubagentRuntime, pure assembler, cwd injection, config consolidation
|
|
1105
|
-
| Core decomposition | #84, #72, #87, #70 | WorktreeManager, AgentManager DI, runtime methods, handler extraction
|
|
1106
|
-
| Interface polish | #66, #77 | SDK types, projectAgentsDir
|
|
1107
|
-
| Features | #61 | JSONL session transcripts
|
|
1108
|
-
| AgentManager | #98, #99, #100, #102 | Record state machine, ParentSnapshot, session-event observation, test factory
|
|
1109
|
-
| Encapsulation | #108, #109, #110, #111, #112, #113, #114, #115, #116, #118 | Registry, settings, activity tracker, record lifecycle, observer, spawn options, deps narrowing, tool split, type housekeeping
|
|
1110
|
-
| Testability | #131, #132, #133, #134, #135, #136 | Shared fixtures, session-config IO, runner SDK boundary, as-any reduction, display extraction, menu decomposition
|
|
1111
|
-
| Observation/ctx | #144, #145, #146, #147, #148 | Observation consolidation, execute decomposition, UI context, text wrapping injection, widget rendering split
|
|
1112
|
-
| Phase 10 | #164, #165, #166, #167, #168, #169, #170, #171, #172 | Domain directories, ResolvedSpawnConfig, ParentSessionInfo, RunnerIO split, ToolFilterConfig, RunContext, buildContentLines, renderResult, content-items
|
|
1113
|
-
| Phase 11 | #192, #193, #194, #195, #196 | SessionContext, runtime queries, interface alignment, tool classes, runner/menu classes, index.ts simplification
|
|
1114
|
-
| Phase 12 | #205, #206, #207, #208 | renderWidgetLines, showAgentDetail, widget update, shared test fixtures
|
|
1115
|
-
| Phase 13 | #214, #215, #216, #217, #218, #219 | Closure-to-class, buildParentContext, startAgent decomp, overwrite guard, settings SDK, test duplication
|
|
1116
|
-
| Phase 14 | #237, #238, #239, #242 | Remove disallowed_tools, remove extensions filtering, collapse filterActiveTools, rename Agent to subagent
|
|
1117
|
-
| Phase 15 | #227, #228, #231, #229, #230, #232 | Agent domain model, async startAgent, runner self-contained, Agent.run(), ConcurrencyQueue, Agent.resume()
|
|
1118
|
-
| Phase 16 | #261, #262, #263, #264, #265 | Lifecycle events (retire permission-bridge), WorkspaceProvider seam, extract worktrees package, remove isolated, born-complete execution / dissolve runner
|
|
1119
|
-
| Phase 16 (abandoned) | #256 (superseded), #257 (parked), #258, #259 (not planned) | Agent collaborator architecture — replaced by the inversion approach above ([ADR-0002])
|
|
1065
|
+
| Phase | Issue | Summary |
|
|
1066
|
+
| -------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1067
|
+
| Foundation | #69, #71, #76, #80 | SubagentRuntime, pure assembler, cwd injection, config consolidation |
|
|
1068
|
+
| Core decomposition | #84, #72, #87, #70 | WorktreeManager, AgentManager DI, runtime methods, handler extraction |
|
|
1069
|
+
| Interface polish | #66, #77 | SDK types, projectAgentsDir |
|
|
1070
|
+
| Features | #61 | JSONL session transcripts |
|
|
1071
|
+
| AgentManager | #98, #99, #100, #102 | Record state machine, ParentSnapshot, session-event observation, test factory |
|
|
1072
|
+
| Encapsulation | #108, #109, #110, #111, #112, #113, #114, #115, #116, #118 | Registry, settings, activity tracker, record lifecycle, observer, spawn options, deps narrowing, tool split, type housekeeping |
|
|
1073
|
+
| Testability | #131, #132, #133, #134, #135, #136 | Shared fixtures, session-config IO, runner SDK boundary, as-any reduction, display extraction, menu decomposition |
|
|
1074
|
+
| Observation/ctx | #144, #145, #146, #147, #148 | Observation consolidation, execute decomposition, UI context, text wrapping injection, widget rendering split |
|
|
1075
|
+
| Phase 10 | #164, #165, #166, #167, #168, #169, #170, #171, #172 | Domain directories, ResolvedSpawnConfig, ParentSessionInfo, RunnerIO split, ToolFilterConfig, RunContext, buildContentLines, renderResult, content-items |
|
|
1076
|
+
| Phase 11 | #192, #193, #194, #195, #196 | SessionContext, runtime queries, interface alignment, tool classes, runner/menu classes, index.ts simplification |
|
|
1077
|
+
| Phase 12 | #205, #206, #207, #208 | renderWidgetLines, showAgentDetail, widget update, shared test fixtures |
|
|
1078
|
+
| Phase 13 | #214, #215, #216, #217, #218, #219 | Closure-to-class, buildParentContext, startAgent decomp, overwrite guard, settings SDK, test duplication |
|
|
1079
|
+
| Phase 14 | #237, #238, #239, #242 | Remove disallowed_tools, remove extensions filtering, collapse filterActiveTools, rename Agent to subagent |
|
|
1080
|
+
| Phase 15 | #227, #228, #231, #229, #230, #232 | Agent domain model, async startAgent, runner self-contained, Agent.run(), ConcurrencyQueue, Agent.resume() |
|
|
1081
|
+
| Phase 16 | #261, #262, #263, #264, #265 | Lifecycle events (retire permission-bridge), WorkspaceProvider seam, extract worktrees package, remove isolated, born-complete execution / dissolve runner |
|
|
1082
|
+
| Phase 16 (abandoned) | #256 (superseded), #257 (parked), #258, #259 (not planned) | Agent collaborator architecture — replaced by the inversion approach above ([ADR-0002]) |
|
|
1083
|
+
| Phase 17 | #381, #373, #374, #375, #376, #377, #378, #379, #380 | ConcurrencyLimiter, SubagentState, run-start encapsulation, run collaborators, events observer, widget decoupling, lifecycle test fixtures, UI/tools test fixtures, settings-loader extraction |
|
|
1084
|
+
| Phase 17 (follow-on) | #412, #415 | Session-mock builder unification, worktrees settings-helper migration |
|
|
1120
1085
|
|
|
1121
1086
|
The remaining open issue is #22 (parent-session resolution), a cross-extension track that does not gate the structural work.
|
|
1122
1087
|
|
|
@@ -1172,4 +1137,12 @@ The upstream test suite is run periodically as a regression canary for the sessi
|
|
|
1172
1137
|
[#381]: https://github.com/gotgenes/pi-packages/issues/381
|
|
1173
1138
|
[#412]: https://github.com/gotgenes/pi-packages/issues/412
|
|
1174
1139
|
[#415]: https://github.com/gotgenes/pi-packages/issues/415
|
|
1140
|
+
[#420]: https://github.com/gotgenes/pi-packages/issues/420
|
|
1141
|
+
[#421]: https://github.com/gotgenes/pi-packages/issues/421
|
|
1142
|
+
[#422]: https://github.com/gotgenes/pi-packages/issues/422
|
|
1143
|
+
[#423]: https://github.com/gotgenes/pi-packages/issues/423
|
|
1144
|
+
[#424]: https://github.com/gotgenes/pi-packages/issues/424
|
|
1145
|
+
[#425]: https://github.com/gotgenes/pi-packages/issues/425
|
|
1146
|
+
[#426]: https://github.com/gotgenes/pi-packages/issues/426
|
|
1147
|
+
[#427]: https://github.com/gotgenes/pi-packages/issues/427
|
|
1175
1148
|
[ADR-0002]: ../decisions/0002-extensions-on-a-minimal-core.md
|