@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,366 +0,0 @@
1
- # Dashboard Keypress Lag 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:** Eliminate perceptible ↑/↓ selection lag on the dashboard by moving prewarm off the keypress path, skipping artifact loads for archived views, and stopping forced PTY probes (issue #9).
6
-
7
- **Architecture:** Three independent fixes: (A) a debounced prewarm scheduler so arrow keys only mutate selection and trigger a render; (B) an archived short-circuit in `listRows` so the 700ms poll (`reconcile()` + `refresh()` + `render()` each call it) stops reading ~10 artifact files per archived view; (C) `ensureHost` no longer forces `ptySupport({refresh:true})`, which spawned a probe process on every keypress when PTY support is broken.
8
-
9
- **Tech Stack:** Node 20+, TypeScript (`.ts` UI) + ESM JavaScript (`.mjs` core), `node --test` test runner, no new dependencies.
10
-
11
- ## Global Constraints
12
-
13
- - No new npm dependencies.
14
- - All commits in this worktree branch `issue-9-dashboard-keypress-lag`; never touch `main` checkout.
15
- - `git add` per-file; never `git add -A`.
16
- - Commit messages in English, conventional-commits format, reference `issue #9`.
17
- - `npm run verify` (typecheck + tests + pack dry-run) must pass before the PR.
18
- - Core modules are `.mjs` with JSDoc types; UI is `.ts`. Follow existing file conventions.
19
-
20
- ---
21
-
22
- ### Task 1: `listRows` archived short-circuit (Fix B)
23
-
24
- **Files:**
25
- - Modify: `src/core/store.mjs` (function `listRows`, around line 220)
26
- - Test: `test/store.test.mjs` (append new test)
27
-
28
- **Interfaces:**
29
- - Consumes: existing `readMeta(root, viewId)`, `loadRow(root, viewId)` from `src/core/store.mjs`.
30
- - Produces: unchanged `listRows(root, opts)` signature and return type. Callers (`service.mjs` `reconcile()`/`rows()`/`pruneWarmHosts()`, `dashboard.ts` render) need no changes.
31
-
32
- - [ ] **Step 1: Write the safety-net test**
33
-
34
- Note: `readJson` swallows missing/corrupt files with a null fallback (`src/core/atomic.mjs`), so the archived short-circuit has no black-box failure mode — pre-fix and post-fix output is identical; the difference is pure IO volume, proven by the Task 4 real-store measurement. This test instead pins the behavioral contract that makes the short-circuit safe: archived views whose artifact files are absent/stale must not break `listRows`, and `includeArchived` semantics stay unchanged.
35
-
36
- Append to `test/store.test.mjs` (imports `createView`, `listRows`, `writeMeta`, `P` are already at top; add `rmSync`/`writeFileSync`/`mkdirSync` to the existing `node:fs` import if missing):
37
-
38
- ```js
39
- test("listRows tolerates archived views with only meta.json", () => {
40
- const root = freshRoot();
41
- try {
42
- const live = createView(root, { id: "live1", name: "live", cwd: "/r" });
43
- for (const id of ["arch1", "arch2"]) {
44
- const meta = createView(root, { id, name: id, cwd: "/r" });
45
- meta.archived = true;
46
- writeMeta(root, meta);
47
- // Simulate the worst case the short-circuit must handle: archived view
48
- // dirs containing nothing but meta.json (no state/evidence/host files).
49
- rmSync(P.viewDir(root, id), { recursive: true, force: true });
50
- mkdirSync(P.viewDir(root, id), { recursive: true });
51
- writeFileSync(P.metaPath(root, id), JSON.stringify(meta));
52
- }
53
- const rows = listRows(root);
54
- assert.equal(rows.length, 1);
55
- assert.equal(rows[0].meta.id, live.id);
56
- const all = listRows(root, { includeArchived: true });
57
- assert.equal(all.length, 3);
58
- assert.equal(all.filter((r) => r.meta.archived).length, 2);
59
- } finally {
60
- rmSync(root, { recursive: true, force: true });
61
- }
62
- });
63
- ```
64
-
65
- - [ ] **Step 2: Run test to confirm green baseline**
66
-
67
- Run: `cd <worktree> && npm install --no-audit --no-fund 2>/dev/null; node --test test/store.test.mjs`
68
- Expected: PASS pre-fix (safety net — see Step 1 note). This test must stay green after the implementation change.
69
-
70
- - [ ] **Step 3: Write minimal implementation**
71
-
72
- In `src/core/store.mjs`, change `listRows`:
73
-
74
- ```js
75
- export function listRows(root, opts = {}) {
76
- const roster = readRoster(root);
77
- /** @type {Row[]} */
78
- const rows = [];
79
- for (const viewId of roster.views) {
80
- // Archived short-circuit: archived rows are invisible on the dashboard, so
81
- // never pay for their artifact files (state/evidence/host/diagnostics...).
82
- // meta.json is the single authoritative source of the archived flag.
83
- const meta = readMeta(root, viewId);
84
- if (!meta) continue;
85
- if (meta.archived && !opts.includeArchived) continue;
86
- const row = loadRow(root, viewId);
87
- if (!row) continue;
88
- if (row.meta.archived && !opts.includeArchived) continue;
89
- rows.push(row);
90
- }
91
- return rows;
92
- }
93
- ```
94
-
95
- (The second archived check is belt-and-suspenders in case `loadRow` re-reads a meta that changed between reads.)
96
-
97
- - [ ] **Step 4: Run test to verify it passes**
98
-
99
- Run: `node --test test/store.test.mjs`
100
- Expected: PASS, all tests in file green.
101
-
102
- - [ ] **Step 5: Commit**
103
-
104
- ```bash
105
- git add src/core/store.mjs test/store.test.mjs
106
- git commit -m "perf: skip artifact loading for archived views in listRows (issue #9)"
107
- ```
108
-
109
- ---
110
-
111
- ### Task 2: Debounced prewarm off the keypress path (Fix A)
112
-
113
- **Files:**
114
- - Create: `src/core/prewarm-schedule.mjs`
115
- - Create: `test/prewarm-schedule.test.mjs`
116
- - Modify: `src/ui/dashboard.ts` (fields near line 127, `moveSelection` ~L237, `refresh` ~L176, `dispose` ~L1086)
117
-
118
- **Interfaces:**
119
- - Produces: `createPrewarmScheduler(prewarm: () => void, delayMs?: number): { schedule(): void; cancel(): void }` — single-flight debounce; repeated `schedule()` within `delayMs` fire `prewarm()` exactly once after the last call; `cancel()` clears the pending timer.
120
- - Consumes (dashboard.ts): existing private `prewarmSelected()`.
121
-
122
- - [ ] **Step 1: Write the failing test**
123
-
124
- `test/prewarm-schedule.test.mjs`:
125
-
126
- ```js
127
- import assert from "node:assert/strict";
128
- import { test } from "node:test";
129
- import { createPrewarmScheduler } from "../src/core/prewarm-schedule.mjs";
130
-
131
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
132
-
133
- test("rapid schedules fire prewarm once after quiet period", async () => {
134
- let fired = 0;
135
- const s = createPrewarmScheduler(() => { fired += 1; }, 15);
136
- s.schedule();
137
- s.schedule();
138
- s.schedule();
139
- await sleep(5);
140
- assert.equal(fired, 0); // still debouncing
141
- await sleep(25);
142
- assert.equal(fired, 1); // exactly once
143
- });
144
-
145
- test("cancel prevents prewarm entirely", async () => {
146
- let fired = 0;
147
- const s = createPrewarmScheduler(() => { fired += 1; }, 10);
148
- s.schedule();
149
- s.cancel();
150
- await sleep(30);
151
- assert.equal(fired, 0);
152
- });
153
-
154
- test("schedule after cancel works again", async () => {
155
- let fired = 0;
156
- const s = createPrewarmScheduler(() => { fired += 1; }, 10);
157
- s.schedule();
158
- s.cancel();
159
- s.schedule();
160
- await sleep(30);
161
- assert.equal(fired, 1);
162
- });
163
-
164
- test("prewarm errors do not crash the scheduler", async () => {
165
- let fired = 0;
166
- const s = createPrewarmScheduler(() => { fired += 1; throw new Error("boom"); }, 5);
167
- s.schedule();
168
- await sleep(20);
169
- assert.equal(fired, 1);
170
- s.schedule();
171
- await sleep(20);
172
- assert.equal(fired, 2);
173
- });
174
- ```
175
-
176
- - [ ] **Step 2: Run test to verify it fails**
177
-
178
- Run: `node --test test/prewarm-schedule.test.mjs`
179
- Expected: FAIL — cannot find module `../src/core/prewarm-schedule.mjs`.
180
-
181
- - [ ] **Step 3: Write minimal implementation**
182
-
183
- `src/core/prewarm-schedule.mjs`:
184
-
185
- ```js
186
- /**
187
- * Single-flight debounce for dashboard prewarm.
188
- *
189
- * Arrow-key navigation must move the selection and repaint immediately; host
190
- * prewarm (which may spawn a PTY host and re-scan rows) is deferred so bursts
191
- * of keypresses trigger exactly one prewarm for the final resting selection.
192
- */
193
-
194
- /**
195
- * @param {() => void} prewarm Invoked (with errors swallowed) once scheduling
196
- * goes quiet for `delayMs`. Re-reads current state at fire time.
197
- * @param {number} [delayMs=200]
198
- * @returns {{ schedule: () => void, cancel: () => void }}
199
- */
200
- export function createPrewarmScheduler(prewarm, delayMs = 200) {
201
- /** @type {ReturnType<typeof setTimeout> | null} */
202
- let timer = null;
203
- const fire = () => {
204
- timer = null;
205
- try {
206
- prewarm();
207
- } catch {
208
- /* prewarm is best-effort; never break navigation */
209
- }
210
- };
211
- return {
212
- schedule() {
213
- if (timer !== null) clearTimeout(timer);
214
- timer = setTimeout(fire, delayMs);
215
- },
216
- cancel() {
217
- if (timer !== null) {
218
- clearTimeout(timer);
219
- timer = null;
220
- }
221
- },
222
- };
223
- }
224
- ```
225
-
226
- - [ ] **Step 4: Run test to verify it passes**
227
-
228
- Run: `node --test test/prewarm-schedule.test.mjs`
229
- Expected: PASS (4 tests).
230
-
231
- - [ ] **Step 5: Wire into DashboardComponent**
232
-
233
- In `src/ui/dashboard.ts`:
234
-
235
- 1. Import: add near the other `../core/` imports:
236
- `import { createPrewarmScheduler } from "../core/prewarm-schedule.mjs";`
237
- 2. Add field (near `private prewarmedId: string | null = null;`):
238
- `private readonly prewarmScheduler = createPrewarmScheduler(() => this.prewarmSelected(), 200);`
239
- 3. `moveSelection()`: replace `this.prewarmSelected();` with `this.prewarmScheduler.schedule();`
240
- 4. `refresh()` (line ~176): replace `if (this.selectedId && this.selectedId !== previousSelected) this.prewarmSelected();` with `if (this.selectedId && this.selectedId !== previousSelected) this.prewarmScheduler.schedule();`
241
- 5. `prewarmSelected()`: add a mode guard as the first line so a timer firing after the user entered peek/session/launch modes does not prewarm the wrong target:
242
- `if (this.mode !== "list" && this.mode !== "select") return;`
243
- 6. `dispose()`: replace the comment-only body with `this.prewarmScheduler.cancel();` (keep the existing comment about poll interval ownership).
244
-
245
- - [ ] **Step 6: Typecheck + full tests**
246
-
247
- Run: `npx tsc --noEmit && node --test test/*.test.mjs`
248
- Expected: no type errors; all tests green.
249
-
250
- - [ ] **Step 7: Commit**
251
-
252
- ```bash
253
- git add src/core/prewarm-schedule.mjs test/prewarm-schedule.test.mjs src/ui/dashboard.ts
254
- git commit -m "perf: debounce dashboard prewarm off the keypress path (issue #9)"
255
- ```
256
-
257
- ---
258
-
259
- ### Task 3: `ensureHost` PTY probe TTL instead of forced refresh (Fix C)
260
-
261
- **Files:**
262
- - Modify: `src/runtime/service.mjs` (`ensureHost`, ~L674: `const pty = ptySupport({ refresh: true });`)
263
- - Test: `test/service.test.mjs` (append new test)
264
-
265
- **Interfaces:**
266
- - Consumes: existing injected `ptySupport(opts)` option of `createService`; existing test helper `service(root, overrides)` in `test/service.test.mjs`.
267
- - Produces: unchanged `ensureHost` return contract; only probe option semantics change (default = cached/TTL instead of forced refresh).
268
-
269
- - [ ] **Step 1: Write the failing test**
270
-
271
- Append to `test/service.test.mjs` (uses `createView`, `writeState`, `readState` imports already present; add `writeFileSync` if not imported):
272
-
273
- ```js
274
- test("ensureHost probes PTY support with TTL cache, not forced refresh", () => {
275
- const root = freshRoot();
276
- try {
277
- process.env.AGENT_BOARD_FORCE_PTY = "1";
278
- const meta = createView(root, { id: "v1", name: "a", cwd: "/r" });
279
- writeFileSync(meta.sessionFile, JSON.stringify({ type: "session", id: "s1", cwd: "/r" }) + "\n");
280
- const probeCalls = [];
281
- const svc = service(root, {
282
- ptySupport: (opts = {}) => { probeCalls.push(opts); return { ok: true }; },
283
- launchHost: () => ({ pid: process.pid, configPath: "/no/host-config.json" }),
284
- });
285
- const res = svc.ensureHost("v1");
286
- assert.equal(res.ok, true);
287
- assert.ok(probeCalls.length >= 1);
288
- for (const opts of probeCalls) {
289
- assert.notEqual(opts?.refresh, true, "ensureHost must not force ptySupport refresh");
290
- }
291
- } finally {
292
- delete process.env.AGENT_BOARD_FORCE_PTY;
293
- rmSync(root, { recursive: true, force: true });
294
- }
295
- });
296
- ```
297
-
298
- - [ ] **Step 2: Run test to verify it fails**
299
-
300
- Run: `node --test test/service.test.mjs`
301
- Expected: new test FAILS — `ensureHost` currently calls `ptySupport({ refresh: true })` so `opts.refresh === true`.
302
-
303
- - [ ] **Step 3: Write minimal implementation**
304
-
305
- In `src/runtime/service.mjs` `ensureHost`, change:
306
-
307
- ```js
308
- const pty = ptySupport({ refresh: true });
309
- ```
310
-
311
- to:
312
-
313
- ```js
314
- // Default probe semantics: success is cached for the process lifetime and a
315
- // failed probe retries on a short TTL. Forcing refresh here would spawn a
316
- // probe process on every keypress-driven prewarm when PTY support is broken.
317
- const pty = ptySupport();
318
- ```
319
-
320
- - [ ] **Step 4: Run test to verify it passes**
321
-
322
- Run: `node --test test/service.test.mjs`
323
- Expected: PASS, all tests in file green.
324
-
325
- - [ ] **Step 5: Commit**
326
-
327
- ```bash
328
- git add src/runtime/service.mjs test/service.test.mjs
329
- git commit -m "fix: stop forcing PTY probe refresh on every ensureHost (issue #9)"
330
- ```
331
-
332
- ---
333
-
334
- ### Task 4: Full verification + performance evidence
335
-
336
- **Files:**
337
- - No source changes expected (fix-only task; measurement script is throwaway, not committed).
338
-
339
- **Interfaces:**
340
- - Consumes: all previous tasks merged on the branch.
341
-
342
- - [ ] **Step 1: Install deps and run full verify**
343
-
344
- Run: `cd <worktree> && npm install --no-audit --no-fund && npm run verify`
345
- Expected: `tsc --noEmit` clean, all 27+ test files pass, `npm pack --dry-run` succeeds.
346
-
347
- - [ ] **Step 2: Measure real-store improvement (read-only)**
348
-
349
- Run against the user's real store (read-only, no mutation):
350
-
351
- ```bash
352
- node --input-type=module -e "
353
- import { listRows } from './src/core/store.mjs';
354
- import os from 'node:os'; import path from 'node:path';
355
- const root = path.join(os.homedir(), '.pi/agent/agent-board');
356
- listRows(root);
357
- const t0 = performance.now(); listRows(root); const t1 = performance.now();
358
- console.log('listRows post-fix:', (t1 - t0).toFixed(1), 'ms');
359
- "
360
- ```
361
-
362
- Expected: ≤ 40ms on the 168-view store (was 180–204ms). Record the number.
363
-
364
- - [ ] **Step 3: Report numbers**
365
-
366
- Paste before/after into the PR body and as an issue #9 comment. No commit needed for this task.