@esso0428/pi-subagents 0.17.5 → 0.17.7

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 (263) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/CONTRIBUTING.md +4 -0
  3. package/README.md +1 -1
  4. package/dist/abortable.d.ts +13 -0
  5. package/dist/abortable.d.ts.map +1 -0
  6. package/dist/abortable.js +43 -0
  7. package/dist/abortable.js.map +1 -0
  8. package/dist/agent-color.d.ts +36 -0
  9. package/dist/agent-color.d.ts.map +1 -0
  10. package/dist/agent-color.js +124 -0
  11. package/dist/agent-color.js.map +1 -0
  12. package/dist/agent-file-toggle.d.ts +126 -0
  13. package/dist/agent-file-toggle.d.ts.map +1 -0
  14. package/dist/agent-file-toggle.js +259 -0
  15. package/dist/agent-file-toggle.js.map +1 -0
  16. package/dist/agent-history.d.ts +4 -0
  17. package/dist/agent-history.d.ts.map +1 -1
  18. package/dist/agent-history.js +47 -1
  19. package/dist/agent-history.js.map +1 -1
  20. package/dist/agent-manager.d.ts +370 -56
  21. package/dist/agent-manager.d.ts.map +1 -1
  22. package/dist/agent-manager.js +1123 -409
  23. package/dist/agent-manager.js.map +1 -1
  24. package/dist/agent-runner.d.ts +100 -10
  25. package/dist/agent-runner.d.ts.map +1 -1
  26. package/dist/agent-runner.js +166 -21
  27. package/dist/agent-runner.js.map +1 -1
  28. package/dist/agent-types.d.ts +57 -5
  29. package/dist/agent-types.d.ts.map +1 -1
  30. package/dist/agent-types.js +164 -32
  31. package/dist/agent-types.js.map +1 -1
  32. package/dist/child-context.d.ts +3 -0
  33. package/dist/child-context.d.ts.map +1 -0
  34. package/dist/child-context.js +13 -0
  35. package/dist/child-context.js.map +1 -0
  36. package/dist/cross-extension-rpc.d.ts +23 -3
  37. package/dist/cross-extension-rpc.d.ts.map +1 -1
  38. package/dist/cross-extension-rpc.js +79 -17
  39. package/dist/cross-extension-rpc.js.map +1 -1
  40. package/dist/custom-agents.d.ts +38 -1
  41. package/dist/custom-agents.d.ts.map +1 -1
  42. package/dist/custom-agents.js +164 -12
  43. package/dist/custom-agents.js.map +1 -1
  44. package/dist/index.d.ts +34 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +1908 -495
  47. package/dist/index.js.map +1 -1
  48. package/dist/invocation-config.d.ts +87 -2
  49. package/dist/invocation-config.d.ts.map +1 -1
  50. package/dist/invocation-config.js +71 -3
  51. package/dist/invocation-config.js.map +1 -1
  52. package/dist/mention-clone.d.ts +88 -0
  53. package/dist/mention-clone.d.ts.map +1 -0
  54. package/dist/mention-clone.js +154 -0
  55. package/dist/mention-clone.js.map +1 -0
  56. package/dist/mention.d.ts +82 -0
  57. package/dist/mention.d.ts.map +1 -0
  58. package/dist/mention.js +132 -0
  59. package/dist/mention.js.map +1 -0
  60. package/dist/model-resolver.d.ts +17 -0
  61. package/dist/model-resolver.d.ts.map +1 -1
  62. package/dist/model-resolver.js +15 -0
  63. package/dist/model-resolver.js.map +1 -1
  64. package/dist/model-scope.d.ts +50 -0
  65. package/dist/model-scope.d.ts.map +1 -0
  66. package/dist/model-scope.js +49 -0
  67. package/dist/model-scope.js.map +1 -0
  68. package/dist/nested-tools.d.ts +57 -0
  69. package/dist/nested-tools.d.ts.map +1 -0
  70. package/dist/nested-tools.js +301 -0
  71. package/dist/nested-tools.js.map +1 -0
  72. package/dist/output-file.d.ts +22 -3
  73. package/dist/output-file.d.ts.map +1 -1
  74. package/dist/output-file.js +58 -7
  75. package/dist/output-file.js.map +1 -1
  76. package/dist/prompts.d.ts +23 -0
  77. package/dist/prompts.d.ts.map +1 -1
  78. package/dist/prompts.js +20 -2
  79. package/dist/prompts.js.map +1 -1
  80. package/dist/schedule.d.ts.map +1 -1
  81. package/dist/schedule.js +36 -15
  82. package/dist/schedule.js.map +1 -1
  83. package/dist/settings.d.ts +228 -2
  84. package/dist/settings.d.ts.map +1 -1
  85. package/dist/settings.js +94 -0
  86. package/dist/settings.js.map +1 -1
  87. package/dist/status-note.d.ts +49 -1
  88. package/dist/status-note.d.ts.map +1 -1
  89. package/dist/status-note.js +62 -1
  90. package/dist/status-note.js.map +1 -1
  91. package/dist/structured-output.d.ts +62 -0
  92. package/dist/structured-output.d.ts.map +1 -0
  93. package/dist/structured-output.js +113 -0
  94. package/dist/structured-output.js.map +1 -0
  95. package/dist/types.d.ts +176 -10
  96. package/dist/types.d.ts.map +1 -1
  97. package/dist/ui/agent-mention.d.ts +83 -0
  98. package/dist/ui/agent-mention.d.ts.map +1 -0
  99. package/dist/ui/agent-mention.js +188 -0
  100. package/dist/ui/agent-mention.js.map +1 -0
  101. package/dist/ui/agent-widget.d.ts +96 -75
  102. package/dist/ui/agent-widget.d.ts.map +1 -1
  103. package/dist/ui/agent-widget.js +397 -420
  104. package/dist/ui/agent-widget.js.map +1 -1
  105. package/dist/ui/conversation-blocks.d.ts.map +1 -1
  106. package/dist/ui/conversation-blocks.js +6 -0
  107. package/dist/ui/conversation-blocks.js.map +1 -1
  108. package/dist/ui/conversation-timeline.d.ts +10 -2
  109. package/dist/ui/conversation-timeline.d.ts.map +1 -1
  110. package/dist/ui/conversation-timeline.js +130 -23
  111. package/dist/ui/conversation-timeline.js.map +1 -1
  112. package/dist/ui/conversation-viewer.d.ts +20 -5
  113. package/dist/ui/conversation-viewer.d.ts.map +1 -1
  114. package/dist/ui/conversation-viewer.js +274 -73
  115. package/dist/ui/conversation-viewer.js.map +1 -1
  116. package/dist/ui/fleet-list.d.ts +198 -0
  117. package/dist/ui/fleet-list.d.ts.map +1 -0
  118. package/dist/ui/fleet-list.js +487 -0
  119. package/dist/ui/fleet-list.js.map +1 -0
  120. package/dist/ui/schedule-menu.d.ts.map +1 -1
  121. package/dist/ui/schedule-menu.js +6 -7
  122. package/dist/ui/schedule-menu.js.map +1 -1
  123. package/dist/ui/select-item.d.ts +28 -0
  124. package/dist/ui/select-item.d.ts.map +1 -0
  125. package/dist/ui/select-item.js +35 -0
  126. package/dist/ui/select-item.js.map +1 -0
  127. package/dist/ui/workflow-card.d.ts +176 -0
  128. package/dist/ui/workflow-card.d.ts.map +1 -0
  129. package/dist/ui/workflow-card.js +333 -0
  130. package/dist/ui/workflow-card.js.map +1 -0
  131. package/dist/ui/workflow-dialog.d.ts +306 -0
  132. package/dist/ui/workflow-dialog.d.ts.map +1 -0
  133. package/dist/ui/workflow-dialog.js +844 -0
  134. package/dist/ui/workflow-dialog.js.map +1 -0
  135. package/dist/ui/workflow-menu.d.ts +61 -0
  136. package/dist/ui/workflow-menu.d.ts.map +1 -0
  137. package/dist/ui/workflow-menu.js +148 -0
  138. package/dist/ui/workflow-menu.js.map +1 -0
  139. package/dist/usage.d.ts +86 -1
  140. package/dist/usage.d.ts.map +1 -1
  141. package/dist/usage.js +72 -1
  142. package/dist/usage.js.map +1 -1
  143. package/dist/workflow/collisions.d.ts +96 -0
  144. package/dist/workflow/collisions.d.ts.map +1 -0
  145. package/dist/workflow/collisions.js +89 -0
  146. package/dist/workflow/collisions.js.map +1 -0
  147. package/dist/workflow/entry.d.ts +33 -0
  148. package/dist/workflow/entry.d.ts.map +1 -0
  149. package/dist/workflow/entry.js +30 -0
  150. package/dist/workflow/entry.js.map +1 -0
  151. package/dist/workflow/host.d.ts +63 -0
  152. package/dist/workflow/host.d.ts.map +1 -0
  153. package/dist/workflow/host.js +363 -0
  154. package/dist/workflow/host.js.map +1 -0
  155. package/dist/workflow/journal.d.ts +98 -0
  156. package/dist/workflow/journal.d.ts.map +1 -0
  157. package/dist/workflow/journal.js +121 -0
  158. package/dist/workflow/journal.js.map +1 -0
  159. package/dist/workflow/json-schema.d.ts +52 -0
  160. package/dist/workflow/json-schema.d.ts.map +1 -0
  161. package/dist/workflow/json-schema.js +112 -0
  162. package/dist/workflow/json-schema.js.map +1 -0
  163. package/dist/workflow/meta.d.ts +68 -0
  164. package/dist/workflow/meta.d.ts.map +1 -0
  165. package/dist/workflow/meta.js +318 -0
  166. package/dist/workflow/meta.js.map +1 -0
  167. package/dist/workflow/progress.d.ts +225 -0
  168. package/dist/workflow/progress.d.ts.map +1 -0
  169. package/dist/workflow/progress.js +362 -0
  170. package/dist/workflow/progress.js.map +1 -0
  171. package/dist/workflow/runtime.d.ts +335 -0
  172. package/dist/workflow/runtime.d.ts.map +1 -0
  173. package/dist/workflow/runtime.js +831 -0
  174. package/dist/workflow/runtime.js.map +1 -0
  175. package/dist/workflow/saved.d.ts +91 -0
  176. package/dist/workflow/saved.d.ts.map +1 -0
  177. package/dist/workflow/saved.js +204 -0
  178. package/dist/workflow/saved.js.map +1 -0
  179. package/dist/workflow/task.d.ts +137 -0
  180. package/dist/workflow/task.d.ts.map +1 -0
  181. package/dist/workflow/task.js +208 -0
  182. package/dist/workflow/task.js.map +1 -0
  183. package/dist/workflow/tool-description.d.ts +39 -0
  184. package/dist/workflow/tool-description.d.ts.map +1 -0
  185. package/dist/workflow/tool-description.js +200 -0
  186. package/dist/workflow/tool-description.js.map +1 -0
  187. package/dist/workflow/worker-source.d.ts +48 -0
  188. package/dist/workflow/worker-source.d.ts.map +1 -0
  189. package/dist/workflow/worker-source.js +779 -0
  190. package/dist/workflow/worker-source.js.map +1 -0
  191. package/dist/worktree.d.ts +10 -3
  192. package/dist/worktree.d.ts.map +1 -1
  193. package/dist/worktree.js +58 -54
  194. package/dist/worktree.js.map +1 -1
  195. package/dist/xml.d.ts +11 -0
  196. package/dist/xml.d.ts.map +1 -0
  197. package/dist/xml.js +13 -0
  198. package/dist/xml.js.map +1 -0
  199. package/docs/rpc.md +183 -0
  200. package/docs/superpowers/plans/2026-09-30-conversation-viewer-scrollbar.md +216 -0
  201. package/docs/superpowers/plans/2026-09-30-upstream-event-workflow-partial-history.md +195 -0
  202. package/docs/superpowers/specs/2026-09-30-conversation-viewer-scrollbar-design.md +82 -0
  203. package/docs/superpowers/specs/2026-09-30-upstream-event-workflow-partial-history-design.md +49 -0
  204. package/docs/workflows.md +437 -0
  205. package/examples/agent-tool-description.md +7 -7
  206. package/examples/workflows/compose.js +51 -0
  207. package/examples/workflows/fan-out-audit.js +47 -0
  208. package/examples/workflows/gated-fix.js +60 -0
  209. package/examples/workflows/lib/count-child.js +27 -0
  210. package/examples/workflows/review-panel.js +63 -0
  211. package/examples/workflows/structured-findings.js +78 -0
  212. package/package.json +1 -1
  213. package/src/abortable.ts +43 -0
  214. package/src/agent-color.ts +161 -0
  215. package/src/agent-file-toggle.ts +269 -0
  216. package/src/agent-history.ts +54 -2
  217. package/src/agent-manager.ts +1263 -402
  218. package/src/agent-runner.ts +251 -27
  219. package/src/agent-types.ts +188 -32
  220. package/src/child-context.ts +15 -0
  221. package/src/cross-extension-rpc.ts +96 -20
  222. package/src/custom-agents.ts +170 -13
  223. package/src/index.ts +2024 -537
  224. package/src/invocation-config.ts +118 -3
  225. package/src/mention-clone.ts +196 -0
  226. package/src/mention.ts +141 -0
  227. package/src/model-resolver.ts +18 -0
  228. package/src/model-scope.ts +70 -0
  229. package/src/nested-tools.ts +424 -0
  230. package/src/output-file.ts +61 -6
  231. package/src/prompts.ts +45 -2
  232. package/src/schedule.ts +35 -14
  233. package/src/settings.ts +312 -2
  234. package/src/status-note.ts +66 -1
  235. package/src/structured-output.ts +130 -0
  236. package/src/types.ts +177 -10
  237. package/src/ui/agent-mention.ts +216 -0
  238. package/src/ui/agent-widget.ts +389 -441
  239. package/src/ui/conversation-blocks.ts +6 -0
  240. package/src/ui/conversation-timeline.ts +139 -25
  241. package/src/ui/conversation-viewer.ts +284 -69
  242. package/src/ui/fleet-list.ts +558 -0
  243. package/src/ui/schedule-menu.ts +9 -8
  244. package/src/ui/select-item.ts +45 -0
  245. package/src/ui/workflow-card.ts +470 -0
  246. package/src/ui/workflow-dialog.ts +1115 -0
  247. package/src/ui/workflow-menu.ts +193 -0
  248. package/src/usage.ts +109 -2
  249. package/src/workflow/collisions.ts +123 -0
  250. package/src/workflow/entry.ts +47 -0
  251. package/src/workflow/host.ts +403 -0
  252. package/src/workflow/journal.ts +164 -0
  253. package/src/workflow/json-schema.ts +128 -0
  254. package/src/workflow/meta.ts +325 -0
  255. package/src/workflow/progress.ts +550 -0
  256. package/src/workflow/runtime.ts +1219 -0
  257. package/src/workflow/saved.ts +217 -0
  258. package/src/workflow/task.ts +302 -0
  259. package/src/workflow/tool-description.ts +200 -0
  260. package/src/workflow/worker-source.ts +781 -0
  261. package/src/worktree.ts +69 -55
  262. package/src/xml.ts +13 -0
  263. package/vitest.config.ts +0 -18
