dirsql 0.4.14__tar.gz → 0.4.16__tar.gz

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 (240) hide show
  1. {dirsql-0.4.14 → dirsql-0.4.16}/Cargo.lock +1 -1
  2. {dirsql-0.4.14 → dirsql-0.4.16}/PKG-INFO +2 -1
  3. dirsql-0.4.16/dirsql/cli/main.py +66 -0
  4. {dirsql-0.4.14 → dirsql-0.4.16}/docs/.vitepress/config.ts +0 -1
  5. {dirsql-0.4.14/packages/rust → dirsql-0.4.16}/docs/howto/extract-from-contents.md +0 -2
  6. {dirsql-0.4.14/packages/rust → dirsql-0.4.16}/docs/howto/load-extension.md +0 -2
  7. {dirsql-0.4.14/packages/rust → dirsql-0.4.16}/docs/howto/write-a-plugin.md +15 -43
  8. {dirsql-0.4.14/packages/rust → dirsql-0.4.16}/docs/plugins.md +4 -27
  9. {dirsql-0.4.14/packages/python → dirsql-0.4.16}/docs/reference/cli.md +3 -4
  10. {dirsql-0.4.14/packages/rust → dirsql-0.4.16}/docs/reference/config.md +5 -15
  11. {dirsql-0.4.14/packages/rust → dirsql-0.4.16}/docs/reference/hooks.md +14 -52
  12. {dirsql-0.4.14/packages/rust → dirsql-0.4.16}/docs/reference/http-api.md +2 -11
  13. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/Cargo.toml +5 -2
  14. dirsql-0.4.16/packages/python/changelog.d/2026-08-04-cli-in-process.md +3 -0
  15. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/.vitepress/config.ts +0 -1
  16. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/extract-from-contents.md +0 -2
  17. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/load-extension.md +0 -2
  18. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/write-a-plugin.md +15 -43
  19. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/plugins.md +4 -27
  20. {dirsql-0.4.14/packages/rust → dirsql-0.4.16/packages/python}/docs/reference/cli.md +3 -4
  21. {dirsql-0.4.14 → dirsql-0.4.16/packages/python}/docs/reference/config.md +5 -15
  22. {dirsql-0.4.14 → dirsql-0.4.16/packages/python}/docs/reference/hooks.md +14 -52
  23. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/reference/http-api.md +2 -11
  24. dirsql-0.4.16/packages/python/e2e-attestations/claude-737-cli-run-shim.json +7 -0
  25. dirsql-0.4.16/packages/python/e2e-attestations/claude-738-pypi-in-process.json +7 -0
  26. dirsql-0.4.16/packages/python/e2e-attestations/claude-739-npm-in-process.json +7 -0
  27. dirsql-0.4.16/packages/python/e2e-attestations/claude-803-remove-query-hooks.json +7 -0
  28. dirsql-0.4.16/packages/python/migrations.d/2026-08-04-cli-in-process.md +63 -0
  29. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/src/lib.rs +21 -0
  30. dirsql-0.4.16/packages/rust/changelog.d/2026-08-04-cli-run-shim.md +3 -0
  31. dirsql-0.4.16/packages/rust/changelog.d/2026-08-10-remove-query-hooks.md +3 -0
  32. {dirsql-0.4.14 → dirsql-0.4.16/packages/rust}/docs/howto/extract-from-contents.md +0 -2
  33. {dirsql-0.4.14 → dirsql-0.4.16/packages/rust}/docs/howto/load-extension.md +0 -2
  34. {dirsql-0.4.14 → dirsql-0.4.16/packages/rust}/docs/howto/write-a-plugin.md +15 -43
  35. {dirsql-0.4.14 → dirsql-0.4.16/packages/rust}/docs/plugins.md +4 -27
  36. {dirsql-0.4.14 → dirsql-0.4.16/packages/rust}/docs/reference/cli.md +3 -4
  37. {dirsql-0.4.14/packages/python → dirsql-0.4.16/packages/rust}/docs/reference/config.md +5 -15
  38. {dirsql-0.4.14/packages/python → dirsql-0.4.16/packages/rust}/docs/reference/hooks.md +14 -52
  39. {dirsql-0.4.14 → dirsql-0.4.16/packages/rust}/docs/reference/http-api.md +2 -11
  40. dirsql-0.4.16/packages/rust/migrations.d/2026-08-10-remove-query-hooks.md +47 -0
  41. dirsql-0.4.16/packages/rust/src/bin/dirsql.rs +46 -0
  42. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/cli/execute.rs +16 -139
  43. dirsql-0.4.16/packages/rust/src/cli/mod.rs +200 -0
  44. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/cli/router.rs +3 -19
  45. dirsql-0.4.14/packages/rust/src/bin/dirsql.rs → dirsql-0.4.16/packages/rust/src/cli/run.rs +142 -146
  46. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/cli/server.rs +0 -2
  47. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/command.rs +4 -5
  48. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/config.rs +26 -156
  49. {dirsql-0.4.14 → dirsql-0.4.16}/pyproject.toml +7 -6
  50. dirsql-0.4.14/dirsql/cli/binary_path.py +0 -23
  51. dirsql-0.4.14/dirsql/cli/is_windows.py +0 -9
  52. dirsql-0.4.14/dirsql/cli/main.py +0 -42
  53. dirsql-0.4.14/docs/howto/search-by-meaning.md +0 -153
  54. dirsql-0.4.14/packages/python/docs/howto/search-by-meaning.md +0 -153
  55. dirsql-0.4.14/packages/rust/docs/howto/search-by-meaning.md +0 -153
  56. dirsql-0.4.14/packages/rust/src/cli/mod.rs +0 -364
  57. {dirsql-0.4.14 → dirsql-0.4.16}/Cargo.toml +0 -0
  58. {dirsql-0.4.14 → dirsql-0.4.16}/README.md +0 -0
  59. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/__init__.py +0 -0
  60. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/_async.py +0 -0
  61. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/_dirsql.pyi +0 -0
  62. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/cli/__init__.py +0 -0
  63. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/cli/discover_plugins/__init__.py +0 -0
  64. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  65. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  66. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  67. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
  68. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  69. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/cli/resolve_config_extensions.py +0 -0
  70. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/py.typed +0 -0
  71. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/resolve_config_extensions.py +0 -0
  72. {dirsql-0.4.14 → dirsql-0.4.16}/dirsql/resolve_extension.py +0 -0
  73. {dirsql-0.4.14 → dirsql-0.4.16}/docs/.claude/CLAUDE.md +0 -0
  74. {dirsql-0.4.14 → dirsql-0.4.16}/docs/.vitepress/theme/index.ts +0 -0
  75. {dirsql-0.4.14 → dirsql-0.4.16}/docs/.vitepress/theme/lang.ts +0 -0
  76. {dirsql-0.4.14 → dirsql-0.4.16}/docs/AGENTS.md +0 -0
  77. {dirsql-0.4.14 → dirsql-0.4.16}/docs/explanation.md +0 -0
  78. {dirsql-0.4.14 → dirsql-0.4.16}/docs/getting-started.md +0 -0
  79. {dirsql-0.4.14 → dirsql-0.4.16}/docs/howto/columns-from-paths.md +0 -0
  80. {dirsql-0.4.14 → dirsql-0.4.16}/docs/howto/define-tables.md +0 -0
  81. {dirsql-0.4.14 → dirsql-0.4.16}/docs/howto/embed.md +0 -0
  82. {dirsql-0.4.14 → dirsql-0.4.16}/docs/howto/parse-files-into-columns.md +0 -0
  83. {dirsql-0.4.14 → dirsql-0.4.16}/docs/howto/persist.md +0 -0
  84. {dirsql-0.4.14 → dirsql-0.4.16}/docs/howto/query-without-config.md +0 -0
  85. {dirsql-0.4.14 → dirsql-0.4.16}/docs/howto/react-to-changes.md +0 -0
  86. {dirsql-0.4.14 → dirsql-0.4.16}/docs/howto/skip-files.md +0 -0
  87. {dirsql-0.4.14 → dirsql-0.4.16}/docs/index.md +0 -0
  88. {dirsql-0.4.14 → dirsql-0.4.16}/docs/migrations.md +0 -0
  89. {dirsql-0.4.14 → dirsql-0.4.16}/docs/package.json +0 -0
  90. {dirsql-0.4.14 → dirsql-0.4.16}/docs/pnpm-lock.yaml +0 -0
  91. {dirsql-0.4.14 → dirsql-0.4.16}/docs/pnpm-workspace.yaml +0 -0
  92. {dirsql-0.4.14 → dirsql-0.4.16}/docs/reference/columns.md +0 -0
  93. {dirsql-0.4.14 → dirsql-0.4.16}/docs/reference/path-tables.md +0 -0
  94. {dirsql-0.4.14 → dirsql-0.4.16}/docs/reference/sdk.md +0 -0
  95. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/CHANGELOG.md +0 -0
  96. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/MIGRATIONS.md +0 -0
  97. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/README.md +0 -0
  98. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  99. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  100. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  101. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  102. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  103. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  104. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  105. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  106. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  107. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  108. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  109. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  110. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
  111. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
  112. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  113. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
  114. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/changelog.d/README.md +0 -0
  115. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/conftest.py +0 -0
  116. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/.claude/CLAUDE.md +0 -0
  117. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  118. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  119. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/AGENTS.md +0 -0
  120. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/explanation.md +0 -0
  121. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/getting-started.md +0 -0
  122. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/columns-from-paths.md +0 -0
  123. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/define-tables.md +0 -0
  124. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/embed.md +0 -0
  125. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
  126. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/persist.md +0 -0
  127. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/query-without-config.md +0 -0
  128. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/react-to-changes.md +0 -0
  129. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/howto/skip-files.md +0 -0
  130. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/index.md +0 -0
  131. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/migrations.md +0 -0
  132. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/package.json +0 -0
  133. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/pnpm-lock.yaml +0 -0
  134. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/pnpm-workspace.yaml +0 -0
  135. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/reference/columns.md +0 -0
  136. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/reference/path-tables.md +0 -0
  137. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/docs/reference/sdk.md +0 -0
  138. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/e2e-attestations/chore-766-narrow-pedantic.json +0 -0
  139. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/e2e-attestations/claude-772-extension-without-config.json +0 -0
  140. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  141. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  142. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  143. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  144. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  145. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  146. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  147. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  148. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/migrations.d/README.md +0 -0
  149. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/tests/__init__.py +0 -0
  150. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/tests/conftest.py +0 -0
  151. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/tests/e2e/__init__.py +0 -0
  152. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  153. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
  154. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/tests/integration/__init__.py +0 -0
  155. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/tests/integration/binding/__init__.py +0 -0
  156. {dirsql-0.4.14 → dirsql-0.4.16}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  157. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/CHANGELOG.md +0 -0
  158. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/Cargo.toml +0 -0
  159. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/MIGRATIONS.md +0 -0
  160. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/README.md +0 -0
  161. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/benches/db_bench.rs +0 -0
  162. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/benches/differ_bench.rs +0 -0
  163. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/benches/matcher_bench.rs +0 -0
  164. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/benches/scanner_bench.rs +0 -0
  165. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-batch-ingest-transaction.md +0 -0
  166. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-chained-pre-post-query-hooks.md +0 -0
  167. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  168. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-fan-out-file-table-matching.md +0 -0
  169. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-persist-wal.md +0 -0
  170. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  171. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-repeatable-builder-config.md +0 -0
  172. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-repeatable-cli-config.md +0 -0
  173. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  174. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-13-subcommand-local-config-flags.md +0 -0
  175. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-19-path-table-query-fallback.md +0 -0
  176. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-19-path-table-vtab.md +0 -0
  177. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  178. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-20-path-table-glob-semantics.md +0 -0
  179. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-20-schema-inference.md +0 -0
  180. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-21-on-file-flag.md +0 -0
  181. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  182. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-23-init-escalation-example.md +0 -0
  183. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-23-query-default-cli.md +0 -0
  184. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  185. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  186. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-07-29-on-file-failures-accumulate.md +0 -0
  187. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-08-02-drop-regex.md +0 -0
  188. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-08-02-per-file-scan-failures.md +0 -0
  189. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-08-02-release-profile.md +0 -0
  190. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-08-03-gitignore-by-default.md +0 -0
  191. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-08-03-nested-default-ignores.md +0 -0
  192. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-08-04-cast-lints.md +0 -0
  193. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/2026-08-04-configless-extension.md +0 -0
  194. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/changelog.d/README.md +0 -0
  195. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/explanation.md +0 -0
  196. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/getting-started.md +0 -0
  197. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  198. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/howto/define-tables.md +0 -0
  199. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/howto/embed.md +0 -0
  200. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
  201. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/howto/persist.md +0 -0
  202. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/howto/query-without-config.md +0 -0
  203. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/howto/react-to-changes.md +0 -0
  204. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/howto/skip-files.md +0 -0
  205. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/index.md +0 -0
  206. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/migrations.md +0 -0
  207. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/reference/columns.md +0 -0
  208. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/reference/path-tables.md +0 -0
  209. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/docs/reference/sdk.md +0 -0
  210. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  211. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-13-fan-out-file-table-matching.md +0 -0
  212. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-13-persist-wal.md +0 -0
  213. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  214. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  215. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-13-subcommand-local-config-flags.md +0 -0
  216. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  217. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-20-path-table-glob-semantics.md +0 -0
  218. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  219. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-23-init-escalation-example.md +0 -0
  220. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-23-query-default-cli.md +0 -0
  221. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  222. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  223. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-08-02-per-file-scan-failures.md +0 -0
  224. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-08-03-gitignore-by-default.md +0 -0
  225. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/2026-08-03-nested-default-ignores.md +0 -0
  226. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/migrations.d/README.md +0 -0
  227. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/cli/init.rs +0 -0
  228. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/cli/serialize.rs +0 -0
  229. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/db.rs +0 -0
  230. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/default_config.toml +0 -0
  231. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/differ.rs +0 -0
  232. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/infer.rs +0 -0
  233. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/lib.rs +0 -0
  234. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/matcher.rs +0 -0
  235. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/parsed_vtab.rs +0 -0
  236. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/path_table.rs +0 -0
  237. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/persist.rs +0 -0
  238. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/scanner.rs +0 -0
  239. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/vtab.rs +0 -0
  240. {dirsql-0.4.14 → dirsql-0.4.16}/packages/rust/src/watcher.rs +0 -0
