db-mcp 1.1.1 → 3.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 (508) hide show
  1. package/README.md +247 -169
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/adapters/database-adapter.d.ts +173 -0
  4. package/dist/adapters/database-adapter.d.ts.map +1 -0
  5. package/dist/adapters/query-validation.d.ts +20 -0
  6. package/dist/adapters/query-validation.d.ts.map +1 -0
  7. package/dist/adapters/registration/index.d.ts +4 -0
  8. package/dist/adapters/registration/index.d.ts.map +1 -0
  9. package/dist/adapters/registration/prompts.d.ts +7 -0
  10. package/dist/adapters/registration/prompts.d.ts.map +1 -0
  11. package/dist/adapters/registration/resources.d.ts +7 -0
  12. package/dist/adapters/registration/resources.d.ts.map +1 -0
  13. package/dist/adapters/registration/tools.d.ts +9 -0
  14. package/dist/adapters/registration/tools.d.ts.map +1 -0
  15. package/dist/adapters/sqlite/index.d.ts +9 -0
  16. package/dist/adapters/sqlite/index.d.ts.map +1 -0
  17. package/dist/adapters/sqlite/json-utils.d.ts +100 -0
  18. package/dist/adapters/sqlite/json-utils.d.ts.map +1 -0
  19. package/dist/adapters/sqlite/prompts/analysis.d.ts +23 -0
  20. package/dist/adapters/sqlite/prompts/analysis.d.ts.map +1 -0
  21. package/dist/adapters/sqlite/prompts/index.d.ts +16 -0
  22. package/dist/adapters/sqlite/prompts/index.d.ts.map +1 -0
  23. package/dist/adapters/sqlite/prompts/query.d.ts +19 -0
  24. package/dist/adapters/sqlite/prompts/query.d.ts.map +1 -0
  25. package/dist/adapters/sqlite/prompts/schema.d.ts +20 -0
  26. package/dist/adapters/sqlite/prompts/schema.d.ts.map +1 -0
  27. package/dist/adapters/sqlite/query-executor.d.ts +38 -0
  28. package/dist/adapters/sqlite/query-executor.d.ts.map +1 -0
  29. package/dist/adapters/sqlite/resources.d.ts +13 -0
  30. package/dist/adapters/sqlite/resources.d.ts.map +1 -0
  31. package/dist/adapters/sqlite/schema-manager.d.ts +69 -0
  32. package/dist/adapters/sqlite/schema-manager.d.ts.map +1 -0
  33. package/dist/adapters/sqlite/schemas/admin.d.ts +459 -0
  34. package/dist/adapters/sqlite/schemas/admin.d.ts.map +1 -0
  35. package/dist/adapters/sqlite/schemas/codemode.d.ts +30 -0
  36. package/dist/adapters/sqlite/schemas/codemode.d.ts.map +1 -0
  37. package/dist/adapters/sqlite/schemas/common.d.ts +9 -0
  38. package/dist/adapters/sqlite/schemas/common.d.ts.map +1 -0
  39. package/dist/adapters/sqlite/schemas/core.d.ts +530 -0
  40. package/dist/adapters/sqlite/schemas/core.d.ts.map +1 -0
  41. package/dist/adapters/sqlite/schemas/error-mixin.d.ts +10 -0
  42. package/dist/adapters/sqlite/schemas/error-mixin.d.ts.map +1 -0
  43. package/dist/adapters/sqlite/schemas/fts.d.ts +106 -0
  44. package/dist/adapters/sqlite/schemas/fts.d.ts.map +1 -0
  45. package/dist/adapters/sqlite/schemas/geo.d.ts +135 -0
  46. package/dist/adapters/sqlite/schemas/geo.d.ts.map +1 -0
  47. package/dist/adapters/sqlite/schemas/index.d.ts +23 -0
  48. package/dist/adapters/sqlite/schemas/index.d.ts.map +1 -0
  49. package/dist/adapters/sqlite/schemas/introspection.d.ts +583 -0
  50. package/dist/adapters/sqlite/schemas/introspection.d.ts.map +1 -0
  51. package/dist/adapters/sqlite/schemas/json.d.ts +849 -0
  52. package/dist/adapters/sqlite/schemas/json.d.ts.map +1 -0
  53. package/dist/adapters/sqlite/schemas/migration.d.ts +220 -0
  54. package/dist/adapters/sqlite/schemas/migration.d.ts.map +1 -0
  55. package/dist/adapters/sqlite/schemas/native.d.ts +235 -0
  56. package/dist/adapters/sqlite/schemas/native.d.ts.map +1 -0
  57. package/dist/adapters/sqlite/schemas/server.d.ts +13 -0
  58. package/dist/adapters/sqlite/schemas/server.d.ts.map +1 -0
  59. package/dist/adapters/sqlite/schemas/spatialite.d.ts +114 -0
  60. package/dist/adapters/sqlite/schemas/spatialite.d.ts.map +1 -0
  61. package/dist/adapters/sqlite/schemas/stats.d.ts +780 -0
  62. package/dist/adapters/sqlite/schemas/stats.d.ts.map +1 -0
  63. package/dist/adapters/sqlite/schemas/text.d.ts +570 -0
  64. package/dist/adapters/sqlite/schemas/text.d.ts.map +1 -0
  65. package/dist/adapters/sqlite/schemas/vector.d.ts +252 -0
  66. package/dist/adapters/sqlite/schemas/vector.d.ts.map +1 -0
  67. package/dist/adapters/sqlite/schemas/virtual.d.ts +257 -0
  68. package/dist/adapters/sqlite/schemas/virtual.d.ts.map +1 -0
  69. package/dist/adapters/sqlite/schemas/where.d.ts +20 -0
  70. package/dist/adapters/sqlite/schemas/where.d.ts.map +1 -0
  71. package/dist/adapters/sqlite/sqlite-adapter/lifecycle.d.ts +13 -0
  72. package/dist/adapters/sqlite/sqlite-adapter/lifecycle.d.ts.map +1 -0
  73. package/dist/adapters/sqlite/sqlite-adapter/schema.d.ts +7 -0
  74. package/dist/adapters/sqlite/sqlite-adapter/schema.d.ts.map +1 -0
  75. package/dist/adapters/sqlite/sqlite-adapter.d.ts +138 -0
  76. package/dist/adapters/sqlite/sqlite-adapter.d.ts.map +1 -0
  77. package/dist/adapters/sqlite/tools/admin/backup/analyze.d.ts +7 -0
  78. package/dist/adapters/sqlite/tools/admin/backup/analyze.d.ts.map +1 -0
  79. package/dist/adapters/sqlite/tools/admin/backup/create.d.ts +11 -0
  80. package/dist/adapters/sqlite/tools/admin/backup/create.d.ts.map +1 -0
  81. package/dist/adapters/sqlite/tools/admin/backup/dump.d.ts +7 -0
  82. package/dist/adapters/sqlite/tools/admin/backup/dump.d.ts.map +1 -0
  83. package/dist/adapters/sqlite/tools/admin/backup/index.d.ts +7 -0
  84. package/dist/adapters/sqlite/tools/admin/backup/index.d.ts.map +1 -0
  85. package/dist/adapters/sqlite/tools/admin/backup/integrity.d.ts +7 -0
  86. package/dist/adapters/sqlite/tools/admin/backup/integrity.d.ts.map +1 -0
  87. package/dist/adapters/sqlite/tools/admin/backup/optimize.d.ts +7 -0
  88. package/dist/adapters/sqlite/tools/admin/backup/optimize.d.ts.map +1 -0
  89. package/dist/adapters/sqlite/tools/admin/backup/restore.d.ts +7 -0
  90. package/dist/adapters/sqlite/tools/admin/backup/restore.d.ts.map +1 -0
  91. package/dist/adapters/sqlite/tools/admin/helpers.d.ts +18 -0
  92. package/dist/adapters/sqlite/tools/admin/helpers.d.ts.map +1 -0
  93. package/dist/adapters/sqlite/tools/admin/index.d.ts +10 -0
  94. package/dist/adapters/sqlite/tools/admin/index.d.ts.map +1 -0
  95. package/dist/adapters/sqlite/tools/admin/pragma.d.ts +37 -0
  96. package/dist/adapters/sqlite/tools/admin/pragma.d.ts.map +1 -0
  97. package/dist/adapters/sqlite/tools/admin/reindex.d.ts +10 -0
  98. package/dist/adapters/sqlite/tools/admin/reindex.d.ts.map +1 -0
  99. package/dist/adapters/sqlite/tools/admin/verify.d.ts +13 -0
  100. package/dist/adapters/sqlite/tools/admin/verify.d.ts.map +1 -0
  101. package/dist/adapters/sqlite/tools/admin/wal.d.ts +10 -0
  102. package/dist/adapters/sqlite/tools/admin/wal.d.ts.map +1 -0
  103. package/dist/adapters/sqlite/tools/codemode.d.ts +22 -0
  104. package/dist/adapters/sqlite/tools/codemode.d.ts.map +1 -0
  105. package/dist/adapters/sqlite/tools/column-validation.d.ts +26 -0
  106. package/dist/adapters/sqlite/tools/column-validation.d.ts.map +1 -0
  107. package/dist/adapters/sqlite/tools/core/alter-table.d.ts +11 -0
  108. package/dist/adapters/sqlite/tools/core/alter-table.d.ts.map +1 -0
  109. package/dist/adapters/sqlite/tools/core/constraints.d.ts +10 -0
  110. package/dist/adapters/sqlite/tools/core/constraints.d.ts.map +1 -0
  111. package/dist/adapters/sqlite/tools/core/convenience-helpers.d.ts +20 -0
  112. package/dist/adapters/sqlite/tools/core/convenience-helpers.d.ts.map +1 -0
  113. package/dist/adapters/sqlite/tools/core/convenience-schemas.d.ts +20 -0
  114. package/dist/adapters/sqlite/tools/core/convenience-schemas.d.ts.map +1 -0
  115. package/dist/adapters/sqlite/tools/core/convenience.d.ts +29 -0
  116. package/dist/adapters/sqlite/tools/core/convenience.d.ts.map +1 -0
  117. package/dist/adapters/sqlite/tools/core/datetime.d.ts +11 -0
  118. package/dist/adapters/sqlite/tools/core/datetime.d.ts.map +1 -0
  119. package/dist/adapters/sqlite/tools/core/index.d.ts +14 -0
  120. package/dist/adapters/sqlite/tools/core/index.d.ts.map +1 -0
  121. package/dist/adapters/sqlite/tools/core/indexes.d.ts +20 -0
  122. package/dist/adapters/sqlite/tools/core/indexes.d.ts.map +1 -0
  123. package/dist/adapters/sqlite/tools/core/queries.d.ts +16 -0
  124. package/dist/adapters/sqlite/tools/core/queries.d.ts.map +1 -0
  125. package/dist/adapters/sqlite/tools/core/tables.d.ts +37 -0
  126. package/dist/adapters/sqlite/tools/core/tables.d.ts.map +1 -0
  127. package/dist/adapters/sqlite/tools/core/triggers.d.ts +18 -0
  128. package/dist/adapters/sqlite/tools/core/triggers.d.ts.map +1 -0
  129. package/dist/adapters/sqlite/tools/fts.d.ts +13 -0
  130. package/dist/adapters/sqlite/tools/fts.d.ts.map +1 -0
  131. package/dist/adapters/sqlite/tools/geo.d.ts +14 -0
  132. package/dist/adapters/sqlite/tools/geo.d.ts.map +1 -0
  133. package/dist/adapters/sqlite/tools/index.d.ts +33 -0
  134. package/dist/adapters/sqlite/tools/index.d.ts.map +1 -0
  135. package/dist/adapters/sqlite/tools/introspection/analysis/constraints.d.ts +10 -0
  136. package/dist/adapters/sqlite/tools/introspection/analysis/constraints.d.ts.map +1 -0
  137. package/dist/adapters/sqlite/tools/introspection/analysis/diff.d.ts +11 -0
  138. package/dist/adapters/sqlite/tools/introspection/analysis/diff.d.ts.map +1 -0
  139. package/dist/adapters/sqlite/tools/introspection/analysis/index.d.ts +10 -0
  140. package/dist/adapters/sqlite/tools/introspection/analysis/index.d.ts.map +1 -0
  141. package/dist/adapters/sqlite/tools/introspection/analysis/risks.d.ts +9 -0
  142. package/dist/adapters/sqlite/tools/introspection/analysis/risks.d.ts.map +1 -0
  143. package/dist/adapters/sqlite/tools/introspection/analysis/snapshot.d.ts +40 -0
  144. package/dist/adapters/sqlite/tools/introspection/analysis/snapshot.d.ts.map +1 -0
  145. package/dist/adapters/sqlite/tools/introspection/diagnostics/index.d.ts +9 -0
  146. package/dist/adapters/sqlite/tools/introspection/diagnostics/index.d.ts.map +1 -0
  147. package/dist/adapters/sqlite/tools/introspection/diagnostics/indexes.d.ts +10 -0
  148. package/dist/adapters/sqlite/tools/introspection/diagnostics/indexes.d.ts.map +1 -0
  149. package/dist/adapters/sqlite/tools/introspection/diagnostics/query-plan.d.ts +10 -0
  150. package/dist/adapters/sqlite/tools/introspection/diagnostics/query-plan.d.ts.map +1 -0
  151. package/dist/adapters/sqlite/tools/introspection/diagnostics/storage.d.ts +10 -0
  152. package/dist/adapters/sqlite/tools/introspection/diagnostics/storage.d.ts.map +1 -0
  153. package/dist/adapters/sqlite/tools/introspection/graph/helpers.d.ts +44 -0
  154. package/dist/adapters/sqlite/tools/introspection/graph/helpers.d.ts.map +1 -0
  155. package/dist/adapters/sqlite/tools/introspection/graph/index.d.ts +9 -0
  156. package/dist/adapters/sqlite/tools/introspection/graph/index.d.ts.map +1 -0
  157. package/dist/adapters/sqlite/tools/introspection/graph/tools.d.ts +12 -0
  158. package/dist/adapters/sqlite/tools/introspection/graph/tools.d.ts.map +1 -0
  159. package/dist/adapters/sqlite/tools/introspection/index.d.ts +17 -0
  160. package/dist/adapters/sqlite/tools/introspection/index.d.ts.map +1 -0
  161. package/dist/adapters/sqlite/tools/json-helpers/helpers.d.ts +21 -0
  162. package/dist/adapters/sqlite/tools/json-helpers/helpers.d.ts.map +1 -0
  163. package/dist/adapters/sqlite/tools/json-helpers/index.d.ts +17 -0
  164. package/dist/adapters/sqlite/tools/json-helpers/index.d.ts.map +1 -0
  165. package/dist/adapters/sqlite/tools/json-helpers/read.d.ts +24 -0
  166. package/dist/adapters/sqlite/tools/json-helpers/read.d.ts.map +1 -0
  167. package/dist/adapters/sqlite/tools/json-helpers/write.d.ts +24 -0
  168. package/dist/adapters/sqlite/tools/json-helpers/write.d.ts.map +1 -0
  169. package/dist/adapters/sqlite/tools/json-operations/crud.d.ts +39 -0
  170. package/dist/adapters/sqlite/tools/json-operations/crud.d.ts.map +1 -0
  171. package/dist/adapters/sqlite/tools/json-operations/diff.d.ts +11 -0
  172. package/dist/adapters/sqlite/tools/json-operations/diff.d.ts.map +1 -0
  173. package/dist/adapters/sqlite/tools/json-operations/helpers.d.ts +18 -0
  174. package/dist/adapters/sqlite/tools/json-operations/helpers.d.ts.map +1 -0
  175. package/dist/adapters/sqlite/tools/json-operations/index.d.ts +10 -0
  176. package/dist/adapters/sqlite/tools/json-operations/index.d.ts.map +1 -0
  177. package/dist/adapters/sqlite/tools/json-operations/query.d.ts +24 -0
  178. package/dist/adapters/sqlite/tools/json-operations/query.d.ts.map +1 -0
  179. package/dist/adapters/sqlite/tools/json-operations/security.d.ts +19 -0
  180. package/dist/adapters/sqlite/tools/json-operations/security.d.ts.map +1 -0
  181. package/dist/adapters/sqlite/tools/json-operations/transform.d.ts +24 -0
  182. package/dist/adapters/sqlite/tools/json-operations/transform.d.ts.map +1 -0
  183. package/dist/adapters/sqlite/tools/migration/helpers.d.ts +34 -0
  184. package/dist/adapters/sqlite/tools/migration/helpers.d.ts.map +1 -0
  185. package/dist/adapters/sqlite/tools/migration/index.d.ts +15 -0
  186. package/dist/adapters/sqlite/tools/migration/index.d.ts.map +1 -0
  187. package/dist/adapters/sqlite/tools/migration/tracking/apply.d.ts +4 -0
  188. package/dist/adapters/sqlite/tools/migration/tracking/apply.d.ts.map +1 -0
  189. package/dist/adapters/sqlite/tools/migration/tracking/history.d.ts +4 -0
  190. package/dist/adapters/sqlite/tools/migration/tracking/history.d.ts.map +1 -0
  191. package/dist/adapters/sqlite/tools/migration/tracking/index.d.ts +7 -0
  192. package/dist/adapters/sqlite/tools/migration/tracking/index.d.ts.map +1 -0
  193. package/dist/adapters/sqlite/tools/migration/tracking/init.d.ts +4 -0
  194. package/dist/adapters/sqlite/tools/migration/tracking/init.d.ts.map +1 -0
  195. package/dist/adapters/sqlite/tools/migration/tracking/record.d.ts +4 -0
  196. package/dist/adapters/sqlite/tools/migration/tracking/record.d.ts.map +1 -0
  197. package/dist/adapters/sqlite/tools/migration/tracking/rollback.d.ts +4 -0
  198. package/dist/adapters/sqlite/tools/migration/tracking/rollback.d.ts.map +1 -0
  199. package/dist/adapters/sqlite/tools/migration/tracking/status.d.ts +4 -0
  200. package/dist/adapters/sqlite/tools/migration/tracking/status.d.ts.map +1 -0
  201. package/dist/adapters/sqlite/tools/stats/advanced.d.ts +28 -0
  202. package/dist/adapters/sqlite/tools/stats/advanced.d.ts.map +1 -0
  203. package/dist/adapters/sqlite/tools/stats/anomaly-detection.d.ts +22 -0
  204. package/dist/adapters/sqlite/tools/stats/anomaly-detection.d.ts.map +1 -0
  205. package/dist/adapters/sqlite/tools/stats/basic.d.ts +32 -0
  206. package/dist/adapters/sqlite/tools/stats/basic.d.ts.map +1 -0
  207. package/dist/adapters/sqlite/tools/stats/helpers.d.ts +27 -0
  208. package/dist/adapters/sqlite/tools/stats/helpers.d.ts.map +1 -0
  209. package/dist/adapters/sqlite/tools/stats/index.d.ts +12 -0
  210. package/dist/adapters/sqlite/tools/stats/index.d.ts.map +1 -0
  211. package/dist/adapters/sqlite/tools/stats/inference/hypothesis.d.ts +7 -0
  212. package/dist/adapters/sqlite/tools/stats/inference/hypothesis.d.ts.map +1 -0
  213. package/dist/adapters/sqlite/tools/stats/inference/index.d.ts +4 -0
  214. package/dist/adapters/sqlite/tools/stats/inference/index.d.ts.map +1 -0
  215. package/dist/adapters/sqlite/tools/stats/inference/outlier.d.ts +7 -0
  216. package/dist/adapters/sqlite/tools/stats/inference/outlier.d.ts.map +1 -0
  217. package/dist/adapters/sqlite/tools/stats/inference/regression.d.ts +7 -0
  218. package/dist/adapters/sqlite/tools/stats/inference/regression.d.ts.map +1 -0
  219. package/dist/adapters/sqlite/tools/stats/math-helpers.d.ts +17 -0
  220. package/dist/adapters/sqlite/tools/stats/math-helpers.d.ts.map +1 -0
  221. package/dist/adapters/sqlite/tools/stats/schema-risks.d.ts +15 -0
  222. package/dist/adapters/sqlite/tools/stats/schema-risks.d.ts.map +1 -0
  223. package/dist/adapters/sqlite/tools/text/formatting.d.ts +48 -0
  224. package/dist/adapters/sqlite/tools/text/formatting.d.ts.map +1 -0
  225. package/dist/adapters/sqlite/tools/text/helpers.d.ts +22 -0
  226. package/dist/adapters/sqlite/tools/text/helpers.d.ts.map +1 -0
  227. package/dist/adapters/sqlite/tools/text/index.d.ts +10 -0
  228. package/dist/adapters/sqlite/tools/text/index.d.ts.map +1 -0
  229. package/dist/adapters/sqlite/tools/text/regex.d.ts +21 -0
  230. package/dist/adapters/sqlite/tools/text/regex.d.ts.map +1 -0
  231. package/dist/adapters/sqlite/tools/text/search.d.ts +17 -0
  232. package/dist/adapters/sqlite/tools/text/search.d.ts.map +1 -0
  233. package/dist/adapters/sqlite/tools/text/sentiment.d.ts +13 -0
  234. package/dist/adapters/sqlite/tools/text/sentiment.d.ts.map +1 -0
  235. package/dist/adapters/sqlite/tools/text/validate.d.ts +11 -0
  236. package/dist/adapters/sqlite/tools/text/validate.d.ts.map +1 -0
  237. package/dist/adapters/sqlite/tools/vector/helpers.d.ts +11 -0
  238. package/dist/adapters/sqlite/tools/vector/helpers.d.ts.map +1 -0
  239. package/dist/adapters/sqlite/tools/vector/index.d.ts +14 -0
  240. package/dist/adapters/sqlite/tools/vector/index.d.ts.map +1 -0
  241. package/dist/adapters/sqlite/tools/vector/metadata.d.ts +28 -0
  242. package/dist/adapters/sqlite/tools/vector/metadata.d.ts.map +1 -0
  243. package/dist/adapters/sqlite/tools/vector/search.d.ts +16 -0
  244. package/dist/adapters/sqlite/tools/vector/search.d.ts.map +1 -0
  245. package/dist/adapters/sqlite/tools/vector/storage.d.ts +24 -0
  246. package/dist/adapters/sqlite/tools/vector/storage.d.ts.map +1 -0
  247. package/dist/adapters/sqlite/tools/vector/tools.d.ts +9 -0
  248. package/dist/adapters/sqlite/tools/vector/tools.d.ts.map +1 -0
  249. package/dist/adapters/sqlite/tools/virtual/analysis.d.ts +24 -0
  250. package/dist/adapters/sqlite/tools/virtual/analysis.d.ts.map +1 -0
  251. package/dist/adapters/sqlite/tools/virtual/extensions.d.ts +13 -0
  252. package/dist/adapters/sqlite/tools/virtual/extensions.d.ts.map +1 -0
  253. package/dist/adapters/sqlite/tools/virtual/helpers.d.ts +18 -0
  254. package/dist/adapters/sqlite/tools/virtual/helpers.d.ts.map +1 -0
  255. package/dist/adapters/sqlite/tools/virtual/index.d.ts +10 -0
  256. package/dist/adapters/sqlite/tools/virtual/index.d.ts.map +1 -0
  257. package/dist/adapters/sqlite/tools/virtual/views.d.ts +21 -0
  258. package/dist/adapters/sqlite/tools/virtual/views.d.ts.map +1 -0
  259. package/dist/adapters/sqlite/tools/virtual/vtable/analyze-csv.d.ts +4 -0
  260. package/dist/adapters/sqlite/tools/virtual/vtable/analyze-csv.d.ts.map +1 -0
  261. package/dist/adapters/sqlite/tools/virtual/vtable/csv.d.ts +4 -0
  262. package/dist/adapters/sqlite/tools/virtual/vtable/csv.d.ts.map +1 -0
  263. package/dist/adapters/sqlite/tools/virtual/vtable/drop.d.ts +4 -0
  264. package/dist/adapters/sqlite/tools/virtual/vtable/drop.d.ts.map +1 -0
  265. package/dist/adapters/sqlite/tools/virtual/vtable/index.d.ts +6 -0
  266. package/dist/adapters/sqlite/tools/virtual/vtable/index.d.ts.map +1 -0
  267. package/dist/adapters/sqlite/tools/virtual/vtable/info.d.ts +4 -0
  268. package/dist/adapters/sqlite/tools/virtual/vtable/info.d.ts.map +1 -0
  269. package/dist/adapters/sqlite/tools/virtual/vtable/list.d.ts +4 -0
  270. package/dist/adapters/sqlite/tools/virtual/vtable/list.d.ts.map +1 -0
  271. package/dist/adapters/sqlite/types.d.ts +89 -0
  272. package/dist/adapters/sqlite/types.d.ts.map +1 -0
  273. package/dist/adapters/sqlite-helpers.d.ts +51 -0
  274. package/dist/adapters/sqlite-helpers.d.ts.map +1 -0
  275. package/dist/adapters/sqlite-native/extensions.d.ts +17 -0
  276. package/dist/adapters/sqlite-native/extensions.d.ts.map +1 -0
  277. package/dist/adapters/sqlite-native/index.d.ts +11 -0
  278. package/dist/adapters/sqlite-native/index.d.ts.map +1 -0
  279. package/dist/adapters/sqlite-native/native-query-executor.d.ts +24 -0
  280. package/dist/adapters/sqlite-native/native-query-executor.d.ts.map +1 -0
  281. package/dist/adapters/sqlite-native/native-sqlite-adapter.d.ts +160 -0
  282. package/dist/adapters/sqlite-native/native-sqlite-adapter.d.ts.map +1 -0
  283. package/dist/adapters/sqlite-native/registration/index.d.ts +12 -0
  284. package/dist/adapters/sqlite-native/registration/index.d.ts.map +1 -0
  285. package/dist/adapters/sqlite-native/tools/spatialite/analysis.d.ts +23 -0
  286. package/dist/adapters/sqlite-native/tools/spatialite/analysis.d.ts.map +1 -0
  287. package/dist/adapters/sqlite-native/tools/spatialite/index.d.ts +15 -0
  288. package/dist/adapters/sqlite-native/tools/spatialite/index.d.ts.map +1 -0
  289. package/dist/adapters/sqlite-native/tools/spatialite/loader.d.ts +22 -0
  290. package/dist/adapters/sqlite-native/tools/spatialite/loader.d.ts.map +1 -0
  291. package/dist/adapters/sqlite-native/tools/spatialite/schemas.d.ts +78 -0
  292. package/dist/adapters/sqlite-native/tools/spatialite/schemas.d.ts.map +1 -0
  293. package/dist/adapters/sqlite-native/tools/spatialite/tools.d.ts +30 -0
  294. package/dist/adapters/sqlite-native/tools/spatialite/tools.d.ts.map +1 -0
  295. package/dist/adapters/sqlite-native/tools/transactions.d.ts +12 -0
  296. package/dist/adapters/sqlite-native/tools/transactions.d.ts.map +1 -0
  297. package/dist/adapters/sqlite-native/tools/window.d.ts +7 -0
  298. package/dist/adapters/sqlite-native/tools/window.d.ts.map +1 -0
  299. package/dist/adapters/sqlite-native/transaction-methods.d.ts +36 -0
  300. package/dist/adapters/sqlite-native/transaction-methods.d.ts.map +1 -0
  301. package/dist/audit/backup-manager.d.ts +90 -0
  302. package/dist/audit/backup-manager.d.ts.map +1 -0
  303. package/dist/audit/index.d.ts +11 -0
  304. package/dist/audit/index.d.ts.map +1 -0
  305. package/dist/audit/interceptor.d.ts +54 -0
  306. package/dist/audit/interceptor.d.ts.map +1 -0
  307. package/dist/audit/logger.d.ts +62 -0
  308. package/dist/audit/logger.d.ts.map +1 -0
  309. package/dist/audit/types.d.ts +112 -0
  310. package/dist/audit/types.d.ts.map +1 -0
  311. package/dist/auth/auth-context.d.ts +28 -0
  312. package/dist/auth/auth-context.d.ts.map +1 -0
  313. package/dist/auth/authorization-server-discovery.d.ts +90 -0
  314. package/dist/auth/authorization-server-discovery.d.ts.map +1 -0
  315. package/dist/auth/errors.d.ts +74 -0
  316. package/dist/auth/errors.d.ts.map +1 -0
  317. package/dist/auth/middleware/core.d.ts +22 -0
  318. package/dist/auth/middleware/core.d.ts.map +1 -0
  319. package/dist/auth/middleware/express-auth.d.ts +13 -0
  320. package/dist/auth/middleware/express-auth.d.ts.map +1 -0
  321. package/dist/auth/middleware/express-scopes.d.ts +6 -0
  322. package/dist/auth/middleware/express-scopes.d.ts.map +1 -0
  323. package/dist/auth/middleware/extraction.d.ts +2 -0
  324. package/dist/auth/middleware/extraction.d.ts.map +1 -0
  325. package/dist/auth/middleware/index.d.ts +5 -0
  326. package/dist/auth/middleware/index.d.ts.map +1 -0
  327. package/dist/auth/oauth-resource-server.d.ts +74 -0
  328. package/dist/auth/oauth-resource-server.d.ts.map +1 -0
  329. package/dist/auth/scope-map.d.ts +24 -0
  330. package/dist/auth/scope-map.d.ts.map +1 -0
  331. package/dist/auth/scopes/constants.d.ts +40 -0
  332. package/dist/auth/scopes/constants.d.ts.map +1 -0
  333. package/dist/auth/scopes/display.d.ts +5 -0
  334. package/dist/auth/scopes/display.d.ts.map +1 -0
  335. package/dist/auth/scopes/enforcement.d.ts +27 -0
  336. package/dist/auth/scopes/enforcement.d.ts.map +1 -0
  337. package/dist/auth/scopes/index.d.ts +6 -0
  338. package/dist/auth/scopes/index.d.ts.map +1 -0
  339. package/dist/auth/scopes/mapping.d.ts +39 -0
  340. package/dist/auth/scopes/mapping.d.ts.map +1 -0
  341. package/dist/auth/scopes/validation.d.ts +27 -0
  342. package/dist/auth/scopes/validation.d.ts.map +1 -0
  343. package/dist/auth/token-validator.d.ts +63 -0
  344. package/dist/auth/token-validator.d.ts.map +1 -0
  345. package/dist/auth/transport-agnostic.d.ts +11 -0
  346. package/dist/auth/transport-agnostic.d.ts.map +1 -0
  347. package/dist/auth/types.d.ts +257 -0
  348. package/dist/auth/types.d.ts.map +1 -0
  349. package/dist/chunk-E5IESRTK.js +489 -0
  350. package/dist/{chunk-TVIZ3XJH.js → chunk-FR65YPAH.js} +8509 -3925
  351. package/dist/{chunk-AOUL5SHS.js → chunk-L552U3QS.js} +880 -252
  352. package/dist/chunk-THATOQRT.js +2624 -0
  353. package/dist/chunk-W5WQVNVX.js +568 -0
  354. package/dist/cli.d.ts +7 -0
  355. package/dist/cli.d.ts.map +1 -0
  356. package/dist/cli.js +114 -19
  357. package/dist/codemode/api-constants.d.ts +40 -0
  358. package/dist/codemode/api-constants.d.ts.map +1 -0
  359. package/dist/codemode/api.d.ts +70 -0
  360. package/dist/codemode/api.d.ts.map +1 -0
  361. package/dist/codemode/auto-return.d.ts +25 -0
  362. package/dist/codemode/auto-return.d.ts.map +1 -0
  363. package/dist/codemode/index.d.ts +12 -0
  364. package/dist/codemode/index.d.ts.map +1 -0
  365. package/dist/codemode/sandbox-factory.d.ts +72 -0
  366. package/dist/codemode/sandbox-factory.d.ts.map +1 -0
  367. package/dist/codemode/sandbox.d.ts +54 -0
  368. package/dist/codemode/sandbox.d.ts.map +1 -0
  369. package/dist/codemode/security.d.ts +45 -0
  370. package/dist/codemode/security.d.ts.map +1 -0
  371. package/dist/codemode/types.d.ts +167 -0
  372. package/dist/codemode/types.d.ts.map +1 -0
  373. package/dist/constants/server-instructions.d.ts +22 -0
  374. package/dist/constants/server-instructions.d.ts.map +1 -0
  375. package/dist/filtering/tool-constants.d.ts +45 -0
  376. package/dist/filtering/tool-constants.d.ts.map +1 -0
  377. package/dist/filtering/tool-filter.d.ts +82 -0
  378. package/dist/filtering/tool-filter.d.ts.map +1 -0
  379. package/dist/{http-VSB7DBJR.js → http-HWTUVFIA.js} +587 -358
  380. package/dist/index.d.ts +9 -842
  381. package/dist/index.d.ts.map +1 -0
  382. package/dist/index.js +4 -5
  383. package/dist/server/mcp-server.d.ts +66 -0
  384. package/dist/server/mcp-server.d.ts.map +1 -0
  385. package/dist/server/registration/audit-tools.d.ts +13 -0
  386. package/dist/server/registration/audit-tools.d.ts.map +1 -0
  387. package/dist/server/registration/built-in-tools.d.ts +8 -0
  388. package/dist/server/registration/built-in-tools.d.ts.map +1 -0
  389. package/dist/server/registration/help-resources.d.ts +7 -0
  390. package/dist/server/registration/help-resources.d.ts.map +1 -0
  391. package/dist/server/registration/index.d.ts +4 -0
  392. package/dist/server/registration/index.d.ts.map +1 -0
  393. package/dist/{sqlite-26V3Y4MK.js → sqlite-6C3AJI4I.js} +115 -147
  394. package/dist/{sqlite-native-5O7FZJGB.js → sqlite-native-ZSSWCTYC.js} +1016 -349
  395. package/dist/transports/http/index.d.ts +8 -0
  396. package/dist/transports/http/index.d.ts.map +1 -0
  397. package/dist/transports/http/middleware.d.ts +25 -0
  398. package/dist/transports/http/middleware.d.ts.map +1 -0
  399. package/dist/transports/http/oauth.d.ts +24 -0
  400. package/dist/transports/http/oauth.d.ts.map +1 -0
  401. package/dist/transports/http/session.d.ts +2 -0
  402. package/dist/transports/http/session.d.ts.map +1 -0
  403. package/dist/transports/http/sessions/index.d.ts +4 -0
  404. package/dist/transports/http/sessions/index.d.ts.map +1 -0
  405. package/dist/transports/http/sessions/legacy-sse.d.ts +6 -0
  406. package/dist/transports/http/sessions/legacy-sse.d.ts.map +1 -0
  407. package/dist/transports/http/sessions/mutex.d.ts +6 -0
  408. package/dist/transports/http/sessions/mutex.d.ts.map +1 -0
  409. package/dist/transports/http/sessions/stateful.d.ts +12 -0
  410. package/dist/transports/http/sessions/stateful.d.ts.map +1 -0
  411. package/dist/transports/http/sessions/stateless.d.ts +6 -0
  412. package/dist/transports/http/sessions/stateless.d.ts.map +1 -0
  413. package/dist/transports/http/transport.d.ts +65 -0
  414. package/dist/transports/http/transport.d.ts.map +1 -0
  415. package/dist/transports/http/type-adapters.d.ts +20 -0
  416. package/dist/transports/http/type-adapters.d.ts.map +1 -0
  417. package/dist/transports/http/types.d.ts +120 -0
  418. package/dist/transports/http/types.d.ts.map +1 -0
  419. package/dist/types/adapter.d.ts +138 -0
  420. package/dist/types/adapter.d.ts.map +1 -0
  421. package/dist/types/auth.d.ts +79 -0
  422. package/dist/types/auth.d.ts.map +1 -0
  423. package/dist/types/database.d.ts +100 -0
  424. package/dist/types/database.d.ts.map +1 -0
  425. package/dist/types/filtering.d.ts +41 -0
  426. package/dist/types/filtering.d.ts.map +1 -0
  427. package/dist/types/index.d.ts +13 -0
  428. package/dist/types/index.d.ts.map +1 -0
  429. package/dist/types/server.d.ts +48 -0
  430. package/dist/types/server.d.ts.map +1 -0
  431. package/dist/utils/annotations.d.ts +62 -0
  432. package/dist/utils/annotations.d.ts.map +1 -0
  433. package/dist/utils/errors/base.d.ts +33 -0
  434. package/dist/utils/errors/base.d.ts.map +1 -0
  435. package/dist/utils/errors/categories.d.ts +41 -0
  436. package/dist/utils/errors/categories.d.ts.map +1 -0
  437. package/dist/utils/errors/classes.d.ts +124 -0
  438. package/dist/utils/errors/classes.d.ts.map +1 -0
  439. package/dist/utils/errors/error-response-fields.d.ts +24 -0
  440. package/dist/utils/errors/error-response-fields.d.ts.map +1 -0
  441. package/dist/utils/errors/format.d.ts +74 -0
  442. package/dist/utils/errors/format.d.ts.map +1 -0
  443. package/dist/utils/errors/index.d.ts +11 -0
  444. package/dist/utils/errors/index.d.ts.map +1 -0
  445. package/dist/utils/errors/suggestions.d.ts +16 -0
  446. package/dist/utils/errors/suggestions.d.ts.map +1 -0
  447. package/dist/utils/icons.d.ts +19 -0
  448. package/dist/utils/icons.d.ts.map +1 -0
  449. package/dist/utils/identifiers.d.ts +121 -0
  450. package/dist/utils/identifiers.d.ts.map +1 -0
  451. package/dist/utils/index.d.ts +9 -0
  452. package/dist/utils/index.d.ts.map +1 -0
  453. package/dist/utils/insights-manager.d.ts +39 -0
  454. package/dist/utils/insights-manager.d.ts.map +1 -0
  455. package/dist/utils/logger/error-codes.d.ts +48 -0
  456. package/dist/utils/logger/error-codes.d.ts.map +1 -0
  457. package/dist/utils/logger/index.d.ts +22 -0
  458. package/dist/utils/logger/index.d.ts.map +1 -0
  459. package/dist/utils/logger/logger.d.ts +94 -0
  460. package/dist/utils/logger/logger.d.ts.map +1 -0
  461. package/dist/utils/logger/module-logger.d.ts +28 -0
  462. package/dist/utils/logger/module-logger.d.ts.map +1 -0
  463. package/dist/utils/logger/types.d.ts +36 -0
  464. package/dist/utils/logger/types.d.ts.map +1 -0
  465. package/dist/utils/progress-utils.d.ts +54 -0
  466. package/dist/utils/progress-utils.d.ts.map +1 -0
  467. package/dist/utils/redaction.d.ts +4 -0
  468. package/dist/utils/redaction.d.ts.map +1 -0
  469. package/dist/utils/resource-annotations.d.ts +36 -0
  470. package/dist/utils/resource-annotations.d.ts.map +1 -0
  471. package/dist/utils/validate-json-path.d.ts +43 -0
  472. package/dist/utils/validate-json-path.d.ts.map +1 -0
  473. package/dist/utils/validate-path.d.ts +37 -0
  474. package/dist/utils/validate-path.d.ts.map +1 -0
  475. package/dist/utils/where-clause.d.ts +42 -0
  476. package/dist/utils/where-clause.d.ts.map +1 -0
  477. package/dist/version.d.ts +10 -0
  478. package/dist/version.d.ts.map +1 -0
  479. package/package.json +33 -20
  480. package/.gitattributes +0 -2
  481. package/dist/chunk-4IA3DB5C.js +0 -135
  482. package/dist/chunk-FW7UCRLN.js +0 -82
  483. package/dist/chunk-RHVEZ42P.js +0 -873
  484. package/dist/chunk-Z2GFQU3G.js +0 -363
  485. package/dist/worker-script.d.ts +0 -2
  486. package/dist/worker-script.js +0 -126
  487. package/playwright.config.ts +0 -101
  488. package/scripts/generate-server-instructions.ts +0 -111
  489. package/server.json +0 -52
  490. package/test-server/README.md +0 -118
  491. package/test-server/code-map.md +0 -409
  492. package/test-server/fixtures/sample.csv +0 -6
  493. package/test-server/reset-database.ps1 +0 -373
  494. package/test-server/sample.csv +0 -11
  495. package/test-server/test-agent-experience.md +0 -243
  496. package/test-server/test-database.sql +0 -388
  497. package/test-server/test-group-tools.md +0 -861
  498. package/test-server/test-help-resources.mjs +0 -238
  499. package/test-server/test-preflight.md +0 -53
  500. package/test-server/test-prompts.md +0 -354
  501. package/test-server/test-resources.md +0 -245
  502. package/test-server/test-tool-annotations.mjs +0 -157
  503. package/test-server/test-tools-advanced-1.md +0 -517
  504. package/test-server/test-tools-advanced-2.md +0 -487
  505. package/test-server/test-tools-codemode.md +0 -629
  506. package/test-server/test-tools.md +0 -176
  507. package/test-server/tool-reference.md +0 -236
  508. package/tsconfig.test.json +0 -9