@@ -0,0 +1,216 @@
1
+ # Conversation Viewer Scrollbar Implementation Plan
2
+
3
+ > [!NOTE]
4
+ > **For agentic workers:** `subagent-driven-development` and
5
+ > `executing-plans` are optional execution helpers. When resolving either
6
+ > skill, prefer the namespaced form (`superpowers:<skill-name>`) when
7
+ > available, then the bare `<skill-name>` form.
8
+ >
9
+ > This name-resolution order does not give those skills priority over the
10
+ > current agent or host framework's native execution/delegation policy.
11
+ >
12
+ > Steps use checkbox (`- [ ]`) syntax for tracking.
13
+
14
+ **Goal:** 在主 `ConversationViewer` transcript viewport 加入與 Tool Output 一致的右側 track/thumb scrollbar,同時保留現有鍵盤、wheel、focus、search 與 read-only 行為。
15
+
16
+ **Architecture:** 重用 `conversation-viewer.ts` 既有的 `renderScrollbarCell()`,只在 transcript content rows 預留最右一格 rail;header、invocation、分隔線、composer/search、footer 不加入 rail。沿用現有 `scrollOffset`、`viewportHeight()` 與 `autoScroll`,不引入第二個 viewport 狀態,也不改用原生 `ScrollView`。
17
+
18
+ **Tech Stack:** TypeScript、`@earendil-works/pi-tui`、Vitest、Biome、TypeScript compiler。
19
+
20
+ ## Global Constraints
21
+
22
+ - 只修改 `/tmp/pi-canonical/pi-subagents-work` canonical checkout,不修改 npm-installed copy 或研究專案根目錄。
23
+ - Scrollbar 只提供視覺 track/thumb;不新增 mouse click-to-jump 或 drag-to-scroll。
24
+ - 保留 `j/k`、方向鍵、PageUp/PageDown、Home/End、wheel、`g/G`、search match、message/tool focus 的既有語意。
25
+ - 保留 ConversationViewer header 的 `[preview] [Esc]` actions;`[preview]` 與 `w` 必須呼叫同一個 focused-tool preview handler,且 action hit-test 不得重疊。
26
+ - Tool Preview 維持 parent-owned in-place preview 與既有 scrollbar,不與主 viewer rail 共用 offset。
27
+ - 不新增跨 package renderer dependency,不改變 transcript read-only 性質。
28
+ - 新增或改寫的測試必須使用 local `vitest`;不能以全域 binary 或 npm-installed package 取代 canonical repo 驗證。
29
+ - 完成後執行 targeted viewer test、`npm test`、`npm run lint`、`npm run typecheck`、`npm run build`、`npm run test:e2e` 與 `npm pack --dry-run`。
30
+
31
+ ---
32
+
33
+ ### Task 1: Add failing ConversationViewer scrollbar tests
34
+
35
+ **Files:**
36
+ - Modify: `test/ui/conversation-viewer.test.ts`
37
+
38
+ **Interfaces:**
39
+ - Consumes: current `ConversationViewer`, `createStaticConversationSource`, `tui()`, `record()` and test `theme` helpers.
40
+ - Produces: regression coverage for the main transcript rail that Task 2 must satisfy.
41
+
42
+ - [ ] **Step 1: Add a long-transcript fixture and rail assertions**
43
+
44
+ Use a transcript longer than the current test TUI viewport:
45
+
46
+ ```ts
47
+ const longText = Array.from({ length: 80 }, (_, index) => `line ${index + 1}`).join("\n");
48
+ const viewer = new ConversationViewer(
49
+ tui(),
50
+ createStaticConversationSource([{ role: "assistant", content: [{ type: "text", text: longText }] }] as any),
51
+ record(),
52
+ undefined,
53
+ theme,
54
+ vi.fn(),
55
+ );
56
+
57
+ const atBottom = viewer.render(100);
58
+ expect(atBottom.some((line) => line.includes("┃") || line.includes("█"))).toBe(true);
59
+ ```
60
+
61
+ The test must also assert that a short transcript does not show a thumb:
62
+
63
+ ```ts
64
+ const shortViewer = new ConversationViewer(
65
+ tui(),
66
+ createStaticConversationSource([{ role: "assistant", content: [{ type: "text", text: "short" }] }] as any),
67
+ record(),
68
+ undefined,
69
+ theme,
70
+ vi.fn(),
71
+ );
72
+ expect(shortViewer.render(100).join("\n")).not.toMatch(/[┃█]/u);
73
+ ```
74
+
75
+ - [ ] **Step 2: Add thumb movement coverage**
76
+
77
+ Capture the row containing the thumb before and after jumping to the top:
78
+
79
+ ```ts
80
+ const bottomLines = viewer.render(100);
81
+ const bottomThumb = bottomLines.findIndex((line) => line.includes("┃") || line.includes("█"));
82
+ viewer.handleInput("g");
83
+ const topLines = viewer.render(100);
84
+ const topThumb = topLines.findIndex((line) => line.includes("┃") || line.includes("█"));
85
+ expect(bottomThumb).toBeGreaterThan(topThumb);
86
+ ```
87
+
88
+ Keep the assertion focused on the rail location, not on a particular color escape sequence, because the test theme intentionally strips most color styles.
89
+
90
+ - [ ] **Step 3: Run the focused test and confirm it fails before implementation**
91
+
92
+ Run:
93
+
94
+ ```bash
95
+ cd /tmp/pi-canonical/pi-subagents-work
96
+ npx vitest run test/ui/conversation-viewer.test.ts
97
+ ```
98
+
99
+ Expected: the existing ConversationViewer tests pass, and the new long-transcript rail assertion fails because the main viewer currently has no `┃`/`█` rail. Do not change production code in this step.
100
+
101
+ ---
102
+
103
+ ### Task 2: Render the main transcript scrollbar without changing layout semantics
104
+
105
+ **Files:**
106
+ - Modify: `src/ui/conversation-viewer.ts:32-52, 444-548`
107
+
108
+ **Interfaces:**
109
+ - Consumes: `renderScrollbarCell()`, `scrollOffset`, `autoScroll`, `viewportHeight()`, `buildContentLines()`, and existing `handleMouse()` geometry.
110
+ - Produces: main viewer content rows with a reserved rightmost rail while Tool Preview continues using its own `FullToolPreview` viewport.
111
+
112
+ - [ ] **Step 1: Define the content rail width and preserve outer width**
113
+
114
+ Inside `render(width)`, keep `innerW = width - 4` for the existing frame/header geometry. Define one transcript-width rule and use it at every content-line build site:
115
+
116
+ ```ts
117
+ const transcriptWidth = (innerW: number): number => Math.max(1, innerW - 1);
118
+ const contentWidth = transcriptWidth(innerW);
119
+ ```
120
+
121
+ Use `contentWidth` when building transcript lines and rendering transcript text. Replace existing `buildContentLines(this.lastInnerW || 80)` calls in input/focus/search paths with `buildContentLines(transcriptWidth(this.lastInnerW || 80))`; use `transcriptWidth(innerW)` in mouse handling. Keep `lastInnerW` as the full inner width so header close-button geometry remains unchanged.
122
+
123
+ - [ ] **Step 2: Add a content-row renderer that reserves the rail**
124
+
125
+ Keep the current `row()` helper for header, invocation, separator, composer/search and footer. Add a separate content-row path with this shape:
126
+
127
+ ```ts
128
+ const contentRow = (content: string, lineIndex: number, totalLines: number, viewportHeight: number, offset: number) => {
129
+ const rail = renderScrollbarCell(th, totalLines, viewportHeight, offset, lineIndex, false);
130
+ const text = truncateToWidth(pad(content, contentWidth), contentWidth, "...", true);
131
+ return th.fg("border", "│") + " " + text + rail + " " + th.fg("border", "│");
132
+ };
133
+ ```
134
+
135
+ The implementation may use an equivalent local helper, but the invariant is fixed: one rail cell is outside the transcript text width and the resulting row remains exactly `width` columns wide.
136
+
137
+ - [ ] **Step 3: Apply the rail only to visible transcript rows**
138
+
139
+ Build content lines at `contentWidth`, compute `visibleStart` and `viewportHeight` as before, and render each displayed/blank transcript row through `contentRow`. Pass the relative visible row index to `renderScrollbarCell()` with the existing total line count and `visibleStart` offset. Preserve the sticky role header replacement and all existing focus/search styling before adding the rail.
140
+
141
+ Do not add a rail to the outer header, invocation row, separator, composer/search row, or footer. When `totalLines <= viewportHeight`, `renderScrollbarCell()` must leave the rail visually empty while preserving its width.
142
+
143
+ - [ ] **Step 4: Preserve the `[preview] [Esc]` header actions**
144
+
145
+ Keep the header action geometry separate from the content rail. Render `[preview]` immediately to the left of `[Esc]`, reserve both labels before truncating the agent header title, and route `[preview]` press/click through the same `openFocusedToolPreview()` method used by `w`. With no focused tool, `[preview]` remains a handled no-op and must never trigger close. Add mouse press capture for both actions so release/click cannot fall through to the timeline.
146
+
147
+ - [ ] **Step 5: Keep mouse hit-testing out of the visual rail**
148
+
149
+ In `handleMouse()`, use the same `contentWidth = Math.max(1, innerW - 1)` for content geometry. Preserve wheel scrolling over the viewport, but do not pass click/press/move events from the reserved rail column into `ConversationTimeline`; the rail is visual-only and must not become a focus target. Header `[preview]`/`[Esc]` hit testing continues to use full `innerW`.
150
+
151
+
152
+ - [ ] **Step 6: Run the focused tests and iterate**
153
+
154
+ Run:
155
+
156
+ ```bash
157
+ cd /tmp/pi-canonical/pi-subagents-work
158
+ npx vitest run test/ui/conversation-viewer.test.ts
159
+ ```
160
+
161
+ Expected: all focused tests pass, including the long-transcript rail presence, short-transcript no-thumb, and thumb movement assertions. If the content width or mouse coordinate assumptions fail, fix only the viewer geometry and rerun this focused suite.
162
+
163
+ ---
164
+
165
+ ### Task 3: Verify regression coverage and package gates
166
+
167
+ **Files:**
168
+ - Inspect: `src/ui/conversation-viewer.ts`
169
+ - Inspect: `test/ui/conversation-viewer.test.ts`
170
+ - Inspect: `docs/superpowers/specs/2026-09-30-conversation-viewer-scrollbar-design.md`
171
+
172
+ **Interfaces:**
173
+ - Consumes: the implementation and tests from Tasks 1–2.
174
+ - Produces: passing verification evidence and a clean diff suitable for release review.
175
+
176
+ - [ ] **Step 1: Run the full unit suite**
177
+
178
+ ```bash
179
+ cd /tmp/pi-canonical/pi-subagents-work
180
+ npm test
181
+ ```
182
+
183
+ Expected: all test files pass; skipped tests may remain only where the existing suite intentionally skips live-model coverage.
184
+
185
+ - [ ] **Step 2: Run static checks and build**
186
+
187
+ ```bash
188
+ cd /tmp/pi-canonical/pi-subagents-work
189
+ npm run lint
190
+ npm run typecheck
191
+ npm run build
192
+ ```
193
+
194
+ Expected: Biome reports no errors, TypeScript reports no errors, and `dist/` compiles successfully.
195
+
196
+ - [ ] **Step 3: Run the e2e and package checks**
197
+
198
+ ```bash
199
+ cd /tmp/pi-canonical/pi-subagents-work
200
+ npm run test:e2e
201
+ npm pack --dry-run
202
+ ```
203
+
204
+ Expected: the faux/scripted e2e suite passes, the tarball includes the compiled `dist/ui/conversation-viewer.js`, and no test source is required at runtime.
205
+
206
+ - [ ] **Step 4: Review the final diff and commit**
207
+
208
+ ```bash
209
+ cd /tmp/pi-canonical/pi-subagents-work
210
+ git diff --check
211
+ git status --short
212
+ git add src/ui/conversation-viewer.ts test/ui/conversation-viewer.test.ts docs/superpowers/plans/2026-09-30-conversation-viewer-scrollbar.md
213
+ git commit -m "feat: add conversation viewer scrollbar"
214
+ ```
215
+
216
+ Expected: only the intended viewer source, focused tests, and this implementation plan are included in the feature commit. Do not publish or push this feature unless the user explicitly requests a release after reviewing the verification results.
@@ -0,0 +1,195 @@
1
+ # 上游事件管理、Workflow 與中途歷史實作計畫
2
+
3
+ > [!NOTE]
4
+ > **給 agentic workers:** 本計畫以目前 fork `64bbbb0` 與 `upstream/master` `e955e29` 的實際差異為準。所有步驟使用 checkbox 追蹤;不得刪除 fork 的 durable history/recovery 與 ConversationViewer 特性。
5
+
6
+ **目標:** 接收上游 Workflow、lifecycle/RPC 與 render-cost 改善,同時讓所有子代理 launch path 都留下可重新開啟的 stopped/aborted/partial `.pi-subagents` 歷史。
7
+
8
+ **架構:** 先將上游功能整合進現有 manager/runner/index seam,再把 durable transcript 附掛下沉到 `AgentManager.spawn()`,使 Agent tool、scheduler、RPC、Workflow 共用同一歷史介面。`.output` 僅是可選的外部串流檔;`.pi-subagents` 是 UI/history/checkpoint 的永久資料源。
9
+
10
+ **技術:** TypeScript、pi ExtensionAPI、pi-tui、Vitest、worker-thread Workflow runtime、JSONL transcript、atomic checkpoint。
11
+
12
+ ## 全域限制
13
+
14
+ - 保留套件名稱 `@esso0428/pi-subagents` 與 JSON agent override。
15
+ - 保留 pi peer floor `>=0.80.8`,除非 typecheck 證明不可行且另有相容性處理。
16
+ - `output_transcript: false` 僅停用 temp `.output`,不得停用 `.pi-subagents` durable history。
17
+ - 不刪除 `src/agent-history.ts`、`src/agent-history-list.ts`、`src/agent-recovery.ts`。
18
+ - 不覆蓋 fork 的 ConversationViewer scrollbar、`[preview] [Esc]`、`w` focused-tool preview、in-place Tool Preview。
19
+ - 任何新日期型路徑使用當天 `2026-09-30`。
20
+ - 完成前執行 lint、typecheck、`npm test`、`npm run test:e2e`、build、pack;使用者已明確要求 commit、push、publish。
21
+
22
+ ---
23
+
24
+ ### Task 1:建立上游整合基線
25
+
26
+ **Files:**
27
+ - Modify: `src/agent-manager.ts`, `src/agent-runner.ts`, `src/agent-types.ts`, `src/types.ts`, `src/settings.ts`
28
+ - Modify: `src/index.ts`, `src/cross-extension-rpc.ts`, `src/output-file.ts`, `src/ui/agent-widget.ts`, `src/ui/fleet-list.ts`
29
+ - Add: `src/workflow/*.ts`, `src/ui/workflow-*.ts`, `docs/workflows.md`, `docs/rpc.md`, `examples/workflows/*`
30
+ - Test: upstream workflow/RPC/lifecycle tests selected from `test/workflow-*.test.ts`, `test/rpc-result-consumption.test.ts`, `test/child-session-shutdown.test.ts`
31
+
32
+ **Interfaces:**
33
+ - Consumes: current fork manager/history/UI interfaces and `upstream/master` workflow/runtime/event contracts.
34
+ - Produces: `SubagentWorkflow` registration, workflow host/runtime/task/journal modules, RPC `consume`, lifecycle event ordering, and RPC activity tracking.
35
+
36
+ - [ ] **Step 1: Record the merge inventory.**
37
+
38
+ In `/tmp/pi-canonical/pi-subagents-work`, compare `git diff --name-status 64bbbb0..upstream/master` and group changes into workflow, lifecycle/RPC, UI, package metadata, and deleted history modules. Treat upstream deletions of fork history/recovery as rejected changes.
39
+
40
+ - [ ] **Step 2: Integrate upstream workflow/event files without replacing fork metadata.**
41
+
42
+ Bring in `src/workflow/`, workflow UI, workflow docs/examples, RPC consume/result-consumption changes, session shutdown ordering, scope-model validation, and RPC-spawn activity tracking. Resolve `src/index.ts`, `src/agent-manager.ts`, `src/agent-runner.ts`, `src/types.ts`, `src/settings.ts`, `src/ui/agent-widget.ts`, `src/ui/fleet-list.ts`, and `src/ui/conversation-viewer.ts` manually. Keep `src/nico-overrides.ts` and fork package identity.
43
+
44
+ - [ ] **Step 3: Keep event semantics explicit.**
45
+
46
+ Ensure readiness is emitted only after the extension is bound; normal Agent tool emits `created`, `started`, terminal `completed`/`failed`, compaction emits `compacted`, steering emits `steered`, and shutdown emits `session_shutdown` before child session disposal. RPC-spawned agents must be observable from returned id and must not rely on `created`.
47
+
48
+ - [ ] **Step 4: Run integration-focused tests.**
49
+
50
+ Run:
51
+ ```bash
52
+ npx vitest run test/cross-extension-rpc.test.ts test/rpc-result-consumption.test.ts test/rpc-lifecycle-gating.test.ts test/child-session-shutdown.test.ts test/workflow-tool.test.ts test/workflow-runtime.test.ts test/workflow.e2e.test.ts
53
+ ```
54
+ Expected: all selected tests pass; failures caused by the history/UI seam remain for Tasks 2–3, not hidden by deleting assertions.
55
+
56
+ ---
57
+
58
+ ### Task 2:把 durable partial history 下沉到 manager seam
59
+
60
+ **Files:**
61
+ - Modify: `src/agent-manager.ts`
62
+ - Modify: `src/index.ts`, `src/output-file.ts`
63
+ - Modify: `src/agent-history.ts`, `src/agent-history-list.ts`, `src/agent-recovery.ts`
64
+ - Modify: `src/types.ts`
65
+ - Test: `test/agent-manager-history.test.ts`, `test/agent-history.test.ts`, `test/agent-history-list.test.ts`, `test/agent-recovery.test.ts`, `test/output-file-history.test.ts`, new `test/partial-history-lifecycle.test.ts`
66
+
67
+ **Interfaces:**
68
+ - Consumes: `createAgentHistoryPath`, `agentHistoryLocator`, `writeInitialEntry`, `streamToOutputFile`, `setTranscript`, `checkpoint`, `restoreRecovered`.
69
+ - Produces: every `manager.spawn()` record has a project-local transcript before queue/start; `output_transcript` only controls `.output`; terminal records retain `transcriptPath`.
70
+
71
+ - [ ] **Step 1: Add one manager-owned durable attach operation.**
72
+
73
+ Add a private operation in `AgentManager` that, for a new record, creates `.pi-subagents/agent-transcripts/<safe-id>.jsonl`, writes the initial user entry, assigns `historyFile`/`transcriptPath`, and checkpoints. Make it idempotent so Agent tool callers do not duplicate the initial entry. Invoke it before the external `onSpawned` callback and clean only the checkpoint/record on a failed spawn; do not discard a successfully created transcript.
74
+
75
+ - [ ] **Step 2: Separate `.output` gating from durable history.**
76
+
77
+ Change `attachTranscript()` in `src/index.ts` so `outputTranscript === false` skips only `createOutputFilePath()` and the temp initial entry. It must still use the manager-provided `historyFile` and `transcriptPath`. Keep `streamToOutputFile()` dual-write behavior when `record.outputFile` exists, and ensure no duplicate JSONL entry is written to history.
78
+
79
+ - [ ] **Step 3: Flush before every terminal checkpoint.**
80
+
81
+ In manager stop/abort/queue cancellation, runner completion/error, resume failure, parent abort, and session shutdown paths, call `flushOutput(record)` before `checkpoint(record)`. Preserve status precedence: externally stopped remains `stopped`; hard max-turn interruption becomes `aborted`; provider/length failure becomes `error`; partial assistant text remains in JSONL even when `record.result` is empty.
82
+
83
+ - [ ] **Step 4: Make history visibly partial and reopenable.**
84
+
85
+ Extend `AgentHistoryStatus`/formatting only as needed to label `stopped`, `aborted`, and `error` as terminal partial-capable states. Keep `canOpenAgentHistory()` based on live session or durable locator. In `ConversationViewer`, use the persisted status/read-only source and show a concise status marker in the header/footer without removing `[preview] [Esc]` or existing scrollbar geometry.
86
+
87
+ - [ ] **Step 5: Add path matrix regression tests.**
88
+
89
+ Cover:
90
+ - tool call in progress followed by `manager.abort()`;
91
+ - queued agent cancellation;
92
+ - provider error after an assistant partial delta;
93
+ - max-turn abort/steer;
94
+ - parent signal abort and `abortAll()`;
95
+ - manager restore of running checkpoint as stopped;
96
+ - scheduler and RPC spawn creating `.pi-subagents` history;
97
+ - `output_transcript: false` still retaining durable history;
98
+ - history menu and viewer reopening after live session disposal.
99
+
100
+ Run the focused history/lifecycle tests before proceeding.
101
+
102
+ ---
103
+
104
+ ### Task 3:合併 UI render-cost 與事件刷新防閃動
105
+
106
+ **Files:**
107
+ - Modify: `src/ui/conversation-viewer.ts`
108
+ - Modify: `src/ui/agent-widget.ts`, `src/ui/fleet-list.ts`
109
+ - Test: `test/ui/conversation-viewer.test.ts`, `test/conversation-viewer.test.ts`, `test/agent-widget.test.ts`, `test/fleet-list.test.ts`, `test/perf/render-invariants.perf.test.ts` if integrated
110
+
111
+ **Interfaces:**
112
+ - Consumes: `ConversationTimeline` cache, fork parent-owned `FullToolPreview`, existing deferred/coalesced refresh behavior, upstream `3d91023` render bound.
113
+ - Produces: stable render cost under rapid text/tool events, no nested overlay/input theft, and regression evidence for the original Tool Output failure.
114
+
115
+ - [ ] **Step 1: Port only the upstream render-cost changes.**
116
+
117
+ Inspect upstream `3d91023` and port bounded hidden-tail/truncation and Markdown fallback behavior into the fork's current viewer. Do not replace the fork's scrollbar rail, header action hitboxes, or `openFocusedToolPreview()` path.
118
+
119
+ - [ ] **Step 2: Coalesce live refreshes.**
120
+
121
+ On session event bursts, invalidate only changed timeline/cache state and schedule one `requestRender()` per event-loop turn. Ensure preview mode owns all input/mouse events and returns to the parent viewer without a nested `ctx.ui.custom` overlay.
122
+
123
+ - [ ] **Step 3: Test the event sequence.**
124
+
125
+ Assert that repeated `message_update`/tool activity does not rebuild unchanged rows indefinitely, that the visible scrollbar thumb remains stable, that Tool Output cannot close the underlying subagent panel, and that `Esc`/`q` restore parent focus. Run all focused UI tests.
126
+
127
+ ---
128
+
129
+ ### Task 4:文件、文件說明與相容性整理
130
+
131
+ **Files:**
132
+ - Modify: `README.md`, `CHANGELOG.md`, `AGENTS.md`
133
+ - Modify: `docs/rpc.md`, `docs/workflows.md`
134
+ - Add/modify: `examples/workflows/*`
135
+ - Preserve: `package.json` identity and peer floor unless verification requires a documented change
136
+
137
+ **Interfaces:**
138
+ - Consumes: implemented lifecycle/workflow/history behavior and test evidence.
139
+ - Produces: user-facing documentation that explains event channels, Workflow ownership, durable partial history, and `.output` opt-out distinction.
140
+
141
+ - [ ] **Step 1: Document partial-history guarantees.**
142
+
143
+ State that `.pi-subagents` is always the durable diagnostic/history source, including stopped/aborted/error/partial runs; `output_transcript` controls only the temp `.output` mirror. Document reopenability and status labels.
144
+
145
+ - [ ] **Step 2: Reconcile upstream docs.**
146
+
147
+ Add the upstream RPC/Workflow usage and caveats, including RPC readiness, no `created` guarantee for RPC spawns, workflow-owned hidden children, and journal replay rules. Keep fork branding and JSON override instructions.
148
+
149
+ - [ ] **Step 3: Add Unreleased entries.**
150
+
151
+ Add separate changelog bullets for Workflow/event management, durable partial history, and UI render stability. Do not rewrite released sections.
152
+
153
+ ---
154
+
155
+ ### Task 5:完整驗證、版本、commit、push、publish
156
+
157
+ **Files:**
158
+ - Modify: `package.json`, `package-lock.json`, `CHANGELOG.md`, `README.md` only if release metadata requires it
159
+ - Test: all repository gates
160
+
161
+ - [ ] **Step 1: Run the full local gates from the canonical checkout.**
162
+
163
+ ```bash
164
+ npm run lint
165
+ npm run typecheck
166
+ npm test
167
+ npm run test:e2e
168
+ npm run build
169
+ npm pack --dry-run
170
+ ```
171
+ Fix every failure; do not weaken durable-history, RPC lifecycle, Workflow, or UI regression assertions.
172
+
173
+ - [ ] **Step 2: Select a release version.**
174
+
175
+ Because Workflow and lifecycle management are notable additions, update the package to the next minor version after `0.17.6` only after all gates pass. Move Unreleased entries into that version and create a fresh Unreleased section.
176
+
177
+ - [ ] **Step 3: Commit the complete integration.**
178
+
179
+ ```bash
180
+ git add docs src test README.md CHANGELOG.md package.json package-lock.json AGENTS.md examples
181
+ git commit -m "feat: integrate upstream workflows and durable partial history"
182
+ ```
183
+
184
+ - [ ] **Step 4: Push and publish only after verification.**
185
+
186
+ ```bash
187
+ git push origin master
188
+ npm publish
189
+ ```
190
+ Then independently verify:
191
+ ```bash
192
+ git ls-remote origin refs/heads/master
193
+ npm view @esso0428/pi-subagents version dist-tags.latest
194
+ ```
195
+ Confirm the remote commit and npm version match the committed release.
@@ -0,0 +1,82 @@
1
+ # Conversation Viewer 主內容 scrollbar 設計
2
+
3
+ ## 狀態
4
+
5
+ - 狀態:已取得使用者對推薦方案的批准,等待 spec review
6
+ - 日期:2026-09-30
7
+ - 範圍:`src/ui/conversation-viewer.ts` 與對應 UI tests
8
+
9
+ ## 問題
10
+
11
+ 目前 `ConversationViewer` 的主 transcript 內容可以用 `j/k`、方向鍵、PageUp/PageDown、wheel 與 footer 百分比滾動,但內容列沒有右側 scrollbar。現有 `FullToolPreview` 已有 track/thumb,因此主 viewer 與 Tool Output 的 viewport 視覺契約不一致,使用者也無法快速判斷目前在 transcript 的位置。
12
+
13
+ ## 目標
14
+
15
+ - 在 ConversationViewer 的 transcript content rows 右側提供真正可見的 track/thumb rail。
16
+ - thumb 位置與高度反映完整 transcript 行數、目前 viewport 高度與 `scrollOffset`。
17
+ - 保留現有鍵盤與 wheel 滾動行為,不增加滑鼠拖曳或點擊跳轉。
18
+ - 保留 ConversationViewer header 的 `[preview]` action;它必須與 `w` 使用同一個 focused-tool preview handler,並與 `[Esc]` 保持不重疊。
19
+ - 保留 message/tool focus、search highlight、sticky header、composer、read-only 行為與 Tool Output preview 行為。
20
+ - 內容寬度預留 rail,避免文字覆蓋 scrollbar。
21
+
22
+ ## 非目標
23
+
24
+ - 本次不新增可拖曳 thumb 或點擊 track 跳轉。
25
+ - 本次不改用 Pi 原生 `ScrollView`。
26
+ - 本次不重構 ConversationTimeline 或抽出跨元件 scrollbar package。
27
+ - 不修改 Tool Output preview 已有的 scrollbar 行為。
28
+
29
+ ## 設計
30
+
31
+ ### 渲染幾何
32
+
33
+ `ConversationViewer.render(width)` 維持現有外框、header、invocation row、footer 與 status layout。只在 transcript content viewport 中保留最右一格作 scrollbar rail:
34
+
35
+ 1. 計算原本的 `innerW`。
36
+ 2. 當 content row render 時,將可用文字寬度設為 `innerW - 1`,最右一格固定輸出 rail。
37
+ 3. 以 `cachedLines.length` 作為 `totalLines`,以 `viewportHeight()` 作為 `viewportHeight`,以 `visibleStart` 或 `scrollOffset` 作為目前 offset。
38
+ 4. 使用既有 `renderScrollbarCell()`:沒有 overflow 時輸出 track 空白;有 overflow 時輸出 track `│` 與 thumb `┃`,scrollbar active 時可使用醒目 thumb `█`。
39
+ 5. Header、invocation row、分隔線、composer/search/footer 不消耗 transcript rail,避免改變既有互動區域。
40
+
41
+ content line 的文字、focus rail 與 search highlight 先完成,再將結果放入保留 rail 的寬度;不可讓 `truncateToWidth` 把 scrollbar 覆蓋掉。
42
+
43
+ ### 狀態與滾動
44
+
45
+ 沿用現有 `scrollOffset`、`autoScroll`、`viewportHeight()` 與 `scrollBy()`,不新增第二份 offset。既有的:
46
+
47
+ - `j/k` 與方向鍵
48
+ - PageUp/PageDown
49
+ - Home/End
50
+ - wheel
51
+ - `g/G`
52
+ - search match 跳轉
53
+ - tool/message focus 導航
54
+
55
+ 都繼續更新同一個 offset,render 時由同一個 offset 計算 thumb。自動追蹤最新內容時 thumb 留在底部;使用者向上滾動後則依現有規則停止 auto-follow。
56
+
57
+ ### 互動與事件
58
+
59
+ 本次 scrollbar 是視覺 track/thumb,不是滑鼠控制元件。`ConversationViewer.handleMouse()` 的 wheel 路由維持不變;click/press 仍依現有 timeline 與 header action hit-test 處理,不讓 scrollbar rail 新增意外 focus target。
60
+
61
+ ConversationViewer header 保留兩個 action:`[preview] [Esc]`。`[preview]` 的 click/press geometry 必須固定在 close action 左側,並呼叫與 `w` 相同的 `openFocusedToolPreview()`;沒有 focused tool 時維持 no-op。Scrollbar rail 不得改變 header action 的 hit-test。
62
+
63
+ Tool Preview 開啟時仍由 `FullToolPreview` 完全接管 render/input/mouse,不將主 viewer rail 與 preview rail 混用。
64
+
65
+ ## 測試
66
+
67
+ 在 `test/ui/conversation-viewer.test.ts` 增加或調整測試:
68
+
69
+ 1. 建立超過 viewport 的長 transcript,確認 content row 最右側出現 track/thumb 字元。
70
+ 2. 使用 `j`、PageDown 或 wheel 後重新 render,確認 thumb 位置會改變,且 hidden content 仍可到達。
71
+ 3. 建立不超過 viewport 的短 transcript,確認不顯示 thumb,且既有文字與外框寬度不變。
72
+ 4. 確認 header `[preview]` 仍可見且可 click,並與 `w` 開啟相同的 read-only Tool Output preview;沒有 focused tool 時不會誤觸 close。
73
+ 5. 確認 search、message/tool focus 與 Tool Output preview 仍可正常使用,沒有因 rail 保留而改變快捷鍵或 close 行為。
74
+ 6. 執行 targeted viewer test,再執行完整 unit tests、lint、typecheck、build、e2e 與 pack。
75
+
76
+ ## 驗收條件
77
+
78
+ - 長 transcript 的主 ConversationViewer 右側可見 track/thumb。
79
+ - thumb 隨現有鍵盤或 wheel 滾動正確移動。
80
+ - 短 transcript 不顯示誤導性的 thumb。
81
+ - 所有原有 ConversationViewer 與 Tool Output 行為測試通過。
82
+ - 不新增 nested overlay、不改變 transcript read-only 性質、不引入跨 package renderer dependency。
@@ -0,0 +1,49 @@
1
+ # 上游事件管理、Workflow 與中途歷史設計規格
2
+
3
+ ## 目標
4
+
5
+ 在保留 fork 既有 JSON agent override、ConversationViewer scrollbar、in-place Tool Output preview 與 `.pi-subagents` 本地資料層的前提下,接收上游的 Workflow 與 lifecycle/RPC 事件管理;任何子代理即使被停止、逾時、達到 turn limit、父程序中斷或 session shutdown,都要留下可重新開啟、可解釋的中途歷史。
6
+
7
+ ## 範圍
8
+
9
+ ### 必須接收
10
+
11
+ - 上游 `SubagentWorkflow`:`agent`、`parallel`、`pipeline`、`workflow`、`phase`、`log`、schema/gate、retry/resume、journal、saved workflow、worker-thread sandbox、Workflow UI。
12
+ - 上游 lifecycle/RPC 管理:`subagents:ready`、`created`、`started`、`completed`、`failed`、`steered`、`compacted`、`session_shutdown`,以及 `ping`、`spawn`、`stop`、`consume` reply channels。
13
+ - 上游 RPC spawned agent 的 activity tracking、scopeModels 驗證、completion consume 去重與 shutdown 順序。
14
+ - 上游 ConversationViewer render-cost bound;但不覆蓋 fork 已有的 scrollbar、`[preview] [Esc]`、focused-tool preview 與 in-place overlay 行為。
15
+
16
+ ### 必須保留或強化
17
+
18
+ - `src/agent-history.ts`、`src/agent-history-list.ts`、`src/agent-recovery.ts` 與相關測試不可因上游刪檔而移除。
19
+ - `.pi-subagents/agent-transcripts/<agent-id>.jsonl` 是 UI 與診斷所需的 durable source of truth;`.output` 是可選的 Claude-compatible side transcript。`output_transcript: false` 只能停用 `.output`,不可停用 `.pi-subagents` 歷史。
20
+ - durable transcript 必須涵蓋 Agent tool、foreground/background、scheduler、cross-extension RPC 與 Workflow child 所有 manager spawn path。
21
+ - transcript 必須逐步保存 user prompt、assistant partial text、tool call、tool result/error、steering message、compaction 前後可恢復內容與終止狀態。
22
+ - checkpoint 必須在 spawn/queued、session 建立、turn/compaction、stop/abort/error/completion/shutdown 等關鍵時點更新;重新啟動時 running/queued checkpoint 若有 transcript,一律還原為可開啟的 `stopped` partial record。
23
+ - `/agents` 與 ConversationViewer 必須把 `stopped`、`aborted`、`error`、`steered` 等終止狀態顯示清楚,歷史可重新開啟且 read-only。
24
+
25
+ ## 設計決策
26
+
27
+ 1. **事件管理採上游協定,資料層採 fork durable history。** `pi.events` 只負責 lifecycle/RPC 通知與跨 extension 協調;`.pi-subagents` 保存完整可解釋過程,兩者不互相取代。
28
+ 2. **歷史附掛下沉至 `AgentManager.spawn()`。** 不再只由 Agent tool 的 `attachTranscript()` 建立歷史;manager 在 caller callback 前確保 project-local transcript 已建立並寫入 initial user entry,因此 scheduler、RPC、Workflow child 也不會漏記。
29
+ 3. **輸出與歷史分離。** `record.outputFile` 仍受 `output_transcript` 控制;`record.historyFile`/`record.transcriptPath` 永遠建立(若檔案系統失敗,checkpoint 仍保存 metadata 並以 warning 呈現)。streamer 同時寫入兩個檔案時必須去重。
30
+ 4. **終止狀態不是刪除。** abort/stop 先停止 session、flush transcript、寫 checkpoint,再釋放 live handle;TTL 只釋放 session,不刪除有 `transcriptPath` 的 record。清理與 session shutdown 不得讓已寫入的歷史消失。
31
+ 5. **Workflow child 的生命週期由 Workflow 管理,但 manager 仍是歷史附掛的單一 seam。** Workflow 事件可維持上游的 hidden child 語義;`.pi-subagents` 以 child id 保存每個 worker 的工具與結果,Workflow journal 另外保存 orchestration progress。
32
+ 6. **UI 閃動採上游 render-cost bound 加 fork 的 deferred/coalesced refresh。** 不引入第二個 overlay,也不讓 spinner/timer 直接重建整個 viewer;只在有效 session change 時 invalidate/requestRender,並以 render key/cache 保持穩定行數。
33
+ 7. **套件身份與相容性不盲目照搬。** 保留 `@esso0428/pi-subagents`、JSON override 與 pi `>=0.80.8` peer floor;只在 typecheck/test 證明 API 必須提高時才調整。
34
+
35
+ ## 驗收條件
36
+
37
+ - upstream Workflow 文件、實作、examples、tests 均可在 fork 中使用,且與 JSON override / existing Agents UI 共存。
38
+ - RPC `consume` 可抑制重複 completion notification;RPC spawn/stop/ready/failed 流程有測試。
39
+ - 各 spawn path 的 `.pi-subagents` transcript 都存在;在 tool call 尚未完成時 stop/abort,重新開啟仍可看到 prompt、tool call、tool result/error 與 partial assistant output。
40
+ - turn limit、provider failure、父 signal abort、session shutdown、SIGKILL 後的 checkpoint restore 都標成 stopped/aborted/error/partial,而不是消失或誤報 completed。
41
+ - ConversationViewer 仍保有 scrollbar rail、`[preview] [Esc]`、`w` 同一路徑與 in-place Tool Preview,並有 render cost regression coverage。
42
+ - 通過 lint、typecheck、完整 unit、E2E、build、pack;版本更新、commit、push、publish 後以 GitHub 與 npm 狀態獨立確認。
43
+
44
+ ## 不在本次範圍
45
+
46
+ - 不刪除 fork 的 durable history/recovery 模組來追上游檔案布局。
47
+ - 不把上游 package name、作者、README branding 或 peer floor 直接覆蓋到 fork。
48
+ - 不以「有 output transcript」替代 `.pi-subagents` durable history。
49
+ - 不把 UI flicker 宣稱為上游已完全解決;上游 0.19.0 的 3d91023 是 render cost bound,仍需以 fork regression test 驗證實際事件序列。