@pi-unipi/unipi 3.0.0-alpha.2 → 3.0.0-alpha.3

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 (173) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +2 -2
  3. package/package.json +23 -22
  4. package/packages/ask-user/package.json +2 -2
  5. package/packages/autocomplete/package.json +1 -1
  6. package/packages/autocomplete/src/constants.ts +10 -19
  7. package/packages/background-tasks/package.json +2 -2
  8. package/packages/background-tasks/src/config.ts +0 -73
  9. package/packages/background-tasks/src/index.ts +0 -15
  10. package/packages/background-tasks/src/registry.ts +1 -171
  11. package/packages/background-tasks/src/types.ts +0 -32
  12. package/packages/btw/README.md +13 -56
  13. package/packages/btw/extensions/btw.ts +403 -1796
  14. package/packages/btw/package.json +5 -2
  15. package/packages/btw/skills/btw/SKILL.md +7 -143
  16. package/packages/compactor/package.json +3 -3
  17. package/packages/core/child-agent.ts +1 -0
  18. package/packages/core/command-echo.ts +63 -0
  19. package/packages/core/constants.ts +0 -5
  20. package/packages/core/fusion-status.ts +4 -0
  21. package/packages/core/index.ts +3 -0
  22. package/packages/core/package.json +1 -1
  23. package/packages/core/src/child-agent/child-args.ts +31 -0
  24. package/packages/core/src/child-agent/delivery.ts +41 -0
  25. package/packages/core/src/child-agent/index.ts +5 -0
  26. package/packages/core/src/child-agent/readers.ts +202 -0
  27. package/packages/core/src/child-agent/runtime.ts +571 -0
  28. package/packages/core/src/settings/engine.ts +48 -2
  29. package/packages/core/src/settings/hub.ts +39 -10
  30. package/packages/core/src/settings/schema.ts +19 -3
  31. package/packages/core/src/tui/hub-kit.ts +12 -0
  32. package/packages/core/src/tui/kit.ts +198 -0
  33. package/packages/core/src/tui/progress.ts +73 -0
  34. package/packages/footer/package.json +3 -3
  35. package/packages/fusion/package.json +3 -3
  36. package/packages/fusion/src/child-args.ts +1 -0
  37. package/packages/fusion/src/index.ts +121 -5
  38. package/packages/fusion/src/pi-settings.ts +57 -0
  39. package/packages/fusion/src/picker.ts +116 -37
  40. package/packages/fusion/src/preset.ts +56 -2
  41. package/packages/fusion/src/prompts.ts +1 -1
  42. package/packages/fusion/src/sidekick-runtime.ts +1 -420
  43. package/packages/fusion/src/tools.ts +71 -133
  44. package/packages/fusion/src/transcript.ts +37 -82
  45. package/packages/image/package.json +2 -2
  46. package/packages/info-screen/package.json +2 -2
  47. package/packages/input-shortcuts/package.json +2 -2
  48. package/packages/input-shortcuts/src/cleared-input.ts +97 -0
  49. package/packages/input-shortcuts/src/index.ts +4 -0
  50. package/packages/kanboard/README.md +16 -8
  51. package/packages/kanboard/index.ts +4 -0
  52. package/packages/kanboard/package.json +7 -7
  53. package/packages/kanboard/skills/kanboard/SKILL.md +10 -4
  54. package/packages/kanboard/src/bin.ts +4 -2
  55. package/packages/kanboard/src/commands.ts +6 -1
  56. package/packages/kanboard/src/progress.ts +27 -0
  57. package/packages/kanboard/src/runner.ts +197 -62
  58. package/packages/kanboard/src/settings.ts +59 -0
  59. package/packages/long-horizon/index.ts +48 -5
  60. package/packages/long-horizon/package.json +2 -2
  61. package/packages/long-horizon/src/commands.ts +18 -1
  62. package/packages/long-horizon/src/engine/continuation.ts +4 -3
  63. package/packages/long-horizon/src/engine/goal-state.ts +2 -1
  64. package/packages/long-horizon/src/engine/runaway.ts +1 -1
  65. package/packages/long-horizon/src/gate.ts +13 -8
  66. package/packages/long-horizon/src/progress.ts +87 -0
  67. package/packages/long-horizon/src/runtime.ts +56 -6
  68. package/packages/long-horizon/src/settings.ts +31 -1
  69. package/packages/long-horizon/src/tools/graph.ts +1 -1
  70. package/packages/long-horizon/src/tools/swarm.ts +3 -3
  71. package/packages/mcp/package.json +2 -2
  72. package/packages/memory/index.ts +44 -17
  73. package/packages/memory/package.json +3 -3
  74. package/packages/memory/tools.ts +99 -105
  75. package/packages/notify/package.json +2 -2
  76. package/packages/skill-registry/package.json +1 -1
  77. package/packages/subagents/README.md +40 -119
  78. package/packages/subagents/package.json +5 -13
  79. package/packages/subagents/skills/subagents/SKILL.md +18 -42
  80. package/packages/subagents/src/agents.ts +213 -0
  81. package/packages/subagents/src/badge-session.ts +46 -0
  82. package/packages/subagents/src/badge.ts +43 -0
  83. package/packages/subagents/src/cards.ts +172 -0
  84. package/packages/subagents/src/index.ts +559 -1086
  85. package/packages/subagents/src/manager.ts +399 -0
  86. package/packages/subagents/src/profiles.ts +130 -0
  87. package/packages/subagents/src/transcript.ts +154 -0
  88. package/packages/subagents/src/ui.ts +328 -0
  89. package/packages/unipi/bundled.js +7983 -16957
  90. package/packages/unipi/index.ts +3 -2
  91. package/packages/updater/package.json +2 -2
  92. package/packages/utility/package.json +2 -2
  93. package/packages/watchdog/index.ts +2 -2
  94. package/packages/watchdog/package.json +3 -3
  95. package/packages/web-api/package.json +2 -2
  96. package/packages/workflow/package.json +2 -2
  97. package/packages/workflow/src/permission/decide.ts +1 -2
  98. package/packages/workflow/src/permission/index.ts +10 -2
  99. package/packages/workflow/src/permission/settings.ts +35 -3
  100. package/packages/background-tasks/extensions/delegate-child.ts +0 -1
  101. package/packages/background-tasks/src/context-parent-snapshot.ts +0 -142
  102. package/packages/background-tasks/src/context-token-budget.ts +0 -903
  103. package/packages/background-tasks/src/context-visible-conversation-v2.ts +0 -551
  104. package/packages/background-tasks/src/delegate/artifacts.ts +0 -487
  105. package/packages/background-tasks/src/delegate/budget.ts +0 -415
  106. package/packages/background-tasks/src/delegate/hook-contract-evidence.json +0 -18
  107. package/packages/background-tasks/src/delegate/hook-contract.ts +0 -154
  108. package/packages/background-tasks/src/delegate/launch.ts +0 -484
  109. package/packages/background-tasks/src/delegate/result-package.ts +0 -459
  110. package/packages/background-tasks/src/delegate/runner.ts +0 -430
  111. package/packages/background-tasks/src/delegate/seed.ts +0 -423
  112. package/packages/background-tasks/src/delegate/types.ts +0 -323
  113. package/packages/background-tasks/src/delegate-child-extension.ts +0 -978
  114. package/packages/background-tasks/src/delegate-extension.ts +0 -654
  115. package/packages/background-tasks/src/fixtures/delegate-context-incident.json +0 -17
  116. package/packages/subagents/agents/delegate.md +0 -14
  117. package/packages/subagents/agents/oracle.md +0 -78
  118. package/packages/subagents/agents/researcher.md +0 -52
  119. package/packages/subagents/agents/reviewer.md +0 -80
  120. package/packages/subagents/agents/scout.md +0 -50
  121. package/packages/subagents/agents/worker.md +0 -59
  122. package/packages/subagents/prompts/council.md +0 -48
  123. package/packages/subagents/prompts/gather-context-and-clarify.md +0 -13
  124. package/packages/subagents/prompts/parallel-cleanup.md +0 -59
  125. package/packages/subagents/prompts/parallel-research.md +0 -50
  126. package/packages/subagents/prompts/parallel-review.md +0 -54
  127. package/packages/subagents/prompts/review-loop.md +0 -43
  128. package/packages/subagents/skills/council-mode/SKILL.md +0 -230
  129. package/packages/subagents/skills/subagents/references/constraints-and-recipes.md +0 -259
  130. package/packages/subagents/skills/subagents/references/execution-controls.md +0 -454
  131. package/packages/subagents/skills/subagents/references/management-authoring-rpc.md +0 -161
  132. package/packages/subagents/skills/subagents/references/multi-lane-orchestration.md +0 -39
  133. package/packages/subagents/skills/subagents/references/prompting-and-roles.md +0 -267
  134. package/packages/subagents/src/acceptance.ts +0 -331
  135. package/packages/subagents/src/agent-manager.ts +0 -405
  136. package/packages/subagents/src/agent-memory.ts +0 -300
  137. package/packages/subagents/src/agent-overrides.ts +0 -183
  138. package/packages/subagents/src/agent-runner.ts +0 -271
  139. package/packages/subagents/src/async-runner.ts +0 -422
  140. package/packages/subagents/src/authority-policy.ts +0 -47
  141. package/packages/subagents/src/budgets.ts +0 -285
  142. package/packages/subagents/src/child-safety.ts +0 -140
  143. package/packages/subagents/src/config.ts +0 -249
  144. package/packages/subagents/src/conversation-viewer.ts +0 -281
  145. package/packages/subagents/src/core-compat.ts +0 -94
  146. package/packages/subagents/src/custom-agents.ts +0 -343
  147. package/packages/subagents/src/file-system-retry.ts +0 -50
  148. package/packages/subagents/src/fleet-data.ts +0 -105
  149. package/packages/subagents/src/fleet-view.ts +0 -322
  150. package/packages/subagents/src/foreground-detach.ts +0 -59
  151. package/packages/subagents/src/fork-context.ts +0 -285
  152. package/packages/subagents/src/global.d.ts +0 -7
  153. package/packages/subagents/src/guide.ts +0 -129
  154. package/packages/subagents/src/mission-state.ts +0 -133
  155. package/packages/subagents/src/mission-store.ts +0 -436
  156. package/packages/subagents/src/output-limits.ts +0 -142
  157. package/packages/subagents/src/parity-types.ts +0 -315
  158. package/packages/subagents/src/pi-args.ts +0 -167
  159. package/packages/subagents/src/result-files.ts +0 -232
  160. package/packages/subagents/src/result-watcher.ts +0 -221
  161. package/packages/subagents/src/retained-children.ts +0 -176
  162. package/packages/subagents/src/run-fanout-budget.ts +0 -356
  163. package/packages/subagents/src/scheduled-runs.ts +0 -349
  164. package/packages/subagents/src/schemas.ts +0 -263
  165. package/packages/subagents/src/slash-commands.ts +0 -80
  166. package/packages/subagents/src/supervisor-channel.ts +0 -249
  167. package/packages/subagents/src/tool-handler.ts +0 -1144
  168. package/packages/subagents/src/types.ts +0 -238
  169. package/packages/subagents/src/widget.ts +0 -457
  170. package/packages/subagents/src/workflow-script.ts +0 -737
  171. package/packages/subagents/src/workflow-worker.ts +0 -384
  172. package/packages/subagents/src/worktree.ts +0 -614
  173. /package/packages/{subagents/src → core/src/child-agent}/pi-spawn.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -6,6 +6,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.0.0-alpha.3] — 2026-09-27
