@huseynsnmz/pi-board 0.15.3 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/CHANGELOG.md +24 -4
  2. package/CONTRIBUTING.md +7 -0
  3. package/README.md +55 -419
  4. package/SECURITY.md +19 -0
  5. package/docs/how-it-works.md +31 -0
  6. package/docs/reference.md +277 -0
  7. package/package.json +5 -11
  8. package/src/commands/agent-board.ts +26 -2
  9. package/src/commands/attach-flow.ts +4 -0
  10. package/src/core/double-press.mjs +6 -2
  11. package/src/core/slash-commands.mjs +52 -0
  12. package/src/index.ts +1 -1
  13. package/src/runtime/service.mjs +12 -0
  14. package/src/ui/dashboard.ts +59 -25
  15. package/src/ui/pty-attach.ts +8 -3
  16. package/IMPLEMENTATION_PLAN.md +0 -920
  17. package/PRD.md +0 -484
  18. package/PROGRESS.md +0 -142
  19. package/VERIFY.md +0 -115
  20. package/docs/BATCH_SELECTION_READ_FLOW.md +0 -277
  21. package/docs/EXPLORATION.md +0 -187
  22. package/docs/PTY_ATTACH_IMPLEMENTATION_PLAN.md +0 -581
  23. package/docs/RELEASE.md +0 -148
  24. package/docs/superpowers/plans/2026-08-15-screenlog-gc.md +0 -704
  25. package/docs/superpowers/plans/2026-08-16-attach-double-cursor-jiggle-retry.md +0 -499
  26. package/docs/superpowers/plans/2026-08-21-attach-coldstart-jiggle-rearm.md +0 -797
  27. package/docs/superpowers/plans/2026-08-21-dashboard-keypress-lag.md +0 -366
  28. package/docs/superpowers/plans/2026-08-21-issue-14-needs-input-no-auto-done.md +0 -576
  29. package/docs/superpowers/plans/2026-08-22-jiggle-shrink-and-hold.md +0 -337
  30. package/docs/superpowers/plans/2026-08-22-launch-cwd-favorites.md +0 -916
  31. package/docs/superpowers/plans/2026-08-22-question-tool-grouping.md +0 -211
  32. package/docs/superpowers/plans/2026-08-22-rename-state-labels.md +0 -182
  33. package/docs/superpowers/plans/2026-08-22-stable-list-order.md +0 -51
  34. package/docs/superpowers/plans/2026-08-27-locks-acquirelock-spin.md +0 -614
  35. package/docs/superpowers/plans/2026-08-27-pty-runner-test-flaky.md +0 -32
  36. package/docs/superpowers/plans/2026-08-29-code-refs-badges.md +0 -223
  37. package/docs/superpowers/plans/2026-08-30-circular-navigation.md +0 -308
  38. package/docs/superpowers/plans/2026-08-30-post-exit-timing-fix.md +0 -37
  39. package/docs/superpowers/plans/2026-08-30-pty-attach-quality-debt.md +0 -311
  40. package/docs/superpowers/plans/2026-08-30-readme-v2.md +0 -294
  41. package/docs/superpowers/plans/2026-09-01-attach-detach-gate-cursor-anchor.md +0 -284
  42. package/docs/superpowers/plans/2026-09-02-attach-detach-editor-state.md +0 -722
  43. package/docs/superpowers/plans/2026-09-03-code-refs-pr-backlink-narrow.md +0 -551
  44. package/docs/superpowers/plans/2026-09-03-detach-gate-glyph-fallback.md +0 -146
  45. package/docs/superpowers/plans/2026-09-04-evidence-outputpreview.md +0 -209
  46. package/docs/superpowers/plans/2026-09-04-warm-host-reclaim.md +0 -796
  47. package/docs/superpowers/plans/2026-09-05-issue-13-drainnextfollowup-pty-probe.md +0 -114
  48. package/docs/superpowers/plans/2026-09-05-issue-38-windows-wezterm-ime-cursor.md +0 -73
  49. package/docs/superpowers/plans/2026-09-05-issue-39-truncate-codepoint-boundary.md +0 -143
  50. package/docs/superpowers/plans/2026-09-05-issue-61-mention-fallback-guards.md +0 -226
  51. package/docs/superpowers/plans/2026-09-05-issue-63-flaky-manual-completion.md +0 -87
  52. package/docs/superpowers/plans/2026-09-05-issue-64-changelog-release-helper.md +0 -53
  53. package/docs/superpowers/plans/2026-09-05-pty-host-stacking-sock-race.md +0 -731
  54. package/docs/superpowers/plans/2026-09-08-attach-ctrl-left-detach.md +0 -30
  55. package/docs/superpowers/plans/2026-09-08-dashboard-shrink-repaint.md +0 -68
  56. package/docs/superpowers/plans/2026-09-08-issue-11-attach-runtime-desync-heal.md +0 -917
  57. package/docs/superpowers/plans/2026-09-08-legacy-stale-host-recovery.md +0 -125
  58. package/docs/superpowers/plans/2026-09-08-spawn-async-error-swallow.md +0 -56
  59. package/docs/superpowers/plans/2026-09-08-stale-model-attach-guard.md +0 -96
  60. package/docs/superpowers/plans/2026-09-09-claimpid-blocks-replace.md +0 -267
  61. package/docs/superpowers/plans/2026-09-09-harden-runner-architecture.md +0 -603
  62. package/docs/superpowers/plans/2026-09-09-single-writer-completion.md +0 -252
  63. package/docs/superpowers/plans/2026-09-10-reader-consistency.md +0 -115
  64. package/docs/superpowers/plans/2026-09-14-attach-cursor-dectcem-gate.md +0 -469
  65. package/docs/superpowers/plans/2026-09-14-attach-snapshot.md +0 -92
  66. package/docs/superpowers/plans/2026-09-14-host-meta-orphan-lock.md +0 -771
  67. package/docs/superpowers/plans/2026-09-14-issue-106-terminal-frame-cognition.md +0 -299
  68. package/docs/superpowers/plans/2026-09-14-issue-113-foreground-preview-race.md +0 -609
  69. package/docs/superpowers/plans/2026-09-14-terminal-model.md +0 -145
  70. package/docs/superpowers/plans/2026-09-15-coordinator-pipe-root-normalize.md +0 -224
  71. package/docs/superpowers/plans/2026-09-15-lease-publish-eprem-reclaim.md +0 -341
  72. package/docs/superpowers/plans/2026-09-18-detach-anchor-reporter-endpoint.md +0 -875
  73. package/docs/superpowers/plans/2026-09-20-control-lifecycle.md +0 -116
  74. package/docs/superpowers/plans/2026-09-20-issue-121-perf-gate-out-of-coverage.md +0 -517
  75. package/docs/superpowers/plans/2026-09-23-a5-mid-stream-assertion.md +0 -25
  76. package/docs/superpowers/plans/2026-09-23-cwd-browse-tab-drill.md +0 -393
  77. package/docs/superpowers/plans/2026-09-23-terminal-query-forwarding.md +0 -51
  78. package/docs/superpowers/plans/2026-09-23-unconditional-detach-key.md +0 -58
  79. package/docs/superpowers/plans/2026-09-24-control-reconcile-flake.md +0 -698
  80. package/docs/superpowers/plans/2026-09-24-probe-attached-clients.md +0 -605
  81. package/docs/superpowers/plans/2026-09-29-issue-145-holding-semantic-state.md +0 -1183
  82. package/docs/superpowers/plans/2026-09-29-issue-145-user-verification.md +0 -66
  83. package/docs/superpowers/plans/2026-09-30-board-delete-key-x-y-confirm.md +0 -649
  84. package/docs/superpowers/plans/2026-09-30-issue-153-runner-stop-boot-window.md +0 -618
  85. package/docs/superpowers/plans/2026-09-30-issue-95-test-discipline.md +0 -555
  86. package/docs/superpowers/plans/2026-09-30-publish-dispatch-tag-check.md +0 -259
  87. package/docs/superpowers/plans/2026-10-06-attach-settle-scheme-delivery.md +0 -751
  88. package/docs/superpowers/plans/2026-10-09-issue-167-attach-middle-paste.md +0 -509
  89. package/docs/superpowers/plans/2026-10-09-issue-169-fullscreen-mouse-ownership.md +0 -346
  90. package/docs/superpowers/plans/2026-10-10-attach-delete-in-place.md +0 -832
  91. package/docs/superpowers/plans/2026-10-10-issue-174-selection-mirror-paste-source.md +0 -510
  92. package/docs/superpowers/plans/2026-10-14-issue-170-attach-reply-guard.md +0 -771
  93. package/docs/superpowers/plans/2026-10-14-issue-178-accept-registration-race.md +0 -1257
  94. package/docs/superpowers/plans/2026-10-14-issue-184-snapshot-window-contract.md +0 -657
  95. package/docs/superpowers/plans/2026-10-14-issue-185-attach-wheel-alt-screen.md +0 -47
  96. package/docs/superpowers/plans/2026-10-14-issue-187-motionless-drag.md +0 -931
  97. package/docs/superpowers/plans/2026-10-14-issue-189-mixed-input-segments.md +0 -823
  98. package/docs/superpowers/plans/2026-10-15-issue-188-x10-mouse-release.md +0 -526
  99. package/docs/superpowers/plans/2026-10-16-issue-198-attach-wheel-forward-fallback.md +0 -32
  100. package/docs/superpowers/plans/2026-10-18-attach-wheel-replay-pseudo-scrollback.md +0 -437
  101. package/docs/superpowers/plans/2026-10-19-issue-213-reply-guard-csi-key.md +0 -257
  102. package/docs/superpowers/plans/2026-10-19-issue-214-attach-forward-alt-modifier.md +0 -202
  103. package/docs/superpowers/plans/2026-10-21-issue-221-ask-user-question.md +0 -198
  104. package/docs/superpowers/plans/2026-10-23-issue-222-attach-ready.md +0 -290
  105. package/docs/superpowers/plans/2026-10-23-issue-225-monotonic-foreground-state.md +0 -450
  106. package/docs/superpowers/plans/2026-10-23-issue-229-vim-jkl.md +0 -449
  107. package/docs/superpowers/plans/2026-10-23-issue-232-attach-bg-only-cells.md +0 -153
  108. package/docs/superpowers/plans/2026-10-23-lease-heartbeat-staleness.md +0 -537
  109. package/docs/superpowers/plans/2026-10-23-selected-row-highlight.md +0 -405
  110. package/docs/superpowers/plans/2026-10-24-issue-217-windows-pid-reuse-stopping.md +0 -367
  111. package/docs/superpowers/plans/2026-10-24-issue-230-warm-host-background-runs.md +0 -806
  112. package/docs/superpowers/plans/2026-10-24-issue-238-windows-process-identity-token.md +0 -490
  113. package/docs/superpowers/plans/2026-10-24-issue-241-coordinator-root-exit.md +0 -461
  114. package/docs/superpowers/plans/2026-10-25-issue-239-coordinator-replacement-identity.md +0 -504
  115. package/docs/superpowers/plans/2026-10-26-issue-245-key-hints-doc-sync.md +0 -244
  116. package/docs/superpowers/plans/2026-10-27-issue-172-fullscreen-selection-clear.md +0 -344
  117. package/docs/superpowers/plans/2026-10-27-issue-252-select-key-hints.md +0 -209
  118. package/docs/superpowers/plans/2026-10-28-issue-255-coordinator-endpoint-zombie.md +0 -442
  119. package/docs/superpowers/plans/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup.md +0 -256
  120. package/docs/superpowers/plans/2026-11-03-cwd-favorites-full-pool.md +0 -266
  121. package/docs/superpowers/specs/2026-08-15-screenlog-gc-design.md +0 -105
  122. package/docs/superpowers/specs/2026-08-16-attach-double-cursor-jiggle-retry-design.md +0 -142
  123. package/docs/superpowers/specs/2026-08-21-attach-coldstart-jiggle-rearm-design.md +0 -110
  124. package/docs/superpowers/specs/2026-08-21-dashboard-keypress-lag-design.md +0 -59
  125. package/docs/superpowers/specs/2026-08-21-issue-14-needs-input-no-auto-done-design.md +0 -109
  126. package/docs/superpowers/specs/2026-08-22-cwd-favorites-design.md +0 -131
  127. package/docs/superpowers/specs/2026-08-22-jiggle-shrink-and-hold-design.md +0 -111
  128. package/docs/superpowers/specs/2026-08-22-question-tool-grouping-design.md +0 -114
  129. package/docs/superpowers/specs/2026-08-22-rename-state-labels-design.md +0 -80
  130. package/docs/superpowers/specs/2026-08-27-locks-acquirelock-spin-design.md +0 -97
  131. package/docs/superpowers/specs/2026-08-27-pty-runner-test-flaky-design.md +0 -35
  132. package/docs/superpowers/specs/2026-08-29-code-refs-badges-design.md +0 -128
  133. package/docs/superpowers/specs/2026-08-30-circular-navigation-design.md +0 -47
  134. package/docs/superpowers/specs/2026-08-30-eprm-atomicwrite-race-design.md +0 -77
  135. package/docs/superpowers/specs/2026-08-30-post-exit-timing-fix-design.md +0 -80
  136. package/docs/superpowers/specs/2026-08-30-pty-attach-quality-debt-design.md +0 -105
  137. package/docs/superpowers/specs/2026-08-30-readme-v2-design.md +0 -115
  138. package/docs/superpowers/specs/2026-09-01-attach-detach-gate-cursor-anchor-design.md +0 -78
  139. package/docs/superpowers/specs/2026-09-02-attach-detach-editor-state-design.md +0 -120
  140. package/docs/superpowers/specs/2026-09-03-code-refs-pr-backlink-narrow-design.md +0 -92
  141. package/docs/superpowers/specs/2026-09-03-detach-gate-glyph-fallback-design.md +0 -99
  142. package/docs/superpowers/specs/2026-09-04-evidence-outputpreview-design.md +0 -50
  143. package/docs/superpowers/specs/2026-09-04-warm-host-reclaim-design.md +0 -106
  144. package/docs/superpowers/specs/2026-09-05-issue-13-drainnextfollowup-pty-probe-design.md +0 -64
  145. package/docs/superpowers/specs/2026-09-05-issue-38-windows-wezterm-ime-design.md +0 -48
  146. package/docs/superpowers/specs/2026-09-05-issue-39-truncate-codepoint-boundary-design.md +0 -64
  147. package/docs/superpowers/specs/2026-09-05-issue-61-mention-fallback-design.md +0 -71
  148. package/docs/superpowers/specs/2026-09-05-issue-63-flaky-manual-completion-design.md +0 -49
  149. package/docs/superpowers/specs/2026-09-05-issue-64-changelog-helper-design.md +0 -76
  150. package/docs/superpowers/specs/2026-09-05-pty-host-stacking-sock-race-design.md +0 -510
  151. package/docs/superpowers/specs/2026-09-07-issue-11-attach-runtime-desync-heal-design.md +0 -130
  152. package/docs/superpowers/specs/2026-09-08-attach-ctrl-left-detach-design.md +0 -58
  153. package/docs/superpowers/specs/2026-09-08-dashboard-shrink-repaint-design.md +0 -52
  154. package/docs/superpowers/specs/2026-09-08-legacy-stale-host-recovery-design.md +0 -87
  155. package/docs/superpowers/specs/2026-09-08-spawn-async-error-swallow-design.md +0 -56
  156. package/docs/superpowers/specs/2026-09-08-stale-model-attach-guard-design.md +0 -79
  157. package/docs/superpowers/specs/2026-09-09-claimpid-blocks-replace-design.md +0 -147
  158. package/docs/superpowers/specs/2026-09-09-harden-runner-architecture-design.md +0 -304
  159. package/docs/superpowers/specs/2026-09-14-attach-cursor-dectcem-gate-design.md +0 -114
  160. package/docs/superpowers/specs/2026-09-14-host-meta-orphan-lock-design.md +0 -120
  161. package/docs/superpowers/specs/2026-09-14-issue-106-terminal-frame-cognition-design.md +0 -146
  162. package/docs/superpowers/specs/2026-09-14-issue-113-foreground-preview-race-design.md +0 -116
  163. package/docs/superpowers/specs/2026-09-15-coordinator-pipe-root-normalize-design.md +0 -84
  164. package/docs/superpowers/specs/2026-09-15-lease-publish-eprem-reclaim-design.md +0 -92
  165. package/docs/superpowers/specs/2026-09-18-detach-anchor-reporter-endpoint-design.md +0 -123
  166. package/docs/superpowers/specs/2026-09-20-issue-121-perf-gate-out-of-coverage-design.md +0 -204
  167. package/docs/superpowers/specs/2026-09-23-a5-mid-stream-assertion-design.md +0 -43
  168. package/docs/superpowers/specs/2026-09-23-cwd-browse-tab-drill-design.md +0 -95
  169. package/docs/superpowers/specs/2026-09-23-terminal-query-forwarding-design.md +0 -63
  170. package/docs/superpowers/specs/2026-09-23-unconditional-detach-key-design.md +0 -57
  171. package/docs/superpowers/specs/2026-09-24-control-reconcile-flake-design.md +0 -98
  172. package/docs/superpowers/specs/2026-09-24-probe-attached-clients-design.md +0 -190
  173. package/docs/superpowers/specs/2026-09-29-issue-145-holding-semantic-state-design.md +0 -394
  174. package/docs/superpowers/specs/2026-09-30-board-delete-key-x-y-confirm-design.md +0 -86
  175. package/docs/superpowers/specs/2026-09-30-issue-153-runner-stop-boot-window-design.md +0 -75
  176. package/docs/superpowers/specs/2026-09-30-issue-95-test-discipline-design.md +0 -226
  177. package/docs/superpowers/specs/2026-09-30-publish-dispatch-tag-check-design.md +0 -129
  178. package/docs/superpowers/specs/2026-10-06-attach-settle-scheme-delivery-design.md +0 -196
  179. package/docs/superpowers/specs/2026-10-09-issue-167-attach-middle-paste-design.md +0 -125
  180. package/docs/superpowers/specs/2026-10-09-issue-169-fullscreen-mouse-ownership-design.md +0 -130
  181. package/docs/superpowers/specs/2026-10-10-attach-delete-in-place-design.md +0 -224
  182. package/docs/superpowers/specs/2026-10-10-issue-174-selection-mirror-paste-source-design.md +0 -154
  183. package/docs/superpowers/specs/2026-10-14-issue-170-attach-reply-guard-design.md +0 -195
  184. package/docs/superpowers/specs/2026-10-14-issue-178-accept-registration-race-design.md +0 -287
  185. package/docs/superpowers/specs/2026-10-14-issue-184-snapshot-window-contract-design.md +0 -288
  186. package/docs/superpowers/specs/2026-10-14-issue-185-attach-wheel-alt-screen-design.md +0 -126
  187. package/docs/superpowers/specs/2026-10-14-issue-187-motionless-drag-design.md +0 -269
  188. package/docs/superpowers/specs/2026-10-14-issue-189-mixed-input-segments-design.md +0 -369
  189. package/docs/superpowers/specs/2026-10-15-issue-188-x10-mouse-release-design.md +0 -252
  190. package/docs/superpowers/specs/2026-10-16-issue-198-attach-wheel-forward-fallback-design.md +0 -67
  191. package/docs/superpowers/specs/2026-10-18-attach-wheel-replay-pseudo-scrollback-design.md +0 -250
  192. package/docs/superpowers/specs/2026-10-19-issue-213-reply-guard-csi-key-design.md +0 -165
  193. package/docs/superpowers/specs/2026-10-19-issue-214-attach-forward-alt-modifier-design.md +0 -131
  194. package/docs/superpowers/specs/2026-10-20-issue-221-ask-user-question-design.md +0 -270
  195. package/docs/superpowers/specs/2026-10-22-issue-225-monotonic-foreground-state-design.md +0 -225
  196. package/docs/superpowers/specs/2026-10-23-issue-222-attach-ready-design.md +0 -204
  197. package/docs/superpowers/specs/2026-10-23-issue-229-vim-jkl-design.md +0 -90
  198. package/docs/superpowers/specs/2026-10-23-issue-232-attach-bg-only-cells-design.md +0 -146
  199. package/docs/superpowers/specs/2026-10-23-lease-heartbeat-staleness-design.md +0 -271
  200. package/docs/superpowers/specs/2026-10-23-selected-row-highlight-design.md +0 -191
  201. package/docs/superpowers/specs/2026-10-24-issue-217-windows-pid-reuse-stopping-design.md +0 -334
  202. package/docs/superpowers/specs/2026-10-24-issue-230-warm-host-background-runs-design.md +0 -283
  203. package/docs/superpowers/specs/2026-10-24-issue-238-windows-process-identity-token-design.md +0 -286
  204. package/docs/superpowers/specs/2026-10-24-issue-241-coordinator-root-exit-design.md +0 -381
  205. package/docs/superpowers/specs/2026-10-25-issue-239-coordinator-replacement-identity-design.md +0 -331
  206. package/docs/superpowers/specs/2026-10-26-issue-245-key-hints-doc-sync-design.md +0 -72
  207. package/docs/superpowers/specs/2026-10-27-issue-172-fullscreen-selection-clear-design.md +0 -248
  208. package/docs/superpowers/specs/2026-10-27-issue-252-select-key-hints-design.md +0 -95
  209. package/docs/superpowers/specs/2026-10-28-issue-255-coordinator-endpoint-zombie-design.md +0 -380
  210. package/docs/superpowers/specs/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup-design.md +0 -197
  211. package/docs/superpowers/specs/2026-11-03-cwd-favorites-full-pool-design.md +0 -106
  212. package/scripts/budget-audit.mjs +0 -135
  213. package/scripts/release.mjs +0 -446
  214. package/scripts/release_helper.mjs +0 -309
  215. package/scripts/run-perf-gate.mjs +0 -40
  216. package/scripts/run-tests.mjs +0 -375
