@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.
- package/CHANGELOG.md +24 -4
- package/CONTRIBUTING.md +7 -0
- package/README.md +55 -419
- package/SECURITY.md +19 -0
- package/docs/how-it-works.md +31 -0
- package/docs/reference.md +277 -0
- package/package.json +5 -11
- package/src/commands/agent-board.ts +26 -2
- package/src/commands/attach-flow.ts +4 -0
- package/src/core/double-press.mjs +6 -2
- package/src/core/slash-commands.mjs +52 -0
- package/src/index.ts +1 -1
- package/src/runtime/service.mjs +12 -0
- package/src/ui/dashboard.ts +59 -25
- package/src/ui/pty-attach.ts +8 -3
- package/IMPLEMENTATION_PLAN.md +0 -920
- package/PRD.md +0 -484
- package/PROGRESS.md +0 -142
- package/VERIFY.md +0 -115
- package/docs/BATCH_SELECTION_READ_FLOW.md +0 -277
- package/docs/EXPLORATION.md +0 -187
- package/docs/PTY_ATTACH_IMPLEMENTATION_PLAN.md +0 -581
- package/docs/RELEASE.md +0 -148
- package/docs/superpowers/plans/2026-08-15-screenlog-gc.md +0 -704
- package/docs/superpowers/plans/2026-08-16-attach-double-cursor-jiggle-retry.md +0 -499
- package/docs/superpowers/plans/2026-08-21-attach-coldstart-jiggle-rearm.md +0 -797
- package/docs/superpowers/plans/2026-08-21-dashboard-keypress-lag.md +0 -366
- package/docs/superpowers/plans/2026-08-21-issue-14-needs-input-no-auto-done.md +0 -576
- package/docs/superpowers/plans/2026-08-22-jiggle-shrink-and-hold.md +0 -337
- package/docs/superpowers/plans/2026-08-22-launch-cwd-favorites.md +0 -916
- package/docs/superpowers/plans/2026-08-22-question-tool-grouping.md +0 -211
- package/docs/superpowers/plans/2026-08-22-rename-state-labels.md +0 -182
- package/docs/superpowers/plans/2026-08-22-stable-list-order.md +0 -51
- package/docs/superpowers/plans/2026-08-27-locks-acquirelock-spin.md +0 -614
- package/docs/superpowers/plans/2026-08-27-pty-runner-test-flaky.md +0 -32
- package/docs/superpowers/plans/2026-08-29-code-refs-badges.md +0 -223
- package/docs/superpowers/plans/2026-08-30-circular-navigation.md +0 -308
- package/docs/superpowers/plans/2026-08-30-post-exit-timing-fix.md +0 -37
- package/docs/superpowers/plans/2026-08-30-pty-attach-quality-debt.md +0 -311
- package/docs/superpowers/plans/2026-08-30-readme-v2.md +0 -294
- package/docs/superpowers/plans/2026-09-01-attach-detach-gate-cursor-anchor.md +0 -284
- package/docs/superpowers/plans/2026-09-02-attach-detach-editor-state.md +0 -722
- package/docs/superpowers/plans/2026-09-03-code-refs-pr-backlink-narrow.md +0 -551
- package/docs/superpowers/plans/2026-09-03-detach-gate-glyph-fallback.md +0 -146
- package/docs/superpowers/plans/2026-09-04-evidence-outputpreview.md +0 -209
- package/docs/superpowers/plans/2026-09-04-warm-host-reclaim.md +0 -796
- package/docs/superpowers/plans/2026-09-05-issue-13-drainnextfollowup-pty-probe.md +0 -114
- package/docs/superpowers/plans/2026-09-05-issue-38-windows-wezterm-ime-cursor.md +0 -73
- package/docs/superpowers/plans/2026-09-05-issue-39-truncate-codepoint-boundary.md +0 -143
- package/docs/superpowers/plans/2026-09-05-issue-61-mention-fallback-guards.md +0 -226
- package/docs/superpowers/plans/2026-09-05-issue-63-flaky-manual-completion.md +0 -87
- package/docs/superpowers/plans/2026-09-05-issue-64-changelog-release-helper.md +0 -53
- package/docs/superpowers/plans/2026-09-05-pty-host-stacking-sock-race.md +0 -731
- package/docs/superpowers/plans/2026-09-08-attach-ctrl-left-detach.md +0 -30
- package/docs/superpowers/plans/2026-09-08-dashboard-shrink-repaint.md +0 -68
- package/docs/superpowers/plans/2026-09-08-issue-11-attach-runtime-desync-heal.md +0 -917
- package/docs/superpowers/plans/2026-09-08-legacy-stale-host-recovery.md +0 -125
- package/docs/superpowers/plans/2026-09-08-spawn-async-error-swallow.md +0 -56
- package/docs/superpowers/plans/2026-09-08-stale-model-attach-guard.md +0 -96
- package/docs/superpowers/plans/2026-09-09-claimpid-blocks-replace.md +0 -267
- package/docs/superpowers/plans/2026-09-09-harden-runner-architecture.md +0 -603
- package/docs/superpowers/plans/2026-09-09-single-writer-completion.md +0 -252
- package/docs/superpowers/plans/2026-09-10-reader-consistency.md +0 -115
- package/docs/superpowers/plans/2026-09-14-attach-cursor-dectcem-gate.md +0 -469
- package/docs/superpowers/plans/2026-09-14-attach-snapshot.md +0 -92
- package/docs/superpowers/plans/2026-09-14-host-meta-orphan-lock.md +0 -771
- package/docs/superpowers/plans/2026-09-14-issue-106-terminal-frame-cognition.md +0 -299
- package/docs/superpowers/plans/2026-09-14-issue-113-foreground-preview-race.md +0 -609
- package/docs/superpowers/plans/2026-09-14-terminal-model.md +0 -145
- package/docs/superpowers/plans/2026-09-15-coordinator-pipe-root-normalize.md +0 -224
- package/docs/superpowers/plans/2026-09-15-lease-publish-eprem-reclaim.md +0 -341
- package/docs/superpowers/plans/2026-09-18-detach-anchor-reporter-endpoint.md +0 -875
- package/docs/superpowers/plans/2026-09-20-control-lifecycle.md +0 -116
- package/docs/superpowers/plans/2026-09-20-issue-121-perf-gate-out-of-coverage.md +0 -517
- package/docs/superpowers/plans/2026-09-23-a5-mid-stream-assertion.md +0 -25
- package/docs/superpowers/plans/2026-09-23-cwd-browse-tab-drill.md +0 -393
- package/docs/superpowers/plans/2026-09-23-terminal-query-forwarding.md +0 -51
- package/docs/superpowers/plans/2026-09-23-unconditional-detach-key.md +0 -58
- package/docs/superpowers/plans/2026-09-24-control-reconcile-flake.md +0 -698
- package/docs/superpowers/plans/2026-09-24-probe-attached-clients.md +0 -605
- package/docs/superpowers/plans/2026-09-29-issue-145-holding-semantic-state.md +0 -1183
- package/docs/superpowers/plans/2026-09-29-issue-145-user-verification.md +0 -66
- package/docs/superpowers/plans/2026-09-30-board-delete-key-x-y-confirm.md +0 -649
- package/docs/superpowers/plans/2026-09-30-issue-153-runner-stop-boot-window.md +0 -618
- package/docs/superpowers/plans/2026-09-30-issue-95-test-discipline.md +0 -555
- package/docs/superpowers/plans/2026-09-30-publish-dispatch-tag-check.md +0 -259
- package/docs/superpowers/plans/2026-10-06-attach-settle-scheme-delivery.md +0 -751
- package/docs/superpowers/plans/2026-10-09-issue-167-attach-middle-paste.md +0 -509
- package/docs/superpowers/plans/2026-10-09-issue-169-fullscreen-mouse-ownership.md +0 -346
- package/docs/superpowers/plans/2026-10-10-attach-delete-in-place.md +0 -832
- package/docs/superpowers/plans/2026-10-10-issue-174-selection-mirror-paste-source.md +0 -510
- package/docs/superpowers/plans/2026-10-14-issue-170-attach-reply-guard.md +0 -771
- package/docs/superpowers/plans/2026-10-14-issue-178-accept-registration-race.md +0 -1257
- package/docs/superpowers/plans/2026-10-14-issue-184-snapshot-window-contract.md +0 -657
- package/docs/superpowers/plans/2026-10-14-issue-185-attach-wheel-alt-screen.md +0 -47
- package/docs/superpowers/plans/2026-10-14-issue-187-motionless-drag.md +0 -931
- package/docs/superpowers/plans/2026-10-14-issue-189-mixed-input-segments.md +0 -823
- package/docs/superpowers/plans/2026-10-15-issue-188-x10-mouse-release.md +0 -526
- package/docs/superpowers/plans/2026-10-16-issue-198-attach-wheel-forward-fallback.md +0 -32
- package/docs/superpowers/plans/2026-10-18-attach-wheel-replay-pseudo-scrollback.md +0 -437
- package/docs/superpowers/plans/2026-10-19-issue-213-reply-guard-csi-key.md +0 -257
- package/docs/superpowers/plans/2026-10-19-issue-214-attach-forward-alt-modifier.md +0 -202
- package/docs/superpowers/plans/2026-10-21-issue-221-ask-user-question.md +0 -198
- package/docs/superpowers/plans/2026-10-23-issue-222-attach-ready.md +0 -290
- package/docs/superpowers/plans/2026-10-23-issue-225-monotonic-foreground-state.md +0 -450
- package/docs/superpowers/plans/2026-10-23-issue-229-vim-jkl.md +0 -449
- package/docs/superpowers/plans/2026-10-23-issue-232-attach-bg-only-cells.md +0 -153
- package/docs/superpowers/plans/2026-10-23-lease-heartbeat-staleness.md +0 -537
- package/docs/superpowers/plans/2026-10-23-selected-row-highlight.md +0 -405
- package/docs/superpowers/plans/2026-10-24-issue-217-windows-pid-reuse-stopping.md +0 -367
- package/docs/superpowers/plans/2026-10-24-issue-230-warm-host-background-runs.md +0 -806
- package/docs/superpowers/plans/2026-10-24-issue-238-windows-process-identity-token.md +0 -490
- package/docs/superpowers/plans/2026-10-24-issue-241-coordinator-root-exit.md +0 -461
- package/docs/superpowers/plans/2026-10-25-issue-239-coordinator-replacement-identity.md +0 -504
- package/docs/superpowers/plans/2026-10-26-issue-245-key-hints-doc-sync.md +0 -244
- package/docs/superpowers/plans/2026-10-27-issue-172-fullscreen-selection-clear.md +0 -344
- package/docs/superpowers/plans/2026-10-27-issue-252-select-key-hints.md +0 -209
- package/docs/superpowers/plans/2026-10-28-issue-255-coordinator-endpoint-zombie.md +0 -442
- package/docs/superpowers/plans/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup.md +0 -256
- package/docs/superpowers/plans/2026-11-03-cwd-favorites-full-pool.md +0 -266
- package/docs/superpowers/specs/2026-08-15-screenlog-gc-design.md +0 -105
- package/docs/superpowers/specs/2026-08-16-attach-double-cursor-jiggle-retry-design.md +0 -142
- package/docs/superpowers/specs/2026-08-21-attach-coldstart-jiggle-rearm-design.md +0 -110
- package/docs/superpowers/specs/2026-08-21-dashboard-keypress-lag-design.md +0 -59
- package/docs/superpowers/specs/2026-08-21-issue-14-needs-input-no-auto-done-design.md +0 -109
- package/docs/superpowers/specs/2026-08-22-cwd-favorites-design.md +0 -131
- package/docs/superpowers/specs/2026-08-22-jiggle-shrink-and-hold-design.md +0 -111
- package/docs/superpowers/specs/2026-08-22-question-tool-grouping-design.md +0 -114
- package/docs/superpowers/specs/2026-08-22-rename-state-labels-design.md +0 -80
- package/docs/superpowers/specs/2026-08-27-locks-acquirelock-spin-design.md +0 -97
- package/docs/superpowers/specs/2026-08-27-pty-runner-test-flaky-design.md +0 -35
- package/docs/superpowers/specs/2026-08-29-code-refs-badges-design.md +0 -128
- package/docs/superpowers/specs/2026-08-30-circular-navigation-design.md +0 -47
- package/docs/superpowers/specs/2026-08-30-eprm-atomicwrite-race-design.md +0 -77
- package/docs/superpowers/specs/2026-08-30-post-exit-timing-fix-design.md +0 -80
- package/docs/superpowers/specs/2026-08-30-pty-attach-quality-debt-design.md +0 -105
- package/docs/superpowers/specs/2026-08-30-readme-v2-design.md +0 -115
- package/docs/superpowers/specs/2026-09-01-attach-detach-gate-cursor-anchor-design.md +0 -78
- package/docs/superpowers/specs/2026-09-02-attach-detach-editor-state-design.md +0 -120
- package/docs/superpowers/specs/2026-09-03-code-refs-pr-backlink-narrow-design.md +0 -92
- package/docs/superpowers/specs/2026-09-03-detach-gate-glyph-fallback-design.md +0 -99
- package/docs/superpowers/specs/2026-09-04-evidence-outputpreview-design.md +0 -50
- package/docs/superpowers/specs/2026-09-04-warm-host-reclaim-design.md +0 -106
- package/docs/superpowers/specs/2026-09-05-issue-13-drainnextfollowup-pty-probe-design.md +0 -64
- package/docs/superpowers/specs/2026-09-05-issue-38-windows-wezterm-ime-design.md +0 -48
- package/docs/superpowers/specs/2026-09-05-issue-39-truncate-codepoint-boundary-design.md +0 -64
- package/docs/superpowers/specs/2026-09-05-issue-61-mention-fallback-design.md +0 -71
- package/docs/superpowers/specs/2026-09-05-issue-63-flaky-manual-completion-design.md +0 -49
- package/docs/superpowers/specs/2026-09-05-issue-64-changelog-helper-design.md +0 -76
- package/docs/superpowers/specs/2026-09-05-pty-host-stacking-sock-race-design.md +0 -510
- package/docs/superpowers/specs/2026-09-07-issue-11-attach-runtime-desync-heal-design.md +0 -130
- package/docs/superpowers/specs/2026-09-08-attach-ctrl-left-detach-design.md +0 -58
- package/docs/superpowers/specs/2026-09-08-dashboard-shrink-repaint-design.md +0 -52
- package/docs/superpowers/specs/2026-09-08-legacy-stale-host-recovery-design.md +0 -87
- package/docs/superpowers/specs/2026-09-08-spawn-async-error-swallow-design.md +0 -56
- package/docs/superpowers/specs/2026-09-08-stale-model-attach-guard-design.md +0 -79
- package/docs/superpowers/specs/2026-09-09-claimpid-blocks-replace-design.md +0 -147
- package/docs/superpowers/specs/2026-09-09-harden-runner-architecture-design.md +0 -304
- package/docs/superpowers/specs/2026-09-14-attach-cursor-dectcem-gate-design.md +0 -114
- package/docs/superpowers/specs/2026-09-14-host-meta-orphan-lock-design.md +0 -120
- package/docs/superpowers/specs/2026-09-14-issue-106-terminal-frame-cognition-design.md +0 -146
- package/docs/superpowers/specs/2026-09-14-issue-113-foreground-preview-race-design.md +0 -116
- package/docs/superpowers/specs/2026-09-15-coordinator-pipe-root-normalize-design.md +0 -84
- package/docs/superpowers/specs/2026-09-15-lease-publish-eprem-reclaim-design.md +0 -92
- package/docs/superpowers/specs/2026-09-18-detach-anchor-reporter-endpoint-design.md +0 -123
- package/docs/superpowers/specs/2026-09-20-issue-121-perf-gate-out-of-coverage-design.md +0 -204
- package/docs/superpowers/specs/2026-09-23-a5-mid-stream-assertion-design.md +0 -43
- package/docs/superpowers/specs/2026-09-23-cwd-browse-tab-drill-design.md +0 -95
- package/docs/superpowers/specs/2026-09-23-terminal-query-forwarding-design.md +0 -63
- package/docs/superpowers/specs/2026-09-23-unconditional-detach-key-design.md +0 -57
- package/docs/superpowers/specs/2026-09-24-control-reconcile-flake-design.md +0 -98
- package/docs/superpowers/specs/2026-09-24-probe-attached-clients-design.md +0 -190
- package/docs/superpowers/specs/2026-09-29-issue-145-holding-semantic-state-design.md +0 -394
- package/docs/superpowers/specs/2026-09-30-board-delete-key-x-y-confirm-design.md +0 -86
- package/docs/superpowers/specs/2026-09-30-issue-153-runner-stop-boot-window-design.md +0 -75
- package/docs/superpowers/specs/2026-09-30-issue-95-test-discipline-design.md +0 -226
- package/docs/superpowers/specs/2026-09-30-publish-dispatch-tag-check-design.md +0 -129
- package/docs/superpowers/specs/2026-10-06-attach-settle-scheme-delivery-design.md +0 -196
- package/docs/superpowers/specs/2026-10-09-issue-167-attach-middle-paste-design.md +0 -125
- package/docs/superpowers/specs/2026-10-09-issue-169-fullscreen-mouse-ownership-design.md +0 -130
- package/docs/superpowers/specs/2026-10-10-attach-delete-in-place-design.md +0 -224
- package/docs/superpowers/specs/2026-10-10-issue-174-selection-mirror-paste-source-design.md +0 -154
- package/docs/superpowers/specs/2026-10-14-issue-170-attach-reply-guard-design.md +0 -195
- package/docs/superpowers/specs/2026-10-14-issue-178-accept-registration-race-design.md +0 -287
- package/docs/superpowers/specs/2026-10-14-issue-184-snapshot-window-contract-design.md +0 -288
- package/docs/superpowers/specs/2026-10-14-issue-185-attach-wheel-alt-screen-design.md +0 -126
- package/docs/superpowers/specs/2026-10-14-issue-187-motionless-drag-design.md +0 -269
- package/docs/superpowers/specs/2026-10-14-issue-189-mixed-input-segments-design.md +0 -369
- package/docs/superpowers/specs/2026-10-15-issue-188-x10-mouse-release-design.md +0 -252
- package/docs/superpowers/specs/2026-10-16-issue-198-attach-wheel-forward-fallback-design.md +0 -67
- package/docs/superpowers/specs/2026-10-18-attach-wheel-replay-pseudo-scrollback-design.md +0 -250
- package/docs/superpowers/specs/2026-10-19-issue-213-reply-guard-csi-key-design.md +0 -165
- package/docs/superpowers/specs/2026-10-19-issue-214-attach-forward-alt-modifier-design.md +0 -131
- package/docs/superpowers/specs/2026-10-20-issue-221-ask-user-question-design.md +0 -270
- package/docs/superpowers/specs/2026-10-22-issue-225-monotonic-foreground-state-design.md +0 -225
- package/docs/superpowers/specs/2026-10-23-issue-222-attach-ready-design.md +0 -204
- package/docs/superpowers/specs/2026-10-23-issue-229-vim-jkl-design.md +0 -90
- package/docs/superpowers/specs/2026-10-23-issue-232-attach-bg-only-cells-design.md +0 -146
- package/docs/superpowers/specs/2026-10-23-lease-heartbeat-staleness-design.md +0 -271
- package/docs/superpowers/specs/2026-10-23-selected-row-highlight-design.md +0 -191
- package/docs/superpowers/specs/2026-10-24-issue-217-windows-pid-reuse-stopping-design.md +0 -334
- package/docs/superpowers/specs/2026-10-24-issue-230-warm-host-background-runs-design.md +0 -283
- package/docs/superpowers/specs/2026-10-24-issue-238-windows-process-identity-token-design.md +0 -286
- package/docs/superpowers/specs/2026-10-24-issue-241-coordinator-root-exit-design.md +0 -381
- package/docs/superpowers/specs/2026-10-25-issue-239-coordinator-replacement-identity-design.md +0 -331
- package/docs/superpowers/specs/2026-10-26-issue-245-key-hints-doc-sync-design.md +0 -72
- package/docs/superpowers/specs/2026-10-27-issue-172-fullscreen-selection-clear-design.md +0 -248
- package/docs/superpowers/specs/2026-10-27-issue-252-select-key-hints-design.md +0 -95
- package/docs/superpowers/specs/2026-10-28-issue-255-coordinator-endpoint-zombie-design.md +0 -380
- package/docs/superpowers/specs/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup-design.md +0 -197
- package/docs/superpowers/specs/2026-11-03-cwd-favorites-full-pool-design.md +0 -106
- package/scripts/budget-audit.mjs +0 -135
- package/scripts/release.mjs +0 -446
- package/scripts/release_helper.mjs +0 -309
- package/scripts/run-perf-gate.mjs +0 -40
- package/scripts/run-tests.mjs +0 -375
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
Drafted: ollama/deepseek-v4.1-flash:1017-cloud (selected) · ollama/deepseek-v4.1-flash:1017-cloud (physical) @ 2026-10-27T00:16:00Z
|
|
2
|
-
Revised: ollama/deepseek-v4.1-flash:1017-cloud (selected) · ollama/deepseek-v4.1-flash:1017-cloud (physical) @ 2026-10-27T00:41:00Z — R1-G1 (U1 deployment preconditions), R1-D1 (README decision), R1-D2 (follow-up issue #250)
|
|
3
|
-
Revised: ollama/deepseek-v4.1-flash:1017-cloud (selected) · ollama/deepseek-v4.1-flash:1017-cloud (physical) @ 2026-10-27T00:52:00Z — R2-D1 (U1 sequencing), R2-D2 (supersession note), R2-D3 (baseline)
|
|
4
|
-
Revised: ollama/deepseek-v4.1-flash:1017-cloud (selected) · ollama/deepseek-v4.1-flash:1017-cloud (physical) @ 2026-10-27T01:25:00Z — local code review F1 (gesture-generation guard) + F3 (deferral pin) + F4 (predicate table)
|
|
5
|
-
|
|
6
|
-
# Spec: #172 — attach view keeps the fullscreen selection highlight after copy-on-release
|
|
7
|
-
|
|
8
|
-
Status: DRAFT (awaiting spec-cross-review, then user approval — github-issue-driven step 4 gates)
|
|
9
|
-
Issue: https://github.com/zhuxixi/pi-agent-board/issues/172
|
|
10
|
-
Repo state baseline: `origin/main` @ `3fcc2a4` (local working copy `724c4da`, one docs-only commit behind; every cited line number was re-verified at `3fcc2a4`), pi-tui / pi-coding-agent 1.1.0
|
|
11
|
-
|
|
12
|
-
## Problem (root cause, verified against source)
|
|
13
|
-
|
|
14
|
-
The reported symptom is real, but the issue's Root cause paragraph points at the wrong
|
|
15
|
-
mechanism. In **fullscreen** (pi ≥1.0, `TuiAltScreen` owns left-drag), the highlight is
|
|
16
|
-
painted by pi-tui's own `applySelection()` from `selectionAnchor` / `selectionFocus`.
|
|
17
|
-
`PtyAttachComponent.handleLocalMouseEvent` — the `shouldCopy` branch the issue blames — is
|
|
18
|
-
never reached in fullscreen (the component's own comment at `pty-attach.ts:474`), so
|
|
19
|
-
`this.selection` stays null and no board-side `clearSelection()` can affect what the user
|
|
20
|
-
sees.
|
|
21
|
-
|
|
22
|
-
pi-tui 1.1.0 `dist/tui-alt-screen.js:1090-1139` release path:
|
|
23
|
-
|
|
24
|
-
```js
|
|
25
|
-
if (this.copyOnSelect)
|
|
26
|
-
void this.copySelectionToClipboard();
|
|
27
|
-
this.requestRender();
|
|
28
|
-
return;
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
The copy is done, the selection state is not reset, so the inverse-video highlight stays
|
|
32
|
-
lit until pi clears it on a later gesture (`clearTextSelection()` is invoked by pi itself
|
|
33
|
-
when the user clicks a component or moves focus).
|
|
34
|
-
|
|
35
|
-
The repo already has the one hook that runs after pi finalizes a selection: #174's
|
|
36
|
-
`process.nextTick` callback scheduled from `handleMouse` for left `release`/`click`
|
|
37
|
-
(`pty-attach.ts:523-528` → `mirrorFullscreenSelectionToPrimary()`, `:1376`).
|
|
38
|
-
|
|
39
|
-
## Goal / non-goals
|
|
40
|
-
|
|
41
|
-
**Goal**: in fullscreen, once pi's copy-on-select has completed for a selection gesture
|
|
42
|
-
that ends inside the attach view, drop pi's selection so the highlight disappears
|
|
43
|
-
immediately — without changing what reaches the clipboard, and without breaking pi's
|
|
44
|
-
multi-click chain (double-click word, triple-click line).
|
|
45
|
-
|
|
46
|
-
**Supersedes** #174's "pi's own selection behavior (visuals, CLIPBOARD copy) is untouched" for
|
|
47
|
-
the post-copy highlight only; #174's mirror, kill-switch and no-consume contracts are
|
|
48
|
-
preserved.
|
|
49
|
-
|
|
50
|
-
**Non-goals**:
|
|
51
|
-
|
|
52
|
-
- The legacy/regular-mode gap (`handleLocalMouseEvent` `shouldCopy` missing
|
|
53
|
-
`clearSelection()`). It is a real, separate bug; this PR leaves regular-mode behavior
|
|
54
|
-
untouched and the existing `pty-attach-legacy-drag` assertions intact. It will be tracked
|
|
55
|
-
separately: issue #250.
|
|
56
|
-
- Selections that end outside the attach overlay (dashboard, other pi UI): outside the
|
|
57
|
-
component's event window, same limitation as the #174 mirror.
|
|
58
|
-
- Any upstream change to pi/pi-tui. The change uses a feature-detected private method; if
|
|
59
|
-
pi ever exposes a public "clear visual selection" API, this code can switch to it.
|
|
60
|
-
- Changing `AGENT_BOARD_ATTACH_NATIVE_PASTE` semantics beyond making the highlight clear
|
|
61
|
-
independent of it (see D2 below).
|
|
62
|
-
|
|
63
|
-
## Decisions
|
|
64
|
-
|
|
65
|
-
**D1 — clear via `clearTextSelection()`, not `resetTextSelection()`.**
|
|
66
|
-
`resetTextSelection()` is public but also clears `lastClick`; `getClickCount` uses
|
|
67
|
-
`lastClick` with `DOUBLE_CLICK_INTERVAL_MS = 500`, so clearing it on every release would
|
|
68
|
-
make the second press of a double-click count as a first click and break word/line
|
|
69
|
-
selection. `clearTextSelection()` only drops the visual selection
|
|
70
|
-
(`tui-alt-screen.js:689-698`), preserving the click chain. It is declared `private` in
|
|
71
|
-
pi-tui's typings but is a plain prototype method at runtime; the board already reads the
|
|
72
|
-
private `getActiveSelectionText` the same way (`pty-attach.ts:1379`). Access is
|
|
73
|
-
feature-detected so older/newer pi degrades to today's behavior instead of throwing.
|
|
74
|
-
|
|
75
|
-
**D2 — decouple the clear from `AGENT_BOARD_ATTACH_NATIVE_PASTE`.**
|
|
76
|
-
That switch is documented as X11 PRIMARY copy + middle-click paste integration. The stale
|
|
77
|
-
highlight is a pi-selection-state issue, not a clipboard concern: with the switch off, pi
|
|
78
|
-
still copies on release and the highlight still lingers. `writePrimarySelection()` already
|
|
79
|
-
self-gates on the env var, so the scheduling predicate does not need it — the mirror keeps
|
|
80
|
-
its exact behavior, and the clear runs regardless.
|
|
81
|
-
|
|
82
|
-
**D3 — only clear when pi actually copied.**
|
|
83
|
-
`getCopyOnSelect()` (public) is checked before clearing. With copy-on-select disabled the
|
|
84
|
-
user keeps the selection deliberately (pi's `Ctrl+X` copies it), so the highlight must
|
|
85
|
-
stay. With it enabled, the text is already in the clipboard, so the highlight has no
|
|
86
|
-
remaining purpose.
|
|
87
|
-
|
|
88
|
-
**D4 — clear only for a non-empty selection.**
|
|
89
|
-
`getActiveSelectionText()` returning empty/undefined means no selection was made (bare
|
|
90
|
-
press-release, click on a link) — nothing to clear, and pi's own click handling is left
|
|
91
|
-
untouched.
|
|
92
|
-
|
|
93
|
-
**D5 — a settle may not consume the next gesture.**
|
|
94
|
-
pi-tui emits batched mouse reports synchronously in one loop, so a `release` and the next
|
|
95
|
-
left `press` can land in the same stdin chunk. Without a guard, the deferred settle would
|
|
96
|
-
run after that press has already started a new (word/line) selection, mirror it, and clear
|
|
97
|
-
it — the double-click would then copy nothing. A monotonic `selectionGestureSerial`,
|
|
98
|
-
bumped on every left press, is captured when the settle is scheduled; a mismatch on the
|
|
99
|
-
next tick drops the settle.
|
|
100
|
-
|
|
101
|
-
## Design
|
|
102
|
-
|
|
103
|
-
### 1. Pure predicate (`src/core/pty-scroll.mjs`)
|
|
104
|
-
|
|
105
|
-
Replace the env-gated mirror helper with an env-free gesture predicate:
|
|
106
|
-
|
|
107
|
-
```js
|
|
108
|
-
/** Issue #174/#172: whether a normalized mouse event ends a fullscreen text
|
|
109
|
-
* selection gesture the attach overlay settles — mirror the selection into
|
|
110
|
-
* X11 PRIMARY (#174) and drop pi's highlight once copy-on-select has run (#172).
|
|
111
|
-
* Only release/click of the left button ends a selection in TuiAltScreen; pi
|
|
112
|
-
* owns the gesture, so the overlay observes without consuming. Pure. */
|
|
113
|
-
export function isFullscreenSelectionEnd(event) → boolean
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Decision table:
|
|
117
|
-
|
|
118
|
-
| type | button | result |
|
|
119
|
-
| --- | --- | --- |
|
|
120
|
-
| release / click | left | `true` |
|
|
121
|
-
| press / move / drag / wheel | any | `false` |
|
|
122
|
-
| release / click | middle / right / none | `false` |
|
|
123
|
-
|
|
124
|
-
`shouldMirrorSelectionToPrimary` is removed; `writePrimarySelection()` remains the single
|
|
125
|
-
place that honours `AGENT_BOARD_ATTACH_NATIVE_PASTE`.
|
|
126
|
-
|
|
127
|
-
### 2. Component wiring (`src/ui/pty-attach.ts`)
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
const nativePasteEnabled = process.env.AGENT_BOARD_ATTACH_NATIVE_PASTE !== "0";
|
|
131
|
-
// D5: a press starts a new gesture; see the serial check below.
|
|
132
|
-
if (event.type === "press" && event.button === "left") this.selectionGestureSerial += 1;
|
|
133
|
-
if (isFullscreenSelectionEnd(event)) {
|
|
134
|
-
// Overlays are dispatched before TuiAltScreen finalizes (and copies) the
|
|
135
|
-
// selection for this event, so settle on the next tick (issue #174).
|
|
136
|
-
const serial = this.selectionGestureSerial;
|
|
137
|
-
process.nextTick(() => {
|
|
138
|
-
if (serial !== this.selectionGestureSerial) return; // D5: next gesture started
|
|
139
|
-
this.settleFullscreenSelection(nativePasteEnabled);
|
|
140
|
-
});
|
|
141
|
-
return undefined; // observe only — pi keeps the gesture
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
`mirrorFullscreenSelectionToPrimary()` is renamed and extended:
|
|
146
|
-
|
|
147
|
-
```ts
|
|
148
|
-
interface FullscreenSelectionHost {
|
|
149
|
-
getActiveSelectionText?: () => string | undefined;
|
|
150
|
-
getCopyOnSelect?: () => boolean;
|
|
151
|
-
clearTextSelection?: () => void; // private in pi-tui's typings; feature-detected
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/** Issue #174 (B2) + #172: after a selection gesture ends inside this overlay,
|
|
155
|
-
* pi has finalized (and copied) its selection. Mirror the text into X11 PRIMARY
|
|
156
|
-
* so middle-click paste works, then drop pi's selection so the inverse-video
|
|
157
|
-
* highlight does not outlive the copy. Clearing is gated on copy-on-select and
|
|
158
|
-
* on the pi-tui method being present; a missing method degrades to the old
|
|
159
|
-
* behaviour (highlight persists) rather than throwing. */
|
|
160
|
-
private settleFullscreenSelection(nativePasteEnabled: boolean): void {
|
|
161
|
-
if (this.closed) return;
|
|
162
|
-
const alt = this.tui as FullscreenSelectionHost;
|
|
163
|
-
const text = alt.getActiveSelectionText?.();
|
|
164
|
-
if (typeof text !== "string" || text.length === 0) return;
|
|
165
|
-
if (nativePasteEnabled) this.writePrimarySelection(text);
|
|
166
|
-
if (alt.getCopyOnSelect?.() === false) return;
|
|
167
|
-
if (typeof alt.clearTextSelection !== "function") return;
|
|
168
|
-
alt.clearTextSelection();
|
|
169
|
-
this.scheduleRender(); // pi's own release repaint happened before this tick
|
|
170
|
-
}
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### Resulting behavior matrix
|
|
174
|
-
|
|
175
|
-
| Scenario | Behavior |
|
|
176
|
-
| --- | --- |
|
|
177
|
-
| fullscreen: drag-select inside attach, release | copied by pi; PRIMARY mirrored; highlight cleared on the next tick ✅ |
|
|
178
|
-
| fullscreen: double-click a word, release | word copied by pi; word highlighted momentarily, then cleared; triple-click chain still works (`lastClick` untouched) ✅ |
|
|
179
|
-
| fullscreen: plain left click | empty selection → nothing cleared, pi's own click handling untouched |
|
|
180
|
-
| fullscreen: `fullscreenCopyOnSelect = false` | selection kept for `Ctrl+X`; highlight stays (intended) |
|
|
181
|
-
| fullscreen: `AGENT_BOARD_ATTACH_NATIVE_PASTE=0` | no PRIMARY write; highlight still cleared |
|
|
182
|
-
| older pi without `clearTextSelection` | no PRIMARY-write change, highlight stays (graceful degradation) |
|
|
183
|
-
| regular / legacy mode | unchanged: `handleMouse` is not called; the local selection path is untouched |
|
|
184
|
-
|
|
185
|
-
## Acceptance matrix
|
|
186
|
-
|
|
187
|
-
| ID | 功能点 | 验收方式 | 具体验证 | 通过标准 |
|
|
188
|
-
|----|--------|----------|----------|----------|
|
|
189
|
-
| A1 | 手势谓词决策表 | 自动化验证(unit) | `node --test test/pty-scroll.test.mjs`(替换原 `shouldMirrorSelectionToPrimary` 用例,覆盖 release/click × left 为 true,press/move/drag/wheel/其它按钮为 false) | 新增用例全绿 |
|
|
190
|
-
| A2 | 非空选区 release:镜像 + 清高亮,且先取文本后清 | 自动化验证(integration,组件级场景) | `test/pty-attach-selection-mirror-scenario.ts` 的 fake TUI 增加 `clearTextSelection()`(置空 fixture 并计数)与 `getCopyOnSelect()`;`test/pty-attach-selection-mirror.test.mjs` 断言 | xclip 日志收到 `-selection primary` 与 fixture 文本(证明清除前已读取),`clearCalls === 1`,`handleMouse` 返回 `undefined` |
|
|
191
|
-
| A3 | 空选区 / press / move 不清 | 自动化验证(同上) | 同场景 | `clearCalls === 0`,无 PRIMARY 写 |
|
|
192
|
-
| A4 | `copyOnSelect === false` 不清、仍镜像 | 自动化验证(同上) | 同场景,fake TUI 返回 false | `clearCalls === 0`,PRIMARY 写 1 次 |
|
|
193
|
-
| A5 | `NATIVE_PASTE=0`:不写 PRIMARY 但仍清高亮 | 自动化验证(同上) | 同场景,env 覆盖 | `killSwitchWrites === 0`,`killSwitchClears === 1` |
|
|
194
|
-
| A6 | 旧 pi(无 `clearTextSelection`):降级不抛错 | 自动化验证(同上) | 同场景,fake TUI 省略该方法 | 无异常,PRIMARY 写 1 次,`clearCalls` 不可用(不适用) |
|
|
195
|
-
| A7 | 类型与构建 | 自动化验证(static/build) | `npm run typecheck`、`npm run verify` | 全部通过(含既有套件、覆盖率阈值、perf gate、pack:dry) |
|
|
196
|
-
| A8 | release + 下一次 press 同 tick 合并:排队中的 settle 不得读/清新选区 | 自动化验证(同上) | 同场景:`handleMouse(release)` 后立即 `handleMouse(press)`,再等 tick | `coalescedWrites === 0` 且 `coalescedClears === 0`;另在 release 后同步断言 `releaseSyncWrites === 0`(deferral 钉死) |
|
|
197
|
-
| U1 | 真机 fullscreen 体验 | 用户实测 | **前置**:① 合并后把 pi 实际加载的 git checkout 更新到 main —— 扩展在 `~/.pi/agent/settings.json` 以 `git:github.com/zhuxixi/pi-agent-board` 注册,路径为 `~/.pi/agent/git/github.com/zhuxixi/pi-agent-board`,入口 `./index.ts`(免构建);执行 `git -C ~/.pi/agent/git/github.com/zhuxixi/pi-agent-board pull --ff-only`,若因本地 `package-lock.json` 改动被拒就先 `git stash push -- package-lock.json`、测完 `git stash pop`;② 完全退出并重启 pi(扩展启动时加载;fullscreen 是默认模式,必要时用 `pi --tui-mode fullscreen` 显式指定);③ 确认 X11 会话且 `which xclip` 有输出。**步骤**:① fullscreen attach 内拖选一段文字并松开 → 高亮立即消失;② 中键粘贴仍粘贴刚选内容;③ 双击选词 → 高亮消失且双击仍能选词;④ 三击选行仍生效;⑤ 把 `~/.pi/agent/settings.json` 的 `"fullscreenCopyOnSelect"` 设为 `false` 并重启,拖选松开 → 高亮保留、`Ctrl+X` 可复制;测完恢复默认并重启 | ①–⑤ 全部符合 |
|
|
198
|
-
|
|
199
|
-
## Testability split design (hard constraint for implementation)
|
|
200
|
-
|
|
201
|
-
- **Pure core**: `isFullscreenSelectionEnd(event)` — no env reads, no side effects; full
|
|
202
|
-
event-shape decision table at unit level (A1).
|
|
203
|
-
- **I/O shell**: `handleMouse` maps the predicate to one `process.nextTick` schedule;
|
|
204
|
-
`settleFullscreenSelection()` owns the ordering (`getActiveSelectionText` →
|
|
205
|
-
`writePrimarySelection` → clear → `scheduleRender`). The gesture serial lives on the
|
|
206
|
-
component (`handleMouse` bumps it on left press, the scheduled closure compares it) and
|
|
207
|
-
needs no separate unit test: A8 drives it through the public seam. The only xclip touch point stays
|
|
208
|
-
`writePrimarySelection`; the only pi-selection touch points stay `getActiveSelectionText`
|
|
209
|
-
/ `getCopyOnSelect` / `clearTextSelection`, all through the structural cast.
|
|
210
|
-
- **Fake TUI seams** (component scenario): `getActiveSelectionText`, `getCopyOnSelect`,
|
|
211
|
-
`clearTextSelection`, `requestRender`. `clearTextSelection` must invalidate the fixture
|
|
212
|
-
so that a wrong order (clear → read) produces zero PRIMARY writes and fails A2 — the
|
|
213
|
-
test must not merely count calls.
|
|
214
|
-
- The clear must not be inlined into `handleMouse` (it needs the deferred tick) and must
|
|
215
|
-
not be replicated in the legacy path.
|
|
216
|
-
|
|
217
|
-
## Risks / notes
|
|
218
|
-
|
|
219
|
-
- Private API coupling: `clearTextSelection` can disappear in a future pi-tui. Mitigated
|
|
220
|
-
by feature detection (degrade, never throw) and by a comment naming the upstream ask
|
|
221
|
-
(expose a public "clear visual selection, keep click history" method).
|
|
222
|
-
- If pi ever defers selection finalization across ticks, the clear would land before the
|
|
223
|
-
copy; the `copyOnSelect` gate would then clear a selection pi is about to copy. Accepted
|
|
224
|
-
risk recorded here; the ordering assumption is pinned by A2's read-before-clear fixture.
|
|
225
|
-
- `Ctrl+X` (pi's copy binding) after a drag becomes a no-op when copy-on-select is on —
|
|
226
|
-
by construction, the text is already in the clipboard; when the user disabled
|
|
227
|
-
copy-on-select, the clear is skipped and `Ctrl+X` still works.
|
|
228
|
-
- The highlight for gestures ending outside the overlay remains (same as #174's mirror
|
|
229
|
-
limitation).
|
|
230
|
-
- A release followed by another press inside one stdin chunk is guarded by the gesture
|
|
231
|
-
serial (D5/A8). A press that lands outside the overlay does not touch the serial, but
|
|
232
|
-
pi's own press path has already reset its selection, so the settle reads nothing.
|
|
233
|
-
- Updating the issue's Root cause / Environment text is part of the PR narrative, not of
|
|
234
|
-
the code change.
|
|
235
|
-
|
|
236
|
-
## Deliverables
|
|
237
|
-
|
|
238
|
-
- `src/core/pty-scroll.mjs`: replace `shouldMirrorSelectionToPrimary` with
|
|
239
|
-
`isFullscreenSelectionEnd`
|
|
240
|
-
- `src/ui/pty-attach.ts`: predicate branch in `handleMouse`; rename/extend
|
|
241
|
-
`settleFullscreenSelection`; `FullscreenSelectionHost` structural type
|
|
242
|
-
- `test/pty-scroll.test.mjs`: decision-table update
|
|
243
|
-
- `test-support/pty-attach-selection-mirror-scenario.ts` + `test/pty-attach-selection-mirror.test.mjs`:
|
|
244
|
-
clear/order/copyOnSelect/kill-switch/fallback cases
|
|
245
|
-
- No README change: the `AGENT_BOARD_ATTACH_NATIVE_PASTE` row (README:323) describes X11
|
|
246
|
-
PRIMARY copy + middle-click paste, which is still exactly what the switch governs; the
|
|
247
|
-
highlight clear is neither, so the current wording stays accurate after the decoupling.
|
|
248
|
-
- CHANGELOG entry via release tooling at release time (not in this PR)
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# spec — issue #252:SELECT 模式的 in-app 文案对齐(hint 行 / `?` 覆盖层 / `!` 措辞)
|
|
2
|
-
|
|
3
|
-
Drafted: deepseek/deepseek-flash (selected) · deepseek/deepseek-flash (physical) @ 2026-10-27T23:28:00+08:00
|
|
4
|
-
Revised: deepseek/deepseek-flash (selected) · deepseek/deepseek-flash (physical) @ 2026-10-27T23:47:00+08:00 — cross-review R2(收敛轮,0 真缺口):R2-D1 接受(§5 残留的 `rg` 改为 `grep -c`,与 §4 A8 一致);R2-D2 接受(`pty-support.mjs:155` → `src/core/pty-support.mjs:155`);R2-D3 接受(U1 前置补 checkout 加载出处 + 重开 pi 会话)
|
|
5
|
-
|
|
6
|
-
基线:`main @ 3fcc2a4`(#249 之后)。调研留档(仓外,不随 PR 提交):`~/.github-issue-driven/zhuxixi/pi-agent-board/issue-252/research/` 下的 `01-surfaces-audit.md`、`02-wording-evidence.md`、`03-test-harness.md`。
|
|
7
|
-
授权:`authorization.md` → `Gate: auto`(合并前仍需用户明确批准)。
|
|
8
|
-
|
|
9
|
-
## 1. 背景
|
|
10
|
-
|
|
11
|
-
`handleSelectKey`(`src/ui/dashboard.ts:398-423`)绑 9 组键:移动(`↑`/`↓`/`j`/`k`)、`space` toggle、`a` 全选、`u` 清空、`d` 批量 Done、`ctrl+x` 批量删除、`m`/`esc`/`ctrl+c` 退出、`?` 帮助、`!` PTY 诊断。
|
|
12
|
-
|
|
13
|
-
面向用户的两个 in-app 表面都落后于这份清单:
|
|
14
|
-
|
|
15
|
-
- **SELECT hint 行**(`listHints()`,`:1347-1358`)写 7 项,缺 `m`/`?`/`!`,且**现状已 122 字符**——120 列终端就被裁掉 2 字符(`esc cancel` → `esc canc`)。
|
|
16
|
-
- **`?` 覆盖层**(`renderHelp`,`:1723`)的 `In select` 行写的是 `j/k move · a select all · u clear · d move done · ctrl+x delete · esc cancel`:缺 `space`(该模式最常用的键)、方向键、`m`、`?`、`!`。
|
|
17
|
-
|
|
18
|
-
另外 `!` 的措辞三处不一致:README 六处 `repair hints`,覆盖层 `fix steps`,运行时面板用 `Fix:` + `Suggested steps`。
|
|
19
|
-
|
|
20
|
-
本 issue 是**纯文案同步**,无键位/行为变更。
|
|
21
|
-
|
|
22
|
-
## 2. 设计决策表
|
|
23
|
-
|
|
24
|
-
| # | 决策 | 依据 |
|
|
25
|
-
|---|---|---|
|
|
26
|
-
| D1 | SELECT hint 行改为 11 个 token 的紧凑形态:`${n} selected` · [`•${u} unread`] · `↑↓/j/k move` · `space toggle` · `a all visible` · `u clear` · `d done` · `ctrl+x delete` · `m/esc cancel` · `? help` · `! pty`(131 可见字符;带 unread 143) | 9 项全在;相对现状只长 9 字符。压缩方式:`d move done`→`d done`、`ctrl+x delete done`→`ctrl+x delete`、`esc cancel`→`m/esc cancel`。保留 `all visible` 的语义精度(过滤态下 `a` 只选可见行) |
|
|
27
|
-
| D2 | `In select` 行改为:`↑↓/j/k move · space toggle · a all · u clear · d done · ctrl+x delete · m/esc cancel`(渲染 101 列) | 只写本模式专属语义;`?`/`!` 由 D3 的全局行覆盖,不在本行重复。**该行决定整个帮助盒子的宽度**(`renderCenteredBox` 取最长行):在 D2 行基础上再补 `? help`/`! pty` 为 118 列(若保留原 `a all visible` 写法则为 126 列),两种形态都超过 120 列终端的 `width-6=114` 上限,在 120 列也照样被裁(research/01 §B) |
|
|
28
|
-
| D3 | 覆盖层新增一行 `["?", "Open the key help overlay (list and multi-select)"]`,位置在 `/` 行与 `!` 行之间 | `?` 只绑在 list(`:373`)与 select(`:421`),覆盖层 26 行里一句都没有——这是 issue 未点明的第三处缺口。`!` 已有全局行,故 D2 不重复它 |
|
|
29
|
-
| D4 | `!` 的 canonical 措辞 = `fix steps`:README 六处改齐(4 张表 + `:289` + `:368`);覆盖层 `:1716` 不动 | 面板自己写 `Fix:` / `Suggested steps`,字段名 `fixHint`/`steps`,代码注释(`src/core/pty-support.mjs:155`)也是 `fix steps`;反向对齐要改运行时代码且与面板自相矛盾(research/02) |
|
|
30
|
-
| D5 | 不动 handler、不动键位、不动 `#246` 的高度适配、不新增 README 表格、不回改历史 spec/plan | 范围纪律。#245 的 D5 是「in-app 三处就其 j/k/l 范围而言已正确,故不动」,并非把 in-app 侧 defer 给后续 issue;本 issue 处理的是 #245 范围**之外**的 SELECT 表面(hint 行的 `m`/`?`/`!`、`In select` 行、`!` 措辞),两者不冲突 |
|
|
31
|
-
|
|
32
|
-
### D1 的取舍:为什么接受「窄终端裁尾」
|
|
33
|
-
|
|
34
|
-
11 个 token 在任何布局下都塞不进 80 列,131 字符在 120 列仍会裁掉尾部(`? help`/`! pty`)。三个理由支撑这个取舍:
|
|
35
|
-
|
|
36
|
-
1. 仓库既有行为就是裁尾:NORMAL hint 行 **238 字符**,240 列才完整(实测,research/01 §A)。
|
|
37
|
-
2. 裁掉的恰好是两个辅助键:`m/esc cancel` 止于第 114 列,在 120 列终端**完整可见**,被裁的只有尾部 `? help` / `! pty`——安全优先。
|
|
38
|
-
3. `?`/`!` 在覆盖层(D3 + `!` 全局行)与 README 里都有完整说明,不依赖 hint 行发现。
|
|
39
|
-
|
|
40
|
-
**被否决的替代方案**:SELECT footer 折成两行(改 `renderFooter`,让 select 模式多占一行)。它能让 80 列也全可见,但会改变 footer 高度、且仓库没有任何多行 hint 先例,属于布局变更而非文案同步——留给 `#246` 的高度适配一并考虑。
|
|
41
|
-
|
|
42
|
-
### 与 `#246` 的交互
|
|
43
|
-
|
|
44
|
-
新增 `?` 行使帮助盒子从 32 行变 **33 行**,`#246` 的裁剪阈值随之多一行。此处不做补偿(不加行数压缩、不删 `normal`/`insert` 说明行):`#246` 的方向就是重构高度适配,提前在文案侧做布局妥协会让它的方案空间变窄。
|
|
45
|
-
|
|
46
|
-
## 3. 改动清单
|
|
47
|
-
|
|
48
|
-
| 文件 | 位置 | 改动 |
|
|
49
|
-
|---|---|---|
|
|
50
|
-
| `src/ui/dashboard.ts` | `listHints()` SELECT 分支 `:1348-1357` | 按 D1 替换 token 列表 |
|
|
51
|
-
| `src/ui/dashboard.ts` | `renderHelp()` rows `:1723` | `In select` 行按 D2 替换 |
|
|
52
|
-
| `src/ui/dashboard.ts` | `renderHelp()` rows `:1715` 后 | 按 D3 插入 `?` 行 |
|
|
53
|
-
| `README.md` | `:148` `:166` `:180` `:200` | `repair hints` → `fix steps` |
|
|
54
|
-
| `README.md` | `:289` | `diagnosis and repair hints` → `diagnosis and fix steps` |
|
|
55
|
-
| `README.md` | `:368` | `follow its repair hints` → `follow its fix steps` |
|
|
56
|
-
| `test-support/vim-keys-wrap.ts` | capture 段 `:130` 之后 | 先插捕获代码:`tui.terminal.rows = 40`,在 SELECT 模式下取 `dash.render(160).join("\n")`,随后恢复 `rows = 24`(照 `:122-126` 的既有手法) |
|
|
57
|
-
| `test-support/vim-keys-wrap.ts` | `out.copy`(`:146`,单行对象字面量) | 把 `selectWide` 加进该对象 |
|
|
58
|
-
| `test/dashboard-vim-keys.test.mjs` | 末尾 | 新增一条 test(A1-A6) |
|
|
59
|
-
|
|
60
|
-
## 4. 验收矩阵
|
|
61
|
-
|
|
62
|
-
| ID | 功能点 | 验收方式 | 具体验证 | 通过标准 |
|
|
63
|
-
|----|--------|----------|----------|----------|
|
|
64
|
-
| A1 | SELECT hint 行文档化 9 组绑定中的 7 个键 + 2 个辅助键 | 自动化(unit,探针渲染) | `node --test test/dashboard-vim-keys.test.mjs`,对 `selectWide` 断言 `/↑↓\/j\/k move/`、`/space toggle/`、`/a all visible/`、`/u clear/`、`/d done/`、`/ctrl\+x delete/`、`/m\/esc cancel/`、`/· \? help · ! pty/` | 8 条全部通过 |
|
|
65
|
-
| A2 | 旧措辞不再出现 | 自动化(unit) | 同命令,`assert.doesNotMatch(selectWide, /d move done/)`、`/ctrl\+x delete done/` | 2 条负向断言通过 |
|
|
66
|
-
| A3 | hint 行宽度受控(防再次膨胀) | 自动化(unit) | 从 `selectWide` 取含 `[SELECT]` 的行,`trimEnd().length` 断言 `<= 132` | 131 ≤ 132 通过;超过即红 |
|
|
67
|
-
| A4 | 覆盖层 `In select` 行同步 | 自动化(unit,探针 `help120`,rows=40) | `/In select.*↑↓\/j\/k move/`、`/In select.*space toggle/`、`/In select.*a all · u clear/`、`/In select.*d done/`、`/In select.*ctrl\+x delete/`、`/In select.*m\/esc cancel/`;负向 `/In select.*a select all/` | 6 条正向 + 1 条负向通过 |
|
|
68
|
-
| A5 | 覆盖层新增 `?` 行 | 自动化(unit,`help120`) | `/\?\s+Open the key help overlay \(list and multi-select\)/` | 通过 |
|
|
69
|
-
| A6 | `!` 措辞统一(in-app 侧) | 自动化(unit,`help120`) | `/Open node-pty diagnostics and fix steps/` 且 `doesNotMatch(/repair hints/)` | 通过 |
|
|
70
|
-
| A7 | 无回归 | 自动化(unit,全量) | `npm test` | 全绿,尤其既有 `dashboard-vim-keys` 两条用例 |
|
|
71
|
-
| A8 | README 六处措辞改齐 | 自动化(static,grep;dev 工具,未入 CI) | `grep -c 'repair hints' README.md` → 0 行匹配;`grep -c 'fix steps' README.md` → 6 | 两个计数符合预期 |
|
|
72
|
-
| A9 | 类型/构建/覆盖率门槛 | 自动化(build + test) | `npm run verify` | typecheck、perf gate、全测试、coverage(lines 85 / funcs 80 / branches 70)、pack:dry 全过 |
|
|
73
|
-
| U1 | 真机观感 | 用户实测 | **前置**:PR 合并后在本 checkout `git pull`;确认扩展从本 checkout 加载(README `### Development auto-discovery`:`ln -s "$(pwd)" ~/.pi/agent/extensions/agent-board`,或 `pi install "$(pwd)"`;npm registry 副本要等发版才能看到改动);**重开 pi 会话**后测(扩展只在 pi 启动时加载,已在跑的实例不会拾取新代码)。**步骤**:① `pi /agent-board`,按 `m`,看底栏是否完整列出 9 项(终端 ≥132 列时可全见,120 列时尾部 `? help`/`! pty` 会被裁——符合 D1 取舍)② 按 `?`,看 `In select` 行含 `space toggle` ③ 在覆盖层确认 `?` 行与 `!` 行文案 ④ 按 `!`:面板标题恒为 `node-pty diagnostics`;**若 PTY 健康**,确认只显示 `Status: healthy`(正文无 `repair hints` 旧措辞即符合 D4);**若面板进故障分支**,确认分节标签为 `Fix:` / `Suggested steps`(这两段只在非健康分支渲染,健康机器上不出现是预期的) ⑤ 按 `m` 或 `esc` 退出 | 五步观察与 D1-D4 一致;若 120 列下尾部裁剪超出预期,记录实际宽度并回报(不视为失败,D1 已声明取舍) |
|
|
74
|
-
|
|
75
|
-
## 5. 可测性拆分设计
|
|
76
|
-
|
|
77
|
-
**不新增函数、不改拆分。** 两个改动点都是既有渲染路径里的字符串字面量:
|
|
78
|
-
|
|
79
|
-
- `listHints()`(`:1340`)已是纯字符串构造:输入 `this.mode` / `selectionCount()` / `unreadCount()` / `input`,输出 `string`,无 I/O、无副作用;由 `renderFooter` 消费。**不把 token 数组提成模块常量**:那样测试只能断言常量自身(同义反复),反而弱于在渲染面上断言。
|
|
80
|
-
- `renderHelp()`(`:1698`)已是 `width -> string[]` 的纯渲染方法,`rows` 是方法内字面量;同样保持内联。
|
|
81
|
-
|
|
82
|
-
**测试边界**:`test-support/vim-keys-wrap.ts`(探针,`node --experimental-transform-types`)→ `test/dashboard-vim-keys.test.mjs`(`node:test` + `assert/strict`)。这是本仓既定的 dashboard 文本断言层级(unit),不需要 integration / E2E:改动不跨组件、不涉及文件或协议。
|
|
83
|
-
|
|
84
|
-
**探针改造(最小)**:现有 `selectRender`(`test-support/vim-keys-wrap.ts:130`)是 120 列,新行 131 字符会被 `clip()` 裁尾 → A1/A3 假红。故新增 `selectWide`(`rows = 40` 下 `render(160)`,插在 `:130` 之后,结果挂进 `:146` 的 `out.copy`)。覆盖层断言复用既有 `help120`(已是 rows=40,绕开 `#246` 的裁剪)。
|
|
85
|
-
|
|
86
|
-
**红绿校验**:A1/A2/A4/A5 在改动前必须是红的。已核对:`space toggle` 早在 `9612d92` 就在 SELECT hint 行里,因此**不能**用它做唯一断言(issue 原建议的 `assert.match(selectRender, /space toggle/)` 今天就是绿的);`m/esc`、`? help`、`! pty`、`In select.*space toggle`、`?` 行在本改动前均不存在(research/03 红绿表)。
|
|
87
|
-
|
|
88
|
-
**不可自动化项**:README 文本(A8 用 `grep -c` 静态核对,不新建 README-lint 测试——仓内无读 README 的测试先例,为此基建超出范围);U1 的真机观感(终端宽度、配色、截断位置只能在真终端上判断)。
|
|
89
|
-
|
|
90
|
-
## 6. 非目标
|
|
91
|
-
|
|
92
|
-
- 不修 `#246`(帮助面板在 <32 行终端的裁剪)——D3 会让它多一行,属于 `#246` 的自留地。
|
|
93
|
-
- 不改任何键位绑定、不改 handler 分支逻辑。
|
|
94
|
-
- 不新增 README 表格、不调整 README 章节结构、不回改 `docs/superpowers/{specs,plans}/2026-10-26-issue-245-*` 历史留档。
|
|
95
|
-
- 不改 `renderPtyHelp` 的面板标签(`Fix:` / `Suggested steps`)——D4 以它们为准。
|