@gotgenes/pi-subagents 17.0.0 → 17.1.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 +16 -0
- package/docs/architecture/architecture.md +222 -159
- package/docs/architecture/history/phase-18-reconsider-ui.md +166 -0
- package/docs/decisions/0004-reconsider-ui-direction.md +220 -0
- package/docs/plans/0426-consolidate-residual-test-clone-families.md +235 -0
- package/docs/plans/0427-reconsider-ui-direction.md +212 -0
- package/docs/plans/0446-spike-session-navigation-entry-criteria.md +171 -0
- package/docs/plans/0447-extract-subagents-settings-command.md +220 -0
- package/docs/plans/0448-block-disabled-agent-spawn.md +207 -0
- package/docs/retro/0425-reconcile-subagent-events-contract.md +55 -0
- package/docs/retro/0426-consolidate-residual-test-clone-families.md +100 -0
- package/docs/retro/0427-reconsider-ui-direction.md +102 -0
- package/docs/retro/0446-spike-session-navigation-entry-criteria.md +99 -0
- package/docs/retro/0447-extract-subagents-settings-command.md +46 -0
- package/docs/retro/0448-block-disabled-agent-spawn.md +75 -0
- package/package.json +1 -1
- package/src/index.ts +12 -0
- package/src/tools/helpers.ts +3 -2
- package/src/tools/spawn-config.ts +6 -0
- package/src/ui/subagents-settings.ts +83 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ 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
|
+
## [17.1.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v17.0.1...pi-subagents-v17.1.0) (2026-06-20)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add SubagentsSettingsHandler for focused settings command ([#447](https://github.com/gotgenes/pi-packages/issues/447)) ([cae804d](https://github.com/gotgenes/pi-packages/commit/cae804d1be7ac437ad7344035b5d99cd1424e0c0))
|
|
14
|
+
* register /subagents-settings command ([#447](https://github.com/gotgenes/pi-packages/issues/447)) ([7735a38](https://github.com/gotgenes/pi-packages/commit/7735a38db2658fd9faca6388ac4bc712fa8e5a86))
|
|
15
|
+
|
|
16
|
+
## [17.0.1](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v17.0.0...pi-subagents-v17.0.1) (2026-06-20)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* **pi-subagents:** exclude disabled agents from the subagent tool description ([#448](https://github.com/gotgenes/pi-packages/issues/448)) ([9a43414](https://github.com/gotgenes/pi-packages/commit/9a43414b3e15f0c978db9d468b737b13b801fdb2))
|
|
22
|
+
* **pi-subagents:** return an error when spawning a disabled agent type ([#448](https://github.com/gotgenes/pi-packages/issues/448)) ([0e0225e](https://github.com/gotgenes/pi-packages/commit/0e0225e167596217dc7b1d99dd6269600d65326b))
|
|
23
|
+
|
|
8
24
|
## [17.0.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v16.6.0...pi-subagents-v17.0.0) (2026-06-18)
|
|
9
25
|
|
|
10
26
|
|
|
@@ -13,8 +13,8 @@ This document describes the architecture of the pi-subagents fork: a focused, co
|
|
|
13
13
|
4. **No time-based scheduling** — cron-style timed dispatch (upstream's `schedule.ts` subsystem) is removed from the core (#52).
|
|
14
14
|
Timed dispatch is a separate concern that any extension can implement by calling `spawn()` on the published API.
|
|
15
15
|
The max-concurrent admission gate is not scheduling in this sense — concurrency management stays in core.
|
|
16
|
-
5. **UI
|
|
17
|
-
|
|
16
|
+
5. **UI is an in-core, substitutable consumer** — [ADR-0004](../decisions/0004-reconsider-ui-direction.md) records the per-component decision: the widget shrinks to background agents only, the bespoke conversation viewer is replaced by native session navigation, the `/agents` command is dissolved into focused surfaces, and the surviving UI stays in the core as a reactive consumer (not extracted to a separate package).
|
|
17
|
+
Extraction remains an available future option because the composition invariant holds — the core is byte-for-byte identical with or without a given UI consumer.
|
|
18
18
|
6. **Snapshot, don't capture** — mutable parent state (ctx, session, model) is read once at spawn time and frozen into a `ParentSnapshot` data object.
|
|
19
19
|
No live references survive past the spawn call.
|
|
20
20
|
7. **Subscribe, don't thread** — observation of agent progress uses direct session-event subscription, not callback parameters threaded through multiple layers.
|
|
@@ -895,178 +895,232 @@ All nine steps are closed: [#381], [#373], [#374], [#375], [#376], [#377], [#378
|
|
|
895
895
|
[#415] migrated `pi-subagents-worktrees` to `loadLayeredSettings` after the Step 9 published release.
|
|
896
896
|
See [phase-17-core-consolidation.md](history/phase-17-core-consolidation.md) for the full findings, step outcomes, dependency diagram, and tracks.
|
|
897
897
|
|
|
898
|
-
## Phase 18
|
|
899
|
-
|
|
900
|
-
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.
|
|
901
|
-
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.
|
|
902
|
-
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.
|
|
903
|
-
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.
|
|
904
|
-
|
|
905
|
-
### Findings
|
|
906
|
-
|
|
907
|
-
Six findings tell one story — the activity tier has metastasized out of the UI and into the core.
|
|
908
|
-
|
|
909
|
-
1. **UI state lives on the core runtime.**
|
|
910
|
-
`SubagentRuntime.agentActivity: Map<string, AgentActivityTracker>` puts a UI streaming-state map on the core composition root.
|
|
911
|
-
`SubagentRuntime` owns session-scoped lifecycle state; `AgentActivityTracker` (active tools, response text, turn count) is pure rendering state the core never reads.
|
|
912
|
-
Category C (coupling).
|
|
913
|
-
2. **Core spawn tools wire UI streaming.**
|
|
914
|
-
`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`).
|
|
915
|
-
Their own doc comments list "AgentActivityTracker creation, UI observer subscription" as responsibilities.
|
|
916
|
-
Category C (mixed responsibility, parameter relay).
|
|
917
|
-
3. **The LLM-facing tool depends on the widget.**
|
|
918
|
-
`AgentTool` takes a 4-method `widget` dependency plus `runtime.agentActivity` and calls `this.widget.setUICtx(ctx.ui)`.
|
|
919
|
-
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.
|
|
920
|
-
Category C/D.
|
|
921
|
-
4. **Two parallel observers split the run-metric domain.**
|
|
922
|
-
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).
|
|
923
|
-
`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.
|
|
924
|
-
Category C (anemic split, duplication).
|
|
925
|
-
5. **A core observation concern reaches into UI state.**
|
|
926
|
-
`NotificationManager` holds the activity map and reads `turnCount`/`maxTurns` from it to build notification details, and deletes entries from it.
|
|
927
|
-
Category C (Law of Demeter).
|
|
928
|
-
6. **The public event contract is both vacant and incomplete.**
|
|
929
|
-
`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.
|
|
930
|
-
Meanwhile three emitted channels (`subagents:failed`, `subagents:compacted`, `subagents:created`) are absent from the constant map.
|
|
931
|
-
Category A/E.
|
|
898
|
+
## Phase 18 (complete)
|
|
932
899
|
|
|
933
|
-
|
|
900
|
+
Phase 18 disentangled the activity tier from the core and recorded a first-principles decision about the UI's direction.
|
|
901
|
+
Steps 1–5 (the spine) consolidated all run state onto `SubagentState`, deleted `AgentActivityTracker` and `ui-observer` (−145 LOC), and made the widget a pure reactive consumer of lifecycle events with no inbound calls from core spawn tools.
|
|
902
|
+
Step 6 reconciled the public event contract (breaking: removed the vacant `SUBAGENT_EVENTS.ACTIVITY` channel; added `FAILED`, `COMPACTED`, `CREATED`, `STEERED`).
|
|
903
|
+
Step 7 consolidated residual test clone families, dropping from 24 to 14 clone groups (below the <15 target).
|
|
904
|
+
Step 8 captured the per-component UI decisions in [ADR-0004]: the widget shrinks to background agents only; the bespoke `ConversationViewer` is replaced by native session navigation (a read-only transcript via `parseSessionEntries`, per the Step 1 spike — see [ADR-0004]'s addendum); the `/agents` command is dissolved (remove the create wizard and agent-types editor, extract settings to a focused command); the surviving UI stays in-core as a substitutable reactive consumer.
|
|
905
|
+
Source LOC decreased from 7,751 (62 files) to 7,650 (61 files); tests grew from 1,031 to 1,047.
|
|
906
|
+
All eight steps are closed: [#420], [#421], [#422], [#423], [#424], [#425], [#426], [#427].
|
|
907
|
+
See [phase-18-reconsider-ui.md](history/phase-18-reconsider-ui.md) for the full findings, step outcomes, dependency diagram, and tracks.
|
|
908
|
+
|
|
909
|
+
## Phase 19 (proposed)
|
|
910
|
+
|
|
911
|
+
Phase 19 implements the per-component UI decisions recorded in [ADR-0004]: shrink the widget to background-only, replace the bespoke conversation viewer with native session navigation, dissolve the monolithic `/agents` menu, and keep the surviving UI in-core.
|
|
912
|
+
|
|
913
|
+
The sequencing follows Kent Beck's "make the change easy, then make the easy change."
|
|
914
|
+
The end state deletes `agent-menu.ts` — the god-command that bundles four unrelated jobs — and everything reachable only from it.
|
|
915
|
+
Rather than surgically mutate that doomed module (and the #1 churn hotspot `index.ts`) once per option, Phase 19 first stands up the replacement surfaces additively, then removes the now-orphaned subtree in a single terminal cut.
|
|
916
|
+
This keeps every responsibility's old surface live until its replacement exists (ADR-0004's no-interim-regression invariant), turns the three replacement steps into genuinely parallel work (none touch `agent-menu.ts`), and reduces `index.ts` edits from four surgical removals to one deregistration.
|
|
917
|
+
|
|
918
|
+
Seven steps in three phases:
|
|
919
|
+
|
|
920
|
+
- **Phase A — stand up replacements (additive):** spike, settings command, background widget, native session navigation (Steps 1–4).
|
|
921
|
+
- **Phase B — dissolve `/agents` (terminal cut):** delete the orphaned subtree in two deletion commits, one per subtree (Steps 5–6).
|
|
922
|
+
- **Phase C — test health:** consolidate the test clones that survive the cut (Step 7).
|
|
923
|
+
|
|
924
|
+
### Health metrics (Phase 18 → Phase 19 target)
|
|
925
|
+
|
|
926
|
+
| Metric | Phase 18 (current) | Phase 19 target |
|
|
927
|
+
| ---------------------- | ------------------------ | -------------------- |
|
|
928
|
+
| Health score | 78/100 (B) | 83/100 (B+) |
|
|
929
|
+
| Source LOC | 7,650 (61 files) | ~6,780 (~55 files) |
|
|
930
|
+
| Production duplication | 11 lines (1 group) | 0 lines |
|
|
931
|
+
| Test clone groups | 16 | ≤ 10 |
|
|
932
|
+
| Top churn hotspot | `index.ts` (103 commits) | `index.ts` (cooling) |
|
|
933
|
+
|
|
934
|
+
### ✅ Step 1 — Spike: resolve ADR-0004 entry criteria ([#446])
|
|
935
|
+
|
|
936
|
+
Smell: Category C (coupling boundary) — four open decisions block the session-navigation implementation.
|
|
937
|
+
Target: `docs/decisions/0004-reconsider-ui-direction.md` addendum.
|
|
938
|
+
|
|
939
|
+
The four entry criteria from ADR-0004:
|
|
940
|
+
|
|
941
|
+
1. **Root-continuity:** Does the root's in-flight turn survive `ctx.switchSession()` and a return gesture?
|
|
942
|
+
2. **View-only vs interactive:** `switchSession` (full interactive takeover) or `loadEntriesFromFile` (read-only transcript built from JSONL)?
|
|
943
|
+
3. **Parallel-agent navigation:** Operator gesture to select which of N background agents to view (from the widget, a command, or both).
|
|
944
|
+
4. **Settings command name:** `/subagents-settings`, `/agents-settings`, or another form consistent with sibling packages?
|
|
945
|
+
|
|
946
|
+
Produce a minimal spike (observed test or PoC against a real session) that answers each question, then record the answers as an addendum to ADR-0004.
|
|
947
|
+
No production source files change; the spike closes when the ADR addendum is merged.
|
|
948
|
+
|
|
949
|
+
Outcome: ADR-0004 updated with all four entry-criteria answers; Step 4 unblocked.
|
|
950
|
+
|
|
951
|
+
`Release: independent`
|
|
952
|
+
|
|
953
|
+
### ✅ Step 2 — Extract settings to a focused `/subagents-settings` command ([#447])
|
|
954
|
+
|
|
955
|
+
Smell: Category E (naming/organization) — settings are buried inside the monolithic `/agents` command per ADR-0004 Decision C. This step is purely additive: it stands up the new surface without touching `agent-menu.ts`.
|
|
956
|
+
Target files:
|
|
957
|
+
|
|
958
|
+
- New `src/ui/subagents-settings.ts` — `SubagentsSettingsHandler` lifted from `AgentsMenuHandler.showSettings`, carrying its own narrow `SubagentsSettingsManager` interface (the three `apply*` methods and three readonly accessors only).
|
|
959
|
+
- `src/index.ts` — register the new command (name confirmed by Step 1); pass `settings` directly.
|
|
960
|
+
- New `test/ui/subagents-settings.test.ts` — unit tests for the extracted handler.
|
|
961
|
+
|
|
962
|
+
`showSettings` depends only on `this.settings` (the self-contained `AgentMenuSettings` shape), so the extraction copies that logic into a new file with zero coupling to the wizard, editor, or viewer.
|
|
963
|
+
The old in-menu Settings option keeps working until the terminal cut deletes `agent-menu.ts` wholesale — there is no surgical removal of `showSettings` or `AgentMenuSettings` from the doomed file.
|
|
964
|
+
|
|
965
|
+
Outcome: new `subagents-settings.ts` (~80 LOC) and focused command registered; `agent-menu.ts` untouched.
|
|
966
|
+
|
|
967
|
+
`Release: independent`
|
|
968
|
+
|
|
969
|
+
### Step 3 — Shrink widget to background agents only ([#444])
|
|
970
|
+
|
|
971
|
+
Smell: Category C (coupling) — the widget shows all agents including foreground ones, duplicating the `subagent` tool's inline `onUpdate` stream for foreground runs.
|
|
972
|
+
Target files:
|
|
973
|
+
|
|
974
|
+
- `src/ui/agent-widget.ts` — funnel both `manager.listAgents()` call sites (`update()` and `renderWidget()`) through a single private accessor, then flip that accessor to background-only via `record.invocation?.runInBackground === true`.
|
|
975
|
+
- `src/ui/widget-renderer.ts` — verify no foreground-specific rendering path survives.
|
|
976
|
+
- `test/ui/agent-widget.test.ts` — add background-only filtering tests; update assertions.
|
|
977
|
+
|
|
978
|
+
The widget calls `listAgents()` at two sites today — `update()` (feeding `seedFinishedAgents`, `assembleWidgetState`, and `clearWidget`) and `renderWidget()` (the tree map).
|
|
979
|
+
Filtering at only one site leaves the other rendering foreground agents, so the enabling move is to route both through one accessor and apply the predicate once at the source.
|
|
980
|
+
`Subagent.invocation.runInBackground` is the reliable signal: set by `spawn-config.ts` → `AgentInvocation.runInBackground` → stored on `Subagent.invocation`.
|
|
981
|
+
ADR-0004 Decision A: foreground runs suppress the widget; the inline `onUpdate` stream is authoritative there.
|
|
982
|
+
|
|
983
|
+
Outcome: widget shows only background agents; foreground/widget duplication eliminated; the background predicate lives at a single funnel.
|
|
984
|
+
|
|
985
|
+
`Release: independent`
|
|
934
986
|
|
|
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
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
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.
|
|
1008
|
-
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.
|
|
1009
|
-
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.
|
|
1010
|
-
Smell: Category E (organization / boundary).
|
|
1011
|
-
Outcome: a recorded per-component decision motivated by the two concerns; the inherited UI is substitutable and no longer preserved by default.
|
|
987
|
+
### Step 4 — Implement native session navigation ([#445])
|
|
988
|
+
|
|
989
|
+
Smell: Category C (coupling) — the bespoke `ConversationViewer` re-implements session-transcript rendering when Pi's own machinery targets the already-persisted child session JSONL.
|
|
990
|
+
This step adds the new surface alongside the existing viewer; it does not touch `agent-menu.ts`.
|
|
991
|
+
Target files:
|
|
992
|
+
|
|
993
|
+
- New `src/ui/session-navigator.ts` (or a widget gesture, per Step 1's answer to parallel-agent navigation) — operator picks one of N background agents and views its persisted session via the spike-chosen mechanism, keyed on `record.outputFile`.
|
|
994
|
+
- `src/index.ts` — register the new navigation surface (command and/or widget gesture, per the spike).
|
|
995
|
+
|
|
996
|
+
ADR-0004 Decision B: "Tell-Don't-Ask — hand Pi the session path; Pi owns the viewer."
|
|
997
|
+
Mechanism (confirmed by the Step 1 spike, [ADR-0004] addendum): a **read-only** transcript rendered from `parseSessionEntries(readFileSync(record.outputFile, "utf8"))`, surfaced through a flat command — **not** `switchSession` (a full takeover that invalidates the root's in-flight turn) and **not** `loadEntriesFromFile` (a test-only export of the SDK's `core/session-manager` module that the package's public barrel does not re-export, in both `0.79.1` and `0.79.8`).
|
|
998
|
+
`Subagent.outputFile` already exposes the persisted child session JSONL path via `subagentSession?.outputFile` — no new SDK dependency.
|
|
999
|
+
Rendering uses Pi's own public APIs (no bespoke renderer): `parseSessionEntries` → drop the `SessionHeader` → `buildSessionContext(...).messages` → Pi's public entry components (`AssistantMessageComponent` / `ToolExecutionComponent` / …) or `serializeConversation` (see the [ADR-0004] addendum, Findings 0 and 1).
|
|
1000
|
+
The new surface stands up while the old `viewAgentConversation`/`ConversationViewer` path still works; the bespoke viewer is removed only by the terminal cut (Step 5).
|
|
1001
|
+
|
|
1002
|
+
Outcome: operator views a child agent's persisted session through Pi's native machinery; the new surface coexists with the old viewer until Step 5.
|
|
1003
|
+
|
|
1004
|
+
`Release: independent` (spike-gated)
|
|
1005
|
+
|
|
1006
|
+
### Step 5 — Dissolve `/agents` and remove the conversation-viewer subtree ([#442])
|
|
1007
|
+
|
|
1008
|
+
Smell: Category A (dead subsystem) plus Category B (oversized) — once Steps 2–4 re-home all four menu responsibilities, the `/agents` command and everything reachable only from `agent-menu.ts` is an unreferenced subtree.
|
|
1009
|
+
This is the first of two deletion commits (split by subtree).
|
|
1010
|
+
The hub `agent-menu.ts` is deleted here, not surgically narrowed, and deleting it is what orphans the leaf subtrees — so it must precede the definition-management deletion (Step 6), because `agent-menu.ts` statically imports the wizard, editor, and file-ops, and dynamically imports the viewer.
|
|
1011
|
+
Target files:
|
|
1012
|
+
|
|
1013
|
+
- `src/index.ts` — remove the `registerCommand("agents", …)` block, the `AgentsMenuHandler` construction and import, and the `FsAgentFileOps` import/construction (its only use is wiring the menu).
|
|
1014
|
+
- Delete `src/ui/agent-menu.ts` (331 LOC) and `test/ui/agent-menu.test.ts` (185 LOC).
|
|
1015
|
+
- Delete `src/ui/conversation-viewer.ts` (241 LOC) and `test/conversation-viewer.test.ts` (239 LOC) — its only consumer is `agent-menu.ts`'s dynamic import, gone with the hub.
|
|
1016
|
+
- Delete `src/ui/message-formatters.ts` (195 LOC) and `test/message-formatters.test.ts` (388 LOC, the largest test function by LOC) — its only consumer is `ConversationViewer`.
|
|
1017
|
+
|
|
1018
|
+
Running-agent visibility is now owned by the background widget (Step 3); session navigation replaces the bespoke overlay (Step 4); settings live in `/subagents-settings` (Step 2).
|
|
1019
|
+
Deleting the hub in one move avoids any surgical edit to the doomed file and leaves the definition-management leaves orphaned for Step 6.
|
|
1020
|
+
|
|
1021
|
+
Outcome: `/agents` dissolved; −767 LOC source (menu hub + viewer + formatters); −812 LOC test; largest test function eliminated; `index.ts` edited once (deregistration), never surgically narrowed.
|
|
1022
|
+
|
|
1023
|
+
`Release: batch "dissolve-agents"`
|
|
1024
|
+
|
|
1025
|
+
### Step 6 — Remove the orphaned agent-definition management subtree ([#441])
|
|
1026
|
+
|
|
1027
|
+
Smell: Category A (dead subsystem) — the creation wizard and config editor are removed per ADR-0004 Decision C; after Step 5 deletes their only importer (`agent-menu.ts`), they and their file-ops helpers are pure orphans.
|
|
1028
|
+
This is the second deletion commit (split by subtree).
|
|
1029
|
+
Target files:
|
|
1030
|
+
|
|
1031
|
+
- Delete `src/ui/agent-creation-wizard.ts` (233 LOC) and `test/ui/agent-creation-wizard.test.ts` (296 LOC).
|
|
1032
|
+
- Delete `src/ui/agent-config-editor.ts` (199 LOC) and `test/ui/agent-config-editor.test.ts` (392 LOC) — eliminates the 11-line internal production clone in `disableAgent`/`ejectAgent`, the package's only remaining production duplication.
|
|
1033
|
+
- Delete `src/ui/agent-file-ops.ts` (59 LOC) and `test/ui/agent-file-ops.test.ts` (112 LOC) — only consumers were wizard + editor.
|
|
1034
|
+
- Delete `src/ui/agent-file-writer.ts` (55 LOC) and `test/ui/agent-file-writer.test.ts` (148 LOC) — only consumers were wizard + editor.
|
|
1035
|
+
- `test/helpers/ui-stubs.ts` — delete `makeFileOps`, `createTestSubagentConfig`, and `spawnAndWait` from `makeMenuManager` if no surviving consumer remains; delete the file outright once all consumers are gone.
|
|
1036
|
+
|
|
1037
|
+
An operator generates a new agent `.md` by asking a Pi session directly (more capable than a fixed wizard) or by writing the file in an editor; viewing and editing definitions is served by opening the `.md` files in an editor or IDE.
|
|
1038
|
+
These files are orphaned by Step 5, so this is a pure `git rm` with no surviving references and no edit to any doomed file.
|
|
1039
|
+
|
|
1040
|
+
Outcome: −546 LOC source (wizard + editor + file-ops + file-writer); −948 LOC test; production duplication → 0 lines; 1 production and 1 test clone group eliminated.
|
|
1041
|
+
|
|
1042
|
+
`Release: batch "dissolve-agents"`
|
|
1043
|
+
|
|
1044
|
+
### Step 7 — Consolidate remaining test clone families ([#443])
|
|
1045
|
+
|
|
1046
|
+
Smell: Category D (testability) — 16 clone groups at Phase 18 end; the terminal cut (Steps 5–6) removes ~4 groups; remaining groups are extraction targets.
|
|
1047
|
+
Run after the cut so no helper is extracted into a file the cut then deletes.
|
|
1048
|
+
Target files:
|
|
1049
|
+
|
|
1050
|
+
- `test/lifecycle/subagent-manager.test.ts` — extract a shared assertion helper for 3 clone families (23 lines across groups at :92/:109, :282/:330, and :323 shared with `subagent.test.ts`).
|
|
1051
|
+
- `test/ui/agent-widget.test.ts` — merge the duplicate `makeWidget` helper defined twice across two `describe` blocks (14-line clone at :225/:284).
|
|
1052
|
+
- `test/session/session-config.test.ts` — extract a shared fixture for the 16-line internal clone (lines 131–146 / 151–166).
|
|
1053
|
+
- `test/lifecycle/concurrency-limiter.test.ts` — extract shared setup for the 10-line clone (lines 21–30 / 148–155).
|
|
1054
|
+
- `test/tools/spawn-config.test.ts` — extract a shared fixture for the 9-line clone (lines 22–30 / 35–43).
|
|
1055
|
+
|
|
1056
|
+
Outcome: test clone groups ≤ 10 (from 16); `subagent-manager.test.ts` uses shared factory helpers.
|
|
1057
|
+
|
|
1058
|
+
`Release: independent`
|
|
1012
1059
|
|
|
1013
1060
|
### Step dependency diagram
|
|
1014
1061
|
|
|
1015
1062
|
```mermaid
|
|
1016
|
-
flowchart
|
|
1017
|
-
S1["
|
|
1018
|
-
S2["
|
|
1019
|
-
S3["3
|
|
1020
|
-
S4["4
|
|
1021
|
-
S5["5
|
|
1022
|
-
S6["6
|
|
1023
|
-
S7["7
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1063
|
+
flowchart LR
|
|
1064
|
+
S1["✅ Step 1 - Spike (#446)"]
|
|
1065
|
+
S2["✅ Step 2 - Settings command (#447)"]
|
|
1066
|
+
S3["Step 3 - Background widget (#444)"]
|
|
1067
|
+
S4["Step 4 - Native session nav (#445)"]
|
|
1068
|
+
S5["Step 5 - Dissolve /agents + viewer (#442)"]
|
|
1069
|
+
S6["Step 6 - Remove definition mgmt (#441)"]
|
|
1070
|
+
S7["Step 7 - Test clones (#443)"]
|
|
1071
|
+
|
|
1072
|
+
S1 --> S4
|
|
1073
|
+
S2 --> S5
|
|
1074
|
+
S3 --> S5
|
|
1075
|
+
S4 --> S5
|
|
1076
|
+
S5 --> S6
|
|
1077
|
+
S6 --> S7
|
|
1029
1078
|
```
|
|
1030
1079
|
|
|
1080
|
+
The terminal cut (Step 5) depends on all three replacements — settings (Step 2), widget (Step 3), and session navigation (Step 4) — because each of the four `/agents` options must have its responsibility re-homed before its branch can die.
|
|
1081
|
+
The old `S1 → S6 → S7` chain hid the widget dependency; this diagram makes it explicit.
|
|
1082
|
+
|
|
1031
1083
|
### Parallel tracks
|
|
1032
1084
|
|
|
1033
|
-
- **Track A —
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1085
|
+
- **Track A — Replacements (Steps 1–4):** the spike gates session navigation (Step 1 → Step 4); settings (Step 2) and the background widget (Step 3) are independent of the spike and of each other.
|
|
1086
|
+
None of these steps edits `agent-menu.ts`, so they carry no shared-file collision on the menu — genuinely parallelizable, unlike the prior plan's Steps 2/3/5, which all collided on `agent-menu.ts` and `index.ts`.
|
|
1087
|
+
Steps 2 and 4 each append a command registration to `index.ts` (additive, low-conflict).
|
|
1088
|
+
- **Track B — Dissolution (Steps 5 → 6):** the terminal cut, gated on all of Track A landing.
|
|
1089
|
+
Hub-first ordering is forced: Step 5 deletes `agent-menu.ts` (orphaning the leaves), then Step 6 `git rm`s the now-orphaned definition-management subtree.
|
|
1090
|
+
- **Track C — Test health (Step 7):** clone consolidation, run after the cut so no surviving helper is extracted into a doomed file.
|
|
1091
|
+
|
|
1092
|
+
### Release batches
|
|
1093
|
+
|
|
1094
|
+
- **Batch "dissolve-agents":** Steps 5, 6 (ship together; tail = Step 6).
|
|
1095
|
+
Depends on Steps 2, 3, 4 already merged.
|
|
1096
|
+
- Independently releasable: Steps 1, 2, 3, 4, 7.
|
|
1043
1097
|
|
|
1044
1098
|
## Refactoring history
|
|
1045
1099
|
|
|
1046
|
-
Phases 1–5, 7–
|
|
1047
|
-
Phase 6 (UI extraction to a separate package)
|
|
1100
|
+
Phases 1–5, 7–18 are complete.
|
|
1101
|
+
Phase 6 (UI extraction to a separate package) was deferred to Phase 18; its intent was resolved by [ADR-0004] (Phase 18 Step 8).
|
|
1048
1102
|
Detailed records are preserved in per-phase history files:
|
|
1049
1103
|
|
|
1050
|
-
| Phase | Title | Status
|
|
1051
|
-
| ----- | --------------------------------------------------- |
|
|
1052
|
-
| 1 | Export SubagentsService API boundary | Complete
|
|
1053
|
-
| 2 | Remove scheduling subsystem | Complete
|
|
1054
|
-
| 3 | Remove group-join, RPC; replace output-file | Complete
|
|
1055
|
-
| 4 | Implement and publish SubagentsService | Complete
|
|
1056
|
-
| 5 | Decompose index.ts | Complete
|
|
1057
|
-
| 6 | Extract UI to separate package |
|
|
1058
|
-
| 7 | Encapsulation and dependency narrowing | Complete
|
|
1059
|
-
| 8 | Testability, display extraction, menu decomposition | Complete
|
|
1060
|
-
| 9 | Observation consolidation, ctx elimination | Complete
|
|
1061
|
-
| 10 | Domain organization, bag decomposition, complexity | Complete
|
|
1062
|
-
| 11 | Closure factories to classes | Complete
|
|
1063
|
-
| 12 | Complexity reduction and test fixture extraction | Complete
|
|
1064
|
-
| 13 | Remaining structural smells | Complete
|
|
1065
|
-
| 14 | Strip policy from core | Complete
|
|
1066
|
-
| 15 | Domain model evolution | Complete
|
|
1067
|
-
| 16 | Invert dependencies (extensions on a minimal core) | Complete
|
|
1068
|
-
| 17 | Core consolidation | Complete
|
|
1069
|
-
| 18 | Reconsider UI (first principles) |
|
|
1104
|
+
| Phase | Title | Status | History |
|
|
1105
|
+
| ----- | --------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------ |
|
|
1106
|
+
| 1 | Export SubagentsService API boundary | Complete | [phase-1-api-boundary.md](history/phase-1-api-boundary.md) |
|
|
1107
|
+
| 2 | Remove scheduling subsystem | Complete | [phase-2-remove-scheduling.md](history/phase-2-remove-scheduling.md) |
|
|
1108
|
+
| 3 | Remove group-join, RPC; replace output-file | Complete | [phase-3-remove-rpc-groupjoin.md](history/phase-3-remove-rpc-groupjoin.md) |
|
|
1109
|
+
| 4 | Implement and publish SubagentsService | Complete | [phase-4-implement-service.md](history/phase-4-implement-service.md) |
|
|
1110
|
+
| 5 | Decompose index.ts | Complete | [phase-5-decompose-index.md](history/phase-5-decompose-index.md) |
|
|
1111
|
+
| 6 | Extract UI to separate package | Superseded by ADR-0004 | — |
|
|
1112
|
+
| 7 | Encapsulation and dependency narrowing | Complete | [phase-7-encapsulation.md](history/phase-7-encapsulation.md) |
|
|
1113
|
+
| 8 | Testability, display extraction, menu decomposition | Complete | [phase-8-testability.md](history/phase-8-testability.md) |
|
|
1114
|
+
| 9 | Observation consolidation, ctx elimination | Complete | [phase-9-observation-ctx.md](history/phase-9-observation-ctx.md) |
|
|
1115
|
+
| 10 | Domain organization, bag decomposition, complexity | Complete | [phase-10-structural-decomposition.md](history/phase-10-structural-decomposition.md) |
|
|
1116
|
+
| 11 | Closure factories to classes | Complete | [phase-11-closure-to-class.md](history/phase-11-closure-to-class.md) |
|
|
1117
|
+
| 12 | Complexity reduction and test fixture extraction | Complete | [phase-12-complexity-test-fixtures.md](history/phase-12-complexity-test-fixtures.md) |
|
|
1118
|
+
| 13 | Remaining structural smells | Complete | [phase-13-remaining-smells.md](history/phase-13-remaining-smells.md) |
|
|
1119
|
+
| 14 | Strip policy from core | Complete | [phase-14-strip-policy.md](history/phase-14-strip-policy.md) |
|
|
1120
|
+
| 15 | Domain model evolution | Complete | [phase-15-domain-model-evolution.md](history/phase-15-domain-model-evolution.md) |
|
|
1121
|
+
| 16 | Invert dependencies (extensions on a minimal core) | Complete | [phase-16-invert-dependencies.md](history/phase-16-invert-dependencies.md) |
|
|
1122
|
+
| 17 | Core consolidation | Complete | [phase-17-core-consolidation.md](history/phase-17-core-consolidation.md) |
|
|
1123
|
+
| 18 | Reconsider UI (first principles) | Complete | [phase-18-reconsider-ui.md](history/phase-18-reconsider-ui.md) |
|
|
1070
1124
|
|
|
1071
1125
|
### Structural refactoring issues
|
|
1072
1126
|
|
|
@@ -1090,6 +1144,7 @@ Detailed records are preserved in per-phase history files:
|
|
|
1090
1144
|
| Phase 16 (abandoned) | #256 (superseded), #257 (parked), #258, #259 (not planned) | Agent collaborator architecture — replaced by the inversion approach above ([ADR-0002]) |
|
|
1091
1145
|
| 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 |
|
|
1092
1146
|
| Phase 17 (follow-on) | #412, #415 | Session-mock builder unification, worktrees settings-helper migration |
|
|
1147
|
+
| Phase 18 | #420, #421, #422, #423, #424, #425, #426, #427 | Fold metrics onto record, migrate readers, delete activity tier, widget self-drives, drop widget from tool, reconcile event contract, consolidate test clones, UI-direction ADR |
|
|
1093
1148
|
|
|
1094
1149
|
The remaining open issue is #22 (parent-session resolution), a cross-extension track that does not gate the structural work.
|
|
1095
1150
|
|
|
@@ -1153,4 +1208,12 @@ The upstream test suite is run periodically as a regression canary for the sessi
|
|
|
1153
1208
|
[#425]: https://github.com/gotgenes/pi-packages/issues/425
|
|
1154
1209
|
[#426]: https://github.com/gotgenes/pi-packages/issues/426
|
|
1155
1210
|
[#427]: https://github.com/gotgenes/pi-packages/issues/427
|
|
1211
|
+
[#441]: https://github.com/gotgenes/pi-packages/issues/441
|
|
1212
|
+
[#442]: https://github.com/gotgenes/pi-packages/issues/442
|
|
1213
|
+
[#443]: https://github.com/gotgenes/pi-packages/issues/443
|
|
1214
|
+
[#444]: https://github.com/gotgenes/pi-packages/issues/444
|
|
1215
|
+
[#445]: https://github.com/gotgenes/pi-packages/issues/445
|
|
1216
|
+
[#446]: https://github.com/gotgenes/pi-packages/issues/446
|
|
1217
|
+
[#447]: https://github.com/gotgenes/pi-packages/issues/447
|
|
1156
1218
|
[ADR-0002]: ../decisions/0002-extensions-on-a-minimal-core.md
|
|
1219
|
+
[ADR-0004]: ../decisions/0004-reconsider-ui-direction.md
|