opencode-sesh 2.0.1 → 2.0.3

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/AGENTS.md CHANGED
@@ -11,24 +11,25 @@ territory: read this first, then the specific file you need.
11
11
  any terminal. Lists **all** sessions across **all** project directories,
12
12
  full-text searchable, with transcript preview and resume/fork/delete.
13
13
  2. **`tui-plugins/sesh-panel/tui.tsx`** — a SolidJS/OpenTUI plugin for the opencode TUI: a
14
- sessions section in the sidebar plus an `option+o` / `/sesh` picker.
14
+ sessions section in the sidebar and on the home screen, plus an `option+o` / `/sesh` picker.
15
15
  3. **`plugins/sesh-list.ts`** — the `sesh_list` custom tool, so the agent
16
16
  can list sessions across every directory by querying the global opencode
17
17
  SQLite store (the native `opencode session list` is project-scoped).
18
18
 
19
19
  No iTerm2, no AppleScript, no panes, no window management — **never add any.**
20
- The one exception is the TUI's right-click action, which shells out to
20
+ The one exception is the TUI's right-click workspace action, which shells out to
21
21
  `cmux new-workspace` when running inside cmux.
22
- opencode has no persistent-sidebar API, so the "sidebar" is a `sidebar_content`
23
- slot section plus an xlarge modal picker; the terminal UI is fullscreen fzf.
22
+ opencode has no persistent-sidebar API, so the TUI uses `sidebar_content` and
23
+ `home_bottom` slot sections plus an xlarge modal picker; the terminal UI is fullscreen fzf.
24
24
 
25
25
  ## Start here
26
26
 
