@huseynsnmz/pi-board 0.15.1 → 0.16.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 (215) hide show
  1. package/CHANGELOG.md +26 -4
  2. package/CONTRIBUTING.md +7 -0
  3. package/README.md +53 -419
  4. package/SECURITY.md +19 -0
  5. package/docs/how-it-works.md +31 -0
  6. package/docs/reference.md +276 -0
  7. package/package.json +18 -19
  8. package/src/index.ts +9 -1
  9. package/src/runtime/service.mjs +12 -0
  10. package/src/ui/dashboard.ts +14 -8
  11. package/src/ui/double-left.ts +5 -1
  12. package/src/ui/focus.ts +7 -1
  13. package/src/ui/waiting.ts +10 -5
  14. package/IMPLEMENTATION_PLAN.md +0 -920
  15. package/PRD.md +0 -484
  16. package/PROGRESS.md +0 -142
  17. package/VERIFY.md +0 -115
  18. package/docs/BATCH_SELECTION_READ_FLOW.md +0 -277
  19. package/docs/EXPLORATION.md +0 -187
  20. package/docs/PTY_ATTACH_IMPLEMENTATION_PLAN.md +0 -581
  21. package/docs/RELEASE.md +0 -148
  22. package/docs/superpowers/plans/2026-08-15-screenlog-gc.md +0 -704
  23. package/docs/superpowers/plans/2026-08-16-attach-double-cursor-jiggle-retry.md +0 -499
  24. package/docs/superpowers/plans/2026-08-21-attach-coldstart-jiggle-rearm.md +0 -797
  25. package/docs/superpowers/plans/2026-08-21-dashboard-keypress-lag.md +0 -366
  26. package/docs/superpowers/plans/2026-08-21-issue-14-needs-input-no-auto-done.md +0 -576
  27. package/docs/superpowers/plans/2026-08-22-jiggle-shrink-and-hold.md +0 -337
  28. package/docs/superpowers/plans/2026-08-22-launch-cwd-favorites.md +0 -916
  29. package/docs/superpowers/plans/2026-08-22-question-tool-grouping.md +0 -211
  30. package/docs/superpowers/plans/2026-08-22-rename-state-labels.md +0 -182
  31. package/docs/superpowers/plans/2026-08-22-stable-list-order.md +0 -51
  32. package/docs/superpowers/plans/2026-08-27-locks-acquirelock-spin.md +0 -614
  33. package/docs/superpowers/plans/2026-08-27-pty-runner-test-flaky.md +0 -32
  34. package/docs/superpowers/plans/2026-08-29-code-refs-badges.md +0 -223
  35. package/docs/superpowers/plans/2026-08-30-circular-navigation.md +0 -308
  36. package/docs/superpowers/plans/2026-08-30-post-exit-timing-fix.md +0 -37
  37. package/docs/superpowers/plans/2026-08-30-pty-attach-quality-debt.md +0 -311
  38. package/docs/superpowers/plans/2026-08-30-readme-v2.md +0 -294
  39. package/docs/superpowers/plans/2026-09-01-attach-detach-gate-cursor-anchor.md +0 -284
  40. package/docs/superpowers/plans/2026-09-02-attach-detach-editor-state.md +0 -722
  41. package/docs/superpowers/plans/2026-09-03-code-refs-pr-backlink-narrow.md +0 -551
  42. package/docs/superpowers/plans/2026-09-03-detach-gate-glyph-fallback.md +0 -146
  43. package/docs/superpowers/plans/2026-09-04-evidence-outputpreview.md +0 -209
  44. package/docs/superpowers/plans/2026-09-04-warm-host-reclaim.md +0 -796
  45. package/docs/superpowers/plans/2026-09-05-issue-13-drainnextfollowup-pty-probe.md +0 -114
  46. package/docs/superpowers/plans/2026-09-05-issue-38-windows-wezterm-ime-cursor.md +0 -73
  47. package/docs/superpowers/plans/2026-09-05-issue-39-truncate-codepoint-boundary.md +0 -143
  48. package/docs/superpowers/plans/2026-09-05-issue-61-mention-fallback-guards.md +0 -226
  49. package/docs/superpowers/plans/2026-09-05-issue-63-flaky-manual-completion.md +0 -87
  50. package/docs/superpowers/plans/2026-09-05-issue-64-changelog-release-helper.md +0 -53
  51. package/docs/superpowers/plans/2026-09-05-pty-host-stacking-sock-race.md +0 -731
  52. package/docs/superpowers/plans/2026-09-08-attach-ctrl-left-detach.md +0 -30
  53. package/docs/superpowers/plans/2026-09-08-dashboard-shrink-repaint.md +0 -68
  54. package/docs/superpowers/plans/2026-09-08-issue-11-attach-runtime-desync-heal.md +0 -917
  55. package/docs/superpowers/plans/2026-09-08-legacy-stale-host-recovery.md +0 -125
  56. package/docs/superpowers/plans/2026-09-08-spawn-async-error-swallow.md +0 -56
  57. package/docs/superpowers/plans/2026-09-08-stale-model-attach-guard.md +0 -96
  58. package/docs/superpowers/plans/2026-09-09-claimpid-blocks-replace.md +0 -267
  59. package/docs/superpowers/plans/2026-09-09-harden-runner-architecture.md +0 -603
  60. package/docs/superpowers/plans/2026-09-09-single-writer-completion.md +0 -252
  61. package/docs/superpowers/plans/2026-09-10-reader-consistency.md +0 -115
  62. package/docs/superpowers/plans/2026-09-14-attach-cursor-dectcem-gate.md +0 -469
  63. package/docs/superpowers/plans/2026-09-14-attach-snapshot.md +0 -92
  64. package/docs/superpowers/plans/2026-09-14-host-meta-orphan-lock.md +0 -771
  65. package/docs/superpowers/plans/2026-09-14-issue-106-terminal-frame-cognition.md +0 -299
  66. package/docs/superpowers/plans/2026-09-14-issue-113-foreground-preview-race.md +0 -609
  67. package/docs/superpowers/plans/2026-09-14-terminal-model.md +0 -145
  68. package/docs/superpowers/plans/2026-09-15-coordinator-pipe-root-normalize.md +0 -224
  69. package/docs/superpowers/plans/2026-09-15-lease-publish-eprem-reclaim.md +0 -341
  70. package/docs/superpowers/plans/2026-09-18-detach-anchor-reporter-endpoint.md +0 -875
  71. package/docs/superpowers/plans/2026-09-20-control-lifecycle.md +0 -116
  72. package/docs/superpowers/plans/2026-09-20-issue-121-perf-gate-out-of-coverage.md +0 -517
  73. package/docs/superpowers/plans/2026-09-23-a5-mid-stream-assertion.md +0 -25
  74. package/docs/superpowers/plans/2026-09-23-cwd-browse-tab-drill.md +0 -393
  75. package/docs/superpowers/plans/2026-09-23-terminal-query-forwarding.md +0 -51
  76. package/docs/superpowers/plans/2026-09-23-unconditional-detach-key.md +0 -58
  77. package/docs/superpowers/plans/2026-09-24-control-reconcile-flake.md +0 -698
  78. package/docs/superpowers/plans/2026-09-24-probe-attached-clients.md +0 -605
  79. package/docs/superpowers/plans/2026-09-29-issue-145-holding-semantic-state.md +0 -1183
  80. package/docs/superpowers/plans/2026-09-29-issue-145-user-verification.md +0 -66
  81. package/docs/superpowers/plans/2026-09-30-board-delete-key-x-y-confirm.md +0 -649
  82. package/docs/superpowers/plans/2026-09-30-issue-153-runner-stop-boot-window.md +0 -618
  83. package/docs/superpowers/plans/2026-09-30-issue-95-test-discipline.md +0 -555
  84. package/docs/superpowers/plans/2026-09-30-publish-dispatch-tag-check.md +0 -259
  85. package/docs/superpowers/plans/2026-10-06-attach-settle-scheme-delivery.md +0 -751
  86. package/docs/superpowers/plans/2026-10-09-issue-167-attach-middle-paste.md +0 -509
  87. package/docs/superpowers/plans/2026-10-09-issue-169-fullscreen-mouse-ownership.md +0 -346
  88. package/docs/superpowers/plans/2026-10-10-attach-delete-in-place.md +0 -832
  89. package/docs/superpowers/plans/2026-10-10-issue-174-selection-mirror-paste-source.md +0 -510
  90. package/docs/superpowers/plans/2026-10-14-issue-170-attach-reply-guard.md +0 -771
  91. package/docs/superpowers/plans/2026-10-14-issue-178-accept-registration-race.md +0 -1257
  92. package/docs/superpowers/plans/2026-10-14-issue-184-snapshot-window-contract.md +0 -657
  93. package/docs/superpowers/plans/2026-10-14-issue-185-attach-wheel-alt-screen.md +0 -47
  94. package/docs/superpowers/plans/2026-10-14-issue-187-motionless-drag.md +0 -931
  95. package/docs/superpowers/plans/2026-10-14-issue-189-mixed-input-segments.md +0 -823
  96. package/docs/superpowers/plans/2026-10-15-issue-188-x10-mouse-release.md +0 -526
  97. package/docs/superpowers/plans/2026-10-16-issue-198-attach-wheel-forward-fallback.md +0 -32
  98. package/docs/superpowers/plans/2026-10-18-attach-wheel-replay-pseudo-scrollback.md +0 -437
  99. package/docs/superpowers/plans/2026-10-19-issue-213-reply-guard-csi-key.md +0 -257
  100. package/docs/superpowers/plans/2026-10-19-issue-214-attach-forward-alt-modifier.md +0 -202
  101. package/docs/superpowers/plans/2026-10-21-issue-221-ask-user-question.md +0 -198
  102. package/docs/superpowers/plans/2026-10-23-issue-222-attach-ready.md +0 -290
  103. package/docs/superpowers/plans/2026-10-23-issue-225-monotonic-foreground-state.md +0 -450
  104. package/docs/superpowers/plans/2026-10-23-issue-229-vim-jkl.md +0 -449
  105. package/docs/superpowers/plans/2026-10-23-issue-232-attach-bg-only-cells.md +0 -153
  106. package/docs/superpowers/plans/2026-10-23-lease-heartbeat-staleness.md +0 -537
  107. package/docs/superpowers/plans/2026-10-23-selected-row-highlight.md +0 -405
  108. package/docs/superpowers/plans/2026-10-24-issue-217-windows-pid-reuse-stopping.md +0 -367
  109. package/docs/superpowers/plans/2026-10-24-issue-230-warm-host-background-runs.md +0 -806
  110. package/docs/superpowers/plans/2026-10-24-issue-238-windows-process-identity-token.md +0 -490
  111. package/docs/superpowers/plans/2026-10-24-issue-241-coordinator-root-exit.md +0 -461
  112. package/docs/superpowers/plans/2026-10-25-issue-239-coordinator-replacement-identity.md +0 -504
  113. package/docs/superpowers/plans/2026-10-26-issue-245-key-hints-doc-sync.md +0 -244
  114. package/docs/superpowers/plans/2026-10-27-issue-172-fullscreen-selection-clear.md +0 -344
  115. package/docs/superpowers/plans/2026-10-27-issue-252-select-key-hints.md +0 -209
  116. package/docs/superpowers/plans/2026-10-28-issue-255-coordinator-endpoint-zombie.md +0 -442
  117. package/docs/superpowers/plans/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup.md +0 -256
  118. package/docs/superpowers/plans/2026-11-03-cwd-favorites-full-pool.md +0 -266
  119. package/docs/superpowers/specs/2026-08-15-screenlog-gc-design.md +0 -105
  120. package/docs/superpowers/specs/2026-08-16-attach-double-cursor-jiggle-retry-design.md +0 -142
  121. package/docs/superpowers/specs/2026-08-21-attach-coldstart-jiggle-rearm-design.md +0 -110
  122. package/docs/superpowers/specs/2026-08-21-dashboard-keypress-lag-design.md +0 -59
  123. package/docs/superpowers/specs/2026-08-21-issue-14-needs-input-no-auto-done-design.md +0 -109
  124. package/docs/superpowers/specs/2026-08-22-cwd-favorites-design.md +0 -131
  125. package/docs/superpowers/specs/2026-08-22-jiggle-shrink-and-hold-design.md +0 -111
  126. package/docs/superpowers/specs/2026-08-22-question-tool-grouping-design.md +0 -114
  127. package/docs/superpowers/specs/2026-08-22-rename-state-labels-design.md +0 -80
  128. package/docs/superpowers/specs/2026-08-27-locks-acquirelock-spin-design.md +0 -97
  129. package/docs/superpowers/specs/2026-08-27-pty-runner-test-flaky-design.md +0 -35
  130. package/docs/superpowers/specs/2026-08-29-code-refs-badges-design.md +0 -128
  131. package/docs/superpowers/specs/2026-08-30-circular-navigation-design.md +0 -47
  132. package/docs/superpowers/specs/2026-08-30-eprm-atomicwrite-race-design.md +0 -77
  133. package/docs/superpowers/specs/2026-08-30-post-exit-timing-fix-design.md +0 -80
  134. package/docs/superpowers/specs/2026-08-30-pty-attach-quality-debt-design.md +0 -105
  135. package/docs/superpowers/specs/2026-08-30-readme-v2-design.md +0 -115
  136. package/docs/superpowers/specs/2026-09-01-attach-detach-gate-cursor-anchor-design.md +0 -78
  137. package/docs/superpowers/specs/2026-09-02-attach-detach-editor-state-design.md +0 -120
  138. package/docs/superpowers/specs/2026-09-03-code-refs-pr-backlink-narrow-design.md +0 -92
  139. package/docs/superpowers/specs/2026-09-03-detach-gate-glyph-fallback-design.md +0 -99
  140. package/docs/superpowers/specs/2026-09-04-evidence-outputpreview-design.md +0 -50
  141. package/docs/superpowers/specs/2026-09-04-warm-host-reclaim-design.md +0 -106
  142. package/docs/superpowers/specs/2026-09-05-issue-13-drainnextfollowup-pty-probe-design.md +0 -64
  143. package/docs/superpowers/specs/2026-09-05-issue-38-windows-wezterm-ime-design.md +0 -48
  144. package/docs/superpowers/specs/2026-09-05-issue-39-truncate-codepoint-boundary-design.md +0 -64
  145. package/docs/superpowers/specs/2026-09-05-issue-61-mention-fallback-design.md +0 -71
  146. package/docs/superpowers/specs/2026-09-05-issue-63-flaky-manual-completion-design.md +0 -49
  147. package/docs/superpowers/specs/2026-09-05-issue-64-changelog-helper-design.md +0 -76
  148. package/docs/superpowers/specs/2026-09-05-pty-host-stacking-sock-race-design.md +0 -510
  149. package/docs/superpowers/specs/2026-09-07-issue-11-attach-runtime-desync-heal-design.md +0 -130
  150. package/docs/superpowers/specs/2026-09-08-attach-ctrl-left-detach-design.md +0 -58
  151. package/docs/superpowers/specs/2026-09-08-dashboard-shrink-repaint-design.md +0 -52
  152. package/docs/superpowers/specs/2026-09-08-legacy-stale-host-recovery-design.md +0 -87
  153. package/docs/superpowers/specs/2026-09-08-spawn-async-error-swallow-design.md +0 -56
  154. package/docs/superpowers/specs/2026-09-08-stale-model-attach-guard-design.md +0 -79
  155. package/docs/superpowers/specs/2026-09-09-claimpid-blocks-replace-design.md +0 -147
  156. package/docs/superpowers/specs/2026-09-09-harden-runner-architecture-design.md +0 -304
  157. package/docs/superpowers/specs/2026-09-14-attach-cursor-dectcem-gate-design.md +0 -114
  158. package/docs/superpowers/specs/2026-09-14-host-meta-orphan-lock-design.md +0 -120
  159. package/docs/superpowers/specs/2026-09-14-issue-106-terminal-frame-cognition-design.md +0 -146
  160. package/docs/superpowers/specs/2026-09-14-issue-113-foreground-preview-race-design.md +0 -116
  161. package/docs/superpowers/specs/2026-09-15-coordinator-pipe-root-normalize-design.md +0 -84
  162. package/docs/superpowers/specs/2026-09-15-lease-publish-eprem-reclaim-design.md +0 -92
  163. package/docs/superpowers/specs/2026-09-18-detach-anchor-reporter-endpoint-design.md +0 -123
  164. package/docs/superpowers/specs/2026-09-20-issue-121-perf-gate-out-of-coverage-design.md +0 -204
  165. package/docs/superpowers/specs/2026-09-23-a5-mid-stream-assertion-design.md +0 -43
  166. package/docs/superpowers/specs/2026-09-23-cwd-browse-tab-drill-design.md +0 -95
  167. package/docs/superpowers/specs/2026-09-23-terminal-query-forwarding-design.md +0 -63
  168. package/docs/superpowers/specs/2026-09-23-unconditional-detach-key-design.md +0 -57
  169. package/docs/superpowers/specs/2026-09-24-control-reconcile-flake-design.md +0 -98
  170. package/docs/superpowers/specs/2026-09-24-probe-attached-clients-design.md +0 -190
  171. package/docs/superpowers/specs/2026-09-29-issue-145-holding-semantic-state-design.md +0 -394
  172. package/docs/superpowers/specs/2026-09-30-board-delete-key-x-y-confirm-design.md +0 -86
  173. package/docs/superpowers/specs/2026-09-30-issue-153-runner-stop-boot-window-design.md +0 -75
  174. package/docs/superpowers/specs/2026-09-30-issue-95-test-discipline-design.md +0 -226
  175. package/docs/superpowers/specs/2026-09-30-publish-dispatch-tag-check-design.md +0 -129
  176. package/docs/superpowers/specs/2026-10-06-attach-settle-scheme-delivery-design.md +0 -196
  177. package/docs/superpowers/specs/2026-10-09-issue-167-attach-middle-paste-design.md +0 -125
  178. package/docs/superpowers/specs/2026-10-09-issue-169-fullscreen-mouse-ownership-design.md +0 -130
  179. package/docs/superpowers/specs/2026-10-10-attach-delete-in-place-design.md +0 -224
  180. package/docs/superpowers/specs/2026-10-10-issue-174-selection-mirror-paste-source-design.md +0 -154
  181. package/docs/superpowers/specs/2026-10-14-issue-170-attach-reply-guard-design.md +0 -195
  182. package/docs/superpowers/specs/2026-10-14-issue-178-accept-registration-race-design.md +0 -287
  183. package/docs/superpowers/specs/2026-10-14-issue-184-snapshot-window-contract-design.md +0 -288
  184. package/docs/superpowers/specs/2026-10-14-issue-185-attach-wheel-alt-screen-design.md +0 -126
  185. package/docs/superpowers/specs/2026-10-14-issue-187-motionless-drag-design.md +0 -269
  186. package/docs/superpowers/specs/2026-10-14-issue-189-mixed-input-segments-design.md +0 -369
  187. package/docs/superpowers/specs/2026-10-15-issue-188-x10-mouse-release-design.md +0 -252
  188. package/docs/superpowers/specs/2026-10-16-issue-198-attach-wheel-forward-fallback-design.md +0 -67
  189. package/docs/superpowers/specs/2026-10-18-attach-wheel-replay-pseudo-scrollback-design.md +0 -250
  190. package/docs/superpowers/specs/2026-10-19-issue-213-reply-guard-csi-key-design.md +0 -165
  191. package/docs/superpowers/specs/2026-10-19-issue-214-attach-forward-alt-modifier-design.md +0 -131
  192. package/docs/superpowers/specs/2026-10-20-issue-221-ask-user-question-design.md +0 -270
  193. package/docs/superpowers/specs/2026-10-22-issue-225-monotonic-foreground-state-design.md +0 -225
  194. package/docs/superpowers/specs/2026-10-23-issue-222-attach-ready-design.md +0 -204
  195. package/docs/superpowers/specs/2026-10-23-issue-229-vim-jkl-design.md +0 -90
  196. package/docs/superpowers/specs/2026-10-23-issue-232-attach-bg-only-cells-design.md +0 -146
  197. package/docs/superpowers/specs/2026-10-23-lease-heartbeat-staleness-design.md +0 -271
  198. package/docs/superpowers/specs/2026-10-23-selected-row-highlight-design.md +0 -191
  199. package/docs/superpowers/specs/2026-10-24-issue-217-windows-pid-reuse-stopping-design.md +0 -334
  200. package/docs/superpowers/specs/2026-10-24-issue-230-warm-host-background-runs-design.md +0 -283
  201. package/docs/superpowers/specs/2026-10-24-issue-238-windows-process-identity-token-design.md +0 -286
  202. package/docs/superpowers/specs/2026-10-24-issue-241-coordinator-root-exit-design.md +0 -381
  203. package/docs/superpowers/specs/2026-10-25-issue-239-coordinator-replacement-identity-design.md +0 -331
  204. package/docs/superpowers/specs/2026-10-26-issue-245-key-hints-doc-sync-design.md +0 -72
  205. package/docs/superpowers/specs/2026-10-27-issue-172-fullscreen-selection-clear-design.md +0 -248
  206. package/docs/superpowers/specs/2026-10-27-issue-252-select-key-hints-design.md +0 -95
  207. package/docs/superpowers/specs/2026-10-28-issue-255-coordinator-endpoint-zombie-design.md +0 -380
  208. package/docs/superpowers/specs/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup-design.md +0 -197
  209. package/docs/superpowers/specs/2026-11-03-cwd-favorites-full-pool-design.md +0 -106
  210. package/scripts/budget-audit.mjs +0 -135
  211. package/scripts/patch-vulns.mjs +0 -59
  212. package/scripts/release.mjs +0 -446
  213. package/scripts/release_helper.mjs +0 -309
  214. package/scripts/run-perf-gate.mjs +0 -40
  215. package/scripts/run-tests.mjs +0 -375
