Setup deliberately avoids the sqlite3 CLI (`setup/verify.ts:5` calls this out: "Uses better-sqlite3 directly (no sqlite3 CLI)") and never installs or probes for the binary. Despite that, 13 skills shelled out to `sqlite3 ...` directly, breaking on hosts where the CLI isn't preinstalled — the same root cause as #2191 but spread across the skill surface. Add `scripts/q.ts`, a ~30-LOC wrapper over the `better-sqlite3` dep that setup already installs and verifies. Default output matches `sqlite3 -list` (pipe-separated, no header) so existing skill text reads identically — only the binary changes. SELECT/WITH queries go through `db.prepare().all()`; everything else (INSERT/UPDATE/DELETE, including compound statements) goes through `db.exec()`. Migrate every in-tree caller: - 17 hardcoded invocations across 8 SKILL.md files (init-first-agent, add-deltachat, add-signal, add-emacs, add-whatsapp, add-ollama-provider, debug, add-parallel) plus add-deltachat/VERIFY.md. - `manage-channels/SKILL.md` shows canonical SQL but never prescribed a tool, so the assistant defaulted to `sqlite3` and silently failed. Add a one-line wrapper hint above the SQL block. - `migrate-v2.sh` schema/count probes (was the original #2191 case). Replace `.tables` with `SELECT name FROM sqlite_master`. - Document the wrapper convention in root `CLAUDE.md` under "Central DB". Add `scripts/q.test.ts` with 6 vitest cases covering both modes, NULL rendering, empty-result, compound mutations, and arg validation. Wire `scripts/**/*.test.ts` into `vitest.config.ts`. Out of scope (flagged for follow-up): - `debug` and `add-parallel` still reference the v1-only path `store/messages.db`. Routing through the wrapper now produces a cleaner "no such file" error, but the surrounding sections are v1-era throughout — a v1-content cleanup is its own PR. - `cleanup-sessions.sh` is being addressed in #1889 (different style, hard-fail rather than wrap); left untouched here to avoid stepping on that author's work. Closes #2191. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
/**
|
|
* scripts/q.ts — sqlite3 CLI replacement for skill SQL invocations.
|
|
*
|
|
* Usage:
|
|
* pnpm exec tsx scripts/q.ts <db-path> "<sql>"
|
|
*
|
|
* Detects SELECT vs mutation on the first keyword. SELECT/WITH queries
|
|
* print rows in sqlite3 CLI default ("list") format — pipe-separated,
|
|
* no header — so existing skill text reads identically. Anything else
|
|
* runs through db.exec() and prints nothing on success.
|
|
*
|
|
* Why this exists: setup/verify.ts:5 codifies that NanoClaw avoids
|
|
* depending on the sqlite3 CLI binary; setup never installs or probes
|
|
* for it. Skills that shell out to `sqlite3` therefore fail on hosts
|
|
* where it isn't preinstalled (common on fresh Ubuntu — see #2191).
|
|
* This wrapper preserves the skill-text shape (path then SQL string)
|
|
* while routing through the better-sqlite3 dep that setup already
|
|
* installs and verifies.
|
|
*/
|
|
import Database from 'better-sqlite3';
|
|
|
|
const [, , dbPath, sql] = process.argv;
|
|
|
|
if (!dbPath || sql === undefined) {
|
|
console.error('Usage: pnpm exec tsx scripts/q.ts <db-path> "<sql>"');
|
|
process.exit(2);
|
|
}
|
|
|
|
const db = new Database(dbPath);
|
|
try {
|
|
const firstKeyword = sql.trim().split(/\s+/)[0]?.toUpperCase() ?? '';
|
|
if (firstKeyword === 'SELECT' || firstKeyword === 'WITH') {
|
|
const rows = db.prepare(sql).all() as Record<string, unknown>[];
|
|
for (const row of rows) {
|
|
console.log(
|
|
Object.values(row)
|
|
.map((v) => (v === null ? '' : String(v)))
|
|
.join('|'),
|
|
);
|
|
}
|
|
} else {
|
|
db.exec(sql);
|
|
}
|
|
} finally {
|
|
db.close();
|
|
}
|