@@ -1,41 +1,49 @@
1
- import { TransactionBeginOutputSchema, TransactionCommitOutputSchema, TransactionRollbackOutputSchema, TransactionSavepointOutputSchema, TransactionReleaseOutputSchema, TransactionRollbackToOutputSchema, TransactionExecuteOutputSchema, WindowRowNumberOutputSchema, validateWhereClause, WindowRankOutputSchema, WindowLagLeadOutputSchema, WindowRunningTotalOutputSchema, resolveAliases, WindowMovingAvgOutputSchema, WindowNtileOutputSchema, autoEnableWal, detectAndSetJsonbSupport, SchemaManager, applyCommonPragmas, isDDL, getResourceDefinitions, getPromptDefinitions, SpatialiteLoadOutputSchema, SpatialiteCreateTableOutputSchema, SpatialiteQueryOutputSchema, SpatialiteAnalyzeOutputSchema, SpatialiteIndexOutputSchema, SpatialiteTransformOutputSchema, SpatialiteImportOutputSchema, normalizeSqliteParams, getCoreTools, getJsonOperationTools, getJsonHelperTools, getTextTools, getStatsTools, getVirtualTools, getVectorTools, getGeoTools, getAdminTools, getIntrospectionTools, getMigrationTools, getCodeModeTools, FtsCreateOutputSchema, sanitizeIdentifier, FtsSearchOutputSchema, validateTableExists, FtsRebuildOutputSchema } from './chunk-TVIZ3XJH.js';
2
- import { DatabaseAdapter } from './chunk-Z2GFQU3G.js';
3
- import { write, readOnly, VERSION, admin, getToolGroupIcon, idempotent } from './chunk-FW7UCRLN.js';
4
- import { formatHandlerError, ValidationError, ConfigurationError, ConnectionError, ResourceNotFoundError, QueryError } from './chunk-4IA3DB5C.js';
5
- import { logger, ERROR_CODES, DbMcpError } from './chunk-AOUL5SHS.js';
1
+ import { RowRecordSchema, WhereConditionSchema, sanitizeIdentifier, buildWhereClause, resolveAliases, autoEnableWal, detectAndSetJsonbSupport, SchemaManager, applyCommonPragmas, isDDL, getResourceDefinitions, getPromptDefinitions, validateIdentifier, normalizeSqliteParams, translateSqliteError, getCoreTools, getJsonOperationTools, getJsonHelperTools, getTextTools, getStatsTools, getVirtualTools, getVectorTools, getGeoTools, getAdminTools, getIntrospectionTools, getMigrationTools, getCodeModeTools, validateTableExists, FtsHeadlineSchema } from './chunk-FR65YPAH.js';
2
+ import { DatabaseAdapter } from './chunk-W5WQVNVX.js';
3
+ import { ErrorResponseFields, write, readOnly, VERSION, admin, writeFs, getToolGroupIcon, idempotent } from './chunk-E5IESRTK.js';
4
+ import { logger, formatHandlerError, ValidationError, ConfigurationError, ERROR_CODES, ConnectionError, DbMcpError, ResourceNotFoundError, ExtensionNotAvailableError } from './chunk-L552U3QS.js';
6
5
  import Database from 'better-sqlite3';