10
+
11
+ ### Breaking Changes
12
+
13
+ - **BREAKING: `subagents` rebuilt on Devin's model.** `spawn_helper`/`get_helper_result` and `bg_delegate`/`bg_result` are gone, along with workflow scripts, missions, schedules, budgets, acceptance gates, agent memory, worktrees, prompt templates and the bundled agents. **Migration path:** use `run_subagent` (foreground / background / resume) with `subagent_explore` or `subagent_general`, or a custom markdown agent in `~/.unipi/config/agents` / `<project>/.unipi/config/agents` (`/unipi:agents` creates them). `read_subagent` replaces the old result tools. Saved `backgroundTasks.delegate.*` settings are ignored, not deleted.
14
+ - **BREAKING: `btw` is an inline panel.** `/unipi:btw-new`, `-tangent`, `-clear`, `-inject`, `-summarize` and `--save` are removed; each `/unipi:btw` question runs in a fresh read-only session seeded from the main branch. Old btw notes still render.
15
+ - **BREAKING: `/unipi:model` saves the default with Alt+Enter**, not Ctrl+S (which clashed with terminals, VS Code, Zellij and XOFF). The startup model and thinking level are also in `/unipi:settings → Fusion → Startup`.
16
+ - `long-horizon`: default mode is now `none` (the judge still routes); set `longHorizon.defaultMode` to keep the old behaviour.
17
+ - `workflow`: the all-projects permission mode moved to its own `permission.defaultMode` key (migrated once from a legacy global `mode`).
18
+
19
+ ### Added
20
+
21
+ - **subagents: Devin-parity screens.** Live foreground card, `N subagents (k running) · ↓ select` strip, ↓ opens a dock (view transcript, `f` foreground, `x` cancel), Ctrl+B backgrounds and Esc cancels a foreground run, state survives resume. Settings hub: default model, thinking, max running, "Manage agents…".
22
+ - **fusion: Devin-parity sidekick.** Steps stream into the chat, blocking handoffs forward approvals to you, background handoffs deny them; the sidekick runs the lead's extensions. Fusion's lead policy and long-horizon's mode block are named system-prompt sections (long-horizon used to drop the lead policy).
23
+ - **kanboard:** task strategies (none/goal/ralph/swarm/graph) and plan-first labels, board default strategy `auto` (jev picks), blocking policy `avoid` (agents note assumptions instead of blocking), grouped board settings dialog written through to the extension settings, Review lane "Done all".
24
+ - **TUI:** one visual language from a shared kit in `@pi-unipi/core` — crafted spinner, badges, rails, progress bars. Subagent cards settle to ✓/✗ in place; background notices, `read_subagent` and the dock are badges; memory cards are rails.
25
+ - **Progress bars** for ralph (checklist), kanboard (board) and goal (a user-only side estimate + summary per loop and on `/unipi:goal status`, configurable in Long-Horizon → Progress).
26
+ - **input-shortcuts:** Ctrl+C keeps the cleared input struck through in the transcript (never sent to the model); ↑ restores it.
27
+ - `core`: every unipi command echoes `❭ /cmd args` in the transcript; the settings engine has an optional `onSet` hook.
28
+ - `npm run tui:gallery` — standalone preview of UniPi's TUI designs, spinners and terminal capabilities.
29
+
30
+ ### Fixed
31
+
32
+ - **long-horizon: goal and ralph loops no longer stop after the first turn.** The next-turn message was sent while pi still counted the turn as running and was rejected (`Agent is already processing`); it is now queued as a follow-up.
33
+ - **long-horizon: batched goals no longer stall.** A turn that changed files and then claimed completion counted as no progress when the verifier said not met, so goals that claim after every batch got a generic nudge instead of the verifier's feedback and paused after eight claims.
34
+ - **fusion:** the Fusion row can always be applied — the model cache refreshes on a miss (bridge-registered models were "not available"), stale saved lead/sidekick keys are dropped, and Enter/Tab opens the dropdown for a missing half. Sidekick tools only appear while Fusion is active; the picker is wide again.
35
+ - **settings:** the permission project and default rows no longer open two pickers at once.
36
+ - **kanboard:** the binary lookup prefers a source checkout's dev build over a stale platform package.
37
+ - **memory:** at most one queued save reminder.
38
+
9
39
  ## [3.0.0-alpha.2] — 2026-09-26
