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 +13 -14
- package/CHANGELOG.md +19 -0
- package/README.md +6 -4
- package/bin/sesh-waiting.sh +2 -2
- package/bin/sesh.sh +2 -2
- package/install.sh +58 -33
- package/package.json +17 -7
- package/plugins/sesh-list.ts +64 -0
- package/tui-plugins/sesh-panel/package.json +9 -0
- package/tui-plugins/sesh-panel/server.ts +2 -0
- package/{tui/sesh-panel.tsx → tui-plugins/sesh-panel/tui.tsx} +564 -253
- package/opencode/tools/sesh-list.ts +0 -51
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 `
|
|
15
|
-
3. **`
|
|
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
|
|
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
|
-
- `
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 `
|
|
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
|
[](https://github.com/ozandogrultan/opencode-sesh/actions/workflows/ci.yml)
|
|
4
4
|
|
|
5
|
-
**
|
|
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
|
-
|
|
|
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,
|
|
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
|
|
package/bin/sesh-waiting.sh
CHANGED
|
@@ -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="
|
|
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.
|
|
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/
|
|
69
|
-
|
|
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.
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
160
|
+
opencode_tmp=$(mktemp "${TMPDIR:-/tmp}/sesh-opencode.XXXXXX")
|
|
147
161
|
if jq '
|
|
148
|
-
(.
|
|
149
|
-
| ($plugins |
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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 "$
|
|
157
|
-
note "registered ./plugins/sesh-panel
|
|
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 "$
|
|
161
|
-
note "warning: could not update $
|
|
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 "
|
|
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
|
|
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" "
|
|
221
|
-
remove_if_marker "$
|
|
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
|
-
|
|
240
|
-
tui/sesh-panel.
|
|
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/
|
|
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:
|
|
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.
|
|
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
|
-
"
|
|
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
|
|
60
|
-
"@opencode
|
|
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.
|
|
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
|
+
})
|