7
6
  import { z } from 'zod';
8
- import path from 'path';
9
- import fs from 'fs';
7
+ import { createRequire } from 'module';
10
8
  import { fileURLToPath } from 'url';
9
+ import path2 from 'path';
10
+ import fs from 'fs';
11
11
 
12
- function buildFts5UnavailableError(tableName) {
13
- return {
14
- success: false,
15
- message: "FTS5 module unavailable",
16
- tableName: tableName ?? "",
17
- error: "FTS5 module unavailable",
18
- hint: "FTS5 requires native SQLite backend (--sqlite-native). WASM mode (sql.js) does not include this module."
19
- };
20
- }
21
- function isFts5UnavailableError(error) {
22
- return error instanceof Error && error.message.toLowerCase().includes("no such module: fts5");
23
- }
24
- function isFts5Available(adapter) {
25
- return adapter.isNativeBackend();
26
- }
27
- function buildFts5SearchUnavailableError() {
28
- return {
29
- success: false,
30
- rowCount: 0,
31
- results: [],
32
- error: "FTS5 module unavailable",
33
- hint: "FTS5 requires native SQLite backend (--sqlite-native). WASM mode (sql.js) does not include this module."
34
- };
35
- }
12
+ var FtsCreateOutputSchema = z.object({
13
+ success: z.boolean(),
14
+ message: z.string().optional(),
15
+ tableName: z.string().optional(),
16
+ triggersCreated: z.array(z.string()).optional()
17
+ }).extend(ErrorResponseFields.shape);
18
+ var FtsResultSchema = z.object({
19
+ rank: z.number().nullable().optional(),
20
+ bm25: z.number().nullable().optional()
21
+ }).loose();
22
+ var FtsSearchOutputSchema = z.object({
23
+ success: z.boolean(),
24
+ rowCount: z.number().optional(),
25
+ results: z.array(FtsResultSchema).optional()
26
+ }).extend(ErrorResponseFields.shape);
27
+ var FtsRebuildOutputSchema = z.object({
28
+ success: z.boolean(),
29
+ message: z.string().optional(),
30
+ tableName: z.string().optional()
31
+ }).extend(ErrorResponseFields.shape);
32
+ var FtsHeadlineOutputSchema = z.object({
33
+ success: z.boolean(),
34
+ rowCount: z.number().optional(),
35
+ results: z.array(
36
+ z.object({
37
+ headline: z.string().optional(),
38
+ snippet: z.string().optional(),
39
+ rank: z.number().nullable().optional()
40
+ }).loose()
41
+ ).optional()
42
+ }).extend(ErrorResponseFields.shape);
36
43
  var coerceEnumValues = (allowed) => (val) => typeof val === "string" && allowed.includes(val) ? val : void 0;
