@huseynsnmz/pi-board 0.15.3 → 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 (211) hide show
  1. package/CHANGELOG.md +13 -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 +5 -11
  8. package/src/index.ts +1 -1
  9. package/src/runtime/service.mjs +12 -0
  10. package/src/ui/dashboard.ts +14 -8
  11. package/IMPLEMENTATION_PLAN.md +0 -920
  12. package/PRD.md +0 -484
  13. package/PROGRESS.md +0 -142
  14. package/VERIFY.md +0 -115
  15. package/docs/BATCH_SELECTION_READ_FLOW.md +0 -277
  16. package/docs/EXPLORATION.md +0 -187
  17. package/docs/PTY_ATTACH_IMPLEMENTATION_PLAN.md +0 -581
  18. package/docs/RELEASE.md +0 -148
  19. package/docs/superpowers/plans/2026-08-15-screenlog-gc.md +0 -704
  20. package/docs/superpowers/plans/2026-08-16-attach-double-cursor-jiggle-retry.md +0 -499
  21. package/docs/superpowers/plans/2026-08-21-attach-coldstart-jiggle-rearm.md +0 -797
  22. package/docs/superpowers/plans/2026-08-21-dashboard-keypress-lag.md +0 -366
  23. package/docs/superpowers/plans/2026-08-21-issue-14-needs-input-no-auto-done.md +0 -576
  24. package/docs/superpowers/plans/2026-08-22-jiggle-shrink-and-hold.md +0 -337
  25. package/docs/superpowers/plans/2026-08-22-launch-cwd-favorites.md +0 -916
  26. package/docs/superpowers/plans/2026-08-22-question-tool-grouping.md +0 -211
  27. package/docs/superpowers/plans/2026-08-22-rename-state-labels.md +0 -182
  28. package/docs/superpowers/plans/2026-08-22-stable-list-order.md +0 -51
  29. package/docs/superpowers/plans/2026-08-27-locks-acquirelock-spin.md +0 -614
  30. package/docs/superpowers/plans/2026-08-27-pty-runner-test-flaky.md +0 -32
  31. package/docs/superpowers/plans/2026-08-29-code-refs-badges.md +0 -223
  32. package/docs/superpowers/plans/2026-08-30-circular-navigation.md +0 -308
  33. package/docs/superpowers/plans/2026-08-30-post-exit-timing-fix.md +0 -37
  34. package/docs/superpowers/plans/2026-08-30-pty-attach-quality-debt.md +0 -311
  35. package/docs/superpowers/plans/2026-08-30-readme-v2.md +0 -294
  36. package/docs/superpowers/plans/2026-09-01-attach-detach-gate-cursor-anchor.md +0 -284
  37. package/docs/superpowers/plans/2026-09-02-attach-detach-editor-state.md +0 -722
  38. package/docs/superpowers/plans/2026-09-03-code-refs-pr-backlink-narrow.md +0 -551
  39. package/docs/superpowers/plans/2026-09-03-detach-gate-glyph-fallback.md +0 -146
  40. package/docs/superpowers/plans/2026-09-04-evidence-outputpreview.md +0 -209
  41. package/docs/superpowers/plans/2026-09-04-warm-host-reclaim.md +0 -796
  42. package/docs/superpowers/plans/2026-09-05-issue-13-drainnextfollowup-pty-probe.md +0 -114
  43. package/docs/superpowers/plans/2026-09-05-issue-38-windows-wezterm-ime-cursor.md +0 -73
  44. package/docs/superpowers/plans/2026-09-05-issue-39-truncate-codepoint-boundary.md +0 -143
  45. package/docs/superpowers/plans/2026-09-05-issue-61-mention-fallback-guards.md +0 -226
  46. package/docs/superpowers/plans/2026-09-05-issue-63-flaky-manual-completion.md +0 -87
  47. package/docs/superpowers/plans/2026-09-05-issue-64-changelog-release-helper.md +0 -53
  48. package/docs/superpowers/plans/2026-09-05-pty-host-stacking-sock-race.md +0 -731
  49. package/docs/superpowers/plans/2026-09-08-attach-ctrl-left-detach.md +0 -30
  50. package/docs/superpowers/plans/2026-09-08-dashboard-shrink-repaint.md +0 -68
  51. package/docs/superpowers/plans/2026-09-08-issue-11-attach-runtime-desync-heal.md +0 -917
  52. package/docs/superpowers/plans/2026-09-08-legacy-stale-host-recovery.md +0 -125
  53. package/docs/superpowers/plans/2026-09-08-spawn-async-error-swallow.md +0 -56
  54. package/docs/superpowers/plans/2026-09-08-stale-model-attach-guard.md +0 -96
  55. package/docs/superpowers/plans/2026-09-09-claimpid-blocks-replace.md +0 -267
  56. package/docs/superpowers/plans/2026-09-09-harden-runner-architecture.md +0 -603
  57. package/docs/superpowers/plans/2026-09-09-single-writer-completion.md +0 -252
  58. package/docs/superpowers/plans/2026-09-10-reader-consistency.md +0 -115
  59. package/docs/superpowers/plans/2026-09-14-attach-cursor-dectcem-gate.md +0 -469
  60. package/docs/superpowers/plans/2026-09-14-attach-snapshot.md +0 -92
  61. package/docs/superpowers/plans/2026-09-14-host-meta-orphan-lock.md +0 -771
  62. package/docs/superpowers/plans/2026-09-14-issue-106-terminal-frame-cognition.md +0 -299
  63. package/docs/superpowers/plans/2026-09-14-issue-113-foreground-preview-race.md +0 -609
  64. package/docs/superpowers/plans/2026-09-14-terminal-model.md +0 -145
  65. package/docs/superpowers/plans/2026-09-15-coordinator-pipe-root-normalize.md +0 -224
  66. package/docs/superpowers/plans/2026-09-15-lease-publish-eprem-reclaim.md +0 -341
  67. package/docs/superpowers/plans/2026-09-18-detach-anchor-reporter-endpoint.md +0 -875
  68. package/docs/superpowers/plans/2026-09-20-control-lifecycle.md +0 -116
  69. package/docs/superpowers/plans/2026-09-20-issue-121-perf-gate-out-of-coverage.md +0 -517
  70. package/docs/superpowers/plans/2026-09-23-a5-mid-stream-assertion.md +0 -25
  71. package/docs/superpowers/plans/2026-09-23-cwd-browse-tab-drill.md +0 -393
  72. package/docs/superpowers/plans/2026-09-23-terminal-query-forwarding.md +0 -51
  73. package/docs/superpowers/plans/2026-09-23-unconditional-detach-key.md +0 -58
  74. package/docs/superpowers/plans/2026-09-24-control-reconcile-flake.md +0 -698
  75. package/docs/superpowers/plans/2026-09-24-probe-attached-clients.md +0 -605
  76. package/docs/superpowers/plans/2026-09-29-issue-145-holding-semantic-state.md +0 -1183
  77. package/docs/superpowers/plans/2026-09-29-issue-145-user-verification.md +0 -66
  78. package/docs/superpowers/plans/2026-09-30-board-delete-key-x-y-confirm.md +0 -649
  79. package/docs/superpowers/plans/2026-09-30-issue-153-runner-stop-boot-window.md +0 -618
  80. package/docs/superpowers/plans/2026-09-30-issue-95-test-discipline.md +0 -555
  81. package/docs/superpowers/plans/2026-09-30-publish-dispatch-tag-check.md +0 -259
  82. package/docs/superpowers/plans/2026-10-06-attach-settle-scheme-delivery.md +0 -751
  83. package/docs/superpowers/plans/2026-10-09-issue-167-attach-middle-paste.md +0 -509
  84. package/docs/superpowers/plans/2026-10-09-issue-169-fullscreen-mouse-ownership.md +0 -346
  85. package/docs/superpowers/plans/2026-10-10-attach-delete-in-place.md +0 -832
  86. package/docs/superpowers/plans/2026-10-10-issue-174-selection-mirror-paste-source.md +0 -510
  87. package/docs/superpowers/plans/2026-10-14-issue-170-attach-reply-guard.md +0 -771
  88. package/docs/superpowers/plans/2026-10-14-issue-178-accept-registration-race.md +0 -1257
  89. package/docs/superpowers/plans/2026-10-14-issue-184-snapshot-window-contract.md +0 -657
  90. package/docs/superpowers/plans/2026-10-14-issue-185-attach-wheel-alt-screen.md +0 -47
  91. package/docs/superpowers/plans/2026-10-14-issue-187-motionless-drag.md +0 -931
  92. package/docs/superpowers/plans/2026-10-14-issue-189-mixed-input-segments.md +0 -823
  93. package/docs/superpowers/plans/2026-10-15-issue-188-x10-mouse-release.md +0 -526
  94. package/docs/superpowers/plans/2026-10-16-issue-198-attach-wheel-forward-fallback.md +0 -32
  95. package/docs/superpowers/plans/2026-10-18-attach-wheel-replay-pseudo-scrollback.md +0 -437
  96. package/docs/superpowers/plans/2026-10-19-issue-213-reply-guard-csi-key.md +0 -257
  97. package/docs/superpowers/plans/2026-10-19-issue-214-attach-forward-alt-modifier.md +0 -202
  98. package/docs/superpowers/plans/2026-10-21-issue-221-ask-user-question.md +0 -198
  99. package/docs/superpowers/plans/2026-10-23-issue-222-attach-ready.md +0 -290
  100. package/docs/superpowers/plans/2026-10-23-issue-225-monotonic-foreground-state.md +0 -450
  101. package/docs/superpowers/plans/2026-10-23-issue-229-vim-jkl.md +0 -449
  102. package/docs/superpowers/plans/2026-10-23-issue-232-attach-bg-only-cells.md +0 -153
  103. package/docs/superpowers/plans/2026-10-23-lease-heartbeat-staleness.md +0 -537
  104. package/docs/superpowers/plans/2026-10-23-selected-row-highlight.md +0 -405
  105. package/docs/superpowers/plans/2026-10-24-issue-217-windows-pid-reuse-stopping.md +0 -367
  106. package/docs/superpowers/plans/2026-10-24-issue-230-warm-host-background-runs.md +0 -806
  107. package/docs/superpowers/plans/2026-10-24-issue-238-windows-process-identity-token.md +0 -490
  108. package/docs/superpowers/plans/2026-10-24-issue-241-coordinator-root-exit.md +0 -461
  109. package/docs/superpowers/plans/2026-10-25-issue-239-coordinator-replacement-identity.md +0 -504
  110. package/docs/superpowers/plans/2026-10-26-issue-245-key-hints-doc-sync.md +0 -244
  111. package/docs/superpowers/plans/2026-10-27-issue-172-fullscreen-selection-clear.md +0 -344
  112. package/docs/superpowers/plans/2026-10-27-issue-252-select-key-hints.md +0 -209
  113. package/docs/superpowers/plans/2026-10-28-issue-255-coordinator-endpoint-zombie.md +0 -442
  114. package/docs/superpowers/plans/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup.md +0 -256
  115. package/docs/superpowers/plans/2026-11-03-cwd-favorites-full-pool.md +0 -266
  116. package/docs/superpowers/specs/2026-08-15-screenlog-gc-design.md +0 -105
  117. package/docs/superpowers/specs/2026-08-16-attach-double-cursor-jiggle-retry-design.md +0 -142
  118. package/docs/superpowers/specs/2026-08-21-attach-coldstart-jiggle-rearm-design.md +0 -110
  119. package/docs/superpowers/specs/2026-08-21-dashboard-keypress-lag-design.md +0 -59
  120. package/docs/superpowers/specs/2026-08-21-issue-14-needs-input-no-auto-done-design.md +0 -109
  121. package/docs/superpowers/specs/2026-08-22-cwd-favorites-design.md +0 -131
  122. package/docs/superpowers/specs/2026-08-22-jiggle-shrink-and-hold-design.md +0 -111
  123. package/docs/superpowers/specs/2026-08-22-question-tool-grouping-design.md +0 -114
  124. package/docs/superpowers/specs/2026-08-22-rename-state-labels-design.md +0 -80
  125. package/docs/superpowers/specs/2026-08-27-locks-acquirelock-spin-design.md +0 -97
  126. package/docs/superpowers/specs/2026-08-27-pty-runner-test-flaky-design.md +0 -35
  127. package/docs/superpowers/specs/2026-08-29-code-refs-badges-design.md +0 -128
  128. package/docs/superpowers/specs/2026-08-30-circular-navigation-design.md +0 -47
  129. package/docs/superpowers/specs/2026-08-30-eprm-atomicwrite-race-design.md +0 -77
  130. package/docs/superpowers/specs/2026-08-30-post-exit-timing-fix-design.md +0 -80
  131. package/docs/superpowers/specs/2026-08-30-pty-attach-quality-debt-design.md +0 -105
  132. package/docs/superpowers/specs/2026-08-30-readme-v2-design.md +0 -115
  133. package/docs/superpowers/specs/2026-09-01-attach-detach-gate-cursor-anchor-design.md +0 -78
  134. package/docs/superpowers/specs/2026-09-02-attach-detach-editor-state-design.md +0 -120
  135. package/docs/superpowers/specs/2026-09-03-code-refs-pr-backlink-narrow-design.md +0 -92
  136. package/docs/superpowers/specs/2026-09-03-detach-gate-glyph-fallback-design.md +0 -99
  137. package/docs/superpowers/specs/2026-09-04-evidence-outputpreview-design.md +0 -50
  138. package/docs/superpowers/specs/2026-09-04-warm-host-reclaim-design.md +0 -106
  139. package/docs/superpowers/specs/2026-09-05-issue-13-drainnextfollowup-pty-probe-design.md +0 -64
  140. package/docs/superpowers/specs/2026-09-05-issue-38-windows-wezterm-ime-design.md +0 -48
  141. package/docs/superpowers/specs/2026-09-05-issue-39-truncate-codepoint-boundary-design.md +0 -64
  142. package/docs/superpowers/specs/2026-09-05-issue-61-mention-fallback-design.md +0 -71
  143. package/docs/superpowers/specs/2026-09-05-issue-63-flaky-manual-completion-design.md +0 -49
  144. package/docs/superpowers/specs/2026-09-05-issue-64-changelog-helper-design.md +0 -76
  145. package/docs/superpowers/specs/2026-09-05-pty-host-stacking-sock-race-design.md +0 -510
  146. package/docs/superpowers/specs/2026-09-07-issue-11-attach-runtime-desync-heal-design.md +0 -130
  147. package/docs/superpowers/specs/2026-09-08-attach-ctrl-left-detach-design.md +0 -58
  148. package/docs/superpowers/specs/2026-09-08-dashboard-shrink-repaint-design.md +0 -52
  149. package/docs/superpowers/specs/2026-09-08-legacy-stale-host-recovery-design.md +0 -87
  150. package/docs/superpowers/specs/2026-09-08-spawn-async-error-swallow-design.md +0 -56
  151. package/docs/superpowers/specs/2026-09-08-stale-model-attach-guard-design.md +0 -79
  152. package/docs/superpowers/specs/2026-09-09-claimpid-blocks-replace-design.md +0 -147
  153. package/docs/superpowers/specs/2026-09-09-harden-runner-architecture-design.md +0 -304
  154. package/docs/superpowers/specs/2026-09-14-attach-cursor-dectcem-gate-design.md +0 -114
  155. package/docs/superpowers/specs/2026-09-14-host-meta-orphan-lock-design.md +0 -120
  156. package/docs/superpowers/specs/2026-09-14-issue-106-terminal-frame-cognition-design.md +0 -146
  157. package/docs/superpowers/specs/2026-09-14-issue-113-foreground-preview-race-design.md +0 -116
  158. package/docs/superpowers/specs/2026-09-15-coordinator-pipe-root-normalize-design.md +0 -84
  159. package/docs/superpowers/specs/2026-09-15-lease-publish-eprem-reclaim-design.md +0 -92
  160. package/docs/superpowers/specs/2026-09-18-detach-anchor-reporter-endpoint-design.md +0 -123
  161. package/docs/superpowers/specs/2026-09-20-issue-121-perf-gate-out-of-coverage-design.md +0 -204
  162. package/docs/superpowers/specs/2026-09-23-a5-mid-stream-assertion-design.md +0 -43
  163. package/docs/superpowers/specs/2026-09-23-cwd-browse-tab-drill-design.md +0 -95
  164. package/docs/superpowers/specs/2026-09-23-terminal-query-forwarding-design.md +0 -63
  165. package/docs/superpowers/specs/2026-09-23-unconditional-detach-key-design.md +0 -57
  166. package/docs/superpowers/specs/2026-09-24-control-reconcile-flake-design.md +0 -98
  167. package/docs/superpowers/specs/2026-09-24-probe-attached-clients-design.md +0 -190
  168. package/docs/superpowers/specs/2026-09-29-issue-145-holding-semantic-state-design.md +0 -394
  169. package/docs/superpowers/specs/2026-09-30-board-delete-key-x-y-confirm-design.md +0 -86
  170. package/docs/superpowers/specs/2026-09-30-issue-153-runner-stop-boot-window-design.md +0 -75
  171. package/docs/superpowers/specs/2026-09-30-issue-95-test-discipline-design.md +0 -226
  172. package/docs/superpowers/specs/2026-09-30-publish-dispatch-tag-check-design.md +0 -129
  173. package/docs/superpowers/specs/2026-10-06-attach-settle-scheme-delivery-design.md +0 -196
  174. package/docs/superpowers/specs/2026-10-09-issue-167-attach-middle-paste-design.md +0 -125
  175. package/docs/superpowers/specs/2026-10-09-issue-169-fullscreen-mouse-ownership-design.md +0 -130
  176. package/docs/superpowers/specs/2026-10-10-attach-delete-in-place-design.md +0 -224
  177. package/docs/superpowers/specs/2026-10-10-issue-174-selection-mirror-paste-source-design.md +0 -154
  178. package/docs/superpowers/specs/2026-10-14-issue-170-attach-reply-guard-design.md +0 -195
  179. package/docs/superpowers/specs/2026-10-14-issue-178-accept-registration-race-design.md +0 -287
  180. package/docs/superpowers/specs/2026-10-14-issue-184-snapshot-window-contract-design.md +0 -288
  181. package/docs/superpowers/specs/2026-10-14-issue-185-attach-wheel-alt-screen-design.md +0 -126
  182. package/docs/superpowers/specs/2026-10-14-issue-187-motionless-drag-design.md +0 -269
  183. package/docs/superpowers/specs/2026-10-14-issue-189-mixed-input-segments-design.md +0 -369
  184. package/docs/superpowers/specs/2026-10-15-issue-188-x10-mouse-release-design.md +0 -252
  185. package/docs/superpowers/specs/2026-10-16-issue-198-attach-wheel-forward-fallback-design.md +0 -67
  186. package/docs/superpowers/specs/2026-10-18-attach-wheel-replay-pseudo-scrollback-design.md +0 -250
  187. package/docs/superpowers/specs/2026-10-19-issue-213-reply-guard-csi-key-design.md +0 -165
  188. package/docs/superpowers/specs/2026-10-19-issue-214-attach-forward-alt-modifier-design.md +0 -131
  189. package/docs/superpowers/specs/2026-10-20-issue-221-ask-user-question-design.md +0 -270
  190. package/docs/superpowers/specs/2026-10-22-issue-225-monotonic-foreground-state-design.md +0 -225
  191. package/docs/superpowers/specs/2026-10-23-issue-222-attach-ready-design.md +0 -204
  192. package/docs/superpowers/specs/2026-10-23-issue-229-vim-jkl-design.md +0 -90
  193. package/docs/superpowers/specs/2026-10-23-issue-232-attach-bg-only-cells-design.md +0 -146
  194. package/docs/superpowers/specs/2026-10-23-lease-heartbeat-staleness-design.md +0 -271
  195. package/docs/superpowers/specs/2026-10-23-selected-row-highlight-design.md +0 -191
  196. package/docs/superpowers/specs/2026-10-24-issue-217-windows-pid-reuse-stopping-design.md +0 -334
  197. package/docs/superpowers/specs/2026-10-24-issue-230-warm-host-background-runs-design.md +0 -283
  198. package/docs/superpowers/specs/2026-10-24-issue-238-windows-process-identity-token-design.md +0 -286
  199. package/docs/superpowers/specs/2026-10-24-issue-241-coordinator-root-exit-design.md +0 -381
  200. package/docs/superpowers/specs/2026-10-25-issue-239-coordinator-replacement-identity-design.md +0 -331
  201. package/docs/superpowers/specs/2026-10-26-issue-245-key-hints-doc-sync-design.md +0 -72
  202. package/docs/superpowers/specs/2026-10-27-issue-172-fullscreen-selection-clear-design.md +0 -248
  203. package/docs/superpowers/specs/2026-10-27-issue-252-select-key-hints-design.md +0 -95
  204. package/docs/superpowers/specs/2026-10-28-issue-255-coordinator-endpoint-zombie-design.md +0 -380
  205. package/docs/superpowers/specs/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup-design.md +0 -197
  206. package/docs/superpowers/specs/2026-11-03-cwd-favorites-full-pool-design.md +0 -106
  207. package/scripts/budget-audit.mjs +0 -135
  208. package/scripts/release.mjs +0 -446
  209. package/scripts/release_helper.mjs +0 -309
  210. package/scripts/run-perf-gate.mjs +0 -40
  211. 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.