10
40
 
11
41
  ### Fixed
package/README.md CHANGED
@@ -41,7 +41,7 @@ pi install npm:@pi-unipi/unipi
41
41
 
42
42
  **[Footer](./packages/footer/README.md)** — Persistent status bar showing live stats from every package. Now with the Glance footer: a framed input box with an animated rainbow brand, git branch title, and a live session strip (turns, wall/tool time, TTFT, tok/s, cache hit). Responsive layout, presets, per-segment toggling.
43
43
 
44
- **[BTW](./packages/btw/README.md)** — Side conversations that run in parallel. Ask questions without interrupting the main agent.
44
+ **[BTW](./packages/btw/README.md)** — Inline side questions (`/unipi:btw`) answered by a fresh read-only session seeded from the current context — the main agent never sees them.
45
45
 
46
46
  **[Ask User](./packages/ask-user/README.md)** — Structured input for decision gates. Single-select, multi-select, freeform. The agent asks instead of guessing.
47
47
 
@@ -96,7 +96,7 @@ Coexists triggers enhance behavior when packages are installed together. Workflo
96
96
  | Notify | `/unipi:notify-` | settings, test, set-tg, set-ntfy |
97
97
  | MCP | `/unipi:mcp-` | add, settings, sync, status |
98
98
  | Web | `/unipi:web-` | settings, cache-clear |
