dirsql 0.4.8__tar.gz → 0.4.10__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 (225) hide show
  1. {dirsql-0.4.8 → dirsql-0.4.10}/Cargo.lock +1 -1
  2. {dirsql-0.4.8 → dirsql-0.4.10}/PKG-INFO +1 -1
  3. dirsql-0.4.10/dirsql/cli/resolve_config_extensions.py +70 -0
  4. {dirsql-0.4.8 → dirsql-0.4.10}/docs/.vitepress/config.ts +7 -0
  5. dirsql-0.4.10/docs/plugins.md +123 -0
  6. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/Cargo.toml +1 -1
  7. dirsql-0.4.10/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +8 -0
  8. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/.vitepress/config.ts +7 -0
  9. dirsql-0.4.10/packages/python/docs/plugins.md +123 -0
  10. dirsql-0.4.10/packages/python/e2e-attestations/fix-754-discovery-ext-resolution.json +7 -0
  11. dirsql-0.4.10/packages/rust/docs/plugins.md +123 -0
  12. dirsql-0.4.8/dirsql/cli/resolve_config_extensions.py +0 -55
  13. {dirsql-0.4.8 → dirsql-0.4.10}/Cargo.toml +0 -0
  14. {dirsql-0.4.8 → dirsql-0.4.10}/README.md +0 -0
  15. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/__init__.py +0 -0
  16. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/_async.py +0 -0
  17. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/_dirsql.pyi +0 -0
  18. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/__init__.py +0 -0
  19. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/binary_path.py +0 -0
  20. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/__init__.py +0 -0
  21. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  22. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  23. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  24. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
  25. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  26. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/is_windows.py +0 -0
  27. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/main.py +0 -0
  28. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/py.typed +0 -0
  29. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/resolve_config_extensions.py +0 -0
  30. {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/resolve_extension.py +0 -0
  31. {dirsql-0.4.8 → dirsql-0.4.10}/docs/.claude/CLAUDE.md +0 -0
  32. {dirsql-0.4.8 → dirsql-0.4.10}/docs/.vitepress/theme/index.ts +0 -0
  33. {dirsql-0.4.8 → dirsql-0.4.10}/docs/.vitepress/theme/lang.ts +0 -0
  34. {dirsql-0.4.8 → dirsql-0.4.10}/docs/AGENTS.md +0 -0
  35. {dirsql-0.4.8 → dirsql-0.4.10}/docs/explanation.md +0 -0
  36. {dirsql-0.4.8 → dirsql-0.4.10}/docs/getting-started.md +0 -0
  37. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/columns-from-paths.md +0 -0
  38. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/define-tables.md +0 -0
  39. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/embed.md +0 -0
  40. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/extract-from-contents.md +0 -0
  41. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/load-extension.md +0 -0
  42. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/parse-files-into-columns.md +0 -0
  43. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/persist.md +0 -0
  44. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/query-without-config.md +0 -0
  45. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/react-to-changes.md +0 -0
  46. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/search-by-meaning.md +0 -0
  47. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/skip-files.md +0 -0
  48. {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/write-a-plugin.md +0 -0
  49. {dirsql-0.4.8 → dirsql-0.4.10}/docs/index.md +0 -0
  50. {dirsql-0.4.8 → dirsql-0.4.10}/docs/migrations.md +0 -0
  51. {dirsql-0.4.8 → dirsql-0.4.10}/docs/package.json +0 -0
  52. {dirsql-0.4.8 → dirsql-0.4.10}/docs/pnpm-lock.yaml +0 -0
  53. {dirsql-0.4.8 → dirsql-0.4.10}/docs/pnpm-workspace.yaml +0 -0
  54. {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/cli.md +0 -0
  55. {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/columns.md +0 -0
  56. {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/config.md +0 -0
  57. {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/hooks.md +0 -0
  58. {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/http-api.md +0 -0
  59. {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/path-tables.md +0 -0
  60. {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/sdk.md +0 -0
  61. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/CHANGELOG.md +0 -0
  62. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/MIGRATIONS.md +0 -0
  63. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/README.md +0 -0
  64. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  65. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  66. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  67. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  68. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  69. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  70. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  71. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  72. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  73. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  74. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  75. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  76. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  77. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/README.md +0 -0
  78. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/conftest.py +0 -0
  79. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/.claude/CLAUDE.md +0 -0
  80. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  81. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  82. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/AGENTS.md +0 -0
  83. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/explanation.md +0 -0
  84. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/getting-started.md +0 -0
  85. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/columns-from-paths.md +0 -0
  86. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/define-tables.md +0 -0
  87. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/embed.md +0 -0
  88. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/extract-from-contents.md +0 -0
  89. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/load-extension.md +0 -0
  90. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
  91. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/persist.md +0 -0
  92. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/query-without-config.md +0 -0
  93. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/react-to-changes.md +0 -0
  94. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/search-by-meaning.md +0 -0
  95. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/skip-files.md +0 -0
  96. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/write-a-plugin.md +0 -0
  97. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/index.md +0 -0
  98. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/migrations.md +0 -0
  99. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/package.json +0 -0
  100. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/pnpm-lock.yaml +0 -0
  101. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/pnpm-workspace.yaml +0 -0
  102. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/cli.md +0 -0
  103. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/columns.md +0 -0
  104. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/config.md +0 -0
  105. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/hooks.md +0 -0
  106. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/http-api.md +0 -0
  107. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/path-tables.md +0 -0
  108. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/sdk.md +0 -0
  109. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/e2e-attestations/feat-745-python-no-ignore.json +0 -0
  110. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  111. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  112. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  113. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  114. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  115. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  116. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  117. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  118. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/README.md +0 -0
  119. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/src/lib.rs +0 -0
  120. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/__init__.py +0 -0
  121. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/conftest.py +0 -0
  122. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/e2e/__init__.py +0 -0
  123. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  124. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
  125. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/integration/__init__.py +0 -0
  126. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/integration/binding/__init__.py +0 -0
  127. {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  128. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/CHANGELOG.md +0 -0
  129. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/Cargo.toml +0 -0
  130. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/MIGRATIONS.md +0 -0
  131. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/README.md +0 -0
  132. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/benches/db_bench.rs +0 -0
  133. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/benches/differ_bench.rs +0 -0
  134. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/benches/matcher_bench.rs +0 -0
  135. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/benches/scanner_bench.rs +0 -0
  136. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-batch-ingest-transaction.md +0 -0
  137. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-chained-pre-post-query-hooks.md +0 -0
  138. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  139. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-fan-out-file-table-matching.md +0 -0
  140. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-persist-wal.md +0 -0
  141. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  142. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-repeatable-builder-config.md +0 -0
  143. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-repeatable-cli-config.md +0 -0
  144. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  145. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-subcommand-local-config-flags.md +0 -0
  146. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-19-path-table-query-fallback.md +0 -0
  147. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-19-path-table-vtab.md +0 -0
  148. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  149. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-20-path-table-glob-semantics.md +0 -0
  150. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-20-schema-inference.md +0 -0
  151. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-21-on-file-flag.md +0 -0
  152. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  153. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-23-init-escalation-example.md +0 -0
  154. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-23-query-default-cli.md +0 -0
  155. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  156. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  157. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-29-on-file-failures-accumulate.md +0 -0
  158. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-02-drop-regex.md +0 -0
  159. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-02-per-file-scan-failures.md +0 -0
  160. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-02-release-profile.md +0 -0
  161. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-03-gitignore-by-default.md +0 -0
  162. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-03-nested-default-ignores.md +0 -0
  163. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/README.md +0 -0
  164. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/explanation.md +0 -0
  165. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/getting-started.md +0 -0
  166. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  167. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/define-tables.md +0 -0
  168. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/embed.md +0 -0
  169. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/extract-from-contents.md +0 -0
  170. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/load-extension.md +0 -0
  171. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
  172. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/persist.md +0 -0
  173. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/query-without-config.md +0 -0
  174. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/react-to-changes.md +0 -0
  175. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  176. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/skip-files.md +0 -0
  177. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/write-a-plugin.md +0 -0
  178. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/index.md +0 -0
  179. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/migrations.md +0 -0
  180. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/cli.md +0 -0
  181. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/columns.md +0 -0
  182. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/config.md +0 -0
  183. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/hooks.md +0 -0
  184. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/http-api.md +0 -0
  185. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/path-tables.md +0 -0
  186. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/sdk.md +0 -0
  187. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  188. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-fan-out-file-table-matching.md +0 -0
  189. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-persist-wal.md +0 -0
  190. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  191. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  192. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-subcommand-local-config-flags.md +0 -0
  193. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  194. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-20-path-table-glob-semantics.md +0 -0
  195. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  196. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-23-init-escalation-example.md +0 -0
  197. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-23-query-default-cli.md +0 -0
  198. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  199. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  200. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-08-02-per-file-scan-failures.md +0 -0
  201. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-08-03-gitignore-by-default.md +0 -0
  202. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-08-03-nested-default-ignores.md +0 -0
  203. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/README.md +0 -0
  204. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/bin/dirsql.rs +0 -0
  205. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/execute.rs +0 -0
  206. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/init.rs +0 -0
  207. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/mod.rs +0 -0
  208. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/router.rs +0 -0
  209. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/serialize.rs +0 -0
  210. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/server.rs +0 -0
  211. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/command.rs +0 -0
  212. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/config.rs +0 -0
  213. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/db.rs +0 -0
  214. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/default_config.toml +0 -0
  215. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/differ.rs +0 -0
  216. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/infer.rs +0 -0
  217. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/lib.rs +0 -0
  218. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/matcher.rs +0 -0
  219. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/parsed_vtab.rs +0 -0
  220. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/path_table.rs +0 -0
  221. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/persist.rs +0 -0
  222. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/scanner.rs +0 -0
  223. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/vtab.rs +0 -0
  224. {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/watcher.rs +0 -0
  225. {dirsql-0.4.8 → dirsql-0.4.10}/pyproject.toml +0 -0
@@ -500,7 +500,7 @@ dependencies = [
500
500
 
501
501
  [[package]]
502
502
  name = "dirsql-py-ext"
503
- version = "0.4.8"
503
+ version = "0.4.10"
504
504
  dependencies = [
505
505
  "dirsql",
506
506
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.4.8
3
+ Version: 0.4.10
4
4
  Requires-Dist: tomli>=2 ; python_full_version < '3.11'
5
5
  Summary: Ephemeral SQL index over a local directory
6
6
  Keywords: sql,filesystem,directory,sqlite,index
@@ -0,0 +1,70 @@
1
+ """Launcher-side resolution of the TOML configs' ``[[dirsql.extension]]`` entries.
2
+
3
+ The compiled ``dirsql`` binary loads a config's extensions literally -- it
4
+ has no ``importlib``, so it cannot resolve a bare **package name**. When any
5
+ TOML config in argv names an extension by package name, the shared SDK
6
+ resolver (:mod:`dirsql.resolve_config_extensions`) resolves every config's
7
+ extensions and this launcher passes the resolved literal paths to the binary
8
+ via repeatable ``--extension`` flags; the binary then loads those and ignores
9
+ the configs' own extension entries.
10
+
11
+ Every config flag occurrence counts -- ``-c``/``--config`` are repeatable,
12
+ and plugin discovery injects fragments as additional ``-c`` flags -- so the
13
+ scan collects them all, in argv order.
14
+
15
+ Native-language configs (``.py`` / ``.js`` / ``.mjs`` / ``.cjs``) are untouched:
16
+ the binary dispatches those to ``dirsql interpret``, whose handshake already
17
+ carries resolved paths.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from ..resolve_config_extensions import resolve_configs_extension_specs
23
+
24
+ # Config extensions the binary dispatches to `dirsql interpret`; never
25
+ # pre-resolved here (that path resolves via the handshake).
26
+ _NATIVE_SUFFIXES = (".py", ".js", ".mjs", ".cjs")
27
+
28
+
29
+ def _config_paths_from_argv(argv: list[str]) -> list[str]:
30
+ """Every config value in argv, in order (``--config X``, ``--config=X``,
31
+ ``-c X``, ``-c=X``, ``-cX``), or the default when none are given."""
32
+ paths: list[str] = []
33
+ i = 0
34
+ while i < len(argv):
35
+ a = argv[i]
36
+ if a == "--config" or a == "-c":
37
+ # A bare trailing flag (no following value) yields "".
38
+ paths.append(next(iter(argv[i + 1 :]), ""))
39
+ i += 2
40
+ continue
41
+ if a.startswith("--config="):
42
+ paths.append(a[len("--config=") :])
43
+ elif a.startswith("-c"):
44
+ paths.append(a[len("-c") :].removeprefix("="))
45
+ i += 1
46
+ return paths or ["./.dirsql.toml"]
47
+
48
+
49
+ def with_resolved_extensions(argv: list[str]) -> list[str]:
50
+ """Return ``argv`` plus ``--extension`` flags when a TOML config names an
51
+ extension by package name; otherwise return ``argv`` unchanged. Raises if a
52
+ package name cannot be resolved (the launcher surfaces a clean error)."""
53
+ if argv and argv[0] == "init":
54
+ return argv
55
+ config_paths = [
56
+ p for p in _config_paths_from_argv(argv) if not p.endswith(_NATIVE_SUFFIXES)
57
+ ]
58
+ if not config_paths:
59
+ return argv
60
+ specs = resolve_configs_extension_specs(config_paths)
61
+ if specs is None:
62
+ return argv
63
+ flags: list[str] = []
64
+ for spec in specs:
65
+ entrypoint = spec["entrypoint"]
66
+ flags.append("--extension")
67
+ flags.append(
68
+ f"{spec['path']}::{entrypoint}" if entrypoint is not None else spec["path"]
69
+ )
70
+ return [*argv, *flags]
@@ -29,6 +29,7 @@ export default defineConfig({
29
29
  { text: 'How-to Guides', link: '/howto/define-tables' },
30
30
  { text: 'Reference', link: '/reference/cli' },
31
31
  { text: 'Explanation', link: '/explanation' },
32
+ { text: 'Plugins', link: '/plugins' },
32
33
  { text: 'GitHub', link: 'https://github.com/thekevinscott/dirsql' }
33
34
  ],
34
35
 
@@ -80,6 +81,12 @@ export default defineConfig({
80
81
  items: [
81
82
  { text: 'How dirsql thinks', link: '/explanation' }
82
83
  ]
84
+ },
85
+ {
86
+ text: 'Plugins',
87
+ items: [
88
+ { text: 'Available plugins', link: '/plugins' }
89
+ ]
83
90
  }
84
91
  ]
85
92
  },
@@ -0,0 +1,123 @@
1
+ # Plugins
2
+
3
+ A **plugin** is an ordinary Python package that ships a `dirsql.toml` config
4
+ fragment and declares itself via a `dirsql` entry point. Installing it in the
5
+ same environment as `dirsql` activates it: the `pip`/`uvx` launcher discovers
6
+ the package and loads its fragment automatically, with zero config edits. The
7
+ full discovery contract (ordering, opt-out, failure modes) is in the
8
+ [CLI reference](./reference/cli.md#plugins); to build your own, see
9
+ [Write a plugin](./howto/write-a-plugin.md).
10
+
11
+ This page lists the first-party plugins.
12
+
13
+ ## `dirsql-plugin-embeddings`
14
+
15
+ Semantic search over a directory of documents. The plugin embeds every matched
16
+ file — `**/*.{md,markdown,mdx,rst,txt,pdf}` — into a `documents` table through
17
+ any OpenAI-compatible `/v1/embeddings` endpoint, then turns each incoming
18
+ question into nearest-neighbor SQL over that table, ranked by
19
+ [`sqlite-vec`](https://github.com/asg017/sqlite-vec)'s
20
+ `vec_distance_cosine()`.
21
+
22
+ [PyPI](https://pypi.org/project/dirsql-plugin-embeddings/) ·
23
+ [Source](https://github.com/thekevinscott/dirsql/tree/main/plugins/dirsql-plugin-embeddings)
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
+ ### Install and launch
30
+
31
+ The plugin is a normal PyPI package; installing it alongside `dirsql` is the
32
+ whole install story (installed = active — there is no enable step). Point the
33
+ three environment variables at any OpenAI-compatible inference server, hosted
34
+ or self-managed:
35
+
36
+ ```sh
37
+ export DIRSQL_EMBEDDINGS_BASE_URL="https://api.openai.com"
38
+ export DIRSQL_EMBEDDINGS_MODEL="text-embedding-3-small"
39
+ export DIRSQL_EMBEDDINGS_API_KEY="sk-…"
40
+
41
+ uvx --with dirsql-plugin-embeddings --with sqlite-vec dirsql server
42
+ ```
43
+
44
+ The launcher finds the package through its `dirsql` entry point and injects
45
+ 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 — hence the second `--with`), 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 --with sqlite-vec \
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`
69
+ ([reference](./reference/cli.md#plugins)).
70
+
71
+ ### Configuration
72
+
73
+ The v0.1 configuration surface is environment variables. The hooks run as
74
+ subprocesses, so the variables must be set in the environment `dirsql` itself
75
+ runs in — they are inherited, not read from a file.
76
+
77
+ | Variable | Required | Meaning |
78
+ |---|---|---|
79
+ | `DIRSQL_EMBEDDINGS_BASE_URL` | yes | Base URL of the embeddings server; `/v1/embeddings` is appended. |
80
+ | `DIRSQL_EMBEDDINGS_MODEL` | yes | Model name sent in each request. |
81
+ | `DIRSQL_EMBEDDINGS_API_KEY` | yes | Bearer token for the `Authorization` header. |
82
+ | `DIRSQL_EMBEDDINGS_CACHE_READ` | no | Set to `0` to bypass reads of the on-disk PDF text-extraction cache (see below). Anything else, or unset, leaves the cache on. |
83
+
84
+ PDF text extraction is the expensive step of a scan, and a scan re-reads every
85
+ matched file — so extracted text is cached on disk at
86
+ `~/.cache/dirsql-plugin-embeddings/`, keyed on the file's path and mtime. An
87
+ edited PDF is a cache miss, never a stale hit. `DIRSQL_EMBEDDINGS_CACHE_READ=0`
88
+ forces every call to re-extract; writes still happen, so the cache stays warm
89
+ for the next run that reads it.
90
+
91
+ ### What gets indexed
92
+
93
+ Every file matching `**/*.{md,markdown,mdx,rst,txt,pdf}` under the root.
94
+ Everything except `.pdf` is read as UTF-8 text; a `.pdf` is read with
95
+ [pypdf](https://pypdf.readthedocs.io), its per-page text joined and embedded
96
+ like any other document. The extension check is case-insensitive (`.PDF` is a
97
+ PDF), but the glob itself is not — an uppercase-suffixed file is not matched
98
+ at all.
99
+
100
+ The glob is an allowlist rather than `**/*` on cost, not correctness: every
101
+ matched file costs a hook subprocess, and every file the plugin can decode
102
+ costs a billed embedding call. Widening the list trades money for recall.
103
+
104
+ A *scanned*, image-only PDF is not an error: pypdf yields no text and the file
105
+ is indexed with an empty `text`, exactly like an empty `.md`.
106
+
107
+ ### When a file fails
108
+
109
+ A file the plugin cannot process — an unreadable file, a failed embedding
110
+ call — is skipped, not fatal. Per the
111
+ [`on-file` failure contract](./reference/hooks.md#failure-semantics), the file
112
+ contributes no rows, `dirsql` names it on stderr and keeps indexing the rest,
113
+ and the run exits `23`: a partial index, distinct from `0` (clean) and `1`
114
+ (the run failed). From the SDK the same information is available via
115
+ `scan_failures()` / `scanFailures()`.
116
+
117
+ ### Planned configurability
118
+
119
+ v0.1 is deliberately minimal: one provider shape, one table, one file = one
120
+ row = one embedding (no chunking), and a hardcoded glob. Configurability —
121
+ alternate embedding backends, chunking strategies, choosing which files get
122
+ indexed, cache knobs — is tracked in
123
+ [#619](https://github.com/thekevinscott/dirsql/issues/619).
@@ -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.8"
7
+ version = "0.4.10"
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
@@ -0,0 +1,8 @@
1
+ **Fixed** The CLI launcher now resolves package-name `[[dirsql.extension]]`
2
+ entries for **every** config flag in argv — `-c X`, `-c=X`, `-cX`,
3
+ `--config X`, `--config=X`, repeated flags included — instead of only the
4
+ first `--config`. In particular, config fragments injected by plugin
5
+ discovery (which arrive as `-c` flags) get their package-name extensions
6
+ resolved to literal paths, so a plugin declaring e.g. `path = "sqlite_vec"`
7
+ loads on the pure discovery path instead of failing with
8
+ `failed to load extension` (#754).
@@ -29,6 +29,7 @@ export default defineConfig({
29
29
  { text: 'How-to Guides', link: '/howto/define-tables' },
30
30
  { text: 'Reference', link: '/reference/cli' },
31
31
  { text: 'Explanation', link: '/explanation' },
32
+ { text: 'Plugins', link: '/plugins' },
32
33
  { text: 'GitHub', link: 'https://github.com/thekevinscott/dirsql' }
33
34
  ],
34
35
 
@@ -80,6 +81,12 @@ export default defineConfig({
80
81
  items: [
81
82
  { text: 'How dirsql thinks', link: '/explanation' }
82
83
  ]
84
+ },
85
+ {
86
+ text: 'Plugins',
87
+ items: [
88
+ { text: 'Available plugins', link: '/plugins' }
89
+ ]
83
90
  }
84
91
  ]
85
92
  },
@@ -0,0 +1,123 @@
1
+ # Plugins
2
+
3
+ A **plugin** is an ordinary Python package that ships a `dirsql.toml` config
4
+ fragment and declares itself via a `dirsql` entry point. Installing it in the
5
+ same environment as `dirsql` activates it: the `pip`/`uvx` launcher discovers
6
+ the package and loads its fragment automatically, with zero config edits. The
7
+ full discovery contract (ordering, opt-out, failure modes) is in the
8
+ [CLI reference](./reference/cli.md#plugins); to build your own, see
9
+ [Write a plugin](./howto/write-a-plugin.md).
10
+
11
+ This page lists the first-party plugins.
12
+
13
+ ## `dirsql-plugin-embeddings`
14
+
15
+ Semantic search over a directory of documents. The plugin embeds every matched
16
+ file — `**/*.{md,markdown,mdx,rst,txt,pdf}` — into a `documents` table through
17
+ any OpenAI-compatible `/v1/embeddings` endpoint, then turns each incoming
18
+ question into nearest-neighbor SQL over that table, ranked by
19
+ [`sqlite-vec`](https://github.com/asg017/sqlite-vec)'s
20
+ `vec_distance_cosine()`.
21
+
22
+ [PyPI](https://pypi.org/project/dirsql-plugin-embeddings/) ·
23
+ [Source](https://github.com/thekevinscott/dirsql/tree/main/plugins/dirsql-plugin-embeddings)
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
+ ### Install and launch
30
+
31
+ The plugin is a normal PyPI package; installing it alongside `dirsql` is the
32
+ whole install story (installed = active — there is no enable step). Point the
33
+ three environment variables at any OpenAI-compatible inference server, hosted
34
+ or self-managed:
35
+
36
+ ```sh
37
+ export DIRSQL_EMBEDDINGS_BASE_URL="https://api.openai.com"
38
+ export DIRSQL_EMBEDDINGS_MODEL="text-embedding-3-small"
39
+ export DIRSQL_EMBEDDINGS_API_KEY="sk-…"
40
+
41
+ uvx --with dirsql-plugin-embeddings --with sqlite-vec dirsql server
42
+ ```
43
+
44
+ The launcher finds the package through its `dirsql` entry point and injects
45
+ 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 — hence the second `--with`), 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 --with sqlite-vec \
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`
69
+ ([reference](./reference/cli.md#plugins)).
70
+
71
+ ### Configuration
72
+
73
+ The v0.1 configuration surface is environment variables. The hooks run as
74
+ subprocesses, so the variables must be set in the environment `dirsql` itself
75
+ runs in — they are inherited, not read from a file.
76
+
77
+ | Variable | Required | Meaning |
78
+ |---|---|---|
79
+ | `DIRSQL_EMBEDDINGS_BASE_URL` | yes | Base URL of the embeddings server; `/v1/embeddings` is appended. |
80
+ | `DIRSQL_EMBEDDINGS_MODEL` | yes | Model name sent in each request. |
81
+ | `DIRSQL_EMBEDDINGS_API_KEY` | yes | Bearer token for the `Authorization` header. |
82
+ | `DIRSQL_EMBEDDINGS_CACHE_READ` | no | Set to `0` to bypass reads of the on-disk PDF text-extraction cache (see below). Anything else, or unset, leaves the cache on. |
83
+
84
+ PDF text extraction is the expensive step of a scan, and a scan re-reads every
85
+ matched file — so extracted text is cached on disk at
86
+ `~/.cache/dirsql-plugin-embeddings/`, keyed on the file's path and mtime. An
87
+ edited PDF is a cache miss, never a stale hit. `DIRSQL_EMBEDDINGS_CACHE_READ=0`
88
+ forces every call to re-extract; writes still happen, so the cache stays warm
89
+ for the next run that reads it.
90
+
91
+ ### What gets indexed
92
+
93
+ Every file matching `**/*.{md,markdown,mdx,rst,txt,pdf}` under the root.
94
+ Everything except `.pdf` is read as UTF-8 text; a `.pdf` is read with
95
+ [pypdf](https://pypdf.readthedocs.io), its per-page text joined and embedded
96
+ like any other document. The extension check is case-insensitive (`.PDF` is a
97
+ PDF), but the glob itself is not — an uppercase-suffixed file is not matched
98
+ at all.
99
+
100
+ The glob is an allowlist rather than `**/*` on cost, not correctness: every
101
+ matched file costs a hook subprocess, and every file the plugin can decode
102
+ costs a billed embedding call. Widening the list trades money for recall.
103
+
104
+ A *scanned*, image-only PDF is not an error: pypdf yields no text and the file
105
+ is indexed with an empty `text`, exactly like an empty `.md`.
106
+
107
+ ### When a file fails
108
+
109
+ A file the plugin cannot process — an unreadable file, a failed embedding
110
+ call — is skipped, not fatal. Per the
111
+ [`on-file` failure contract](./reference/hooks.md#failure-semantics), the file
112
+ contributes no rows, `dirsql` names it on stderr and keeps indexing the rest,
113
+ and the run exits `23`: a partial index, distinct from `0` (clean) and `1`
114
+ (the run failed). From the SDK the same information is available via
115
+ `scan_failures()` / `scanFailures()`.
116
+
117
+ ### Planned configurability
118
+
119
+ v0.1 is deliberately minimal: one provider shape, one table, one file = one
120
+ row = one embedding (no chunking), and a hardcoded glob. Configurability —
121
+ alternate embedding backends, chunking strategies, choosing which files get
122
+ indexed, cache knobs — is tracked in
123
+ [#619](https://github.com/thekevinscott/dirsql/issues/619).
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1785779409,
4
+ "exit_code": 0,
5
+ "commit": "610d8ff41538de6e3d5f19b4abea3ec1b351986a",
6
+ "branch": "fix/754-discovery-ext-resolution"
7
+ }
@@ -0,0 +1,123 @@
1
+ # Plugins
2
+
3
+ A **plugin** is an ordinary Python package that ships a `dirsql.toml` config
4
+ fragment and declares itself via a `dirsql` entry point. Installing it in the
5
+ same environment as `dirsql` activates it: the `pip`/`uvx` launcher discovers
6
+ the package and loads its fragment automatically, with zero config edits. The
7
+ full discovery contract (ordering, opt-out, failure modes) is in the
8
+ [CLI reference](./reference/cli.md#plugins); to build your own, see
9
+ [Write a plugin](./howto/write-a-plugin.md).
10
+
11
+ This page lists the first-party plugins.
12
+
13
+ ## `dirsql-plugin-embeddings`
14
+
15
+ Semantic search over a directory of documents. The plugin embeds every matched
16
+ file — `**/*.{md,markdown,mdx,rst,txt,pdf}` — into a `documents` table through
17
+ any OpenAI-compatible `/v1/embeddings` endpoint, then turns each incoming
18
+ question into nearest-neighbor SQL over that table, ranked by
19
+ [`sqlite-vec`](https://github.com/asg017/sqlite-vec)'s
20
+ `vec_distance_cosine()`.
21
+
22
+ [PyPI](https://pypi.org/project/dirsql-plugin-embeddings/) ·
23
+ [Source](https://github.com/thekevinscott/dirsql/tree/main/plugins/dirsql-plugin-embeddings)
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
+ ### Install and launch
30
+
31
+ The plugin is a normal PyPI package; installing it alongside `dirsql` is the
32
+ whole install story (installed = active — there is no enable step). Point the
33
+ three environment variables at any OpenAI-compatible inference server, hosted
34
+ or self-managed:
35
+
36
+ ```sh
37
+ export DIRSQL_EMBEDDINGS_BASE_URL="https://api.openai.com"
38
+ export DIRSQL_EMBEDDINGS_MODEL="text-embedding-3-small"
39
+ export DIRSQL_EMBEDDINGS_API_KEY="sk-…"
40
+
41
+ uvx --with dirsql-plugin-embeddings --with sqlite-vec dirsql server
42
+ ```
43
+
44
+ The launcher finds the package through its `dirsql` entry point and injects
45
+ 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 — hence the second `--with`), 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 --with sqlite-vec \
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`
69
+ ([reference](./reference/cli.md#plugins)).
70
+
71
+ ### Configuration
72
+
73
+ The v0.1 configuration surface is environment variables. The hooks run as
74
+ subprocesses, so the variables must be set in the environment `dirsql` itself
75
+ runs in — they are inherited, not read from a file.
76
+
77
+ | Variable | Required | Meaning |
78
+ |---|---|---|
79
+ | `DIRSQL_EMBEDDINGS_BASE_URL` | yes | Base URL of the embeddings server; `/v1/embeddings` is appended. |
80
+ | `DIRSQL_EMBEDDINGS_MODEL` | yes | Model name sent in each request. |
81
+ | `DIRSQL_EMBEDDINGS_API_KEY` | yes | Bearer token for the `Authorization` header. |
82
+ | `DIRSQL_EMBEDDINGS_CACHE_READ` | no | Set to `0` to bypass reads of the on-disk PDF text-extraction cache (see below). Anything else, or unset, leaves the cache on. |
83
+
84
+ PDF text extraction is the expensive step of a scan, and a scan re-reads every
85
+ matched file — so extracted text is cached on disk at
86
+ `~/.cache/dirsql-plugin-embeddings/`, keyed on the file's path and mtime. An
87
+ edited PDF is a cache miss, never a stale hit. `DIRSQL_EMBEDDINGS_CACHE_READ=0`
88
+ forces every call to re-extract; writes still happen, so the cache stays warm
89
+ for the next run that reads it.
90
+
91
+ ### What gets indexed
92
+
93
+ Every file matching `**/*.{md,markdown,mdx,rst,txt,pdf}` under the root.
94
+ Everything except `.pdf` is read as UTF-8 text; a `.pdf` is read with
95
+ [pypdf](https://pypdf.readthedocs.io), its per-page text joined and embedded
96
+ like any other document. The extension check is case-insensitive (`.PDF` is a
97
+ PDF), but the glob itself is not — an uppercase-suffixed file is not matched
98
+ at all.
99
+
100
+ The glob is an allowlist rather than `**/*` on cost, not correctness: every
101
+ matched file costs a hook subprocess, and every file the plugin can decode
102
+ costs a billed embedding call. Widening the list trades money for recall.
103
+
104
+ A *scanned*, image-only PDF is not an error: pypdf yields no text and the file
105
+ is indexed with an empty `text`, exactly like an empty `.md`.
106
+
107
+ ### When a file fails
108
+
109
+ A file the plugin cannot process — an unreadable file, a failed embedding
110
+ call — is skipped, not fatal. Per the
111
+ [`on-file` failure contract](./reference/hooks.md#failure-semantics), the file
112
+ contributes no rows, `dirsql` names it on stderr and keeps indexing the rest,
113
+ and the run exits `23`: a partial index, distinct from `0` (clean) and `1`
114
+ (the run failed). From the SDK the same information is available via
115
+ `scan_failures()` / `scanFailures()`.
116
+
117
+ ### Planned configurability
118
+
119
+ v0.1 is deliberately minimal: one provider shape, one table, one file = one
120
+ row = one embedding (no chunking), and a hardcoded glob. Configurability —
121
+ alternate embedding backends, chunking strategies, choosing which files get
122
+ indexed, cache knobs — is tracked in
123
+ [#619](https://github.com/thekevinscott/dirsql/issues/619).
@@ -1,55 +0,0 @@
1
- """Launcher-side resolution of a TOML config's ``[[dirsql.extension]]`` entries.
2
-
3
- The compiled ``dirsql`` binary loads a config's extensions literally -- it
4
- has no ``importlib``, so it cannot resolve a bare **package name**. When a
5
- TOML config names an extension by package name, the shared SDK resolver
6
- (:mod:`dirsql.resolve_config_extensions`) resolves every one of its
7
- extensions and this launcher passes the resolved literal paths to the binary
8
- via repeatable ``--extension`` flags; the binary then loads those and ignores
9
- the config's own extension entries.
10
-
11
- Native-language configs (``.py`` / ``.js`` / ``.mjs`` / ``.cjs``) are untouched:
12
- the binary dispatches those to ``dirsql interpret``, whose handshake already
13
- carries resolved paths.
14
- """
15
-
16
- from __future__ import annotations
17
-
18
- from ..resolve_config_extensions import resolve_config_extension_specs
19
-
20
- # Config extensions the binary dispatches to `dirsql interpret`; never
21
- # pre-resolved here (that path resolves via the handshake).
22
- _NATIVE_SUFFIXES = (".py", ".js", ".mjs", ".cjs")
23
-
24
-
25
- def _config_path_from_argv(argv: list[str]) -> str:
26
- """The ``--config`` value (``--config X`` or ``--config=X``), or the default."""
27
- for i, a in enumerate(argv):
28
- if a == "--config":
29
- # A bare trailing `--config` (no following value) yields "".
30
- return next(iter(argv[i + 1 :]), "")
31
- if a.startswith("--config="):
32
- return a[len("--config=") :]
33
- return "./.dirsql.toml"
34
-
35
-
36
- def with_resolved_extensions(argv: list[str]) -> list[str]:
37
- """Return ``argv`` plus ``--extension`` flags when the TOML config names an
38
- extension by package name; otherwise return ``argv`` unchanged. Raises if a
39
- package name cannot be resolved (the launcher surfaces a clean error)."""
40
- if argv and argv[0] == "init":
41
- return argv
42
- config_path = _config_path_from_argv(argv)
43
- if config_path.endswith(_NATIVE_SUFFIXES):
44
- return argv
45
- specs = resolve_config_extension_specs(config_path)
46
- if specs is None:
47
- return argv
48
- flags: list[str] = []
49
- for spec in specs:
50
- entrypoint = spec["entrypoint"]
51
- flags.append("--extension")
52
- flags.append(
53
- f"{spec['path']}::{entrypoint}" if entrypoint is not None else spec["path"]
54
- )
55
- return [*argv, *flags]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes