The OpenCode TUI renders tool output through a literal <text> node
(packages/tui/.../session/index.tsx, GenericTool), so a GFM table
becomes a wall of pipes. The web/desktop client passes the same output
through the markdown renderer and draws a proper grid, so a GFM table
is the most compact form there.
The previous fix emitted a markdown table and assumed the TUI would
render it. It does not. The fix: ship both. The ASCII table is space-
padded, word-wraps long cells, and stays aligned even when the TUI
shows only its collapsed 3-line preview; the markdown table follows
and is what the web/desktop client renders with a proper grid.
- New rowsToAsciiTable: cellToAscii, truncateForCell, wrapCell,
visibleWidth, padRight. NULL -> <null>, BLOB -> <BLOB nB>, Date ->
ISO, BigInt -> string. Cell width capped at 40 chars by default
(configurable). Single words longer than the cap are hard-wrapped.
- sqlite_query's format=table path now emits the ASCII table first
and the markdown table second, with a blank line between.
- README explains why the duplication and how to read both.
End-to-end verified via Code Mode (no model in the loop) after
opencode service restart picked up the new transform.
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)
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.