@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,211 +0,0 @@
|
|
|
1
|
-
# Question/Questionnaire Tool Grouping 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:** Make pi sessions blocked on the `question`/`questionnaire` tools group under "Needs answer" instead of "Running".
|
|
6
|
-
|
|
7
|
-
**Architecture:** Two minimal changes to `src/core/events.mjs`: (1) extend the private `questionFromArgs` helper to read pi's arg shapes; (2) replace the hardcoded `=== "ask_questions"` name checks with a `QUESTION_TOOL_NAMES` set. All downstream behavior (needs_input state, grouping, summary) already exists via `preservePendingQuestion` and `deriveSummary` — verified in spec section 3.3, nothing else changes.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** Node.js (`.mjs` ESM, no deps), `node:test` + `node:assert/strict` for tests.
|
|
10
|
-
|
|
11
|
-
## Global Constraints
|
|
12
|
-
|
|
13
|
-
- All code changes confined to `src/core/events.mjs` and `test/events.test.mjs`.
|
|
14
|
-
- No store/schema/type changes; no changes to `finalizeRun`, `projectViewState`, `deriveSummary`, `rows.mjs`, `service.mjs`.
|
|
15
|
-
- Non-interactive (detached) reduction path keeps its current behavior — the `opts.interactive` gate stays.
|
|
16
|
-
- Static name set, no config surface.
|
|
17
|
-
- Commit messages in conventional commits format; stage files individually (`git add <file>`), never `git add -A`.
|
|
18
|
-
- Test command: `node --test test/events.test.mjs`; project gate: `npm run verify`.
|
|
19
|
-
- Work in worktree `/home/elling/git-repo/github/pi-agent-board/.pi/worktrees/issue-26-question-tool-grouping`; never touch main.
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
### Task 1: Extend `questionFromArgs` for pi arg shapes
|
|
24
|
-
|
|
25
|
-
**Files:**
|
|
26
|
-
- Modify: `src/core/events.mjs:229-235`
|
|
27
|
-
- Test: `test/events.test.mjs` (append new test near the ask_questions tests, after line 160)
|
|
28
|
-
|
|
29
|
-
**Interfaces:**
|
|
30
|
-
- Consumes: nothing new.
|
|
31
|
-
- Produces: `questionFromArgs(args)` (private) returns the first non-empty question text from: `args.question` (string), or `args.questions[]` items' `question` or `prompt` fields; falls back to `"Answer the pending question"`. Task 2's name-recognition relies on this extraction.
|
|
32
|
-
|
|
33
|
-
- [ ] **Step 1: Write the failing test**
|
|
34
|
-
|
|
35
|
-
Append to `test/events.test.mjs` (after the "interactive questions remain visible..." test):
|
|
36
|
-
|
|
37
|
-
```js
|
|
38
|
-
test("questionFromArgs extracts pi question/questionnaire arg shapes", () => {
|
|
39
|
-
// pi `question` tool shape: args.question is a plain string.
|
|
40
|
-
const s1 = createRunStatus(cfg(), 1, 1000);
|
|
41
|
-
reduceEvent(s1, {
|
|
42
|
-
type: "tool_execution_start",
|
|
43
|
-
toolCallId: "q1",
|
|
44
|
-
toolName: "ask_questions",
|
|
45
|
-
args: { question: "Approve the plan?" },
|
|
46
|
-
}, 2000, { interactive: true });
|
|
47
|
-
assert.equal(s1.question, "Approve the plan?");
|
|
48
|
-
|
|
49
|
-
// pi `questionnaire` tool shape: args.questions[].prompt.
|
|
50
|
-
const s2 = createRunStatus(cfg(), 1, 1000);
|
|
51
|
-
reduceEvent(s2, {
|
|
52
|
-
type: "tool_execution_start",
|
|
53
|
-
toolCallId: "q1",
|
|
54
|
-
toolName: "ask_questions",
|
|
55
|
-
args: { questions: [{ prompt: "Pick the scope?" }] },
|
|
56
|
-
}, 2000, { interactive: true });
|
|
57
|
-
assert.equal(s2.question, "Pick the scope?");
|
|
58
|
-
});
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Note: the tests route through the reducer with the already-recognized `ask_questions` name because `questionFromArgs` is private and the reducer is the public surface; name recognition for the pi tools lands in Task 2.
|
|
62
|
-
|
|
63
|
-
- [ ] **Step 2: Run test to verify it fails**
|
|
64
|
-
|
|
65
|
-
Run: `node --test test/events.test.mjs`
|
|
66
|
-
Expected: FAIL — both assertions get `"Answer the pending question"` (the current extractor only reads `questions[].question`).
|
|
67
|
-
|
|
68
|
-
- [ ] **Step 3: Implement the extractor**
|
|
69
|
-
|
|
70
|
-
Replace the body of `questionFromArgs` in `src/core/events.mjs` (L229-235):
|
|
71
|
-
|
|
72
|
-
```js
|
|
73
|
-
function questionFromArgs(args) {
|
|
74
|
-
if (typeof args?.question === "string" && args.question.trim()) return args.question.trim();
|
|
75
|
-
for (const item of Array.isArray(args?.questions) ? args.questions : []) {
|
|
76
|
-
const question = String(item?.question ?? item?.prompt ?? "").trim();
|
|
77
|
-
if (question) return question;
|
|
78
|
-
}
|
|
79
|
-
return "Answer the pending question";
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
- [ ] **Step 4: Run tests to verify they pass**
|
|
84
|
-
|
|
85
|
-
Run: `node --test test/events.test.mjs`
|
|
86
|
-
Expected: PASS (all 17 existing + 1 new test).
|
|
87
|
-
|
|
88
|
-
- [ ] **Step 5: Commit**
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
git add src/core/events.mjs test/events.test.mjs
|
|
92
|
-
git commit -m "fix: support pi question arg shapes in questionFromArgs (issue #26)"
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
### Task 2: Recognize `question`/`questionnaire` as pending-question tools
|
|
98
|
-
|
|
99
|
-
**Files:**
|
|
100
|
-
- Modify: `src/core/events.mjs:25-27` (insert set), `src/core/events.mjs:83`, `src/core/events.mjs:97`
|
|
101
|
-
- Test: `test/events.test.mjs` (append three tests after the Task 1 test)
|
|
102
|
-
|
|
103
|
-
**Interfaces:**
|
|
104
|
-
- Consumes: `questionFromArgs` extraction from Task 1.
|
|
105
|
-
- Produces: `QUESTION_TOOL_NAMES` (module-private `Set<string>`). `reduceEvent` treats any interactive tool_execution_start/end whose tool name is in the set as a pending-question event — `upsertPendingQuestion`/`removePendingQuestion` plus the existing `preservePendingQuestion` flow (needs_input state, `currentTool = null`).
|
|
106
|
-
|
|
107
|
-
- [ ] **Step 1: Write the failing tests**
|
|
108
|
-
|
|
109
|
-
Append to `test/events.test.mjs`:
|
|
110
|
-
|
|
111
|
-
```js
|
|
112
|
-
test("interactive pi question tool is treated as a pending question", () => {
|
|
113
|
-
const s = createRunStatus(cfg(), 1, 1000);
|
|
114
|
-
reduceEvent(s, {
|
|
115
|
-
type: "tool_execution_start",
|
|
116
|
-
toolCallId: "q1",
|
|
117
|
-
toolName: "question",
|
|
118
|
-
args: { question: "Approve the plan?", options: [{ label: "Yes" }, { label: "No" }] },
|
|
119
|
-
}, 2000, { interactive: true });
|
|
120
|
-
assert.equal(s.semanticState, "needs_input");
|
|
121
|
-
assert.equal(s.question, "Approve the plan?");
|
|
122
|
-
assert.equal(s.currentTool, null);
|
|
123
|
-
assert.equal(s.summary, "Approve the plan?");
|
|
124
|
-
assert.deepEqual(s.pendingQuestions, [{ toolCallId: "q1", question: "Approve the plan?" }]);
|
|
125
|
-
assert.equal(projectViewState(s, 2100).needsInput, true);
|
|
126
|
-
|
|
127
|
-
reduceEvent(s, { type: "tool_execution_end", toolCallId: "q1", toolName: "question", isError: false }, 2400, { interactive: true });
|
|
128
|
-
assert.equal(s.semanticState, "working");
|
|
129
|
-
assert.equal(s.question, null);
|
|
130
|
-
assert.deepEqual(s.pendingQuestions, []);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test("interactive questionnaire tool extracts prompt and clears on end", () => {
|
|
134
|
-
const s = createRunStatus(cfg(), 1, 1000);
|
|
135
|
-
reduceEvent(s, {
|
|
136
|
-
type: "tool_execution_start",
|
|
137
|
-
toolCallId: "q1",
|
|
138
|
-
toolName: "questionnaire",
|
|
139
|
-
args: { questions: [{ prompt: "Pick the scope?" }] },
|
|
140
|
-
}, 2000, { interactive: true });
|
|
141
|
-
assert.equal(s.semanticState, "needs_input");
|
|
142
|
-
assert.equal(s.question, "Pick the scope?");
|
|
143
|
-
reduceEvent(s, { type: "tool_execution_end", toolCallId: "q1", toolName: "questionnaire", isError: false }, 2400, { interactive: true });
|
|
144
|
-
assert.equal(s.semanticState, "working");
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test("detached question tool keeps legacy currentTool behavior", () => {
|
|
148
|
-
const s = createRunStatus(cfg(), 1, 1000);
|
|
149
|
-
reduceEvent(s, { type: "tool_execution_start", toolCallId: "q1", toolName: "question", args: { question: "Approve?" } }, 2000);
|
|
150
|
-
assert.equal(s.semanticState, "working");
|
|
151
|
-
assert.equal(s.currentTool.name, "question");
|
|
152
|
-
assert.deepEqual(s.pendingQuestions, []);
|
|
153
|
-
});
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
- [ ] **Step 2: Run tests to verify they fail**
|
|
157
|
-
|
|
158
|
-
Run: `node --test test/events.test.mjs`
|
|
159
|
-
Expected: FAIL — question/questionnaire names are not recognized: first test asserts `needs_input` but gets `working` with `currentTool.name === "question"`.
|
|
160
|
-
|
|
161
|
-
- [ ] **Step 3: Add the name set and wire the two checks**
|
|
162
|
-
|
|
163
|
-
Insert after the imports at the top of `src/core/events.mjs` (before `createRunStatus`, ~L25):
|
|
164
|
-
|
|
165
|
-
```js
|
|
166
|
-
/** Tool names whose interactive execution blocks on a user answer. */
|
|
167
|
-
const QUESTION_TOOL_NAMES = new Set(["ask_questions", "question", "questionnaire"]);
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Replace L83:
|
|
171
|
-
|
|
172
|
-
```js
|
|
173
|
-
if (opts.interactive && QUESTION_TOOL_NAMES.has(name)) {
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Replace L97:
|
|
177
|
-
|
|
178
|
-
```js
|
|
179
|
-
if (opts.interactive && QUESTION_TOOL_NAMES.has(event.toolName ?? "")) removePendingQuestion(status, event.toolCallId);
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
- [ ] **Step 4: Run tests to verify they pass**
|
|
183
|
-
|
|
184
|
-
Run: `node --test test/events.test.mjs`
|
|
185
|
-
Expected: PASS (21 tests total: 17 existing + 1 Task 1 + 3 new). Existing `ask_questions` tests must pass unchanged.
|
|
186
|
-
|
|
187
|
-
- [ ] **Step 5: Full project gate**
|
|
188
|
-
|
|
189
|
-
Run: `npm run verify`
|
|
190
|
-
Expected: typecheck, all tests, and pack dry-run pass.
|
|
191
|
-
|
|
192
|
-
- [ ] **Step 6: Commit**
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
git add src/core/events.mjs test/events.test.mjs
|
|
196
|
-
git commit -m "fix: recognize question/questionnaire tools as pending questions (issue #26)"
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
## Self-Review
|
|
202
|
-
|
|
203
|
-
**Spec coverage:**
|
|
204
|
-
- Spec 3.1 (QUESTION_TOOL_NAMES replacing both hardcoded checks) → Task 2 steps 3. ✓
|
|
205
|
-
- Spec 3.2 (questionFromArgs pi shapes: `args.question`, `items[].prompt`, fallback `item.question`) → Task 1 step 3. ✓
|
|
206
|
-
- Spec 3.4 tests 1-4 (question start→needs_input, questionnaire extraction, end→working, detached unchanged) → Task 2 step 1 + Task 1 step 1. ✓
|
|
207
|
-
- Spec 3.3 downstream flow unchanged → asserted via `summary`/`needsInput` in Task 2 test 1; no production code touched outside `events.mjs`. ✓
|
|
208
|
-
|
|
209
|
-
**Placeholder scan:** every step carries concrete code or exact commands; no TBD/TODO/"similar to". ✓
|
|
210
|
-
|
|
211
|
-
**Type consistency:** `QUESTION_TOOL_NAMES` used identically in both replace steps; arg fields (`question`, `questions[].prompt`) match the pi extension schemas (`~/.pi/agent/extensions/question.ts`, `questionnaire.ts`). ✓
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
# Rename State Labels 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:** Rename dashboard state labels so each waiting state names the user action it waits for: `needs_input` → "Needs answer", `idle` → "Needs instructions", plus header wording "awaiting input" → "needs answer".
|
|
6
|
-
|
|
7
|
-
**Architecture:** Display-only rename riding the existing label pipeline: `GROUP_LABELS` (group headers, confirm prompts, filter aliases) and `fallbackStatusText` (row summaries) are the two label sources; persisted summaries normalize at render time via `normalizeGenericStatusText` + `GENERIC_STATUS_TEXT` legacy sets, so old rows migrate visually with zero data writes.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** Node.js ESM (`.mjs`) core + TypeScript UI file, `node --test` test runner, JSDoc typedefs.
|
|
10
|
-
|
|
11
|
-
## Global Constraints
|
|
12
|
-
|
|
13
|
-
- No changes to `SEMANTIC_STATES`, store schemas, state transitions, or classifier internals (issue #14's scope).
|
|
14
|
-
- `GENERIC_STATUS_TEXT` sets only ever GROW — "Needs input", "Idle", "In Progress" must remain recognized legacy texts.
|
|
15
|
-
- Do NOT edit `PRD.md` or `IMPLEMENTATION_PLAN.md` (historical point-in-time docs).
|
|
16
|
-
- Commit messages in English, conventional-commits format; stage files explicitly (never `git add -A`).
|
|
17
|
-
- All work happens in the worktree `/home/elling/git-repo/github/pi-agent-board/.pi/worktrees/issue-15-rename-state-labels` (branch `issue-15-rename-state-labels`). Never touch the main checkout.
|
|
18
|
-
- Exact new labels: `"Needs answer"` (needs_input), `"Needs instructions"` (idle), header `"needs answer"` / compact `"answer"`.
|
|
19
|
-
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
### Task 1: Core label constants and normalization (types.mjs, derive.mjs)
|
|
23
|
-
|
|
24
|
-
**Files:**
|
|
25
|
-
- Modify: `src/core/types.mjs:65,70` (`GROUP_LABELS`)
|
|
26
|
-
- Modify: `src/core/derive.mjs:19-20,52-54` (`GENERIC_STATUS_TEXT`, `fallbackStatusText`)
|
|
27
|
-
- Test: `test/derive.test.mjs:92-98`, `test/rows.test.mjs:85-88`
|
|
28
|
-
|
|
29
|
-
**Interfaces:**
|
|
30
|
-
- Consumes: none (leaf change).
|
|
31
|
-
- Produces: `GROUP_LABELS.needs_input === "Needs answer"`, `GROUP_LABELS.idle === "Needs instructions"`; `fallbackStatusText("needs_input") === "Needs answer"`, `fallbackStatusText("idle") === "Needs instructions"`; `normalizeGenericStatusText` recognizes "Needs input" → needs_input label, {"Idle","In Progress"} → idle label.
|
|
32
|
-
|
|
33
|
-
- [ ] **Step 1: Update the failing tests**
|
|
34
|
-
|
|
35
|
-
In `test/derive.test.mjs`, extend the import (line 3) and replace/extend the fallback test:
|
|
36
|
-
|
|
37
|
-
```js
|
|
38
|
-
import { deriveSummary, fallbackStatusText, finalizeSemanticState, normalizeGenericStatusText } from "../src/core/derive.mjs";
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
```js
|
|
42
|
-
test("fallbackStatusText", () => {
|
|
43
|
-
assert.equal(fallbackStatusText("queued"), "Queued");
|
|
44
|
-
assert.equal(fallbackStatusText("working"), "Running…");
|
|
45
|
-
assert.equal(fallbackStatusText("needs_input"), "Needs answer");
|
|
46
|
-
assert.equal(fallbackStatusText("idle"), "Needs instructions");
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("normalizeGenericStatusText maps legacy labels to current ones", () => {
|
|
50
|
-
assert.equal(normalizeGenericStatusText("idle", "Idle"), "Needs instructions");
|
|
51
|
-
assert.equal(normalizeGenericStatusText("idle", "In Progress"), "Needs instructions");
|
|
52
|
-
assert.equal(normalizeGenericStatusText("needs_input", "Needs input"), "Needs answer");
|
|
53
|
-
assert.equal(normalizeGenericStatusText("idle", "Custom summary"), "Custom summary");
|
|
54
|
-
});
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
In `test/rows.test.mjs`, replace the existing normalization test (lines 85-88) with:
|
|
58
|
-
|
|
59
|
-
```js
|
|
60
|
-
test("rowView normalizes generic status labels to current display names", () => {
|
|
61
|
-
assert.equal(rowView(row("a", "working", { summary: "Working…" }), 0).summary, "Running…");
|
|
62
|
-
assert.equal(rowView(row("b", "idle", { summary: "Idle" }), 0).summary, "Needs instructions");
|
|
63
|
-
assert.equal(rowView(row("c", "idle", { summary: "In Progress" }), 0).summary, "Needs instructions");
|
|
64
|
-
assert.equal(rowView(row("d", "needs_input", { summary: "Needs input" }), 0).summary, "Needs answer");
|
|
65
|
-
});
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
(`row(id, state, overrides)` is the existing test helper in that file.)
|
|
69
|
-
|
|
70
|
-
- [ ] **Step 2: Run tests to verify they fail**
|
|
71
|
-
|
|
72
|
-
Run: `cd /home/elling/git-repo/github/pi-agent-board/.pi/worktrees/issue-15-rename-state-labels && npm ci --no-audit --no-fund && node --test test/derive.test.mjs test/rows.test.mjs`
|
|
73
|
-
Expected: FAIL — fallbackStatusText/rowView assertions return "Needs input"/"In Progress". (Skip `npm ci` if node_modules already exists.)
|
|
74
|
-
|
|
75
|
-
- [ ] **Step 3: Implement**
|
|
76
|
-
|
|
77
|
-
`src/core/types.mjs` — in `GROUP_LABELS`:
|
|
78
|
-
|
|
79
|
-
```js
|
|
80
|
-
needs_input: "Needs answer",
|
|
81
|
-
```
|
|
82
|
-
```js
|
|
83
|
-
idle: "Needs instructions",
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
`src/core/derive.mjs` — legacy sets (keep old entries, add new):
|
|
87
|
-
|
|
88
|
-
```js
|
|
89
|
-
needs_input: new Set(["Needs input", "Needs answer"]),
|
|
90
|
-
idle: new Set(["Idle", "In Progress", "Needs instructions"]),
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
`fallbackStatusText` cases:
|
|
94
|
-
|
|
95
|
-
```js
|
|
96
|
-
case "needs_input":
|
|
97
|
-
return "Needs answer";
|
|
98
|
-
case "idle":
|
|
99
|
-
return "Needs instructions";
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
- [ ] **Step 4: Run tests to verify they pass**
|
|
103
|
-
|
|
104
|
-
Run: `node --test test/derive.test.mjs test/rows.test.mjs`
|
|
105
|
-
Expected: PASS (all tests in both files).
|
|
106
|
-
|
|
107
|
-
- [ ] **Step 5: Commit**
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
git add src/core/types.mjs src/core/derive.mjs test/derive.test.mjs test/rows.test.mjs
|
|
111
|
-
git commit -m "feat: rename needs_input/idle labels to Needs answer/Needs instructions (issue #15)"
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### Task 2: Call-site labels and header wording (service.mjs, dashboard.ts, README)
|
|
115
|
-
|
|
116
|
-
**Files:**
|
|
117
|
-
- Modify: `src/runtime/service.mjs:961` (reconciled-host summary)
|
|
118
|
-
- Modify: `src/ui/dashboard.ts:926` (compat-guard blank state summary), `src/ui/dashboard.ts:1757` (header stage part)
|
|
119
|
-
- Modify: `README.md:65` (state list)
|
|
120
|
-
- Test: none new — grep-confirmed zero test assertions on these exact strings; suite must stay green.
|
|
121
|
-
|
|
122
|
-
**Interfaces:**
|
|
123
|
-
- Consumes: Task 1 label values (only literals here; no imports of the strings).
|
|
124
|
-
- Produces: none.
|
|
125
|
-
|
|
126
|
-
- [ ] **Step 1: Edit the four call sites**
|
|
127
|
-
|
|
128
|
-
`src/runtime/service.mjs` (~L961, inside `reconcile()`):
|
|
129
|
-
```js
|
|
130
|
-
s.summary = failed ? "Failed (PTY host exited)" : "Needs instructions";
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
`src/ui/dashboard.ts` (~L926, blank-state compat guard):
|
|
134
|
-
```js
|
|
135
|
-
summary: "Needs instructions",
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
`src/ui/dashboard.ts` (~L1757, `headerStageSummary`):
|
|
139
|
-
```js
|
|
140
|
-
headerStagePart(theme, "needs_input", counts.needs, compact ? "answer" : "needs answer"),
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
`README.md` (L65):
|
|
144
|
-
```markdown
|
|
145
|
-
- Watch rows move through `Queued`, `Running`, `Needs answer`, `Needs instructions`, `Done`, `Failed`, and `Stopped`.
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
- [ ] **Step 2: Run the full suite and typecheck**
|
|
149
|
-
|
|
150
|
-
Run: `npm test && npm run typecheck`
|
|
151
|
-
Expected: PASS — `node --test test/*.test.mjs` all green, `tsc --noEmit` clean.
|
|
152
|
-
|
|
153
|
-
- [ ] **Step 3: Commit**
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
git add src/runtime/service.mjs src/ui/dashboard.ts README.md
|
|
157
|
-
git commit -m "feat: apply Needs answer/Needs instructions wording to service, header, and README (issue #15)"
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Task 3: Full verification gate
|
|
161
|
-
|
|
162
|
-
**Files:**
|
|
163
|
-
- Modify: none (verification only; fix and amend-with-new-commit if anything fails).
|
|
164
|
-
|
|
165
|
-
**Interfaces:**
|
|
166
|
-
- Consumes: Tasks 1-2.
|
|
167
|
-
- Produces: verified branch ready for review.
|
|
168
|
-
|
|
169
|
-
- [ ] **Step 1: Run the project's standard gate**
|
|
170
|
-
|
|
171
|
-
Run: `npm run verify`
|
|
172
|
-
Expected: typecheck + full test suite + pack:dry all pass.
|
|
173
|
-
|
|
174
|
-
- [ ] **Step 2: Sweep for stale label strings**
|
|
175
|
-
|
|
176
|
-
Run: `grep -rn '"In Progress"' src/ README.md; grep -rn 'awaiting input' src/`
|
|
177
|
-
Expected: "In Progress" appears ONLY in `src/core/derive.mjs` legacy set; "awaiting input" zero hits.
|
|
178
|
-
|
|
179
|
-
- [ ] **Step 3: Confirm clean tree**
|
|
180
|
-
|
|
181
|
-
Run: `git status --short && git log --oneline main..HEAD`
|
|
182
|
-
Expected: clean tree; commits = spec + task 1 + task 2.
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Stable List Order 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:** Make the dashboard list order stable — rows must never reshuffle while sessions are running, so the cursor never loses its target (issue #20).
|
|
6
|
-
|
|
7
|
-
**Architecture:** Replace activity-time sort keys with fixed creation-time keys. `lastActivityAt` stays in `RowView` for the "3s ago" display only, never for ordering. Rows sort by `pinned desc → createdAt asc → id asc`; folders sort by `pinned desc → min(createdAt) asc → name asc`, so a folder's position is anchored by its first-created row and doesn't jump when any row inside gets busy. New sessions append at the bottom (createdAt ascending).
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** Node 20+, 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-20-stable-list-order`; never touch `main` checkout.
|
|
15
|
-
- `git add` per-file; never `git add -A`.
|
|
16
|
-
- Commit messages in English, conventional-commits format, reference `issue #20`.
|
|
17
|
-
- `npm run verify` (typecheck + tests + pack dry-run) must pass before the PR.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
### Task 1: Stable row sort in `sortRowViews`
|
|
22
|
-
|
|
23
|
-
**Files:**
|
|
24
|
-
- Modify: `src/core/rows.mjs` (function `sortRowViews`)
|
|
25
|
-
- Test: `test/rows.test.mjs`
|
|
26
|
-
|
|
27
|
-
- [x] Add `createdAt` to `RowView` typedef and `rowView()` output (fallback `meta.updatedAt ?? 0`).
|
|
28
|
-
- [x] Change sort keys to `pinned desc → createdAt asc → id asc`.
|
|
29
|
-
- [x] Update `groupRows` doc comment ("pinned first, then creation order").
|
|
30
|
-
- [x] Rewrite `groupRows sorts pinned first then recent` test → creation order, plus new regression test `groupRows ignores activity recency so order stays stable`.
|
|
31
|
-
|
|
32
|
-
### Task 2: Stable folder sort in `groupRowsByFolder`
|
|
33
|
-
|
|
34
|
-
**Files:**
|
|
35
|
-
- Modify: `src/core/rows.mjs` (function `groupRowsByFolder`)
|
|
36
|
-
- Test: `test/rows.test.mjs`
|
|
37
|
-
|
|
38
|
-
- [x] Folder key `lastActivityAt` → `createdAt`, computed as `Math.min` over folder rows (first-created row anchors the folder).
|
|
39
|
-
- [x] Folder sort keys → `pinned desc → createdAt asc → name asc`; update JSDoc return type.
|
|
40
|
-
- [x] Update `groupRowsByFolder nests rows by folder inside each stage` expectations, plus new regression test `groupRowsByFolder keeps folder order stable regardless of activity`.
|
|
41
|
-
|
|
42
|
-
### Task 3: Verify
|
|
43
|
-
|
|
44
|
-
- [x] `node --test test/rows.test.mjs` — 18 pass.
|
|
45
|
-
- [x] `npm run verify` — typecheck + full suite (200 pass) + pack dry-run.
|
|
46
|
-
|
|
47
|
-
## Non-goals
|
|
48
|
-
|
|
49
|
-
- Display of relative age ("3s ago") unchanged — still activity-based.
|
|
50
|
-
- State-group order (`GROUP_ORDER`) unchanged — already fixed.
|
|
51
|
-
- No reordering of the roster on disk; ordering is a pure view-model concern.
|