@@ -500,7 +500,7 @@ dependencies = [
500
500
 
501
501
  [[package]]
502
502
  name = "dirsql-py-ext"
503
- version = "0.4.14"
503
+ version = "0.4.16"
504
504
  dependencies = [
505
505
  "dirsql",
506
506
  "pyo3",
@@ -1,7 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.4.14
3
+ Version: 0.4.16
4
4
  Requires-Dist: tomli>=2 ; python_full_version < '3.11'
5
+ Requires-Dist: bin-shim>=0.1
5
6
  Summary: Ephemeral SQL index over a local directory
6
7
  Keywords: sql,filesystem,directory,sqlite,index
7
8
  Author: Kevin Scott
@@ -0,0 +1,66 @@
1
+ """Console-script entry point. Runs the CLI in-process through the compiled
2
+ extension module — the same `_dirsql` the SDK imports — so the wheel ships one
3
+ copy of the core instead of a `.so` plus a bundled binary (#738).
4
+
5
+ All argv is forwarded transparently to the core, which owns subcommand
6
+ dispatch; the launcher only prepends what the core cannot work out for itself
7
+ (plugin config fragments, resolved extension paths).
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import signal
13
+ import sys
14
+
15
+ from bin_shim import main as run_in_process
16
+
17
+ from .discover_plugins.with_discovered_plugins import with_discovered_plugins
18
+ from .resolve_config_extensions import with_resolved_extensions
19
+
20
+
21
+ def _absorb_interrupt(*_args: object) -> None:
22
+ """Let the core's own shutdown decide the exit code on SIGINT.
23
+
24
+ signal-hook (which tokio uses) *chains*: it runs tokio's handler — which
25
+ drives `dirsql server`'s graceful shutdown, after which `run_cli` returns
26
+ 0 — and then whatever handler was installed before it. CPython's default
27
+ is `default_int_handler`, which raises `KeyboardInterrupt`; that lands
28
+ after `run_cli` has already returned 0 and turns a clean shutdown into a
29
+ 130. This handler occupies that slot without raising, so the core's exit
30
+ code is the one that survives, exactly as it does when the CLI is its own
31
+ process.
32
+
33
+ A signal arriving when the core is NOT handling signals still terminates:
34
+ `run_cli` is only reached with this installed, and it returns promptly for
35
+ every non-server command.
36
+ """
37
+
38
+
39
+ def with_core_owned_signals(handler=signal.signal):
40
+ """Install `_absorb_interrupt` for SIGINT and return the prior handler."""
41
+ return handler(signal.SIGINT, _absorb_interrupt)
42
+
43
+
44
+ def main(argv: list[str] | None = None) -> int:
45
+ if argv is None:
46
+ argv = sys.argv[1:]
47
+
48
+ # Discover installed plugins (CLI only) and inject their config fragments as
49
+ # `-c` flags before resolving extensions; then resolve any package-name
50
+ # extensions in a TOML config here (the core can't) as `--extension`
51
+ # flags. Both are no-ops when nothing applies.
52
+ try:
53
+ argv = with_discovered_plugins(argv)
54
+ argv = with_resolved_extensions(argv)
55
+ except Exception as exc:
56
+ print(f"dirsql: {exc}", file=sys.stderr)
57
+ return 1
58
+
59
+ previous = with_core_owned_signals()
60
+ try:
61
+ return run_in_process(argv=argv, module="dirsql._dirsql")
62
+ except Exception as exc:
63
+ print(f"dirsql: {exc}", file=sys.stderr)
64
+ return 1
65
+ finally:
66
+ signal.signal(signal.SIGINT, previous)
@@ -54,7 +54,6 @@ export default defineConfig({
54
54
  { text: 'Derive columns from file paths', link: '/howto/columns-from-paths' },
55
55
  { text: 'Extract rows from file contents', link: '/howto/extract-from-contents' },
56
56
  { text: 'Parse your files into columns', link: '/howto/parse-files-into-columns' },
57
- { text: 'Search documents by meaning', link: '/howto/search-by-meaning' },
58
57
  { text: "Skip files you don't want indexed", link: '/howto/skip-files' },
59
58
  { text: 'Load a SQLite extension', link: '/howto/load-extension' },
60
59
  { text: 'Keep the index across restarts', link: '/howto/persist' },
@@ -79,8 +79,6 @@ SQLite value mapping is under
79
79
 
80
80
  - The command re-runs on every startup and on every change to a matched
81
81
  file. If it is expensive, [keep the index across restarts](./persist.md).
82
- - The flagship use of `on-file` — computing embeddings — is
83
- [Search documents by meaning](./search-by-meaning.md).
84
82
  - Embedding `dirsql` in a program instead? The SDK's `on_file` callback
85
83
  fills the same role in-process — see
86
84
  [Embed `dirsql` in your application](./embed.md).
@@ -85,5 +85,3 @@ interpreter to resolve package names with
85
85
  - Embedding `dirsql` in a program? The SDK constructor takes the same
86
86
  specs via its `extensions` parameter
87
87
  ([SDK reference](../reference/sdk.md#constructor)).
88
- - The payoff use case — `sqlite-vec` powering semantic search — is
89
- [Search documents by meaning](./search-by-meaning.md).
@@ -24,8 +24,7 @@ dirsql-embeddings/
24
24
  └── dirsql_embeddings/
25
25
  ├── __init__.py
26
26
  ├── dirsql.toml # the config fragment
27
- ├── embed.py # on-file hook
28
- └── search.py # pre-query hook
27
+ └── embed.py # on-file hook
29
28
  ```
30
29
 
31
30
  The entry point maps a **source label** (the name) to the **module that
@@ -55,8 +54,7 @@ structurally **identical to a user config**. It may declare
55
54
  [`[[table]]`](../reference/config.md#table) (with
56
55
  [`on-file`](../reference/hooks.md#on-file)),
57
56
  [`[[dirsql.extension]]`](../reference/config.md#dirsql-extension),
58
- [`ignore`](../reference/config.md#dirsql-keys),
59
- [`pre-query`/`post-query`](../reference/hooks.md#pre-query), and
57
+ [`ignore`](../reference/config.md#dirsql-keys), and
60
58
  [`hook-timeout`](../reference/hooks.md#timeout).
61
59
 
62
60
  There are **no plugin-specific keys and no plugin-specific restrictions**. The
@@ -96,17 +94,14 @@ matter most for a published plugin:
96
94
  ## Worked example: an embeddings plugin
97
95
 
98
96
  Here is the whole plugin — vector search over a directory of notes, buildable
99
- in about fifty lines. It composes the same three pieces as
100
- [Search documents by meaning](./search-by-meaning.md): the
97
+ in about forty lines. It composes two pieces: the
101
98
  [`sqlite-vec`](https://github.com/asg017/sqlite-vec) extension for the
102
- distance math, an `on-file` command to embed each file, and a `pre-query`
103
- command to embed the question.
99
+ distance math, and an `on-file` command to embed each file.
104
100
 
105
101
  The fragment, `src/dirsql_embeddings/dirsql.toml`:
106
102
 
107
103
  ```toml
108
104
  [dirsql]
109
- pre-query = "uv run --with model2vec python search.py {args}"
110
105
  hook-timeout = 300 # headroom for the first-run model download
111
106
 
112
107
  [[dirsql.extension]]
@@ -140,46 +135,23 @@ row = {"path": os.path.relpath(path, root), "text": text,
140
135
  print(json.dumps([row]))
141
136
  ```
142
137
 
143
- `search.py` turns a `{"q": "..."}` request body into nearest-neighbor SQL:
144
-
145
- ```python
146
- """Turn a {"q": "..."} request body into a nearest-neighbor SQL query."""
147
- import json
148
- import sys
149
-
150
- from model2vec import StaticModel
151
-
152
- body = json.loads(sys.argv[1])
153
- model = StaticModel.from_pretrained("minishlab/potion-base-8M")
154
- vector = model.encode([body["q"]])[0]
155
- needle = json.dumps([round(float(x), 6) for x in vector])
156
- print(
157
- "SELECT path, ROUND(vec_distance_cosine(embedding, '%s'), 3) AS distance "
158
- "FROM notes ORDER BY distance LIMIT 3" % needle
159
- )
160
- ```
161
-
162
- ::: warning The hook owns SQL safety
163
- Whatever SQL `pre-query` prints is executed as-is. Here the interpolated
164
- value is a numeric vector the script itself produced; never splice raw request
165
- text into SQL. See [`pre-query`](../reference/hooks.md#pre-query).
166
- :::
167
-
168
- The relative `embed.py` / `search.py` above resolve against the fragment
169
- directory, which is convenient during development. For a published plugin,
170
- promote them to console scripts (`[project.scripts]` → `embed-file`,
171
- `embed-search`) so the commands carry their own interpreter and dependencies
172
- and no longer depend on `uv run --with`.
138
+ The relative `embed.py` above resolves against the fragment directory, which
139
+ is convenient during development. For a published plugin, promote it to a
140
+ console script (`[project.scripts]` → `embed-file`) so the command carries
141
+ its own interpreter and dependencies and no longer depends on
142
+ `uv run --with`.
173
143
 
174
144
  Once the package is installed alongside the launcher, its `notes` table is
175
145
  queryable with no config edits:
176
146
 
177
147
  ```bash
178
- uvx --with dirsql-embeddings dirsql query '{"q": "how do I cook pasta?"}'
148
+ uvx --with dirsql-embeddings dirsql query \
149
+ "SELECT path FROM notes ORDER BY vec_distance_cosine(embedding, '[0.1, ...]') LIMIT 3"
179
150
  ```
180
151
 
181
152
  The launcher discovers the installed plugin, composes its fragment, and the
182
- `pre-query` hook turns the question into vector-distance SQL.
153
+ `notes` table (with `vec_distance_cosine()` from the loaded extension) is
154
+ available to the query.
183
155
 
184
156
  ## SDK-style convention: expose the config
185
157
 
@@ -230,8 +202,8 @@ Discovery is deliberately narrow. Know exactly who does what:
230
202
  [convention above](#sdk-style-convention-expose-the-config)).
231
203
  - **Name collisions are a hard error.** Because fragments compose like any
232
204
  [multiple configs](../reference/config.md#composing-multiple-configs), two
233
- plugins (or a plugin and your config) defining a table of the same name — or
234
- the same query hook — fail loudly, naming the conflict. It is never a silent
205
+ plugins (or a plugin and your config) defining a table of the same name
206
+ fail loudly, naming the conflict. It is never a silent
235
207
  last-writer-wins.
236
208
 
237
209
  ::: warning Config flags are subcommand-local
@@ -22,10 +22,6 @@ question into nearest-neighbor SQL over that table, ranked by
22
22
  [PyPI](https://pypi.org/project/dirsql-plugin-embeddings/) ·
23
23
  [Source](https://github.com/thekevinscott/dirsql/tree/main/plugins/dirsql-plugin-embeddings)
24
24
 
25
- It is the packaged form of the
26
- [Search documents by meaning](./howto/search-by-meaning.md) how-to, with that
27
- guide's local `model2vec` model swapped for a hosted endpoint.
28
-
29
25
  ### Install and launch
30
26
 
31
27
  The plugin is a normal PyPI package; installing it alongside `dirsql` is the
@@ -43,29 +39,10 @@ uvx --with dirsql-plugin-embeddings dirsql server
43
39
 
44
40
  The launcher finds the package through its `dirsql` entry point and injects
45
41
  the shipped `dirsql.toml` fragment as an ordinary `-c` flag, composed after
46
- your own configs. The fragment declares three things:
47
-
48
- - the `sqlite-vec` extension (resolved from the installed `sqlite-vec`
49
- package, which the plugin depends on), for `vec_distance_cosine()`;
50
- - the `documents` table (`path`, `text`, `embedding`), whose
51
- [`on-file`](./reference/hooks.md#on-file) hook embeds each matched file at
52
- index time;
53
- - a [`pre-query`](./reference/hooks.md#pre-query) hook that embeds each
54
- incoming question and emits the nearest-neighbor SQL, plus a 300-second
55
- [`hook-timeout`](./reference/config.md#dirsql-keys) so slow embedding calls
56
- don't hit the 30-second default.
57
-
58
- Ask a question as a `{"q": …}` body — via `POST /query` against the server,
59
- or in one shot from the shell:
60
-
61
- ```sh
62
- uvx --with dirsql-plugin-embeddings \
63
- dirsql query '{"q": "how do I cook spaghetti?"}'
64
- # [{"path":"pasta.md","distance":0.113}, …]
65
- ```
66
-
67
- The result is the three nearest documents, closest first. Discovery can be
68
- turned off per-invocation with `--no-plugin` or `DIRSQL_NO_PLUGIN=1`
42
+ your own configs. The fragment declares the `sqlite-vec` extension (resolved
43
+ from the installed `sqlite-vec` package, which the plugin depends on), so
44
+ `vec_distance_cosine()` is callable in queries. Discovery can be turned off
45
+ per-invocation with `--no-plugin` or `DIRSQL_NO_PLUGIN=1`
69
46
  ([reference](./reference/cli.md#plugins)).
70
47
 
71
48
  ### Configuration
@@ -78,8 +78,8 @@ Config flags are subcommand-local: pass them after `server`
78
78
 
79
79
  - Per-query timeout: **30 seconds**. A query exceeding it returns
80
80
  `408 Request Timeout`.
81
- - Command hooks (`on-file`, `pre-query`, `post-query`) default to a
82
- **30-second** timeout each, overridable with the config key
81
+ - `on-file` command hooks default to a **30-second** timeout each,
82
+ overridable with the config key
83
83
  [`[dirsql].hook-timeout`](./config.md#dirsql-keys).
84
84
 
85
85
  ### Configless mode
@@ -166,8 +166,7 @@ uses**, so behavior is identical to `POST /query` by construction:
166
166
  (`--persist=/path`) so it does not swallow the SQL argument.
167
167
  - **`--no-ignore`** is honored: path-tables in the query scan files a
168
168
  `.gitignore` would hide. See [Skip rules](./path-tables.md#skip-rules).
169
- - **Hooks** ([`pre-query`](./hooks.md#pre-query) /
170
- [`post-query`](./hooks.md#post-query)) and the
169
+ - **`on-file` hooks** and the
171
170
  [`[dirsql].hook-timeout`](./config.md#dirsql-keys) apply identically.
172
171
  - The **30-second query timeout**, the **read-only rule**, and the
173
172
  `_dirsql_*` **internal-table denial** apply identically. A rejected read
@@ -23,9 +23,7 @@ the config file's location. See [`--config`](./cli.md#flags).
23
23
  | Key | Type | Default | Description |
24
24
  |---|---|---|---|
25
25
  | `ignore` | array of strings | `[]` | Glob patterns matched against root-relative paths. Matched files are skipped entirely — excluded from the initial scan and from watch events. |
26
- | `pre-query` | string | none | Server-wide command hook: the raw `POST /query` request body is passed to this command as `{args}`, and the plain-text SQL it prints is executed instead of parsing the body as `{"sql": …}`. CLI server only; the SDKs ignore it. Must be non-empty. See [Command hooks](./hooks.md#pre-query). |
27
- | `post-query` | string | none | Server-wide command hook: each successful `POST /query` result set is handed to this command (as a JSON array on stdin, and as `{args}` up to 96 KiB), and the JSON body it prints is returned instead of the bare row array. CLI server only; the SDKs ignore it. Must be non-empty. See [Command hooks](./hooks.md#post-query). |
28
- | `hook-timeout` | integer (seconds) | `30` | One global per-run timeout for every command hook — `on-file`, `pre-query`, and `post-query` alike. Positive whole seconds; zero and negative values are a config error. See [Command hooks](./hooks.md#timeout). |
26
+ | `hook-timeout` | integer (seconds) | `30` | One global per-run timeout for every `on-file` command hook run. Positive whole seconds; zero and negative values are a config error. See [Command hooks](./hooks.md#timeout). |
29
27
 
30
28
  The top-level `.dirsql/` directory under the root is always excluded from
31
29
  scanning, whether or not it appears in `ignore` — it is reserved for
@@ -147,15 +145,10 @@ The configs load and merge in **argv order**:
147
145
 
148
146
  - **`[[table]]`, `ignore`, and `[[dirsql.extension]]` entries accumulate** across
149
147
  all configs, in order.
150
- - **Each config's `on-file`, `pre-query`, and `post-query` hooks run from that
151
- config file's own directory**, under that config's own
152
- [`hook-timeout`](#dirsql-keys) so a relative command like
153
- `on-file = "sh ./extract.sh"` resolves against the config that declared it,
154
- wherever it lives.
155
- - **`pre-query` / `post-query` hooks chain FIFO**: the request body flows through
156
- each `pre-query` stage in order to the final SQL, and the result rows flow
157
- through each `post-query` stage to the response. See the
158
- [hook contract](./hooks.md).
148
+ - **Each config's `on-file` hooks run from that config file's own
149
+ directory**, under that config's own [`hook-timeout`](#dirsql-keys) — so a
150
+ relative command like `on-file = "sh ./extract.sh"` resolves against the
151
+ config that declared it, wherever it lives.
159
152
  - Each config is **validated on its own** (the [parse errors](#parse-errors)
160
153
  below apply per file). There is no cross-file merge validation, with one
161
154
  structural exception: **two configs defining a table of the same name is an
@@ -181,7 +174,6 @@ SDKs raise/reject) when:
181
174
  > `[[table]] '**/*.md' has no on-file hook, so every row would be all-NULL. Add an `on-file` hook that emits the columns, or, for stat columns with no code, query the path directly: `FROM './'``
182
175
 
183
176
  - A `[[dirsql.extension]]` entry omits `path`, or `path` is empty.
184
- - `pre-query` or `post-query` is present but empty/whitespace.
185
177
  - `hook-timeout` is zero or negative.
186
178
 
187
179
  ## Full example
@@ -189,8 +181,6 @@ SDKs raise/reject) when:
189
181
  ```toml
190
182
  [dirsql]
191
183
  ignore = ["node_modules/**", ".git/**", "dist/**"]
192
- pre-query = "uv run python to_sql.py {args}"
193
- post-query = "jq -c '{results: .}'"
194
184
  hook-timeout = 120
195
185
 
196
186
  [[dirsql.extension]]
@@ -1,8 +1,8 @@
1
1
  # Command hooks
2
2
 
3
- Three [config keys](./config.md) run an external command: `on-file` (per
4
- `[[table]]`), and the server-wide `pre-query` and `post-query` (under
5
- `[dirsql]`; CLI server only). All three share one execution contract.
3
+ The `on-file` [config key](./config.md) (per `[[table]]`, also available as
4
+ the [`--on-file` flag](./cli.md#on-file-command) on `dirsql query`) runs an
5
+ external command under the execution contract below.
6
6
 
7
7
  ## Execution contract
8
8
 
@@ -32,8 +32,8 @@ occurrence, within whole argv tokens, in a single left-to-right pass:
32
32
  `{…}` is inert.
33
33
  - An unrecognized `{…}` is left literal.
34
34
 
35
- Which placeholders exist depends on the hook (see
36
- [per-hook contracts](#per-hook-contracts) below).
35
+ The available placeholders are listed under the
36
+ [`on-file` contract](#on-file-contract) below.
37
37
 
38
38
  ### Working directory and environment
39
39
 
@@ -62,7 +62,7 @@ compactly on one line.
62
62
 
63
63
  Every hook run is bounded by a **30-second** default timeout. A run
64
64
  exceeding it is killed and treated as a failure. One global config key
65
- raises (or tightens) the bound for **all** hooks:
65
+ raises (or tightens) the bound:
66
66
 
67
67
  ```toml
68
68
  [dirsql]
@@ -80,19 +80,16 @@ A hook run fails when the command:
80
80
  stderr tail are reported),
81
81
  - exceeds the timeout (killed; stderr tail reported),
82
82
  - exits zero but prints no non-empty stdout line,
83
- - or (per hook, below) prints output that does not parse as expected.
83
+ - or prints output that does not parse as a JSON array of row objects.
84
84
 
85
- What a failure *means* differs per hook:
85
+ What a failure *means*: **per-file isolation.** The file contributes no rows
86
+ and is reported as skipped; the scan indexes every other file and commits.
87
+ The CLI names up to ten skipped files on stderr, then `... and N more`, and
88
+ exits `23` — distinct from `0` (clean) and `1` (the run failed), so a caller
89
+ can tell a partial index from a complete one. A row the table rejects under
90
+ `strict` counts as the same kind of failure.
86
91
 
87
- | Hook | On failure |
88
- |---|---|
89
- | `on-file` | **Per-file isolation.** The file contributes no rows and is reported as skipped; the scan indexes every other file and commits. The CLI names up to ten skipped files on stderr, then `... and N more`, and exits `23` — distinct from `0` (clean) and `1` (the run failed), so a caller can tell a partial index from a complete one. A row the table rejects under `strict` counts as the same kind of failure. |
90
- | `pre-query` | The request returns `500 Internal Server Error` with the command's stderr tail in the JSON `error` body. |
91
- | `post-query` | The request returns `500 Internal Server Error` with the command's stderr tail (or, for unparseable output, `post-query did not return valid JSON: <err>`) in the JSON `error` body. |
92
-
93
- ## Per-hook contracts
94
-
95
- ### `on-file`
92
+ ## `on-file` contract
96
93
 
97
94
  Runs once per file matched by the table's `glob`, at initial scan and on
98
95
  every watched change. The command reads the file itself and prints a JSON
@@ -114,38 +111,3 @@ the path or stat metadata emits it (it has `{path}`).
114
111
  |---|---|
115
112
  | `{path}` | The matched file's **absolute** path. `on-file = "extract.py {path}"` — self-sufficient from any working directory, so the command resolves it even when the config lives outside the index. |
116
113
  | `{root}` | The index root directory. Derive a root-relative path with `relpath({path}, {root})`. |
117
-
118
- ### `pre-query`
119
-
120
- Runs once per `POST /query` request, before the query. The raw request body
121
- goes in; plain-text SQL comes out (the stdout payload line). `dirsql` runs
122
- that SQL and returns rows as usual. With no `pre-query` key, the body is
123
- parsed as `{"sql": …}` instead — see [HTTP API](./http-api.md#post-query).
124
-
125
- | Placeholder | Value |
126
- |---|---|
127
- | `{args}` | The raw `POST /query` request body, verbatim, as one argv token. |
128
-
129
- **The hook owns SQL safety.** The `{args}` substitution keeps the untrusted
130
- body inert *as an argv token*, but whatever SQL string the hook prints is
131
- executed as-is. Validate, escape, or parameterize inside the hook.
132
-
133
- ### `post-query`
134
-
135
- Runs once per successful `POST /query`, after the query. The result rows
136
- are serialized to a JSON array and delivered two ways:
137
-
138
- - **On stdin** — always, unbounded. This is the recommended path.
139
- - **As `{args}`** — only when the serialized payload is ≤ **96 KiB**. Above
140
- that, `{args}` is substituted with an **empty string** and a stderr
141
- warning naming the byte size directs the operator to stdin. The full
142
- payload is still on stdin — this is a fallback, not truncation.
143
-
144
- | Placeholder | Value |
145
- |---|---|
146
- | `{args}` | The result rows as a JSON array, as one argv token; emptied (with a stderr warning) when the payload exceeds 96 KiB. |
147
-
148
- The stdout payload line is parsed as JSON and returned verbatim as the
149
- `200 application/json` response body. A payload that is not valid JSON
150
- fails the request (`500`). With no `post-query` key, the bare row array is
151
- returned — see [HTTP API](./http-api.md#post-query).
@@ -48,11 +48,11 @@ excluded from `SELECT *` results.
48
48
 
49
49
  | Status | When |
50
50
  |---|---|
51
- | `200` | Query succeeded. Body: array of row objects (or the [`post-query`](./hooks.md#post-query) hook's JSON). |
51
+ | `200` | Query succeeded. Body: array of row objects. |
52
52
  | `400` | Malformed JSON body, missing or empty `sql` field, or a SQL error (syntax error, unknown table, or a statement SQLite classifies as a write — queries are read-only). |
53
53
  | `405` | `GET /query`. Plain-text body `method not allowed`. |
54
54
  | `408` | The query exceeded the 30-second per-query timeout. |
55
- | `500` | Internal server fault, or a failed [`pre-query`](./hooks.md#pre-query) / [`post-query`](./hooks.md#post-query) hook. |
55
+ | `500` | Internal server fault. |
56
56
  | `503` | The server is in [degraded mode](./cli.md#degraded-mode) (the config file exists but failed to load). |
57
57
 
58
58
  All error responses (except `405`) are `application/json`:
@@ -61,15 +61,6 @@ All error responses (except `405`) are `application/json`:
61
61
  {"error": "syntax error near \"SLECT\""}
62
62
  ```
63
63
 
64
- ### Hook interactions
65
-
66
- - With [`[dirsql].pre-query`](./config.md#dirsql-keys) configured, the
67
- request body is **not** parsed as `{"sql": …}`; the raw body is passed to
68
- the hook, which prints the SQL to run. Hook failure → `500`.
69
- - With [`[dirsql].post-query`](./config.md#dirsql-keys) configured, the
70
- `200` body is whatever JSON the hook prints instead of the bare row
71
- array. Hook failure or non-JSON output → `500`.
72
-
73
64
  ## `GET /events`
74
65
 
75
66
  Opens a [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
4
4
  # pypi/maturin handler can rewrite it via `write-version` before
5
5
  # `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
6
6
  # and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
7
- version = "0.4.14"
7
+ version = "0.4.16"
8
8
  # abi3 note: the `abi3-py310` pyo3 feature (below) builds ONE stable-ABI
9
9
  # `cp310-abi3` wheel per platform that loads on every CPython >= 3.10
10
10
  # (matching `pyproject.toml`'s `requires-python = ">=3.10"`), instead of
@@ -22,7 +22,10 @@ name = "dirsql_py_ext"
22
22
  crate-type = ["cdylib", "rlib"]
23
23
 
24
24
  [dependencies]
25
- dirsql.workspace = true
25
+ # `cli` is on so the extension module carries `dirsql::cli::run_cli`: the
26
+ # console script calls it in-process instead of exec'ing a bundled binary
27
+ # (#738), which is what lets `dirsql/_binary/` leave the wheel.
28
+ dirsql = { workspace = true, features = ["cli"] }
26
29
  pyo3 = { version = "0.28", features = ["extension-module", "generate-import-lib", "abi3-py310"], optional = true }
27
30
 
28
31
  [lints.rust]
@@ -0,0 +1,3 @@
1
+ **Changed** — the `dirsql` console script now runs **in-process** through the compiled extension module instead of `exec`ing a bundled binary. `_dirsql` is built with the core's `cli` feature and exports `run_cli`, which the launcher calls via [bin-shim](https://pypi.org/project/bin-shim/). Plugin discovery and config-extension resolution are unchanged and still run first. The Windows/POSIX split is gone — `os.execv` on POSIX and `subprocess.run` on Windows are replaced by one in-process call on every platform, so the two no longer drift.
2
+
3
+ **Removed** — **BREAKING (packaging)**: the wheel no longer ships `dirsql/_binary/`. It held a standalone `dirsql` executable duplicating the core already present in the extension module; `pyproject.toml`'s `[tool.maturin].include` row and the release pipeline's pypi `bundle_cli` staging are both gone. `pip install dirsql && dirsql ...` and `uvx dirsql` behave exactly as before — verified across `--version`, a query, a SQL error (1), an unknown flag (2), and `dirsql server` + Ctrl-C (graceful shutdown, **0**). Anyone locating that binary by path must instead call `dirsql._dirsql.run_cli(argv)`, or install the Rust binary with `cargo install dirsql --features cli`. See [MIGRATIONS.md](../../MIGRATIONS.md). #738.
@@ -54,7 +54,6 @@ export default defineConfig({
54
54
  { text: 'Derive columns from file paths', link: '/howto/columns-from-paths' },
55
55
  { text: 'Extract rows from file contents', link: '/howto/extract-from-contents' },
56
56
  { text: 'Parse your files into columns', link: '/howto/parse-files-into-columns' },
57
- { text: 'Search documents by meaning', link: '/howto/search-by-meaning' },
58
57
  { text: "Skip files you don't want indexed", link: '/howto/skip-files' },
59
58
  { text: 'Load a SQLite extension', link: '/howto/load-extension' },
60
59
  { text: 'Keep the index across restarts', link: '/howto/persist' },
@@ -79,8 +79,6 @@ SQLite value mapping is under
79
79
 
80
80
  - The command re-runs on every startup and on every change to a matched
81
81
  file. If it is expensive, [keep the index across restarts](./persist.md).
82
- - The flagship use of `on-file` — computing embeddings — is
83
- [Search documents by meaning](./search-by-meaning.md).
84
82
  - Embedding `dirsql` in a program instead? The SDK's `on_file` callback
85
83
  fills the same role in-process — see
86
84
  [Embed `dirsql` in your application](./embed.md).
@@ -85,5 +85,3 @@ interpreter to resolve package names with
85
85
  - Embedding `dirsql` in a program? The SDK constructor takes the same
86
86
  specs via its `extensions` parameter
87
87
  ([SDK reference](../reference/sdk.md#constructor)).
88
- - The payoff use case — `sqlite-vec` powering semantic search — is
89
- [Search documents by meaning](./search-by-meaning.md).
@@ -24,8 +24,7 @@ dirsql-embeddings/
24
24
  └── dirsql_embeddings/
25
25
  ├── __init__.py
26
26
  ├── dirsql.toml # the config fragment
27
- ├── embed.py # on-file hook
28
- └── search.py # pre-query hook
27
+ └── embed.py # on-file hook
29
28
  ```
30
29
 
31
30
  The entry point maps a **source label** (the name) to the **module that
@@ -55,8 +54,7 @@ structurally **identical to a user config**. It may declare
55
54
  [`[[table]]`](../reference/config.md#table) (with
56
55
  [`on-file`](../reference/hooks.md#on-file)),
57
56
  [`[[dirsql.extension]]`](../reference/config.md#dirsql-extension),
58
- [`ignore`](../reference/config.md#dirsql-keys),
59
- [`pre-query`/`post-query`](../reference/hooks.md#pre-query), and
57
+ [`ignore`](../reference/config.md#dirsql-keys), and
60
58
  [`hook-timeout`](../reference/hooks.md#timeout).
61
59
 
62
60
  There are **no plugin-specific keys and no plugin-specific restrictions**. The
@@ -96,17 +94,14 @@ matter most for a published plugin:
96
94
  ## Worked example: an embeddings plugin
97
95
 
98
96
  Here is the whole plugin — vector search over a directory of notes, buildable
99
- in about fifty lines. It composes the same three pieces as
100
- [Search documents by meaning](./search-by-meaning.md): the
97
+ in about forty lines. It composes two pieces: the
101
98
  [`sqlite-vec`](https://github.com/asg017/sqlite-vec) extension for the
102
- distance math, an `on-file` command to embed each file, and a `pre-query`
103
- command to embed the question.
99
+ distance math, and an `on-file` command to embed each file.
104
100
 
105
101
  The fragment, `src/dirsql_embeddings/dirsql.toml`:
106
102
 
107
103
  ```toml
108
104
  [dirsql]
109
- pre-query = "uv run --with model2vec python search.py {args}"
110
105
  hook-timeout = 300 # headroom for the first-run model download
111
106
 
112
107
  [[dirsql.extension]]
@@ -140,46 +135,23 @@ row = {"path": os.path.relpath(path, root), "text": text,
140
135
  print(json.dumps([row]))
141
136
  ```
142
137
 
143
- `search.py` turns a `{"q": "..."}` request body into nearest-neighbor SQL:
144
-
145
- ```python
146
- """Turn a {"q": "..."} request body into a nearest-neighbor SQL query."""
147
- import json
148
- import sys
149
-
150
- from model2vec import StaticModel
151
-
152
- body = json.loads(sys.argv[1])
153
- model = StaticModel.from_pretrained("minishlab/potion-base-8M")
154
- vector = model.encode([body["q"]])[0]
155
- needle = json.dumps([round(float(x), 6) for x in vector])
156
- print(
157
- "SELECT path, ROUND(vec_distance_cosine(embedding, '%s'), 3) AS distance "
158
- "FROM notes ORDER BY distance LIMIT 3" % needle
159
- )
160
- ```
161
-
162
- ::: warning The hook owns SQL safety
163
- Whatever SQL `pre-query` prints is executed as-is. Here the interpolated
164
- value is a numeric vector the script itself produced; never splice raw request
165
- text into SQL. See [`pre-query`](../reference/hooks.md#pre-query).
166
- :::
167
-
168
- The relative `embed.py` / `search.py` above resolve against the fragment
169
- directory, which is convenient during development. For a published plugin,
170
- promote them to console scripts (`[project.scripts]` → `embed-file`,
171
- `embed-search`) so the commands carry their own interpreter and dependencies
172
- and no longer depend on `uv run --with`.
138
+ The relative `embed.py` above resolves against the fragment directory, which
139
+ is convenient during development. For a published plugin, promote it to a
140
+ console script (`[project.scripts]` → `embed-file`) so the command carries
141
+ its own interpreter and dependencies and no longer depends on
142
+ `uv run --with`.
173
143
 
174
144
  Once the package is installed alongside the launcher, its `notes` table is
175
145
  queryable with no config edits:
176
146
 
177
147
  ```bash
178
- uvx --with dirsql-embeddings dirsql query '{"q": "how do I cook pasta?"}'
148
+ uvx --with dirsql-embeddings dirsql query \
149
+ "SELECT path FROM notes ORDER BY vec_distance_cosine(embedding, '[0.1, ...]') LIMIT 3"
179
150
  ```
180
151
 
181
152
  The launcher discovers the installed plugin, composes its fragment, and the
182
- `pre-query` hook turns the question into vector-distance SQL.
153
+ `notes` table (with `vec_distance_cosine()` from the loaded extension) is
154
+ available to the query.
183
155
 
184
156
  ## SDK-style convention: expose the config
185
157
 
@@ -230,8 +202,8 @@ Discovery is deliberately narrow. Know exactly who does what:
230
202
  [convention above](#sdk-style-convention-expose-the-config)).
231
203
  - **Name collisions are a hard error.** Because fragments compose like any
232
204
  [multiple configs](../reference/config.md#composing-multiple-configs), two
233
- plugins (or a plugin and your config) defining a table of the same name — or
234
- the same query hook — fail loudly, naming the conflict. It is never a silent
205
+ plugins (or a plugin and your config) defining a table of the same name
206
+ fail loudly, naming the conflict. It is never a silent
235
207
  last-writer-wins.
236
208
 
237
209
  ::: warning Config flags are subcommand-local