@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.
Files changed (46) hide show
  1. package/CHANGELOG.md +352 -0
  2. package/LICENSE +21 -0
  3. package/README.md +543 -0
  4. package/docs/ARCHITECTURE.md +125 -0
  5. package/docs/COST-ACCOUNTING.md +66 -0
  6. package/docs/PLAN.md +325 -0
  7. package/docs/RELEASING.md +32 -0
  8. package/docs/ROADMAP.md +252 -0
  9. package/docs/SECURITY.md +85 -0
  10. package/docs/UI-OVERHAUL.md +186 -0
  11. package/docs/UX.md +141 -0
  12. package/extensions/subagent.ts +1 -0
  13. package/package.json +58 -0
  14. package/skills/subagent/SKILL.md +103 -0
  15. package/src/agents.ts +285 -0
  16. package/src/backend.ts +146 -0
  17. package/src/backends/claude.ts +384 -0
  18. package/src/backends/codex.ts +330 -0
  19. package/src/backends/index.ts +26 -0
  20. package/src/backends/pi.ts +94 -0
  21. package/src/btw.ts +34 -0
  22. package/src/config.ts +254 -0
  23. package/src/distill.ts +222 -0
  24. package/src/extension.ts +1527 -0
  25. package/src/format.ts +365 -0
  26. package/src/index.ts +60 -0
  27. package/src/launch.ts +120 -0
  28. package/src/maintenance.ts +6 -0
  29. package/src/model-policy.ts +157 -0
  30. package/src/notifications.ts +106 -0
  31. package/src/orchestrator.ts +247 -0
  32. package/src/output.ts +124 -0
  33. package/src/persistence.ts +334 -0
  34. package/src/policy.ts +500 -0
  35. package/src/process-lock.ts +687 -0
  36. package/src/protocol.ts +290 -0
  37. package/src/registry.ts +632 -0
  38. package/src/runner.ts +850 -0
  39. package/src/schema.ts +166 -0
  40. package/src/semaphore.ts +123 -0
  41. package/src/structured.ts +169 -0
  42. package/src/transcript.ts +360 -0
  43. package/src/types.ts +197 -0
  44. package/src/ui.ts +545 -0
  45. package/src/usage.ts +274 -0
  46. package/src/worktree.ts +753 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,352 @@