99
- | BTW | `/unipi:btw` | question, btw-new, btw-tangent, btw-inject, btw-summarize |
99
+ | BTW | `/unipi:btw` | question |
100
100
  | Utility | `/unipi:` | env, doctor, status, cleanup, badge-name |
101
101
  | Kanboard | `/unipi:kanboard` | toggle, doctor |
102
102
  | Footer | `/unipi:footer` | toggle, settings |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/unipi",
3
- "version": "3.0.0-alpha.2",
3
+ "version": "3.0.0-alpha.3",
4
4
  "description": "All-in-one extension suite for Pi coding agent",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,6 +29,7 @@
29
29
  "publish:all": "npm publish --workspaces --access public",
30
30
  "test": "npx tsx --test tests/*.test.js packages/memory/tests/*.test.ts && npm test --workspaces --if-present",
31
31
  "typecheck": "npx tsc --noEmit --skipLibCheck",
32
+ "tui:gallery": "npx tsx scripts/tui-gallery/index.ts",
32
33
  "publish:kanboard": "node scripts/publish-kanboard-platforms.mjs"
33
34
  },
34
35
  "files": [
@@ -83,27 +84,27 @@
83
84
  "typebox": "^1.1.38"
84
85
  },
85
86
  "dependencies": {
86
- "@pi-unipi/ask-user": "3.0.0-alpha.2",
87
- "@pi-unipi/background-tasks": "3.0.0-alpha.2",
88
- "@pi-unipi/btw": "3.0.0-alpha.2",
89
- "@pi-unipi/command-enchantment": "3.0.0-alpha.2",
90
- "@pi-unipi/compactor": "3.0.0-alpha.2",
91
- "@pi-unipi/core": "3.0.0-alpha.2",
92
- "@pi-unipi/footer": "3.0.0-alpha.2",
93
- "@pi-unipi/image": "3.0.0-alpha.2",
94
- "@pi-unipi/fusion": "3.0.0-alpha.2",
95
- "@pi-unipi/info-screen": "3.0.0-alpha.2",
96
- "@pi-unipi/input-shortcuts": "3.0.0-alpha.2",
97
- "@pi-unipi/kanboard": "3.0.0-alpha.2",
98
- "@pi-unipi/mcp": "3.0.0-alpha.2",
99
- "@pi-unipi/memory": "3.0.0-alpha.2",
100
- "@pi-unipi/notify": "3.0.0-alpha.2",
101
- "@pi-unipi/skill-registry": "3.0.0-alpha.2",
102
- "@pi-unipi/subagents": "3.0.0-alpha.2",
103
- "@pi-unipi/updater": "3.0.0-alpha.2",
104
- "@pi-unipi/utility": "3.0.0-alpha.2",
105
- "@pi-unipi/web-api": "3.0.0-alpha.2",
106
- "@pi-unipi/workflow": "3.0.0-alpha.2"
87
+ "@pi-unipi/ask-user": "3.0.0-alpha.3",
88
+ "@pi-unipi/background-tasks": "3.0.0-alpha.3",
89
+ "@pi-unipi/btw": "3.0.0-alpha.3",
90
+ "@pi-unipi/command-enchantment": "3.0.0-alpha.3",
91
+ "@pi-unipi/compactor": "3.0.0-alpha.3",
92
+ "@pi-unipi/core": "3.0.0-alpha.3",
93
+ "@pi-unipi/footer": "3.0.0-alpha.3",
94
+ "@pi-unipi/image": "3.0.0-alpha.3",
95
+ "@pi-unipi/fusion": "3.0.0-alpha.3",
96
+ "@pi-unipi/info-screen": "3.0.0-alpha.3",
97
+ "@pi-unipi/input-shortcuts": "3.0.0-alpha.3",
98
+ "@pi-unipi/kanboard": "3.0.0-alpha.3",
99
+ "@pi-unipi/mcp": "3.0.0-alpha.3",
100
+ "@pi-unipi/memory": "3.0.0-alpha.3",
101
+ "@pi-unipi/notify": "3.0.0-alpha.3",
102
+ "@pi-unipi/skill-registry": "3.0.0-alpha.3",
103
+ "@pi-unipi/subagents": "3.0.0-alpha.3",
104
+ "@pi-unipi/updater": "3.0.0-alpha.3",
105
+ "@pi-unipi/utility": "3.0.0-alpha.3",
106
+ "@pi-unipi/web-api": "3.0.0-alpha.3",
107
+ "@pi-unipi/workflow": "3.0.0-alpha.3"
107
108
  },
