@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
@@ -0,0 +1,277 @@
1
+ # Reference
2
+
3
+ ## Main list
4
+
5
+ Typing goes straight into the input, as in Claude Code's agent view, so there's no mode to enter first.
6
+
7
+ | Key | Action |
8
+ | --- | --- |
9
+ | Any text | Start writing a task. |
10
+ | `Enter` | Start the task, or attach to the selected session when the input is empty. |
11
+ | `Ctrl+Enter` | Start the task and attach to it. |
12
+ | `Shift+Enter` / `Ctrl+J` | New line in the task. |
13
+ | `Ctrl+N` | While typing, choose the folder, model and thinking level first. |
14
+ | `Left` / `Right` | Attach to the selected session. |
15
+ | `Left` twice | From an empty Pi prompt, put this session on the board and open it. |
16
+ | `Up` / `Down` | Move between rows. |
17
+ | `PgUp` / `PgDn` | Move by a screenful. |
18
+ | `Home` / `End` | First or last row. |
19
+ | `Alt+Up` / `Alt+Down` | Previous or next group. |
20
+ | `Alt+1`..`Alt+9` | Attach to that row. |
21
+ | `Space` | Open or close Peek. |
22
+ | `/` | Pick one of Pi's commands. It closes the board and runs in the Pi you opened it from. A template or skill starts a session instead, like any task. |
23
+ | `Ctrl+F` | Filter the list. |
24
+ | `Ctrl+S` | Group by state or by directory. |
25
+ | `Shift+Up` / `Shift+Down` | Move the row up or down its group. |
26
+ | `Ctrl+G` | Write the task in `$VISUAL` or `$EDITOR`. |
27
+ | `Ctrl+T` | Pin or unpin. |
28
+ | `Ctrl+R` | Rename. |
29
+ | `Ctrl+X` | Stop the session; press again within 2 seconds to delete it. |
30
+ | `Ctrl+D` | Confirm marking an inactive session Done. |
31
+ | `Ctrl+B` | Hold or unhold an inactive session. |
32
+ | `Ctrl+A` | Select several rows. |
33
+ | `Ctrl+O` | Read-only transcript. |
34
+ | `Ctrl+E` | Evidence / Diagnostics. |
35
+ | `Ctrl+K` | Delete inactive rows in the selected state. |
36
+ | `!` | node-pty diagnostics and fix steps. |
37
+ | `?` | Help. |
38
+ | `Esc` | Clear a draft, or leave the board. |
39
+ | `Ctrl+C` | Clear a draft; press twice within a second to quit Pi, from the board or an attached session. Background sessions keep running. |
40
+
41
+ On macOS, the `Alt` keys need your terminal to send Option as Alt.
42
+
43
+
44
+ ## Multi-select
45
+
46
+ Press `Ctrl+A` in the main list to act on several sessions at once.
47
+
48
+ | Key | Action |
49
+ | --- | --- |
50
+ | `Up` / `Down` / `j` / `k` | Move the selection. |
51
+ | `Space` | Toggle the current row. |
52
+ | `a` | Select all visible rows. |
53
+ | `u` | Clear the selection. |
54
+ | `d` | Confirm marking the selected inactive rows Done. |
55
+ | `Ctrl+X` | Delete the selected Done rows (confirmation prompt). |
56
+ | `m` / `Esc` / `Ctrl+C` | Leave multi-select mode. |
57
+ | `?` | Open the help overlay. |
58
+ | `!` | Open node-pty diagnostics and fix steps. |
59
+
60
+
61
+ ## Peek
62
+
63
+ Peek shows the selected session's summary, blocker or question, latest output, and available issue/PR references.
64
+
65
+ | Key | Action |
66
+ | --- | --- |
67
+ | Any text | Start a reply, and press `Enter` to send it without attaching. |
68
+ | `Left` / `Right` | Attach to the session. |
69
+ | `Up` / `Down` | Move to the previous or next session. |
70
+ | `Ctrl+O` | Open the read-only transcript. |
71
+ | `Ctrl+E` | Open Evidence / Diagnostics. |
72
+ | `Ctrl+D` | Confirm marking the inactive session Done. |
73
+ | `Ctrl+B` | Hold or unhold the session. |
74
+ | `!` | Open node-pty diagnostics and fix steps. |
75
+ | `Space` / `Esc` | Return to the main list. |
76
+
77
+ When a Pi question or questionnaire tool is pending, inline reply is rejected; attach to answer that interactive question in the real Pi session.
78
+
79
+
80
+ ## Transcript
81
+
82
+ The `v` view is a read-only projection of the durable Pi session JSONL. It does not interrupt a running worker.
83
+
84
+ | Key | Action |
85
+ | --- | --- |
86
+ | `Up` / `Down` / `j` / `k` | Scroll one line. |
87
+ | `PageUp` / `PageDown` | Scroll one page. |
88
+ | `Space` | Open Peek. |
89
+ | `r` | Enter reply mode. |
90
+ | `Enter` or `a` | Attach to the session. |
91
+ | `e` | Open Evidence / Diagnostics. |
92
+ | `d` | Confirm marking the inactive session Done. |
93
+ | `h` | Hold or unhold the session. |
94
+ | `!` | Open node-pty diagnostics and fix steps. |
95
+ | `Left` / `Esc` / `<` | Return to the main list. |
96
+
97
+
98
+ ## Evidence / Diagnostics
99
+
100
+ The `e` view shows durable session evidence, including changed files, commands and their outcomes, command output previews, assistant evidence, errors, diagnostics, and artifact paths. Press `x` to clear diagnostics while preserving the evidence artifacts.
101
+
102
+ | Key | Action |
103
+ | --- | --- |
104
+ | `Up` / `Down` / `j` / `k` | Scroll one line. |
105
+ | `PageUp` / `PageDown` | Scroll one page. |
106
+ | `r` | Enter reply mode. |
107
+ | `v` | Open the read-only transcript. |
108
+ | `Enter`, `a`, `Right`, or `l` | Attach to the session. |
109
+ | `x` | Clear diagnostics; evidence is preserved. |
110
+ | `Left` / `Esc` / `<` | Return to the main list. |
111
+
112
+
113
+ ## PTY attach
114
+
115
+ PTY attach opens the real interactive Pi session. `Ctrl+Left` detaches and returns to the board regardless of editor state, and `Ctrl+\` is the unconditional escape — a single raw ASCII byte (0x1c) that terminals forward unchanged in raw mode (kitty CSI-u and modifyOtherKeys encodings included), honored no matter what the child editor reports. `Left` detaches only while the child Pi reports an empty editor; while you are editing text — or when the child's editor state is unknown (e.g. the child extension is missing) — `Left` is forwarded to the Pi editor. A disconnected host can always be exited with `Left`. `Ctrl+]` is not a detach key — it is passed through to the child Pi editor. `Ctrl+\` caveats: on keyboard layouts where `\` sits on AltGr (e.g. German) the chord may never produce the byte — use `Ctrl+Left` there; in legacy keyboard modes `Ctrl+4` emits the same byte and also detaches; and the key is captured from the child while attached, so the child's own `Ctrl+\` binding (e.g. the vim terminal-mode prefix) is unavailable. While attached, `PageUp`, `PageDown`, `Home`, `End`, and the mouse wheel scroll local scrollback; whenever that viewport cannot move — the session holds the alternate screen (pi's fullscreen default), or there is no local history to travel — the wheel is forwarded to the session instead, which scrolls its own transcript: the same fallback the paging keys use. The attach viewport only scrolls scrollback the hosted session actually produced: rows that a snapshot hydration had to scroll out of the local window are not history, and the wheel is forwarded to the session instead of consuming those rows. Mouse drag or double-click selects and copies text, clicks open detected links, and middle-click paste is available on systems with the required X11 tooling. `Ctrl+X` opens an in-place delete confirm: press `y` (or Enter) to archive the row and return to the board with the next row selected — any other key cancels and is passed through to the session. While attached, the child Pi's own `Ctrl+X` bindings (copy in `/tree` and fullscreen, clear-all in the models dialog) are captured by this gesture.
116
+
117
+ Automatic light/dark themes work in attach sessions too. The child Pi's background-color probe (OSC 11) and its color-scheme change notification switch are forwarded to your real terminal; replies and notifications flow back to the child when your terminal answers — a terminal that never answers keeps the dark fallback. Attach also re-probes the background once when it settles, so the theme is correct from the first frame without re-selecting it in `/settings`. All of this is on by default; set `AGENT_BOARD_FORWARD_TERMINAL_QUERIES=0` to disable it. Not covered: keyboard-protocol negotiation (kitty flags / DA1) is not forwarded — the child negotiates once at spawn, before any attach client exists, and forwarding it would retune the shared real-terminal keyboard stack — so modifier-key encoding can still differ from a directly-run Pi (the modifyOtherKeys fallback applies).
118
+
119
+ The attach surface can forward terminal clipboard and image/file passthrough sequences. These behaviors can be disabled individually in [Configuration](#configuration). Cold hosts may briefly show a loading/reconnect surface while their PTY becomes ready.
120
+
121
+ ## States, Grouping, and Filters
122
+
123
+ The board separates a session's semantic task state from whether a worker process is currently alive. An exited worker can therefore leave a durable row that is still resumable or attachable.
124
+
125
+ | Display state | Meaning |
126
+ | --- | --- |
127
+ | **Queued** | A run has been scheduled but has not started processing. |
128
+ | **Running** | The session is actively processing. |
129
+ | **Needs answer** | The session is waiting for user input or an answer to a question. |
130
+ | **Needs instructions** | The run ended without being marked complete and needs the next directive. |
131
+ | **On hold** | The user parked this session intentionally (manual verdict, `h` to toggle). Automated writers can't push it to Done; queued follow-ups do not wake it. |
132
+ | **Done** | The user marked the inactive session complete; this is the default completion path. |
133
+ | **Failed** | The worker or host ended with an error. |
134
+ | **Stopped** | The user stopped the active work. |
135
+
136
+ Rows are grouped by state. When a state contains sessions from multiple directories, rows are grouped by folder within that state. Pinned rows and folders come first, then creation order remains stable; activity does not reshuffle the list. New agent activity is marked unread with stronger row glyphs and header/footer counts. Replies sent while a session is busy enter a durable FIFO follow-up queue and are delivered when the session is ready; a `qN` badge shows queued follow-ups.
137
+
138
+ Press `Ctrl+F` to enter filter mode. Filter tokens are case-insensitive and can be combined with free-text terms:
139
+
140
+ ```text
141
+ s:running
142
+ s:hold
143
+ review:ready
144
+ diag:stalled
145
+ evidence:error
146
+ queued:true
147
+ steer:awaiting-approval
148
+ ```
149
+
150
+ - `s:<state>` matches a state prefix, including display-label aliases such as `needs-answer`.
151
+ - `review:ready` finds sessions with review-ready evidence.
152
+ - `evidence:error` finds sessions whose evidence contains errors.
153
+ - `queued:true` (also `yes` or `1`) finds sessions with queued follow-ups.
154
+ - `steer:<state>` filters by a persisted steering state.
155
+ - Bare words match name, summary, and working directory; multiple words use AND matching.
156
+
157
+ `diag:stalled` can consume persisted stalled diagnostics, but the current runner does not provide a general provider-stall detector. It should not be read as a complete automatic stall-detection feature.
158
+
159
+ ## Evidence and Code References
160
+
161
+ Evidence is collected locally from session events. The board can extract issue and pull-request references from that evidence and show badges such as `#40` or `▸#45` on rows; Peek includes the provider, confidence, source, and URL when available. Built-in GitHub/GitLab-style providers are available, and an optional per-store `providers.json` can extend the provider rules. The `AGENT_BOARD_CODE_REFS=off` setting disables extraction.
162
+
163
+ For internal code platforms (non-github/gitlab hosts) or custom CLIs, add a per-store `providers.json` so claim/action rules exist and sessions stop depending on the low-confidence mention fallback. Example — an internal CLI (`acli`) with claim-strength issue rules:
164
+
165
+ ```json
166
+ {
167
+ "providers": [
168
+ {
169
+ "name": "acode",
170
+ "hosts": ["acode.internal.example.com"],
171
+ "rules": [
172
+ { "pattern": "acli\\s+issue\\s+update\\s+#?(\\d+)(?=[\\s\\S]*--assignee)", "kind": "issue", "strength": "claim" },
173
+ { "pattern": "acli\\s+issue\\s+(?:note|comment|close)\\s+#?(\\d+)", "kind": "issue", "strength": "action" },
174
+ { "pattern": "acli\\s+issue\\s+(?:show|view)\\s+#?(\\d+)", "kind": "issue", "strength": "view" }
175
+ ]
176
+ }
177
+ ]
178
+ }
179
+ ```
180
+
181
+ `hosts` matches the repo's remote host; rules follow the same `pattern`/`kind`/`strength` shape as the built-in `gh`/`glab` tables (`strength`: `claim` > `action` > `view`), and the `#N` capture group supplies the number. Validation errors from a broken file surface in the diagnostics panel and never break extraction — an invalid file is simply ignored.
182
+
183
+ ## Configuration
184
+
185
+ Settings live in `~/.pi/agent/extensions/pi-board/config.json`. Everything is optional, and a missing or broken file means the defaults. Restart Pi after editing it.
186
+
187
+ ```json
188
+ {
189
+ "model": "provider/model-id",
190
+ "autoDone": false
191
+ }
192
+ ```
193
+
194
+ ### Helper model
195
+
196
+ Titles, row summaries and telling `Needs answer` from `Needs instructions` can use a model. **It's off by default**, so the board makes no model calls of its own and uses built-in rules instead.
197
+
198
+ Run `/board-model` inside Pi to pick a model or turn it off. It's saved to the file above and applies to sessions started from then on. These calls run through Pi, so any model Pi can use works, and they send up to 6,000 characters of a session's latest reply to that model.
199
+
200
+ ### Other settings
201
+
202
+ | Key | Default | Purpose |
203
+ | --- | --- | --- |
204
+ | `model` | off | Helper model, as `provider/id`. |
205
+ | `groupBy` | `state` | `state` or `directory`. `Ctrl+S` changes it. |
206
+ | `root` | `~/.pi/agent/agent-board/` | Where the board stores its state. |
207
+ | `titleThinking` | `low` | Thinking level for titles. |
208
+ | `autoDone` | `false` | Let the helper model mark sessions Done. |
209
+ | `codeRefs` | `true` | Issue and pull request badges. |
210
+ | `disablePty` | `false` | Turn off live terminal sessions and attach. |
211
+ | `attachMouse` | `true` | Mouse handling in attached sessions. |
212
+ | `mouseScroll` | `true` | Mouse wheel scrolling in attached sessions. |
213
+ | `wheelLines` | `1` | Lines per wheel notch, from 1 to 50. |
214
+ | `maxWarmHosts` | `4` | Idle sessions kept ready for fast attach, from 0 to 50. |
215
+ | `warmHostTtlMs` | `600000` | How long an idle one is kept; `0` keeps it. |
216
+ | `nativePaste` | `true` | X11 PRIMARY copy and middle-click paste. |
217
+ | `forwardClipboard` | `true` | Forward OSC 52 clipboard writes from attached sessions. |
218
+ | `forwardImages` | `true` | Forward terminal images from attached sessions. |
219
+ | `imeFix` | `true` | IME cursor fix in attached sessions. |
220
+ | `terminalSnapshot` | `true` | Newer attach path; `false` uses the older one. |
221
+ | `replyGuard` | `true` | Discard stray terminal replies delivered as input. |
222
+
223
+ An `AGENT_BOARD_*` environment variable that's already set overrides the file for that run.
224
+
225
+ Setting `terminalSnapshot` to `false` routes attach onto the legacy fallback family: the screen.log replay tail plus the shrink-and-hold jiggle redraw. These paths exist only for pre-protocol runners and as a rollback hatch — they are not part of the snapshot+subscribe protocol path (issue #91 phase 4). They will be retired once the installed runner fleet is on the snapshot protocol baseline (detectable on the wire via hello protocol fields).
226
+
227
+ Older `AGENT_VIEW_*` names are still read in selected compatibility paths. Prefer `AGENT_BOARD_*` for new setups. Internal child markers are managed by the board and are not user settings.
228
+
229
+ The `providers.json` file under the configured store root can extend the built-in issue/PR reference providers; see the [Evidence and Code References](#evidence-and-code-references) section for the feature overview.
230
+
231
+ ## Troubleshooting
232
+
233
+ ### Rows stay in `Running`
234
+
235
+ First verify that Pi itself can complete a one-shot model call:
236
+
237
+ ```bash
238
+ pi --mode json -p --no-session "Reply with exactly: DONE"
239
+ ```
240
+
241
+ The command should emit an assistant reply, then an `agent_end` event, and exit. If it hangs before the assistant reply, fix Pi provider authentication or network access first. The board cannot produce live model results until Pi works independently.
242
+
243
+ ### `node-pty unavailable`
244
+
245
+ Press `!` in the dashboard to open the diagnostic panel and follow its fix steps. Common causes include a missing native `node-pty` binary, a Node/architecture mismatch, a missing or non-executable macOS `spawn-helper`, or macOS quarantine. You can temporarily set `AGENT_BOARD_DISABLE_PTY=1` to use background JSON-runner behavior where supported.
246
+
247
+ ### Attach is slow or keeps reconnecting
248
+
249
+ A cold PTY host may briefly show a loading or reconnecting surface while it starts. Check the PTY status in the dashboard with `!`; stale hosts are diagnosed separately from active task workers. If the host never becomes healthy, repair `node-pty` or use background mode for eligible managed sessions.
250
+
251
+ ### IME candidate window is stuck at the window edge (Windows WezTerm)
252
+
253
+ On Windows WezTerm with a WSL2 backend, the IME candidate window may stay pinned to the right edge instead of following the text cursor in an attached session. Windows WezTerm only tracks the IME candidate position from the visible hardware cursor, and Pi hides the hardware cursor by default — the block cursor you see in the editor is drawn content, not the hardware cursor. Linux terminals are not affected.
254
+
255
+ Make the hardware cursor visible, either way:
256
+
257
+ ```bash
258
+ export PI_HARDWARE_CURSOR=1 # machine-local, e.g. ~/.zshrc.local
259
+ ```
260
+
261
+ or set `"showHardwareCursor": true` in Pi's `settings.json` (syncs across machines if the config is version-controlled; harmless on Linux).
262
+
263
+ Trade-off: the real terminal cursor becomes visible inside the TUI. This is cosmetic only.
264
+
265
+ ### Start & attach falls back to background
266
+
267
+ Start & attach requires PTY support. When PTY is unavailable, the task is still dispatched in the background and the dashboard displays a warning. Repair PTY and retry attach from the normal `/agent-board` command path.
268
+
269
+ ### Inline reply is rejected
270
+
271
+ A pending Pi question or questionnaire requires the real interactive session. Attach to the row and answer it there; ordinary replies can be sent from Peek and are queued while a session is busy.
272
+
273
+ ### Sessions in the same repository conflict
274
+
275
+ Worktree isolation is not enabled. Stop overlapping writers, separate their working directories, or create and manage Git worktrees yourself before running concurrent coding tasks.
276
+
277
+
package/package.json CHANGED
@@ -1,22 +1,19 @@
1
1
  {
2
2
  "name": "@huseynsnmz/pi-board",
3
- "version": "0.15.3",
3
+ "version": "0.17.0",
4
4
  "description": "A board for Pi's background sessions: start, watch, reply to and attach to them. A fork of @zhuxixi/pi-agent-board.",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
7
7
  "exports": "./index.ts",
8
8
  "files": [
9
9
  "CHANGELOG.md",
10
- "IMPLEMENTATION_PLAN.md",
10
+ "CONTRIBUTING.md",
11
11
  "LICENSE",
12
- "PRD.md",
13
- "PROGRESS.md",
14
12
  "README.md",
15
- "VERIFY.md",
13
+ "SECURITY.md",
16
14
  "docs",
17
15
  "index.ts",
18
16
  "runner",
19
- "scripts",
20
17
  "src"
21
18
  ],
22
19
  "keywords": [
@@ -46,9 +43,7 @@
46
43
  "pi": {
47
44
  "extensions": [
48
45
  "./src/index.ts"
49
- ],
50
- "video": "https://github.com/zhuxixi/pi-agent-board/raw/refs/heads/main/assets/demo.mp4",
51
- "image": "https://github.com/zhuxixi/pi-agent-board/raw/refs/heads/main/assets/banner.png"
46
+ ]
52
47
  },
53
48
  "scripts": {
54
49
  "typecheck": "tsc --noEmit",
@@ -56,8 +51,7 @@
56
51
  "test:coverage": "c8 node scripts/run-tests.mjs",
57
52
  "test:perf": "node scripts/run-perf-gate.mjs",
58
53
  "pack:dry": "npm pack --dry-run",
59
- "verify": "npm run typecheck && npm run test:perf && npm test && npm run test:coverage && npm run pack:dry",
60
- "changelog": "node scripts/release_helper.mjs"
54
+ "verify": "npm run typecheck && npm run test:perf && npm test && npm run test:coverage && npm run pack:dry"
61
55
  },
62
56
  "peerDependencies": {
63
57
  "@earendil-works/pi-coding-agent": "*",
@@ -11,6 +11,7 @@ import { Key, matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
11
11
  import { requestDashboardRender } from "../core/dashboard-render.mjs";
12
12
  import { nextVisibleIdAfterRemoval } from "../core/rows.mjs";
13
13
  import { createService } from "../runtime/service.mjs";
14
+ import { boardCommands } from "../core/slash-commands.mjs";
14
15
  import { planAttachPrelude, planAttachResolved } from "./attach-decision.mjs";
15
16
  import { screenLogPath } from "../core/paths.mjs";
16
17
  import { appendDiagnostic } from "../core/diagnostics.mjs";
@@ -31,7 +32,10 @@ export interface AgentBoardCommandOptions {
31
32
 
32
33
  const sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));
33
34
 
35
+ let addedCommands: () => { name: string; description?: string; source: string }[] = () => [];
36
+
34
37
  export function registerAgentBoardCommand(pi: ExtensionAPI, opts: AgentBoardCommandOptions): void {
38
+ addedCommands = () => pi.getCommands();
35
39
  pi.registerCommand("agent-board", {
36
40
  description: "Open the background agent-board dashboard",
37
41
  handler: async (args, ctx) => {
@@ -73,7 +77,7 @@ export function registerAgentBoardCommand(pi: ExtensionAPI, opts: AgentBoardComm
73
77
  }
74
78
 
75
79
  export async function openDashboard(
76
- ctx: Pick<ExtensionCommandContext, "ui" | "cwd" | "modelRegistry" | "model" | "sessionManager">,
80
+ ctx: Pick<ExtensionCommandContext, "ui" | "cwd" | "modelRegistry" | "model" | "sessionManager" | "shutdown">,
77
81
  service: ReturnType<typeof createService>,
78
82
  options: {
79
83
  initialSelectedId?: string | null;
@@ -85,6 +89,8 @@ export async function openDashboard(
85
89
  ctx.ui.setHeader(() => ({ render: () => [], invalidate() {} }));
86
90
  ctx.ui.setFooter(() => ({ render: () => [], invalidate() {} }));
87
91
  ctx.ui.setTitle("agent-board");
92
+ let board: unknown = null;
93
+ let command: string | null = null;
88
94
  let availableModels: any[] = [];
89
95
  try {
90
96
  availableModels = ctx.modelRegistry.getAvailable();
@@ -92,8 +98,9 @@ export async function openDashboard(
92
98
  availableModels = [];
93
99
  }
94
100
  try {
95
- return await ctx.ui.custom<DashboardResult>(
101
+ const result = await ctx.ui.custom<DashboardResult>(
96
102
  (tui, theme, keybindings, done) => {
103
+ board = tui;
97
104
  let interval: ReturnType<typeof setInterval> | null = null;
98
105
  const wrappedDone = (result: DashboardResult) => {
99
106
  if (interval) clearInterval(interval);
@@ -110,6 +117,7 @@ export async function openDashboard(
110
117
  availableModels,
111
118
  currentModel: ctx.model ?? null,
112
119
  currentThinkingLevel: options.currentThinkingLevel ?? "off",
120
+ commands: boardCommands(addedCommands()),
113
121
  });
114
122
  interval = setInterval(() => {
115
123
  void service.reconcile().catch(() => {});
@@ -132,8 +140,20 @@ export async function openDashboard(
132
140
  overlayOptions: { anchor: "top-left", width: "100%", maxHeight: "100%", margin: 0 },
133
141
  },
134
142
  );
143
+ if (result.action === "quit") ctx.shutdown();
144
+ if (result.action === "command") command = result.text;
145
+ return result;
135
146
  } finally {
136
147
  restoreChrome(ctx);
148
+ // A command runs with more than an extension is given, so this goes the way a typed one does.
149
+ if (command) {
150
+ ctx.ui.setEditorText(command);
151
+ setTimeout(() => {
152
+ const focused = (board as { getFocusedComponent?: () => { handleInput?: (data: string) => void; getExpandedText?: () => string } | null } | null)?.getFocusedComponent?.();
153
+ // Only if it's the prompt holding the command. Otherwise it's left there to send by hand.
154
+ if (focused?.getExpandedText?.() === command) focused.handleInput?.("\r");
155
+ }, 0);
156
+ }
137
157
  }
138
158
  }
139
159
 
@@ -203,6 +223,10 @@ async function attach(
203
223
  void service.markVisited?.(viewId)?.catch(() => {});
204
224
  const result = await openPtyAttach(ctx, root, row.meta.id, row.meta.name, plan.socketPath);
205
225
  void service.markVisited?.(viewId)?.catch(() => {});
226
+ if (result.action === "quit") {
227
+ ctx.shutdown();
228
+ return { action: "switched" }; // Nothing to come back to.
229
+ }
206
230
  if (result.action === "delete") {
207
231
  // Issue #147: the component already tore down and exited — archive
208
232
  // here so the host's death is never rendered inside the attach view.
@@ -145,6 +145,10 @@ export async function attach(
145
145
  void service.markVisited?.(viewId)?.catch(() => {});
146
146
  const result = await openPtyAttach(ctx, root, row.meta.id, row.meta.name, plan.socketPath);
147
147
  void service.markVisited?.(viewId)?.catch(() => {});
148
+ if (result.action === "quit") {
149
+ ctx.shutdown();
150
+ return { action: "switched" }; // Nothing to come back to.
151
+ }
148
152
  return { action: result.action === "closed" ? "closed" : "detached" };
149
153
  }
150
154
  if (plan.plan === "session-switch") {
@@ -1,17 +1,21 @@
1
1
  /** How close two presses must be to count as one double press. */
2
2
  export const DOUBLE_PRESS_MS = 400;
3
3
 
4
+ /** Longer than Pi's own 500ms, or a session could take the second Ctrl+C and quit by itself. */
5
+ export const QUIT_PRESS_MS = 1000;
6
+
4
7
  /**
5
8
  * Tells a second press apart from a first. Anything else in between starts over.
6
9
  * @param {() => number} [now]
10
+ * @param {number} [windowMs]
7
11
  * @returns {{ press(): boolean, reset(): void }} press() is true on the second press.
8
12
  */
9
- export function createDoublePress(now = Date.now) {
13
+ export function createDoublePress(now = Date.now, windowMs = DOUBLE_PRESS_MS) {
10
14
  let last = null;
11
15
  return {
12
16
  press() {
13
17
  const at = now();
14
- const second = last !== null && at - last <= DOUBLE_PRESS_MS;
18
+ const second = last !== null && at - last <= windowMs;
15
19
  last = second ? null : at;
16
20
  return second;
17
21
  },
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Pi's own commands. It doesn't export this list, and pi.getCommands() leaves them out.
3
+ * From pi-coding-agent 1.5.0, dist/core/slash-commands.js.
4
+ */
5
+ export const BUILTIN_COMMANDS = [
6
+ ["settings", "Open settings menu"],
7
+ ["model", "Select model (opens selector UI)"],
8
+ ["tree", "Navigate session tree (switch branches)"],
9
+ ["thinking", "Set thinking level"],
10
+ ["scoped-models", "Enable/disable models for Ctrl+P cycling"],
11
+ ["export", "Export session (HTML default, or specify path: .html/.jsonl)"],
12
+ ["import", "Import a JSONL session, preserving its ID and working directory"],
13
+ ["share", "Share session via a Radius artifact or a GitHub gist"],
14
+ ["bug", "Report a bug to the Pi developers"],
15
+ ["copy", "Copy last agent message to clipboard"],
16
+ ["name", "Set session display name"],
17
+ ["session", "Show session info and stats"],
18
+ ["changelog", "Show changelog entries"],
19
+ ["hotkeys", "Show all keyboard shortcuts"],
20
+ ["fork", "Create a new fork from a previous user message"],
21
+ ["clone", "Duplicate the current session at the current position"],
22
+ ["trust", "Save project trust decision for future sessions"],
23
+ ["login", "Configure provider authentication"],
24
+ ["logout", "Remove provider authentication"],
25
+ ["new", "Start a new session"],
26
+ ["compact", "Manually compact the session context"],
27
+ ["resume", "Resume another session"],
28
+ ["reload", "Reload keybindings, extensions, skills, prompts, themes, and context files"],
29
+ ["quit", "Quit Pi"],
30
+ ].map(([name, description]) => ({ name, description, source: "builtin" }));
31
+
32
+ /**
33
+ * What the board offers after `/`: Pi's commands, then what extensions, templates and skills add.
34
+ * @param {{ name: string, description?: string, source: string }[]} added from pi.getCommands()
35
+ */
36
+ export function boardCommands(added) {
37
+ const seen = new Set(BUILTIN_COMMANDS.map((command) => command.name));
38
+ return [...BUILTIN_COMMANDS, ...added.filter((command) => !seen.has(command.name))];
39
+ }
40
+
41
+ /**
42
+ * Commands act on the Pi the board is open in. Templates and skills are prompts, so they
43
+ * start a session like any task, and so does anything that isn't a command.
44
+ * @param {string} text
45
+ * @param {{ name: string, source: string }[]} commands
46
+ */
47
+ export function runsInPi(text, commands) {
48
+ if (!text.startsWith("/")) return false;
49
+ const name = text.slice(1).split(/\s/, 1)[0];
50
+ const command = commands.find((candidate) => candidate.name === name);
51
+ return command !== undefined && command.source !== "prompt" && command.source !== "skill";
52
+ }
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Registers the `/agent-board` dashboard command, resolves how to
5
5
  * launch background workers and the detached runner, and keeps a small footer status with
6
- * the count of sessions needing attention. See docs/EXPLORATION.md for the design.
6
+ * the count of sessions needing attention.
7
7
  */
8
8
  import "./core/load-config.mjs";
9
9
  import { fileURLToPath } from "node:url";
@@ -151,6 +151,9 @@ export function resolveAttachResolveTimeoutMs(env = process.env) {
151
151
  * },
152
152
  * }} opts
153
153
  */
154
+ /** A pending question that is an open dialog, such as a permission prompt. */
155
+ const DIALOG = "dialog";
156
+
154
157
  export function createService(opts) {
155
158
  const root = opts.root;
156
159
  const launch = opts.launch ?? launchRun;
@@ -1814,6 +1817,8 @@ export function createService(opts) {
1814
1817
  status.semanticState = event.waiting ? "needs_input" : "working";
1815
1818
  status.processState = "alive";
1816
1819
  status.question = event.waiting ? "Waiting on a prompt. Attach to answer it." : null;
1820
+ // Counts as pending so the host isn't evicted, and so a reply can tell it's there.
1821
+ status.pendingQuestions = event.waiting ? [{ kind: DIALOG, question: status.question }] : [];
1817
1822
  status.summary = event.waiting ? "Waiting on a prompt" : "Running…";
1818
1823
  status.lastActivityAt = now;
1819
1824
  void writeForegroundState(row, status);
@@ -1845,6 +1850,7 @@ export function createService(opts) {
1845
1850
  }
1846
1851
 
1847
1852
  if (event.type === "agent_end") {
1853
+ status.pendingQuestions = status.pendingQuestions.filter((question) => question?.kind !== DIALOG);
1848
1854
  // #46-class fence (issue #91): a manual verdict is a user judgment that
1849
1855
  // outlives the turn. A late/duplicate agent_end after markCompleted must
1850
1856
  // not resurrect the row via finalizeRun + projection — skip all semantic
@@ -2073,6 +2079,12 @@ export function createService(opts) {
2073
2079
  if (!prompt) return { ok: false, error: "Empty reply" };
2074
2080
  const row = loadRow(root, viewId);
2075
2081
  if (!row) return { ok: false, error: "Unknown session" };
2082
+ // Text and Enter sent to the terminal would go to the open dialog, and could approve what it
2083
+ // asks. So it waits its turn, and answering the dialog takes attaching.
2084
+ if (row.state?.pendingQuestions?.some((question) => question?.kind === DIALOG)) {
2085
+ const queued = enqueueFollowUp(root, viewId, prompt, { kind: replyOpts.kind ?? "reply", delivery: "queue", source: "user" });
2086
+ return queued.ok ? { ok: true, queued: true, summary: queued.summary } : queued;
2087
+ }
2076
2088
  if (hasPendingQuestions(row)) return { ok: false, error: "Attach to answer the pending question" };
2077
2089
  const delivery = replyOpts.delivery ?? "auto";
2078
2090
  const kind = replyOpts.kind ?? "reply";