1
+ # Changelog
2
+
3
+ ## 0.8.1 — @cr1ms0n community fork (2026-09-08)
4
+
5
+ - Require an explicit model matching user-owned default/agent model policy.
6
+ - Restrict fallback models and their order to the configured route.
7
+ - Inject the effective model mapping into the parent prompt.
8
+ - Show actual attempt models in inline, background, inspector and completion UI.
9
+ - Preserve older completion payloads and encode Windows parallel/synthesis record filenames.
10
+ - Keep thinking-level selection unchanged from upstream.
11
+
12
+ The entries below are retained upstream history from @parke.dev/pi-subagent.
13
+
14
+
15
+ ## Unreleased
16
+
17
+ ### Machine-wide worktree GC
18
+
19
+ - Startup maintenance now sweeps every repo container under `worktreeDir` via
20
+ `WorktreeManager.sweepAll()`, not just the current checkout's — stale
21
+ containers for repos you stop visiting are finally reclaimed. Each
22
+ container's base repo is resolved from the create-time `base-repo` marker or
23
+ the linked worktree's gitdir pointer, then swept with the existing `sweep()`
24
+ safety model (archive unique work, never delete unreachable branches, 1h
25
+ min-age, keepPaths shielding).
26
+ - Containers whose base repo is gone are **kept and reported**
27
+ (`GlobalSweepReport.orphanedContainers`), never deleted: their object stores
28
+ lived inside the deleted repo, so unique work cannot be proven absent or
29
+ archived. Empty leftovers (no worktrees, no archived patches) are removed.
30
+ - Run process records now carry `worktreeCwd` so live worktree-isolated runs
31
+ from **other concurrent Pi processes** are shielded from the global sweep,
32
+ same as this session's live runs.
33
+ - Known limitation: `pi-workflows` reuses `WorktreeManager` with the default
34
+ root (its worktrees land in the same containers and are reclaimed by the
35
+ global sweep) but writes run records to a separate lock root, so its live
36
+ worktrees are shielded only by the 1h min-age window, not by run records.
37
+
38
+ ## 0.8.0
39
+
40
+ ### Lifecycle-driven storage GC (no more wall-clock retention)
41
+
42
+ Sessions and worktrees are now reclaimed when their run is **over**, not after
43
+ N days. "Over" means: terminal run state, not referenced by the parent branch,
44
+ not owned by any running run record machine-wide, and past a 1-hour
45
+ concurrency race guard.
46
+
47
+ - **Child session transcripts** are distilled to a small `.digest.json`
48
+ preserving the meaningful impact — task, final output, model/thinking,
49
+ usage totals, turn/tool/error counts, duration — and the raw `.jsonl` is
50
+ deleted (`src/distill.ts`). Sessions referenced by the active branch or busy
51
+ in any live run are never touched, so resume keeps working.
52
+ - **Worktrees** holding unique work are archived as one applyable
53
+ `git apply --3way` patch under `<repo-container>/_patches/` and the multi-GB
54
+ directory (checkout + node_modules) is reclaimed immediately. Branches whose
55
+ commits exist on no other ref are still never deleted. If archiving fails,
56
+ the worktree is kept — work is never destroyed unpreserved.
57
+ - `diff` / `apply` / `discard` transparently fall back to the archived patch
58
+ when the worktree directory is already reclaimed.
59
+ - `sessionRetentionDays` and `worktreeRetentionDays` are accepted but inert.
60
+
61
+ ## 0.7.0
62
+
63
+ ### Public library SDK
64
+
65
+ - Added stable `@parke.dev/pi-subagent` and `@parke.dev/pi-subagent/sdk`
66
+ entrypoints for programmatic consumers.
67
+ - Exported orchestration, runner, worktree, process-lock, semaphore, backend,
68
+ usage, and task/result types without requiring `src/*` imports.
69
+ - The Pi extension manifest remains `./extensions/subagent.ts` and is unchanged.
70
+ - Deep `src/*` package imports are intentionally no longer public once this
71
+ export map ships.
72
+
73
+ ## 0.6.0
74
+
75
+ ### Multi-backend children: pi, Codex, Claude Code
76
+
77
+ `backend: "pi" | "codex" | "claude"` on any task, parallel item, or agent
78
+ frontmatter. Children run on the vendor CLI as a child process, so **every
79
+ existing safety guarantee still applies** — git worktree isolation, machine-wide
80
+ process locks, nesting-depth limits, orphan reclaim, PID-identity group kill —
81
+ and **no new dependencies** are added. (The reference implementation this was
82
+ adapted from embeds `@anthropic-ai/claude-agent-sdk` in-process; the `claude`
83
+ CLI exposes everything needed without that weight.)
84
+
85
+ Internally this is a new `BackendAdapter` seam (`src/backend.ts`,
86
+ `src/backends/`). `ChildRunner` keeps all the backend-agnostic machinery;
87
+ adapters own only invocation building, event-stream parsing, the stdin command
88
+ dialect, and a capability record. The `pi` backend is a verbatim extraction of
89
+ the previous inline logic.
90
+
91
+ **Capabilities are enforced, not assumed.** Requests a backend cannot honor are
92
+ refused at validation time with an explanation, because silently dropping a
93
+ budget or a read-only guarantee turns a safety feature into a no-op:
94
+
95
+ | | pi | codex | claude |
96
+ | -------------------------------- | ----------------- | ----------------------------------- | ---------------------- |
97
+ | `max_cost` | ✅ | ❌ refused (tokens only, no cost) | ✅ `total_cost_usd` |
98
+ | read-only profile | ✅ tool allowlist | ✅ `--sandbox read-only` (OS-level) | ✅ `--allowedTools` |
99
+ | steering / graceful wrap-up | ✅ | ❌ no stdin channel | ❌ one-shot print mode |
100
+ | `resume` | ✅ | ✅ | ✅ |
101
+ | `context:'fork'` / `fork_resume` | ✅ | ❌ refused | ✅ `--fork-session` |
102
+ | `thinking` | ✅ | ❌ | ❌ |
103
+ | `output_schema` | ✅ | ✅ `--output-schema` | ✅ `--json-schema` |
104
+
105
+ Parsers were written against event streams captured verbatim from the real
106
+ CLIs (codex-cli 0.144.6, claude-code 2.1.219) and are fixture-tested including
107
+ truncated-stream, API-error and rate-limit paths.
108
+
109
+ ### Live transcript for every backend
110
+
111
+ Pressing `t` on a running run in `/subagents` previously assumed pi's session
112
+ layout and entry schema, so codex/claude runs showed "waiting for child
113
+ session…" forever. Vendor transcripts are now located by session id and
114
+ rendered through per-backend renderers, with each vendor's boilerplate
115
+ (codex's sandbox preamble, claude's queue bookkeeping) filtered out.
116
+
117
+ Tests: 277 → 308.
118
+
119
+ **Verified live:** codex end-to-end through the runner; the `max_cost` refusal
120
+ message; codex's read-only sandbox blocking a shell write with "operation not
121
+ permitted"; and both vendor transcripts tailing real on-disk session files.
122
+ Claude's happy path is fixture-tested only — the development account was
123
+ rate-limited during this work.
124
+
125
+ ## 0.5.1
126
+
127
+ ### `subagent_wait` — dedicated blocking-collect tool
128
+
129
+ - New **`subagent_wait`** tool (`{ id, timeout_ms? }`) sits alongside `subagent`.
130
+ Collecting a background run is the one management step a model reaches for
131
+ reflexively mid-flow, and burying it behind the `action:` union cost a
132
+ discovery step. This matches the shape the highest-adoption package in the
133
+ ecosystem converged on (`pi-subagents` ships `subagent` + `subagent_wait`).
134
+ - Implemented as a thin front-end that rewrites its arguments into the
135
+ equivalent `action:"wait"` request and reuses the main tool's `execute`, so
136
+ delivery / `markDelivered` / output-cap semantics cannot drift between the
137
+ two surfaces. `action:"wait"` remains fully supported.
138
+ - **`timeout_ms`** added to the shared wait path (so `action:"wait"` gains it
139
+ too): on timeout the run is explicitly **not** cancelled and **not** marked
140
+ delivered, so it stays collectable by a later wait.
141
+
142
+ ### `/btw` — side questions hidden from the main agent
143
+
144
+ - New **`/btw <question>`** command (or bare `/btw` for a prompt). The aside
145
+ runs as a normal subagent run — full policy, profile, budget, semaphore and
146
+ process-lock machinery — but its result is delivered with `pi.appendEntry()`
147
+ - an entry renderer, which by design does not participate in LLM context.
148
+ The user gets an answer rendered in the transcript while the main agent keeps
149
+ working, unaware of both question and answer.
150
+ - Ported from [davis7dotsh/my-pi-setup](https://github.com/davis7dotsh/my-pi-setup)'s
151
+ by-the-way feature, adapted to our process-per-child model.
152
+
153
+ Tests: 273 → 276. Both features' load-bearing invariants are mutation-checked.
154
+
155
+ ## 0.5.0
156
+
157
+ ### Native Pi cost accounting (pi#6671)
158
+
159
+ - **Upward**: the tool result that delivers a run (foreground completion or
160
+ the first `wait`) now carries the run's total provider usage as a native
161
+ `usage` field. Pi builds after v0.80.10 persist it on the session entry and
162
+ fold it into the footer cost, `/session` statistics (`Tools/summaries`
163
+ bucket), and RPC `get_state` totals — resolving the undercount that
164
+ motivated [pi#6509](https://github.com/earendil-works/pi/issues/6509).
165
+ Attachment is delivered-flag gated: exactly once per run UUID; status,
166
+ replayed waits, steer, worktree actions, and plan responses never attach
167
+ usage. Older Pi hosts silently ignore the field (no minimum version bump).
168
+ - **Downward**: tool-result messages in a child's event stream that carry
169
+ nested usage (e.g. grandchild subagents on a new-Pi child) now fold into
170
+ the run's cumulative usage, so `max_cost` budgets and the
171
+ root/subagent/combined ledger see true subtree spend. Pre-#6671 children
172
+ never emit the field; behavior there is unchanged.
173
+ - Known native-total gaps documented in COST-ACCOUNTING.md: dismissed-without-
174
+ wait background runs and failed/lost runs (thrown errors carry no usage)
175
+ reach only the extension ledger.
176
+
177
+ ## 0.4.0
178
+
179
+ ### Agent ecosystem (PLAN phase 2)
180
+
181
+ - **`spawns:` allowlist** in agent frontmatter (`false` / `"*"` / name list):
182
+ controls which agents a persona's children may spawn. The policy travels via
183
+ `PI_SUBAGENT_SPAWNS`; `spawns: false` children don't register the subagent
184
+ tool at all. Malformed env fails closed to disabled. Accidental-recursion
185
+ guard, not a security boundary (documented in SECURITY.md).
186
+ - **`@include relative/path.md`** in agent bodies: one-level prompt
187
+ composition with the same 64KB/symlink guards as `@contract.json`;
188
+ missing/rejected includes stay verbatim.
189
+ - **Resumable-session discovery**: bare `status` lists `session <id8>
190
+ (resumable)` under completed runs; run-specific `status` shows full ids, and
191
+ the prompt guidelines mention `resume:`.
192
+ - **`action: "plan"`** dry-run: full validation plus worktree/fork/output
193
+ preflights, returning the resolved per-task plan (model, tools, budgets,
194
+ isolation, notes) without spawning — same errors as the real call.
195
+
196
+ ### Engine hardening (PLAN phase 3)
197
+
198
+ - **Depth-tiered global slots**: slot records carry `depth` and shallow tiers
199
+ reserve capacity for deeper ones, so a spawn tree wider than
200
+ `maxGlobalActive` can no longer deadlock while parents wait on children.
201
+ Old slot files without `depth` count as depth 0.
202
+ - **`include_wip: true`** (worktree isolation only): seeds the worktree with
203
+ the parent checkout's uncommitted changes. `diff`/`apply` subtract the WIP
204
+ patch when clean, else report the combined delta with an explicit
205
+ `[includes parent WIP]` warning; an untouched WIP-only worktree counts as
206
+ unchanged and is cleaned up.
207
+ - **Faster stale-lock reclaim**: a lease-expired cross-host (or unverifiable
208
+ foreign) owner is reclaimable after one lease period; the 2× window remains
209
+ only where clock skew is plausible (same host, identity unknown).
210
+ - **Library-use warning**: `runSubagent()` without `locks` + `runId` writes no
211
+ durable run record (children invisible to orphan reclaim) — now documented
212
+ loudly in JSDoc and README.
213
+
214
+ ### Observability (PLAN phase 4)
215
+
216
+ - **Live transcript view**: in `/subagents`, `t` on a running run tails the
217
+ child's session file (500ms poll, auto-follow, scroll-up pauses); `s` steer
218
+ works from the same view.
219
+ - **`widget: "off"` / `notifications: "off"`** config keys (env
220
+ `PI_SUBAGENT_WIDGET` / `PI_SUBAGENT_NOTIFICATIONS`) for quiet mode.
221
+ - Status previews append `[stalled <dur>]` and `[attempt N]` so background
222
+ polling surfaces watchdog/retry state without the overlay.
223
+
224
+ ## 0.3.1
225
+
226
+ - Remove `publishConfig.provenance` (it blocked the one-time local bootstrap
227
+ publish of the new package name; OIDC publishes generate provenance
228
+ automatically). First release published end-to-end via Trusted Publishing
229
+ under `@parke.dev`.
230
+
231
+ ## 0.3.0
232
+
233
+ ### Structured results
234
+
235
+ - **`output_schema`**: declare a JSON Schema per task (or in agent-file
236
+ frontmatter as inline JSON / `@contract.json`). The contract is appended to
237
+ the child's system prompt; the final message must end with a fenced
238
+ `json:result` block. Validation runs parent-side against a dependency-free
239
+ JSON-Schema subset (type/properties/required/items/enum/const; unknown
240
+ keywords ignored). Invalid output triggers **one steer-based repair round**
241
+ before the child is allowed to settle; still-invalid results end `partial`
242
+ with `structuredError` and the raw text delivered — paid work is never
243
+ discarded. Valid results deliver as clean JSON and surface as
244
+ `details.results[].structuredOutput`.
245
+ - **Typed synthesis handoff**: validated parallel results feed the `synthesis`
246
+ child as JSON blocks instead of prose tails, with per-task validity flags.
247
+ - **Arg repair**: double-encoded task/system-prompt text (literal `\n`/`\"`
248
+ escapes) is conservatively de-mangled once at validation time; identifier
249
+ fields and path-like strings are never touched.
250
+ - UI: terminal rows annotate `✓ schema` / `schema ✗`.
251
+
252
+ ## 0.2.1
253
+
254
+ - **Package moved to `@parke.dev/pi-subagent`** (owned by the `parke.dev` npm
255
+ org). `@lukehagar/pi-subagent` is deprecated at 0.2.0 and will receive no
256
+ further updates; install the new scope with
257
+ `pi install npm:@parke.dev/pi-subagent`. No code changes besides the rename.
258
+ - CI/release workflows on actions/checkout@v7 + actions/setup-node@v7;
259
+ CI matrix trimmed to supported LTS lines (22, 24); `engines.node` corrected
260
+ to `>=22.19.0` (the actual pi-coding-agent floor).
261
+
262
+ ## 0.2.0
263
+
264
+ Major feature release: reliability engine, named agents, background-run UX,
265
+ and a complete TUI overhaul.
266
+
267
+ ### Named agent files
268
+
269
+ - Reusable subagent personas as markdown files with YAML frontmatter, discovered
270
+ from `.pi/agents/` (project), `.agents/agents/` (shared workspace), and
271
+ `$PI_CODING_AGENT_DIR/agents/` (global). Invoke with `agent: "name"`.
272
+ - Body becomes the child's appended system prompt; frontmatter supplies defaults
273
+ (`model`, `thinking`, `profile`, `tools`, budgets, `fallback_models`, `isolation`).
274
+ - Precedence per field: explicit params > agent file > per-profile `taskDefaults`
275
+ > parent inheritance. Capability profiles fail closed regardless of what an
276
+ > agent file declares.
277
+ - Catalog advertised in the tool's system-prompt guidelines and live in bare
278
+ `status` output; file changes picked up within seconds.
279
+
280
+ ### Reliability
281
+
282
+ - **Graceful budget stops**: at `max_turns`/`max_cost` the child is steered to
283
+ wrap up and given `grace_turns` (default 2) for a final answer before SIGTERM.
284
+ Results end `partial` with `wrappedUp: true` when the child concluded in time.
285
+ - **Retry with model fallback**: transient failures (queue timeouts, stalls,
286
+ spawn errors, provider errors, protocol truncation) retry automatically up to
287
+ `max_retries` extra attempts, escalating through `fallback_models`. Usage
288
+ accumulates across attempts; `attempts`/`attemptedModels` recorded. Task-quality
289
+ failures never retry.
290
+ - **Stall watchdog**: protocol silence for `stallAfterMs` (90s) flags the task
291
+ and probes liveness via `get_state`; continued silence for `stallKillAfterMs`
292
+ more kills the child (feeding retry) instead of burning the whole timeout.
293
+ - **PID-reuse protection on macOS/BSD**: process start-time identity via
294
+ `ps -o lstart=`; group kills verify identity before signalling.
295
+
296
+ ### Orchestration
297
+
298
+ - **Mid-run steering** (`action: "steer"`): children run in Pi RPC mode with a
299
+ live stdin command channel; inject guidance delivered after the current turn.
300
+ - **Context forking** (`context: "fork"`): child starts from a real branched
301
+ copy of the parent conversation. Single-task only; fails fast when the parent
302
+ session is not persisted.
303
+ - **Worktree loop**: `diff` / `apply` / `discard` actions on finished runs with
304
+ changed worktrees. `apply` lands the combined patch as uncommitted changes via
305
+ `git apply --3way`; never commits, never auto-deletes.
306
+ - **Parallel synthesis** (`synthesis: "…"`): one read-only child folds parallel
307
+ outputs into a brief delivered first, with explicit truncation markers.
308
+ - **Per-task `description`** labels and per-profile `taskDefaults` config
309
+ (model/thinking/budget routing without naming agents).
310
+
311
+ ### Background runs
312
+
313
+ - **Completion notifications**: terminal async runs send a batched `followUp`
314
+ message so the parent reacts without polling. Successes group within a short
315
+ window; failures flush immediately; a consuming `wait` suppresses the
316
+ redundant notification. Themed compact box for humans.
317
+ - **Ambient widget**: live above-editor tree (spinner, stats, activity tail)
318
+ for background runs only — foreground runs already render inline.
319
+
320
+ ### TUI overhaul
321
+
322
+ - One-line `renderCall`; fixed-shape mutate-in-place streaming blocks; compact
323
+ terminal stats with state glyphs; per-task rows for parallel runs; frozen
324
+ durations at `endedAt`; reliability annotations (`[attempt 2]`,
325
+ `[stalled 2m]`, `◐ wrapped up`).
326
+ - Terse footer (running/ready counts only); cost ledger moved to
327
+ `/subagent-cost`, `status`, and the `/subagents` overlay header.
328
+ - Overlay rebuilt: themed header with counters + ledger, two-line list rows,
329
+ structured detail view, steering (`s`), worktree apply/discard (`a`/`x`).
330
+ - Trailing-edge streaming flush (the last update of a burst always renders);
331
+ stable component identity across partial renders.
332
+
333
+ ### Performance
334
+
335
+ - Transcript joins only on message boundaries (was O(N²) per stdout chunk).
336
+ - Memoized per-result snapshot projection (only changed tasks re-project).
337
+ - Trailing-edge coalescing for streamed tool updates.
338
+
339
+ ### Fixes
340
+
341
+ - Resolve the Pi CLI entry through bin symlinks (npm/Homebrew shims) instead of
342
+ falling back to bare `pi` on PATH.
343
+ - Headless children auto-cancel extension UI dialogs so they can never hang.
344
+ - Prompt-rejection in RPC mode fails fast instead of idling forever.
345
+
346
+ ## 0.1.3
347
+
348
+ - Require `type: object` tool schema for provider compatibility.
349
+
350
+ ## 0.1.2
351
+
352
+ - Publish scoped `@lukehagar/pi-subagent` on npm; release workflow hardening.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Luke Parke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.