@@ -1,284 +0,0 @@
1
- # ← Detach Gate Cursor-Anchor Fix Implementation Plan
2
-
3
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
-
5
- **Goal:** Fix issue #66 — `←` must detach when the Pi editor line is empty even while the terminal cursor rests on working/output lines (attach / streaming).
6
-
7
- **Architecture:** Replace the cursor-line anchor in `PtyAttachComponent.childInputLooksEmpty()` with a bottom-up scan for Pi's inverse-video fake-cursor cell (`ESC[7m`, persists in the xterm buffer across differential frames), with a prompt-glyph fallback and a "treat as empty" escape fallback. Add a pure helper `isProbablyPiInputLine` for glyph detection.
8
-
9
- **Tech Stack:** TypeScript (pty-attach.ts, run via `node --experimental-transform-types` in tests), plain ESM (pty-input.mjs), `node:test` runner, @xterm/headless.
10
-
11
- **Spec:** `docs/superpowers/specs/2026-09-01-attach-detach-gate-cursor-anchor-design.md`
12
-
13
- ## Global Constraints
14
-
15
- - Coverage gates: lines 85 / funcs 80 / branches 70 (c8, `npm run test:coverage`); Node 22/24 both green (CI).
16
- - `isProbablyPiInputLine` glyph set must stay identical to `isProbablyEmptyPiInputLine`'s trim charset: `›>┃│|┆╎╏:`.
17
- - Do not change `ctrl+]` semantics (passes through to Pi since v0.5.1) and do not make `←` unconditionally detach (keeps the edit-protection gate — spec §3).
18
- - Do not modify `src/core/pty-input.mjs`'s existing `isProbablyEmptyPiInputLine` behavior.
19
- - All edits inside worktree `WT=.pi/worktrees/issue-66-attach-detach-gate-cursor-anchor`; git ops via `git -C $WT`.
20
-
21
- ---
22
-
23
- ### Task 1: Add `isProbablyPiInputLine` pure helper + unit tests
24
-
25
- **Files:**
26
- - Modify: `src/core/pty-input.mjs` (append glyph const + function after existing helper)
27
- - Test: `test/pty-input.test.mjs`
28
-
29
- **Interfaces:**
30
- - Produces: `export function isProbablyPiInputLine(line: string): boolean` — true iff the line, after trimming leading whitespace, starts with a prompt/continuation glyph.
31
-
32
- - [ ] **Step 1: Write the failing test**
33
-
34
- Append to `test/pty-input.test.mjs` (keep existing tests untouched):
35
-
36
- ```js
37
- import { isProbablyEmptyPiInputLine, isProbablyPiInputLine } from "../src/core/pty-input.mjs";
38
-
39
- test("isProbablyPiInputLine recognizes Pi prompt / continuation lines", () => {
40
- assert.equal(isProbablyPiInputLine("> "), true);
41
- assert.equal(isProbablyPiInputLine(" ┃ edit me"), true);
42
- assert.equal(isProbablyPiInputLine(" │ second line"), true);
43
- assert.equal(isProbablyPiInputLine("› draft"), true);
44
- });
45
-
46
- test("isProbablyPiInputLine rejects content lines and empty lines", () => {
47
- assert.equal(isProbablyPiInputLine("chat content"), false);
48
- assert.equal(isProbablyPiInputLine("────── ◊◊ ──────"), false);
49
- assert.equal(isProbablyPiInputLine(""), false);
50
- assert.equal(isProbablyPiInputLine(" "), false);
51
- });
52
- ```
53
-
54
- - [ ] **Step 2: Run test to verify it fails**
55
-
56
- Run: `node --test test/pty-input.test.mjs`
57
- Expected: FAIL — `isProbablyPiInputLine is not a function` (import error).
58
-
59
- - [ ] **Step 3: Write minimal implementation**
60
-
61
- Append to `src/core/pty-input.mjs` (before `isProbablyEmptyPiInputLine` or after — any top-level position):
62
-
63
- ```js
64
- /** Glyphs Pi uses to render editor prompt / continuation lines (`>` main prompt,
65
- * `›`/`┃`/`│` and variants in older releases). Must stay in sync with the
66
- * trim charset of isProbablyEmptyPiInputLine below. */
67
- const PROMPT_GLYPHS = "›>┃│|┆╎╏:";
68
-
69
- /**
70
- * Whether the given terminal line looks like a Pi editor input line: leading
71
- * whitespace followed by a prompt/continuation glyph. The attach surface uses
72
- * this to locate the editor line inside the buffer instead of trusting the
73
- * terminal cursor, which wanders onto output/working lines while Pi streams
74
- * (issue #66).
75
- * @param {string} line
76
- * @returns {boolean}
77
- */
78
- export function isProbablyPiInputLine(line) {
79
- const withoutLeftPadding = String(line || "").replace(/^[\s\u00a0]+/u, "");
80
- return withoutLeftPadding.length > 0 && PROMPT_GLYPHS.includes(withoutLeftPadding[0]);
81
- }
82
- ```
83
-
84
- - [ ] **Step 4: Run test to verify it passes**
85
-
86
- Run: `node --test test/pty-input.test.mjs`
87
- Expected: PASS (4 tests: 2 existing + 2 new).
88
-
89
- - [ ] **Step 5: Commit**
90
-
91
- ```bash
92
- git add test/pty-input.test.mjs src/core/pty-input.mjs
93
- git commit -m "feat: add isProbablyPiInputLine helper (issue #66)"
94
- ```
95
-
96
- ---
97
-
98
- ### Task 2: Rework `childInputLooksEmpty()` anchor + smoke scenarios
99
-
100
- **Files:**
101
- - Modify: `src/ui/pty-attach.ts` (import line ~8; `childInputLooksEmpty()` ~line 319; add private helper near it)
102
- - Modify: `test-support/detach-gate-smoke.ts` (scenarios B/B1/B2/B3 + new E)
103
- - Modify: `test/pty-attach-detach-gate.test.mjs` (assertions)
104
-
105
- **Interfaces:**
106
- - Consumes: `isProbablyPiInputLine` from Task 1; existing `isProbablyEmptyPiInputLine`.
107
- - Produces: private `findLastInverseCellLine(active): number | null` — bottom-most line index containing an `isInverse()` cell; `null` when none.
108
-
109
- - [ ] **Step 1: Write the failing smoke scenarios**
110
-
111
- In `test-support/detach-gate-smoke.ts`:
112
-
113
- 1. Change scenario **B** (line ~76) so the draft line carries a fake cursor, then add B3 (cursor off the empty input line) and E (empty input line without fake cursor). Replace the current B block and append:
114
-
115
- ```ts
116
- // B. ← must NOT detach while attached with a draft in the editor line (child
117
- // is mid-draft and ← is also the editor's cursor-left key). The draft line
118
- // carries Pi's inverse-video fake cursor (ESC[7m).
119
- {
120
- const { attach, sent, didDetach } = makeAttach();
121
- await writeToTerm(attach, "chat content\r\n> \x1b[7m草\x1b[27m稿");
122
- (attach as unknown as { connected: boolean }).connected = true;
123
- attach.handleInput("\x1b[D");
124
- out.leftStaysGatedOnNonEmptyLine = !didDetach() && sent.length === 1 && sent[0].type === "input" && sent[0].data === "\x1b[D";
125
- attach.dispose();
126
- }
127
-
128
- // B3. The streaming case from issue #66: the editor line is empty (bottom of
129
- // the buffer, with its fake cursor) but the terminal cursor rests on the
130
- // working line because Pi's differential frames only repaint the changed
131
- // line. The gate must be judged from the fake-cursor line, not the cursor.
132
- {
133
- const { attach, sent, didDetach } = makeAttach();
134
- await writeToTerm(attach, "chat content\r\n> \x1b[7m \x1b[27m");
135
- await writeToTerm(attach, "\x1b[2;1H⠙ Working...");
136
- (attach as unknown as { connected: boolean }).connected = true;
137
- attach.handleInput("\x1b[D");
138
- out.leftDetachesWhenCursorOffEmptyInputLine = didDetach() && sent.length === 0;
139
- attach.dispose();
140
- }
141
-
142
- // E. Empty input line rendered WITHOUT a fake cursor: no inverse cell and no
143
- // glyph anywhere, and the terminal cursor sits on a non-empty output line.
144
- // Falls through to the escape fallback — treat as empty, detach.
145
- {
146
- const { attach, sent, didDetach } = makeAttach();
147
- await writeToTerm(attach, "chat content\r\n");
148
- await writeToTerm(attach, "\x1b[1;1H"); // park the cursor on the non-empty line
149
- (attach as unknown as { connected: boolean }).connected = true;
150
- attach.handleInput("\x1b[D");
151
- out.leftDetachesOnEmptyInputWithoutFakeCursor = didDetach() && sent.length === 0;
152
- attach.dispose();
153
- }
154
- ```
155
-
156
- 2. Update the B1 header comment (scenario text already fits) and ensure B1 (`────── ◊◊ ──────` garbled buffer) stays as-is — it now asserts escape-on-garbled-buffer.
157
-
158
- - [ ] **Step 2: Run smoke to verify new scenarios fail**
159
-
160
- Run: `node --experimental-transform-types test-support/detach-gate-smoke.ts`
161
- Expected: `leftDetachesWhenCursorOffEmptyInputLine` is `false` (old cursor-line anchor reads the Working line) and `leftDetachesOnEmptyInputWithoutFakeCursor` is `false` (old anchor reads last non-empty line `chat content`? — verify output); `leftStaysGatedOnNonEmptyLine` true.
162
-
163
- - [ ] **Step 3: Write the implementation**
164
-
165
- In `src/ui/pty-attach.ts`:
166
-
167
- 1. Update import (line ~8):
168
-
169
- ```ts
170
- import { isProbablyEmptyPiInputLine, isProbablyPiInputLine } from "../core/pty-input.mjs";
171
- ```
172
-
173
- 2. Replace the `childInputLooksEmpty()` method (currently ~line 319) and add the helper above it:
174
-
175
- ```ts
176
- /** Bottom-most line whose cells include an inverse-video cell — Pi renders
177
- * its editor cursor as an inverse "fake cursor" (`ESC[7m`), and the cell
178
- * persists in the buffer even while streaming differential frames skip
179
- * repainting the editor line. */
180
- private findLastInverseCellLine(active: {
181
- baseY: number;
182
- length: number;
183
- getLine(index: number): BufferLineLike | undefined;
184
- }): number | null {
185
- for (let y = active.baseY + active.length - 1; y >= active.baseY; y--) {
186
- const line = active.getLine(y);
187
- if (!line) continue;
188
- for (let x = 0; x < line.length; x++) {
189
- if (line.getCell(x)?.isInverse()) return y;
190
- }
191
- }
192
- return null;
193
- }
194
-
195
- private childInputLooksEmpty(): boolean {
196
- if (!this.receivedOutput) return true;
197
- const active = this.term.buffer.active;
198
- // The terminal cursor is not a reliable anchor for the editor line:
199
- // while Pi streams output (or right after attach) the cursor rests on
200
- // working/output lines, never the input line, so a genuinely empty
201
- // editor was misread as non-empty and ← stopped detaching (issue #66).
202
- // Pi's editor line always carries an inverse-video fake-cursor cell,
203
- // so anchor on that instead.
204
- const fakeCursorLine = this.findLastInverseCellLine(active);
205
- if (fakeCursorLine !== null) {
206
- const line = active.getLine(fakeCursorLine)?.translateToString(true) ?? "";
207
- return isProbablyEmptyPiInputLine(line);
208
- }
209
- // Fallback: Pi variants that render no fake cursor — look for a
210
- // prompt-glyph line.
211
- for (let y = active.baseY + active.length - 1; y >= active.baseY; y--) {
212
- const line = active.getLine(y)?.translateToString(true) ?? "";
213
- if (isProbablyPiInputLine(line)) return isProbablyEmptyPiInputLine(line);
214
- }
215
- // No editor line recoverable (e.g. a garbled replay buffer): treat the
216
- // input as empty — ← is the only detach key left on the attach surface,
217
- // so it must always escape rather than trap the user.
218
- return true;
219
- }
220
- ```
221
-
222
- - [ ] **Step 4: Update gate assertions**
223
-
224
- In `test/pty-attach-detach-gate.test.mjs`, add to the existing test (after `leftDetachesOnEmptyInput`):
225
-
226
- ```js
227
- assert.equal(parsed.leftDetachesWhenCursorOffEmptyInputLine, true, "← must detach when the editor line is empty even if the cursor sits on a working line");
228
- assert.equal(parsed.leftDetachesOnEmptyInputWithoutFakeCursor, true, "← must detach when an empty editor line renders no fake cursor");
229
- ```
230
-
231
- - [ ] **Step 5: Run tests to verify pass**
232
-
233
- Run: `node --test test/pty-attach-detach-gate.test.mjs test/pty-input.test.mjs`
234
- Expected: PASS — all gate assertions true, including the three new ones.
235
-
236
- - [ ] **Step 6: Commit**
237
-
238
- ```bash
239
- git add src/ui/pty-attach.ts test-support/detach-gate-smoke.ts test/pty-attach-detach-gate.test.mjs
240
- git commit -m "fix: anchor ← detach gate on Pi's fake-cursor line, not terminal cursor (issue #66)"
241
- ```
242
-
243
- ---
244
-
245
- ### Task 3: Full regression (A6)
246
-
247
- **Files:** none (verification only).
248
-
249
- - [ ] **Step 1: Run verify**
250
-
251
- Run (in worktree): `npm run verify`
252
- Expected: typecheck clean; all `node --test test/*.test.mjs` pass (325+ tests, none of the pre-existing ones changed semantics); c8 coverage above gates (lines ≥85 / funcs ≥80 / branches ≥70); `npm pack --dry-run` succeeds.
253
-
254
- - [ ] **Step 2: Commit any incidental fixes**
255
-
256
- If verify surfaced issues, fix and commit with a message referencing issue #66. Otherwise nothing to commit.
257
-
258
- ---
259
-
260
- ### Task 4: Post-implementation manual verification (U1, U2)
261
-
262
- **Files:** none (user verification; report back into the PR).
263
-
264
- - [ ] **Step 1: U1 — attach-then-←**
265
-
266
- 1. Start agent-board, attach into an existing pi session (or create a new one).
267
- 2. As soon as the attach surface paints, press `←`.
268
- Expected: returns to the dashboard immediately, no ↑/↓ or type-then-delete needed.
269
-
270
- - [ ] **Step 2: U2 — ← while Pi is thinking**
271
-
272
- 1. Attach into a session and send a prompt that triggers Pi streaming (`⠹ Working...` animation visible).
273
- 2. While the animation is running, press `←`.
274
- Expected: returns to the dashboard. (Fails before this fix — the exact reported symptom.)
275
-
276
- - [ ] **Step 3: Sanity — ← does not steal the editor's cursor-left**
277
-
278
- 1. Attach, type a draft in the input box.
279
- 2. Press `←`.
280
- Expected: cursor moves left inside the draft (key forwarded), NOT detach.
281
-
282
- - [ ] **Step 4: Record results**
283
-
284
- Write the U1/U2/U3 outcomes into the PR description (or a PR comment) before merge.