108
109
  "devDependencies": {
109
110
  "@earendil-works/pi-agent-core": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/ask-user",
3
- "version": "3.0.0-alpha.2",
3
+ "version": "3.0.0-alpha.3",
4
4
  "description": "Structured user input tool for Pi coding agent — single-select, multi-select, freeform",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -40,7 +40,7 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@pi-unipi/core": "3.0.0-alpha.2"
43
+ "@pi-unipi/core": "3.0.0-alpha.3"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@earendil-works/pi-coding-agent": "^0.87.1",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/command-enchantment",
3
- "version": "3.0.0-alpha.2",
3
+ "version": "3.0.0-alpha.3",
4
4
  "description": "Enhanced TUI autocomplete for /unipi:* commands — colored, sorted, and grouped by package",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -58,13 +58,12 @@ export const COMMAND_REGISTRY: Record<string, string> = {
58
58
  "unipi:memory-forget": "memory",
59
59
  "unipi:global-memory-list": "memory",
60
60
 
61
- // btw (6 commands)
61
+ // btw
62
62
  "unipi:btw": "btw",
63
- "unipi:btw-tangent": "btw",
64
- "unipi:btw-new": "btw",
65
- "unipi:btw-clear": "btw",
66
- "unipi:btw-inject": "btw",
67
- "unipi:btw-summarize": "btw",
63
+
64
+ // subagents
65
+ "unipi:subagents": "subagents",
66
+ "unipi:agents": "subagents",
68
67
 
69
68
  // mcp (5 commands)
70
69
  "unipi:mcp-status": "mcp",
@@ -82,10 +81,7 @@ export const COMMAND_REGISTRY: Record<string, string> = {
82
81
  // utility (settings hub)
83
82
  "unipi:settings": "utility",
84
83
 
85
- // subagents (3 commands)
86
- "unipi:subagents-fleet": "subagents",
87
- "unipi:subagents-doctor": "subagents",
88
- "unipi:subagents-guide": "subagents",
84
+ // subagents (no user commands — Devin model)
89
85
 
90
86
  // background-tasks (8 commands)
91
87
  "unipi:bg": "background-tasks",
@@ -150,12 +146,10 @@ export const COMMAND_DESCRIPTIONS: Record<string, string> = {
150
146
  "unipi:memory-forget": "Delete a memory by title",
151
147
  "unipi:global-memory-list": "List all memories across all projects",
152
148
 
153
- "unipi:btw": "Run a parallel side conversation",
154
- "unipi:btw-tangent": "Start a contextless BTW tangent thread",
155
- "unipi:btw-new": "Start a fresh BTW thread with session context",
156
- "unipi:btw-clear": "Dismiss and clear the BTW thread",
157
- "unipi:btw-inject": "Inject the BTW thread into the main agent",
158
- "unipi:btw-summarize": "Summarize and inject the BTW thread",
149
+ "unipi:btw": "Ask a side question in an inline panel (read-only)",
150
+
151
+ "unipi:subagents": "Open the subagent panel (also ↓ from an empty input)",
152
+ "unipi:agents": "Manage subagent profiles — create, edit, copy, delete custom agents",
159
153
 
160
154
  "unipi:mcp-status": "Show MCP server status",
161
155
 
@@ -195,9 +189,6 @@ export const COMMAND_DESCRIPTIONS: Record<string, string> = {
195
189
  "unipi:bg-tasks": "Open the background task manager UI",
196
190
  "unipi:model": "Pick a model or Fusion lead+sidekick pair (Devin-style picker)",
197
191
  "unipi:fusion-stats": "Estimated Fusion savings (sidekick tokens priced at lead rates)",
198
- "unipi:subagents-fleet": "Open the subagents fleet view",
199
- "unipi:subagents-doctor": "Diagnose subagents configuration",
200
- "unipi:subagents-guide": "Show the subagents usage guide",
201
192
  };
202
193
 
203
194
  // ─── Package Display Names ───────────────────────────────────────────
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/background-tasks",
3
- "version": "3.0.0-alpha.2",
3
+ "version": "3.0.0-alpha.3",
4
4
  "description": "Background tasks for UniPi — durable shell jobs and delegated background agents with a footer dock",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@earendil-works/pi-ai": "^0.87.1",
13
- "@pi-unipi/core": "3.0.0-alpha.2",
13
+ "@pi-unipi/core": "3.0.0-alpha.3",
14
14
  "turndown": "^7.2.4"
15
15
  },
16
16
  "devDependencies": {
@@ -27,14 +27,6 @@ export interface BackgroundTasksConfig {
27
27
  maxFinishedTasks: number;
28
28
  /** Output cap in bytes before a task is killed+failed (default 20 MiB). */
29
29
  maxOutputBytes: number;
30
- /** Delegate defaults. */
31
- delegate: {
32
- extensionMode: "isolated" | "ambient";
33
- autoDeliver: "never" | "when_small" | "always";
34
- maxTurns: number;
35
- maxToolCalls: number;
36
- timeoutSeconds: number;
37
- };
38
30
  }
39
31
 
40
32
  export const DEFAULT_CONFIG: BackgroundTasksConfig = {
@@ -44,13 +36,6 @@ export const DEFAULT_CONFIG: BackgroundTasksConfig = {
44
36
  defaultTimeoutSeconds: 0,
45
37
  maxFinishedTasks: 30,
46
38
  maxOutputBytes: 20 * 1024 * 1024,
47
- delegate: {
48
- extensionMode: "isolated",
49
- autoDeliver: "when_small",
50
- maxTurns: 40,
51
- maxToolCalls: 120,
52
- timeoutSeconds: 900,
53
- },
54
39
  };
55
40
 
56
41
  function getGlobalConfigPath(): string {
@@ -144,32 +129,6 @@ export function validateBackgroundTasksConfig(config: unknown): string[] {
144
129
  problems.push("maxOutputBytes must be an integer >= 1024");
145
130
  }
146
131
  }
147
- if (c.delegate !== undefined) {
148
- if (typeof c.delegate !== "object" || c.delegate === null) {
149
- problems.push("delegate must be an object");
150
- } else {
151
- const d = c.delegate as Record<string, unknown>;
152
- if (d.extensionMode !== undefined && d.extensionMode !== "isolated" && d.extensionMode !== "ambient") {
153
- problems.push('delegate.extensionMode must be "isolated" or "ambient"');
154
- }
155
- if (
156
- d.autoDeliver !== undefined &&
157
- d.autoDeliver !== "never" &&
158
- d.autoDeliver !== "when_small" &&
159
- d.autoDeliver !== "always"
160
- ) {
161
- problems.push('delegate.autoDeliver must be "never", "when_small", or "always"');
162
- }
163
- for (const key of ["maxTurns", "maxToolCalls"] as const) {
164
- if (d[key] !== undefined && (typeof d[key] !== "number" || !Number.isInteger(d[key]) || (d[key] as number) < 1)) {
165
- problems.push(`delegate.${key} must be a positive integer`);
166
- }
167
- }
168
- if (d.timeoutSeconds !== undefined && (typeof d.timeoutSeconds !== "number" || !Number.isFinite(d.timeoutSeconds) || (d.timeoutSeconds as number) <= 0)) {
169
- problems.push("delegate.timeoutSeconds must be a positive number");
170
- }
171
- }
172
- }
173
132
  return problems;
174
133
  }
175
134
 
@@ -203,29 +162,6 @@ registerSettings({
203
162
  { key: "maxOutputBytes", type: "number", label: "Output cap bytes", min: 1024, description: "Kill+fail a task past this output size" },
204
163
  ],
205
164
  },
206
- {
207
- title: "Delegate",
208
- fields: [
209
- {
210
- key: "delegate.extensionMode",
211
- type: "enum",
212
- label: "Extension mode",
213
- options: [
214
- { value: "isolated", label: "isolated" },
215
- { value: "ambient", label: "ambient (weakens isolation)" },
216
- ],
217
- },
218
- {
219
- key: "delegate.autoDeliver",
220
- type: "enum",
221
- label: "Auto deliver",
222
- options: ["when_small", "always", "never"],
223
- },
224
- { key: "delegate.maxTurns", type: "number", label: "Max turns", min: 1 },
225
- { key: "delegate.maxToolCalls", type: "number", label: "Max tool calls", min: 1 },
226
- { key: "delegate.timeoutSeconds", type: "number", label: "Timeout s", min: 1 },
227
- ],
228
- },
229
165
  ],
230
166
  });
231
167
 
@@ -278,15 +214,6 @@ export function loadBackgroundTasksConfig(cwd: string): LoadedBackgroundTasksCon
278
214
  typeof merged.maxOutputBytes === "number" && Number.isInteger(merged.maxOutputBytes) && merged.maxOutputBytes >= 1024
279
215
  ? merged.maxOutputBytes
280
216
  : DEFAULT_CONFIG.maxOutputBytes,
281
- delegate: {
282
- ...DEFAULT_CONFIG.delegate,
283
- ...merged.delegate,
284
- extensionMode: merged.delegate?.extensionMode === "ambient" ? "ambient" : "isolated",
285
- autoDeliver:
286
- merged.delegate?.autoDeliver === "never" || merged.delegate?.autoDeliver === "always"
287
- ? merged.delegate.autoDeliver
288
- : "when_small",
289
- },
290
217
  };
