opencode-sessions-explorer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/LICENSE +21 -0
- package/README.md +304 -0
- package/dist/bin/bulk-export.js +779 -0
- package/dist/bin/check-deps.js +948 -0
- package/dist/bin/dedupe-export.js +798 -0
- package/dist/plugin.js +15656 -0
- package/package.json +74 -0
- package/types/plugin.d.ts +4 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `opencode-sessions-explorer` will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-06-13
|
|
11
|
+
|
|
12
|
+
Initial public release on npm.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- `opencode-sessions-explorer-unarchive-session` — the first and only **write** tool. Restores a session to a usable state by clearing `session.time_archived` **and** refreshing `session.time_updated` in one `UPDATE`. It always resurfaces (even an already-active-but-buried session), so it is not a silent no-op on active rows; idempotent in effect (active + at the top). Only a non-existent id returns `NOT_FOUND`. The `time_updated` bump is required: OpenCode loads sessions ordered by `time_updated DESC` with a default `LIMIT 100` per directory, so merely clearing `time_archived` leaves a long-archived session buried below that window — the app never loads it and prompting fails with "Unable to retrieve session". Bumping resurfaces it at the top. OpenCode exposes no HTTP/SDK endpoint that can clear the flag (its `UpdatePayload.time.archived` is a finite number and the handler ignores `undefined`; verified against v1.15.12 source) and `opencode session` only offers list/delete, so a direct DB write is the only mechanism. Reads stay on the shared read-only handle; the write goes through a separate short-lived read-write connection in `src/lib/db-write.ts`. New `WRITE_FAILED` error code. The plugin namespace is now 18 tools (17 read-only + 1 write).
|
|
16
|
+
- `tests/unarchive.test.ts` — exercises the write path against a throwaway snapshot copy of the live DB (real archived session → unarchived, already-active-but-buried session → resurfaced, `time_updated` refresh, NOT_FOUND, and live-DB isolation), so the suite never mutates the real DB. `verify-end-to-end.ts` probes the tool via the zero-mutation NOT_FOUND path (now 17/17).
|
|
17
|
+
- Columnar + interning result codec (`src/lib/table.ts`: `table()`/`decodeTable()`/`isTable()`) applied to all list-shaped tool results. Lossless; measured −33% to −56% payload size by removing per-row key repetition and interning repeated model/directory/agent/project/channel/type values. Envelope and tool descriptions unchanged. Flat `search-text` hits drop the constant `raw_ref` (use the in-row `part_id` with `get-part`); duplicate `ranked_sessions` removed in favor of the single `sessions` table.
|
|
18
|
+
- Hermetic synthetic fixture DB so `bun test` runs without a live OpenCode history by default; live runs are opt-in via `OPENCODE_SESSIONS_EXPLORER_LIVE=1` (or `bun run test:live`).
|
|
19
|
+
- Curated recall surfaces for `search-text` and `grep-session`: `recall`, `debug_trace`, `tool_audit`, `code`, and `forensics`.
|
|
20
|
+
- Channelized export views under `by-channel/` while preserving raw `by-session/` replay data.
|
|
21
|
+
- Session-first ranked `search-text` results for unscoped recall, with evidence snippets, channel counts, suppressed counts, and raw refs.
|
|
22
|
+
- Structured `truncated_fields` metadata in `get-part` and `get-message`.
|
|
23
|
+
- `current-session` compact/default output with explicit `detail:'full'` for counters, children, paths, and suggestions.
|
|
24
|
+
- Redaction regression coverage and forensic/raw parity coverage in the rehearsal suite.
|
|
25
|
+
- Initial extraction from `~/.config/opencode/` into a standalone repo.
|
|
26
|
+
- 18 tools registered under the `opencode-sessions-explorer-*` namespace:
|
|
27
|
+
- **Recall**: `current-session`, `get-session`, `session-summary`, `session-timeline`, `get-message`, `get-part`, `session-genealogy`
|
|
28
|
+
- **Browse**: `list-sessions`, `search-sessions-meta`
|
|
29
|
+
- **Search**: `search-text`, `grep-session`, `search-tool-calls`
|
|
30
|
+
- **Analysis**: `cost-by-project`, `cost-by-period`, `list-tool-failures`, `list-repeated-prompts`
|
|
31
|
+
- **Health**: `db-stats`
|
|
32
|
+
- **Mutate** (write): `unarchive-session`
|
|
33
|
+
- CLI bins: `opencode-sessions-explorer-bulk-export`, `opencode-sessions-explorer-dedupe-export`, `opencode-sessions-explorer-check-deps`.
|
|
34
|
+
- Single Plugin entry point at `src/plugin.ts` returning `{ tool: { ... } }` per OpenCode plugin contract.
|
|
35
|
+
- 99 rehearsal probes covering the read-only tools (hermetic by default; live mode opt-in via `OPENCODE_SESSIONS_EXPLORER_LIVE=1`).
|
|
36
|
+
- README + LICENSE (MIT) + CHANGELOG.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
- Fixed `ck` multi-scope hangs by running bounded single-scope invocations and merging results.
|
|
40
|
+
- Reduced default noise in `search-tool-calls`, `session-timeline`, `session-summary`, `list-tool-failures`, and `list-repeated-prompts`.
|
|
41
|
+
- Defaulted search snippet redaction to on and expanded common secret patterns.
|
|
42
|
+
- Removed hardcoded `/Users/aleksandr.efremenkov/.cargo/bin/ck` from `lib/ck.ts`; added `OPENCODE_SESSIONS_EXPLORER_CK_BIN` env override.
|
|
43
|
+
- Replaced CJS `require("node:fs")` with ESM import in `lib/ck.ts`.
|
|
44
|
+
- Added `OPENCODE_SESSIONS_EXPLORER_TOOL_OUTPUT_DIR` env override in `lib/path-guard.ts`; added Windows support via `%LOCALAPPDATA%`.
|
|
45
|
+
- All tool imports rewritten from `"../opencode-sessions-explorer/lib/…"` (home-dir-coupled) to `"../lib/…"` (portable repo-relative).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aleksandr Efremenkov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# opencode-sessions-explorer
|
|
2
|
+
|
|
3
|
+
> Access to every prior OpenCode session on your machine — recall, search/grep, and historical analysis via 18 LLM-discoverable tools (17 read-only + one explicit unarchive write).
|
|
4
|
+
|
|
5
|
+
[](https://github.com/iamironz/opencode-sessions-explorer/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/opencode-sessions-explorer)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
`opencode-sessions-explorer` is an [OpenCode](https://opencode.ai) plugin that exposes your local SQLite session history (`~/.local/share/opencode/opencode.db`) to the running LLM as a set of named tools. Ask in natural language — *"Where in my history did I mention X?"*, *"How much did I spend on Claude this month?"*, *"Which tool fails most for me?"* — and the LLM picks the right tool automatically.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
This is published on npm as
|
|
16
|
+
[`opencode-sessions-explorer`](https://www.npmjs.com/package/opencode-sessions-explorer).
|
|
17
|
+
Add it to the `plugin` array in your OpenCode config — OpenCode auto-installs npm
|
|
18
|
+
plugins with Bun on startup (cached under `~/.cache/opencode/node_modules/`), so
|
|
19
|
+
there is no separate `npm install` step:
|
|
20
|
+
|
|
21
|
+
```jsonc
|
|
22
|
+
// ~/.config/opencode/opencode.json
|
|
23
|
+
{
|
|
24
|
+
"$schema": "https://opencode.ai/config.json",
|
|
25
|
+
|
|
26
|
+
"plugin": [
|
|
27
|
+
"opencode-sessions-explorer"
|
|
28
|
+
],
|
|
29
|
+
|
|
30
|
+
"permission": {
|
|
31
|
+
"external_directory": {
|
|
32
|
+
"~/.local/share/opencode/**": "allow"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
To pin a version, use `"opencode-sessions-explorer@0.1.0"`.
|
|
39
|
+
|
|
40
|
+
Then **quit and restart OpenCode**. All 18 tools auto-register.
|
|
41
|
+
|
|
42
|
+
The `external_directory` permission is required because the OpenCode DB lives
|
|
43
|
+
outside your project workspace; you grant read+write to it explicitly (the lone
|
|
44
|
+
write is `unarchive-session` — see [Writes](#writes)).
|
|
45
|
+
|
|
46
|
+
### From source (dev)
|
|
47
|
+
|
|
48
|
+
To run a local checkout, point the `plugin` entry at the built file instead of
|
|
49
|
+
the npm package:
|
|
50
|
+
|
|
51
|
+
```jsonc
|
|
52
|
+
// ~/.config/opencode/opencode.json
|
|
53
|
+
{
|
|
54
|
+
"$schema": "https://opencode.ai/config.json",
|
|
55
|
+
|
|
56
|
+
"plugin": [
|
|
57
|
+
"file:///absolute/path/to/opencode-sessions-explorer/dist/plugin.js"
|
|
58
|
+
],
|
|
59
|
+
|
|
60
|
+
"permission": {
|
|
61
|
+
"external_directory": {
|
|
62
|
+
"~/.local/share/opencode/**": "allow"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Run `bun run build` first to produce `dist/plugin.js`. For active development you
|
|
69
|
+
can point at `src/plugin.ts` directly — Bun loads TS without a build step. Then
|
|
70
|
+
**quit and restart OpenCode**.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## First run
|
|
75
|
+
|
|
76
|
+
The text-search tools (`search-text`, `grep-session`) need a filesystem export of your session content (used by `ck` for indexed search). The export contains both raw replay files and derived channel views used for cleaner default recall:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# One-time, ~30-60s for typical histories
|
|
80
|
+
bunx opencode-sessions-explorer-bulk-export
|
|
81
|
+
|
|
82
|
+
# After upgrading from pre-channel versions, backfill curated recall views
|
|
83
|
+
bunx opencode-sessions-explorer-bulk-export --reset
|
|
84
|
+
|
|
85
|
+
# Optional: build the semantic search index (~5 h for ~150k parts; resumable)
|
|
86
|
+
cd ~/.local/share/opencode-sessions-explorer && ck --index .
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
After the first export, the plugin auto-syncs new parts on every search call (3-4s budget).
|
|
90
|
+
|
|
91
|
+
Run the health check anytime:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
bunx opencode-sessions-explorer-check-deps
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## External dependencies
|
|
100
|
+
|
|
101
|
+
| Dependency | Required for | Install |
|
|
102
|
+
| ---------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
103
|
+
| **Bun ≥ 1.0** | Everything (the plugin uses `bun:sqlite`) | OpenCode ships Bun. If running CLIs standalone: <https://bun.sh> |
|
|
104
|
+
| **OpenCode DB** | Everything (the source of truth) | Auto-created at `~/.local/share/opencode/opencode.db` by OpenCode. Override path via `$OPENCODE_SESSIONS_EXPLORER_DB` |
|
|
105
|
+
| **`ck` CLI ≥ 0.7** | `search-text` + `grep-session` (the other 16 tools work without) | `cargo install ck-search` — see <https://github.com/BeaconBay/ck> |
|
|
106
|
+
|
|
107
|
+
If `ck` is missing, `search-text`/`grep-session` cleanly return `CK_NOT_FOUND`; the other 16 tools work fine.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## The 18 tools
|
|
112
|
+
|
|
113
|
+
### Recall
|
|
114
|
+
|
|
115
|
+
| Tool | Answers |
|
|
116
|
+
| ----------------------------------- | ---------------------------------------------------------------------- |
|
|
117
|
+
| `opencode-sessions-explorer-current-session` | *"What session am I in / who am I / where am I"* |
|
|
118
|
+
| `opencode-sessions-explorer-get-session` | *"Tell me about session ses_…"* (metadata + counts + children) |
|
|
119
|
+
| `opencode-sessions-explorer-session-summary` | *"Summarize session ses_…"* (prompts, files, tools, errors, cost) |
|
|
120
|
+
| `opencode-sessions-explorer-session-timeline` | *"Walk through session ses_… chronologically"* |
|
|
121
|
+
| `opencode-sessions-explorer-get-message` | *"Fetch message msg_… with its parts"* |
|
|
122
|
+
| `opencode-sessions-explorer-get-part` | *"Show me part prt_…"* (+ optional tool-output dereference) |
|
|
123
|
+
| `opencode-sessions-explorer-session-genealogy` | *"Parent chain / subagents spawned from ses_…"* |
|
|
124
|
+
|
|
125
|
+
### Browse / filter
|
|
126
|
+
|
|
127
|
+
| Tool | Answers |
|
|
128
|
+
| -------------------------------------- | ------------------------------------------------------------------------------- |
|
|
129
|
+
| `opencode-sessions-explorer-list-sessions` | *"List my recent sessions / sessions using agent X / sessions in directory Y"* |
|
|
130
|
+
| `opencode-sessions-explorer-search-sessions-meta` | *"Find sessions costing more than $5 / title matching X / under directory Y"* |
|
|
131
|
+
|
|
132
|
+
### Content search
|
|
133
|
+
|
|
134
|
+
| Tool | Answers |
|
|
135
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
136
|
+
| `opencode-sessions-explorer-search-text` | *"Where in my history did I mention X?"* (curated session-first recall by default; `surface:'forensics'` for raw replay) |
|
|
137
|
+
| `opencode-sessions-explorer-grep-session` | *"Inside session ses_…, grep for X"* (curated channels by default; raw via `surface:'forensics'`) |
|
|
138
|
+
| `opencode-sessions-explorer-search-tool-calls` | *"Every time I ran git push / every read that errored / all my Jira MCP calls"* |
|
|
139
|
+
|
|
140
|
+
### Analysis
|
|
141
|
+
|
|
142
|
+
| Tool | Answers |
|
|
143
|
+
| --------------------------------------- | ------------------------------------------------------ |
|
|
144
|
+
| `opencode-sessions-explorer-cost-by-project` | *"Cost by project / directory / agent / model"* |
|
|
145
|
+
| `opencode-sessions-explorer-cost-by-period` | *"OpenCode spend per day / week / month"* |
|
|
146
|
+
| `opencode-sessions-explorer-list-tool-failures` | *"Which tool fails most / what errors keep recurring"* |
|
|
147
|
+
| `opencode-sessions-explorer-list-repeated-prompts` | *"Have I asked this question before / repeated prompts"* |
|
|
148
|
+
|
|
149
|
+
### Health
|
|
150
|
+
|
|
151
|
+
| Tool | Answers |
|
|
152
|
+
| -------------------------- | ---------------------------------------------------- |
|
|
153
|
+
| `opencode-sessions-explorer-db-stats` | *"Is the local OpenCode DB healthy / any schema drift"* |
|
|
154
|
+
|
|
155
|
+
### Mutate (the one write tool)
|
|
156
|
+
|
|
157
|
+
| Tool | Answers |
|
|
158
|
+
| ------------------------------------------ | ------------------------------------------------------------------------- |
|
|
159
|
+
| `opencode-sessions-explorer-unarchive-session` | *"Unarchive / restore an archived session ses_…"* (clears `time_archived` + resurfaces) |
|
|
160
|
+
|
|
161
|
+
This is the **only** tool that writes to `opencode.db`; see [Writes](#writes) below.
|
|
162
|
+
|
|
163
|
+
### Search Surfaces
|
|
164
|
+
|
|
165
|
+
`search-text` and `grep-session` are curated by default. They preserve raw recall by reference instead of dumping every matching byte.
|
|
166
|
+
|
|
167
|
+
| Surface | Default channels | Use when |
|
|
168
|
+
| ------- | ---------------- | -------- |
|
|
169
|
+
| `recall` | `conversation`, `session-summary` | normal "have I discussed X?" memory questions |
|
|
170
|
+
| `debug_trace` | `conversation`, `session-summary`, `tool-error`, `tool-input-summary` | errors, stack traces, failed commands, logs |
|
|
171
|
+
| `tool_audit` | `tool-input-summary`, `tool-error` | tool invocation history |
|
|
172
|
+
| `code` | `conversation`, `session-summary`, `code-touch`, `patch-summary`, `tool-input-summary` | files, symbols, diffs, code paths |
|
|
173
|
+
| `forensics` | `raw` | exhaustive raw replay, including tool output and reasoning |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Compact result format (columnar + interning)
|
|
178
|
+
|
|
179
|
+
List-shaped results (`list-sessions`, `search-sessions-meta`, `search-tool-calls`, `session-timeline`, `cost-by-project`, `cost-by-period`, `list-tool-failures`, `list-repeated-prompts`, `search-text`, `grep-session`, `session-genealogy` ancestors) are returned as a **lossless columnar table** instead of an array-of-objects. This removes per-row key repetition and interns high-repetition values (model, directory, agent, project, channel, event type) into a small dictionary — measured **−33% to −56%** payload size with no information removed.
|
|
180
|
+
|
|
181
|
+
```jsonc
|
|
182
|
+
"sessions": {
|
|
183
|
+
"cols": ["id","title","agent","model","directory", "...", "archived"],
|
|
184
|
+
"dict": { "agent": ["build","executor-gpt"], "model": [{"id":"gpt-5.5-fast", "...": "..."}], "directory": ["/Users/you"] },
|
|
185
|
+
"rows": [ ["ses_…","Title…",0,0,0, "…", true] ]
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Decode rule (single):** a cell in a column whose name is a key in `dict` is an integer index into `dict[col]`; otherwise it is the literal value. Scalars next to the table (`has_more`, `mode`, `suppressed`, …) are unchanged. A reference decoder ships as `decodeTable()` in `src/lib/table.ts`. The envelope (`ok`/`data`/`meta`/`warnings`) is unchanged.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Architecture (4 layers)
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
L1 SQLite DB ← source of truth (read-only access)
|
|
197
|
+
↓ (delta sync, runs before every search call)
|
|
198
|
+
L2 opencode-sessions-explorer/ tree ← raw by-session replay + derived by-channel views
|
|
199
|
+
↓ (conversation, session-summary, tool-error,
|
|
200
|
+
↓ code-touch, tool-output, reasoning, etc.)
|
|
201
|
+
L3 .ck/ index ← BM25 (Tantivy) + embeddings (bge-small),
|
|
202
|
+
↓ auto-incremental via blake3 chunk hash
|
|
203
|
+
L4 enriched response ← every hit re-fetches session/part metadata
|
|
204
|
+
from SQLite for accuracy
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
All **reads** go through a shared `bun:sqlite` handle opened `readonly: true` + `PRAGMA query_only = 1`; any accidental write on that path throws. The single exception is the `unarchive-session` tool — see [Writes](#writes).
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Writes
|
|
212
|
+
|
|
213
|
+
17 of the 18 tools are strictly read-only. The lone exception is **`unarchive-session`**, which restores an archived session so it can be opened and prompted again.
|
|
214
|
+
|
|
215
|
+
- **Why a direct DB write?** OpenCode exposes no archive/unarchive endpoint that can *clear* the flag: its HTTP `UpdatePayload` types `time.archived` as a finite number and the handler ignores `undefined`, so a clear/`null` can't be sent over the wire (verified against v1.15.12 source). `opencode session` only offers `list`/`delete`. A direct DB write is the only mechanism.
|
|
216
|
+
- **What it writes.** It clears `time_archived` **and** refreshes `time_updated` to now, in one `UPDATE`, via a separate short-lived read-write connection (`src/lib/db-write.ts`); the shared read handle stays read-only. It **always restores to a usable state** — including an already-active-but-buried session (e.g. one unarchived by an older build that didn't refresh `time_updated`) — so it is not a silent no-op on active sessions; it is idempotent in effect (active + at the top). Only a non-existent id is rejected (`NOT_FOUND`).
|
|
217
|
+
- **Why bump `time_updated`?** OpenCode's app/server load the session list ordered by `time_updated DESC` with a default `LIMIT 100` **per directory**. A long-archived session keeps an old `time_updated`, so merely clearing `time_archived` leaves it buried below that window — the app never loads it and prompting fails with *"Unable to retrieve session"*. Refreshing `time_updated` resurfaces the restored session at the top, where the app loads it (this is also the intuitive meaning of "restore").
|
|
218
|
+
- **Permission.** No extra permission is needed: the existing `external_directory: { "~/.local/share/opencode/**": "allow" }` rule already covers read+write access to the DB file.
|
|
219
|
+
- **After restoring.** An external write emits no `session.updated` event, so an already-open OpenCode window won't update live. **Reload/restart the window** and open OpenCode in the session's **directory** (sessions are listed per directory). Because `time_updated` is refreshed, the restored session then appears at the top of the list.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Configuration
|
|
224
|
+
|
|
225
|
+
All paths are env-overridable:
|
|
226
|
+
|
|
227
|
+
| Env var | Default | Purpose |
|
|
228
|
+
| -------------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------ |
|
|
229
|
+
| `OPENCODE_SESSIONS_EXPLORER_DB` | `$XDG_DATA_HOME/opencode/opencode.db` (Linux/Mac) / `%LOCALAPPDATA%/opencode/opencode.db` (Win) | Path to the OpenCode SQLite DB |
|
|
230
|
+
| `OPENCODE_SESSIONS_EXPLORER_EXPORT_ROOT` | `$XDG_DATA_HOME/opencode-sessions-explorer` | Where to materialize searchable session content |
|
|
231
|
+
| `OPENCODE_SESSIONS_EXPLORER_TOOL_OUTPUT_DIR` | `$XDG_DATA_HOME/opencode/tool-output` | Whitelist root for `get-part` dereference |
|
|
232
|
+
| `OPENCODE_SESSIONS_EXPLORER_CK_BIN` | `ck` (via $PATH) | Override `ck` binary location |
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Privacy
|
|
237
|
+
|
|
238
|
+
The plugin exposes **all your prior OpenCode conversations** to the LLM — including tool inputs/outputs that may contain credentials, API tokens, file contents, and other sensitive material. Consider:
|
|
239
|
+
|
|
240
|
+
- The `search-text` and `grep-session` tools redact common secret shapes (`AKIA…`, `ghp_…`, `sk-…`, JWTs, bearer tokens, etc.) in returned snippets by default. Pass `redact:false` only for explicit local forensics.
|
|
241
|
+
- All access is **local read-only** — no data leaves your machine via this plugin.
|
|
242
|
+
- The `external_directory` permission rule is required because the DB lives outside your project workspace; you grant it explicitly.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Development
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# Install
|
|
250
|
+
bun install
|
|
251
|
+
|
|
252
|
+
# Typecheck
|
|
253
|
+
bun run typecheck
|
|
254
|
+
|
|
255
|
+
# Build to dist/
|
|
256
|
+
bun run build
|
|
257
|
+
|
|
258
|
+
# Run the rehearsal harness (hermetic by default; live DB via OPENCODE_SESSIONS_EXPLORER_LIVE=1)
|
|
259
|
+
bun test
|
|
260
|
+
|
|
261
|
+
# End-to-end verifier (compares tool output vs ground-truth SQL; needs a live DB)
|
|
262
|
+
bun tests/verify-end-to-end.ts
|
|
263
|
+
|
|
264
|
+
# Plugin invocation (sanity)
|
|
265
|
+
bun src/plugin.ts
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Repo layout
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
src/
|
|
272
|
+
├── plugin.ts default Plugin export — registers all 18 tools
|
|
273
|
+
├── tools/
|
|
274
|
+
│ ├── index.ts registry { "opencode-sessions-explorer-…": toolDefinition, … }
|
|
275
|
+
│ ├── current-session.ts 1 per tool — named const, not default export
|
|
276
|
+
│ ├── unarchive-session.ts the only write tool (clears time_archived + resurfaces)
|
|
277
|
+
│ └── (16 more)
|
|
278
|
+
├── lib/ shared internals (db, db-write, ck, export, decode, …)
|
|
279
|
+
└── bin/
|
|
280
|
+
├── bulk-export.ts materializes session content for ck
|
|
281
|
+
├── dedupe-export.ts maintenance
|
|
282
|
+
└── check-deps.ts install health probe
|
|
283
|
+
|
|
284
|
+
tests/
|
|
285
|
+
├── rehearsal.test.ts read-only probes (hermetic fixture by default; live DB opt-in)
|
|
286
|
+
├── unarchive.test.ts write-path probes (run against a throwaway DB copy)
|
|
287
|
+
├── helpers.ts
|
|
288
|
+
├── fixtures.json session IDs used by the rehearsal probes
|
|
289
|
+
└── verify-end-to-end.ts smoke verifier — runs every tool + compares vs SQL
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Status
|
|
295
|
+
|
|
296
|
+
- 18 tools registered (17 read-only + 1 unarchive write)
|
|
297
|
+
- Published on npm as [`opencode-sessions-explorer`](https://www.npmjs.com/package/opencode-sessions-explorer)
|
|
298
|
+
- Test suite passing **hermetically by default** against a synthetic fixture DB (live-DB probes opt-in via `OPENCODE_SESSIONS_EXPLORER_LIVE=1`; unarchive write-path probes run against a throwaway DB copy)
|
|
299
|
+
- 17/17 end-to-end tool verification passing (unarchive probed via the zero-mutation NOT_FOUND path)
|
|
300
|
+
- Local and npm plugin installs verified end-to-end
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
[MIT](LICENSE)
|