@zhuxixi/pi-agent-board 0.3.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/IMPLEMENTATION_PLAN.md +920 -0
- package/LICENSE +21 -0
- package/PRD.md +484 -0
- package/PROGRESS.md +127 -0
- package/README.md +131 -0
- package/VERIFY.md +113 -0
- package/docs/BATCH_SELECTION_READ_FLOW.md +277 -0
- package/docs/EXPLORATION.md +187 -0
- package/docs/PTY_ATTACH_IMPLEMENTATION_PLAN.md +579 -0
- package/docs/superpowers/plans/2026-08-15-screenlog-gc.md +704 -0
- package/docs/superpowers/plans/2026-08-16-attach-double-cursor-jiggle-retry.md +499 -0
- package/docs/superpowers/plans/2026-08-21-dashboard-keypress-lag.md +366 -0
- package/docs/superpowers/specs/2026-08-15-screenlog-gc-design.md +105 -0
- package/docs/superpowers/specs/2026-08-16-attach-double-cursor-jiggle-retry-design.md +142 -0
- package/docs/superpowers/specs/2026-08-21-dashboard-keypress-lag-design.md +59 -0
- package/index.ts +6 -0
- package/package.json +81 -0
- package/runner/job-runner.mjs +420 -0
- package/runner/pty-runner.mjs +310 -0
- package/runner/state-runner.mjs +120 -0
- package/runner/title-runner.mjs +80 -0
- package/scripts/patch-vulns.mjs +59 -0
- package/src/commands/agent-board.ts +318 -0
- package/src/commands/attach-flow.ts +231 -0
- package/src/commands/bg.ts +70 -0
- package/src/core/atomic.mjs +145 -0
- package/src/core/auto-state.mjs +320 -0
- package/src/core/dashboard-render.mjs +10 -0
- package/src/core/derive.mjs +114 -0
- package/src/core/diagnostics.mjs +109 -0
- package/src/core/events.mjs +268 -0
- package/src/core/evidence.mjs +242 -0
- package/src/core/follow-up-queue.mjs +193 -0
- package/src/core/heuristics.mjs +240 -0
- package/src/core/ids.mjs +35 -0
- package/src/core/invocation.mjs +43 -0
- package/src/core/launch-options.mjs +317 -0
- package/src/core/launch.mjs +116 -0
- package/src/core/locks.mjs +80 -0
- package/src/core/paths.mjs +86 -0
- package/src/core/pid.mjs +42 -0
- package/src/core/prewarm-schedule.mjs +41 -0
- package/src/core/prompt-transport.mjs +13 -0
- package/src/core/pty-attach-jiggle-retry.mjs +90 -0
- package/src/core/pty-attach-render.mjs +51 -0
- package/src/core/pty-input.mjs +15 -0
- package/src/core/pty-links.mjs +71 -0
- package/src/core/pty-scroll.mjs +155 -0
- package/src/core/pty-support.mjs +327 -0
- package/src/core/repo.mjs +47 -0
- package/src/core/rows.mjs +290 -0
- package/src/core/screen-log-gc.mjs +198 -0
- package/src/core/screen-log.mjs +160 -0
- package/src/core/session-view.mjs +174 -0
- package/src/core/steering-prompts.mjs +34 -0
- package/src/core/steering.mjs +133 -0
- package/src/core/store.mjs +308 -0
- package/src/core/title.mjs +43 -0
- package/src/core/types.mjs +380 -0
- package/src/core/worktree.mjs +64 -0
- package/src/index.ts +109 -0
- package/src/runtime/service.mjs +1194 -0
- package/src/ui/dashboard-evidence.mjs +85 -0
- package/src/ui/dashboard.ts +1952 -0
- package/src/ui/pty-attach.ts +1378 -0
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Pi Agent Board
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/zhuxixi/pi-agent-board/main/assets/banner.png" alt="Pi Agent Board" width="100%" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://github.com/zhuxixi/pi-agent-board/blob/main/assets/demo.mp4"><strong>30s demo</strong></a>
|
|
9
|
+
| <a href="https://pi.dev/packages?name=@zhuxixi/pi-agent-board">Pi package gallery</a>
|
|
10
|
+
| <a href="https://www.npmjs.com/package/@zhuxixi/pi-agent-board">npm</a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
Pi Agent Board is a full-screen TUI dashboard for [Pi](https://github.com/earendil-works/pi-mono). It lets you dispatch, monitor, peek/reply to, attach to, and clean up multiple background Pi sessions from one place.
|
|
14
|
+
|
|
15
|
+
## Problems It Solves
|
|
16
|
+
|
|
17
|
+
- Run several Pi tasks at once without losing track of which are queued, running, waiting for input, in progress, done, failed, or stopped.
|
|
18
|
+
- Keep real Pi sessions durable and resumable after `/reload`, closing Pi, or restarting the terminal.
|
|
19
|
+
- Check the latest output and answer follow-up questions without interrupting a running session.
|
|
20
|
+
- Attach to the full interactive Pi session only when hands-on work is needed.
|
|
21
|
+
- Manage work across multiple projects in one global board.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
From npm:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pi install npm:@zhuxixi/pi-agent-board
|
|
29
|
+
pi /agent-board
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
You can also start Pi normally and run `/agent-board`.
|
|
33
|
+
|
|
34
|
+
Pi Agent Board requires Node 20+ and working Pi provider auth. If rows stay in `Running`, first confirm Pi can complete a one-shot model call:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pi --mode json -p --no-session "Reply with exactly: DONE"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
That command should produce an assistant reply and finish with an `agent_end` event.
|
|
41
|
+
|
|
42
|
+
From a local checkout:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install
|
|
46
|
+
pi install "$(pwd)"
|
|
47
|
+
pi /agent-board
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
For auto-discovery while developing:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
ln -s "$(pwd)" ~/.pi/agent/extensions/agent-board
|
|
54
|
+
pi
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Remove that symlink when you no longer want Pi to auto-load the checkout. If you installed by path, remove it with `pi remove "$(pwd)"`.
|
|
58
|
+
|
|
59
|
+
## Use
|
|
60
|
+
|
|
61
|
+
Open the board with `pi /agent-board` or `/agent-board` inside Pi.
|
|
62
|
+
|
|
63
|
+
- Type a task in the bottom input, then press `enter`.
|
|
64
|
+
- Confirm **Start session**, or adjust `cwd`, model, and thinking level first.
|
|
65
|
+
- Watch rows move through `Queued`, `Running`, `Needs input`, `In Progress`, `Done`, `Failed`, and `Stopped`.
|
|
66
|
+
- Press `space` to peek at the selected row's summary, blocker, and latest output.
|
|
67
|
+
- Press `r` to reply inline without attaching.
|
|
68
|
+
- Press `enter`, `right`, or `>` to attach to the real Pi session.
|
|
69
|
+
- Press `v` for a read-only live transcript.
|
|
70
|
+
- Press `/` to filter by text or state, such as `s:running`.
|
|
71
|
+
- Press `ctrl+r` rename, `ctrl+t` pin, `ctrl+s` stop, `d` mark done, `m` multi-select, `ctrl+x` delete/archive, `X` delete inactive rows in the selected state, and `?` for help.
|
|
72
|
+
|
|
73
|
+
Rows are stored under `~/.pi/agent/agent-board/` by default. Deleting a row archives it from the board; it does not remove the underlying Pi session file.
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
Useful environment variables:
|
|
78
|
+
|
|
79
|
+
| Variable | Use |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `AGENT_BOARD_ROOT` | Store location. Defaults to `~/.pi/agent/agent-board/`. |
|
|
82
|
+
| `AGENT_BOARD_AUTO_STATE=off` | Disable automatic terminal-state moves. |
|
|
83
|
+
| `AGENT_BOARD_AUTO_STATE_MODEL=<model>` | Model for classifying finished turns. Defaults to `gpt-4o`; use `off` for heuristic-only. |
|
|
84
|
+
| `AGENT_BOARD_SUMMARY_MODEL=<model>` | Model for short row summaries. Defaults to `gpt-4o`; use `off` to disable. |
|
|
85
|
+
| `AGENT_BOARD_TITLE_MODEL=<model>` | Model for generated session titles. Defaults to `openai-codex/gpt-5.5`; use `off` to disable. |
|
|
86
|
+
| `AGENT_BOARD_TITLE_THINKING_LEVEL=<level>` | Thinking level for title generation. Defaults to `low`; use `off` to omit it. |
|
|
87
|
+
| `AGENT_BOARD_DISABLE_PTY=1` | Disable PTY attach mode. |
|
|
88
|
+
| `AGENT_BOARD_FORCE_PTY=1` | Force PTY attach mode. |
|
|
89
|
+
| `AGENT_BOARD_ATTACH_MOUSE=0` | Disable attach-view mouse handling and use terminal-native selection. |
|
|
90
|
+
| `AGENT_BOARD_WHEEL_LINES=<1-50>` | Lines scrolled per mouse-wheel event in attach view. Defaults to `1`. |
|
|
91
|
+
|
|
92
|
+
Legacy `AGENT_VIEW_*` variables are still honored for migration.
|
|
93
|
+
|
|
94
|
+
If the board reports `node-pty unavailable`, press `!` in the dashboard for diagnosis and fix steps.
|
|
95
|
+
|
|
96
|
+
## Develop
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm install
|
|
100
|
+
npm run typecheck
|
|
101
|
+
npm test
|
|
102
|
+
npm run pack:dry
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Run all checks with:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npm run verify
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`npm run verify` runs typecheck, tests, and a dry npm pack.
|
|
112
|
+
|
|
113
|
+
## Publish
|
|
114
|
+
|
|
115
|
+
Before publishing a new release, bump the package version, run verification, then publish:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm run verify
|
|
119
|
+
npm version patch
|
|
120
|
+
npm publish
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
If the version is already bumped, skip `npm version patch`.
|
|
124
|
+
|
|
125
|
+
Use `npm version minor` or `npm version major` instead when the release warrants it. After publish, users install with:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pi install npm:@zhuxixi/pi-agent-board
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The Pi package gallery uses the `pi.video` and `pi.image` URLs from `package.json`.
|
package/VERIFY.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Manual Verification
|
|
2
|
+
|
|
3
|
+
Steps you can run yourself to check the extension. Grouped from "no auth needed" to
|
|
4
|
+
"needs pi provider auth". Commands assume you're in the repo root.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 0. Static checks (no auth, fast)
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install # dev + runtime deps
|
|
12
|
+
npm run typecheck # expect: 0 errors
|
|
13
|
+
npm test # expect: 0 failures
|
|
14
|
+
npm run pack:dry # expect: pi-agent-board-<version>.tgz contents only include deploy files
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`npm test` includes a hermetic integration test that runs the **real detached runner** against
|
|
18
|
+
a fake pi worker (`test-support/fake-pi.mjs`) — it proves dispatch → events → status/state →
|
|
19
|
+
finalize (completed / needs_input / failed / stopped) without any model/network.
|
|
20
|
+
|
|
21
|
+
## 1. Does the extension load in pi? (no auth)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pi --list-models -e "$(pwd)/src/index.ts"
|
|
25
|
+
```
|
|
26
|
+
Expect a normal model table and **exit 0** (the extension factory ran without throwing). If you
|
|
27
|
+
see an error mentioning `index.ts` / jiti / a missing import, that's a load problem.
|
|
28
|
+
|
|
29
|
+
## 2. CRITICAL: can pi reach a model at all? (needs pi auth)
|
|
30
|
+
|
|
31
|
+
This is the thing that was blocked in the dev sandbox. The background worker is just
|
|
32
|
+
`pi --mode json -p --session <file> "<prompt>"`, so first confirm a plain one-shot works:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Should print a JSON event stream that ENDS WITH a line of type "agent_end", then exit
|
|
36
|
+
# within a few seconds. Watch for an "assistant" message_end before agent_end.
|
|
37
|
+
pi --mode json -p --no-session "Reply with exactly: DONE" | tail -n 20
|
|
38
|
+
```
|
|
39
|
+
- ✅ **Healthy:** you see `...message_end (assistant)...`, then `agent_end`, and the command exits.
|
|
40
|
+
- ❌ **Hang:** it prints up to a `message_end` for the **user** message then sits idle (no
|
|
41
|
+
assistant reply, never exits). That means pi has no working provider auth / network here.
|
|
42
|
+
Fix pi's auth first:
|
|
43
|
+
```bash
|
|
44
|
+
pi # then run /login inside pi, or set the provider key pi expects, e.g.
|
|
45
|
+
# export ANTHROPIC_API_KEY=... (or OPENAI_API_KEY=... for gpt-4o summaries)
|
|
46
|
+
```
|
|
47
|
+
Re-run the one-shot above until it ends in `agent_end`. The dashboard cannot show live results
|
|
48
|
+
until this works — it's a pi setup step, independent of this extension.
|
|
49
|
+
|
|
50
|
+
## 3. Install the extension for normal use
|
|
51
|
+
|
|
52
|
+
For a local checkout, install it as a Pi package:
|
|
53
|
+
```bash
|
|
54
|
+
pi install "$(pwd)"
|
|
55
|
+
```
|
|
56
|
+
Or symlink the repo into pi's global extensions dir (auto-discovered via the top-level `index.ts`):
|
|
57
|
+
```bash
|
|
58
|
+
ln -s "$(pwd)" ~/.pi/agent/extensions/agent-board
|
|
59
|
+
```
|
|
60
|
+
After publish, install with:
|
|
61
|
+
```bash
|
|
62
|
+
pi install npm:pi-agent-board
|
|
63
|
+
```
|
|
64
|
+
Then start pi normally:
|
|
65
|
+
```bash
|
|
66
|
+
pi
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 4. Drive the dashboard
|
|
70
|
+
|
|
71
|
+
Inside pi:
|
|
72
|
+
1. Type `/agent-board`, or start with `pi /agent-board` → the full-screen dashboard opens.
|
|
73
|
+
- With `pi /agent-board`, quitting the dashboard exits Pi instead of dropping you into a normal chat session.
|
|
74
|
+
- The startup path should feel cleaner than `/agent-board`: no normal Pi header/footer chrome and no dispatch notifications above the dashboard.
|
|
75
|
+
2. Type a task in the bottom input (e.g. `list the files in this repo and summarize the README`), then press **Enter**.
|
|
76
|
+
- A **Start session** dialog opens with **Start session** focused by default.
|
|
77
|
+
- Press **Enter** again to launch immediately, or move with **↑/↓** to change **cwd**, **model**, or **thinking** first.
|
|
78
|
+
- A row appears and moves `Queued → Running → Done` (needs step 2 healthy).
|
|
79
|
+
3. **space** = peek when the input is empty (summary, blocker, latest output); in peek **r** = reply, **a** = attach.
|
|
80
|
+
**→** / **>** = open a full-screen live session view without interrupting; **←** / **<** returns.
|
|
81
|
+
4. **enter** on an empty input = attach to the selected full session (confirms first if it's still running).
|
|
82
|
+
You're now in the real Pi session; run `/agent-board` again to return.
|
|
83
|
+
5. Other keys: **/** filter (`s:running`, or free text), **Ctrl+R** rename, **Ctrl+T** pin, **Ctrl+S** stop,
|
|
84
|
+
**Ctrl+X** delete (archives the row, keeps the session file), **?** help, **Esc** clears input / quits when empty.
|
|
85
|
+
|
|
86
|
+
## 5. Inspect the durable store on disk
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
ls -R ~/.pi/agent/agent-board
|
|
90
|
+
cat ~/.pi/agent/agent-board/roster.json
|
|
91
|
+
cat ~/.pi/agent/agent-board/views/*/state.json
|
|
92
|
+
cat ~/.pi/agent/agent-board/views/*/runs/*/status.json
|
|
93
|
+
# raw worker event stream for a run:
|
|
94
|
+
cat ~/.pi/agent/agent-board/views/*/runs/*/events.jsonl
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 6. Recovery / persistence
|
|
98
|
+
|
|
99
|
+
- Start a dispatch, then quit pi (or `/reload`). Re-open pi and `/agent-board` — the row is still
|
|
100
|
+
there with its last state (rehydrated from disk). If a run's runner died without finishing,
|
|
101
|
+
the dashboard reconciles it to `failed (runner exited)` on open.
|
|
102
|
+
|
|
103
|
+
## 7. Same-repo session launches
|
|
104
|
+
|
|
105
|
+
- Dispatch one task in a git repo, then (while it's running) dispatch a second in the
|
|
106
|
+
**same repo**. Both launches should be allowed. The extension never creates a git worktree on
|
|
107
|
+
its own.
|
|
108
|
+
|
|
109
|
+
## 8. Summary model
|
|
110
|
+
|
|
111
|
+
Default summary model is **gpt-4o** (override `AGENT_BOARD_SUMMARY_MODEL=<model>`, disable with
|
|
112
|
+
`AGENT_BOARD_SUMMARY_MODEL=off`; legacy `AGENT_VIEW_SUMMARY_MODEL` is also honored). It needs OpenAI auth; without it the row keeps its heuristic
|
|
113
|
+
summary (e.g. the first sentence of the agent's last message or the active tool).
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Batch Selection + Read/Unread Flow
|
|
2
|
+
|
|
3
|
+
**Status:** Proposed
|
|
4
|
+
**Context:** Pi Agent Board dashboard
|
|
5
|
+
**Created:** 2026-06-02
|
|
6
|
+
|
|
7
|
+
## Assumption
|
|
8
|
+
|
|
9
|
+
"Move to done to delete that batch" is treated as a **safe 2-step cleanup flow**:
|
|
10
|
+
|
|
11
|
+
1. bulk-select sessions,
|
|
12
|
+
2. move them to **Done**,
|
|
13
|
+
3. optionally delete that same batch from **Done** with a second explicit confirmation.
|
|
14
|
+
|
|
15
|
+
This keeps "done" non-destructive and makes deletion intentional.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. Goals
|
|
20
|
+
|
|
21
|
+
### A. Multi-session selection
|
|
22
|
+
- Let users select multiple rows from the board.
|
|
23
|
+
- Let users batch-mark them as **Done**.
|
|
24
|
+
- Let users immediately clean up that same batch from the **Done** group.
|
|
25
|
+
|
|
26
|
+
### B. Read / Unread
|
|
27
|
+
- Mark a session as **Read** once the user has actually visited it via attach / transcript-style deep view.
|
|
28
|
+
- Show a **subtle unread hint** on rows with unseen activity.
|
|
29
|
+
- If new activity happens after a visit, the row becomes **Unread** again.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. UX overview
|
|
34
|
+
|
|
35
|
+
### Normal mode
|
|
36
|
+
- Board behaves exactly like today: single active row, peek, attach, done, delete.
|
|
37
|
+
|
|
38
|
+
### Selection mode
|
|
39
|
+
- User enters a temporary **multi-select mode**.
|
|
40
|
+
- Selection count appears in header/footer: `3 selected`.
|
|
41
|
+
- Rows show a subtle selected marker.
|
|
42
|
+
- Actions become batch-oriented:
|
|
43
|
+
- **Mark selected done**
|
|
44
|
+
- **Delete selected** (only from Done, with confirm)
|
|
45
|
+
- **Clear selection**
|
|
46
|
+
|
|
47
|
+
### Read state
|
|
48
|
+
- Rows can be either:
|
|
49
|
+
- **Unread** = new activity since last visit
|
|
50
|
+
- **Read** = user has already visited the latest activity
|
|
51
|
+
- Unread should not overpower semantic state; it is a secondary signal.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 3. Multi-session selection flow
|
|
56
|
+
|
|
57
|
+
## 3.1 Enter selection mode
|
|
58
|
+
|
|
59
|
+
**Trigger**
|
|
60
|
+
- User presses a dedicated shortcut from board list view.
|
|
61
|
+
- Suggested shortcut: `m` for **multi-select**.
|
|
62
|
+
|
|
63
|
+
**Result**
|
|
64
|
+
- Footer changes to selection hints.
|
|
65
|
+
- Selection starts empty; the current row stays focused but is **not** auto-selected.
|
|
66
|
+
- Header shows selection count.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 3.2 Build the selection
|
|
71
|
+
|
|
72
|
+
While in selection mode:
|
|
73
|
+
- `↑ / ↓` moves cursor
|
|
74
|
+
- `space` toggles current row in selection
|
|
75
|
+
- `a` selects all visible rows in current filter/group
|
|
76
|
+
- `u` clears the current selection without leaving selection mode
|
|
77
|
+
- `esc` clears selection and exits selection mode
|
|
78
|
+
|
|
79
|
+
Optional later:
|
|
80
|
+
- `A` = select all rows in current state group
|
|
81
|
+
- `u` = unselect all
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 3.3 Move selected rows to Done
|
|
86
|
+
|
|
87
|
+
**Trigger**
|
|
88
|
+
- User presses `d` while in selection mode.
|
|
89
|
+
|
|
90
|
+
**Confirmation copy**
|
|
91
|
+
- `Mark 5 selected sessions as done? (y/N)`
|
|
92
|
+
|
|
93
|
+
**Rules**
|
|
94
|
+
- Running/live rows are skipped.
|
|
95
|
+
- Needs-input / idle / failed / stopped rows may be moved to Done.
|
|
96
|
+
- Confirmation should mention skipped rows if any.
|
|
97
|
+
|
|
98
|
+
**Result**
|
|
99
|
+
- Matching rows are moved to `Done`.
|
|
100
|
+
- The same rows remain selected.
|
|
101
|
+
- Board auto-scrolls/focuses to the `Done` section.
|
|
102
|
+
- Toast example: `Moved 5 to Done · skipped 2 live`
|
|
103
|
+
|
|
104
|
+
This preserves the batch as a temporary working set for cleanup.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 3.4 Delete the same batch from Done
|
|
109
|
+
|
|
110
|
+
**Trigger**
|
|
111
|
+
- With the same batch still selected, user presses `ctrl+x` or a batch delete key.
|
|
112
|
+
|
|
113
|
+
**Guardrail**
|
|
114
|
+
- Deletion is only enabled when all selected rows are already in `Done`.
|
|
115
|
+
- If selection includes non-Done rows, show: `Only Done sessions can be batch deleted`.
|
|
116
|
+
|
|
117
|
+
**Confirmation copy**
|
|
118
|
+
- `Delete 5 done sessions? Session files are preserved. (y/N)`
|
|
119
|
+
|
|
120
|
+
**Result**
|
|
121
|
+
- Selected rows are archived from dashboard.
|
|
122
|
+
- Selection clears.
|
|
123
|
+
- Toast example: `Deleted 5 done sessions`
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 4. Read / Unread flow
|
|
128
|
+
|
|
129
|
+
## 4.1 What counts as Read
|
|
130
|
+
|
|
131
|
+
A session becomes **Read** when the user intentionally opens that session in a deeper way:
|
|
132
|
+
- attach via `enter` / `→`
|
|
133
|
+
- transcript/full-session view
|
|
134
|
+
|
|
135
|
+
**Not read by default:**
|
|
136
|
+
- merely highlighting a row
|
|
137
|
+
- passive polling updates
|
|
138
|
+
- quick list navigation
|
|
139
|
+
- optional: peek can remain non-read to preserve signal
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 4.2 When a row becomes Unread again
|
|
144
|
+
|
|
145
|
+
A previously read row becomes **Unread** when a new assistant reply lands after the last visit, for example:
|
|
146
|
+
- new assistant message
|
|
147
|
+
- new blocker/question raised in that message
|
|
148
|
+
- session re-enters `needs_input` because of that message
|
|
149
|
+
|
|
150
|
+
User-authored actions alone should not create unread state, and intermediate tool churn alone should not flip unread.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 4.3 Recommended subtle hint
|
|
155
|
+
|
|
156
|
+
Use the **stage icon itself** as the unread signal:
|
|
157
|
+
- **Unread:** stronger/heavier variant of that stage icon
|
|
158
|
+
- **Read:** lighter/default variant of that stage icon
|
|
159
|
+
|
|
160
|
+
Examples:
|
|
161
|
+
- queued: `○` → `◎`
|
|
162
|
+
- needs input: `◇` → `◆`
|
|
163
|
+
- done: `✓` → `✔`
|
|
164
|
+
|
|
165
|
+
Optional secondary treatment:
|
|
166
|
+
- unread row title slightly brighter
|
|
167
|
+
- read row title normal
|
|
168
|
+
|
|
169
|
+
Avoid:
|
|
170
|
+
- loud badges like `UNREAD`
|
|
171
|
+
- full-row highlight
|
|
172
|
+
- strong color conflict with semantic states like Failed / Needs input
|
|
173
|
+
|
|
174
|
+
### Priority of signals
|
|
175
|
+
1. semantic state (Running, Needs input, Done, Failed)
|
|
176
|
+
2. selection state
|
|
177
|
+
3. unread hint
|
|
178
|
+
|
|
179
|
+
Unread should help scanning, not dominate the board.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 5. State model
|
|
184
|
+
|
|
185
|
+
## 5.1 Batch selection
|
|
186
|
+
|
|
187
|
+
Selection can stay **ephemeral UI state** in the dashboard component:
|
|
188
|
+
- `selectedIds: Set<string>`
|
|
189
|
+
- `selectionMode: boolean`
|
|
190
|
+
|
|
191
|
+
No persistence needed for V1.
|
|
192
|
+
|
|
193
|
+
## 5.2 Read state
|
|
194
|
+
|
|
195
|
+
Recommended durable fields:
|
|
196
|
+
- `lastVisitedAt: number | null`
|
|
197
|
+
- `lastAgentActivityAt: number | null`
|
|
198
|
+
|
|
199
|
+
Derived flag:
|
|
200
|
+
- `isUnread = lastAgentActivityAt > lastVisitedAt`
|
|
201
|
+
|
|
202
|
+
This is simpler and more reliable than storing a raw boolean.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 6. Edge cases
|
|
207
|
+
|
|
208
|
+
### Live rows inside a batch
|
|
209
|
+
- Cannot be batch-done or batch-deleted.
|
|
210
|
+
- Skip and report counts.
|
|
211
|
+
|
|
212
|
+
### Mixed-state selection
|
|
213
|
+
- Batch done: allowed for inactive non-done rows.
|
|
214
|
+
- Batch delete: only allowed if every selected row is already Done.
|
|
215
|
+
|
|
216
|
+
### New activity during selection
|
|
217
|
+
- Keep row selected.
|
|
218
|
+
- If it receives new output, unread hint can appear even while selected.
|
|
219
|
+
|
|
220
|
+
### Re-attaching to a row
|
|
221
|
+
- Refresh `lastVisitedAt`.
|
|
222
|
+
- Any prior unread marker clears.
|
|
223
|
+
|
|
224
|
+
### Peek behavior
|
|
225
|
+
- Recommend: peek does **not** mark read.
|
|
226
|
+
- Reason: peek is triage, attach/transcript is actual visit.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 7. Suggested implementation slices
|
|
231
|
+
|
|
232
|
+
### Dashboard (`src/ui/dashboard.ts`)
|
|
233
|
+
- add selection mode
|
|
234
|
+
- add `selectedIds`
|
|
235
|
+
- batch confirm flows
|
|
236
|
+
- render selected marker + unread marker
|
|
237
|
+
|
|
238
|
+
### Service (`src/runtime/service.mjs`)
|
|
239
|
+
- add `markCompletedMany(viewIds)`
|
|
240
|
+
- add `archiveMany(viewIds)`
|
|
241
|
+
- add `markVisited(viewId)`
|
|
242
|
+
|
|
243
|
+
### Store/types (`src/core/types.mjs`, `src/core/store.mjs`)
|
|
244
|
+
- add read-tracking timestamps
|
|
245
|
+
- expose unread derivation on rows
|
|
246
|
+
|
|
247
|
+
### Attach / session view entry points
|
|
248
|
+
- mark row visited when attach or transcript view opens
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 8. Recommended default interaction summary
|
|
253
|
+
|
|
254
|
+
### Batch
|
|
255
|
+
- `m` enter multi-select
|
|
256
|
+
- `space` toggle row
|
|
257
|
+
- `a` select all visible
|
|
258
|
+
- `u` clear selection
|
|
259
|
+
- `d` move selected to Done
|
|
260
|
+
- `ctrl+x` delete selected Done batch
|
|
261
|
+
- `esc` clear/exit
|
|
262
|
+
|
|
263
|
+
### Read state
|
|
264
|
+
- attach / transcript => mark read
|
|
265
|
+
- new assistant reply => unread again
|
|
266
|
+
- unread indicator => subtle left dot/bar
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## 9. Acceptance criteria
|
|
271
|
+
|
|
272
|
+
- User can select multiple sessions from the board.
|
|
273
|
+
- User can mark that selection Done in one action.
|
|
274
|
+
- User can immediately delete that same batch from Done with explicit confirmation.
|
|
275
|
+
- A session becomes Read after attach/transcript visit.
|
|
276
|
+
- New agent activity turns a previously read row back to Unread.
|
|
277
|
+
- Unread is visible through a subtle row hint, not a loud badge.
|