291
218
  return { config, warnings };
292
219
  }
@@ -18,7 +18,6 @@ import {
18
18
  type BackgroundTaskExtensionService,
19
19
  } from "./extension-api.js";
20
20
  import { registerToolsAndCommands } from "./tools.js";
21
- import { registerDelegateExtension } from "./delegate-extension.js";
22
21
  import { setSharedTaskRegistry, clearSharedTaskRegistry } from "./registry-shared.js";
23
22
  import { formatDuration, taskDisplayName, type BgTask, type StartTaskOptions } from "./types.js";
24
23
 
@@ -205,11 +204,6 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
205
204
  return result;
206
205
  },
207
206
  rerunTask: async (task) => {
208
- if (task.delegate !== undefined) {
209
- throw new Error(
210
- "Only shell-command tasks can be rerun from the dock; relaunch this typed workflow through its owning tool.",
211
- );
212
- }
213
207
  const rerunOptions: StartTaskOptions = {
214
208
  name: taskDisplayName(task),
215
209
  isAgent: task.isAgent,
@@ -261,15 +255,6 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
261
255
  clearFinishedNotices,
262
256
  });
263
257
 
264
- registerDelegateExtension(pi, {
265
- startDelegateTask: async (ctx, options) => {
266
- currentCtx = ctx;
267
- return registry.startDelegateTask(ctx, options);
268
- },
269
- snapshot: (task) => registry.snapshot(task),
270
- resolveTask: (idOrPrefix) => registry.resolveTask(idOrPrefix),
271
- });
272
-
273
258
  pi.on("session_start", async (_event, ctx) => {
274
259
  registry.setShuttingDown(false);
275
260
  wakeLineInstalled = false; // pi clears extension widgets on reload/new session
@@ -27,7 +27,6 @@ import {
27
27
  type BgTaskSnapshot,
28
28
  type JsonObject,
29
29
  type KillKind,
30
- type StartDelegateTaskOptions,
31
30
  type StartTaskOptions,
32
31
  type TaskContextUsage,
33
32
  type TaskStatus,
@@ -637,31 +636,6 @@ function noopOnChange(): void {
637
636
  return undefined;
638
637
  }
639
638
 
640
- /**
641
- * Deliver the delegate prompt bytes over stdin.
642
- *
643
- * A failure to deliver the seed is loud: the caller terminates the task rather
644
- * than letting a child run without the context it was supposed to receive.
645
- */
646
- function writeDelegateStdin(
647
- child: BackgroundTaskChildProcess,
648
- bytes: Buffer,
649
- onError: (error: Error) => void,
650
- ): void {
651
- const stdin = child.stdin;
652
- if (stdin === undefined || stdin === null) {
653
- onError(new Error('delegate child stdin pipe is unavailable'));
654
- return;
655
- }
656
- stdin.once('error', onError);
657
- stdin.write(bytes, (error?: Error | null) => {
658
- if (error !== undefined && error !== null) {
659
- onError(error);
660
- return;
661
- }
662
- stdin.end();
663
- });
664
- }
665
639
 
666
640
  export class BackgroundTaskRegistry {
667
641
  private readonly tasks = new Map<string, BgTask>();
@@ -921,145 +895,6 @@ export class BackgroundTaskRegistry {
921
895
  }
922
896
  }
923
897
 
924
- /**
925
- * Start a prepared delegate child.
926
- *
927
- * The caller has already completed preflight, so by the time this runs the
928
- * seed, budget plan, and artifact directory exist and the argv is fixed. The
929
- * child is launched directly, never through a shell, and its terminal state
930
- * flows through the same durable notification path as `bg_run`.
931
- */
932
- async startDelegateTask(
933
- ctx: BackgroundTaskContext,
934
- request: StartDelegateTaskOptions,
935
- ): Promise<BgTask> {
936
- if (this.shuttingDown)
937
- throw new Error('Cannot start a delegate task while Pi is shutting down');
938
-
939
- const launch = resolvePiLaunch({ platform: this.platform });
940
- assertWindowsCommandLineWithinLimit(launch, request.argv, this.platform, 'bg-delegate');
941
-
942
- const dir = await this.ensureRuntimeDir(ctx);
943
- const id = request.facts.taskId;
944
- const outputAbsPath = join(dir.abs, `${id}.output`);
945
- const metadataAbsPath = join(dir.abs, `${id}.json`);
946
- const outputPath = join(dir.display, `${id}.output`);
947
-
948
- const task: BgTask = {
949
- id,
950
- name: normalizeTaskName(request.name) ?? 'Delegate task',
951
- command: ['pi', ...request.argv].map(shellQuote).join(' '),
952
- status: 'running',
953
- outputPath,
954
- outputAbsPath,
955
- metadataAbsPath,
956
- cwd: ctx.cwd,
957
- startTime: this.now(),
958
- exitCode: undefined,
959
- pid: undefined,
960
- bytesWritten: 0,
961
- isAgent: true,
962
- notified: false,
963
- notifyOnCompletion: request.notifyOnCompletion,
964
- triggerOnCompletion: request.triggerOnCompletion,
965
- timeoutSeconds: request.timeoutSeconds,
966
- model: request.facts.route.qualifiedId,
967
- delegate: request.facts,
968
- waiters: [],
969
- };
970
- this.tasks.set(id, task);
971
-
972
- const stream = createWriteStream(outputAbsPath, { flags: 'a', encoding: 'utf8' });
973
- task.stream = stream;
974
- stream.on('error', (error) => {
975
- task.error = `Output file write failed: ${error.message}`;
976
- });
977
-
978
- try {
979
- const child = this.spawn(launch.executable, piLaunchArgv(launch, [...request.argv]), {
980
- cwd: ctx.cwd,
981
- detached: this.platform !== 'win32',
982
- shell: false,
983
- // The seed travels over stdin, never as a shell or positional argument,
984
- // so the bytes the child reads are exactly the bytes that were persisted
985
- // and hashed, with no quoting or command-line length limit in the path.
986
- stdio: ['pipe', 'pipe', 'pipe'],
987
- env: request.env,
988
- windowsHide: true,
989
- });
990
- task.child = child;
991
- task.pid = child.pid;
992
- writeDelegateStdin(child, request.stdinBytes, (error) => {
993
- this.writeNotice(task, `\n[delegate stdin write failed: ${error.message}]\n`);
994
- if (task.status === 'running') {
995
- task.killKind = 'user';
996
- task.error = `Delegate seed could not be delivered: ${error.message}`;
997
- try {
998
- this.requestKill(task, 'SIGTERM');
999
- } catch {
1000
- void this.finalizeTask(task, 'failed', null, undefined, task.error);
1001
- }
1002
- }
1003
- });
1004
-
1005
- child.stdout?.on('data', (data) => {
1006
- this.appendChildOutput(task, data, 'stdout');
1007
- });
1008
- child.stderr?.on('data', (data) => {
1009
- this.appendChildOutput(task, data, 'stderr');
1010
- });
1011
- child.on('error', (error) => {
1012
- this.writeNotice(task, `\n[delegate spawn error: ${error.message}]\n`);
1013
- void this.finalizeTask(task, 'failed', null, undefined, error.message);
1014
- });
1015
- child.on('close', (code, signalName) => {
1016
- let status: TaskStatus;
1017
- let error: string | undefined;
1018
- if (task.killKind === 'user' || task.killKind === 'shutdown') {
1019
- status = 'killed';
1020
- } else if (task.killKind === 'timeout') {
1021
- status = 'failed';
1022
- error = task.error ?? `Timed out after ${String(request.timeoutSeconds ?? 0)}s`;
1023
- } else if ((code ?? 0) === 0) {
1024
- status = 'completed';
1025
- } else {
1026
- status = 'failed';
1027
- error = `Exited with code ${code === null ? 'null' : String(code)}${signalName ? ` (${signalName})` : ''}`;
1028
- }
1029
- void this.finalizeTask(task, status, code, signalName, error);
1030
- });
1031
-
1032
- if (request.timeoutSeconds !== undefined) {
1033
- task.timeoutHandle = setTimeout(() => {
1034
- if (task.status !== 'running') return;
1035
- task.killKind = 'timeout';
1036
- task.error = `Timed out after ${String(request.timeoutSeconds)}s`;
1037
- this.writeNotice(task, `\n[delegate timeout: ${task.error}]\n`);
1038
- try {
1039
- this.requestKill(task, 'SIGTERM');
1040
- } catch (error) {
1041
- void this.finalizeTask(
1042
- task,
1043
- 'failed',
1044
- null,
1045
- undefined,
1046
- `${task.error}; kill failed: ${error instanceof Error ? error.message : String(error)}`,
1047
- );
1048
- }
1049
- }, request.timeoutSeconds * 1000);
1050
- }
1051
-
1052
- await this.writeMetadata(task);
1053
- this.onChange();
1054
- return task;
1055
- } catch (error) {
1056
- const message = error instanceof Error ? error.message : String(error);
1057
- this.writeNotice(task, `\n[delegate spawn exception: ${message}]\n`);
1058
- await this.finalizeTask(task, 'failed', null, undefined, message);
1059
- throw new Error(`Failed to start delegate task: ${message}`);
1060
- }
1061
- }
1062
-
1063
898
  resolveTask(idOrPrefix: string): BgTask {
1064
899
  const id = idOrPrefix.trim();
1065
900
  if (!id) throw new Error('Task ID is required');
@@ -1816,12 +1651,7 @@ export class BackgroundTaskRegistry {
1816
1651
  task.exitCode === undefined ? '' : `\n <exit-code>${String(task.exitCode)}</exit-code>`;
1817
1652
  const error = task.error ? `\n <error>${escapeXml(task.error)}</error>` : '';
1818
1653
  const taskName = taskDisplayName(task);
1819
- const guidance =
1820
- task.delegate === undefined
1821
- ? 'Terminal state and output metadata are durable. Do not call bg_status to reconfirm; use bg_logs only if output is needed.'
1822
- : task.status === 'completed'
1823
- ? `Delegate result is durably committed. Call bg_result({taskId:${JSON.stringify(task.id)}}) once to retrieve it; do not poll.`
1824
- : `Delegate ended ${task.status}. Inspect the preserved artifacts at ${task.delegate.artifactDir}; do not poll.`;
1654
+ const guidance = 'Terminal state and output metadata are durable. Do not call bg_status to reconfirm; use bg_logs only if output is needed.';
1825
1655
  const content = [
1826
1656
  '<background-task-notification>',
1827
1657
  ` <task-id>${task.id}</task-id>`,
@@ -68,26 +68,10 @@ export interface BgTaskSnapshot {
68
68
  toolUsage?: TaskToolUsage | undefined;
69
69
  model?: string | undefined;
70
70
  telemetryUnavailableReason?: string | undefined;
71
- delegate?: DelegateTaskFacts | undefined;
72
71
  /** Last few non-empty output lines (bounded), for compact chat cards. */
73
72
  outputTail?: string[] | undefined;
74
73
  }
75
74
 
76
- /** Delegate-specific task facts surfaced through snapshots and `bg_result`. */
77
- export interface DelegateTaskFacts {
78
- taskId: string;
79
- launchNonce: string;
80
- artifactDir: string;
81
- artifactDirAbs: string;
82
- seedSha256: string;
83
- childSessionId: string;
84
- route: { provider: string; model: string; qualifiedId: string };
85
- budget: DelegateBudgetRouteSource;
86
- extensionMode: DelegateExtensionMode;
87
- autoDeliver: "never" | "when_small" | "always";
88
- /** Set once the run reaches a terminal state and its result has been evaluated. */
89
- outcome?: DelegateTaskOutcome | undefined;
90
- }
91
75
 
92
76
  export interface DelegateTaskOutcome {
93
77
  status: "committed" | "failed" | "cancelled";
@@ -98,9 +82,6 @@ export interface DelegateTaskOutcome {
98
82
  toolCalls?: number | undefined;
99
83
  }
100
84
 
101
- /** Forward declarations satisfied by ./delegate/types.js (kept here to avoid cycles). */
102
- export type DelegateBudgetRouteSource = import("./delegate/types.js").DelegateBudgetRouteSource;
103
- export type DelegateExtensionMode = import("./delegate/types.js").DelegateExtensionMode;
104
85
 
105
86
  export interface BgTask extends Omit<BgTaskSnapshot, "name"> {
106
87
  name: string;
@@ -129,7 +110,6 @@ export interface BgTask extends Omit<BgTaskSnapshot, "name"> {
129
110
  /** Partial trailing stdout line held between chunks while reconstructing wrapped-agent control lines. */
130
111
  agentStdoutBuffer?: string | undefined;
131
112
  telemetryUnavailableReason?: string | undefined;
132
- delegate?: DelegateTaskFacts | undefined;
133
113
  outputTail?: string[] | undefined;
134
114
  metadataWriteChain?: Promise<void> | undefined;
135
115
  waiters: Array<() => void>;
@@ -227,17 +207,6 @@ export interface StartTaskOptions {
227
207
  terminalPublicationGate?: Promise<void> | undefined;
228
208
  }
229
209
 
230
- export interface StartDelegateTaskOptions {
231
- name: string;
232
- argv: readonly string[];
233
- /** Prompt bytes delivered over stdin, never as a shell or positional argument. */
234
- stdinBytes: Buffer;
235
- env: NodeJS.ProcessEnv;
236
- facts: DelegateTaskFacts;
237
- notifyOnCompletion: boolean;
238
- triggerOnCompletion: boolean;
239
- timeoutSeconds?: number | undefined;
240
- }
241
210
 
242
211
  /** Default tool-output byte cap (mirrors pi's DEFAULT_MAX_BYTES). */
243
212
  export const DEFAULT_MAX_BYTES = 30 * 1024;
@@ -759,7 +728,6 @@ export function snapshot(task: BgTask): BgTaskSnapshot {
759
728
  toolUsage: task.toolUsage,
760
729
  model: task.model,
761
730
  telemetryUnavailableReason: task.telemetryUnavailableReason,
762
- delegate: task.delegate,
763
731
  outputTail: task.outputTail === undefined ? undefined : [...task.outputTail],
764
732
  };
765
733
  }