@cr1ms0n/pi-subagent 0.8.1
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 +352 -0
- package/LICENSE +21 -0
- package/README.md +543 -0
- package/docs/ARCHITECTURE.md +125 -0
- package/docs/COST-ACCOUNTING.md +66 -0
- package/docs/PLAN.md +325 -0
- package/docs/RELEASING.md +32 -0
- package/docs/ROADMAP.md +252 -0
- package/docs/SECURITY.md +85 -0
- package/docs/UI-OVERHAUL.md +186 -0
- package/docs/UX.md +141 -0
- package/extensions/subagent.ts +1 -0
- package/package.json +58 -0
- package/skills/subagent/SKILL.md +103 -0
- package/src/agents.ts +285 -0
- package/src/backend.ts +146 -0
- package/src/backends/claude.ts +384 -0
- package/src/backends/codex.ts +330 -0
- package/src/backends/index.ts +26 -0
- package/src/backends/pi.ts +94 -0
- package/src/btw.ts +34 -0
- package/src/config.ts +254 -0
- package/src/distill.ts +222 -0
- package/src/extension.ts +1527 -0
- package/src/format.ts +365 -0
- package/src/index.ts +60 -0
- package/src/launch.ts +120 -0
- package/src/maintenance.ts +6 -0
- package/src/model-policy.ts +157 -0
- package/src/notifications.ts +106 -0
- package/src/orchestrator.ts +247 -0
- package/src/output.ts +124 -0
- package/src/persistence.ts +334 -0
- package/src/policy.ts +500 -0
- package/src/process-lock.ts +687 -0
- package/src/protocol.ts +290 -0
- package/src/registry.ts +632 -0
- package/src/runner.ts +850 -0
- package/src/schema.ts +166 -0
- package/src/semaphore.ts +123 -0
- package/src/structured.ts +169 -0
- package/src/transcript.ts +360 -0
- package/src/types.ts +197 -0
- package/src/ui.ts +545 -0
- package/src/usage.ts +274 -0
- package/src/worktree.ts +753 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Cost accounting
|
|
2
|
+
|
|
3
|
+
`pi-subagent` reports three independent ledgers:
|
|
4
|
+
|
|
5
|
+
- **root** — provider-reported usage from assistant messages on the active parent-session branch.
|
|
6
|
+
- **subagents** — provider-reported cumulative usage from child-run checkpoints and terminal events on that same branch.
|
|
7
|
+
- **combined** — root + subagents.
|
|
8
|
+
|
|
9
|
+
These totals appear in `subagent { action: "status" }`, per-run status, the `/subagent-cost` command, and the `/subagents` overlay header. The footer stays terse (running/ready counts only) because Pi's native footer already shows session cost — including subagent spend, on Pi builds with native tool-result usage accounting (see below).
|
|
10
|
+
|
|
11
|
+
## Source of truth
|
|
12
|
+
|
|
13
|
+
The extension does not estimate prices. It uses Pi's normalized provider response:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
message.usage.cost.total
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
It also retains provider-reported input/output/cache category costs, token counts, reasoning tokens, context size, and completed turn count when supplied.
|
|
20
|
+
|
|
21
|
+
## Native Pi usage accounting
|
|
22
|
+
|
|
23
|
+
Pi builds after v0.80.10 persist an optional `usage` field on tool-result messages ([pi#6671](https://github.com/earendil-works/pi/pull/6671)) and fold it into the native footer total, `/session` statistics (as `Tools/summaries`), and RPC `get_state` totals.
|
|
24
|
+
|
|
25
|
+
The extension participates in both directions:
|
|
26
|
+
|
|
27
|
+
- **Upward** — the tool result that *delivers* a run (foreground completion, or the first `wait`) carries the run's total provider usage as native `usage`. Attachment is gated on the same delivered-flag transition as output delivery, so it happens exactly once per run UUID. Status, replayed waits, steer, diff/apply/discard, and plan responses never attach usage. Older Pi hosts copy only `content`/`details` from tool results and silently ignore the field — safe on every version this package supports.
|
|
28
|
+
- **Downward** — a child's event stream may contain tool-result messages that themselves carry nested usage (for example, a grandchild subagent on a new-Pi child). The parent folds that into the run's cumulative usage, so `max_cost` budgets and both ledgers see true subtree spend. Pre-#6671 children simply never emit the field.
|
|
29
|
+
|
|
30
|
+
Known undercounts in the **native** total (the extension ledger still counts these from persisted entries):
|
|
31
|
+
|
|
32
|
+
- A background run dismissed in the overlay (or via status) without a delivering `wait` never produces a tool result, so its spend reaches only the extension ledger.
|
|
33
|
+
- A failed or lost run raises an error instead of returning a tool result; any pre-failure usage likewise reaches only the extension ledger.
|
|
34
|
+
|
|
35
|
+
Because the native footer counts parent assistant messages plus delivered tool-result usage, and the extension's **combined** counts the same runs by UUID, the two agree whenever every terminal run was delivered.
|
|
36
|
+
|
|
37
|
+
## Deduplication rules
|
|
38
|
+
|
|
39
|
+
1. Root assistant messages are counted once by session-entry ID.
|
|
40
|
+
2. Each subagent run is counted once by full run UUID; the newest live/checkpoint/terminal cumulative value replaces older values.
|
|
41
|
+
3. Delivery, dismissal, status, and checkpoint events never add cost.
|
|
42
|
+
4. If an old run is evicted from in-memory UI history, its latest persisted usage still contributes to the session ledger.
|
|
43
|
+
5. Active and immediately completed runs supplement or replace stale persisted checkpoints until newer session entries become visible; the full run UUID prevents double counting afterward.
|
|
44
|
+
6. Resumed and forked invocations are distinct billed runs. Their new provider usage is counted once, even though they reuse prior context.
|
|
45
|
+
7. Retry attempts (transient-failure retries and model fallbacks) accumulate into their
|
|
46
|
+
run's single usage record — every attempt's billed usage counts once, under one run
|
|
47
|
+
UUID, with `attemptedModels` recording the escalation path.
|
|
48
|
+
8. The optional parallel `synthesis` child bills into the same run as an extra result.
|
|
49
|
+
9. Native `usage` on the delivering tool result mirrors rule 2's run totals and is attached at most once per run (delivered-flag gated), so Pi-side totals cannot double count a run either.
|
|
50
|
+
|
|
51
|
+
## Branch semantics
|
|
52
|
+
|
|
53
|
+
Only `sessionManager.getBranch()` is used. Costs from abandoned sibling branches are excluded. When a parent session is forked, its inherited active-branch terminal entries remain part of that fork's historical total; new runs are added to the fork independently.
|
|
54
|
+
|
|
55
|
+
## Failure and cancellation
|
|
56
|
+
|
|
57
|
+
Any usage reported before a failure, timeout, budget stop, cancellation, or parent crash is retained in a cumulative checkpoint/terminal record. A run with no provider response contributes zero rather than an estimate.
|
|
58
|
+
|
|
59
|
+
## Provider limitations
|
|
60
|
+
|
|
61
|
+
Accounting is only as precise as the provider data normalized by Pi:
|
|
62
|
+
|
|
63
|
+
- Some providers may report zero or incomplete costs.
|
|
64
|
+
- `reasoning` is a subset of output tokens and is not added to output again.
|
|
65
|
+
- `contextTokens` is the latest turn's context size, not an additive billed-token field.
|
|
66
|
+
- The extension deliberately does not infer missing prices from a local model table.
|
package/docs/PLAN.md
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# Execution plan — remaining roadmap phases
|
|
2
|
+
|
|
3
|
+
Formalization of [ROADMAP.md](./ROADMAP.md) phases 2–4 into implementable work
|
|
4
|
+
items. Where the roadmap holds rationale and design sketches, this document
|
|
5
|
+
holds the execution contract: exact scope, file-level work breakdown,
|
|
6
|
+
acceptance criteria, test plan, and release gates. Each work item is sized to
|
|
7
|
+
be implementable in isolation (one branch / one reviewable diff) by a person
|
|
8
|
+
or subagent given only this document and the codebase.
|
|
9
|
+
|
|
10
|
+
Status legend: `[ ]` not started · `[~]` in progress · `[x]` done
|
|
11
|
+
|
|
12
|
+
Shipped so far: Phase 1 (structured results) in v0.3.0; phases 2–4 landed
|
|
13
|
+
together and shipped as a single v0.4.0 (the staged v0.4.0/v0.5.0/v0.5.x
|
|
14
|
+
gates below were collapsed — all items met their gates concurrently).
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Ground rules (apply to every item)
|
|
19
|
+
|
|
20
|
+
1. **Invariants hold.** Every item must preserve docs/ARCHITECTURE.md
|
|
21
|
+
invariants 1–26. Items that touch spawn/kill/lock paths must state which
|
|
22
|
+
invariants they interact with in the PR description.
|
|
23
|
+
2. **Precedence order is sacred:** explicit request params > agent file >
|
|
24
|
+
per-profile `taskDefaults` > parent inheritance. New fields slot into this
|
|
25
|
+
order; nothing reorders it.
|
|
26
|
+
3. **Fail closed, degrade open.** Policy/validation errors reject before
|
|
27
|
+
spawn with actionable messages. Runtime failures after money is spent
|
|
28
|
+
preserve partial work (`partial`, never silent discard).
|
|
29
|
+
4. **Every item ships with:** unit tests, an integration test through the
|
|
30
|
+
extension harness when the tool surface changes, doc updates (README +
|
|
31
|
+
ARCHITECTURE invariants if applicable + CHANGELOG entry), and a green
|
|
32
|
+
`npm run release:check`.
|
|
33
|
+
5. **Schema changes are additive.** `additionalProperties: false` on the tool
|
|
34
|
+
schema means older callers break on unknown fields — new fields are always
|
|
35
|
+
optional, never renamed, never repurposed.
|
|
36
|
+
6. **Fake-pi first.** New child behaviors get a deterministic fake-pi mode
|
|
37
|
+
(tests/helpers/fake-pi.mjs) before any real-Pi E2E. Real-Pi E2E is run
|
|
38
|
+
manually for runner-level changes and noted in the PR.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Phase 2 — Agent ecosystem depth → v0.4.0
|
|
43
|
+
|
|
44
|
+
Theme: deepen the named-agent system shipped in 0.2.0 without adding a second
|
|
45
|
+
config surface. All items are additive.
|
|
46
|
+
|
|
47
|
+
### 2.1 `spawns:` allowlist in agent frontmatter `[x]` (S, high)
|
|
48
|
+
|
|
49
|
+
Per-agent control over which agents a child may spawn — finer than the global
|
|
50
|
+
depth cap, mirroring oh-my-pi's spawn policy.
|
|
51
|
+
|
|
52
|
+
**Behavior contract**
|
|
53
|
+
- Frontmatter `spawns:` accepts `false`, `"*"`, or a comma/bracket list of
|
|
54
|
+
agent names. Absent = unrestricted (`"*"`), matching today's behavior.
|
|
55
|
+
- The policy travels to the child via a new env var `PI_SUBAGENT_SPAWNS`
|
|
56
|
+
(set in `src/runner.ts` childEnv, next to `PI_SUBAGENT_DEPTH`):
|
|
57
|
+
- unset/`*` → unrestricted
|
|
58
|
+
- empty string → spawning disabled
|
|
59
|
+
- `a,b` → only agents `a` or `b` may be requested; **agentless composition
|
|
60
|
+
is also rejected** (a restricted parent may only delegate to named,
|
|
61
|
+
vetted personas).
|
|
62
|
+
- Enforcement lives in `validateSubagentRequest` (`src/policy.ts`): parse the
|
|
63
|
+
env like `parseDepth` — **fail closed on malformed values** (treat as
|
|
64
|
+
disabled, not unrestricted).
|
|
65
|
+
- A child whose policy is `spawns: false` additionally does not register the
|
|
66
|
+
subagent tool at all (extend the boot-depth check in
|
|
67
|
+
`src/extension.ts` `registerSubagent`).
|
|
68
|
+
- This is an accidental-recursion guard, not a security boundary (children
|
|
69
|
+
can shell out to `pi`); document in SECURITY.md next to the depth rule.
|
|
70
|
+
|
|
71
|
+
**Work breakdown**
|
|
72
|
+
- `src/agents.ts`: parse `spawns` frontmatter into
|
|
73
|
+
`spawns?: false | "*" | string[]` on `AgentDefinition`.
|
|
74
|
+
- `src/policy.ts`: `SPAWNS_ENV_VAR`, `parseSpawnPolicy(value)` (exported,
|
|
75
|
+
pure), enforcement branch in `validateSubagentRequest` before task
|
|
76
|
+
normalization.
|
|
77
|
+
- `src/runner.ts`: set `PI_SUBAGENT_SPAWNS` in childEnv from
|
|
78
|
+
`spec.spawns` (new TaskSpec field, resolved from the agent definition in
|
|
79
|
+
policy).
|
|
80
|
+
- `src/extension.ts`: skip tool registration when the boot spawn policy is
|
|
81
|
+
disabled (same pattern as `bootDepth >= 100`).
|
|
82
|
+
|
|
83
|
+
**Acceptance criteria**
|
|
84
|
+
- Agent file `spawns: false` → its children get no subagent tool; direct
|
|
85
|
+
tool calls (if forced) are rejected with a message naming the restriction.
|
|
86
|
+
- `spawns: reviewer` → child may `agent: "reviewer"` only; `agent: "scout"`
|
|
87
|
+
and agentless tasks are rejected with the allowlist in the error.
|
|
88
|
+
- Malformed env (`PI_SUBAGENT_SPAWNS="\x00junk"`) → spawning disabled, not
|
|
89
|
+
unrestricted.
|
|
90
|
+
- Unrestricted paths (no agent file, no `spawns`) behave exactly as today —
|
|
91
|
+
zero regression in existing tests.
|
|
92
|
+
|
|
93
|
+
**Tests:** policy unit tests (parse + enforce + fail-closed), agents.ts parse
|
|
94
|
+
tests, one integration test spawning through a restricted persona (fake-pi).
|
|
95
|
+
|
|
96
|
+
### 2.2 Resumable-session discovery in `status` `[x]` (S)
|
|
97
|
+
|
|
98
|
+
**Behavior contract:** bare `status` output lists, for each completed run
|
|
99
|
+
with a session id, a line ` session <id8> (resumable)` under the run
|
|
100
|
+
preview; run-specific `status` includes full session ids. One new
|
|
101
|
+
`promptGuidelines` bullet: resume via `resume: "<session id>"`.
|
|
102
|
+
|
|
103
|
+
**Work breakdown:** `src/extension.ts` status branch only (snapshot data
|
|
104
|
+
already carries `results[].sessionId`); no schema change.
|
|
105
|
+
|
|
106
|
+
**Acceptance criteria:** a finished run's session id is discoverable from
|
|
107
|
+
`status` alone (no overlay, no prior knowledge); delivered/dismissed runs
|
|
108
|
+
still listed until evicted.
|
|
109
|
+
|
|
110
|
+
**Tests:** extend the existing status integration test.
|
|
111
|
+
|
|
112
|
+
### 2.3 Dry-run validation — `action: "plan"` `[x]` (S)
|
|
113
|
+
|
|
114
|
+
**Behavior contract**
|
|
115
|
+
- `{ action: "plan", ...any single/parallel params }` runs full validation +
|
|
116
|
+
preflight and returns the resolved plan without spawning:
|
|
117
|
+
per task — label, agent (if any), model, thinking, profile, RO/RW,
|
|
118
|
+
effective tools, budgets, isolation, and `resolutionNotes`.
|
|
119
|
+
- Preflight beyond policy: worktree tasks check `isGitRepo(cwd)`;
|
|
120
|
+
`context:'fork'` checks the parent session file exists; `output` paths
|
|
121
|
+
check the parent directory is writable (stat only, no writes).
|
|
122
|
+
- Validation failures return the same errors the real call would — `plan` is
|
|
123
|
+
a truth oracle, never a softer check.
|
|
124
|
+
|
|
125
|
+
**Work breakdown**
|
|
126
|
+
- `src/schema.ts`: add `"plan"` to the Action union. **Note:** unlike other
|
|
127
|
+
actions, `plan` combines WITH task fields — adjust the mode-exclusivity
|
|
128
|
+
check in `src/policy.ts` (`action:"plan"` + task/tasks is the valid shape;
|
|
129
|
+
`plan` alone is an error).
|
|
130
|
+
- `src/policy.ts`: thread a `planOnly` flag through `ValidationResult`.
|
|
131
|
+
- `src/extension.ts`: on plan mode, run worktree/fork/output preflights and
|
|
132
|
+
return a formatted plan text + `details.plan` array. No registry entry, no
|
|
133
|
+
run id.
|
|
134
|
+
|
|
135
|
+
**Acceptance criteria:** a parallel request with a shared-cwd writer
|
|
136
|
+
violation reports the same error via `plan` as via execution; a valid plan
|
|
137
|
+
reports resolved model/tools per task; nothing is spawned (no run appears in
|
|
138
|
+
`status` afterward).
|
|
139
|
+
|
|
140
|
+
**Tests:** policy unit tests for the new mode shape; integration test
|
|
141
|
+
asserting plan output + absence of registry entries.
|
|
142
|
+
|
|
143
|
+
### 2.4 Agent-file prompt composition — `@file.md` references `[x]` (S)
|
|
144
|
+
|
|
145
|
+
**Behavior contract:** an agent body line consisting solely of
|
|
146
|
+
`@include relative/path.md` is replaced by that file's contents (relative to
|
|
147
|
+
the agent file, same 64KB/symlink/name guards as `output_schema: @ref`).
|
|
148
|
+
One level only — includes do not recurse. Missing/oversized/symlinked
|
|
149
|
+
includes leave the line verbatim (degrade open, never fail discovery).
|
|
150
|
+
|
|
151
|
+
**Work breakdown:** `src/agents.ts` only (`parseAgentFile` body
|
|
152
|
+
post-processing + shared guard helper with `parseSchemaValue`).
|
|
153
|
+
|
|
154
|
+
**Tests:** agents unit tests (resolution, missing file, symlink rejection,
|
|
155
|
+
no recursion).
|
|
156
|
+
|
|
157
|
+
**Release gate v0.4.0:** 2.1–2.4 merged · all tests green · README agent-file
|
|
158
|
+
docs updated (spawns, @include) · SECURITY.md spawn-policy note · CHANGELOG ·
|
|
159
|
+
tag.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Phase 3 — Engine hardening → v0.5.0
|
|
164
|
+
|
|
165
|
+
Theme: close the last known failure modes from the fresh-eyes review and the
|
|
166
|
+
oh-my-pi concurrency lesson. Highest-risk phase; every item starts with a
|
|
167
|
+
failing repro test.
|
|
168
|
+
|
|
169
|
+
### 3.1 Global-slot granularity for spawn trees `[x]` (M, high)
|
|
170
|
+
|
|
171
|
+
**Problem (repro first):** `maxGlobalActive` slots (`src/process-lock.ts`
|
|
172
|
+
`tryAcquireGlobalSlot`, held in `src/runner.ts` for the child's entire run)
|
|
173
|
+
are consumed by nested parents while they block on their own children — a
|
|
174
|
+
spawn tree wider than the cap deadlocks.
|
|
175
|
+
|
|
176
|
+
**Step 1 — repro test (merge even before the fix):**
|
|
177
|
+
`tests/process-lock.test.ts`: with `maxGlobalActive: 2`, simulate a depth-1
|
|
178
|
+
parent holding a slot while two of its children queue for slots; assert the
|
|
179
|
+
current behavior deadlocks/times out, then flip the assertion with the fix.
|
|
180
|
+
|
|
181
|
+
**Step 2 — chosen design: depth-reserved tiers.** Deterministic and simple:
|
|
182
|
+
slot files gain a `depth` field; `tryAcquireGlobalSlot(runId, depth)` enforces
|
|
183
|
+
`activeAtOrBelowDepth(depth) < maxGlobalActive - reservedFor(depth)` where
|
|
184
|
+
`reservedFor(depth) = min(depth, maxDepth-1)` slots are held back for deeper
|
|
185
|
+
tiers. With defaults (cap 16, maxDepth 2): depth-0 children may hold at most
|
|
186
|
+
15 slots, guaranteeing depth-1 spawns always have ≥1 slot — deadlock becomes
|
|
187
|
+
impossible by construction. Rejected alternative (release-while-waiting) needs
|
|
188
|
+
child-side cooperation signals we don't have.
|
|
189
|
+
|
|
190
|
+
**Work breakdown:** `src/process-lock.ts` (slot record field + tiered
|
|
191
|
+
acquire), `src/runner.ts` (pass depth), migration: slot files without `depth`
|
|
192
|
+
count as depth 0.
|
|
193
|
+
|
|
194
|
+
**Acceptance criteria:** repro test passes; existing single-level fanout
|
|
195
|
+
behavior unchanged (16 leaf tasks still run 16-wide); a full-width tree at
|
|
196
|
+
depth 0 + spawning children completes without timeout.
|
|
197
|
+
|
|
198
|
+
### 3.2 Dirty-baseline worktrees — `include_wip` `[x]` (M)
|
|
199
|
+
|
|
200
|
+
**Behavior contract**
|
|
201
|
+
- New task field `include_wip: true` (worktree isolation only; rejected
|
|
202
|
+
otherwise): after `git worktree add`, the parent checkout's uncommitted
|
|
203
|
+
changes (`git diff HEAD` + untracked files) are applied to the worktree,
|
|
204
|
+
uncommitted.
|
|
205
|
+
- The WIP patch is stored in the `WorktreeHandle`; `diff` and `apply`
|
|
206
|
+
subtract it: `diff` shows agent-only changes when subtraction is clean,
|
|
207
|
+
and falls back to the combined delta **with an explicit
|
|
208
|
+
`[includes parent WIP]` warning** when it is not (never silently wrong).
|
|
209
|
+
- Default off. `finalize`'s changed-detection treats a worktree containing
|
|
210
|
+
only the untouched WIP patch as unchanged (clean up, don't preserve).
|
|
211
|
+
|
|
212
|
+
**Work breakdown:** `src/worktree.ts` (create option, WIP capture/apply,
|
|
213
|
+
handle field, subtraction in `diff`), `src/orchestrator.ts` (thread the
|
|
214
|
+
flag), `src/schema.ts`/`src/policy.ts` (field + validation), extension
|
|
215
|
+
worktree actions unchanged (they read the handle).
|
|
216
|
+
|
|
217
|
+
**Acceptance criteria:** worktree child sees parent WIP; `diff` on an
|
|
218
|
+
untouched WIP-seeded worktree reports no agent changes; `apply` lands only
|
|
219
|
+
agent changes on the clean-subtraction path; combined-delta fallback carries
|
|
220
|
+
the warning.
|
|
221
|
+
|
|
222
|
+
**Tests:** worktree unit tests with a dirty repo fixture (staged + unstaged +
|
|
223
|
+
untracked), orchestrator integration test.
|
|
224
|
+
|
|
225
|
+
### 3.3 Lease-expiry reclaim latency `[x]` (S)
|
|
226
|
+
|
|
227
|
+
**Behavior contract:** in `src/process-lock.ts` stale-lock evaluation
|
|
228
|
+
(`acquireSessionLock`), a lock whose owner is *verifiably dead* (same host,
|
|
229
|
+
`isAlive === false` with a start-time identity match) is reclaimable
|
|
230
|
+
immediately (already true) — and a lock whose lease is expired is reclaimable
|
|
231
|
+
after **one** lease period (`leaseExpiresAt < now`) when the owner's host
|
|
232
|
+
differs or identity is unverifiable-but-lease-expired, keeping the current
|
|
233
|
+
2× window only when clock skew is plausible (same host, identity unknown).
|
|
234
|
+
Document the skew assumption inline.
|
|
235
|
+
|
|
236
|
+
**Tests:** table-driven stale-evaluation tests over (host match ×
|
|
237
|
+
identity-verifiable × lease state).
|
|
238
|
+
|
|
239
|
+
### 3.4 API-consumer orphan documentation `[x]` (S)
|
|
240
|
+
|
|
241
|
+
`runSubagent()` without `locks` + `runId` writes no durable run record, so
|
|
242
|
+
its children are invisible to orphan reclaim. Add a prominent JSDoc warning
|
|
243
|
+
on `runSubagent` and `RunnerOptions.locks`, plus a README "Using the runner
|
|
244
|
+
as a library" note. Decision recorded: no implicit default lock manager (an
|
|
245
|
+
API user who wants durability opts in; magic global state is worse).
|
|
246
|
+
|
|
247
|
+
**Release gate v0.5.0:** 3.1 repro + fix · 3.2–3.4 · ARCHITECTURE invariants
|
|
248
|
+
updated (tiered slots → new invariant; WIP worktrees → amend invariant 16) ·
|
|
249
|
+
real-Pi E2E for 3.1/3.2 noted in PR · CHANGELOG · tag.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Phase 4 — Observability polish → v0.5.x
|
|
254
|
+
|
|
255
|
+
Theme: close the observe→steer loop. UI-only; no engine risk.
|
|
256
|
+
|
|
257
|
+
### 4.1 Live transcript view in `/subagents` `[x]` (M)
|
|
258
|
+
|
|
259
|
+
**Behavior contract**
|
|
260
|
+
- In the overlay detail view of a **running** run, pressing `t` toggles a
|
|
261
|
+
live transcript pane: tail of the child's session file
|
|
262
|
+
(`sessionDir/<sessionId>.jsonl` — resolve via the same glob the session
|
|
263
|
+
retention sweep uses), rendered as compact lines (role-prefixed text,
|
|
264
|
+
`→ tool` / `← result` markers), auto-following unless scrolled up.
|
|
265
|
+
- Read-only file tailing on a 500ms poll while visible; no RPC traffic, no
|
|
266
|
+
reads when hidden or for finished runs (finished runs keep the existing
|
|
267
|
+
checkpointed transcript).
|
|
268
|
+
- Degrades gracefully: session file not yet created → "waiting for child
|
|
269
|
+
session…"; unparseable lines skipped.
|
|
270
|
+
|
|
271
|
+
**Work breakdown:** `src/ui.ts` (detail-view mode flag, tail state, `t`
|
|
272
|
+
key), a small pure `tailSessionFile(path, maxLines)` helper in
|
|
273
|
+
`src/maintenance.ts` or new `src/transcript.ts` (unit-testable), adapter
|
|
274
|
+
method `getSessionFilePath(id)` on `SubagentAdapter`.
|
|
275
|
+
|
|
276
|
+
**Acceptance criteria:** transcript follows a live child within one poll
|
|
277
|
+
interval; scroll-up pauses follow; `s` steering still works from the same
|
|
278
|
+
view (observe → steer without leaving the overlay).
|
|
279
|
+
|
|
280
|
+
**Tests:** pure tail-helper tests (partial lines, rotation, missing file);
|
|
281
|
+
UI model test for the mode toggle.
|
|
282
|
+
|
|
283
|
+
### 4.2 Widget/notification config `[x]` (S)
|
|
284
|
+
|
|
285
|
+
`SubagentConfig` gains `widget: "background" | "off"` (default `background`)
|
|
286
|
+
and `notifications: "batched" | "off"` (default `batched`), env
|
|
287
|
+
`PI_SUBAGENT_WIDGET` / `PI_SUBAGENT_NOTIFICATIONS`. Gates in
|
|
288
|
+
`refreshWidget` and the `CompletionBatcher` wiring (`src/extension.ts`).
|
|
289
|
+
Config-sanitizer + integration tests for the off states.
|
|
290
|
+
|
|
291
|
+
### 4.3 Reliability flags in status previews `[x]` (S)
|
|
292
|
+
|
|
293
|
+
`formatStatusPreview` (`src/format.ts`) appends `[stalled <dur>]` for active
|
|
294
|
+
runs with `stalledSince` and `[attempt N]` when `attempts > 1`, so background
|
|
295
|
+
`status` polling and streamed tool updates surface watchdog/retry state
|
|
296
|
+
without the overlay. Format unit tests; keep the preview single-line and
|
|
297
|
+
within existing truncation.
|
|
298
|
+
|
|
299
|
+
**Release gate v0.5.x:** 4.1–4.3 · UX.md updated · CHANGELOG · tag.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Cross-cutting checklists
|
|
304
|
+
|
|
305
|
+
**Definition of done (per item)**
|
|
306
|
+
- [ ] Failing test written first for behavior changes (mandatory for Phase 3)
|
|
307
|
+
- [ ] Unit tests + integration test (if tool surface changed)
|
|
308
|
+
- [ ] Fake-pi mode added when child behavior is involved
|
|
309
|
+
- [ ] README + relevant docs/ updated; ARCHITECTURE invariant added/amended
|
|
310
|
+
when a guarantee changes
|
|
311
|
+
- [ ] CHANGELOG entry under the next unreleased version
|
|
312
|
+
- [ ] `npm run release:check` green
|
|
313
|
+
- [ ] Roadmap/plan status boxes updated (`[ ]` → `[x]`)
|
|
314
|
+
|
|
315
|
+
**Release procedure** (per docs/RELEASING.md): bump version + CHANGELOG →
|
|
316
|
+
commit → `git tag pi-subagent-vX.Y.Z` → push tag → monorepo CI publishes
|
|
317
|
+
this package (GitHub Release + npm via OIDC with provenance).
|
|
318
|
+
|
|
319
|
+
**Re-planning triggers** — revisit this plan (not just execute it) if:
|
|
320
|
+
- Pi upstream ships native subagent/task support (re-evaluate overlap),
|
|
321
|
+
- the RPC protocol changes shape (runner assumptions in 2.1/4.1),
|
|
322
|
+
- Claude Code's agent-teams stabilizes AND user demand for inter-agent
|
|
323
|
+
messaging materializes (deferred item in ROADMAP.md),
|
|
324
|
+
- `@parke.dev/pi-subagent` adoption surfaces a failure mode not covered by
|
|
325
|
+
phases 3–4 (reliability reports take priority over planned work).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Releasing @cr1ms0n/pi-subagent
|
|
2
|
+
|
|
3
|
+
This is an independent community fork of `@parke.dev/pi-subagent` by Luke Parke. Preserve the MIT license and copyright, and do not publish this fork under the upstream scope. The upstream monorepo's tag automation does not publish this package.
|
|
4
|
+
|
|
5
|
+
## Prepare
|
|
6
|
+
|
|
7
|
+
1. Update `package.json` and `CHANGELOG.md`; use an unpublished version.
|
|
8
|
+
2. Run strict type checking against the installed Pi version and offline fake-runner/extension tests. Do not run real provider calls without permission.
|
|
9
|
+
3. Run `npm pack --dry-run --json` and review the file list. Do not include authentication, user settings, machine-specific paths, local backups, session transcripts or generated test bundles.
|
|
10
|
+
4. Run `npm pack --ignore-scripts`, install the resulting tarball into an isolated prefix with `--ignore-scripts --legacy-peer-deps`, then repeat the offline checks against the packed source.
|
|
11
|
+
|
|
12
|
+
## Publish
|
|
13
|
+
|
|
14
|
+
Use an existing npm login or a securely supplied environment-based credential. Never put tokens in command text, source files, or a committed `.npmrc`. Enable TLS verification.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm whoami --strict-ssl=true --registry=https://registry.npmjs.org/
|
|
18
|
+
npm publish ./cr1ms0n-pi-subagent-<version>.tgz --access public --ignore-scripts --strict-ssl=true --registry=https://registry.npmjs.org/
|
|
19
|
+
npm view @cr1ms0n/pi-subagent@<version> name version dist.integrity --strict-ssl=true --registry=https://registry.npmjs.org/
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
A successful public release makes every file in the tarball public. Verify the package metadata and registry integrity before replacing an existing installation.
|
|
23
|
+
|
|
24
|
+
## Install and replace
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pi install npm:@cr1ms0n/pi-subagent@<version>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Do not enable this package and `@parke.dev/pi-subagent` at the same time: both register the same tool names. Back up the old package selection, activate only the new package after verification, and keep the old source for rollback. Reload or restart Pi after changing packages. Configure `~/.pi/subagent.json` modelPolicy before spawning tasks.
|
|
31
|
+
|
|
32
|
+
This fork uses the same config and persisted state paths as upstream. Switching packages is not a data migration. Upgrading must not overwrite user model choices or credentials.
|