opencode-sesh 0.14.1 → 1.0.1

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
@@ -10,9 +10,9 @@ territory: read this first, then the specific file you need.
10
10
  1. **`bin/`** — a fullscreen [fzf](https://github.com/junegunn/fzf) picker for
11
11
  any terminal. Lists **all** sessions across **all** project directories,
12
12
  full-text searchable, with transcript preview and resume/fork/delete.
13
- 2. **`tui/sesh-panel.tsx`** — a SolidJS/OpenTUI plugin for the opencode TUI: a
14
- recent-sessions section in the sidebar plus an `option+o` / `/sesh` picker.
15
- 3. **`opencode/tools/sesh-list.ts`** — the `sesh-list` custom tool, so the agent
13
+ 2. **`tui-plugins/sesh-panel/tui.tsx`** — a SolidJS/OpenTUI plugin for the opencode TUI: a
14
+ recent-sessions section in the sidebar plus an `alt+o` / `/sesh` picker.
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
  db` store (the native `opencode session list` is project-scoped).
18
18
 
@@ -29,7 +29,7 @@ bun install # dev deps (TypeScript, opencode/OpenTUI types)
29
29
  bun run test # fixture-DB regression suite — must stay green
30
30
  bun run test:changelog # release-tooling regressions (scripts/changelog.sh)
31
31
  bun run test:picker # PTY picker suite (needs fzf >= 0.73)
32
- bun run typecheck # tsc over tui/ and opencode/
32
+ bun run typecheck # tsc over tui-plugins/ and plugins/
33
33
  bun run lint:sh # bash -n on every script
34
34
  HOME=/tmp/fakehome bash install.sh # installer smoke test (never touches ~/.config)
35
35
  ```
@@ -47,15 +47,14 @@ HOME=/tmp/fakehome bash install.sh # installer smoke test (never touches ~/.co
47
47
  stay on `opencode session delete`.
48
48
  - `contrib/` — caller-side integrations (currently cmux). Nothing here may add
49
49
  window management to sesh itself.
50
- - `tui/sesh-panel.tsx` — SolidJS panel, `/** @jsxImportSource @opentui/solid */`.
51
- - `opencode/tools/sesh-list.ts` — the agent-facing `sesh-list` tool.
50
+ - `tui-plugins/sesh-panel/tui.tsx` — SolidJS panel, `/** @jsxImportSource @opentui/solid */`.
51
+ - `plugins/sesh-list.ts` — the agent-facing `sesh_list` tool.
52
52
  - `scripts/changelog.sh` — release tooling: drafts conventional commits,
53
53
  writes a dated version, prints release notes and
54
54
  checks the compare links. `tests/changelog.sh` covers it in a throwaway repo.
55
55
  - `themes/`, `tests/`, `install.sh`, `README.md`.
56
56
 
57
- The **filename becomes the tool name** in opencode, so `sesh-list.ts` is the
58
- `sesh-list` tool. Do not rename it without updating the docs.
57
+ The tool name in opencode is `sesh_list`. Do not rename it without updating the docs.
59
58
 
60
59
  ## Data flow (fzf picker)
61
60
 
@@ -123,7 +122,7 @@ Resume happens in place (`exec` after `cd` to the session's cwd).
123
122
  action must come **before** `reload`/`reload-sync`: placed after, fzf silently
124
123
  publishes an empty list (verified on 0.74.3).
125
124
  - Destructive actions confirm. `sesh-delete.sh` prompts on a TTY and refuses
126
- without `--yes` when stdin is not one; the TUI arms on the first Ctrl-X and
125
+ without `--yes` when stdin is not one; the TUI arms on the first Option-D and
127
126
  commits on the second (or `y`).
128
127
  - The installer prefers the local opencode version for `@opencode-ai/*` and
129
128
  merges (never clobbers) the config `package.json`; opencode runs `bun install`
@@ -137,7 +136,7 @@ Resume happens in place (`exec` after `cd` to the session's cwd).
137
136
  and writes the new dated version and compare link. The released section is
138
137
  used as the GitHub release body.
139
138
 
140
- ## TUI panel (`tui/sesh-panel.tsx`)
139
+ ## TUI panel (`tui-plugins/sesh-panel/tui.tsx`)
141
140
 
142
141
  - **Sidebar:** `api.slots.register` on `sidebar_content` (append mode — native
143
142
  sidebar content stays). Pinned directories sort first, then directory groups
@@ -145,7 +144,7 @@ Resume happens in place (`exec` after `cd` to the session's cwd).
145
144
  Row markers alone signal session state: a running agent animates a loading
146
145
  spinner marker, the open session shows its own ●, and every other idle row
147
146
  stays neutral (polled every 15 s); Option-P previews
148
- a row and ctrl+x deletes one (armed, then confirmed). The section lists every
147
+ a row and option+d deletes one (armed, then confirmed). The section lists every
149
148
  session without a row cap and flex-grows to fill the sidebar, with overflow
150
149
  scrolling inside; the picker remains the place for transcript search.
151
150
  Sessions waiting on the user (unanswered questions, stuck runs) pin a
@@ -154,7 +153,7 @@ Resume happens in place (`exec` after `cd` to the session's cwd).
154
153
  - **Picker:** a custom dialog (not `DialogSelect`) grouped by
155
154
  project/directory, recency-ordered, resume via
156
155
  `api.route.navigate("session", …)`. `option+o` and the command palette open it;
157
- Ctrl-X arms and then confirms a delete through `api.client.session.delete` and
156
+ Option-D arms and then confirms a delete through `api.client.session.delete` and
158
157
  removes the row only after the server confirms; Ctrl-F forks through
159
158
  `api.client.session.fork`; Ctrl-G scopes the list to the selected session's
160
159
  project.
@@ -208,7 +207,7 @@ Resume happens in place (`exec` after `cd` to the session's cwd).
208
207
  same row. The section lists every session with no row cap
209
208
  (`tests/tui.mjs` asserts the cap stays out); overflow scrolls inside the
210
209
  stretched section.
211
- - **Delete in the TUI is two-step.** The first `ctrl+x` arms `pendingDelete`,
210
+ - **Delete in the TUI is two-step.** The first `option+d` arms `pendingDelete`,
212
211
  the second (or `y`, or Enter in the picker footer) commits the armed row
213
212
  wherever the pointer or cursor is, and `n`/Esc (or a five-second timeout)
214
213
  cancels. Moving the pointer must never disarm: edge-hover flicker ate the
@@ -231,5 +230,5 @@ Resume happens in place (`exec` after `cd` to the session's cwd).
231
230
  - `bun run typecheck` — `tsc` over `tui/` and `opencode/`.
232
231
  - `bun run lint:sh` — `bash -n` on every script.
233
232
  - `HOME=/tmp/fakehome bash install.sh` — installer smoke test.
234
- - Keep `tui/sesh-panel.tsx` and any installed copy byte-identical when testing
233
+ - Keep `tui-plugins/sesh-panel/tui.tsx` and any installed copy byte-identical when testing
235
234
  the panel locally.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ 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
+ ## [1.0.1] - 2026-10-08
9
+
10
+ ### Fixed
11
+
12
+ - **tui:** Bind delete to option+d, readable selected rows, keep scroll on delete
13
+
14
+ ## [1.0.0] - 2026-10-07
15
+
16
+ ### Breaking changes
17
+
18
+ - Migrate to OpenCode V2 plugin API with full feature parity _(breaking)_
19
+
20
+ ### Fixed
21
+
22
+ - **tui:** Adapt V2 theme colors for overlays and markdown previews
23
+ - **tui:** Center home recent sessions list horizontally
24
+
8
25
  ## [0.14.1] - 2026-10-01
9
26
 
10
27
  ### Fixed
@@ -407,6 +424,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
407
424
  - Fixture-database regression suite, TypeScript typechecking, and ShellCheck in
408
425
  CI.
409
426
 
427
+ [1.0.1]: https://github.com/ozandogrultan/opencode-sesh/compare/v1.0.0...v1.0.1
428
+ [1.0.0]: https://github.com/ozandogrultan/opencode-sesh/compare/v0.14.1...v1.0.0
410
429
  [0.14.1]: https://github.com/ozandogrultan/opencode-sesh/compare/v0.14.0...v0.14.1
411
430
  [0.14.0]: https://github.com/ozandogrultan/opencode-sesh/compare/v0.13.0...v0.14.0
412
431
  [0.13.0]: https://github.com/ozandogrultan/opencode-sesh/compare/v0.12.0...v0.13.0
package/README.md CHANGED
@@ -2,10 +2,12 @@
2
2
 
3
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
4
 
5
- **A session browser for [opencode](https://opencode.ai).** Search every session
5
+ **An [OpenCode V2](https://opencode.ai/v2/) plugin and terminal session browser.** Search every session
6
6
  across every project, preview the transcript, and resume in place — from your
7
7
  terminal or from inside the TUI.
8
8
 
9
+ The TUI plugin and agent tool require OpenCode V2 and are not compatible with V1.
10
+
9
11
  `opencode` keeps a growing pile of sessions, and its native lists (`<leader>l`,
10
12
  `/sessions`) are scoped to the current project. `sesh` shows all of them —
11
13
  grouped by directory, full-text searchable, and previewable from anywhere.
@@ -174,7 +176,7 @@ non-interactive `sesh-delete.sh` refuses unless given `--yes`.
174
176
  | `↑`/`↓`, `PgUp`/`PgDn`, `Home`/`End` | Move the selection |
175
177
  | Option-P | Toggle the transcript preview |
176
178
  | Enter | Open the selected session |
177
- | Ctrl-X | Delete the selected session (asks to confirm) |
179
+ | Option-D | Delete the selected session (asks to confirm) |
178
180
  | Ctrl-F | Fork the selected session |
179
181
  | Ctrl-G | Toggle scope: the selected session's project, or every project |
180
182
  | Option-W / Option-S | Show only sessions needing input / pinned sessions |
@@ -195,7 +197,7 @@ workspace at its directory; outside cmux it shows a toast instead.
195
197
  Click the sidebar's `search…` box to filter recent sessions in place; click
196
198
  elsewhere or press Esc to leave search. Click the **Sessions** heading to drive
197
199
  the list from the keyboard instead of the mouse (`↑`/`↓` to move, Enter to open,
198
- Option-P to preview, Ctrl-S/Ctrl-D to pin, Ctrl-X to delete, Esc to leave). Pinned
200
+ Option-P to preview, Ctrl-S/Ctrl-D to pin, Option-D to delete, Esc to leave). Pinned
199
201
  directories rise first, while sessions within each directory are ordered by
200
202
  last update, newest first. The section lists every session and scrolls to fill
201
203
  the sidebar, so click **▾ hide** to collapse it when you need the room.
@@ -253,7 +255,7 @@ any SQL interpolation.
253
255
  Flat scripts back the terminal UI — the picker (`sesh.sh`), the refresh engine
254
256
  (`sesh-list.sh`, driven by a per-picker `sesh-refresh-worker.sh` that serializes
255
257
  scans), preview renderer (`sesh-preview.sh`), deleter (`sesh-delete.sh`) and
256
- shortcut help (`sesh-shortcuts.sh`). The TUI panel (`tui/sesh-panel.tsx`) is a
258
+ shortcut help (`sesh-shortcuts.sh`). The TUI panel (`tui-plugins/sesh-panel/tui.tsx`) is a
257
259
  SolidJS OpenTUI plugin that talks to the opencode SDK over the same store; the
258
260
  `sesh-list` agent tool reads it through `opencode db`.
259
261
 
@@ -13,7 +13,7 @@
13
13
  #
14
14
  # Usage: sesh-waiting.sh [--json]
15
15
  # default prints a human table; --json prints [{id,reason,title,directory,updated}]
16
- # Keep NEEDS_INPUT_SQL in sync with the TUI sidebar copy in tui/sesh-panel.tsx.
16
+ # Keep NEEDS_INPUT_SQL in sync with the TUI sidebar copy in tui-plugins/sesh-panel/tui.tsx.
17
17
  set -euo pipefail
18
18
 
19
19
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -52,7 +52,7 @@ DB_PATH=$(resolve_db) || { echo 'sesh: session database unavailable' >&2; exit 1
52
52
  NOW_MS=$(python3 -c 'import time; print(int(time.time() * 1000))' 2>/dev/null || date +%s000)
53
53
  STUCK_BEFORE=$((NOW_MS - 600000))
54
54
 
55
- # NEEDS_INPUT_SQL (shared heuristic — keep in sync with tui/sesh-panel.tsx).
55
+ # NEEDS_INPUT_SQL (shared heuristic — keep in sync with tui-plugins/sesh-panel/tui.tsx).
56
56
  read -r -d '' QUERY <<SQL || true
57
57
  SELECT s.id AS id, s.directory AS directory, s.title AS title, s.time_updated AS updated,
58
58
  CASE WHEN EXISTS (
package/bin/sesh.sh CHANGED
@@ -41,8 +41,8 @@ if [ "${1:-}" = --check ]; then
41
41
  # The TUI panel is a copied file that opencode imports once at startup. Report
42
42
  # when the installed copy has fallen behind this package so upgrades are not
43
43
  # silently stale.
44
- panel_bundled="$SCRIPT_DIR/../tui/sesh-panel.tsx"
45
- panel_installed="${XDG_CONFIG_HOME:-$HOME/.config}/opencode/plugins/sesh-panel.tsx"
44
+ panel_bundled="$SCRIPT_DIR/../tui-plugins/sesh-panel/tui.tsx"
45
+ panel_installed="${XDG_CONFIG_HOME:-$HOME/.config}/opencode/tui-plugins/sesh-panel/tui.tsx"
46
46
  if [ -f "$panel_installed" ] && [ -f "$panel_bundled" ]; then
47
47
  if cmp -s "$panel_bundled" "$panel_installed"; then
48
48
  echo 'sesh: sidebar panel is current'
package/install.sh CHANGED
@@ -23,12 +23,12 @@ SYNC_PANEL=0
23
23
 
24
24
  # Fallback plugin version for when the opencode CLI is unavailable; the
25
25
  # installer prefers the local opencode version so the panel matches its SDK.
26
- PLUGIN_VERSION_FALLBACK="1.18.30"
26
+ PLUGIN_VERSION_FALLBACK="2.0.18"
27
27
  # Peer line the panel was developed and typechecked against. A checkout's
28
28
  # package.json overrides these, so dependency bumps cannot drift the installed
29
29
  # config out of sync (solid-js moves with OpenTUI via @opentui/keymap's peer).
30
30
  OPENTUI_RANGE="^0.5.11"
31
- SOLID_VERSION="1.9.12"
31
+ SOLID_VERSION="1.9.15"
32
32
  if [ -f "$SOURCE_DIR/package.json" ] && command -v jq >/dev/null 2>&1; then
33
33
  opentui_range=$(jq -r '.devDependencies["@opentui/solid"] // empty' "$SOURCE_DIR/package.json" 2>/dev/null || true)
34
34
  solid_version=$(jq -r '.devDependencies["solid-js"] // empty' "$SOURCE_DIR/package.json" 2>/dev/null || true)
@@ -65,9 +65,11 @@ LAUNCHER="$BIN_DIR/sesh"
65
65
  # `/sesh` is registered by the TUI plugin (a markdown command cannot open the
66
66
  # dialog); this path only exists so we can clean up an obsolete install.
67
67
  COMMAND_DST="$CONFIG_DIR/commands/sesh.md"
68
- TOOL_DST="$CONFIG_DIR/tools/sesh-list.ts"
69
- PANEL_DST="$CONFIG_DIR/plugins/sesh-panel.tsx"
68
+ TOOL_DST="$CONFIG_DIR/plugins/sesh-list.ts"
69
+ PANEL_DIR="$CONFIG_DIR/tui-plugins/sesh-panel"
70
+ PANEL_DST="$PANEL_DIR/tui.tsx"
70
71
  PACKAGE_JSON="$CONFIG_DIR/package.json"
72
+ OPENCODE_JSON="$CONFIG_DIR/opencode.json"
71
73
  TUI_JSON="$CONFIG_DIR/tui.json"
72
74
 
73
75
  # Remove a file only when it carries our marker, so a user's own file with a
@@ -94,6 +96,19 @@ remove_tui_entry() {
94
96
  fi
95
97
  }
96
98
 
99
+ remove_opencode_entry() {
100
+ [ -f "$OPENCODE_JSON" ] || return 0
101
+ command -v jq >/dev/null 2>&1 || return 0
102
+ local tmp
103
+ tmp=$(mktemp "${TMPDIR:-/tmp}/sesh-opencode.XXXXXX") || return 0
104
+ if jq 'if (.plugins | type) == "array" then .plugins = [.plugins[] | select(. != "./tui-plugins/sesh-panel")] else . end' "$OPENCODE_JSON" > "$tmp" 2>/dev/null; then
105
+ cmp -s "$OPENCODE_JSON" "$tmp" || mv "$tmp" "$OPENCODE_JSON"
106
+ rm -f "$tmp"
107
+ else
108
+ rm -f "$tmp"
109
+ fi
110
+ }
111
+
97
112
  # The launcher is a symlink we create. Treat it as ours only when it resolves to
98
113
  # a sesh launcher, so a foreign symlink is never replaced on install nor deleted
99
114
  # on uninstall. Recognized by the exact source path, a `.../bin/sesh` target, or
@@ -125,7 +140,9 @@ install_file() {
125
140
  }
126
141
 
127
142
  install_tui_panel() {
128
- install_file "$SOURCE_DIR/tui/sesh-panel.tsx" "$PANEL_DST"
143
+ install_file "$SOURCE_DIR/tui-plugins/sesh-panel/package.json" "$PANEL_DIR/package.json"
144
+ install_file "$SOURCE_DIR/tui-plugins/sesh-panel/server.ts" "$PANEL_DIR/server.ts"
145
+ install_file "$SOURCE_DIR/tui-plugins/sesh-panel/tui.tsx" "$PANEL_DST"
129
146
 
130
147
  local opencode_version='' raw_version='' plugin_version=''
131
148
  if command -v opencode >/dev/null 2>&1; then
@@ -134,33 +151,32 @@ install_tui_panel() {
134
151
  fi
135
152
  plugin_version="${opencode_version:-$PLUGIN_VERSION_FALLBACK}"
136
153
 
137
- # opencode has no persistent-sidebar API: the panel is an xlarge modal dialog
138
- # (see tui/sesh-panel.tsx). Register it idempotently and drop the previous
139
- # filename if an older install left it behind.
140
- local tui_created=0 tui_tmp=''
141
- if [ ! -f "$TUI_JSON" ]; then
142
- printf '{\n "$schema": "https://opencode.ai/tui.json",\n "plugin": []\n}\n' > "$TUI_JSON"
143
- tui_created=1
144
- note "created $TUI_JSON"
154
+ local opencode_created=0 opencode_tmp=''
155
+ if [ ! -f "$OPENCODE_JSON" ]; then
156
+ printf '{\n "$schema": "https://opencode.ai/config.json",\n "plugins": []\n}\n' > "$OPENCODE_JSON"
157
+ opencode_created=1
158
+ note "created $OPENCODE_JSON"
145
159
  fi
146
- tui_tmp=$(mktemp "${TMPDIR:-/tmp}/sesh-tui.XXXXXX")
160
+ opencode_tmp=$(mktemp "${TMPDIR:-/tmp}/sesh-opencode.XXXXXX")
147
161
  if jq '
148
- (.plugin // []) as $plugins
149
- | ($plugins | map(select(. != "./plugins/sessions-panel.tsx"))) as $clean
150
- | .plugin = (if ($clean | index("./plugins/sesh-panel.tsx")) then $clean else $clean + ["./plugins/sesh-panel.tsx"] end)
151
- ' "$TUI_JSON" > "$tui_tmp" 2>/dev/null; then
152
- if cmp -s "$TUI_JSON" "$tui_tmp"; then
153
- note "tui.json already registers the sesh panel"
154
- rm -f "$tui_tmp"
162
+ (.plugins // []) as $plugins
163
+ | if ($plugins | index("./tui-plugins/sesh-panel")) then . else .plugins = $plugins + ["./tui-plugins/sesh-panel"] end
164
+ ' "$OPENCODE_JSON" > "$opencode_tmp" 2>/dev/null; then
165
+ if cmp -s "$OPENCODE_JSON" "$opencode_tmp"; then
166
+ note "opencode.json already registers the sesh panel"
167
+ rm -f "$opencode_tmp"
155
168
  else
156
- mv "$tui_tmp" "$TUI_JSON"
157
- note "registered ./plugins/sesh-panel.tsx in tui.json"
169
+ mv "$opencode_tmp" "$OPENCODE_JSON"
170
+ note "registered ./tui-plugins/sesh-panel in opencode.json"
158
171
  fi
159
172
  else
160
- rm -f "$tui_tmp"
161
- note "warning: could not update $TUI_JSON; add \"./plugins/sesh-panel.tsx\" to its plugin list by hand"
173
+ rm -f "$opencode_tmp"
174
+ note "warning: could not update $OPENCODE_JSON; add \"./tui-plugins/sesh-panel\" to its plugins list by hand"
162
175
  fi
163
176
 
177
+ # Clean up obsolete V1 tui.json entry if present
178
+ remove_tui_entry
179
+
164
180
  # Local plugins resolve their imports from the config directory, and opencode
165
181
  # runs `bun install` there at startup. Keep the required packages declared
166
182
  # without clobbering versions the user already pinned.
@@ -171,10 +187,10 @@ install_tui_panel() {
171
187
  note "created $PACKAGE_JSON"
172
188
  fi
173
189
  pkg_tmp=$(mktemp "${TMPDIR:-/tmp}/sesh-pkg.XXXXXX")
174
- if jq --arg p "$plugin_version" --arg o "$OPENTUI_RANGE" --arg s "$SOLID_VERSION" '
190
+ if jq --arg p "^$plugin_version" --arg o "$OPENTUI_RANGE" --arg s "$SOLID_VERSION" '
175
191
  .dependencies = ((.dependencies // {}) as $d
176
192
  | {
177
- "@opencode-ai/plugin": ($d["@opencode-ai/plugin"] // $p),
193
+ "@opencode/plugin": ($d["@opencode/plugin"] // $p),
178
194
  "@opentui/core": ($d["@opentui/core"] // $o),
179
195
  "@opentui/keymap": ($d["@opentui/keymap"] // $o),
180
196
  "@opentui/solid": ($d["@opentui/solid"] // $o),
@@ -217,8 +233,13 @@ if [ "$UNINSTALL" = 1 ]; then
217
233
  fi
218
234
  fi
219
235
  remove_if_marker "$COMMAND_DST" "rich interactive picker" && note "removed $COMMAND_DST"
220
- remove_if_marker "$TOOL_DST" "list opencode sessions for the agent" && note "removed $TOOL_DST"
221
- remove_if_marker "$PANEL_DST" "@jsxImportSource @opentui/solid" && note "removed $PANEL_DST"
236
+ remove_if_marker "$TOOL_DST" "sesh_list" && note "removed $TOOL_DST"
237
+ remove_if_marker "$CONFIG_DIR/tools/sesh-list.ts" "list opencode sessions for the agent" && note "removed $CONFIG_DIR/tools/sesh-list.ts"
238
+ if [ -d "$PANEL_DIR" ]; then
239
+ rm -rf "$PANEL_DIR" && note "removed $PANEL_DIR"
240
+ fi
241
+ remove_if_marker "$CONFIG_DIR/plugins/sesh-panel.tsx" "@jsxImportSource @opentui/solid" && note "removed $CONFIG_DIR/plugins/sesh-panel.tsx"
242
+ remove_opencode_entry && note "unregistered the panel from $OPENCODE_JSON"
222
243
  remove_tui_entry && note "unregistered the panel from $TUI_JSON"
223
244
  note "uninstalled (extraction cache and plugin dependencies left intact)"
224
245
  exit 0
@@ -236,8 +257,10 @@ for path in \
236
257
  bin/sesh-retitle.sh \
237
258
  bin/sesh-waiting.sh \
238
259
  bin/sesh-shortcuts.sh \
239
- opencode/tools/sesh-list.ts \
240
- tui/sesh-panel.tsx \
260
+ plugins/sesh-list.ts \
261
+ tui-plugins/sesh-panel/package.json \
262
+ tui-plugins/sesh-panel/server.ts \
263
+ tui-plugins/sesh-panel/tui.tsx \
241
264
  themes/glow-dark-clean.json; do
242
265
  [ -f "$SOURCE_DIR/$path" ] || fail "installer bundle is incomplete: missing $path."
243
266
  done
@@ -283,7 +306,9 @@ note "linked $LAUNCHER -> $SOURCE_DIR/bin/sesh"
283
306
  # agent; the TUI plugin now registers the slash itself. Drop the old file so the
284
307
  # two do not collide.
285
308
  remove_if_marker "$COMMAND_DST" "rich interactive picker" && note "removed obsolete markdown command $COMMAND_DST"
286
- [ "$INSTALL_TOOL" = 1 ] && install_file "$SOURCE_DIR/opencode/tools/sesh-list.ts" "$TOOL_DST"
309
+ [ "$INSTALL_TOOL" = 1 ] && install_file "$SOURCE_DIR/plugins/sesh-list.ts" "$TOOL_DST"
310
+ # Clean up obsolete V1 tool if present
311
+ remove_if_marker "$CONFIG_DIR/tools/sesh-list.ts" "list opencode sessions for the agent" && note "removed obsolete V1 tool"
287
312
 
288
313
  if [ "$INSTALL_TUI" = 1 ]; then
289
314
  install_tui_panel
@@ -292,7 +317,7 @@ fi
292
317
  "$LAUNCHER" --check || fail "post-install check failed."
293
318
  note "done"
294
319
  note " picker: run 'sesh' in any terminal, or '/sesh' inside opencode"
295
- note " sidebar: option+o opens the full picker"
320
+ note " sidebar: alt+o opens the full picker"
296
321
  note_restart
297
322
  case ":$PATH:" in
298
323
  *":$BIN_DIR:"*) ;;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-sesh",
3
- "version": "0.14.1",
3
+ "version": "1.0.1",
4
4
  "description": "Browse, search, preview and resume opencode sessions from the terminal and the TUI.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -21,18 +21,24 @@
21
21
  "tui",
22
22
  "cli"
23
23
  ],
24
+ "exports": {
25
+ "./tui": "./tui-plugins/sesh-panel/tui.tsx",
26
+ "./tool": "./plugins/sesh-list.ts"
27
+ },
24
28
  "bin": {
25
29
  "sesh": "bin/sesh"
26
30
  },
27
31
  "files": [
28
32
  "bin/",
29
33
  "contrib/",
30
- "opencode/",
34
+ "plugins/",
31
35
  "themes/",
32
- "tui/",
36
+ "tui-plugins/",
33
37
  "install.sh",
34
38
  "AGENTS.md",
35
39
  "CHANGELOG.md",
40
+ "LICENSE",
41
+ "README.md",
36
42
  "ROADMAP.md"
37
43
  ],
38
44
  "publishConfig": {
@@ -40,7 +46,8 @@
40
46
  },
41
47
  "packageManager": "bun@1.4.2",
42
48
  "engines": {
43
- "node": ">=20"
49
+ "node": ">=20",
50
+ "opencode": ">=2.0.0"
44
51
  },
45
52
  "scripts": {
46
53
  "prepare": "husky",
@@ -53,17 +60,20 @@
53
60
  "postinstall": "bash install.sh --sync-panel || true",
54
61
  "prepublishOnly": "bun run test && bun run typecheck"
55
62
  },
63
+ "peerDependencies": {
64
+ "@opencode/plugin": ">=2.0.0"
65
+ },
56
66
  "devDependencies": {
57
67
  "@commitlint/cli": "^21.2.2",
58
68
  "@commitlint/config-conventional": "^21.2.2",
59
- "@opencode-ai/plugin": "1.18.30",
60
- "@opencode-ai/sdk": "1.18.30",
69
+ "@opencode/client": "2.0.18",
70
+ "@opencode/plugin": "2.0.18",
61
71
  "@opentui/core": "^0.5.11",
62
72
  "@opentui/keymap": "^0.5.11",
63
73
  "@opentui/solid": "^0.5.11",
64
74
  "@types/node": "26.5.1",
65
75
  "husky": "^9.1.7",
66
- "solid-js": "1.9.12",
76
+ "solid-js": "1.9.15",
67
77
  "typescript": "7.0.2"
68
78
  }
69
79
  }
@@ -0,0 +1,64 @@
1
+ import { Plugin } from "@opencode/plugin"
2
+ import { homedir } from "node:os"
3
+ import { join } from "node:path"
4
+
5
+ function dataHome(): string {
6
+ return process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share")
7
+ }
8
+
9
+ const input = {
10
+ type: "object",
11
+ properties: {
12
+ limit: {
13
+ type: "number",
14
+ description: "Maximum sessions to return (0-1000; 0 returns none)",
15
+ default: 50,
16
+ },
17
+ directory: {
18
+ type: "string",
19
+ description: "Only sessions from this directory (default: all directories)",
20
+ },
21
+ },
22
+ required: [],
23
+ additionalProperties: false,
24
+ } as const
25
+
26
+ export default Plugin.define({
27
+ id: "sesh-list",
28
+ async setup(ctx) {
29
+ ctx.tool.transform((editor) => {
30
+ editor.add({
31
+ name: "sesh_list",
32
+ description: "List opencode sessions across all project directories, newest first",
33
+ input,
34
+ async execute(args: any) {
35
+ const limit = args.limit === undefined ? 50 : Number(args.limit)
36
+ if (!Number.isInteger(limit) || limit < 0 || limit > 1000) {
37
+ throw new Error("limit must be an integer between 0 and 1000")
38
+ }
39
+ if (limit === 0) return { content: "[]" }
40
+
41
+ const specifier = "bun:sqlite"
42
+ const sqlite: any = await import(specifier).catch(() => undefined)
43
+ if (typeof sqlite?.Database !== "function") {
44
+ throw new Error("sesh_list requires the Bun runtime (bun:sqlite)")
45
+ }
46
+
47
+ const db = new sqlite.Database(join(dataHome(), "opencode", "opencode.db"), { readonly: true })
48
+ try {
49
+ const scoped = typeof args.directory === "string" && args.directory.length > 0
50
+ const query = `SELECT id, title, directory, time_updated AS updated, time_created AS created
51
+ FROM session_v2
52
+ WHERE parent_id IS NULL AND time_archived IS NULL${scoped ? " AND directory = ?" : ""}
53
+ ORDER BY time_updated DESC, id DESC
54
+ LIMIT ${limit}`
55
+ const rows = scoped ? db.query(query).all(args.directory) : db.query(query).all()
56
+ return { content: JSON.stringify(rows ?? []) }
57
+ } finally {
58
+ db.close?.()
59
+ }
60
+ },
61
+ })
62
+ })
63
+ },
64
+ })
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "opencode-tui-sesh-panel",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": "./server.ts",
7
+ "./tui": "./tui.tsx"
8
+ }
9
+ }
@@ -0,0 +1,2 @@
1
+ import { Plugin } from "@opencode/plugin"
2
+ export default Plugin.define({ id: "tui-sesh-panel", setup() {} })