db-mcp 1.1.0 → 2.0.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.
Files changed (84) hide show
  1. package/.gitleaks.toml +9 -0
  2. package/.trivyignore +8 -0
  3. package/README.md +193 -120
  4. package/dist/{chunk-DWJXQEFA.js → chunk-5Y42NPBP.js} +4168 -2411
  5. package/dist/{chunk-AOUL5SHS.js → chunk-645ZEFLA.js} +70 -20
  6. package/dist/chunk-OKOVZ5QE.js +28 -0
  7. package/dist/chunk-SFJQCNG7.js +131 -0
  8. package/dist/{chunk-S5IDDSSB.js → chunk-VIDSICEL.js} +12 -1
  9. package/dist/chunk-WBER5YY4.js +2053 -0
  10. package/dist/{chunk-4IA3DB5C.js → chunk-X3MUUOWM.js} +19 -2
  11. package/dist/{chunk-Z2GFQU3G.js → chunk-Z7C2TM4L.js} +114 -21
  12. package/dist/cli.js +79 -5
  13. package/dist/{http-VSB7DBJR.js → http-6KF4ULDI.js} +199 -77
  14. package/dist/index.d.ts +231 -8
  15. package/dist/index.js +6 -5
  16. package/dist/{sqlite-VHBA4ABV.js → sqlite-U5KSYQXK.js} +63 -140
  17. package/dist/{sqlite-native-D2LH5ZT7.js → sqlite-native-JXMCFQBA.js} +576 -114
  18. package/dist/worker-script.js +34 -10
  19. package/logs/.gitkeep +1 -0
  20. package/mcp-config-example.json +83 -0
  21. package/package.json +9 -8
  22. package/playwright.config.ts +1 -1
  23. package/scripts/update-badges.ts +99 -0
  24. package/server.json +7 -5
  25. package/test-server/README.md +20 -23
  26. package/test-server/code-map.md +45 -33
  27. package/test-server/reset-database.ps1 +59 -17
  28. package/test-server/scripts/README.md +27 -0
  29. package/test-server/{test-help-resources.mjs → scripts/test-help-resources.mjs} +12 -5
  30. package/test-server/scripts/test-prompts.mjs +251 -0
  31. package/test-server/{test-tool-annotations.mjs → scripts/test-tool-annotations.mjs} +9 -4
  32. package/test-server/test-advanced/README.md +70 -0
  33. package/test-server/test-advanced/test-codemode-advanced-admin.md +174 -0
  34. package/test-server/test-advanced/test-codemode-advanced-core.md +193 -0
  35. package/test-server/test-advanced/test-codemode-advanced-geo.md +157 -0
  36. package/test-server/test-advanced/test-codemode-advanced-introspection.md +171 -0
  37. package/test-server/test-advanced/test-codemode-advanced-json.md +169 -0
  38. package/test-server/test-advanced/test-codemode-advanced-migration.md +160 -0
  39. package/test-server/test-advanced/test-codemode-advanced-stats.md +185 -0
  40. package/test-server/test-advanced/test-codemode-advanced-text.md +183 -0
  41. package/test-server/test-advanced/test-codemode-advanced-transactions.md +136 -0
  42. package/test-server/test-advanced/test-codemode-advanced-vector.md +141 -0
  43. package/test-server/test-codemode/README.md +121 -0
  44. package/test-server/test-codemode/test-codemode-admin.md +223 -0
  45. package/test-server/test-codemode/test-codemode-core.md +286 -0
  46. package/test-server/test-codemode/test-codemode-geo.md +177 -0
  47. package/test-server/test-codemode/test-codemode-introspection.md +190 -0
  48. package/test-server/test-codemode/test-codemode-json.md +237 -0
  49. package/test-server/test-codemode/test-codemode-migration.md +278 -0
  50. package/test-server/test-codemode/test-codemode-sandbox.md +413 -0
  51. package/test-server/test-codemode/test-codemode-stats.md +232 -0
  52. package/test-server/test-codemode/test-codemode-text.md +237 -0
  53. package/test-server/test-codemode/test-codemode-transactions.md +236 -0
  54. package/test-server/test-codemode/test-codemode-vector.md +244 -0
  55. package/test-server/test-codemode/test-codemode-wasm-degradation.md +394 -0
  56. package/test-server/test-database.sql +37 -1
  57. package/test-server/test-resources.md +43 -16
  58. package/test-server/test-tool-groups/README.md +100 -0
  59. package/test-server/test-tool-groups/test-admin-core.md +165 -0
  60. package/test-server/test-tool-groups/test-admin-extensions.md +133 -0
  61. package/test-server/{test-tools.md → test-tool-groups/test-core-data.md} +103 -17
  62. package/test-server/test-tool-groups/test-core-schema.md +240 -0
  63. package/test-server/test-tool-groups/test-geo-haversine.md +130 -0
  64. package/test-server/test-tool-groups/test-geo-spatialite.md +110 -0
  65. package/test-server/test-tool-groups/test-introspection-diagnostics.md +123 -0
  66. package/test-server/test-tool-groups/test-introspection-schema.md +133 -0
  67. package/test-server/test-tool-groups/test-json-read.md +219 -0
  68. package/test-server/test-tool-groups/test-json-write.md +157 -0
  69. package/test-server/test-tool-groups/test-migration.md +193 -0
  70. package/test-server/test-tool-groups/test-stats-advanced.md +118 -0
  71. package/test-server/test-tool-groups/test-stats-basic.md +156 -0
  72. package/test-server/test-tool-groups/test-text-advanced.md +169 -0
  73. package/test-server/test-tool-groups/test-text-basic.md +177 -0
  74. package/test-server/test-tool-groups/test-transactions.md +179 -0
  75. package/test-server/test-tool-groups/test-vector-read.md +130 -0
  76. package/test-server/test-tool-groups/test-vector-write.md +115 -0
  77. package/test-server/tool-reference.md +79 -58
  78. package/tsconfig.build.json +6 -0
  79. package/dist/chunk-DZQLDEQS.js +0 -879
  80. package/test-server/test-agent-experience.md +0 -243
  81. package/test-server/test-group-tools.md +0 -861
  82. package/test-server/test-tools-advanced-1.md +0 -517
  83. package/test-server/test-tools-advanced-2.md +0 -487
  84. package/test-server/test-tools-codemode.md +0 -629