27
27
  ```bash
28
28
  bun install # dev deps (TypeScript, opencode/OpenTUI types)
29
- bun run test # fixture-DB regression suite — must stay green
29
+ bun run build # compile the panel to dist/tui.js
30
+ bun run test # build + fixture-DB regression suite — must stay green
30
31
  bun run test:changelog # release-tooling regressions (scripts/changelog.sh)
31
- bun run test:picker # PTY picker suite (needs fzf >= 0.73)
32
+ bun run test:picker # PTY picker suite
32
33
  bun run typecheck # tsc over tui-plugins/ and plugins/
33
34
  bun run lint:sh # bash -n on every script
34
35
  HOME=/tmp/fakehome bash install.sh # installer smoke test (never touches ~/.config)
@@ -39,7 +40,8 @@ HOME=/tmp/fakehome bash install.sh # installer smoke test (never touches ~/.co
39
40
  - `bin/` — flat; no subdirs. Scripts resolve siblings from their own location.
40
41
  Never hardcode install paths. `sesh-waiting.sh` owns the needs-input query
41
42
  (shared heuristic with the TUI sidebar copy, marked `NEEDS_INPUT_SQL` in
42
- both); `sesh-prune.sh` deletes stale sessions; `sesh-costs.sh` sums
43
+ both); `sesh-pins.sh` manages persistent session/directory pins;
44
+ `sesh-prune.sh` deletes stale sessions; `sesh-costs.sh` sums
43
45
  assistant-message cost per directory. Reads go through `sqlite3 -readonly`
44
46
  (required; `opencode db` no longer exists). Sesh never writes the database
45
47
  directly; deletes go through `opencode session delete`.
@@ -47,9 +49,16 @@ HOME=/tmp/fakehome bash install.sh # installer smoke test (never touches ~/.co
47
49
  window management to sesh itself.
48
50
  - `tui-plugins/sesh-panel/tui.tsx` — SolidJS panel, `/** @jsxImportSource @opentui/solid */`.
49
51
  - `plugins/sesh-list.ts` — the agent-facing `sesh_list` tool.
52
+ - `scripts/build-tui.mjs` — compiles the panel with Babel + `babel-preset-solid`
53
+ (`moduleName: "@opentui/solid"`, universal) to `dist/tui.js` (gitignored).
54
+ `package.json` exports `./tui` from `dist/tui.js`; `bun run build`, `bun run
55
+ test`, `prepack` and CI all run it. OpenCode applies its Solid transform only
56
+ to sources outside `node_modules`, so shipping raw `tui.tsx` in the npm package
57
+ renders a non-reactive (empty) panel — never export the `.tsx` source.
50
58
  - `scripts/changelog.sh` — release tooling: drafts conventional commits,
51
59
  writes a dated version, prints release notes and
52
60
  checks the compare links. `tests/changelog.sh` covers it in a throwaway repo.
61
+ - `assets/` — README logo (`logo.svg`) and square mark (`icon.svg`); wordmark is outlined paths, no font dependency.
53
62
  - `themes/`, `tests/`, `install.sh`, `README.md`.
54
63
 
55
64
  The tool name in opencode is `sesh_list`. Do not rename it without updating the docs.
@@ -58,13 +67,13 @@ The tool name in opencode is `sesh_list`. Do not rename it without updating the
58
67
 
59
68
  `bin/sesh-list.sh` owns the fzf picker's session store access (opencode SQLite
60
69
  DB: `session_v2` / `session_message` tables); the `sesh_list` agent tool queries
61
- the same store read-only through `bun:sqlite`. V2 discovers the tool from the
70
+ the same store read-only through `bun:sqlite`. OpenCode discovers the tool from the
62
71
  global config directory's `plugins/`. Keep its SQL column names in sync with
63
72
  the schema below. Keystrokes never touch the database:
64
73
 
65
74
  - `--refresh` (expensive): bulk-reads session metadata and per-session text
66
75
  parts, validates the persistent extraction cache
67
- (`$SESH_CACHE_DIR/extractions/<ses_*.json>`, schema 3) against `time_updated`,
76
+ (`$SESH_CACHE_DIR/extractions/<ses_*.json>`) against `time_updated`,
68
77
  message count and the latest message timestamp, re-extracts only changed sessions,
69
78
  prunes vanished ones, and atomically publishes `STATE_DIR/snapshot.jsonl`.
70
79
  Extraction reads user `data.text` and assistant `data.content` text entries,
@@ -91,8 +100,10 @@ the schema below. Keystrokes never touch the database:
91
100
  `ctrl+d` itself (composer delete-char, session delete), so ctrl pins would
92
101
  shadow the composer. Pinned directories sort before groups
93
102
  containing pinned sessions. The terminal picker puts pinned sessions first
94
- inside each group; the TUI picker and sidebar keep sessions recency-ordered
95
- within each directory. The home list puts pinned sessions first.
103
+ inside each group; the TUI picker ranks pinned sessions first before filtering
104
+ and keeps sessions within each directory ordered by recency; the sidebar keeps
105
+ sessions within each directory ordered by recency; the home list puts pinned
106
+ sessions first.
96
107
 
97
108
  **Output contract** (TSV, 6 fields):
98
109
  `agentId sessionId liveState display cwd trackingId`. `display` is the only
@@ -100,8 +111,8 @@ rendered column; `trackingId` is fzf's `--id-nth`. Headers/notices carry an
100
111
  empty `sessionId` and are a selection no-op — keep that guard.
101
112
 
102
113
  One worker (`sesh-refresh-worker.sh`, per picker, TERMed on exit) serializes
103
- scans; fzf's `start`/`every(3)`/`change` bindings render only. Selection requests
104
- a fresh poll (`request`/`wait`, ≤12 s) before dispatch — skipped for `--print`,
114
+ scans; fzf's `start`/`every(...)`/`change` bindings render only. Selection requests
115
+ a fresh poll (`request`/`wait`) before dispatch — skipped for `--print`,
105
116
  which is a pure snapshot lookup — and prints a progress line to stderr while it
106
117
  waits, because fzf has already exited and the terminal is idle. opencode has no
107
118
  live-agent API, so `liveState` is always `unknown` and rows render gray unless
@@ -125,14 +136,14 @@ when opencode exits, the picker reopens with the query preserved.
125
136
  `sqlite3 -json` in `-R` mode; it pretty-prints — parse as JSON.
126
137
  - `jq -R` output stays JSON-quoted: use `-Rr` when a shell variable needs the
127
138
  raw string.
128
- - fzf: stock only, `>= 0.73` (`transform:`, `every():`). `{q}` in binds is
139
+ - fzf: stock only (`transform:`, `every():`). `{q}` in binds is
129
140
  shell-quoted by fzf — don't add quoting. Ctrl-G is bind-only (stays open);
130
141
  Ctrl-F is `--expect` (accepts with fork). A `transform-header` inside a chained
131
142
  action must come **before** `reload`/`reload-sync`: placed after, fzf silently
132
- publishes an empty list (verified on 0.74.3).
143
+ publishes an empty list.
133
144
  - Destructive actions confirm. `sesh-delete.sh` prompts on a TTY and refuses
134
145
  without `--yes` when stdin is not one; the TUI arms on the first Option-D and
135
- commits on the second (or `y`).
146
+ commits on the second, `y`, or Enter.
136
147
  - The installer prefers the local opencode version for `@opencode/*` and
137
148
  merges (never clobbers) the config `package.json`; opencode runs `bun install`
138
149
  at startup.
@@ -147,13 +158,18 @@ when opencode exits, the picker reopens with the query preserved.
147
158
 
148
159
  ## TUI panel (`tui-plugins/sesh-panel/tui.tsx`)
149
160
 
150
- - **Sidebar:** `api.slots.register` on `sidebar_content` (prepend mode — native
151
- sidebar content stays). Pinned directories sort first, then directory groups
161
+ - **Sidebar & Home list:** `api.slots.register` on `sidebar_content` (`sidebar.content`
162
+ prepend mode — native sidebar content stays) and `home_bottom` (`home.footer`
163
+ prepend mode). In the sidebar, pinned directories sort first, then directory groups
152
164
  by recency; sessions within each group sort by last update regardless of pins.
165
+ In the home list, pinned sessions sort first.
153
166
  Row markers alone signal session state: a running agent animates a loading
154
167
  spinner marker, the open session shows its own ●, and every other idle row
155
- stays neutral (polled every 15 s); Option-P previews
156
- a row and option+d deletes one (armed, then confirmed). The section lists every
168
+ stays neutral (polled periodically); Option-P previews
169
+ a row and option+d deletes one (armed, then confirmed). Right-clicking a
170
+ sidebar row opens an action context menu (open, preview, cmux workspace when
171
+ inside cmux, fork, pin/unpin, delete); right-clicking a home or picker row
172
+ opens the session in a new cmux workspace. The sidebar section lists every
157
173
  session without a row cap and flex-grows to fill the sidebar, with overflow
158
174
  scrolling inside; the picker remains the place for transcript search.
159
175
  Sessions waiting on the user (unanswered questions, stuck runs) pin a
@@ -167,7 +183,7 @@ when opencode exits, the picker reopens with the query preserved.
167
183
  `api.client.session.fork`; Ctrl-G scopes the list to the selected session's
168
184
  project.
169
185
  - **Picker search:** pages the global session list (`SESSION_PAGE_LIMIT`, capped
170
- at `SESSION_MAX` and reported when truncated) instead of a fixed 500-row
186
+ at `SESSION_MAX` and reported when truncated) rather than a fixed-size
171
187
  window, then indexes transcript text for **every** session in batches
172
188
  (`TRANSCRIPT_BATCH`) with bounded remote concurrency (`REMOTE_CONCURRENCY`).
173
189
  The header shows indexing progress/coverage. Visible transcript hits get
@@ -177,7 +193,7 @@ when opencode exits, the picker reopens with the query preserved.
177
193
  `/sesh-needs` uses the shared needs-input set plus the oldest unresolved
178
194
  question or running-tool timestamp, lists longest-waiting first, and `n`
179
195
  opens the next waiting session. `tests/tui.mjs` locks the data layer.
180
- - **Durable install:** V2 reloads plugins on watched configuration changes;
196
+ - **Durable install:** OpenCode reloads plugins on watched configuration changes;
181
197
  unwatched dependencies may need a restart. If a panel update does not appear,
182
198
  fully quit/reopen opencode. `install.sh --sync-panel`
183
199
  (run by the `postinstall`) refreshes an already-installed panel and is a
@@ -222,8 +238,8 @@ when opencode exits, the picker reopens with the query preserved.
222
238
  (`tests/tui.mjs` asserts the cap stays out); overflow scrolls inside the
223
239
  stretched section.
224
240
  - **Delete in the TUI is two-step.** The first `option+d` arms `pendingDelete`,
225
- the second (or `y`, or Enter in the picker footer) commits the armed row
226
- wherever the pointer or cursor is, and `n`/Esc (or a five-second timeout)
241
+ the second (or `y`, or Enter) commits the armed row
242
+ wherever the pointer or cursor is, and `n`/Esc (or a timeout)
227
243
  cancels. Moving the pointer must never disarm: edge-hover flicker ate the
228
244
  confirm before `confirmArmed` landed. The `y`/`n` layer is registered *only
229
245
  while armed*, so it can never shadow the search box's typing.
@@ -240,9 +256,12 @@ when opencode exits, the picker reopens with the query preserved.
240
256
  - `bun run test:changelog` — release-tooling regressions; builds its own git
241
257
  history in a temp dir (included in `bun run test`).
242
258
  - `bun run test:picker` — PTY suite driving the real fzf picker (needs fzf
243
- `>= 0.73` and Python 3).
259
+ and Python 3).
244
260
  - `bun run typecheck` — `tsc` over `tui-plugins/` and `plugins/`.
245
261
  - `bun run lint:sh` — `bash -n` on every script.
246
262
  - `HOME=/tmp/fakehome bash install.sh` — installer smoke test.
247
263
  - Keep `tui-plugins/sesh-panel/tui.tsx` and any installed copy byte-identical when testing
248
264
  the panel locally.
265
+ - The npm install path needs the plugin in both `opencode.json` (server tool) and
266
+ `cli.json` (TUI panel); `plugin.list` shows only server plugins, so verify the
267
+ panel by launching the TUI against a fixture or the real store.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.3] - 2026-10-17
9
+
10
+ ### Fixed
11
+
12
+ - **tui:** Support ctrl-n and ctrl-p in the session picker (#11)
13
+
14
+ ## [2.0.2] - 2026-10-10
15
+
16
+ ### Fixed
17
+
18
+ - **packaging:** Ship precompiled TUI panel for npm installs
19
+
8
20
  ## [2.0.1] - 2026-10-10
9
21
 
10
22
  ### Fixed
@@ -488,6 +500,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
488
500
  - Fixture-database regression suite, TypeScript typechecking, and ShellCheck in
489
501
  CI.
490
502
 
503
+ [2.0.3]: https://github.com/ozandogrultan/opencode-sesh/compare/v2.0.2...v2.0.3
504
+ [2.0.2]: https://github.com/ozandogrultan/opencode-sesh/compare/v2.0.1...v2.0.2
491
505
  [2.0.1]: https://github.com/ozandogrultan/opencode-sesh/compare/v2.0.0...v2.0.1
492
506
  [2.0.0]: https://github.com/ozandogrultan/opencode-sesh/compare/v1.1.0...v2.0.0
493
507
  [1.1.0]: https://github.com/ozandogrultan/opencode-sesh/compare/v1.0.8...v1.1.0
package/README.md CHANGED
@@ -1,21 +1,23 @@
1
- # sesh
2
-
3
- [![CI](https://github.com/ozandogrultan/opencode-sesh/actions/workflows/ci.yml/badge.svg)](https://github.com/ozandogrultan/opencode-sesh/actions/workflows/ci.yml)
4
-
5
- **An [OpenCode V2](https://opencode.ai/v2/) plugin and terminal session browser.** Search every session
1
+ <h1 align="center">
2
+ <img src="assets/logo.svg" alt="sesh" height="96">
3
+ </h1>
4
+
5
+ <p align="center">
6
+ <a href="https://github.com/ozandogrultan/opencode-sesh/actions/workflows/ci.yml"><img src="https://github.com/ozandogrultan/opencode-sesh/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
7
+ <a href="https://www.npmjs.com/package/opencode-sesh"><img src="https://img.shields.io/npm/v/opencode-sesh" alt="npm"></a>
8
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
9
+ <a href="#contributing"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs welcome"></a>
10
+ <a href="https://github.com/ozandogrultan/opencode-sesh/stargazers"><img src="https://img.shields.io/github/stars/ozandogrultan/opencode-sesh?style=social" alt="GitHub stars"></a>
11
+ </p>
12
+
13
+ **An [OpenCode](https://opencode.ai) plugin and terminal session browser.** Search every session
6
14
  across every project, preview the transcript, and resume in place — from your
7
15
  terminal or from inside the TUI.
8
16
 
9
- The TUI plugin and agent tool require OpenCode V2 and are not compatible with V1.
10
-
11
17
  `opencode` keeps a growing pile of sessions, and its native lists (`<leader>l`,
12
18
  `/sessions`) are scoped to the current project. `sesh` shows all of them —
13
19
  grouped by directory, full-text searchable, and previewable from anywhere.
14
20
 
15
- [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
16
- [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](#contributing)
17
- [![GitHub stars](https://img.shields.io/github/stars/ozandogrultan/opencode-sesh?style=social)](https://github.com/ozandogrultan/opencode-sesh/stargazers)
18
-
19
21
  ```text
20
22
  Sessions (8) ▾ hide
21
23
  search…
@@ -38,9 +40,10 @@ search…
38
40
  subagent child sessions are hidden by default.
39
41
  - **Pin what matters.** Ctrl-S pins a session and Ctrl-D pins its directory in
40
42
  either picker; the TUI sidebar and home list use Option-S and Option-R.
41
- Pins are shared and persist across restarts. Pinned directories rise first;
42
- pinned sessions sort first in the terminal picker and home list. The TUI picker
43
- and sidebar keep sessions within each directory recency-ordered.
43
+ Pins are shared and persist across restarts. Pinned directories rise first
44
+ (followed by directories containing pinned sessions in the TUI picker);
45
+ pinned sessions sort first in the terminal picker and home list, while the
46
+ TUI picker and sidebar keep sessions within each directory ordered by recency.
44
47
  - **Full-text search.** Type to match against session titles *and* the text of
45
48
  the conversation itself. Reasoning and tool output are excluded, so the index
46
49
  stays clean.
@@ -59,18 +62,19 @@ search…
59
62
 
60
63
  ### OpenCode plugin
61
64
 
62
- Add the package to `plugins` in your OpenCode V2 `opencode.json` or
63
- `opencode.jsonc`:
65
+ Add the package to `plugins` in your `opencode.json` (server tool)
66
+ and `cli.json` (TUI panel):
64
67
 
65
68
  ```json
66
69
  {
67
- "$schema": "https://opencode.ai/config.json",
68
70
  "plugins": ["opencode-sesh"]
69
71
  }
70
72
  ```
71
73
 
72
- OpenCode installs the package and loads its server tool and TUI panel. Merge
73
- this entry with your existing plugins. Remove the copied
74
+ OpenCode installs the package and loads its server tool and TUI panel. The
75
+ published panel is precompiled (`dist/tui.js`) because OpenCode does not apply
76
+ its Solid transform to sources under `node_modules`. Merge this entry with your
77
+ existing plugins. Remove any copied
74
78
  `./tui-plugins/sesh-panel` registration and `plugins/sesh-list.ts` tool before
75
79
  switching to avoid loading them twice.
76
80
 
@@ -94,15 +98,15 @@ bash install.sh
94
98
  `sesh install` (or `bash install.sh`) links `sesh` into `$XDG_BIN_HOME`
95
99
  (default `~/.local/bin`), copies
96
100
  the `sesh_list` tool and the TUI panel into
97
- `${XDG_CONFIG_HOME:-~/.config}/opencode`, registers the panel in `opencode.json`, and
101
+ `${XDG_CONFIG_HOME:-~/.config}/opencode`, registers `./tui-plugins/sesh-panel` in `opencode.json`, and
98
102
  declares the plugin dependencies (opencode installs them on next start). The
99
- panel registers the `/sesh` slash command. It never edits your shell rc, and any
100
- file it would overwrite is backed up first.
103
+ panel registers the `/sesh` slash command. It never edits your shell rc or
104
+ overwrites a foreign `sesh` symlink.
101
105
 
102
106
  The npm package ships the same scripts and installer; the runtime tools below
103
107
  are still required.
104
108
 
105
- V2 reloads plugins when watched configuration files change. If a panel update
109
+ OpenCode reloads plugins when watched configuration files change. If a panel update
106
110
  does not appear, fully quit opencode and reopen it. Upgrades
107
111
  refresh an already-installed panel automatically (the npm `postinstall` syncs
108
112
  it), and `sesh --check` reports when the installed panel is out of date.
@@ -121,7 +125,7 @@ option+o # inside opencode — picker
121
125
  ### Requirements
122
126
 
123
127
  - [opencode](https://opencode.ai), used at least once
124
- - `bash`, `jq`, and [`fzf`](https://github.com/junegunn/fzf) `>= 0.73`
128
+ - `bash`, `jq`, and [`fzf`](https://github.com/junegunn/fzf) (modern stock build; run `sesh --check` to verify)
125
129
  - `sqlite3` — the picker queries the session DB directly
126
130
  - [`glow`](https://github.com/charmbracelet/glow) optional — styles the
127
131
  transcript preview as Markdown; without it the preview shows the plain
@@ -167,11 +171,8 @@ confirms first and a non-TTY run needs `--yes`.
167
171
 
168
172
  `sesh costs [--days N] [--json]` sums assistant-message cost per project, with a
169
173
  recent window beside the lifetime total, so a day's work reads as a
170
- per-project record. Legacy V1 history is included when available; sessions
171
- already present in V2 are counted only once.
172
-
173
- Session browsing uses the V2 store. Sessions remaining only in the legacy V1
174
- tables are not listed or resumable through sesh.
174
+ per-project record. Earlier history tables are included when present in the
175
+ database, and sessions are counted only once.
175
176
 
176
177
  When searching, title matches outrank transcript-only matches and the current
177
178
  project rises, so the list answers "where was that thing I worked on" before it
@@ -197,7 +198,8 @@ non-interactive `sesh-delete.sh` refuses unless given `--yes`.
197
198
  | `/sesh-needs` | Sessions waiting on you (Enter opens) |
198
199
  | `option+o` | Open the full picker (also in the command palette) |
199
200
  | Type | Search titles, directories and transcript text |
200
- | `↑`/`↓`, `PgUp`/`PgDn`, `Home`/`End` | Move the selection |
201
+ | `↑`/`↓` or Ctrl-P/Ctrl-N | Move the selection up/down |
202
+ | `PgUp`/`PgDn`, `Home`/`End` | Move by page or jump to the first/last session |
201
203
  | Option-P | Toggle the transcript preview |
202
204
  | Enter | Open the selected session |
203
205
  | Option-D | Arm deletion; press Option-D again, `y`, or Enter to confirm |
@@ -213,7 +215,8 @@ Option-O opens the picker globally; the other keys above apply inside it.
213
215
  The picker groups sessions under collapsible directory headings (click ▾/▸).
214
216
  Mouse-wheel scrolling moves through the tree without changing the selection
215
217
  under a stationary pointer. Option-P opens a full-size transcript preview over
216
- the picker; use ↑/↓ to preview other sessions, then Esc to return to the list.
218
+ the picker; use ↑/↓ or Ctrl-P/Ctrl-N to preview other sessions, then Esc to
219
+ return to the list.
217
220
  Right-click a sidebar session to open its action menu: open, preview, fork,
218
221
  pin/unpin, or delete with confirmation. Inside cmux, the menu also offers opening
219
222
  the session in a new workspace at its directory. Use ↑/↓ and Enter to choose an
@@ -227,7 +230,7 @@ Click the sidebar's `search…` box to filter sessions in place; click
227
230
  elsewhere or press Esc to leave search. Click the **Sessions** heading to drive
228
231
  the list from the keyboard instead of the mouse (`↑`/`↓` to move, Enter to open,
229
232
  Option-P to preview, Option-S to pin a session, Option-R to pin its directory,
230
- Option-D to arm deletion, Esc to leave). Press Option-D again or `y` to confirm
233
+ Option-D to arm deletion, Esc to leave). Press Option-D again, `y`, or Enter to confirm
231
234
  an armed deletion; `n` or Esc cancels. Pinned
232
235
  directories rise first, while sessions within each directory are ordered by
233
236
  last update, newest first. The section lists every session and scrolls to fill
@@ -247,14 +250,15 @@ replace the picker's Ctrl-S/Ctrl-D bindings; Option-S in the picker filters pins
247
250
 
248
251
  ### Transcript search and needs-input triage
249
252
 
250
- The full picker pages through your whole global session list (no fixed window)
253
+ The full picker pages through your global session list
251
254
  and indexes transcript text for every session in the background, showing
252
- indexing progress under the search box. It only stops at a safety cap of 5,000
253
- sessions, and says so when it does. Transcript matches show a short excerpt
255
+ indexing progress under the search box (and noting if the safety cap is reached).
256
+ Transcript matches show a short excerpt
254
257
  under the result; the Project, Needs input, and Pinned filters combine with
255
258
  search. The picker remembers your query and filters until you restart opencode.
256
259
  The Needs input dialog (`/sesh-needs`) shows why and how long each session has
257
- been waiting, oldest first. Press `n` there to open the next waiting session,
260
+ been waiting, oldest first. Use ↑/↓ or Ctrl-P/Ctrl-N to navigate and Enter to
261
+ open the selected session. Press `n` there to open the next waiting session,
258
262
  or reopen it after answering one to continue through the list.
259
263
 
260
264
  ## Configuration
@@ -280,8 +284,8 @@ workspace, and a global "resume from anywhere" hotkey — all caller-side.
280
284
 
281
285
  ## How it works
282
286
 
283
- The `bin/` readers use the V2 opencode session
284
- store (SQLite: `session_v2` / `session_message`). Each refresh extracts session
287
+ The `bin/` readers query the opencode session
288
+ store in SQLite (`session_v2` / `session_message`). Each refresh extracts session
285
289
  metadata and text-only parts into a persistent per-session cache keyed on
286
290
  `time_updated`, message count and the latest message timestamp, then atomically
287
291
  publishes a `snapshot.jsonl`. Every keystroke re-renders that snapshot with `jq`
@@ -289,13 +293,14 @@ alone, so typing never starts competing database scans. Reasoning and tool
289
293
  payloads are never indexed or previewed, and session ids are validated before
290
294
  any SQL interpolation.
291
295
 
292
- Flat scripts back the terminal UI — the picker (`sesh.sh`), the refresh engine
293
- (`sesh-list.sh`, driven by a per-picker `sesh-refresh-worker.sh` that serializes
294
- scans), preview renderer (`sesh-preview.sh`), deleter (`sesh-delete.sh`) and
295
- shortcut help (`sesh-shortcuts.sh`). The TUI panel (`tui-plugins/sesh-panel/tui.tsx`) is a
296
- SolidJS OpenTUI plugin that talks to the opencode SDK over the same store; the
297
- `sesh_list` agent tool reads it read-only through `bun:sqlite`. V2 discovers
298
- the installed tool automatically in the global config directory's `plugins/`.
296
+ Flat scripts in `bin/` back the terminal UI and CLI subcommands — the picker,
297
+ serialized refresh worker, preview renderer, pin store, deleter, pruner,
298
+ waiting-session check, cost digest, and shortcut help. The TUI panel
299
+ (`tui-plugins/sesh-panel/tui.tsx`) is a SolidJS OpenTUI plugin that talks to the
300
+ opencode SDK over the same store; the npm package ships it precompiled as
301
+ `dist/tui.js`. The `sesh_list` agent tool reads the store read-only through
302
+ `bun:sqlite` and is discovered automatically from the global config directory's
303
+ `plugins/`.
299
304
 
300
305
  ## FAQ
301
306
 
@@ -325,8 +330,8 @@ checks before opening a PR:
325
330
 
326
331
  ```bash
327
332
  bun install
328
- bun run test # fixture-database regression suite
329
- bun run test:picker # PTY picker suite (needs fzf >= 0.73)
333
+ bun run test # builds dist/tui.js, then the fixture-database regression suite
334
+ bun run test:picker # PTY picker suite
330
335
  bun run typecheck # tsc over tui-plugins/ and plugins/
331
336
  bun run lint:sh # bash -n on every script
332
337
  ```