@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,346 +0,0 @@
|
|
|
1
|
-
# Issue #169 Fullscreen Outer-Mouse Ownership 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:** Stop `PtyAttachComponent` from writing ANY outer-terminal mouse-mode sequence in fullscreen mode (where `TuiAltScreen` owns reporting), fixing the post-detach mouse kill and the mid-attach mode downgrade, while keeping regular-mode behavior byte-identical.
|
|
6
|
-
|
|
7
|
-
**Architecture:** A pure decision helper (`shouldOwnOuterMouseMode(mode, mouseEnabled)` in `src/core/pty-scroll.mjs`) decides ownership; the component's two write choke points (`enableMouseScroll`, `disableMouseScroll`) both early-return when it says no. All existing call sites (ctor, connect, resize, close) route through those two methods, so no other code changes.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** TypeScript (tabs), node:test + assert/strict, node --experimental-transform-types scenario with a fake-TUI write spy and a nonexistent control socket.
|
|
10
|
-
|
|
11
|
-
**Spec:** `docs/superpowers/specs/2026-10-09-issue-169-fullscreen-mouse-ownership-design.md` (acceptance IDs A1–A4, U1 referenced per task). Cross-review was waived by user decision (recorded in the issue research dir).
|
|
12
|
-
|
|
13
|
-
## Global Constraints
|
|
14
|
-
|
|
15
|
-
- Work ONLY inside the worktree `<WT>` (branch `issue-169-fullscreen-mouse-ownership`); never touch main.
|
|
16
|
-
- Tabs for indentation; English comments and commit messages; conventional commit subjects.
|
|
17
|
-
- Pure-function split is a hard spec constraint: `shouldOwnOuterMouseMode` must not read `process.env` or `this.*` (call site resolves both args); must not be re-inlined into the component.
|
|
18
|
-
- `enableMouseScroll` / `disableMouseScroll` must remain the ONLY places that write `MOUSE_ENABLE` / `MOUSE_DISABLE` / `XTSHIFTESCAPE_SELECT` to the outer terminal.
|
|
19
|
-
- Regular-mode behavior must stay byte-identical (ctor disable→enable→refresh, 0/50/250ms refresh timers, connect/resize re-enable, close disable) — only the ownership gate is new.
|
|
20
|
-
- No behavior change for wheel/scroll/selection/middle-paste inside attach views; no changes outside the two choke points.
|
|
21
|
-
- Tests use `node:test` with self-contained fixtures under temp dirs; never the host repository.
|
|
22
|
-
- `test/` and `test-support/` are EXCLUDED from tsc — scenario files are runtime-transformed only; `src/` must stay `npm run typecheck`-clean (pi-tui 1.1.0 typings provide `TUI.mode`).
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
### Task 1: Pure decision helper `shouldOwnOuterMouseMode` (A1)
|
|
27
|
-
|
|
28
|
-
**Files:**
|
|
29
|
-
- Modify: `src/core/pty-scroll.mjs` (add export next to `resolveAttachMouseAction`, near the other mouse helpers)
|
|
30
|
-
- Test: `test/pty-scroll.test.mjs` (extend the existing import block and append tests)
|
|
31
|
-
|
|
32
|
-
**Interfaces:**
|
|
33
|
-
- Consumes: none.
|
|
34
|
-
- Produces: `shouldOwnOuterMouseMode(mode, mouseEnabled) → boolean` where `mode` is `Tui["mode"] | undefined` (string `"regular" | "fullscreen" | undefined`). Task 2's component imports this from `../core/pty-scroll.mjs`.
|
|
35
|
-
|
|
36
|
-
- [ ] **Step 1: Write the failing test**
|
|
37
|
-
|
|
38
|
-
In `test/pty-scroll.test.mjs`, extend the existing import from `../src/core/pty-scroll.mjs` with `shouldOwnOuterMouseMode`, then append:
|
|
39
|
-
|
|
40
|
-
```js
|
|
41
|
-
test("shouldOwnOuterMouseMode: fullscreen never owns; regular/undefined follow the switch", () => {
|
|
42
|
-
assert.equal(shouldOwnOuterMouseMode("fullscreen", true), false);
|
|
43
|
-
assert.equal(shouldOwnOuterMouseMode("fullscreen", false), false);
|
|
44
|
-
assert.equal(shouldOwnOuterMouseMode("regular", true), true);
|
|
45
|
-
assert.equal(shouldOwnOuterMouseMode("regular", false), false);
|
|
46
|
-
// Old pi runtimes have no tui.mode — must behave like regular.
|
|
47
|
-
assert.equal(shouldOwnOuterMouseMode(undefined, true), true);
|
|
48
|
-
assert.equal(shouldOwnOuterMouseMode(undefined, false), false);
|
|
49
|
-
});
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
- [ ] **Step 2: Run test to verify it fails**
|
|
53
|
-
|
|
54
|
-
Run: `node --test test/pty-scroll.test.mjs`
|
|
55
|
-
Expected: FAIL — `shouldOwnOuterMouseMode` is not exported / not a function.
|
|
56
|
-
|
|
57
|
-
- [ ] **Step 3: Implement**
|
|
58
|
-
|
|
59
|
-
In `src/core/pty-scroll.mjs`, next to `resolveAttachMouseAction`:
|
|
60
|
-
|
|
61
|
-
```js
|
|
62
|
-
/**
|
|
63
|
-
* Issue #169: whether the attach surface should manage the OUTER terminal's
|
|
64
|
-
* mouse mode. Only in regular TUI mode — in fullscreen, TuiAltScreen owns
|
|
65
|
-
* mouse reporting (asserted once at startup, never re-asserted), so any write
|
|
66
|
-
* from the attach surface can only downgrade or kill it. Old runtimes without
|
|
67
|
-
* tui.mode behave as regular. Pure: both arguments are resolved at the call
|
|
68
|
-
* site (mode from the TUI, the flag from the env-derived helper).
|
|
69
|
-
*/
|
|
70
|
-
export function shouldOwnOuterMouseMode(mode, mouseEnabled) {
|
|
71
|
-
return mode !== "fullscreen" && !!mouseEnabled;
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
- [ ] **Step 4: Run test to verify it passes**
|
|
76
|
-
|
|
77
|
-
Run: `node --test test/pty-scroll.test.mjs`
|
|
78
|
-
Expected: PASS (new + all pre-existing cases).
|
|
79
|
-
|
|
80
|
-
- [ ] **Step 5: Commit**
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
git add src/core/pty-scroll.mjs test/pty-scroll.test.mjs
|
|
84
|
-
git commit -m "feat(attach): pure outer-mouse-mode ownership decision helper"
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
### Task 2: Component gating + runner-free ownership scenario (A2)
|
|
90
|
-
|
|
91
|
-
**Files:**
|
|
92
|
-
- Modify: `src/ui/pty-attach.ts` (import line ~13; new private method near `mouseScrollEnabled` (~:862); guards in `enableMouseScroll` (~:852) and `disableMouseScroll` (~:882))
|
|
93
|
-
- Create: `test-support/pty-attach-mouse-mode-scenario.ts`
|
|
94
|
-
- Test: `test/pty-attach-mouse-mode.test.mjs`
|
|
95
|
-
|
|
96
|
-
**Interfaces:**
|
|
97
|
-
- Consumes: `shouldOwnOuterMouseMode(mode, mouseEnabled)` from Task 1; `this.tui.mode` (typed `readonly mode: TuiMode` by pi-tui 1.1.0; absent at runtime on old hosts); `this.mouseScrollEnabled()` (existing private).
|
|
98
|
-
- Produces: private `ownsOuterMouseMode(): boolean`; gated `enableMouseScroll`/`disableMouseScroll`.
|
|
99
|
-
|
|
100
|
-
- [ ] **Step 1: Write the failing test + scenario**
|
|
101
|
-
|
|
102
|
-
Create `test/pty-attach-mouse-mode.test.mjs`:
|
|
103
|
-
|
|
104
|
-
```js
|
|
105
|
-
import assert from "node:assert/strict";
|
|
106
|
-
import test from "node:test";
|
|
107
|
-
import { execFileSync } from "node:child_process";
|
|
108
|
-
import { fileURLToPath } from "node:url";
|
|
109
|
-
import { join } from "node:path";
|
|
110
|
-
|
|
111
|
-
const ROOT_DIR = fileURLToPath(new URL("../", import.meta.url));
|
|
112
|
-
const SCENARIO = join(ROOT_DIR, "test-support", "pty-attach-mouse-mode-scenario.ts");
|
|
113
|
-
|
|
114
|
-
// Component-level outer-mouse-mode ownership coverage (issue #169): the REAL
|
|
115
|
-
// PtyAttachComponent against a fake TUI write spy and a nonexistent control
|
|
116
|
-
// socket. Asserts zero mouse-mode writes in fullscreen across ctor + refresh
|
|
117
|
-
// window + close, the preserved regular-mode pairing, zero writes under the
|
|
118
|
-
// kill switch (incl. close — the previously unguarded disable), and old-runtime
|
|
119
|
-
// (mode absent) behaving like regular.
|
|
120
|
-
test("attach mouse-mode ownership: fullscreen writes nothing; regular pairing kept; kill switch silent", () => {
|
|
121
|
-
const out = execFileSync(process.execPath, ["--experimental-transform-types", SCENARIO], {
|
|
122
|
-
encoding: "utf8",
|
|
123
|
-
timeout: 60_000,
|
|
124
|
-
});
|
|
125
|
-
const parsed = JSON.parse(out.trim().split("\n").filter(Boolean).pop());
|
|
126
|
-
assert.equal(parsed.error, null, `scenario error: ${parsed.error}`);
|
|
127
|
-
assert.equal(parsed.fullscreen.writes, 0, "fullscreen: zero mouse-mode/XTSHIFTESCAPE writes across ctor+timers+close");
|
|
128
|
-
assert.equal(parsed.fullscreen.enableAtCtor, false, "fullscreen: no MOUSE_ENABLE at ctor");
|
|
129
|
-
assert.equal(parsed.fullscreen.disableAtClose, false, "fullscreen: no MOUSE_DISABLE at close");
|
|
130
|
-
assert.equal(parsed.regular.enableAtCtor, true, "regular: MOUSE_ENABLE at ctor preserved");
|
|
131
|
-
assert.equal(parsed.regular.disableAtClose, true, "regular: MOUSE_DISABLE at close preserved");
|
|
132
|
-
assert.equal(parsed.off.writes, 0, "AGENT_BOARD_ATTACH_MOUSE=0: zero writes including close");
|
|
133
|
-
assert.equal(parsed.legacy.enableAtCtor, true, "old runtime (no mode): behaves like regular");
|
|
134
|
-
assert.equal(parsed.legacy.disableAtClose, true, "old runtime (no mode): close disables like regular");
|
|
135
|
-
});
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
Create `test-support/pty-attach-mouse-mode-scenario.ts`:
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
// Component-level outer-mouse-mode ownership coverage (issue #169): the REAL
|
|
142
|
-
// PtyAttachComponent with a fake TUI whose terminal.write collects bytes, run
|
|
143
|
-
// against a nonexistent control socket (on non-Windows, connect() short-
|
|
144
|
-
// circuits to its reconnect loop before creating a socket — no socket churn).
|
|
145
|
-
// Four cases:
|
|
146
|
-
// 1. mode "fullscreen" → ZERO mouse-mode/XTSHIFTESCAPE writes across
|
|
147
|
-
// ctor + the 0/50/250ms refresh window + close() (TuiAltScreen owns it);
|
|
148
|
-
// 2. mode "regular" → today's pairing preserved (MOUSE_ENABLE at
|
|
149
|
-
// ctor, MOUSE_DISABLE at close);
|
|
150
|
-
// 3. mode "regular" + AGENT_BOARD_ATTACH_MOUSE=0 → zero writes including
|
|
151
|
-
// close() (fixes the previously unguarded disable);
|
|
152
|
-
// 4. mode absent (old pi) → behaves like regular.
|
|
153
|
-
// Run via `node --experimental-transform-types`.
|
|
154
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
155
|
-
import { tmpdir } from "node:os";
|
|
156
|
-
import { join } from "node:path";
|
|
157
|
-
import { PtyAttachComponent } from "../src/ui/pty-attach.ts";
|
|
158
|
-
|
|
159
|
-
const sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));
|
|
160
|
-
|
|
161
|
-
const MOUSE_BYTE_RE = /\x1b\[\?(1000|1002|1003|1004|1006)[hl]/;
|
|
162
|
-
const XTSHIFTESCAPE_RE = /\x1b\[>0s/;
|
|
163
|
-
|
|
164
|
-
interface CaseResult {
|
|
165
|
-
writes: number;
|
|
166
|
-
enableAtCtor: boolean;
|
|
167
|
-
disableAtClose: boolean;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async function runCase(mode: string | undefined, env: Record<string, string> | undefined): Promise<CaseResult> {
|
|
171
|
-
const writes: string[] = [];
|
|
172
|
-
const tui = {
|
|
173
|
-
mode,
|
|
174
|
-
terminal: { rows: 24, cols: 80, columns: 80, write: (s: string) => { writes.push(s); } },
|
|
175
|
-
requestRender: () => {},
|
|
176
|
-
};
|
|
177
|
-
const theme = { fg: (_c: string, t: string) => t, bold: (t: string) => t };
|
|
178
|
-
const root = mkdtempSync(join(tmpdir(), "agentview-mouse-mode-"));
|
|
179
|
-
const socketPath = join(root, "nonexistent.sock");
|
|
180
|
-
const prevEnv: Record<string, string | undefined> = {};
|
|
181
|
-
for (const [k, v] of Object.entries(env ?? {})) {
|
|
182
|
-
prevEnv[k] = process.env[k];
|
|
183
|
-
process.env[k] = v;
|
|
184
|
-
}
|
|
185
|
-
let component: PtyAttachComponent | null = null;
|
|
186
|
-
try {
|
|
187
|
-
component = new PtyAttachComponent(
|
|
188
|
-
tui as never,
|
|
189
|
-
theme as never,
|
|
190
|
-
{} as never,
|
|
191
|
-
() => {},
|
|
192
|
-
{ socketPath, title: "mouse mode e2e" } as never,
|
|
193
|
-
);
|
|
194
|
-
const enableAtCtor = writes.some((s) => s.includes("\x1b[?1000h"));
|
|
195
|
-
await sleep(400); // past the 250ms refresh window
|
|
196
|
-
try { component.dispose(); } catch {}
|
|
197
|
-
await sleep(100);
|
|
198
|
-
const disableAtClose = writes.some((s) => s.includes("\x1b[?1000l"));
|
|
199
|
-
return {
|
|
200
|
-
writes: writes.filter((s) => MOUSE_BYTE_RE.test(s) || XTSHIFTESCAPE_RE.test(s)).length,
|
|
201
|
-
enableAtCtor,
|
|
202
|
-
disableAtClose,
|
|
203
|
-
};
|
|
204
|
-
} finally {
|
|
205
|
-
try { component?.dispose(); } catch {}
|
|
206
|
-
for (const [k, v] of Object.entries(prevEnv)) {
|
|
207
|
-
if (v === undefined) delete process.env[k];
|
|
208
|
-
else process.env[k] = v;
|
|
209
|
-
}
|
|
210
|
-
try { rmSync(root, { recursive: true, force: true, maxRetries: 3, retryDelay: 30 }); } catch {}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const result = {
|
|
215
|
-
error: null as string | null,
|
|
216
|
-
fullscreen: null as CaseResult | null,
|
|
217
|
-
regular: null as CaseResult | null,
|
|
218
|
-
off: null as CaseResult | null,
|
|
219
|
-
legacy: null as CaseResult | null,
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
try {
|
|
223
|
-
result.fullscreen = await runCase("fullscreen", undefined);
|
|
224
|
-
result.regular = await runCase("regular", undefined);
|
|
225
|
-
result.off = await runCase("regular", { AGENT_BOARD_ATTACH_MOUSE: "0" });
|
|
226
|
-
result.legacy = await runCase(undefined, undefined);
|
|
227
|
-
} catch (err) {
|
|
228
|
-
result.error = err instanceof Error ? err.message : String(err);
|
|
229
|
-
}
|
|
230
|
-
console.log(JSON.stringify(result));
|
|
231
|
-
process.exit(0);
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
- [ ] **Step 2: Run the test to verify it fails**
|
|
235
|
-
|
|
236
|
-
Run: `node --test test/pty-attach-mouse-mode.test.mjs`
|
|
237
|
-
Expected: FAIL — `parsed.fullscreen.writes` > 0 (ctor writes `MOUSE_DISABLE`+`XTSHIFTESCAPE`+`MOUSE_ENABLE`, refresh timers re-enable) and/or `parsed.off.writes` > 0 (unguarded disable). The `regular`/`legacy` assertions may already pass — the failure must be on the fullscreen/off fields.
|
|
238
|
-
|
|
239
|
-
- [ ] **Step 3: Implement the gating**
|
|
240
|
-
|
|
241
|
-
In `src/ui/pty-attach.ts`:
|
|
242
|
-
|
|
243
|
-
Import line (~13) — extend the core import (keep alphabetical order):
|
|
244
|
-
|
|
245
|
-
```ts
|
|
246
|
-
import { clampInt, parseMouseInputChunk, resolveAttachMouseAction, resolveWheelLines, scrollViewportTop, selectionDragScrollLines, shouldOwnOuterMouseMode } from "../core/pty-scroll.mjs";
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
Near `mouseScrollEnabled()` (~:862), add the private method:
|
|
250
|
-
|
|
251
|
-
```ts
|
|
252
|
-
/** Issue #169: in fullscreen mode TuiAltScreen owns outer-terminal mouse
|
|
253
|
-
* reporting (asserted once at startup, never re-asserted) — writing any
|
|
254
|
-
* mouse-mode sequence from here can only downgrade or kill it. tui.mode is
|
|
255
|
-
* typed non-optional but old pi runtimes lack it; the strict inequality
|
|
256
|
-
* then keeps today's (regular) behavior. */
|
|
257
|
-
private ownsOuterMouseMode(): boolean {
|
|
258
|
-
return shouldOwnOuterMouseMode(this.tui.mode, this.mouseScrollEnabled());
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
In `enableMouseScroll()` (~:852), replace the guard:
|
|
263
|
-
|
|
264
|
-
```ts
|
|
265
|
-
private enableMouseScroll(): void {
|
|
266
|
-
if (!this.ownsOuterMouseMode()) return;
|
|
267
|
-
try {
|
|
268
|
-
this.tui.terminal.write(XTSHIFTESCAPE_SELECT);
|
|
269
|
-
this.tui.terminal.write(MOUSE_ENABLE);
|
|
270
|
-
} catch {
|
|
271
|
-
/* best-effort: some terminals reject these sequences; mouse reporting is optional */
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
In `disableMouseScroll()` (~:882), add the guard as the first statement:
|
|
277
|
-
|
|
278
|
-
```ts
|
|
279
|
-
private disableMouseScroll(): void {
|
|
280
|
-
if (!this.ownsOuterMouseMode()) return;
|
|
281
|
-
try {
|
|
282
|
-
this.tui.terminal.write(MOUSE_DISABLE);
|
|
283
|
-
} catch {
|
|
284
|
-
/* best-effort: terminal may already be gone at teardown */
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
Do NOT change any other call site (ctor :278-280, connect :487, resize :1203, close :1524 route through these methods unchanged).
|
|
290
|
-
|
|
291
|
-
- [ ] **Step 4: Run the test to verify it passes**
|
|
292
|
-
|
|
293
|
-
Run: `node --test test/pty-attach-mouse-mode.test.mjs`
|
|
294
|
-
Expected: PASS.
|
|
295
|
-
|
|
296
|
-
- [ ] **Step 5: Run the unit tests + typecheck**
|
|
297
|
-
|
|
298
|
-
Run: `node --test test/pty-scroll.test.mjs && npm run typecheck`
|
|
299
|
-
Expected: PASS both.
|
|
300
|
-
|
|
301
|
-
- [ ] **Step 6: Commit**
|
|
302
|
-
|
|
303
|
-
```bash
|
|
304
|
-
git add src/ui/pty-attach.ts test-support/pty-attach-mouse-mode-scenario.ts test/pty-attach-mouse-mode.test.mjs
|
|
305
|
-
git commit -m "fix(attach): stop writing outer-terminal mouse mode in fullscreen (issue #169)"
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
---
|
|
309
|
-
|
|
310
|
-
### Task 3: Full verify + coverage gate (A3, A4)
|
|
311
|
-
|
|
312
|
-
**Files:**
|
|
313
|
-
- Modify: whatever Tasks 1–2 fallout requires (expected: none).
|
|
314
|
-
|
|
315
|
-
**Interfaces:**
|
|
316
|
-
- Consumes: everything from Tasks 1–2.
|
|
317
|
-
- Produces: green `npm run verify` — the PR-ready state.
|
|
318
|
-
|
|
319
|
-
- [ ] **Step 1: Run the full verify pipeline**
|
|
320
|
-
|
|
321
|
-
Run: `npm run verify` (= typecheck + perf gate + tests + coverage + pack:dry)
|
|
322
|
-
Expected: PASS end-to-end. Coverage thresholds: lines 85 / funcs 80 / branches 70 — `shouldOwnOuterMouseMode` is fully unit-covered (Task 1); the component gate lines are exercised by the Task 2 scenario at runtime (c8 does not instrument test-support, same as #171 — no coverage hacks).
|
|
323
|
-
|
|
324
|
-
- [ ] **Step 2: Fix any fallout, then re-run**
|
|
325
|
-
|
|
326
|
-
Run: `npm run verify`
|
|
327
|
-
Expected: PASS. If a pre-existing flaky real-process test blocks (issue #95), re-run that single test once; if still red, STOP and report BLOCKED with the failure output.
|
|
328
|
-
|
|
329
|
-
- [ ] **Step 3: Commit (only if Step 2 needed changes)**
|
|
330
|
-
|
|
331
|
-
```bash
|
|
332
|
-
git add <changed files>
|
|
333
|
-
git commit -m "test: verify fallout fixes for issue #169"
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
---
|
|
337
|
-
|
|
338
|
-
## Acceptance traceability
|
|
339
|
-
|
|
340
|
-
| Spec ID | Covered by |
|
|
341
|
-
| --- | --- |
|
|
342
|
-
| A1 (unit decision table) | Task 1 |
|
|
343
|
-
| A2 (component-level ownership scenario) | Task 2 |
|
|
344
|
-
| A3 (static/build) | Task 3 (+ typecheck in Task 2 Step 5) |
|
|
345
|
-
| A4 (existing suite regression) | Task 3 |
|
|
346
|
-
| U1 (user manual: detach-then-select survives; 5-step checklist) | Post-implementation checklist for the user — executed after merge or from the worktree install |
|