OpenCode's tool content schema (Tool.Content = TextContent | FileContent)
gives a server plugin no metadata channel — the TUI's only view of tool
output is the content string. So: format the result as a Markdown
table, which the TUI's built-in markdown renderer already displays as
a real table.
- sqlite_query gains format = 'table' (default) | 'json' | 'both'.
'table' is the new default and renders a header line, a separator
row, and one row per record with pipes/newlines/backslashes escaped.
'json' keeps the old behaviour for callers that need raw rows.
- Every tool that runs SQL echoes 'SQL: <stmt> params: [...]' as the
first line of its output, so the user sees what was executed
including the bound values.
- Every tool that runs a statement pushes context.progress() at start
and end, which surfaces in the TUI status bar.
- cellToMarkdown caps each cell at 80 chars to keep wide BLOBs from
blowing up the TUI column width.
End-to-end verified via Code Mode (no model in the loop):
- format=table renders correctly with edge cases (| in text, \n in
text, \ in text)
- format=both appends the JSON view below the table
- exec echoes the bound params as a JSON array
- write+read round-trip persists (UPDATE → SELECT sees the new value)
User asked what happens if the window is closed mid-task. Added a
'What happens if the process dies mid-task' section that tabulates
the four exit paths (TUI close, SIGTERM, SIGKILL, power loss) and
empirically confirms that anything past the last fsync'd commit is
on disk. The only ways to lose data are :memory:, an explicit
synchronous=OFF, or a network filesystem. Also corrects the earlier
'leak fd' framing — a dead process leaks no fds, the OS reclaims
them.
User asked what happens if the connection is never closed and whether
concurrent calls are safe. Adds a Lifecycle and concurrency section
to README.md covering:
- not closing only leaks fds; data is durable on commit
- 3-tier concurrency model: same service / multi-CLI same service /
multi-process, with the actual busy_timeout default (5s) and what
to do if a longer wait is needed (run PRAGMA busy_timeout via
sqlite_exec)
- :memory: semantics (gone on close, even within one process)
- NFS/SMB caveat
No code changes; current defaults (busy_timeout 5s, synchronous
FULL, locking normal) are sensible and the existing test sweep
already verified end-to-end.
Adds a single-file V2 plugin that exposes eight tools under the
`sqlite` namespace (open, close, list, query, exec, script, tables,
schema) so a model can read and write SQLite databases from a session.
- OpenCode discovers it automatically from ~/.config/opencode/plugins/.
- New runtime dependency: better-sqlite3 (installed in this repo's
node_modules so the host's module resolution picks it up).
- README documents install, copy-to-another-machine, options, and
troubleshooting; SETUP.md is a copy-paste checklist.
- Schema/options were trimmed down while authoring: the initial draft
registered a no-op SQLite function on every open as a 'future hook';
removed, it was dead code.