37
44
  var FtsCreateSchema = z.object({
38
- tableName: z.string().describe("Name of the FTS table to create"),
45
+ tableName: z.string().optional().describe("Name of the FTS table to create"),
46
+ ftsTable: z.string().optional().describe("Name of the FTS table to create (alias)"),
39
47
  sourceTable: z.string().describe("Source table to index"),
40
48
  columns: z.array(z.string()).describe("Columns to include in the index"),
41
49
  contentTable: z.string().optional().describe("Content table for external content FTS"),
@@ -43,19 +51,21 @@ var FtsCreateSchema = z.object({
43
51
  coerceEnumValues(["unicode61", "ascii", "porter"]),
44
52
  z.enum(["unicode61", "ascii", "porter"]).optional().default("unicode61")
45
53
  ),
46
- createTriggers: z.boolean().optional().default(true).describe(
47
- "Create INSERT/UPDATE/DELETE triggers for auto-sync (only for external content tables)"
48
- )
54
+ createTriggers: z.boolean().optional().default(true).describe("Create triggers")
49
55
  });
50
56
  var FtsSearchSchema = z.object({
51
57
  table: z.string().describe("FTS table name"),
52
58
  query: z.string().describe("Full-text search query"),
53
59
  columns: z.array(z.string()).optional().describe("Specific columns to search"),
54
- limit: z.preprocess(
55
- (val) => typeof val === "string" ? isNaN(Number(val)) ? void 0 : Number(val) : val,
56
- z.number().optional().default(100)
57
- ),
58
- highlight: z.boolean().optional().default(false).describe("Include highlighted snippets")
60
+ limit: z.preprocess((val) => {
61
+ if (typeof val === "string") {
62
+ const parsed = Number(val);
63
+ return isNaN(parsed) ? val : parsed;
64
+ }
65
+ return val;
66
+ }, z.number().optional().default(100)),
67
+ highlight: z.boolean().optional().default(false).describe("Include highlighted snippets"),
68
+ includeRowData: z.boolean().optional().default(true).describe("Include full row data in results")
59
69
  });
60
70
  var FtsRebuildSchema = z.object({
61
71
  table: z.string().describe("FTS table name to rebuild")
@@ -66,14 +76,42 @@ var FtsMatchInfoSchema = z.object({
66
76
  format: z.preprocess(
67
77
  coerceEnumValues(["bm25", "rank"]),
68
78
  z.enum(["bm25", "rank"]).optional().default("bm25")
69
- )
79
+ ),
80
+ includeRowData: z.boolean().optional().default(true).describe("Include full row data in results")
70
81
  });
82
+
83
+ // src/adapters/sqlite/tools/fts.ts
84
+ function buildFts5UnavailableError(tableName) {
85
+ return {
86
+ success: false,
87
+ message: "FTS5 module unavailable",
88
+ tableName: tableName ?? "",
89
+ error: "FTS5 module unavailable",
90
+ hint: "FTS5 requires native SQLite backend (--sqlite-native). WASM mode (sql.js) does not include this module."
91
+ };
92
+ }
93
+ function isFts5UnavailableError(error) {
94
+ return error instanceof Error && error.message.toLowerCase().includes("no such module: fts5");
95
+ }
96
+ function isFts5Available(adapter) {
97
+ return adapter.isNativeBackend();
98
+ }
99
+ function buildFts5SearchUnavailableError() {
100
+ return {
101
+ success: false,
102
+ rowCount: 0,
103
+ results: [],
104
+ error: "FTS5 module unavailable",
105
+ hint: "FTS5 requires native SQLite backend (--sqlite-native). WASM mode (sql.js) does not include this module."
106
+ };
107
+ }
71
108
  function getFtsTools(adapter) {
72
109
  return [
73
110
  createFtsCreateTool(adapter),
74
111
  createFtsSearchTool(adapter),
75
112
  createFtsRebuildTool(adapter),
76
- createFtsMatchInfoTool(adapter)
113
+ createFtsMatchInfoTool(adapter),
114
+ createFtsHeadlineTool(adapter)
77
115
  ];
78
116
  }
79
117
  function createFtsCreateTool(adapter) {
@@ -88,7 +126,13 @@ function createFtsCreateTool(adapter) {
88
126
  handler: async (params, _context) => {
89
127
  try {
90
128
  const input = FtsCreateSchema.parse(params);
91
- sanitizeIdentifier(input.tableName);
129
+ const targetTableName = input.tableName || input.ftsTable;
130
+ if (!targetTableName) {
131
+ throw new ValidationError(
132
+ "Must provide either tableName or ftsTable"
133
+ );
134
+ }
135
+ sanitizeIdentifier(targetTableName);
92
136
  sanitizeIdentifier(input.sourceTable);
93
137
  for (const col of input.columns) {
94
138
  sanitizeIdentifier(col);
@@ -98,31 +142,31 @@ function createFtsCreateTool(adapter) {
98
142
  const effectiveContentTable = input.contentTable ?? input.sourceTable;
99
143
  sanitizeIdentifier(effectiveContentTable);
100
144
  options += `, content="${effectiveContentTable}"`;
101
- const sql = `CREATE VIRTUAL TABLE IF NOT EXISTS "${input.tableName}" USING fts5(${columnList}, ${options})`;
145
+ const sql = `CREATE VIRTUAL TABLE IF NOT EXISTS "${targetTableName}" USING fts5(${columnList}, ${options})`;
102
146
  await adapter.executeQuery(sql);
103
147
  let triggersCreated = [];
104
148
  if (input.createTriggers) {
105
149
  triggersCreated = await createSyncTriggers(
106
150
  adapter,
107
- input.tableName,
151
+ targetTableName,
108
152
  effectiveContentTable,
109
153
  input.columns
110
154
  );
111
155
  }
112
156
  await adapter.executeQuery(
113
- `INSERT INTO "${input.tableName}"("${input.tableName}") VALUES('rebuild')`
157
+ `INSERT INTO "${targetTableName}"("${targetTableName}") VALUES('rebuild')`
114
158
  );
115
- const message = triggersCreated.length ? `FTS5 table '${input.tableName}' created with ${triggersCreated.length} sync triggers` : `FTS5 table '${input.tableName}' created`;
159
+ const message = triggersCreated.length ? `FTS5 table '${targetTableName}' created with ${triggersCreated.length} sync triggers` : `FTS5 table '${targetTableName}' created`;
116
160
  return {
117
161
  success: true,
118
162
  message,
119
- tableName: input.tableName,
163
+ tableName: targetTableName,
120
164
  triggersCreated: triggersCreated.length ? triggersCreated : void 0
121
165
  };
122
166
  } catch (error) {
123
167
  if (isFts5UnavailableError(error)) {
124
168
  return buildFts5UnavailableError(
125
- params?.tableName
169
+ params?.tableName || params?.ftsTable
126
170
  );
127
171
  }
128
172
  return formatHandlerError(error);
@@ -141,7 +185,7 @@ async function createSyncTriggers(adapter, ftsTable, contentTable, columns) {
141
185
  INSERT INTO "${ftsTable}"(rowid, ${colList}) VALUES (NEW.rowid, ${newColList});
142
186
  END;
143
187
  `;
144
- await adapter.executeQuery(insertTrigger);
188
+ await adapter.rawQuery(insertTrigger, void 0);
145
189
  triggersCreated.push(insertTriggerName);
146
190
  const deleteTriggerName = `${ftsTable}_ad`;
147
191
  const deleteTrigger = `
@@ -149,7 +193,7 @@ async function createSyncTriggers(adapter, ftsTable, contentTable, columns) {
149
193
  INSERT INTO "${ftsTable}"("${ftsTable}", rowid, ${colList}) VALUES('delete', OLD.rowid, ${oldColList});
150
194
  END;
151
195
  `;
152
- await adapter.executeQuery(deleteTrigger);
196
+ await adapter.rawQuery(deleteTrigger, void 0);
153
197
  triggersCreated.push(deleteTriggerName);
154
198
  const updateTriggerName = `${ftsTable}_au`;
155
199
  const updateTrigger = `
@@ -158,7 +202,7 @@ async function createSyncTriggers(adapter, ftsTable, contentTable, columns) {
158
202
  INSERT INTO "${ftsTable}"(rowid, ${colList}) VALUES (NEW.rowid, ${newColList});
159
203
  END;
160
204
  `;
161
- await adapter.executeQuery(updateTrigger);
205
+ await adapter.rawQuery(updateTrigger, void 0);
162
206
  triggersCreated.push(updateTriggerName);
163
207
  return triggersCreated;
164
208
  }
@@ -174,18 +218,19 @@ function createFtsSearchTool(adapter) {
174
218
  handler: async (params, _context) => {
175
219
  try {
176
220
  const input = FtsSearchSchema.parse(params);
221
+ const queryParams = [];
177
222
  if (!isFts5Available(adapter)) {
178
223
  return buildFts5SearchUnavailableError();
179
224
  }
180
225
  sanitizeIdentifier(input.table);
181
226
  await validateTableExists(adapter, input.table);
182
- let selectClause = "*";
227
+ let selectClause = input.includeRowData ? "*" : "rowid";
183
228
  if (input.highlight) {
184
- selectClause = `*, highlight("${input.table}", 0, '<b>', '</b>') as snippet`;
229
+ selectClause += `, highlight("${input.table}", 0, '<b>', '</b>') as snippet`;
185
230
  }
186
231
  if (input.query === "*" || input.query.trim() === "") {
187
232
  const sql2 = `SELECT ${selectClause}, NULL as rank FROM "${input.table}" ORDER BY rowid LIMIT ${input.limit}`;
188
- const result2 = await adapter.executeReadQuery(sql2);
233
+ const result2 = await adapter.executeReadQuery(sql2, queryParams);
189
234
  return {
190
235
  success: true,
191
236
  rowCount: result2.rows?.length ?? 0,
@@ -202,7 +247,7 @@ function createFtsSearchTool(adapter) {
202
247
  matchExpr = `"${input.table}" MATCH '${colFilter}'`;
203
248
  }
204
249
  const sql = `SELECT ${selectClause}, rank FROM "${input.table}" WHERE ${matchExpr} ORDER BY rank LIMIT ${input.limit}`;
205
- const result = await adapter.executeReadQuery(sql);
250
+ const result = await adapter.executeReadQuery(sql, queryParams);
206
251
  return {
207
252
  success: true,
208
253
  rowCount: result.rows?.length ?? 0,
@@ -264,6 +309,7 @@ function createFtsMatchInfoTool(adapter) {
264
309
  handler: async (params, _context) => {
265
310
  try {
266
311
  const input = FtsMatchInfoSchema.parse(params);
312
+ const queryParams = [];
267
313
  if (!isFts5Available(adapter)) {
268
314
  return buildFts5SearchUnavailableError();
269
315
  }
@@ -276,8 +322,71 @@ function createFtsMatchInfoTool(adapter) {
276
322
  } else {
277
323
  rankExpr = "rank";
278
324
  }
279
- const sql = `SELECT *, ${rankExpr} as score FROM "${input.table}" WHERE "${input.table}" MATCH '${queryEscaped}' ORDER BY score`;
280
- const result = await adapter.executeReadQuery(sql);
325
+ const selectCols = input.includeRowData ? "*" : "rowid";
326
+ const sql = `SELECT ${selectCols}, ${rankExpr} as score FROM "${input.table}" WHERE "${input.table}" MATCH '${queryEscaped}' ORDER BY score`;
327
+ const result = await adapter.executeReadQuery(sql, queryParams);
328
+ return {
329
+ success: true,
330
+ rowCount: result.rows?.length ?? 0,
331
+ results: result.rows
332
+ };
333
+ } catch (error) {
334
+ if (isFts5UnavailableError(error)) {
335
+ return buildFts5SearchUnavailableError();
336
+ }
337
+ return formatHandlerError(error);
338
+ }
339
+ }
340
+ };
341
+ }
342
+ function createFtsHeadlineTool(adapter) {
343
+ return {
344
+ name: "sqlite_fts_headline",
345
+ description: "Generate highlighted snippets from FTS5 full-text search results. Returns headline (highlight) and snippet (context window) for each match.",
346
+ group: "text",
347
+ inputSchema: FtsHeadlineSchema,
348
+ outputSchema: FtsHeadlineOutputSchema,
349
+ requiredScopes: ["read"],
350
+ annotations: readOnly("FTS Headline"),
351
+ handler: async (params, _context) => {
352
+ try {
353
+ const input = FtsHeadlineSchema.parse(params);
354
+ const queryParams = [];
355
+ if (!isFts5Available(adapter)) {
356
+ return buildFts5SearchUnavailableError();
357
+ }
358
+ sanitizeIdentifier(input.table);
359
+ await validateTableExists(adapter, input.table);
360
+ const queryEscaped = input.query.replace(/'/g, "''");
361
+ let columnIndex = 0;
362
+ if (input.column) {
363
+ const colResult = await adapter.executeReadQuery(
364
+ `PRAGMA table_info("${input.table}")`,
365
+ queryParams
366
+ );
367
+ const colRows = colResult.rows ?? [];
368
+ const found = colRows.findIndex(
369
+ (r) => String(r["name"]) === input.column
370
+ );
371
+ if (found >= 0) {
372
+ columnIndex = found;
373
+ }
374
+ }
375
+ const startSel = input.startSel.replace(/'/g, "''");
376
+ const stopSel = input.stopSel.replace(/'/g, "''");
377
+ const highlightExpr = `highlight("${input.table}", ${String(columnIndex)}, '${startSel}', '${stopSel}')`;
378
+ const snippetExpr = `snippet("${input.table}", ${String(columnIndex)}, '${startSel}', '${stopSel}', '...', ${String(input.snippetWords)})`;
379
+ if (input.query === "*" || input.query.trim() === "") {
380
+ const sql2 = `SELECT *, NULL as headline, NULL as snippet, NULL as rank FROM "${input.table}" ORDER BY rowid LIMIT ${String(input.limit)}`;
381
+ const result2 = await adapter.executeReadQuery(sql2, queryParams);
382
+ return {
383
+ success: true,
384
+ rowCount: result2.rows?.length ?? 0,
385
+ results: result2.rows
386
+ };
387
+ }
388
+ const sql = `SELECT ${highlightExpr} as headline, ${snippetExpr} as snippet, rank FROM "${input.table}" WHERE "${input.table}" MATCH '${queryEscaped}' ORDER BY rank LIMIT ${String(input.limit)}`;
389
+ const result = await adapter.executeReadQuery(sql, queryParams);
281
390
  return {
282
391
  success: true,
283
392
  rowCount: result.rows?.length ?? 0,
@@ -292,17 +401,166 @@ function createFtsMatchInfoTool(adapter) {
292
401
  }
293
402
  };
294
403
  }
295
- var VALID_MODES = ["deferred", "immediate", "exclusive"];
404
+ var TransactionBeginOutputSchema = z.object({
405
+ success: z.boolean(),
406
+ message: z.string().optional(),
407
+ mode: z.string().optional()
408
+ }).extend(ErrorResponseFields.shape);
409
+ var TransactionCommitOutputSchema = z.object({
410
+ success: z.boolean(),
411
+ message: z.string().optional()
412
+ }).extend(ErrorResponseFields.shape);
413
+ var TransactionRollbackOutputSchema = z.object({
414
+ success: z.boolean(),
415
+ message: z.string().optional()
416
+ }).extend(ErrorResponseFields.shape);
417
+ var TransactionSavepointOutputSchema = z.object({
418
+ success: z.boolean(),
419
+ message: z.string().optional(),
420
+ name: z.string().optional(),
421
+ savepoint: z.string().optional()
422
+ }).extend(ErrorResponseFields.shape);
423
+ var TransactionReleaseOutputSchema = z.object({
424
+ success: z.boolean(),
425
+ message: z.string().optional(),
426
+ name: z.string().optional(),
427
+ savepoint: z.string().optional()
428
+ }).extend(ErrorResponseFields.shape);
429
+ var TransactionRollbackToOutputSchema = z.object({
430
+ success: z.boolean(),
431
+ message: z.string().optional(),
432
+ name: z.string().optional(),
433
+ savepoint: z.string().optional()
434
+ }).extend(ErrorResponseFields.shape);
435
+ var TransactionExecuteOutputSchema = z.object({
436
+ success: z.boolean(),
437
+ message: z.string().optional(),
438
+ statementsExecuted: z.number().optional(),
439
+ results: z.array(z.unknown()).optional()
440
+ }).extend(ErrorResponseFields.shape);
441
+ var TransactionStatusOutputSchema = z.object({
442
+ success: z.boolean(),
443
+ status: z.enum(["active", "none"]).optional().describe(
444
+ 'Transaction state: "active" (transaction in progress) or "none" (no active transaction)'
445
+ ),
446
+ active: z.boolean().optional().describe("Whether a transaction is currently in progress"),
447
+ message: z.string().optional()
448
+ }).extend(ErrorResponseFields.shape);
449
+ var RowNumberResultSchema = z.object({
450
+ row_number: z.number()
451
+ }).loose();
452
+ var WindowRowNumberOutputSchema = z.object({
453
+ success: z.boolean(),
454
+ rowCount: z.number().optional(),
455
+ rows: z.array(RowNumberResultSchema).optional(),
456
+ hint: z.string().optional()
457
+ }).extend(ErrorResponseFields.shape);
458
+ var RankResultSchema = z.object({
459
+ rank: z.number().optional(),
460
+ dense_rank: z.number().optional(),
461
+ percent_rank: z.number().optional()
462
+ }).loose();
463
+ var WindowRankOutputSchema = z.object({
464
+ success: z.boolean(),
465
+ rankType: z.string().optional(),
466
+ rowCount: z.number().optional(),
467
+ rows: z.array(RankResultSchema).optional(),
468
+ hint: z.string().optional()
469
+ }).extend(ErrorResponseFields.shape);
470
+ var LagLeadResultSchema = z.object({
471
+ lag_value: z.unknown().optional(),
472
+ lead_value: z.unknown().optional()
473
+ }).loose();
474
+ var WindowLagLeadOutputSchema = z.object({
475
+ success: z.boolean(),
476
+ direction: z.string().optional(),
477
+ offset: z.number().optional(),
478
+ rowCount: z.number().optional(),
479
+ rows: z.array(LagLeadResultSchema).optional(),
480
+ hint: z.string().optional()
481
+ }).extend(ErrorResponseFields.shape);
482
+ var RunningTotalResultSchema = z.object({
483
+ running_total: z.number()
484
+ }).loose();
485
+ var WindowRunningTotalOutputSchema = z.object({
486
+ success: z.boolean(),
487
+ valueColumn: z.string().optional(),
488
+ rowCount: z.number().optional(),
489
+ rows: z.array(RunningTotalResultSchema).optional(),
490
+ hint: z.string().optional()
491
+ }).extend(ErrorResponseFields.shape);
492
+ var MovingAvgResultSchema = z.object({
493
+ moving_avg: z.number()
494
+ }).loose();
495
+ var WindowMovingAvgOutputSchema = z.object({
496
+ success: z.boolean(),
497
+ valueColumn: z.string().optional(),
498
+ windowSize: z.number().optional(),
499
+ rowCount: z.number().optional(),
500
+ rows: z.array(MovingAvgResultSchema).optional(),
501
+ hint: z.string().optional()
502
+ }).extend(ErrorResponseFields.shape);
503
+ var NtileResultSchema = z.object({
504
+ ntile: z.number()
505
+ }).loose();
506
+ var WindowNtileOutputSchema = z.object({
507
+ success: z.boolean(),
508
+ buckets: z.number().optional(),
509
+ rowCount: z.number().optional(),
510
+ rows: z.array(NtileResultSchema).optional(),
511
+ hint: z.string().optional()
512
+ }).extend(ErrorResponseFields.shape);
513
+ var SpatialiteLoadOutputSchema = z.object({
514
+ success: z.boolean(),
515
+ message: z.string().optional(),
516
+ alreadyLoaded: z.boolean().optional(),
517
+ extensionPath: z.string().optional(),
518
+ searchedPaths: z.array(z.string()).optional()
519
+ }).extend(ErrorResponseFields.shape);
520
+ var SpatialiteCreateTableOutputSchema = z.object({
521
+ success: z.boolean(),
522
+ message: z.string().optional(),
523
+ tableName: z.string().optional(),
524
+ alreadyExists: z.boolean().optional(),
525
+ geometryColumn: z.string().optional(),
526
+ geometryType: z.string().optional(),
527
+ srid: z.number().optional()
528
+ }).extend(ErrorResponseFields.shape);
529
+ var SpatialiteQueryOutputSchema = z.object({
530
+ success: z.boolean(),
531
+ rowCount: z.number().optional(),
532
+ rows: z.array(RowRecordSchema).optional()
533
+ }).extend(ErrorResponseFields.shape);
534
+ var SpatialiteIndexOutputSchema = z.object({
535
+ success: z.boolean(),
536
+ message: z.string().optional(),
537
+ action: z.string().optional(),
538
+ alreadyExists: z.boolean().optional(),
539
+ alreadyDropped: z.boolean().optional(),
540
+ indexed: z.boolean().optional(),
541
+ valid: z.boolean().nullable().optional()
542
+ }).extend(ErrorResponseFields.shape);
543
+ var SpatialiteAnalyzeOutputSchema = z.object({
544
+ success: z.boolean(),
545
+ analysisType: z.string().optional(),
546
+ rowCount: z.number().optional(),
547
+ results: z.array(RowRecordSchema).optional()
548
+ }).extend(ErrorResponseFields.shape);
549
+ var SpatialiteTransformOutputSchema = z.object({
550
+ success: z.boolean(),
551
+ operation: z.string().optional(),
552
+ result: z.string().optional()
553
+ }).extend(ErrorResponseFields.shape);
554
+ var SpatialiteImportOutputSchema = z.object({
555
+ success: z.boolean(),
556
+ message: z.string().optional(),
557
+ rowsAffected: z.number().optional()
558
+ }).extend(ErrorResponseFields.shape);
559
+
560
+ // src/adapters/sqlite-native/tools/transactions.ts
296
561
  var BeginTransactionSchema = z.object({
297
- mode: z.preprocess(
298
- (val) => {
299
- if (typeof val !== "string") return void 0;
300
- const normalized = val.toLowerCase();
301
- return VALID_MODES.includes(normalized) ? normalized : void 0;
302
- },
303
- z.enum(["deferred", "immediate", "exclusive"]).optional().default("deferred").describe(
304
- "Transaction mode: deferred waits for first write, immediate acquires lock immediately, exclusive blocks all access"
305
- )
562
+ mode: z.enum(["deferred", "immediate", "exclusive"]).optional().default("deferred").describe(
563
+ "Transaction mode: deferred waits for first write, immediate acquires lock immediately, exclusive blocks all access"
306
564
  )
307
565
  });
308
566
  var SavepointSchema = z.object({
@@ -315,6 +573,7 @@ var ExecuteInTransactionSchema = z.object({
315
573
  function getTransactionTools(adapter) {
316
574
  return [
317
575
  createBeginTransactionTool(adapter),
576
+ createTransactionStatusTool(adapter),
318
577
  createCommitTransactionTool(adapter),
319
578
  createRollbackTransactionTool(adapter),
320
579
  createSavepointTool(adapter),
@@ -327,7 +586,7 @@ function createBeginTransactionTool(adapter) {
327
586
  return {
328
587
  name: "sqlite_transaction_begin",
329
588
  description: "Begin a new transaction. Use immediate or exclusive mode for write-heavy operations.",
330
- group: "admin",
589
+ group: "transactions",
331
590
  inputSchema: BeginTransactionSchema,
332
591
  outputSchema: TransactionBeginOutputSchema,
333
592
  annotations: write("Begin Transaction"),
@@ -348,11 +607,36 @@ function createBeginTransactionTool(adapter) {
348
607
  }
349
608
  };
350
609
  }
610
+ function createTransactionStatusTool(adapter) {
611
+ return {
612
+ name: "sqlite_transaction_status",
613
+ description: "Check whether a transaction is currently active. Returns status and a boolean flag. Read-only \u2014 does not alter transaction state.",
614
+ group: "transactions",
615
+ inputSchema: z.object({}),
616
+ outputSchema: TransactionStatusOutputSchema,
617
+ annotations: readOnly("Transaction Status"),
618
+ requiredScopes: ["read"],
619
+ handler: (_params, _context) => {
620
+ try {
621
+ const db = adapter.getDatabase();
622
+ const active = db.inTransaction;
623
+ return Promise.resolve({
624
+ success: true,
625
+ status: active ? "active" : "none",
626
+ active,
627
+ message: active ? "A transaction is currently active." : "No transaction is active."
628
+ });
629
+ } catch (error) {
630
+ return Promise.resolve(formatHandlerError(error));
631
+ }
632
+ }
633
+ };
634
+ }
351
635
  function createCommitTransactionTool(adapter) {
352
636
  return {
353
637
  name: "sqlite_transaction_commit",
354
638
  description: "Commit the current transaction, making all changes permanent.",
355
- group: "admin",
639
+ group: "transactions",
356
640
  inputSchema: z.object({}),
357
641
  outputSchema: TransactionCommitOutputSchema,
358
642
  annotations: write("Commit Transaction"),
@@ -374,7 +658,7 @@ function createRollbackTransactionTool(adapter) {
374
658
  return {
375
659
  name: "sqlite_transaction_rollback",
376
660
  description: "Rollback the current transaction, discarding all changes.",
377
- group: "admin",
661
+ group: "transactions",
378
662
  outputSchema: TransactionRollbackOutputSchema,
379
663
  inputSchema: z.object({}),
380
664
  annotations: write("Rollback Transaction"),
@@ -396,7 +680,7 @@ function createSavepointTool(adapter) {
396
680
  return {
397
681
  name: "sqlite_transaction_savepoint",
398
682
  description: "Create a savepoint within the current transaction for partial rollback.",
399
- group: "admin",
683
+ group: "transactions",
400
684
  outputSchema: TransactionSavepointOutputSchema,
401
685
  inputSchema: SavepointSchema,
402
686
  annotations: write("Create Savepoint"),
@@ -429,7 +713,7 @@ function createReleaseSavepointTool(adapter) {
429
713
  return {
430
714
  name: "sqlite_transaction_release",
431
715
  description: "Release a savepoint, keeping the changes made since it was created.",
432
- group: "admin",
716
+ group: "transactions",
433
717
  inputSchema: SavepointSchema,
434
718
  outputSchema: TransactionReleaseOutputSchema,
435
719
  annotations: write("Release Savepoint"),
@@ -462,7 +746,7 @@ function createRollbackToSavepointTool(adapter) {
462
746
  return {
463
747
  name: "sqlite_transaction_rollback_to",
464
748
  description: "Rollback to a savepoint, discarding changes made after it was created.",
465
- group: "admin",
749
+ group: "transactions",
466
750
  inputSchema: SavepointSchema,
467
751
  outputSchema: TransactionRollbackToOutputSchema,
468
752
  annotations: write("Rollback to Savepoint"),
@@ -495,43 +779,65 @@ function createExecuteInTransactionTool(adapter) {
495
779
  return {
496
780
  name: "sqlite_transaction_execute",
497
781
  description: "Execute multiple SQL statements in a single transaction. Automatically commits on success or rolls back on error.",
498
- group: "admin",
782
+ group: "transactions",
499
783
  outputSchema: TransactionExecuteOutputSchema,
500
784
  inputSchema: ExecuteInTransactionSchema,
501
785
  annotations: write("Execute in Transaction"),
502
786
  requiredScopes: ["write"],
503
787
  handler: async (params, _context) => {
788
+ const queryParams = [];
504
789
  let input;
505
790
  try {
506
791
  input = ExecuteInTransactionSchema.parse(params);
792
+ if (input.statements.length === 0) {
793
+ throw new ValidationError("Must provide at least one SQL statement");
794
+ }
507
795
  } catch (error) {
796
+ const errObj = formatHandlerError(error);
508
797
  return {
509
- ...formatHandlerError(error),
510
- message: "",
798
+ ...errObj,
799
+ message: errObj.error || "Transaction execution failed",
511
800
  statementsExecuted: 0,
512
801
  results: []
513
802
  };
514
803
  }
515
804
  const results = [];
516
805
  let success = true;
806
+ let transactionStarted = false;
807
+ const db = adapter.getDatabase();
808
+ const originallyInTransaction = db.inTransaction;
517
809
  try {
518
- adapter.beginTransaction();
810
+ if (!originallyInTransaction) {
811
+ adapter.beginTransaction();
812
+ transactionStarted = true;
813
+ }
519
814
  for (const statement of input.statements) {
520
815
  try {
521
816
  const isSelect = statement.trim().toUpperCase().startsWith("SELECT");
522
817
  if (isSelect) {
523
- const result = await adapter.executeReadQuery(statement);
818
+ const result = await adapter.executeReadQuery(
819
+ statement,
820
+ queryParams
821
+ );
524
822
  const rowCount = result.rows?.length ?? 0;
525
823
  const statementResult = {
526
824
  statement: statement.substring(0, 100) + (statement.length > 100 ? "..." : ""),
527
825
  rowCount
528
826
  };
529
827
  if (result.rows) {
530
- statementResult.rows = result.rows;
828
+ if (result.rows.length > 50) {
829
+ statementResult.rows = result.rows.slice(0, 50);
830
+ statementResult.error = "Result truncated to 50 rows. Use sqlite_read_query with LIMIT for larger datasets.";
831
+ } else {
832
+ statementResult.rows = result.rows;
833
+ }
531
834
  }
532
835
  results.push(statementResult);
533
836
  } else {
534
- const result = await adapter.executeWriteQuery(statement);
837
+ const result = await adapter.executeWriteQuery(
838
+ statement,
839
+ queryParams
840
+ );
535
841
  results.push({
536
842
  statement: statement.substring(0, 100) + (statement.length > 100 ? "..." : ""),
537
843
  rowsAffected: result.rowsAffected ?? 0
@@ -549,25 +855,38 @@ function createExecuteInTransactionTool(adapter) {
549
855
  success = false;
550
856
  }
551
857
  }
552
- adapter.commitTransaction();
858
+ if (transactionStarted) {
859
+ adapter.commitTransaction();
860
+ }
553
861
  return {
554
862
  success,
863
+ error: success ? void 0 : "Transaction completed with errors",
555
864
  message: success ? "Transaction completed successfully" : "Transaction completed with errors",
556
865
  statementsExecuted: input.statements.length,
557
866
  results
558
867
  };
559
868
  } catch (error) {
560
869
  let rollbackFailure;
561
- try {
562
- adapter.rollbackTransaction();
563
- } catch (rbError) {
564
- rollbackFailure = rbError instanceof Error ? rbError.message : String(rbError);
870
+ if (transactionStarted) {
871
+ try {
872
+ adapter.rollbackTransaction();
873
+ } catch (rbError) {
874
+ rollbackFailure = rbError instanceof Error ? rbError.message : String(rbError);
875
+ }
876
+ } else if (originallyInTransaction && input.rollbackOnError) {
877
+ try {
878
+ adapter.rollbackTransaction();
879
+ } catch (rbError) {
880
+ rollbackFailure = rbError instanceof Error ? rbError.message : String(rbError);
881
+ }
565
882
  }
566
883
  const message = error instanceof Error ? error.message : String(error);
567
884
  const formatted = formatHandlerError(error);
568
885
  let rollbackMessage = `Transaction rolled back: ${message}`;
569
886
  if (rollbackFailure) {
570
887
  rollbackMessage += ` (rollback error: ${rollbackFailure})`;
888
+ } else if (!transactionStarted && !originallyInTransaction) {
889
+ rollbackMessage = `Transaction failed to start: ${message}`;
571
890
  }
572
891
  return {
573
892
  ...formatted,
@@ -580,7 +899,14 @@ function createExecuteInTransactionTool(adapter) {
580
899
  }
581
900
  };
582
901
  }
583
- var coerceNumber = (val) => typeof val === "string" ? isNaN(Number(val)) ? void 0 : Number(val) : val;
902
+ var coerceNumber = (val) => {
903
+ if (typeof val === "string") {
904
+ if (val.trim() === "") return void 0;
905
+ const num = Number(val);
906
+ return isNaN(num) ? val : num;
907
+ }
908
+ return val;
909
+ };
584
910
  var coerceEnumValues2 = (allowed) => (val) => typeof val === "string" && allowed.includes(val) ? val : void 0;
585
911
  var VALID_DIRECTIONS = ["lag", "lead"];
586
912
  var RowNumberSchema = z.object({
@@ -588,10 +914,10 @@ var RowNumberSchema = z.object({
588
914
  orderBy: z.string().describe("Column(s) to order by"),
589
915
  partitionBy: z.string().optional().describe("Column(s) to partition by"),
590
916
  selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
591
- whereClause: z.string().optional().describe("Optional WHERE clause"),
917
+ conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
592
918
  limit: z.preprocess(
593
919
  coerceNumber,
594
- z.number().optional().default(100).describe("Maximum rows to return")
920
+ z.number().optional().default(20).describe("Maximum rows to return")
595
921
  )
596
922
  });
597
923
  var RankSchema = z.object({
@@ -603,10 +929,10 @@ var RankSchema = z.object({
603
929
  coerceEnumValues2(["rank", "dense_rank", "percent_rank"]),
604
930
  z.enum(["rank", "dense_rank", "percent_rank"]).optional().default("rank").describe("Rank function type")
605
931
  ),
606
- whereClause: z.string().optional().describe("Optional WHERE clause"),
932
+ conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
607
933
  limit: z.preprocess(
608
934
  coerceNumber,
609
- z.number().optional().default(100).describe("Maximum rows to return")
935
+ z.number().optional().default(20).describe("Maximum rows to return")
610
936
  )
611
937
  });
612
938
  var LagLeadSchema = z.object({
@@ -621,10 +947,10 @@ var LagLeadSchema = z.object({
621
947
  defaultValue: z.string().optional().describe("Default value if no row exists"),
622
948
  partitionBy: z.string().optional().describe("Column(s) to partition by"),
623
949
  selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
624
- whereClause: z.string().optional().describe("Optional WHERE clause"),
950
+ conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
625
951
  limit: z.preprocess(
626
952
  coerceNumber,
627
- z.number().optional().default(100).describe("Maximum rows to return")
953
+ z.number().optional().default(20).describe("Maximum rows to return")
628
954
  )
629
955
  });
630
956
  var RunningTotalSchema = z.object({
@@ -633,10 +959,10 @@ var RunningTotalSchema = z.object({
633
959
  orderBy: z.string().describe("Column(s) to order by"),
634
960
  partitionBy: z.string().optional().describe("Reset running total for each partition"),
635
961
  selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
636
- whereClause: z.string().optional().describe("Optional WHERE clause"),
962
+ conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
637
963
  limit: z.preprocess(
638
964
  coerceNumber,
639
- z.number().optional().default(100).describe("Maximum rows to return")
965
+ z.number().optional().default(20).describe("Maximum rows to return")
640
966
  )
641
967
  });
642
968
  var MovingAverageSchema = z.object({
@@ -645,14 +971,14 @@ var MovingAverageSchema = z.object({
645
971
  orderBy: z.string().describe("Column(s) to order by"),
646
972
  windowSize: z.preprocess(
647
973
  coerceNumber,
648
- z.number().optional().describe("Number of rows in the moving window")
974
+ z.number().describe("Number of rows in the moving window")
649
975
  ),
650
976
  partitionBy: z.string().optional().describe("Column(s) to partition by"),
651
977
  selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
652
- whereClause: z.string().optional().describe("Optional WHERE clause"),
978
+ conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
653
979
  limit: z.preprocess(
654
980
  coerceNumber,
655
- z.number().optional().default(100).describe("Maximum rows to return")
981
+ z.number().optional().default(20).describe("Maximum rows to return")
656
982
  )
657
983
  });
658
984
  var NtileSchema = z.object({
@@ -660,24 +986,18 @@ var NtileSchema = z.object({
660
986
  orderBy: z.string().describe("Column(s) to order by"),
661
987
  buckets: z.preprocess(
662
988
  coerceNumber,
663
- z.number().optional().describe("Number of buckets (e.g., 4 for quartiles)")
989
+ z.number().describe("Number of buckets (e.g., 4 for quartiles)")
664
990
  ),
665
991
  partitionBy: z.string().optional().describe("Column(s) to partition by"),
666
992
  selectColumns: z.array(z.string()).optional().describe("Columns to include in result"),
667
- whereClause: z.string().optional().describe("Optional WHERE clause"),
993
+ conditions: z.array(WhereConditionSchema).optional().describe("Optional WHERE clause conditions"),
668
994
  limit: z.preprocess(
669
995
  coerceNumber,
670
- z.number().optional().default(100).describe("Maximum rows to return")
996
+ z.number().optional().default(20).describe("Maximum rows to return")
671
997
  )
672
998
  });
673
999
  async function validateTableExists2(adapter, table) {
674
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {
675
- throw new DbMcpError(
676
- "Invalid table name",
677
- "NATIVE_WINDOW_INVALID_TABLE",
678
- "validation" /* VALIDATION */
679
- );
680
- }
1000
+ validateIdentifier(table);
681
1001
  const result = await adapter.executeReadQuery(
682
1002
  `SELECT 1 FROM sqlite_master WHERE type IN ('table', 'view') AND name='${table}'`
683
1003
  );
@@ -694,13 +1014,7 @@ async function validateTableExists2(adapter, table) {
694
1014
  }
695
1015
  }
696
1016
  async function validateColumnInTable(adapter, table, column) {
697
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(column)) {
698
- throw new DbMcpError(
699
- "Invalid column name",
700
- "NATIVE_WINDOW_INVALID_COLUMN",
701
- "validation" /* VALIDATION */
702
- );
703
- }
1017
+ validateIdentifier(column);
704
1018
  const tableInfo = await adapter.executeReadQuery(
705
1019
  `SELECT name FROM pragma_table_info('${table}') WHERE name='${column}'`
706
1020
  );
@@ -723,16 +1037,128 @@ async function validateOrderByColumns(adapter, table, orderBy) {
723
1037
  const firstToken = tokens[0];
724
1038
  if (!firstToken) continue;
725
1039
  const colName = firstToken.replace(/^"|"$/g, "");
726
- if (/[.()+*/]/.test(colName)) continue;
1040
+ if (/[;()+*/]/.test(colName)) {
1041
+ throw new DbMcpError(
1042
+ `Invalid ORDER BY expression: '${colName}' contains disallowed characters. Only column names with optional ASC/DESC are permitted.`,
1043
+ "NATIVE_WINDOW_INVALID_ORDERBY",
1044
+ "validation" /* VALIDATION */
1045
+ );
1046
+ }
727
1047
  if (/^(ASC|DESC)$/i.test(colName)) continue;
1048
+ if (colName.includes(".")) {
1049
+ for (const segment of colName.split(".")) {
1050
+ validateIdentifier(segment);
1051
+ }
1052
+ continue;
1053
+ }
728
1054
  await validateColumnInTable(adapter, table, colName);
729
1055
  }
730
1056
  }
731
- function formatColumns(selectColumns) {
732
- if (selectColumns === void 0 || selectColumns.length === 0) {
733
- return "*";
1057
+ async function resolveSelectColumns(adapter, table, selectColumns, rankCol) {
1058
+ if (selectColumns && selectColumns.length > 0) {
1059
+ return {
1060
+ columnList: selectColumns.map((c) => sanitizeIdentifier(c)).join(", ")
1061
+ };
1062
+ }
1063
+ const tableInfo = await adapter.executeReadQuery(
1064
+ `PRAGMA table_info('${table}')`
1065
+ );
1066
+ const TEXT_TYPES = /* @__PURE__ */ new Set([
1067
+ "text",
1068
+ "blob",
1069
+ "clob",
1070
+ "varchar",
1071
+ "nvarchar",
1072
+ "char"
1073
+ ]);
1074
+ const LONG_CONTENT_PATTERNS = [
1075
+ "description",
1076
+ "body",
1077
+ "bio",
1078
+ "content",
1079
+ "notes",
1080
+ "summary",
1081
+ "comment",
1082
+ "details",
1083
+ "html",
1084
+ "markdown",
1085
+ "text",
1086
+ "message",
1087
+ "payload",
1088
+ "raw",
1089
+ "data",
1090
+ "log",
1091
+ "blob"
1092
+ ];
1093
+ const excluded = [];
1094
+ const included = [];
1095
+ for (const c of tableInfo.rows ?? []) {
1096
+ const colName = c["name"];
1097
+ const colType = (c["type"] ?? "").toLowerCase();
1098
+ const nameLower = colName.toLowerCase();
1099
+ const isText = [...TEXT_TYPES].some(
1100
+ (t) => colType === t || colType.startsWith(t)
1101
+ );
1102
+ const isRankCol = rankCol ? nameLower === rankCol.toLowerCase() : false;
1103
+ const isLongContent = LONG_CONTENT_PATTERNS.some(
1104
+ (p) => nameLower === p || nameLower.endsWith(`_${p}`) || nameLower.startsWith(`${p}_`)
1105
+ );
1106
+ if (isText && !isRankCol && isLongContent) {
1107
+ excluded.push(colName);
1108
+ } else {
1109
+ included.push(colName);
1110
+ }
734
1111
  }
735
- return selectColumns.map((c) => `"${c}"`).join(", ");
1112
+ if (included.length > 10) {
1113
+ throw new ValidationError(
1114
+ `Table '${table}' has too many columns (${included.length} remaining after text filtering). You must explicitly provide 'selectColumns' to prevent context window bloat.`,
1115
+ "INVALID_INPUT"
1116
+ );
1117
+ }
1118
+ if (excluded.length > 0 && included.length > 0) {
1119
+ return {
1120
+ columnList: included.map((c) => sanitizeIdentifier(c)).join(", "),
1121
+ hint: `Excluded ${excluded.length} long-content column(s) (${excluded.join(", ")}) to reduce payload. Use selectColumns to override.`
1122
+ };
1123
+ }
1124
+ return { columnList: "*" };
1125
+ }
1126
+ function sanitizePartitionBy(partitionBy) {
1127
+ const columns = partitionBy.split(",").map((c) => c.trim()).filter(Boolean);
1128
+ for (const col of columns) {
1129
+ validateIdentifier(col);
1130
+ }
1131
+ return columns.map((c) => sanitizeIdentifier(c)).join(", ");
1132
+ }
1133
+ function sanitizeOrderByExpr(orderBy) {
1134
+ const parts = orderBy.split(",");
1135
+ const sanitized = [];
1136
+ for (const part of parts) {
1137
+ const tokens = part.trim().split(/\s+/);
1138
+ const colToken = tokens[0];
1139
+ if (!colToken) continue;
1140
+ const colName = colToken.replace(/^"|"$/g, "");
1141
+ validateIdentifier(colName);
1142
+ const direction = tokens[1];
1143
+ if (direction && /^(ASC|DESC)$/i.test(direction)) {
1144
+ sanitized.push(
1145
+ `${sanitizeIdentifier(colName)} ${direction.toUpperCase()}`
1146
+ );
1147
+ } else {
1148
+ sanitized.push(sanitizeIdentifier(colName));
1149
+ }
1150
+ }
1151
+ return sanitized.join(", ");
1152
+ }
1153
+ function validateDefaultValue(value) {
1154
+ if (/^-?\d+(\.\d+)?$/.test(value)) return;
1155
+ if (/^'[^']*'$/.test(value)) return;
1156
+ if (/^NULL$/i.test(value)) return;
1157
+ throw new DbMcpError(
1158
+ `Invalid default value: '${value}'. Only numeric literals, single-quoted strings, or NULL are permitted.`,
1159
+ "NATIVE_WINDOW_INVALID_DEFAULT",
1160
+ "validation" /* VALIDATION */
1161
+ );
736
1162
  }
737
1163
  function getWindowTools(adapter) {
738
1164
  return [
@@ -754,28 +1180,41 @@ function createRowNumberTool(adapter) {
754
1180
  annotations: readOnly("Window Row Number"),
755
1181
  requiredScopes: ["read"],
756
1182
  handler: async (params, _context) => {
1183
+ const queryParams = [];
757
1184
  try {
758
1185
  const input = RowNumberSchema.parse(params);
759
1186
  await validateTableExists2(adapter, input.table);
760
1187
  await validateOrderByColumns(adapter, input.table, input.orderBy);
761
- const columns = formatColumns(input.selectColumns);
762
- const partition = input.partitionBy ? `PARTITION BY ${input.partitionBy}` : "";
1188
+ const { columnList: columns, hint } = await resolveSelectColumns(
1189
+ adapter,
1190
+ input.table,
1191
+ input.selectColumns
1192
+ );
1193
+ const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
1194
+ const orderByExpr = sanitizeOrderByExpr(input.orderBy);
763
1195
  let sql = `
764
1196
  SELECT ${columns},
765
- ROW_NUMBER() OVER (${partition} ORDER BY ${input.orderBy}) as row_number
766
- FROM "${input.table}"
1197
+ ROW_NUMBER() OVER (${partition} ORDER BY ${orderByExpr}) as row_number
1198
+ FROM ${sanitizeIdentifier(input.table)}
767
1199
  `;
768
- if (input.whereClause) {
769
- validateWhereClause(input.whereClause);
770
- sql += ` WHERE ${input.whereClause}`;
1200
+ if (input.conditions) {
1201
+ const { sql: whereSql, params: whereParams } = buildWhereClause(
1202
+ input.conditions
1203
+ );
1204
+ if (whereSql !== "") {
1205
+ sql += ` WHERE ${whereSql}`;
1206
+ queryParams.push(...whereParams);
1207
+ }
771
1208
  }
772
1209
  sql += ` LIMIT ${input.limit}`;
773
- const result = await adapter.executeReadQuery(sql);
774
- return {
1210
+ const result = await adapter.executeReadQuery(sql, queryParams);
1211
+ const response = {
775
1212
  success: true,
776
1213
  rowCount: result.rows?.length ?? 0,
777
1214
  rows: result.rows
778
1215
  };
1216
+ if (hint) response["hint"] = hint;
1217
+ return response;
779
1218
  } catch (error) {
780
1219
  return formatHandlerError(error);
781
1220
  }
@@ -794,28 +1233,41 @@ function createRankTool(adapter) {
794
1233
  handler: async (params, _context) => {
795
1234
  try {
796
1235
  const input = RankSchema.parse(params);
1236
+ const queryParams = [];
797
1237
  await validateTableExists2(adapter, input.table);
798
1238
  await validateOrderByColumns(adapter, input.table, input.orderBy);
799
- const columns = formatColumns(input.selectColumns);
800
- const partition = input.partitionBy ? `PARTITION BY ${input.partitionBy}` : "";
1239
+ const { columnList: columns, hint } = await resolveSelectColumns(
1240
+ adapter,
1241
+ input.table,
1242
+ input.selectColumns
1243
+ );
1244
+ const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
801
1245
  const rankFunc = input.rankType.toUpperCase();
1246
+ const orderByExpr = sanitizeOrderByExpr(input.orderBy);
802
1247
  let sql = `
803
1248
  SELECT ${columns},
804
- ${rankFunc}() OVER (${partition} ORDER BY ${input.orderBy}) as ${input.rankType}
805
- FROM "${input.table}"
1249
+ ${rankFunc}() OVER (${partition} ORDER BY ${orderByExpr}) as ${input.rankType}
1250
+ FROM ${sanitizeIdentifier(input.table)}
806
1251
  `;
807
- if (input.whereClause) {
808
- validateWhereClause(input.whereClause);
809
- sql += ` WHERE ${input.whereClause}`;
1252
+ if (input.conditions) {
1253
+ const { sql: whereSql, params: whereParams } = buildWhereClause(
1254
+ input.conditions
1255
+ );
1256
+ if (whereSql !== "") {
1257
+ sql += ` WHERE ${whereSql}`;
1258
+ queryParams.push(...whereParams);
1259
+ }
810
1260
  }
811
1261
  sql += ` LIMIT ${input.limit}`;
812
- const result = await adapter.executeReadQuery(sql);
813
- return {
1262
+ const result = await adapter.executeReadQuery(sql, queryParams);
1263
+ const response = {
814
1264
  success: true,
815
1265
  rankType: input.rankType,
816
1266
  rowCount: result.rows?.length ?? 0,
817
1267
  rows: result.rows
818
1268
  };
1269
+ if (hint) response["hint"] = hint;
1270
+ return response;
819
1271
  } catch (error) {
820
1272
  return formatHandlerError(error);
821
1273
  }
@@ -833,7 +1285,10 @@ function createLagLeadTool(adapter) {
833
1285
  requiredScopes: ["read"],
834
1286
  handler: async (params, _context) => {
835
1287
  try {
836
- const input = LagLeadSchema.parse(params);
1288
+ const input = LagLeadSchema.parse(
1289
+ resolveAliases(params, { valueColumn: "column" })
1290
+ );
1291
+ const queryParams = [];
837
1292
  const normalizedDirection = input.direction.toLowerCase();
838
1293
  if (!VALID_DIRECTIONS.includes(
839
1294
  normalizedDirection
@@ -849,28 +1304,45 @@ function createLagLeadTool(adapter) {
849
1304
  await validateTableExists2(adapter, input.table);
850
1305
  await validateColumnInTable(adapter, input.table, input.column);
851
1306
  await validateOrderByColumns(adapter, input.table, input.orderBy);
852
- const columns = formatColumns(input.selectColumns);
853
- const partition = input.partitionBy ? `PARTITION BY ${input.partitionBy}` : "";
1307
+ const { columnList: columns, hint } = await resolveSelectColumns(
1308
+ adapter,
1309
+ input.table,
1310
+ input.selectColumns,
1311
+ input.column
1312
+ );
1313
+ const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
854
1314
  const func = normalizedDirection.toUpperCase();
855
- const defaultVal = input.defaultValue !== void 0 ? `, ${input.defaultValue}` : "";
1315
+ let defaultVal = "";
1316
+ if (input.defaultValue !== void 0) {
1317
+ validateDefaultValue(input.defaultValue);
1318
+ defaultVal = `, ${input.defaultValue}`;
1319
+ }
1320
+ const orderByExpr = sanitizeOrderByExpr(input.orderBy);
856
1321
  let sql = `
857
1322
  SELECT ${columns},
858
- ${func}("${input.column}", ${input.offset}${defaultVal}) OVER (${partition} ORDER BY ${input.orderBy}) as ${normalizedDirection}_value
859
- FROM "${input.table}"
1323
+ ${func}(${sanitizeIdentifier(input.column)}, ${input.offset}${defaultVal}) OVER (${partition} ORDER BY ${orderByExpr}) as ${normalizedDirection}_value
1324
+ FROM ${sanitizeIdentifier(input.table)}
860
1325
  `;
861
- if (input.whereClause) {
862
- validateWhereClause(input.whereClause);
863
- sql += ` WHERE ${input.whereClause}`;
1326
+ if (input.conditions) {
1327
+ const { sql: whereSql, params: whereParams } = buildWhereClause(
1328
+ input.conditions
1329
+ );
1330
+ if (whereSql !== "") {
1331
+ sql += ` WHERE ${whereSql}`;
1332
+ queryParams.push(...whereParams);
1333
+ }
864
1334
  }
865
1335
  sql += ` LIMIT ${input.limit}`;
866
- const result = await adapter.executeReadQuery(sql);
867
- return {
1336
+ const result = await adapter.executeReadQuery(sql, queryParams);
1337
+ const response = {
868
1338
  success: true,
869
1339
  direction: normalizedDirection,
870
1340
  offset: input.offset,
871
1341
  rowCount: result.rows?.length ?? 0,
872
1342
  rows: result.rows
873
1343
  };
1344
+ if (hint) response["hint"] = hint;
1345
+ return response;
874
1346
  } catch (error) {
875
1347
  return formatHandlerError(error);
876
1348
  }
@@ -887,6 +1359,7 @@ function createRunningTotalTool(adapter) {
887
1359
  annotations: readOnly("Window Running Total"),
888
1360
  requiredScopes: ["read"],
889
1361
  handler: async (params, _context) => {
1362
+ const queryParams = [];
890
1363
  try {
891
1364
  const input = RunningTotalSchema.parse(
892
1365
  resolveAliases(params, { valueColumn: "column" })
@@ -894,25 +1367,38 @@ function createRunningTotalTool(adapter) {
894
1367
  await validateTableExists2(adapter, input.table);
895
1368
  await validateColumnInTable(adapter, input.table, input.column);
896
1369
  await validateOrderByColumns(adapter, input.table, input.orderBy);
897
- const columns = formatColumns(input.selectColumns);
898
- const partition = input.partitionBy ? `PARTITION BY ${input.partitionBy}` : "";
1370
+ const { columnList: columns, hint } = await resolveSelectColumns(
1371
+ adapter,
1372
+ input.table,
1373
+ input.selectColumns,
1374
+ input.column
1375
+ );
1376
+ const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
1377
+ const orderByExpr = sanitizeOrderByExpr(input.orderBy);
899
1378
  let sql = `
900
1379
  SELECT ${columns},
901
- SUM("${input.column}") OVER (${partition} ORDER BY ${input.orderBy} ROWS UNBOUNDED PRECEDING) as running_total
902
- FROM "${input.table}"
1380
+ SUM(${sanitizeIdentifier(input.column)}) OVER (${partition} ORDER BY ${orderByExpr} ROWS UNBOUNDED PRECEDING) as running_total
1381
+ FROM ${sanitizeIdentifier(input.table)}
903
1382
  `;
904
- if (input.whereClause) {
905
- validateWhereClause(input.whereClause);
906
- sql += ` WHERE ${input.whereClause}`;
1383
+ if (input.conditions) {
1384
+ const { sql: whereSql, params: whereParams } = buildWhereClause(
1385
+ input.conditions
1386
+ );
1387
+ if (whereSql !== "") {
1388
+ sql += ` WHERE ${whereSql}`;
1389
+ queryParams.push(...whereParams);
1390
+ }
907
1391
  }
908
1392
  sql += ` LIMIT ${input.limit}`;
909
- const result = await adapter.executeReadQuery(sql);
910
- return {
1393
+ const result = await adapter.executeReadQuery(sql, queryParams);
1394
+ const response = {
911
1395
  success: true,
912
1396
  valueColumn: input.column,
913
1397
  rowCount: result.rows?.length ?? 0,
914
1398
  rows: result.rows
915
1399
  };
1400
+ if (hint) response["hint"] = hint;
1401
+ return response;
916
1402
  } catch (error) {
917
1403
  return formatHandlerError(error);
918
1404
  }
@@ -929,43 +1415,48 @@ function createMovingAverageTool(adapter) {
929
1415
  annotations: readOnly("Window Moving Average"),
930
1416
  requiredScopes: ["read"],
931
1417
  handler: async (params, _context) => {
1418
+ const queryParams = [];
932
1419
  try {
933
1420
  const input = MovingAverageSchema.parse(
934
1421
  resolveAliases(params, { valueColumn: "column" })
935
1422
  );
936
- if (input.windowSize === void 0) {
937
- return {
938
- success: false,
939
- error: "'windowSize' is required",
940
- code: "VALIDATION_ERROR",
941
- category: "validation",
942
- recoverable: false
943
- };
944
- }
945
1423
  await validateTableExists2(adapter, input.table);
946
1424
  await validateColumnInTable(adapter, input.table, input.column);
947
1425
  await validateOrderByColumns(adapter, input.table, input.orderBy);
948
- const columns = formatColumns(input.selectColumns);
949
- const partition = input.partitionBy ? `PARTITION BY ${input.partitionBy}` : "";
1426
+ const { columnList: columns, hint } = await resolveSelectColumns(
1427
+ adapter,
1428
+ input.table,
1429
+ input.selectColumns,
1430
+ input.column
1431
+ );
1432
+ const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
950
1433
  const preceding = input.windowSize - 1;
1434
+ const orderByExpr = sanitizeOrderByExpr(input.orderBy);
951
1435
  let sql = `
952
1436
  SELECT ${columns},
953
- AVG("${input.column}") OVER (${partition} ORDER BY ${input.orderBy} ROWS BETWEEN ${preceding} PRECEDING AND CURRENT ROW) as moving_avg
954
- FROM "${input.table}"
1437
+ AVG(${sanitizeIdentifier(input.column)}) OVER (${partition} ORDER BY ${orderByExpr} ROWS BETWEEN ${preceding} PRECEDING AND CURRENT ROW) as moving_avg
1438
+ FROM ${sanitizeIdentifier(input.table)}
955
1439
  `;
956
- if (input.whereClause) {
957
- validateWhereClause(input.whereClause);
958
- sql += ` WHERE ${input.whereClause}`;
1440
+ if (input.conditions) {
1441
+ const { sql: whereSql, params: whereParams } = buildWhereClause(
1442
+ input.conditions
1443
+ );
1444
+ if (whereSql !== "") {
1445
+ sql += ` WHERE ${whereSql}`;
1446
+ queryParams.push(...whereParams);
1447
+ }
959
1448
  }
960
1449
  sql += ` LIMIT ${input.limit}`;
961
- const result = await adapter.executeReadQuery(sql);
962
- return {
1450
+ const result = await adapter.executeReadQuery(sql, queryParams);
1451
+ const response = {
963
1452
  success: true,
964
1453
  valueColumn: input.column,
965
1454
  windowSize: input.windowSize,
966
1455
  rowCount: result.rows?.length ?? 0,
967
1456
  rows: result.rows
968
1457
  };
1458
+ if (hint) response["hint"] = hint;
1459
+ return response;
969
1460
  } catch (error) {
970
1461
  return formatHandlerError(error);
971
1462
  }
@@ -984,43 +1475,54 @@ function createNtileTool(adapter) {
984
1475
  handler: async (params, _context) => {
985
1476
  try {
986
1477
  const input = NtileSchema.parse(params);
987
- if (input.buckets === void 0) {
988
- return {
989
- success: false,
990
- error: "'buckets' is required",
991
- code: "VALIDATION_ERROR",
992
- category: "validation",
993
- recoverable: false
994
- };
995
- }
1478
+ const queryParams = [];
996
1479
  await validateTableExists2(adapter, input.table);
997
1480
  await validateOrderByColumns(adapter, input.table, input.orderBy);
998
- const columns = formatColumns(input.selectColumns);
999
- const partition = input.partitionBy ? `PARTITION BY ${input.partitionBy}` : "";
1481
+ const { columnList: columns, hint } = await resolveSelectColumns(
1482
+ adapter,
1483
+ input.table,
1484
+ input.selectColumns
1485
+ );
1486
+ const partition = input.partitionBy ? `PARTITION BY ${sanitizePartitionBy(input.partitionBy)}` : "";
1487
+ const orderByExpr = sanitizeOrderByExpr(input.orderBy);
1000
1488
  let sql = `
1001
1489
  SELECT ${columns},
1002
- NTILE(${input.buckets}) OVER (${partition} ORDER BY ${input.orderBy}) as ntile
1003
- FROM "${input.table}"
1490
+ NTILE(${input.buckets}) OVER (${partition} ORDER BY ${orderByExpr}) as ntile
1491
+ FROM ${sanitizeIdentifier(input.table)}
1004
1492
  `;
1005
- if (input.whereClause) {
1006
- validateWhereClause(input.whereClause);
1007
- sql += ` WHERE ${input.whereClause}`;
1493
+ if (input.conditions) {
1494
+ const { sql: whereSql, params: whereParams } = buildWhereClause(
1495
+ input.conditions
1496
+ );
1497
+ if (whereSql !== "") {
1498
+ sql += ` WHERE ${whereSql}`;
1499
+ queryParams.push(...whereParams);
1500
+ }
1008
1501
  }
1009
1502
  sql += ` LIMIT ${input.limit}`;
1010
- const result = await adapter.executeReadQuery(sql);
1011
- return {
1503
+ const result = await adapter.executeReadQuery(sql, queryParams);
1504
+ const response = {
1012
1505
  success: true,
1013
1506
  buckets: input.buckets,
1014
1507
  rowCount: result.rows?.length ?? 0,
1015
1508
  rows: result.rows
1016
1509
  };
1510
+ if (hint) response["hint"] = hint;
1511
+ return response;
1017
1512
  } catch (error) {
1018
1513
  return formatHandlerError(error);
1019
1514
  }
1020
1515
  }
1021
1516
  };
1022
1517
  }
1023
- var coerceNumber2 = (val) => typeof val === "string" ? isNaN(Number(val)) ? void 0 : Number(val) : val;
1518
+ var coerceNumber2 = (val) => {
1519
+ if (typeof val === "string") {
1520
+ if (val.trim() === "") return void 0;
1521
+ const num = Number(val);
1522
+ return isNaN(num) ? val : num;
1523
+ }
1524
+ return val;
1525
+ };
1024
1526
  var coerceBoolean = (val) => typeof val === "string" ? val === "true" ? true : val === "false" ? false : void 0 : val;
1025
1527
  function createEnumCoercer(validValues) {
1026
1528
  return (val) => typeof val === "string" && validValues.includes(val) ? val : typeof val === "string" ? void 0 : val;
@@ -1051,9 +1553,20 @@ var VALID_OPERATIONS = [
1051
1553
  "envelope",
1052
1554
  "simplify"
1053
1555
  ];
1556
+ var VALID_COLUMN_TYPES = [
1557
+ "TEXT",
1558
+ "INTEGER",
1559
+ "REAL",
1560
+ "BLOB",
1561
+ "NUMERIC",
1562
+ "VARCHAR",
1563
+ "BOOLEAN",
1564
+ "DATE",
1565
+ "DATETIME",
1566
+ "TIMESTAMP"
1567
+ ];
1054
1568
  var coerceGeometryType = createEnumCoercer(VALID_GEOMETRY_TYPES);
1055
1569
  var LoadSpatialiteSchema = z.object({
1056
- extensionPath: z.string().optional().describe("Custom path to mod_spatialite extension"),
1057
1570
  forceReload: z.preprocess(
1058
1571
  coerceBoolean,
1059
1572
  z.boolean().optional().default(false).describe("Force reload if already loaded")
@@ -1081,7 +1594,7 @@ var CreateSpatialTableSchema = z.object({
1081
1594
  additionalColumns: z.array(
1082
1595
  z.object({
1083
1596
  name: z.string(),
1084
- type: z.string()
1597
+ type: z.enum(VALID_COLUMN_TYPES).optional().default("TEXT")
1085
1598
  })
1086
1599
  ).optional().default([]).describe("Additional non-spatial columns")
1087
1600
  });
@@ -1151,8 +1664,9 @@ var SpatialImportSchema = z.object({
1151
1664
  ),
1152
1665
  additionalData: z.record(z.string(), z.unknown()).optional().describe("Additional column values")
1153
1666
  });
1154
-
1155
- // src/adapters/sqlite-native/tools/spatialite/loader.ts
1667
+ var require2 = createRequire(import.meta.url);
1668
+ var __filename$1 = fileURLToPath(import.meta.url);
1669
+ var __dirname$1 = path2.dirname(__filename$1);
1156
1670
  var SPATIALITE_PATHS = [
1157
1671
  process.env["SPATIALITE_PATH"],
1158
1672
  "mod_spatialite",
@@ -1163,20 +1677,27 @@ var SPATIALITE_PATHS = [
1163
1677
  "/usr/local/lib/mod_spatialite.dylib"
1164
1678
  ].filter((p) => Boolean(p));
1165
1679
  var loadedDatabases = /* @__PURE__ */ new WeakSet();
1166
- function tryLoadSpatialite(adapter, customPath) {
1680
+ function tryLoadSpatialite(adapter) {
1167
1681
  const db = adapter.getDatabase();
1168
1682
  if (db === null) {
1169
1683
  return { success: false, error: "Database not connected" };
1170
1684
  }
1171
- const paths = customPath ? [customPath, ...SPATIALITE_PATHS] : SPATIALITE_PATHS;
1172
- const chosenPathForEnv = customPath ?? process.env["SPATIALITE_PATH"];
1685
+ const paths = SPATIALITE_PATHS;
1686
+ const chosenPathForEnv = process.env["SPATIALITE_PATH"];
1687
+ let dllCookie = null;
1688
+ let win32Dll = null;
1173
1689
  if (process.platform === "win32" && chosenPathForEnv) {
1174
1690
  const looksLikeFsPath = chosenPathForEnv.includes("/") || chosenPathForEnv.includes("\\");
1175
1691
  if (looksLikeFsPath) {
1176
1692
  const extensionDir = chosenPathForEnv.replace(/[/\\][^/\\]+$/, "");
1177
- const currentPath = process.env["PATH"] ?? "";
1178
- if (!currentPath.includes(extensionDir)) {
1179
- process.env["PATH"] = extensionDir + ";" + currentPath;
1693
+ try {
1694
+ const addonPath = path2.resolve(
1695
+ __dirname$1,
1696
+ "../../../../../build/Release/win32_dll.node"
1697
+ );
1698
+ win32Dll = require2(addonPath);
1699
+ dllCookie = win32Dll.addDllDirectory(extensionDir);
1700
+ } catch {
1180
1701
  }
1181
1702
  }
1182
1703
  }
@@ -1185,10 +1706,16 @@ function tryLoadSpatialite(adapter, customPath) {
1185
1706
  db.loadExtension(candidatePath);
1186
1707
  db.exec("SELECT InitSpatialMetaData(1)");
1187
1708
  loadedDatabases.add(db);
1709
+ if (win32Dll !== null && dllCookie !== null) {
1710
+ win32Dll.removeDllDirectory(dllCookie);
1711
+ }
1188
1712
  return { success: true, path: candidatePath };
1189
1713
  } catch {
1190
1714
  }
1191
1715
  }
1716
+ if (win32Dll !== null && dllCookie !== null) {
1717
+ win32Dll.removeDllDirectory(dllCookie);
1718
+ }
1192
1719
  return {
1193
1720
  success: false,
1194
1721
  error: "SpatiaLite extension not found. Install mod_spatialite and set SPATIALITE_PATH environment variable."
@@ -1211,11 +1738,9 @@ function ensureSpatialite(adapter) {
1211
1738
  if (!isSpatialiteLoaded(adapter)) {
1212
1739
  const result = tryLoadSpatialite(adapter);
1213
1740
  if (!result.success) {
1214
- throw new DbMcpError(
1215
- result.error ?? "Failed to load SpatiaLite",
1216
- "SPATIALITE_LOAD_FAILED",
1217
- "connection" /* CONNECTION */
1218
- );
1741
+ throw new ExtensionNotAvailableError("SpatiaLite", {
1742
+ suggestion: "Install mod_spatialite and set SPATIALITE_PATH environment variable."
1743
+ });
1219
1744
  }
1220
1745
  }
1221
1746
  }
@@ -1240,7 +1765,7 @@ function createLoadSpatialiteTool(adapter) {
1240
1765
  alreadyLoaded: true
1241
1766
  });
1242
1767
  }
1243
- const result = tryLoadSpatialite(adapter, input.extensionPath);
1768
+ const result = tryLoadSpatialite(adapter);
1244
1769
  if (result.success) {
1245
1770
  return Promise.resolve({
1246
1771
  success: true,
@@ -1275,7 +1800,9 @@ function createSpatialTableTool(adapter) {
1275
1800
  try {
1276
1801
  const input = CreateSpatialTableSchema.parse(params);
1277
1802
  ensureSpatialite(adapter);
1278
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(input.tableName)) {
1803
+ try {
1804
+ validateIdentifier(input.tableName);
1805
+ } catch {
1279
1806
  return {
1280
1807
  success: false,
1281
1808
  error: `Invalid table name: '${input.tableName}'`,
@@ -1284,8 +1811,20 @@ function createSpatialTableTool(adapter) {
1284
1811
  recoverable: false
1285
1812
  };
1286
1813
  }
1814
+ try {
1815
+ validateIdentifier(input.geometryColumn);
1816
+ } catch {
1817
+ return {
1818
+ success: false,
1819
+ error: `Invalid geometry column name: '${input.geometryColumn}'`,
1820
+ code: "VALIDATION_ERROR",
1821
+ category: "validation",
1822
+ recoverable: false
1823
+ };
1824
+ }
1287
1825
  const existsCheck = await adapter.executeReadQuery(
1288
- `SELECT name FROM sqlite_master WHERE type='table' AND name='${input.tableName}'`
1826
+ `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
1827
+ [input.tableName]
1289
1828
  );
1290
1829
  const alreadyExists = existsCheck.rows != null && existsCheck.rows.length > 0;
1291
1830
  if (alreadyExists) {
@@ -1298,7 +1837,9 @@ function createSpatialTableTool(adapter) {
1298
1837
  }
1299
1838
  const columns = ["id INTEGER PRIMARY KEY AUTOINCREMENT"];
1300
1839
  for (const col of input.additionalColumns) {
1301
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(col.name)) {
1840
+ try {
1841
+ validateIdentifier(col.name);
1842
+ } catch {
1302
1843
  return {
1303
1844
  success: false,
1304
1845
  error: `Invalid column name: '${col.name}'`,
@@ -1307,10 +1848,10 @@ function createSpatialTableTool(adapter) {
1307
1848
  recoverable: false
1308
1849
  };
1309
1850
  }
1310
- columns.push(`"${col.name}" ${col.type}`);
1851
+ columns.push(`${sanitizeIdentifier(col.name)} ${col.type}`);
1311
1852
  }
1312
1853
  await adapter.executeWriteQuery(
1313
- `CREATE TABLE "${input.tableName}" (${columns.join(", ")})`
1854
+ `CREATE TABLE ${sanitizeIdentifier(input.tableName)} (${columns.join(", ")})`
1314
1855
  );
1315
1856
  const addResult = await adapter.executeReadQuery(
1316
1857
  `SELECT AddGeometryColumn('${input.tableName}', '${input.geometryColumn}', ${input.srid}, '${input.geometryType}', 'XY')`
@@ -1389,7 +1930,9 @@ function createSpatialIndexTool(adapter) {
1389
1930
  try {
1390
1931
  const input = SpatialIndexSchema.parse(params);
1391
1932
  ensureSpatialite(adapter);
1392
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(input.tableName)) {
1933
+ try {
1934
+ validateIdentifier(input.tableName);
1935
+ } catch {
1393
1936
  return {
1394
1937
  success: false,
1395
1938
  error: `Invalid table name: '${input.tableName}'`,
@@ -1407,8 +1950,20 @@ function createSpatialIndexTool(adapter) {
1407
1950
  recoverable: false
1408
1951
  };
1409
1952
  }
1953
+ try {
1954
+ validateIdentifier(input.geometryColumn);
1955
+ } catch {
1956
+ return {
1957
+ success: false,
1958
+ error: `Invalid geometry column name: '${input.geometryColumn}'`,
1959
+ code: "VALIDATION_ERROR",
1960
+ category: "validation",
1961
+ recoverable: false
1962
+ };
1963
+ }
1410
1964
  const tableCheck = await adapter.executeReadQuery(
1411
- `SELECT name FROM sqlite_master WHERE type='table' AND name='${input.tableName}'`
1965
+ `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
1966
+ [input.tableName]
1412
1967
  );
1413
1968
  if (!tableCheck.rows || tableCheck.rows.length === 0) {
1414
1969
  return {
@@ -1422,9 +1977,10 @@ function createSpatialIndexTool(adapter) {
1422
1977
  }
1423
1978
  const indexExists = async () => {
1424
1979
  const idxCheck = await adapter.executeReadQuery(
1425
- `SELECT name FROM sqlite_master WHERE type='table' AND name='idx_${input.tableName}_${input.geometryColumn}'`
1980
+ `SELECT spatial_index_enabled FROM geometry_columns WHERE f_table_name = '${input.tableName}' AND f_geometry_column = '${input.geometryColumn}'`
1426
1981
  );
1427
- return (idxCheck.rows?.length ?? 0) > 0;
1982
+ const val = idxCheck.rows?.[0]?.["spatial_index_enabled"];
1983
+ return val === 1 || val === "1";
1428
1984
  };
1429
1985
  switch (input.action) {
1430
1986
  case "create": {
@@ -1436,9 +1992,18 @@ function createSpatialIndexTool(adapter) {
1436
1992
  action: "create"
1437
1993
  };
1438
1994
  }
1439
- await adapter.executeReadQuery(
1440
- `SELECT CreateSpatialIndex('${input.tableName}', '${input.geometryColumn}')`
1995
+ const createRes = await adapter.executeReadQuery(
1996
+ `SELECT CreateSpatialIndex('${input.tableName}', '${input.geometryColumn}') as res`
1441
1997
  );
1998
+ if (createRes.rows?.[0]?.["res"] === 0) {
1999
+ return {
2000
+ success: false,
2001
+ error: `Failed to create spatial index on ${input.tableName}.${input.geometryColumn}`,
2002
+ code: "SPATIAL_INDEX_CREATE_FAILED",
2003
+ category: "internal",
2004
+ recoverable: false
2005
+ };
2006
+ }
1442
2007
  return {
1443
2008
  success: true,
1444
2009
  message: `Spatial index created on ${input.tableName}.${input.geometryColumn}`,
@@ -1454,9 +2019,18 @@ function createSpatialIndexTool(adapter) {
1454
2019
  action: "drop"
1455
2020
  };
1456
2021
  }
1457
- await adapter.executeReadQuery(
1458
- `SELECT DisableSpatialIndex('${input.tableName}', '${input.geometryColumn}')`
2022
+ const dropRes = await adapter.executeReadQuery(
2023
+ `SELECT DisableSpatialIndex('${input.tableName}', '${input.geometryColumn}') as res`
1459
2024
  );
2025
+ if (dropRes.rows?.[0]?.["res"] === 0) {
2026
+ return {
2027
+ success: false,
2028
+ error: `Failed to drop spatial index on ${input.tableName}.${input.geometryColumn}`,
2029
+ code: "SPATIAL_INDEX_DROP_FAILED",
2030
+ category: "internal",
2031
+ recoverable: false
2032
+ };
2033
+ }
1460
2034
  return {
1461
2035
  success: true,
1462
2036
  message: `Spatial index dropped from ${input.tableName}.${input.geometryColumn}`,
@@ -1531,6 +2105,7 @@ function createSpatialAnalysisTool(adapter) {
1531
2105
  requiredScopes: ["read"],
1532
2106
  annotations: readOnly("SpatiaLite Analyze"),
1533
2107
  handler: async (params, _context) => {
2108
+ const queryParams = [];
1534
2109
  try {
1535
2110
  const input = SpatialAnalysisSchema.parse(params);
1536
2111
  ensureSpatialite(adapter);
@@ -1545,7 +2120,9 @@ function createSpatialAnalysisTool(adapter) {
1545
2120
  recoverable: false
1546
2121
  };
1547
2122
  }
1548
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(input.sourceTable)) {
2123
+ try {
2124
+ validateIdentifier(input.sourceTable);
2125
+ } catch {
1549
2126
  return {
1550
2127
  success: false,
1551
2128
  error: `Invalid source table name: '${input.sourceTable}'`,
@@ -1554,10 +2131,25 @@ function createSpatialAnalysisTool(adapter) {
1554
2131
  recoverable: false
1555
2132
  };
1556
2133
  }
1557
- if (input.targetTable && !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(input.targetTable)) {
2134
+ if (input.targetTable) {
2135
+ try {
2136
+ validateIdentifier(input.targetTable);
2137
+ } catch {
2138
+ return {
2139
+ success: false,
2140
+ error: `Invalid target table name: '${input.targetTable}'`,
2141
+ code: "VALIDATION_ERROR",
2142
+ category: "validation",
2143
+ recoverable: false
2144
+ };
2145
+ }
2146
+ }
2147
+ try {
2148
+ validateIdentifier(input.geometryColumn);
2149
+ } catch {
1558
2150
  return {
1559
2151
  success: false,
1560
- error: `Invalid target table name: '${input.targetTable}'`,
2152
+ error: `Invalid geometry column name: '${input.geometryColumn}'`,
1561
2153
  code: "VALIDATION_ERROR",
1562
2154
  category: "validation",
1563
2155
  recoverable: false
@@ -1565,15 +2157,18 @@ function createSpatialAnalysisTool(adapter) {
1565
2157
  }
1566
2158
  let query;
1567
2159
  switch (input.analysisType) {
1568
- case "spatial_extent":
2160
+ case "spatial_extent": {
2161
+ const geomCol = sanitizeIdentifier(input.geometryColumn);
2162
+ const srcTable = sanitizeIdentifier(input.sourceTable);
1569
2163
  query = `SELECT
1570
- MbrMinX(Extent("${input.geometryColumn}")) as min_x,
1571
- MbrMinY(Extent("${input.geometryColumn}")) as min_y,
1572
- MbrMaxX(Extent("${input.geometryColumn}")) as max_x,
1573
- MbrMaxY(Extent("${input.geometryColumn}")) as max_y,
2164
+ MbrMinX(Extent(${geomCol})) as min_x,
2165
+ MbrMinY(Extent(${geomCol})) as min_y,
2166
+ MbrMaxX(Extent(${geomCol})) as max_x,
2167
+ MbrMaxY(Extent(${geomCol})) as max_y,
1574
2168
  COUNT(*) as feature_count
1575
- FROM "${input.sourceTable}"`;
2169
+ FROM ${srcTable}`;
1576
2170
  break;
2171
+ }
1577
2172
  case "nearest_neighbor": {
1578
2173
  if (!input.targetTable) {
1579
2174
  return {
@@ -1584,13 +2179,16 @@ function createSpatialAnalysisTool(adapter) {
1584
2179
  recoverable: false
1585
2180
  };
1586
2181
  }
2182
+ const geomCol = sanitizeIdentifier(input.geometryColumn);
2183
+ const srcTable = sanitizeIdentifier(input.sourceTable);
2184
+ const tgtTable = sanitizeIdentifier(input.targetTable);
1587
2185
  const sameTable = input.sourceTable === input.targetTable;
1588
2186
  const selfFilter = sameTable && input.excludeSelf ? "WHERE s.id != t.id" : "";
1589
- const geomColumns = input.includeGeometry ? `, AsText(s."${input.geometryColumn}") as source_geom, AsText(t."${input.geometryColumn}") as target_geom` : "";
2187
+ const geomColumns = input.includeGeometry ? `, AsText(s.${geomCol}) as source_geom, AsText(t.${geomCol}) as target_geom` : "";
1590
2188
  query = `SELECT
1591
2189
  s.id as source_id, t.id as target_id,
1592
- ST_Distance(s."${input.geometryColumn}", t."${input.geometryColumn}") as distance${geomColumns}
1593
- FROM "${input.sourceTable}" s, "${input.targetTable}" t
2190
+ ST_Distance(s.${geomCol}, t.${geomCol}) as distance${geomColumns}
2191
+ FROM ${srcTable} s, ${tgtTable} t
1594
2192
  ${selfFilter}
1595
2193
  ORDER BY distance LIMIT ${input.limit}`;
1596
2194
  break;
@@ -1605,11 +2203,14 @@ function createSpatialAnalysisTool(adapter) {
1605
2203
  recoverable: false
1606
2204
  };
1607
2205
  }
1608
- const geomCols = input.includeGeometry ? `, AsText(s."${input.geometryColumn}") as source_geom, AsText(t."${input.geometryColumn}") as target_geom` : "";
2206
+ const geomCol = sanitizeIdentifier(input.geometryColumn);
2207
+ const srcTable = sanitizeIdentifier(input.sourceTable);
2208
+ const tgtTable = sanitizeIdentifier(input.targetTable);
2209
+ const geomCols = input.includeGeometry ? `, AsText(s.${geomCol}) as source_geom, AsText(t.${geomCol}) as target_geom` : "";
1609
2210
  query = `SELECT
1610
2211
  s.id as source_id, t.id as target_id${geomCols}
1611
- FROM "${input.sourceTable}" s, "${input.targetTable}" t
1612
- WHERE ST_Within(s."${input.geometryColumn}", t."${input.geometryColumn}")
2212
+ FROM ${srcTable} s, ${tgtTable} t
2213
+ WHERE ST_Within(s.${geomCol}, t.${geomCol})
1613
2214
  LIMIT ${input.limit}`;
1614
2215
  break;
1615
2216
  }
@@ -1617,9 +2218,12 @@ function createSpatialAnalysisTool(adapter) {
1617
2218
  const dmTarget = input.targetTable ?? input.sourceTable;
1618
2219
  const dmSameTable = dmTarget === input.sourceTable;
1619
2220
  const dmFilter = dmSameTable ? "WHERE a.id < b.id" : "";
2221
+ const geomCol = sanitizeIdentifier(input.geometryColumn);
2222
+ const srcTable = sanitizeIdentifier(input.sourceTable);
2223
+ const dmTgtTable = sanitizeIdentifier(dmTarget);
1620
2224
  query = `SELECT a.id as id1, b.id as id2,
1621
- ST_Distance(a."${input.geometryColumn}", b."${input.geometryColumn}") as distance
1622
- FROM "${input.sourceTable}" a, "${dmTarget}" b
2225
+ ST_Distance(a.${geomCol}, b.${geomCol}) as distance
2226
+ FROM ${srcTable} a, ${dmTgtTable} b
1623
2227
  ${dmFilter}
1624
2228
  ORDER BY distance LIMIT ${input.limit}`;
1625
2229
  break;
@@ -1627,7 +2231,7 @@ function createSpatialAnalysisTool(adapter) {
1627
2231
  default:
1628
2232
  query = "SELECT 1";
1629
2233
  }
1630
- const result = await adapter.executeReadQuery(query);
2234
+ const result = await adapter.executeReadQuery(query, queryParams);
1631
2235
  return {
1632
2236
  success: true,
1633
2237
  analysisType: input.analysisType,
@@ -1650,6 +2254,7 @@ function createGeometryTransformTool(adapter) {
1650
2254
  requiredScopes: ["read"],
1651
2255
  annotations: readOnly("SpatiaLite Transform"),
1652
2256
  handler: async (params, _context) => {
2257
+ const queryParams = [];
1653
2258
  try {
1654
2259
  const input = GeometryTransformSchema.parse(params);
1655
2260
  ensureSpatialite(adapter);
@@ -1665,71 +2270,69 @@ function createGeometryTransformTool(adapter) {
1665
2270
  let query;
1666
2271
  switch (input.operation) {
1667
2272
  case "buffer": {
1668
- const bufferGeom = `Buffer(GeomFromText('${input.geometry1}', ${input.srid}), ${input.distance})`;
2273
+ const bufferGeom = `Buffer(GeomFromText(?, CAST(? AS INTEGER)), ?)`;
1669
2274
  const defaultTolerance = Math.max(1e-4, input.distance * 0.01);
1670
2275
  const tolerance = input.simplifyTolerance ?? defaultTolerance;
1671
- const finalGeom = tolerance > 0 ? `Simplify(${bufferGeom}, ${tolerance})` : bufferGeom;
2276
+ const finalGeom = tolerance > 0 ? `Simplify(${bufferGeom}, ${String(tolerance)})` : bufferGeom;
1672
2277
  query = `SELECT AsText(${finalGeom}) as result`;
2278
+ queryParams.push(input.geometry1, input.srid, input.distance);
1673
2279
  break;
1674
2280
  }
1675
- case "intersection":
1676
- if (!input.geometry2) {
1677
- return {
1678
- success: false,
1679
- error: "Second geometry required for intersection",
1680
- code: "VALIDATION_ERROR",
1681
- category: "validation",
1682
- recoverable: false
1683
- };
1684
- }
1685
- query = `SELECT AsText(Intersection(
1686
- GeomFromText('${input.geometry1}', ${input.srid}),
1687
- GeomFromText('${input.geometry2}', ${input.srid})
1688
- )) as result`;
2281
+ case "intersection": {
2282
+ const intersectionGeom = `Intersection(GeomFromText(?, CAST(? AS INTEGER)), GeomFromText(?, CAST(? AS INTEGER)))`;
2283
+ query = `SELECT AsText(${intersectionGeom}) as result`;
2284
+ queryParams.push(
2285
+ input.geometry1,
2286
+ input.srid,
2287
+ input.geometry2,
2288
+ input.srid
2289
+ );
1689
2290
  break;
1690
- case "union":
1691
- if (!input.geometry2) {
1692
- return {
1693
- success: false,
1694
- error: "Second geometry required for union",
1695
- code: "VALIDATION_ERROR",
1696
- category: "validation",
1697
- recoverable: false
1698
- };
1699
- }
1700
- query = `SELECT AsText(GUnion(
1701
- GeomFromText('${input.geometry1}', ${input.srid}),
1702
- GeomFromText('${input.geometry2}', ${input.srid})
1703
- )) as result`;
2291
+ }
2292
+ case "union": {
2293
+ const unionGeom = `GUnion(GeomFromText(?, CAST(? AS INTEGER)), GeomFromText(?, CAST(? AS INTEGER)))`;
2294
+ query = `SELECT AsText(${unionGeom}) as result`;
2295
+ queryParams.push(
2296
+ input.geometry1,
2297
+ input.srid,
2298
+ input.geometry2,
2299
+ input.srid
2300
+ );
1704
2301
  break;
1705
- case "difference":
1706
- if (!input.geometry2) {
1707
- return {
1708
- success: false,
1709
- error: "Second geometry required for difference",
1710
- code: "VALIDATION_ERROR",
1711
- category: "validation",
1712
- recoverable: false
1713
- };
1714
- }
1715
- query = `SELECT AsText(Difference(
1716
- GeomFromText('${input.geometry1}', ${input.srid}),
1717
- GeomFromText('${input.geometry2}', ${input.srid})
1718
- )) as result`;
2302
+ }
2303
+ case "difference": {
2304
+ const differenceGeom = `Difference(GeomFromText(?, CAST(? AS INTEGER)), GeomFromText(?, CAST(? AS INTEGER)))`;
2305
+ query = `SELECT AsText(${differenceGeom}) as result`;
2306
+ queryParams.push(
2307
+ input.geometry1,
2308
+ input.srid,
2309
+ input.geometry2,
2310
+ input.srid
2311
+ );
1719
2312
  break;
1720
- case "centroid":
1721
- query = `SELECT AsText(Centroid(GeomFromText('${input.geometry1}', ${input.srid}))) as result`;
2313
+ }
2314
+ case "centroid": {
2315
+ const centroidGeom = `Centroid(GeomFromText(?, CAST(? AS INTEGER)))`;
2316
+ query = `SELECT AsText(${centroidGeom}) as result`;
2317
+ queryParams.push(input.geometry1, input.srid);
1722
2318
  break;
1723
- case "envelope":
1724
- query = `SELECT AsText(Envelope(GeomFromText('${input.geometry1}', ${input.srid}))) as result`;
2319
+ }
2320
+ case "envelope": {
2321
+ const envelopeGeom = `Envelope(GeomFromText(?, CAST(? AS INTEGER)))`;
2322
+ query = `SELECT AsText(${envelopeGeom}) as result`;
2323
+ queryParams.push(input.geometry1, input.srid);
1725
2324
  break;
1726
- case "simplify":
1727
- query = `SELECT AsText(Simplify(GeomFromText('${input.geometry1}', ${input.srid}), ${input.distance})) as result`;
2325
+ }
2326
+ case "simplify": {
2327
+ const simplifyGeom = `Simplify(GeomFromText(?, CAST(? AS INTEGER)), ?)`;
2328
+ query = `SELECT AsText(${simplifyGeom}) as result`;
2329
+ queryParams.push(input.geometry1, input.srid, input.distance);
1728
2330
  break;
2331
+ }
1729
2332
  default:
1730
2333
  query = "SELECT 1";
1731
2334
  }
1732
- const result = await adapter.executeReadQuery(query);
2335
+ const result = await adapter.executeReadQuery(query, queryParams);
1733
2336
  const wktResult = result.rows?.[0]?.["result"];
1734
2337
  if (wktResult === null || wktResult === void 0) {
1735
2338
  return {
@@ -1759,7 +2362,7 @@ function createSpatialImportTool(adapter) {
1759
2362
  inputSchema: SpatialImportSchema,
1760
2363
  outputSchema: SpatialiteImportOutputSchema,
1761
2364
  requiredScopes: ["write"],
1762
- annotations: write("SpatiaLite Import"),
2365
+ annotations: writeFs("SpatiaLite Import"),
1763
2366
  handler: async (params, _context) => {
1764
2367
  try {
1765
2368
  const input = SpatialImportSchema.parse(params);
@@ -1773,7 +2376,9 @@ function createSpatialImportTool(adapter) {
1773
2376
  recoverable: false
1774
2377
  };
1775
2378
  }
1776
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(input.tableName)) {
2379
+ try {
2380
+ validateIdentifier(input.tableName);
2381
+ } catch {
1777
2382
  return {
1778
2383
  success: false,
1779
2384
  error: `Invalid table name: '${input.tableName}'`,
@@ -1786,10 +2391,23 @@ function createSpatialImportTool(adapter) {
1786
2391
  if (input.format === "geojson") {
1787
2392
  try {
1788
2393
  JSON.parse(input.data);
2394
+ const geojsonCheck = await adapter.executeReadQuery(
2395
+ `SELECT ST_IsValid(GeomFromGeoJSON(?)) as valid`,
2396
+ [input.data]
2397
+ );
2398
+ const isValid2 = geojsonCheck.rows?.[0]?.["valid"];
2399
+ if (isValid2 !== 1) {
2400
+ return {
2401
+ success: false,
2402
+ error: `Invalid GeoJSON geometry: could not be parsed by SpatiaLite (must be a valid Geometry object)`,
2403
+ code: "VALIDATION_ERROR",
2404
+ category: "validation",
2405
+ recoverable: false
2406
+ };
2407
+ }
1789
2408
  const columns2 = ["geom"];
1790
- const values2 = [
1791
- `SetSRID(GeomFromGeoJSON('${input.data}'), ${input.srid})`
1792
- ];
2409
+ const placeholders2 = [`SetSRID(GeomFromGeoJSON(?), ?)`];
2410
+ const insertParams2 = [input.data, input.srid];
1793
2411
  if (input.additionalData) {
1794
2412
  for (const [key, value] of Object.entries(input.additionalData)) {
1795
2413
  if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
@@ -1801,14 +2419,16 @@ function createSpatialImportTool(adapter) {
1801
2419
  recoverable: false
1802
2420
  };
1803
2421
  }
1804
- columns2.push(`"${key}"`);
1805
- values2.push(
1806
- typeof value === "string" ? `'${value.replace(/'/g, "''")}'` : String(value)
1807
- );
2422
+ columns2.push(sanitizeIdentifier(key));
2423
+ placeholders2.push("?");
2424
+ insertParams2.push(value);
1808
2425
  }
1809
2426
  }
1810
- const sql2 = `INSERT INTO "${input.tableName}" (${columns2.join(", ")}) VALUES (${values2.join(", ")})`;
1811
- const insertResult2 = await adapter.executeWriteQuery(sql2);
2427
+ const sql2 = `INSERT INTO ${sanitizeIdentifier(input.tableName)} (${columns2.join(", ")}) VALUES (${placeholders2.join(", ")})`;
2428
+ const insertResult2 = await adapter.executeWriteQuery(
2429
+ sql2,
2430
+ insertParams2
2431
+ );
1812
2432
  return {
1813
2433
  success: true,
1814
2434
  message: "GeoJSON geometry imported",
@@ -1827,10 +2447,11 @@ function createSpatialImportTool(adapter) {
1827
2447
  wkt = input.data;
1828
2448
  }
1829
2449
  const wktCheck = await adapter.executeReadQuery(
1830
- `SELECT GeomFromText('${wkt}', ${input.srid}) as geom`
2450
+ `SELECT ST_IsValid(GeomFromText(?, CAST(? AS INTEGER))) as valid`,
2451
+ [wkt, input.srid]
1831
2452
  );
1832
- const parsedGeom = wktCheck.rows?.[0]?.["geom"];
1833
- if (parsedGeom === null || parsedGeom === void 0) {
2453
+ const isValid = wktCheck.rows?.[0]?.["valid"];
2454
+ if (isValid !== 1) {
1834
2455
  return {
1835
2456
  success: false,
1836
2457
  error: `Invalid WKT geometry: '${wkt}' could not be parsed`,
@@ -1840,7 +2461,8 @@ function createSpatialImportTool(adapter) {
1840
2461
  };
1841
2462
  }
1842
2463
  const columns = ["geom"];
1843
- const values = [`GeomFromText('${wkt}', ${input.srid})`];
2464
+ const placeholders = [`GeomFromText(?, CAST(? AS INTEGER))`];
2465
+ const insertParams = [wkt, input.srid];
1844
2466
  if (input.additionalData) {
1845
2467
  for (const [key, value] of Object.entries(input.additionalData)) {
1846
2468
  if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
@@ -1852,14 +2474,13 @@ function createSpatialImportTool(adapter) {
1852
2474
  recoverable: false
1853
2475
  };
1854
2476
  }
1855
- columns.push(`"${key}"`);
1856
- values.push(
1857
- typeof value === "string" ? `'${value.replace(/'/g, "''")}'` : String(value)
1858
- );
2477
+ columns.push(sanitizeIdentifier(key));
2478
+ placeholders.push("?");
2479
+ insertParams.push(value);
1859
2480
  }
1860
2481
  }
1861
- const sql = `INSERT INTO "${input.tableName}" (${columns.join(", ")}) VALUES (${values.join(", ")})`;
1862
- const insertResult = await adapter.executeWriteQuery(sql);
2482
+ const sql = `INSERT INTO ${sanitizeIdentifier(input.tableName)} (${columns.join(", ")}) VALUES (${placeholders.join(", ")})`;
2483
+ const insertResult = await adapter.executeWriteQuery(sql, insertParams);
1863
2484
  return {
1864
2485
  success: true,
1865
2486
  message: "WKT geometry imported",
@@ -1920,16 +2541,16 @@ function getNativeToolDefinitions(adapter) {
1920
2541
  function findProjectRoot(startDir) {
1921
2542
  let dir = startDir;
1922
2543
  for (let i = 0; i < 10; i++) {
1923
- if (fs.existsSync(path.join(dir, "package.json"))) return dir;
1924
- const parent = path.dirname(dir);
2544
+ if (fs.existsSync(path2.join(dir, "package.json"))) return dir;
2545
+ const parent = path2.dirname(dir);
1925
2546
  if (parent === dir) break;
1926
2547
  dir = parent;
1927
2548
  }
1928
2549
  return startDir;
1929
2550
  }
1930
2551
  var __moduleFilename = fileURLToPath(import.meta.url);
1931
- var PROJECT_ROOT = findProjectRoot(path.dirname(__moduleFilename));
1932
- var EXTENSIONS_DIR = path.join(PROJECT_ROOT, "extensions");
2552
+ var PROJECT_ROOT = findProjectRoot(path2.dirname(__moduleFilename));
2553
+ var EXTENSIONS_DIR = path2.join(PROJECT_ROOT, "extensions");
1933
2554
  function tryLoadExtension(db, name, envVar, candidates, log2) {
1934
2555
  for (const extPath of candidates) {
1935
2556
  try {
@@ -1949,12 +2570,12 @@ function loadSpatialite(db, log2) {
1949
2570
  const spatialitePaths = [
1950
2571
  process.env["SPATIALITE_PATH"],
1951
2572
  // Absolute paths to local extensions
1952
- path.join(
2573
+ path2.join(
1953
2574
  EXTENSIONS_DIR,
1954
2575
  "mod_spatialite-5.1.0-win-amd64",
1955
2576
  "mod_spatialite"
1956
2577
  ),
1957
- path.join(
2578
+ path2.join(
1958
2579
  EXTENSIONS_DIR,
1959
2580
  "mod_spatialite-5.1.0-win-amd64",
1960
2581
  "mod_spatialite.dll"
@@ -1968,7 +2589,7 @@ function loadSpatialite(db, log2) {
1968
2589
  ].filter((p) => Boolean(p));
1969
2590
  const envSpatialitePath = process.env["SPATIALITE_PATH"];
1970
2591
  if (envSpatialitePath && process.platform === "win32") {
1971
- const spatialiteExtDir = path.dirname(envSpatialitePath);
2592
+ const spatialiteExtDir = path2.dirname(envSpatialitePath);
1972
2593
  const currentPath = process.env["PATH"] ?? "";
1973
2594
  if (!currentPath.includes(spatialiteExtDir)) {
1974
2595
  process.env["PATH"] = spatialiteExtDir + ";" + currentPath;
@@ -1980,8 +2601,8 @@ function loadCsvExtension(db, log2) {
1980
2601
  const csvPaths = [
1981
2602
  process.env["CSV_EXTENSION_PATH"],
1982
2603
  // sqlite-xsv extension with absolute paths
1983
- path.join(EXTENSIONS_DIR, "xsv0.dll"),
1984
- path.join(EXTENSIONS_DIR, "xsv0"),
2604
+ path2.join(EXTENSIONS_DIR, "xsv0.dll"),
2605
+ path2.join(EXTENSIONS_DIR, "xsv0"),
1985
2606
  // System paths
1986
2607
  "xsv0",
1987
2608
  "xsv0.dll",
@@ -2043,18 +2664,7 @@ function nativeExecuteRead(db, sql, params, log2) {
2043
2664
  executionTimeMs: Date.now() - start
2044
2665
  });
2045
2666
  } catch (error) {
2046
- const message = error instanceof Error ? error.message : String(error);
2047
- log2.error(`Query failed: ${message}`, {
2048
- code: ERROR_CODES.DB.QUERY_FAILED.full
2049
- });
2050
- throw new QueryError(
2051
- `Query execution failed: ${message}`,
2052
- "DB_QUERY_FAILED",
2053
- {
2054
- sql,
2055
- cause: error instanceof Error ? error : void 0
2056
- }
2057
- );
2667
+ translateSqliteError(error, sql, "Query execution", log2);
2058
2668
  }
2059
2669
  }
2060
2670
  function nativeExecuteWrite(db, sql, params, log2) {
@@ -2062,21 +2672,27 @@ function nativeExecuteWrite(db, sql, params, log2) {
2062
2672
  try {
2063
2673
  const stmt = db.prepare(sql);
2064
2674
  const normalizedParams = normalizeSqliteParams(params);
2675
+ if (stmt.reader) {
2676
+ const rows = normalizedParams ? stmt.all(...normalizedParams) : stmt.all();
2677
+ return Promise.resolve({
2678
+ rows,
2679
+ rowsAffected: rows.length,
2680
+ // .all() does not return changes, but we know it's rows.length for RETURNING
2681
+ executionTimeMs: Date.now() - start
2682
+ });
2683
+ }
2065
2684
  const info = normalizedParams ? stmt.run(...normalizedParams) : stmt.run();
2066
- return Promise.resolve({
2685
+ const result = {
2067
2686
  rows: [],
2068
2687
  rowsAffected: info.changes,
2069
2688
  executionTimeMs: Date.now() - start
2070
- });
2689
+ };
2690
+ if (info.lastInsertRowid !== void 0) {
2691
+ result.lastInsertId = Number(info.lastInsertRowid);
2692
+ }
2693
+ return Promise.resolve(result);
2071
2694
  } catch (error) {
2072
- const message = error instanceof Error ? error.message : String(error);
2073
- log2.error(`Write query failed: ${message}`, {
2074
- code: ERROR_CODES.DB.QUERY_FAILED.full
2075
- });
2076
- throw new QueryError(`Write query failed: ${message}`, "DB_WRITE_FAILED", {
2077
- sql,
2078
- cause: error instanceof Error ? error : void 0
2079
- });
2695
+ translateSqliteError(error, sql, "Write query", log2);
2080
2696
  }
2081
2697
  }
2082
2698
 
@@ -2099,7 +2715,8 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
2099
2715
  */
2100
2716
  getConfiguredPath() {
2101
2717
  const config = this.config;
2102
- return config?.filePath ?? config?.connectionString ?? ":memory:";
2718
+ const path3 = config?.filePath ?? config?.connectionString ?? ":memory:";
2719
+ return path3;
2103
2720
  }
2104
2721
  db = null;
2105
2722
  schemaManager = null;
@@ -2137,6 +2754,17 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
2137
2754
  const versionResult = db.prepare("SELECT sqlite_version()").get();
2138
2755
  return versionResult?.["sqlite_version()"] ?? "0.0.0";
2139
2756
  }, log);
2757
+ if (sqliteConfig.initializationSql && Array.isArray(sqliteConfig.initializationSql)) {
2758
+ for (const sql of sqliteConfig.initializationSql) {
2759
+ db.exec(sql);
2760
+ }
2761
+ log.info(
2762
+ `Executed ${sqliteConfig.initializationSql.length} initialization SQL statements`,
2763
+ {
2764
+ code: "SQLITE_INIT_SQL"
2765
+ }
2766
+ );
2767
+ }
2140
2768
  this.schemaManager = new SchemaManager(this);
2141
2769
  this.connected = true;
2142
2770
  } catch (error) {
@@ -2230,6 +2858,7 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
2230
2858
  */
2231
2859
  executeReadQuery(sql, params) {
2232
2860
  this.ensureConnected();
2861
+ this.validateQuery(sql, true);
2233
2862
  return nativeExecuteRead(this.ensureDb(), sql, params, log);
2234
2863
  }
2235
2864
  /**
@@ -2237,6 +2866,7 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
2237
2866
  */
2238
2867
  executeWriteQuery(sql, params) {
2239
2868
  this.ensureConnected();
2869
+ this.validateQuery(sql, false);
2240
2870
  const result = nativeExecuteWrite(this.ensureDb(), sql, params, log);
2241
2871
  if (isDDL(sql)) {
2242
2872
  this.clearSchemaCache();
@@ -2248,11 +2878,26 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
2248
2878
  */
2249
2879
  executeQuery(sql, params) {
2250
2880
  const trimmed = sql.trim().toUpperCase();
2251
- if (trimmed.startsWith("SELECT") || trimmed.startsWith("PRAGMA") || trimmed.startsWith("EXPLAIN")) {
2881
+ if (trimmed.startsWith("PRAGMA")) {
2882
+ if (sql.includes("=") || sql.includes("(")) {
2883
+ return this.executeWriteQuery(sql, params);
2884
+ }
2885
+ return this.executeReadQuery(sql, params);
2886
+ }
2887
+ if (trimmed.startsWith("SELECT") || trimmed.startsWith("EXPLAIN")) {
2252
2888
  return this.executeReadQuery(sql, params);
2253
2889
  }
2254
2890
  return this.executeWriteQuery(sql, params);
2255
2891
  }
2892
+ /**
2893
+ * Execute a SQL script containing multiple statements
2894
+ */
2895
+ executeScript(sql) {
2896
+ this.ensureConnected();
2897
+ this.ensureDb().exec(sql);
2898
+ this.clearSchemaCache();
2899
+ return Promise.resolve();
2900
+ }
2256
2901
  /**
2257
2902
  * Get schema information (cached via SchemaManager)
2258
2903
  */
@@ -2328,6 +2973,23 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
2328
2973
  listSchemas() {
2329
2974
  return Promise.resolve(["main"]);
2330
2975
  }
2976
+ /**
2977
+ * Get indexes, optionally for a specific table (cached via SchemaManager)
2978
+ */
2979
+ async getIndexes(table) {
2980
+ this.ensureConnected();
2981
+ if (this.schemaManager) {
2982
+ if (table) {
2983
+ return this.schemaManager.getTableIndexes(table);
2984
+ }
2985
+ return this.schemaManager.getAllIndexes();
2986
+ }
2987
+ const all = await this.getAllIndexes();
2988
+ if (table) {
2989
+ return all.filter((i) => i.tableName === table);
2990
+ }
2991
+ return all;
2992
+ }
2331
2993
  /**
2332
2994
  * Get all indexes in the database (cached via SchemaManager)
2333
2995
  * Required by sqlite_indexes resource
@@ -2393,7 +3055,8 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
2393
3055
  "admin",
2394
3056
  "geo",
2395
3057
  "introspection",
2396
- "migration"
3058
+ "migration",
3059
+ "transactions"
2397
3060
  ];
2398
3061
  }
2399
3062
  /**
@@ -2452,7 +3115,11 @@ var NativeSqliteAdapter = class extends DatabaseAdapter {
2452
3115
  * Execute raw SQL and return results (for tools)
2453
3116
  */
2454
3117
  rawQuery(sql, params) {
2455
- return this.executeQuery(sql, params);
3118
+ const trimmed = sql.trim().toUpperCase();
3119
+ if (trimmed.startsWith("SELECT") || trimmed.startsWith("EXPLAIN") || trimmed.startsWith("PRAGMA") && !sql.includes("=") && !sql.includes("(")) {
3120
+ return nativeExecuteRead(this.ensureDb(), sql, params, log);
3121
+ }
3122
+ return nativeExecuteWrite(this.ensureDb(), sql, params, log);
2456
3123
  }
2457
3124
  /**
2458
3125
  * Begin a transaction