@@ -0,0 +1,278 @@
1
+ # db-mcp Code Mode Testing: [migration]
2
+
3
+ > [!IMPORTANT]
4
+ > **Do not track progress in this file.** Track your test progress, coverage matrix, and findings in your internal task tracking system (artifact). However, you SHOULD edit this file to fix any factual errors, broken code, or incorrect assertions in the test prompts.
5
+ > If there is nothing to fix, don't update UNRELEASED.md.
6
+ > We're currently testing Native mode.
7
+
8
+ **Step 1:** Read `C:\Users\chris\Desktop\db-mcp\src\constants\server-instructions\gotchas.md` using `view_file`.
9
+
10
+ **Step 2:** Conduct an exhaustive test of the **migration** tool group using ONLY `sqlite_execute_code`. Do not use direct tool calls or terminal.
11
+
12
+ **Step 3:** The agent should update C:\Users\chris\Desktop\db-mcp\UNRELEASED.md with any/all changes/fixes.
13
+
14
+ > **⚠️ After testing, run `Set-Location C:\Users\chris\Desktop\db-mcp\test-server; .\reset-database.ps1`** — migration testing creates the `_mcp_migrations` tracking table and modifies schema. Always reset after.
15
+
16
+ ## WASM Mode
17
+
18
+ > When testing against a **WASM backend** (`--sqlite` / sql.js): All 6 migration tools are fully WASM-compatible. No phases to skip or adjust.
19
+
20
+ ## Reporting Format
21
+
22
+ - ❌ Fail: Tool errors or produces incorrect results
23
+ - ⚠️ Issue: Unexpected behavior or improvement opportunity
24
+ - 📦 Payload: Unnecessarily large response — monitor `metrics.tokenEstimate`.
25
+
26
+ ## Test Database Schema
27
+
28
+ | Table | Rows | Key Columns |
29
+ | ------------- | ---- | ---------------------------------------- |
30
+ | test_products | 16 | id, name, price, category |
31
+ | test_orders | 20 | id, product_id (FK), total_price, status |
32
+
33
+ ## Testing Requirements
34
+
35
+ > [!CAUTION]
36
+ > **Zero tolerance for raw MCP errors.** Report as ❌.
37
+
38
+ 1. **Batched scripting**: Bundle checks with `failures` array where possible.
39
+ 2. **Error path testing**: Every tool with `{}` (Zod) and domain error.
40
+ 3. **Token tracking**: Monitor `metrics.tokenEstimate`.
41
+ 4. **Coverage Matrix**: `| Tool | Happy Path | Domain Error | Zod Error |`
42
+ 5. **Deterministic checklist first**.
43
+ 6. **Code Over Docs**: Fix the handler code if standards (Structured Errors/Zod) are violated. Do NOT change docs/prompts to accommodate broken code.
44
+
45
+ > **⚠️ Migration ordering matters**: Migration tests are stateful — each depends on the previous. Run lifecycle tests sequentially, not batched.
46
+
47
+ ## Structured Error Response Pattern
48
+
49
+ Handler error ✅ = JSON with `success` + `error`. MCP error ❌ = raw text, `isError: true`.
50
+
51
+ ---
52
+
53
+ ## Phase 1: Initialization & Recording — Happy Paths (sequential)
54
+
55
+ ### 1.1 — Init migrations
56
+
57
+ ```javascript
58
+ return await sqlite.migration.migrationInit();
59
+ ```
60
+
61
+ Expected: `{success: true}`, creates `_mcp_migrations` table (idempotent).
62
+
63
+ ### 1.2 — Init again (idempotency)
64
+
65
+ ```javascript
66
+ return await sqlite.migration.migrationInit();
67
+ ```
68
+
69
+ Expected: Succeeds without error.
70
+
71
+ ### 1.3 — Check status (empty)
72
+
73
+ ```javascript
74
+ return await sqlite.migration.migrationStatus();
75
+ ```
76
+
77
+ Expected: No migrations applied.
78
+
79
+ ### 1.4 — Record a migration (no execution)
80
+
81
+ ```javascript
82
+ return await sqlite.migration.migrationRecord({
83
+ version: "1.0.0",
84
+ description: "Create temp table",
85
+ migrationSql:
86
+ "CREATE TABLE temp_cm_mig_test (id INTEGER PRIMARY KEY, name TEXT)",
87
+ });
88
+ ```
89
+
90
+ Expected: Recorded (SQL not executed — only logged).
91
+
92
+ ### 1.5 — Check status (1 migration)
93
+
94
+ ```javascript
95
+ return await sqlite.migration.migrationStatus();
96
+ ```
97
+
98
+ Expected: Count incremented.
99
+
100
+ ### 1.6 — Check history
101
+
102
+ ```javascript
103
+ return await sqlite.migration.migrationHistory();
104
+ ```
105
+
106
+ Expected: Version 1.0.0 listed.
107
+
108
+ ---
109
+
110
+ ## Phase 2: Apply & Execute — Happy Paths (sequential)
111
+
112
+ ### 2.1 — Apply a migration (SQL executed)
113
+
114
+ ```javascript
115
+ return await sqlite.migration.migrationApply({
116
+ version: "1.0.1",
117
+ description: "Create applied table",
118
+ migrationSql:
119
+ "CREATE TABLE temp_cm_mig_applied (id INTEGER PRIMARY KEY, value TEXT)",
120
+ });
121
+ ```
122
+
123
+ Expected: Applied (SQL executed AND recorded).
124
+
125
+ ### 2.2 — Verify table exists
126
+
127
+ ```javascript
128
+ return await sqlite.core.readQuery(
129
+ "SELECT name FROM sqlite_master WHERE name = 'temp_cm_mig_applied'",
130
+ );
131
+ ```
132
+
133
+ Expected: Table exists.
134
+
135
+ ### 2.3 — Check history (2 migrations)
136
+
137
+ ```javascript
138
+ return await sqlite.migration.migrationHistory();
139
+ ```
140
+
141
+ Expected: Both 1.0.0 and 1.0.1 listed.
142
+
143
+ ---
144
+
145
+ ## Phase 3: SHA-256 Deduplication
146
+
147
+ ### 3.1 — Duplicate SQL detection
148
+
149
+ ```javascript
150
+ return await sqlite.migration.migrationRecord({
151
+ version: "1.0.2",
152
+ description: "Duplicate test",
153
+ migrationSql:
154
+ "CREATE TABLE temp_cm_mig_test (id INTEGER PRIMARY KEY, name TEXT)",
155
+ });
156
+ ```
157
+
158
+ Expected: Fail — duplicate SQL hash detected.
159
+
160
+ ---
161
+
162
+ ## Phase 4: Rollback — Happy Paths (sequential)
163
+
164
+ ### 4.1 — Rollback without rollback SQL
165
+
166
+ ```javascript
167
+ return await sqlite.migration.migrationRollback({ version: "1.0.1" });
168
+ ```
169
+
170
+ Expected: Informative error (no rollbackSql was provided).
171
+
172
+ ### 4.2 — Apply with rollback SQL
173
+
174
+ ```javascript
175
+ return await sqlite.migration.migrationApply({
176
+ version: "1.0.3",
177
+ description: "With rollback",
178
+ migrationSql: "CREATE TABLE temp_cm_mig_rollback (id INTEGER PRIMARY KEY)",
179
+ rollbackSql: "DROP TABLE IF EXISTS temp_cm_mig_rollback",
180
+ });
181
+ ```
182
+
183
+ Expected: Applied with rollback SQL stored.
184
+
185
+ ### 4.3 — Execute rollback
186
+
187
+ ```javascript
188
+ return await sqlite.migration.migrationRollback({ version: "1.0.3" });
189
+ ```
190
+
191
+ Expected: Rollback SQL executed.
192
+
193
+ ### 4.4 — Verify table gone
194
+
195
+ ```javascript
196
+ return await sqlite.core.readQuery(
197
+ "SELECT name FROM sqlite_master WHERE name = 'temp_cm_mig_rollback'",
198
+ );
199
+ ```
200
+
201
+ Expected: Table does NOT exist.
202
+
203
+ ---
204
+
205
+ ## Phase 5: Migration Domain Errors (batched)
206
+
207
+ 🔴 5.1. `sqlite.migration.migrationApply({version: "bad version!", description: "Invalid", migrationSql: "SELECT 1"})` → report behavior
208
+ 🔴 5.2. `sqlite.migration.migrationRollback({version: "nonexistent_version"})` → `{success: false}`
209
+
210
+ ---
211
+
212
+ ## Phase 6: Migration Zod Validation (batched)
213
+
214
+ 🔴 6.1. `sqlite.migration.migrationInit({})` → success (no required params)
215
+ 🔴 6.2. `sqlite.migration.migrationRecord({})` → `{success: false}` (missing required params)
216
+ 🔴 6.3. `sqlite.migration.migrationApply({})` → `{success: false}` (missing required params)
217
+ 🔴 6.4. `sqlite.migration.migrationRollback({})` → `{success: false}` (missing `version`)
218
+ 🔴 6.5. `sqlite.migration.migrationHistory({})` → success (no required params)
219
+ 🔴 6.6. `sqlite.migration.migrationStatus({})` → success (no required params)
220
+
221
+ ---
222
+
223
+ ## Phase 7: Multi-Step Workflow
224
+
225
+ ### 7.1 — Full migration lifecycle
226
+
227
+ ```javascript
228
+ const failures = [];
229
+ // Init
230
+ await sqlite.migration.migrationInit();
231
+
232
+ // Apply
233
+ await sqlite.migration.migrationApply({
234
+ version: "9.9.1",
235
+ description: "Lifecycle test",
236
+ migrationSql:
237
+ "CREATE TABLE temp_cm_mig_lifecycle (id INTEGER PRIMARY KEY, val TEXT)",
238
+ rollbackSql: "DROP TABLE IF EXISTS temp_cm_mig_lifecycle",
239
+ });
240
+
241
+ // Verify
242
+ const status = await sqlite.migration.migrationStatus();
243
+ const history = await sqlite.migration.migrationHistory();
244
+ const tableExists = await sqlite.core.readQuery(
245
+ "SELECT name FROM sqlite_master WHERE name = 'temp_cm_mig_lifecycle'",
246
+ );
247
+
248
+ if (!tableExists.rows || tableExists.rows.length === 0)
249
+ failures.push("table not created after apply");
250
+
251
+ // Rollback
252
+ await sqlite.migration.migrationRollback({ version: "9.9.1" });
253
+ const afterRollback = await sqlite.core.readQuery(
254
+ "SELECT name FROM sqlite_master WHERE name = 'temp_cm_mig_lifecycle'",
255
+ );
256
+ if (afterRollback.rows && afterRollback.rows.length > 0)
257
+ failures.push("table still exists after rollback");
258
+
259
+ return {
260
+ failures,
261
+ success: failures.length === 0,
262
+ statusBefore: status,
263
+ historyEntries: history,
264
+ };
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Post-Test Procedures
270
+
271
+ 1. **⚠️ Explicit Cleanup**: Execute a final Code Mode script to `DROP TABLE IF EXISTS` all `temp_*` tables created during the test, as the active MCP server lock prevents the reset script from clearing them.
272
+ 2. **⚠️ Reset database**: Run `Set-Location C:\Users\chris\Desktop\db-mcp\test-server; .\reset-database.ps1` to re-seed the test database.
273
+ 3. **Triage findings**: Create implementation plan if issues found
274
+ 4. **Scope of fixes**: Handler code, server-instructions, this prompt
275
+ 5. **Validate**: Instruct the user to run the test suite (Vitest/Playwright), lint, and typecheck. Do NOT run them yourself.
276
+ 6. **Commit**: Stage and commit — do NOT push
277
+ 7. **Token audit**: Report most expensive block
278
+ 8. **Final summary**: After testing/re-testing
@@ -0,0 +1,413 @@
1
+ # db-mcp Code Mode Testing: [sandbox]
2
+
3
+ > [!IMPORTANT]
4
+ > **Do not track progress in this file.** Track your test progress, coverage matrix, and findings in your internal task tracking system (artifact). However, you SHOULD edit this file to fix any factual errors, broken code, or incorrect assertions in the test prompts.
5
+ > If there is nothing to fix, don't update UNRELEASED.md.
6
+ > We're currently testing Native mode.
7
+
8
+ **Step 1:** Read `C:\Users\chris\Desktop\db-mcp\src\constants\server-instructions\gotchas.md` using `view_file`.
9
+
10
+ **Step 2:** Conduct an exhaustive test of the **Code Mode sandbox** using ONLY `sqlite_execute_code`. Do not use direct tool calls or terminal.
11
+
12
+ **Step 3:** The agent should update C:\Users\chris\Desktop\db-mcp\UNRELEASED.md with any/all changes/fixes.
13
+
14
+ ## WASM Mode
15
+
16
+ > When testing against a **WASM backend** (`--sqlite` / sql.js), apply these adjustments:
17
+
18
+ - **Phase 2.1** (top-level help): Expect fewer than 10 groups — `transactions` is not listed (0 tools registered in WASM). `totalMethods` will be ~125 instead of ~151.
19
+ - **Phase 2.3** (all groups exist): The `transactions` group property exists on the `sqlite` object but returns 0 methods. Adjust the assertion to allow 0 methods for `transactions`.
20
+ - **Phase 4.5** (stats read-only): Stats tools are fully WASM-compatible — no adjustment needed.
21
+
22
+ ## Reporting Format
23
+
24
+ - ❌ Fail: Tool errors or produces incorrect results (include error message)
25
+ - ⚠️ Issue: Unexpected behavior or improvement opportunity
26
+ - 📦 Payload: Unnecessarily large response — **blocking, equally important as ❌ bugs**. You **MUST** monitor `metrics.tokenEstimate` for every operation. Report the response size in tokens/KB and suggest optimization.
27
+
28
+ ## Test Database Schema
29
+
30
+ | Table | Rows | Key Columns |
31
+ | ------------- | ---- | ------------------------------------------------------------------------------------------- |
32
+ | test_products | 16 | id, name, description, price (REAL), category (TEXT lowercase), created_at |
33
+ | test_orders | 20 | id, product_id (FK→test_products), customer_name, quantity, total_price, order_date, status |
34
+
35
+ > **Note:** This prompt tests the sandbox execution environment, not specific tool groups. It uses `test_products` and `test_orders` as representative tables for validation.
36
+
37
+ ## Testing Requirements
38
+
39
+ > [!CAUTION]
40
+ > **Zero tolerance for raw MCP errors.** Any response that is a raw MCP error (no `success` field) is a bug — report as ❌.
41
+
42
+ 1. **Error path testing**: Validate structured error responses for invalid inputs.
43
+ 2. **Token tracking**: Monitor `metrics.tokenEstimate` on every response. Report the most expensive block.
44
+ 3. **Deterministic checklist first**: Complete ALL numbered items before freeform exploration.
45
+ 4. **Code Over Docs**: Fix the handler code if standards (Structured Errors/Zod) are violated. Do NOT change docs/prompts to accommodate broken code.
46
+
47
+ ## Structured Error Response Pattern
48
+
49
+ ```json
50
+ { "success": false, "error": "Human-readable error message" }
51
+ ```
52
+
53
+ | Type | What you see | Verdict |
54
+ | -------------------- | --------------------------------------------- | ------- |
55
+ | **Handler error** ✅ | JSON object with `success` and `error` fields | Correct |
56
+ | **MCP error** ❌ | Raw text, `isError: true`, no `success` field | Bug |
57
+
58
+ ---
59
+
60
+ ## Phase 1: Sandbox Basics (9 tests)
61
+
62
+ > These tests validate the Code Mode sandbox itself — run them first.
63
+
64
+ ### 1.1 — Simple return value
65
+
66
+ ```javascript
67
+ return 42;
68
+ ```
69
+
70
+ Expected: `{success: true, result: 42}`
71
+
72
+ ### 1.2 — Object return
73
+
74
+ ```javascript
75
+ return { name: "test", values: [1, 2, 3] };
76
+ ```
77
+
78
+ ### 1.3 — Async/await support
79
+
80
+ ```javascript
81
+ const result = await Promise.resolve("async works");
82
+ return result;
83
+ ```
84
+
85
+ ### 1.4 — Runtime error handling
86
+
87
+ ```javascript
88
+ const x = undefinedVariable;
89
+ return x;
90
+ ```
91
+
92
+ Expected: `{success: false, error: "...not defined..."}` — structured, not crash.
93
+
94
+ ### 1.5 — Empty code
95
+
96
+ Call `sqlite_execute_code` with `code: ""`.
97
+ Expected: `{success: false}` with validation error, not raw MCP error.
98
+
99
+ ### 1.6 — Empty params
100
+
101
+ Call `sqlite_execute_code` with `{}` (no `code` param).
102
+ Expected: structured handler error, NOT raw MCP `-32602`.
103
+
104
+ ### 1.7 — Return null
105
+
106
+ ```javascript
107
+ return null;
108
+ ```
109
+
110
+ Expected: `{success: true, result: null}` — sandbox must handle null return values.
111
+
112
+ ### 1.8 — Return undefined
113
+
114
+ ```javascript
115
+ return undefined;
116
+ ```
117
+
118
+ Expected: `{success: true}` — sandbox must handle undefined without crashing. `result` may be absent or null.
119
+
120
+ ### 1.9 — Return large nested object
121
+
122
+ ```javascript
123
+ const nested = {};
124
+ let current = nested;
125
+ for (let i = 0; i < 10; i++) {
126
+ current.level = i;
127
+ current.child = {};
128
+ current = current.child;
129
+ }
130
+ current.leaf = "deep value";
131
+ return nested;
132
+ ```
133
+
134
+ Expected: `{success: true}` — sandbox must serialize deeply nested objects.
135
+
136
+ ---
137
+
138
+ ## Phase 2: API Discoverability (7 tests)
139
+
140
+ ### 2.1 — Top-level help
141
+
142
+ ```javascript
143
+ return await sqlite.help();
144
+ ```
145
+
146
+ Expected: `{groups: [...], totalMethods: <number>, usage: "..."}` with 10 groups listed (including transactions). **WASM**: Fewer groups — `transactions` is absent; `totalMethods` ≈ 125.
147
+
148
+ ### 2.2 — Group help (core)
149
+
150
+ ```javascript
151
+ return await sqlite.core.help();
152
+ ```
153
+
154
+ Expected: `{group: "core", methods: [...]}` with methods including `readQuery`, `writeQuery`, `listTables`, `describeTable`, `upsert`, `batchInsert`, `count`, `exists`, `truncate`.
155
+
156
+ ### 2.3 — All groups exist
157
+
158
+ ```javascript
159
+ const groups = [
160
+ "core",
161
+ "json",
162
+ "text",
163
+ "stats",
164
+ "vector",
165
+ "admin",
166
+ "transactions",
167
+ "geo",
168
+ "introspection",
169
+ "migration",
170
+ ];
171
+ const results = {};
172
+ for (const g of groups) {
173
+ const h = await sqlite[g].help();
174
+ results[g] = h.methods.length;
175
+ }
176
+ return results;
177
+ ```
178
+
179
+ Expected: All 10 groups return >0 methods. **WASM**: `transactions` returns 0 methods — adjust assertion to allow this.
180
+
181
+ ### 2.4 — Method aliases resolve
182
+
183
+ ```javascript
184
+ const r1 = await sqlite.core.query("SELECT 1 AS num");
185
+ const r2 = await sqlite.core.readQuery("SELECT 1 AS num");
186
+ return { aliasResult: r1, canonicalResult: r2 };
187
+ ```
188
+
189
+ Expected: Both return identical results.
190
+
191
+ ### 2.5 — Top-level convenience aliases
192
+
193
+ ```javascript
194
+ const tables = await sqlite.listTables();
195
+ return { success: true, tableCount: tables.tables?.length };
196
+ ```
197
+
198
+ ### 2.6 — Positional args
199
+
200
+ ```javascript
201
+ return await sqlite.core.readQuery("SELECT name FROM test_products LIMIT 2");
202
+ ```
203
+
204
+ Expected: Works with string positional arg (not just object).
205
+
206
+ ### 2.7 — Built-in tools not in sandbox
207
+
208
+ ```javascript
209
+ return {
210
+ serverInfo: typeof sqlite.serverInfo,
211
+ serverHealth: typeof sqlite.serverHealth,
212
+ listAdapters: typeof sqlite.listAdapters,
213
+ server_info: typeof sqlite.server_info,
214
+ server_health: typeof sqlite.server_health,
215
+ list_adapters: typeof sqlite.list_adapters,
216
+ };
217
+ ```
218
+
219
+ Expected: All values are `"undefined"`. The 3 built-in tools (`server_info`, `server_health`, `list_adapters`) are always-on MCP tools available outside Code Mode but must NOT be accessible in the `sqlite.*` sandbox namespace.
220
+
221
+ ---
222
+
223
+ ## Phase 3: Security & Error Handling (7 tests)
224
+
225
+ ### 3.1 — Blocked pattern (require)
226
+
227
+ ```javascript
228
+ const fs = require("fs");
229
+ return fs.readFileSync("/etc/passwd");
230
+ ```
231
+
232
+ Expected: `{success: false, code: "CODEMODE_VALIDATION_FAILED"}`
233
+
234
+ ### 3.2 — Blocked pattern (process)
235
+
236
+ ```javascript
237
+ return process.env;
238
+ ```
239
+
240
+ Expected: `{success: false}` — blocked pattern or runtime error.
241
+
242
+ ### 3.3 — Blocked pattern (eval)
243
+
244
+ ```javascript
245
+ return eval("1+1");
246
+ ```
247
+
248
+ Expected: `{success: false, code: "CODEMODE_VALIDATION_FAILED"}`
249
+
250
+ ### 3.4 — Timeout enforcement
251
+
252
+ ```javascript
253
+ while (true) {}
254
+ ```
255
+
256
+ Call with `timeout: 2000`. Expected: `{success: false}` with timeout error within ~2s.
257
+
258
+ ### 3.5 — Timeout enforcement (tight tolerance)
259
+
260
+ ```javascript
261
+ const start = Date.now();
262
+ while (Date.now() - start < 1000) {} // busy-wait 1s
263
+ return "completed";
264
+ ```
265
+
266
+ Call with `timeout: 500`. Expected: `{success: false}` with timeout error — the 500ms timeout must fire before the 1s loop completes.
267
+
268
+ ### 3.6 — Invalid tool call via API
269
+
270
+ ```javascript
271
+ return await sqlite.core.readQuery({ query: "SELECT * FROM nonexistent_xyz" });
272
+ ```
273
+
274
+ Expected: Returns `{success: false, error: "..."}` — sandbox must not crash.
275
+
276
+ ### 3.7 — Undefined API group
277
+
278
+ ```javascript
279
+ return await sqlite.nonexistent.help();
280
+ ```
281
+
282
+ Expected: runtime error, not crash.
283
+
284
+ ---
285
+
286
+ ## Phase 4: Readonly Mode (5 tests)
287
+
288
+ All tests use `readonly: true` on the `sqlite_execute_code` call.
289
+
290
+ ### 4.1 — Read operations work
291
+
292
+ ```javascript
293
+ // readonly: true
294
+ return await sqlite.core.readQuery("SELECT COUNT(*) AS cnt FROM test_products");
295
+ ```
296
+
297
+ Expected: `{success: true, rows: [{cnt: 16}]}`
298
+
299
+ ### 4.2 — Write operations blocked
300
+
301
+ ```javascript
302
+ // readonly: true
303
+ return await sqlite.core.writeQuery(
304
+ "INSERT INTO test_products (name) VALUES ('blocked')",
305
+ );
306
+ ```
307
+
308
+ Expected: `{success: false, code: "CODEMODE_READONLY_VIOLATION"}`
309
+
310
+ ### 4.3 — Read methods still discoverable
311
+
312
+ ```javascript
313
+ // readonly: true
314
+ const help = await sqlite.core.help();
315
+ return {
316
+ hasWriteQuery: help.methods.includes("writeQuery"),
317
+ methods: help.methods,
318
+ };
319
+ ```
320
+
321
+ Expected: `writeQuery` still appears in help (for discoverability) but is guarded.
322
+
323
+ ### 4.4 — Create table blocked
324
+
325
+ ```javascript
326
+ // readonly: true
327
+ return await sqlite.core.writeQuery(
328
+ "CREATE TABLE temp_readonly_test (id INTEGER)",
329
+ );
330
+ ```
331
+
332
+ Expected: `{success: false, code: "CODEMODE_READONLY_VIOLATION"}`
333
+
334
+ ### 4.5 — Stats read-only works
335
+
336
+ ```javascript
337
+ // readonly: true
338
+ return await sqlite.stats.statsBasic({
339
+ table: "test_products",
340
+ column: "price",
341
+ });
342
+ ```
343
+
344
+ Expected: succeeds — stats tools are read-only.
345
+
346
+ ---
347
+
348
+ ## Phase 5: State Isolation (2 tests)
349
+
350
+ ### 5.1 — Variables don't persist between calls
351
+
352
+ Run two separate `sqlite_execute_code` calls:
353
+
354
+ **Call 1:**
355
+
356
+ ```javascript
357
+ var persistTest = "should not persist";
358
+ return persistTest;
359
+ ```
360
+
361
+ **Call 2:**
362
+
363
+ ```javascript
364
+ try {
365
+ return { persisted: typeof persistTest !== "undefined", value: persistTest };
366
+ } catch (e) {
367
+ return { persisted: false, error: e.message };
368
+ }
369
+ ```
370
+
371
+ Expected: Call 2 returns `{persisted: false}` — variables from Call 1 must not leak.
372
+
373
+ ### 5.2 — Database state persists between calls
374
+
375
+ Run two separate `sqlite_execute_code` calls:
376
+
377
+ **Call 1:**
378
+
379
+ ```javascript
380
+ await sqlite.core.createTable({
381
+ table: "temp_cm_iso_test",
382
+ columns: [
383
+ { name: "id", type: "INTEGER", primaryKey: true },
384
+ { name: "val", type: "TEXT" },
385
+ ],
386
+ });
387
+ await sqlite.core.writeQuery(
388
+ "INSERT INTO temp_cm_iso_test VALUES (1, 'persisted')",
389
+ );
390
+ return "created";
391
+ ```
392
+
393
+ **Call 2:**
394
+
395
+ ```javascript
396
+ const result = await sqlite.core.readQuery("SELECT * FROM temp_cm_iso_test");
397
+ await sqlite.core.dropTable({ table: "temp_cm_iso_test", ifExists: true });
398
+ return result;
399
+ ```
400
+
401
+ Expected: Call 2 reads the row inserted in Call 1 — database state persists across sandbox invocations (sandbox is stateless, database is not).
402
+
403
+ ---
404
+
405
+ ## Post-Test Procedures
406
+
407
+ 1. **Cleanup**: Confirm all `temp_*` tables are removed
408
+ 2. **Triage findings**: Create implementation plan if issues found
409
+ 3. **Scope of fixes**: Handler code, server-instructions, this prompt
410
+ 4. **Validate**: Instruct the user to run the test suite (Vitest/Playwright), lint, and typecheck. Do NOT run them yourself.
411
+ 5. **Commit**: Stage and commit — do NOT push
412
+ 6. **Token audit**: Report `metrics.tokenEstimate` for the most expensive block
413
+ 7. **Final summary**: After testing/re-testing