@@ -1,581 +0,0 @@
1
- # Implementation Plan: PTY-backed Live Attach
2
-
3
- **Status:** Proposed / spike-ready
4
- **Goal:** make attaching to a live agent-board row feel like attaching to the same normal Pi session, without interrupting the running work.
5
- **Created:** 2026-05-31
6
-
7
- ## 1. Decision
8
-
9
- The previous `SessionClient`/RPC idea is clean, but it will not be 1:1 with normal Pi unless we reimplement or refactor a lot of interactive Pi UI behavior.
10
-
11
- For a 1:1 user experience, invert the design:
12
-
13
- > A background row should be hosted by a real interactive Pi process running inside a PTY. Attach should connect the user to that live PTY, not recreate Pi UI over RPC.
14
-
15
- Current MVP keeps a detached one-shot JSON worker:
16
-
17
- ```text
18
- Dashboard
19
- └─ job-runner.mjs
20
- └─ pi --mode json -p --session <file> <prompt>
21
- ├─ emits JSON events
22
- ├─ writes session file
23
- └─ exits after the prompt finishes
24
- ```
25
-
26
- Target live-attach model:
27
-
28
- ```text
29
- Dashboard
30
- └─ pty-runner.mjs
31
- ├─ control.sock
32
- ├─ host.json
33
- └─ PTY
34
- └─ pi --session <file> <initial prompt>
35
- ├─ real interactive Pi TUI
36
- ├─ real slash commands/keybindings/extensions
37
- ├─ writes same session file
38
- └─ stays alive until explicitly closed
39
- ```
40
-
41
- ## 2. Critical exploration findings
42
-
43
- ### Existing code that helps
44
-
45
- - `src/runtime/service.mjs` already owns dispatch/reply/stop/archive and same-repo worktree safety.
46
- - `runner/job-runner.mjs` already demonstrates detached durable process ownership.
47
- - Store layout under `~/.pi/agent/agent-board/` is sound: `views/<id>/meta.json`, `state.json`, per-run artifacts, session file per row.
48
- - `src/index.ts` already mirrors foreground session events into managed row state via `service.syncForegroundEvent(...)`.
49
- - `src/commands/agent-board.ts` already owns attach and back-to-dashboard behavior.
50
- - `src/ui/dashboard.ts` already has list/peek/reply/session modes and can add a new attach mode/result.
51
-
52
- ### Important mismatch in current state model
53
-
54
- `Row.alive` currently means “the current managed run pid is alive” and is also overloaded for foreground mirrored activity.
55
-
56
- For PTY hosting we need two separate concepts:
57
-
58
- 1. **host liveness** — is the interactive Pi PTY process alive and attachable?
59
- 2. **agent activity** — is the agent currently processing/streaming/tooling?
60
-
61
- A PTY-hosted row can be:
62
-
63
- ```text
64
- host: alive
65
- agent activity: idle/completed/needs_input
66
- ```
67
-
68
- That should still be directly attachable without fallback resume.
69
-
70
- ### Biggest technical caveat
71
-
72
- Pi extension `ctx.ui.custom()` renders line-based components. It does **not** expose a documented raw terminal takeover API.
73
-
74
- Therefore there are three implementation options:
75
-
76
- | Option | Description | 1:1 fidelity | Fits extension-only? | Recommendation |
77
- |---|---|---:|---:|---|
78
- | A | PTY + terminal emulator component (`xterm-headless` style) | high, not perfect | yes | try first |
79
- | B | Pi core raw terminal takeover API | highest | requires Pi core change | later if needed |
80
- | C | standalone/tmux-like external agent-board CLI | highest | separate CLI, not pure `/agent-board` | fallback |
81
-
82
- This plan attempts **Option A** first because it preserves the extension flow and avoids rebuilding the agent protocol/UI. It runs real Pi, captures its PTY output, and renders a virtual terminal buffer inside `ctx.ui.custom()`.
83
-
84
- ## 3. Target architecture
85
-
86
- ```text
87
- ┌──────────────────────────────┐
88
- │ Parent Pi / /agent-board dashboard │
89
- └──────────────┬───────────────┘
90
- │ dispatch
91
- ▼
92
- ┌────────────────────────────────────────────────────────────┐
93
- │ pty-runner.mjs │
94
- │ │
95
- │ host.json durable host status │
96
- │ control.sock IPC for attach/input/resize/stop │
97
- │ screen.log optional raw PTY output log │
98
- │ │
99
- │ ┌──────────────────────────────────────────────────────┐ │
100
- │ │ PTY │ │
101
- │ │ └─ pi --session <managed.jsonl> <initial prompt> │ │
102
- │ │ └─ real Pi interactive TUI │ │
103
- │ └──────────────────────────────────────────────────────┘ │
104
- └────────────────────────────────────────────────────────────┘
105
- ▲
106
- │ child extension events write row state
107
- │ AGENT_BOARD_ROOT / AGENT_BOARD_VIEW_ID
108
- │
109
- ┌──────────────┴───────────────┐
110
- │ agent-board extension in child │
111
- │ mirrors agent/tool/message │
112
- │ events to state.json │
113
- └──────────────────────────────┘
114
- ```
115
-
116
- Attach path:
117
-
118
- ```text
119
- User presses Enter on live row
120
- ├─ if host socket alive:
121
- │ open PtyAttachComponent
122
- │ connect to control.sock
123
- │ replay PTY snapshot/log into virtual terminal
124
- │ forward keyboard input to PTY
125
- │ intercept detach chord only
126
- │
127
- └─ else:
128
- fallback to existing ctx.switchSession(sessionFile)
129
- ```
130
-
131
- ## 4. Store/data model changes
132
-
133
- ### 4.1 Add host status file
134
-
135
- New path helpers in `src/core/paths.mjs`:
136
-
137
- ```js
138
- hostPath(root, viewId) // views/<viewId>/host.json
139
- controlSocketPath(root,id) // views/<viewId>/control.sock
140
- screenLogPath(root,id) // views/<viewId>/screen.log
141
- ```
142
-
143
- New shape in `src/core/types.mjs`:
144
-
145
- ```ts
146
- type HostMode = "json-runner" | "pty";
147
- type HostState = "starting" | "alive" | "exited" | "failed";
148
-
149
- interface HostStatus {
150
- version: 1;
151
- viewId: string;
152
- mode: HostMode;
153
- runnerPid: number | null;
154
- childPid: number | null;
155
- socketPath: string | null;
156
- state: HostState;
157
- startedAt: number;
158
- lastSeenAt: number;
159
- endedAt: number | null;
160
- exitCode: number | null;
161
- error: string | null;
162
- cols: number;
163
- rows: number;
164
- attachedClients: number;
165
- }
166
- ```
167
-
168
- ### 4.2 Extend `Row`
169
-
170
- In `src/core/store.mjs`, `loadRow()` should return:
171
-
172
- ```ts
173
- interface Row {
174
- meta: ViewMeta;
175
- state: ViewState | null;
176
- alive: boolean; // current agent activity/run alive, legacy-compatible
177
- hostAlive: boolean; // PTY host/socket alive and attachable
178
- host: HostStatus | null;
179
- }
180
- ```
181
-
182
- Dashboard row labels should distinguish:
183
-
184
- ```text
185
- ● working agent active
186
- ◌ hosted Pi process alive but idle
187
- ✓ completed completed, host may still be alive
188
- ```
189
-
190
- ## 5. Runner changes
191
-
192
- ### 5.1 Keep current JSON runner as fallback
193
-
194
- Do not delete `runner/job-runner.mjs`. Keep it for:
195
-
196
- - tests,
197
- - non-PTY fallback,
198
- - environments where `node-pty` cannot install,
199
- - comparison/debugging.
200
-
201
- ### 5.2 Add `runner/pty-runner.mjs`
202
-
203
- Responsibilities:
204
-
205
- 1. read `HostConfig` from JSON file,
206
- 2. create/remove stale socket,
207
- 3. spawn real interactive Pi in a PTY,
208
- 4. write `host.json`,
209
- 5. expose control socket,
210
- 6. append raw PTY output to `screen.log`,
211
- 7. broadcast output to attached clients,
212
- 8. accept input/resize/stop commands,
213
- 9. finalize host status on exit.
214
-
215
- Proposed host config:
216
-
217
- ```ts
218
- interface HostConfig {
219
- root: string;
220
- viewId: string;
221
- sessionFile: string;
222
- cwd: string;
223
- initialPrompt: string | null;
224
- piCommand: string;
225
- piArgsPrefix: string[];
226
- model: string | null;
227
- tools: string | null;
228
- env: Record<string, string>;
229
- cols: number;
230
- rows: number;
231
- }
232
- ```
233
-
234
- Spawn args:
235
-
236
- ```js
237
- const args = [
238
- ...piArgsPrefix,
239
- "--session", sessionFile,
240
- ];
241
- if (model) args.push("--model", model);
242
- if (tools) args.push("--tools", tools);
243
- if (initialPrompt) args.push(initialPrompt);
244
- ```
245
-
246
- Environment injected into child Pi:
247
-
248
- ```text
249
- AGENT_BOARD_ROOT=<root>
250
- AGENT_BOARD_VIEW_ID=<viewId>
251
- AGENT_BOARD_CHILD=1
252
- AGENT_BOARD_HOSTED=pty
253
- ```
254
-
255
- `AGENT_BOARD_CHILD=1` lets the extension avoid dashboard-first startup behavior and any recursive agent-board UI side effects inside hosted children.
256
-
257
- ### 5.3 Control socket protocol
258
-
259
- Use JSONL messages over a Unix socket.
260
-
261
- Client → runner:
262
-
263
- ```json
264
- {"type":"hello","clientId":"...","wantOutput":true}
265
- {"type":"input","data":"raw terminal bytes"}
266
- {"type":"resize","cols":120,"rows":36}
267
- {"type":"detach","clientId":"..."}
268
- {"type":"interrupt"}
269
- {"type":"terminate"}
270
- {"type":"get_status"}
271
- ```
272
-
273
- Runner → client:
274
-
275
- ```json
276
- {"type":"hello","status":{...}}
277
- {"type":"output","data":"raw terminal bytes"}
278
- {"type":"status","status":{...}}
279
- {"type":"exit","exitCode":0}
280
- {"type":"error","message":"..."}
281
- ```
282
-
283
- For attach, the parent sends raw input bytes through `input`. The attach surface intercepts only `←` when the child input line appears empty; all other keys, including Pi's native `ctrl+]` editor shortcut, pass through to the child.
284
-
285
- > **Historical:** superseded by the editor_state side channel (issue #91 Phase 6) — `←` now detaches only when the child pushes `editorEmpty=true`; otherwise (draft or unknown state) it is forwarded to the child. `Ctrl+←` always detaches.
286
-
287
- The detach chord is `←` because it is already the board navigation key and preserves Pi editor keybindings.
288
-
289
- ## 6. Attach UI design
290
-
291
- ### 6.1 Option A: virtual terminal component
292
-
293
- Add `src/ui/pty-attach.ts`:
294
-
295
- ```ts
296
- export class PtyAttachComponent implements Component {
297
- // connects to control.sock
298
- // feeds output into terminal emulator buffer
299
- // renders buffer lines via ctx.ui.custom
300
- // forwards input to socket
301
- // sends resize from tui.terminal rows/cols
302
- // done({ action: "detached" }) on detach chord
303
- }
304
- ```
305
-
306
- Potential dependency choices:
307
-
308
- - `node-pty` for PTY creation in runner,
309
- - `xterm-headless` or equivalent for terminal emulation in attach component.
310
-
311
- If adding dependencies, update `package.json` `dependencies`, not `devDependencies`, because Pi package installs use production deps.
312
-
313
- Expected fidelity:
314
-
315
- - normal Pi input behavior: high, because real Pi receives real terminal bytes,
316
- - normal Pi visual behavior: high for text UI,
317
- - possible gaps: inline images, OSC hyperlinks, exact hardware cursor/IME, mouse support.
318
-
319
- ### 6.2 Option B: raw takeover API if Option A is insufficient
320
-
321
- If virtual rendering cannot meet expectations, propose a Pi core API:
322
-
323
- ```ts
324
- ctx.ui.rawTerminalSession(async ({ input, output, resize, restore }) => {
325
- // parent TUI suspends rendering
326
- // extension proxies bytes to/from child PTY
327
- });
328
- ```
329
-
330
- This would give true terminal proxy behavior, but requires Pi core work outside this extension.
331
-
332
- ## 7. Extension changes
333
-
334
- ### 7.1 `src/index.ts`
335
-
336
- Current extension mirrors events for any managed foreground session. Adjust it for hosted child processes:
337
-
338
- - if `process.env.AGENT_BOARD_CHILD === "1"`, skip dashboard auto-open handling,
339
- - still register event listeners,
340
- - when `AGENT_BOARD_VIEW_ID` is present, mirror events directly to that row,
341
- - keep footer status disabled/no-op in child to avoid confusing nested hosted Pi.
342
-
343
- Potential helper:
344
-
345
- ```ts
346
- const hostedViewId = process.env.AGENT_BOARD_VIEW_ID;
347
- const isHostedChild = process.env.AGENT_BOARD_CHILD === "1";
348
- ```
349
-
350
- ### 7.2 `src/runtime/service.mjs`
351
-
352
- Add methods:
353
-
354
- ```js
355
- launchHost(meta, initialPrompt)
356
- ensureHost(viewId)
357
- attachTarget(viewId) // { kind: "pty", socketPath } | { kind: "session", sessionFile }
358
- stopActivity(viewId) // sends interrupt to socket if hosted, else current stop
359
- terminateHost(viewId)
360
- injectReply(viewId, text) // if host alive, paste/submit into PTY; else fallback launch one-shot/host
361
- ```
362
-
363
- Dispatch flow becomes:
364
-
365
- ```text
366
- createView
367
- launchHost(meta, prompt)
368
- state = queued/working once child extension events arrive
369
- ```
370
-
371
- Reply flow:
372
-
373
- ```text
374
- if hostAlive:
375
- send text + Enter to PTY
376
- else:
377
- launchHost(existingMeta, text) or existing JSON reply fallback
378
- ```
379
-
380
- Stop flow needs two actions:
381
-
382
- - **interrupt active agent**: send Escape or RPC-like interrupt if available,
383
- - **kill hosted Pi**: terminate PTY runner and child process.
384
-
385
- Existing `ctrl+s stop` should initially mean “interrupt/stop active work”; add a separate confirm for killing host if needed.
386
-
387
- ### 7.3 `src/commands/agent-board.ts`
388
-
389
- Change attach decision:
390
-
391
- ```ts
392
- if (row.hostAlive) {
393
- openPtyAttach(ctx, row)
394
- } else if (row.alive) {
395
- existing confirm interrupt + switchSession fallback
396
- } else {
397
- ctx.switchSession(row.meta.sessionFile, ...)
398
- }
399
- ```
400
-
401
- `openPtyAttach` should return to the dashboard without switching sessions.
402
-
403
- ### 7.4 `src/ui/dashboard.ts`
404
-
405
- Update row rendering:
406
-
407
- - show host-alive indicator,
408
- - attach hint says `enter attach live` when `hostAlive`,
409
- - running row no longer always asks “Interrupt and attach?” if host socket exists,
410
- - session read-only view remains useful as non-interrupting transcript.
411
-
412
- ## 8. Worktree/safety implications
413
-
414
- Existing same-repo writer worktree isolation remains valid.
415
-
416
- PTY-hosted sessions make the isolation rule more important because hosts can stay alive after task completion. Active writer detection should consider:
417
-
418
- ```text
419
- hostAlive && writeCapable && worktreeMode !== "worktree"
420
- ```
421
-
422
- However, an idle hosted process may not be writing. For MVP, be conservative:
423
-
424
- - if another non-worktree host is alive in the same repo, force worktree for new write-capable dispatch,
425
- - later refine by checking `state.semanticState === "working"`.
426
-
427
- ## 9. Testing plan
428
-
429
- ### 9.1 Unit tests
430
-
431
- Add tests for:
432
-
433
- - host path helpers,
434
- - host status read/write,
435
- - `loadRow().hostAlive`,
436
- - service attach target selection,
437
- - hosted vs fallback reply behavior,
438
- - child event mirroring does not mark idle host as dead.
439
-
440
- ### 9.2 Runner integration tests
441
-
442
- Add fake interactive child script:
443
-
444
- ```text
445
- test-support/fake-pty-pi.mjs
446
- ```
447
-
448
- It should:
449
-
450
- - write recognizable ANSI output,
451
- - accept stdin,
452
- - echo prompts,
453
- - simulate busy/idle states through environment or marker files,
454
- - exit on a command.
455
-
456
- Test `pty-runner.mjs`:
457
-
458
- - creates socket and host.json,
459
- - broadcasts PTY output,
460
- - forwards input,
461
- - handles resize,
462
- - finalizes on child exit,
463
- - kills child on terminate.
464
-
465
- ### 9.3 Attach component tests
466
-
467
- Keep most logic pure:
468
-
469
- - socket client parser,
470
- - terminal buffer projection,
471
- - detach chord interception,
472
- - resize event generation.
473
-
474
- Manual verification is required for final TUI fidelity.
475
-
476
- ## 10. Phased implementation
477
-
478
- ### Phase 0 — feasibility spike
479
-
480
- Goal: prove or disprove extension-only PTY attach.
481
-
482
- Tasks:
483
-
484
- 1. Add temporary `node-pty` experiment script outside app flow.
485
- 2. Spawn `pi --session <tmp.jsonl> "say hi"` inside PTY.
486
- 3. Verify Pi runs initial prompt and remains interactive afterward.
487
- 4. Build tiny `ctx.ui.custom` component that renders a fake ANSI stream through a terminal emulator.
488
- 5. Confirm parent Pi TUI can render the virtual terminal without corrupting its own screen.
489
- 6. Confirm child extension can mirror events via `AGENT_BOARD_ROOT/VIEW_ID`.
490
-
491
- Exit criteria:
492
-
493
- - Can attach, see live Pi UI, type into it, detach, and keep child alive.
494
-
495
- If this fails due to public TUI limitations, switch to Option B/C instead of forcing a bad clone.
496
-
497
- ### Phase 1 — host store + service plumbing
498
-
499
- - Add `HostStatus` types/path helpers/store functions.
500
- - Extend `Row` with `host`/`hostAlive`.
501
- - Add service methods for host launch/status/terminate.
502
- - Keep legacy JSON runner as fallback.
503
-
504
- ### Phase 2 — PTY runner
505
-
506
- - Add `runner/pty-runner.mjs`.
507
- - Add socket protocol.
508
- - Add fake PTY integration tests.
509
- - Persist `host.json` and `screen.log`.
510
-
511
- ### Phase 3 — child event mirroring
512
-
513
- - Modify `src/index.ts` for hosted child env vars.
514
- - Make `syncForegroundEvent` or new `syncHostedEvent` update row activity without confusing host liveness.
515
- - Verify state transitions: queued → working → completed/needs_input while host remains alive.
516
-
517
- ### Phase 4 — live attach component
518
-
519
- - Add socket client.
520
- - Add virtual terminal renderer.
521
- - Intercept detach chord.
522
- - Forward all other input bytes.
523
- - Handle resize.
524
- - Integrate into `/agent-board` attach flow.
525
-
526
- ### Phase 5 — reply/stop behavior
527
-
528
- - Reply to host by injecting text + Enter into PTY.
529
- - Stop active work by sending Escape first.
530
- - Add terminate-host confirm if needed.
531
- - Preserve existing fallback for dead hosts.
532
-
533
- ### Phase 6 — hardening/polish
534
-
535
- - stale socket cleanup,
536
- - host TTL or user-visible “close host” command,
537
- - dependency install docs,
538
- - dashboard indicators,
539
- - worktree cleanup with live hosts,
540
- - manual verification matrix.
541
-
542
- ## 11. Acceptance criteria
543
-
544
- MVP live attach is accepted when:
545
-
546
- 1. Dispatch creates a real managed session and launches an interactive hosted Pi.
547
- 2. Dashboard shows the row working via child extension event mirroring.
548
- 3. Pressing attach while work is live opens the hosted session without interrupting it.
549
- 4. User can type normally into the attached Pi session.
550
- 5. Slash commands like `/session`, `/model`, `/tree` are handled by the child Pi, not reimplemented by agent-board.
551
- 6. Detach returns to dashboard and child Pi keeps running.
552
- 7. Reattach returns to the same live child Pi process.
553
- 8. If the host dies, attach falls back to `ctx.switchSession(sessionFile)`.
554
- 9. Existing tests pass; new host tests cover runner/socket/store behavior.
555
-
556
- ## 12. Risk register
557
-
558
- | Risk | Impact | Mitigation |
559
- |---|---|---|
560
- | `ctx.ui.custom` cannot faithfully render child terminal output | high | Phase 0 spike; fallback to Pi core raw takeover API or standalone CLI |
561
- | `node-pty` native install friction | medium | keep JSON runner fallback; document dependency; consider tmux fallback |
562
- | child Pi extension recursion | medium | `AGENT_BOARD_CHILD=1`; skip dashboard auto-open/footer in child |
563
- | host liveness conflated with agent activity | high | add `host.json`; separate `hostAlive` from `row.alive` |
564
- | worktree safety too conservative with idle hosts | low/medium | conservative MVP, later refine with activity state |
565
- | `←` is also a child-editor cursor key | low | detach only when the child input line appears empty; keep all other editor shortcuts, including `ctrl+]`, pass-through. **Superseded (issue #91 Phase 6):** detach now gates on the pushed `editorEmpty` state, not the rendered buffer; `Ctrl+←` always detaches |
566
- | terminal images/OSC links not perfect in virtual renderer | medium | document limitation; raw takeover/core API if needed |
567
-
568
- ## 13. Confidence
569
-
570
- - **PTY-hosted process + socket + status mirroring:** high, ~80–85%.
571
- - **Extension-only virtual-terminal attach:** medium, ~60–70% until Phase 0 proves TUI fidelity.
572
- - **True raw 1:1 terminal attach:** high conceptually, but likely needs Pi core or standalone CLI support.
573
-
574
- ## 14. Recommended next step
575
-
576
- Do **Phase 0 only** first. Do not refactor the whole service until we prove that a parent Pi extension can render and drive a child Pi PTY well enough inside `ctx.ui.custom()`.
577
-
578
- If Phase 0 passes, proceed with phases 1–6. If it fails, stop and design either:
579
-
580
- 1. a small Pi core raw-terminal takeover API, or
581
- 2. a standalone `pi-agent-board` CLI that owns the terminal like tmux.