dirsql 0.4.16__tar.gz → 0.4.18__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.
- {dirsql-0.4.16 → dirsql-0.4.18}/Cargo.lock +1 -2
- {dirsql-0.4.16 → dirsql-0.4.18}/PKG-INFO +1 -1
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/.vitepress/config.ts +1 -0
- dirsql-0.4.18/docs/howto/search-by-meaning.md +114 -0
- {dirsql-0.4.16/packages/python → dirsql-0.4.18}/docs/howto/write-a-plugin.md +6 -6
- dirsql-0.4.18/docs/plugins.md +100 -0
- {dirsql-0.4.16/packages/python → dirsql-0.4.18}/docs/reference/cli.md +16 -11
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/reference/config.md +102 -16
- {dirsql-0.4.16/packages/rust → dirsql-0.4.18}/docs/reference/hooks.md +21 -9
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/Cargo.toml +1 -1
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/.vitepress/config.ts +1 -0
- dirsql-0.4.18/packages/python/docs/howto/search-by-meaning.md +114 -0
- {dirsql-0.4.16 → dirsql-0.4.18/packages/python}/docs/howto/write-a-plugin.md +6 -6
- dirsql-0.4.18/packages/python/docs/plugins.md +100 -0
- {dirsql-0.4.16/packages/rust → dirsql-0.4.18/packages/python}/docs/reference/cli.md +16 -11
- {dirsql-0.4.16/packages/rust → dirsql-0.4.18/packages/python}/docs/reference/config.md +102 -16
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/reference/hooks.md +21 -9
- dirsql-0.4.18/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +7 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/Cargo.toml +1 -4
- dirsql-0.4.18/packages/rust/changelog.d/2026-08-10-dirsql-function.md +1 -0
- dirsql-0.4.18/packages/rust/changelog.d/2026-08-11-oneshot-query-no-timeout.md +3 -0
- dirsql-0.4.18/packages/rust/changelog.d/2026-08-11-retire-hook-timeout.md +3 -0
- dirsql-0.4.18/packages/rust/docs/howto/search-by-meaning.md +114 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/write-a-plugin.md +6 -6
- dirsql-0.4.18/packages/rust/docs/plugins.md +100 -0
- {dirsql-0.4.16 → dirsql-0.4.18/packages/rust}/docs/reference/cli.md +16 -11
- {dirsql-0.4.16/packages/python → dirsql-0.4.18/packages/rust}/docs/reference/config.md +102 -16
- {dirsql-0.4.16 → dirsql-0.4.18/packages/rust}/docs/reference/hooks.md +21 -9
- dirsql-0.4.18/packages/rust/migrations.d/2026-08-11-oneshot-query-no-timeout.md +46 -0
- dirsql-0.4.18/packages/rust/migrations.d/2026-08-11-retire-hook-timeout.md +51 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/cli/execute.rs +54 -14
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/cli/router.rs +1 -1
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/cli/run.rs +9 -7
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/command.rs +21 -93
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/config.rs +542 -117
- dirsql-0.4.18/packages/rust/src/functions.rs +771 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/lib.rs +200 -71
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/parsed_vtab.rs +2 -2
- dirsql-0.4.16/docs/plugins.md +0 -100
- dirsql-0.4.16/packages/python/docs/plugins.md +0 -100
- dirsql-0.4.16/packages/python/e2e-attestations/chore-766-narrow-pedantic.json +0 -7
- dirsql-0.4.16/packages/python/e2e-attestations/claude-737-cli-run-shim.json +0 -7
- dirsql-0.4.16/packages/python/e2e-attestations/claude-738-pypi-in-process.json +0 -7
- dirsql-0.4.16/packages/python/e2e-attestations/claude-739-npm-in-process.json +0 -7
- dirsql-0.4.16/packages/python/e2e-attestations/claude-772-extension-without-config.json +0 -7
- dirsql-0.4.16/packages/python/e2e-attestations/claude-803-remove-query-hooks.json +0 -7
- dirsql-0.4.16/packages/rust/docs/plugins.md +0 -100
- {dirsql-0.4.16 → dirsql-0.4.18}/Cargo.toml +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/README.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/__init__.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/_async.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/py.typed +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/resolve_config_extensions.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/AGENTS.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/explanation.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/getting-started.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/embed.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/persist.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/index.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/migrations.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/package.json +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/reference/columns.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/docs/reference/sdk.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/README.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/conftest.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/docs/reference/sdk.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/src/lib.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/README.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-batch-ingest-transaction.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-chained-pre-post-query-hooks.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-fan-out-file-table-matching.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-persist-wal.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-repeatable-builder-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-repeatable-cli-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-13-subcommand-local-config-flags.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-19-path-table-query-fallback.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-19-path-table-vtab.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-20-path-table-glob-semantics.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-20-schema-inference.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-21-on-file-flag.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-23-init-escalation-example.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-23-query-default-cli.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-07-29-on-file-failures-accumulate.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-08-02-drop-regex.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-08-02-per-file-scan-failures.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-08-03-gitignore-by-default.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-08-03-nested-default-ignores.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-08-04-cli-run-shim.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-08-04-configless-extension.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/2026-08-10-remove-query-hooks.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/changelog.d/README.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/migrations.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/docs/reference/sdk.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-13-fan-out-file-table-matching.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-13-persist-wal.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-13-subcommand-local-config-flags.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-20-path-table-glob-semantics.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-23-init-escalation-example.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-23-query-default-cli.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-08-02-per-file-scan-failures.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-08-03-gitignore-by-default.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-08-03-nested-default-ignores.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/2026-08-10-remove-query-hooks.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/migrations.d/README.md +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/db.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/default_config.toml +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.16 → dirsql-0.4.18}/pyproject.toml +0 -0
|
@@ -484,7 +484,6 @@ dependencies = [
|
|
|
484
484
|
"tokio",
|
|
485
485
|
"tokio-stream",
|
|
486
486
|
"toml",
|
|
487
|
-
"wait-timeout",
|
|
488
487
|
"walkdir",
|
|
489
488
|
]
|
|
490
489
|
|
|
@@ -500,7 +499,7 @@ dependencies = [
|
|
|
500
499
|
|
|
501
500
|
[[package]]
|
|
502
501
|
name = "dirsql-py-ext"
|
|
503
|
-
version = "0.4.
|
|
502
|
+
version = "0.4.18"
|
|
504
503
|
dependencies = [
|
|
505
504
|
"dirsql",
|
|
506
505
|
"pyo3",
|
|
@@ -54,6 +54,7 @@ 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' },
|
|
57
58
|
{ text: "Skip files you don't want indexed", link: '/howto/skip-files' },
|
|
58
59
|
{ text: 'Load a SQLite extension', link: '/howto/load-extension' },
|
|
59
60
|
{ text: 'Keep the index across restarts', link: '/howto/persist' },
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Search documents by meaning
|
|
2
|
+
|
|
3
|
+
Ask a question in plain language and get the closest documents back — even
|
|
4
|
+
when they share no keywords with it. Install
|
|
5
|
+
[`dirsql-plugin-embeddings`](../plugins.md#dirsql-plugin-embeddings) and
|
|
6
|
+
semantic search becomes plain SQL: the plugin's `embed()` function turns
|
|
7
|
+
text into vectors, [`sqlite-vec`](https://github.com/asg017/sqlite-vec)'s
|
|
8
|
+
`vec_distance_cosine()` measures distance, and `ORDER BY … LIMIT` does the
|
|
9
|
+
ranking. No config, no API keys, no services — the model runs locally.
|
|
10
|
+
|
|
11
|
+
Suppose short notes live in `notes/*.md`:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
notes/pasta.md # boiling spaghetti, olive oil, garlic
|
|
15
|
+
notes/branches.md # git feature branches and pull requests
|
|
16
|
+
notes/tomatoes.md # planting tomato seedlings after the last frost
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## The one-liner
|
|
20
|
+
|
|
21
|
+
The plugin package is also its own command. Give it a corpus glob and a
|
|
22
|
+
question, and it prints the closest paths, ranked by distance:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uvx dirsql-plugin-embeddings 'notes/*.md' "how do I cook pasta?" -k 3
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- The **corpus glob is required**, and always first: the plugin never picks a
|
|
29
|
+
default corpus, so you always say exactly which files are in scope. A bare
|
|
30
|
+
glob is fine — the command normalizes it to the `./`-relative form the SQL
|
|
31
|
+
layer requires.
|
|
32
|
+
- The question is the second positional.
|
|
33
|
+
- `-k` / `--limit` (both spellings, default 10) is the number of results —
|
|
34
|
+
it is exactly the SQL `LIMIT` of the generated query; there is no other
|
|
35
|
+
cutoff.
|
|
36
|
+
- `--model <id>` switches the embedding model
|
|
37
|
+
([model story](../plugins.md#model)).
|
|
38
|
+
|
|
39
|
+
The first-ever run downloads the model (on the order of a hundred megabytes,
|
|
40
|
+
with progress on stderr); after that it loads from the local cache. Results
|
|
41
|
+
print one `path<TAB>distance` line per match, closest first.
|
|
42
|
+
|
|
43
|
+
## The SQL behind it
|
|
44
|
+
|
|
45
|
+
The one-liner generates and runs ordinary `dirsql` SQL, and you can write it
|
|
46
|
+
yourself when you want more than ranked paths — a different projection, a
|
|
47
|
+
join, a `WHERE` clause, a subset of a JSON file's content:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uvx --with dirsql-plugin-embeddings dirsql "
|
|
51
|
+
SELECT path,
|
|
52
|
+
vec_distance_cosine(emb, embed('how do I cook pasta?')) AS distance
|
|
53
|
+
FROM (SELECT path, embed(content) AS emb FROM './notes/*.md')
|
|
54
|
+
ORDER BY distance
|
|
55
|
+
LIMIT 3"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
[{"path":"notes/pasta.md","distance":0.315},{"path":"notes/tomatoes.md","distance":0.881},{"path":"notes/branches.md","distance":0.92}]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Neither "cook" nor any other keyword needs to appear in `pasta.md` — the
|
|
63
|
+
distance ranking is doing the work.
|
|
64
|
+
|
|
65
|
+
Reading the query inside-out:
|
|
66
|
+
|
|
67
|
+
1. The subquery scans the [path-table](../reference/path-tables.md)
|
|
68
|
+
`'./notes/*.md'` and embeds each file's
|
|
69
|
+
[`content`](../reference/path-tables.md#columns) — only the files the
|
|
70
|
+
glob matches are ever read or embedded. In hand-written SQL the `./`
|
|
71
|
+
prefix is [required](../reference/path-tables.md#writing-the-path); only
|
|
72
|
+
the one-liner normalizes a bare glob for you.
|
|
73
|
+
2. `embed('how do I cook pasta?')` embeds the question once (the function is
|
|
74
|
+
deterministic, so SQLite reuses the value across rows).
|
|
75
|
+
3. `vec_distance_cosine(...)` computes cosine distance between the two
|
|
76
|
+
vectors; `ORDER BY distance LIMIT 3` keeps the three nearest.
|
|
77
|
+
|
|
78
|
+
Structured files compose with SQL's JSON operators — embed one field instead
|
|
79
|
+
of the whole file:
|
|
80
|
+
|
|
81
|
+
```sql
|
|
82
|
+
SELECT path
|
|
83
|
+
FROM (SELECT path, embed(content ->> 'abstract') AS emb
|
|
84
|
+
FROM './papers/**/metadata.json')
|
|
85
|
+
ORDER BY vec_distance_cosine(emb, embed('local private models'))
|
|
86
|
+
LIMIT 10
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
::: tip Top-k is `LIMIT k`
|
|
90
|
+
If you know `sqlite-vec` you may reach for its `MATCH … AND k = 10` idiom.
|
|
91
|
+
That syntax belongs to `sqlite-vec`'s `vec0` virtual table, which `dirsql`
|
|
92
|
+
does not use — `dirsql` tables are per-file row tables. For plain
|
|
93
|
+
expressions, `sqlite-vec`'s own documented pattern is exactly what this
|
|
94
|
+
guide uses: `ORDER BY vec_distance_cosine(...) LIMIT k`.
|
|
95
|
+
:::
|
|
96
|
+
|
|
97
|
+
## Repeat runs are cheap
|
|
98
|
+
|
|
99
|
+
Computed vectors are cached on disk, keyed on content and model
|
|
100
|
+
([vector cache](../plugins.md#vector-cache)) — re-running a search over
|
|
101
|
+
unchanged files skips the model entirely and re-embeds only what changed.
|
|
102
|
+
And the plugin costs nothing when idle: a query that never calls `embed()`
|
|
103
|
+
spawns no worker and loads no model
|
|
104
|
+
([zero cost when unused](../plugins.md#zero-cost-when-unused)).
|
|
105
|
+
|
|
106
|
+
## How `embed()` gets into SQL
|
|
107
|
+
|
|
108
|
+
The plugin ships a config fragment declaring `embed()` via
|
|
109
|
+
[`[[dirsql.function]]`](../reference/config.md#dirsql-function), which the
|
|
110
|
+
`uvx`/`pip` launcher [discovers automatically](../reference/cli.md#plugins).
|
|
111
|
+
The same mechanism is open to your own configs and plugins — any external
|
|
112
|
+
command that speaks the
|
|
113
|
+
[worker protocol](../reference/config.md#worker-protocol) can back a SQL
|
|
114
|
+
function. To build one, see [Write a plugin](./write-a-plugin.md).
|
|
@@ -54,8 +54,10 @@ structurally **identical to a user config**. It may declare
|
|
|
54
54
|
[`[[table]]`](../reference/config.md#table) (with
|
|
55
55
|
[`on-file`](../reference/hooks.md#on-file)),
|
|
56
56
|
[`[[dirsql.extension]]`](../reference/config.md#dirsql-extension),
|
|
57
|
-
[`
|
|
58
|
-
[`
|
|
57
|
+
[`[[dirsql.function]]`](../reference/config.md#dirsql-function) (how
|
|
58
|
+
[`dirsql-plugin-embeddings`](../plugins.md#dirsql-plugin-embeddings) provides
|
|
59
|
+
its `embed()` SQL function),
|
|
60
|
+
and [`ignore`](../reference/config.md#dirsql-keys).
|
|
59
61
|
|
|
60
62
|
There are **no plugin-specific keys and no plugin-specific restrictions**. The
|
|
61
63
|
config schema is content-only: the index `root` and `--persist` are
|
|
@@ -101,9 +103,6 @@ distance math, and an `on-file` command to embed each file.
|
|
|
101
103
|
The fragment, `src/dirsql_embeddings/dirsql.toml`:
|
|
102
104
|
|
|
103
105
|
```toml
|
|
104
|
-
[dirsql]
|
|
105
|
-
hook-timeout = 300 # headroom for the first-run model download
|
|
106
|
-
|
|
107
106
|
[[dirsql.extension]]
|
|
108
107
|
path = "sqlite_vec"
|
|
109
108
|
entrypoint = "sqlite3_vec_init"
|
|
@@ -202,7 +201,8 @@ Discovery is deliberately narrow. Know exactly who does what:
|
|
|
202
201
|
[convention above](#sdk-style-convention-expose-the-config)).
|
|
203
202
|
- **Name collisions are a hard error.** Because fragments compose like any
|
|
204
203
|
[multiple configs](../reference/config.md#composing-multiple-configs), two
|
|
205
|
-
plugins (or a plugin and your config) defining a table
|
|
204
|
+
plugins (or a plugin and your config) defining a table — or declaring a
|
|
205
|
+
[function](../reference/config.md#dirsql-function) — of the same name
|
|
206
206
|
fail loudly, naming the conflict. It is never a silent
|
|
207
207
|
last-writer-wins.
|
|
208
208
|
|
|
@@ -0,0 +1,100 @@
|
|
|
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 files. The plugin's product is content → vectors: it
|
|
16
|
+
declares an `embed()` SQL scalar function (via
|
|
17
|
+
[`[[dirsql.function]]`](./reference/config.md#dirsql-function)) that turns
|
|
18
|
+
TEXT or BLOB values into embedding vectors, and loads
|
|
19
|
+
[`sqlite-vec`](https://github.com/asg017/sqlite-vec) so
|
|
20
|
+
`vec_distance_cosine()` and friends do the distance math. You scope the
|
|
21
|
+
search with an ordinary [path-table](./reference/path-tables.md) glob, rank
|
|
22
|
+
with `ORDER BY`, and cut with `LIMIT` — search is plain SQL.
|
|
23
|
+
|
|
24
|
+
[PyPI](https://pypi.org/project/dirsql-plugin-embeddings/) ·
|
|
25
|
+
[Source](https://github.com/thekevinscott/dirsql/tree/main/plugins/dirsql-plugin-embeddings)
|
|
26
|
+
|
|
27
|
+
### Install and launch
|
|
28
|
+
|
|
29
|
+
The plugin is a normal PyPI package; installing it alongside `dirsql` is the
|
|
30
|
+
whole install story (installed = active — there is no enable step, and no
|
|
31
|
+
configuration at all):
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
uvx --with dirsql-plugin-embeddings dirsql "
|
|
35
|
+
SELECT path
|
|
36
|
+
FROM (SELECT path, embed(content ->> 'abstract') AS emb
|
|
37
|
+
FROM './arxiv-firehose/data/**/metadata.json')
|
|
38
|
+
ORDER BY vec_distance_cosine(emb, embed('local private models'))
|
|
39
|
+
LIMIT 10"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The launcher finds the package through its `dirsql` entry point and injects
|
|
43
|
+
the shipped `dirsql.toml` fragment as an ordinary `-c` flag, composed after
|
|
44
|
+
your own configs. The fragment declares the `sqlite-vec` extension (resolved
|
|
45
|
+
from the installed `sqlite-vec` package, which the plugin depends on) and the
|
|
46
|
+
`embed()` function entry. Discovery can be turned off per-invocation with
|
|
47
|
+
`--no-plugin` or `DIRSQL_NO_PLUGIN=1`
|
|
48
|
+
([reference](./reference/cli.md#plugins)).
|
|
49
|
+
|
|
50
|
+
For the common case — one glob, one question, top-k paths — the package is
|
|
51
|
+
also its own command, generating and running exactly that SQL:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
uvx dirsql-plugin-embeddings '**/*.md' "local private models" -k 10
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The corpus glob is a **required** first positional — the plugin never picks a
|
|
58
|
+
default corpus for you — and a bare glob is normalized to the `./`-relative
|
|
59
|
+
form the SQL layer requires. Results print as ranked `path<TAB>distance`
|
|
60
|
+
lines, closest first. See
|
|
61
|
+
[Search documents by meaning](./howto/search-by-meaning.md) for the guide to
|
|
62
|
+
both styles.
|
|
63
|
+
|
|
64
|
+
### Zero cost when unused
|
|
65
|
+
|
|
66
|
+
`embed()` is [inert until called](./reference/config.md#worker-lifecycle):
|
|
67
|
+
installing the plugin changes nothing for queries that never call it. No
|
|
68
|
+
worker process is spawned, no model is loaded or downloaded, and no cache is
|
|
69
|
+
touched. Only what a query's glob actually selects is ever embedded — the
|
|
70
|
+
worker receives **values, not paths**, and never opens files itself.
|
|
71
|
+
|
|
72
|
+
### Model
|
|
73
|
+
|
|
74
|
+
Embeddings come from [model2vec](https://github.com/MinishLab/model2vec)
|
|
75
|
+
static models — inference needs numpy and tokenizers only, no torch, so the
|
|
76
|
+
plugin stays light enough for `uvx` ephemeral environments and is fast on
|
|
77
|
+
CPU. The default model is
|
|
78
|
+
[`minishlab/potion-retrieval-32M`](https://huggingface.co/minishlab/potion-retrieval-32M).
|
|
79
|
+
|
|
80
|
+
The very first `embed()` call downloads the model (on the order of a hundred
|
|
81
|
+
megabytes — expect seconds to a few minutes depending on your connection,
|
|
82
|
+
with progress on stderr) into the standard Hugging Face cache
|
|
83
|
+
(`~/.cache/huggingface`), which persists across `uvx` environments; every
|
|
84
|
+
later run loads it from disk.
|
|
85
|
+
|
|
86
|
+
Override the model per call with the optional second argument —
|
|
87
|
+
`embed(text, 'model-id')` — or per run with the one-liner's `--model` flag,
|
|
88
|
+
which templates the same second argument. The id must be a
|
|
89
|
+
**model2vec-loadable** model; sentence-transformers/torch models are out of
|
|
90
|
+
scope.
|
|
91
|
+
|
|
92
|
+
### Vector cache
|
|
93
|
+
|
|
94
|
+
Computed vectors are cached at `~/.cache/dirsql/embeddings/` (respecting
|
|
95
|
+
`XDG_CACHE_HOME`), keyed on the SHA-256 of the value bytes plus the model
|
|
96
|
+
identifier. Changing either recomputes — switching models never serves stale
|
|
97
|
+
vectors — and re-running a query over unchanged files is cache hits all the
|
|
98
|
+
way. There is no eviction: the directory is **safe to wipe at any time**; the
|
|
99
|
+
only cost is re-embedding. The cache never lives inside a queried tree — the
|
|
100
|
+
worker writes nothing into the directories you query.
|
|
@@ -76,11 +76,12 @@ Config flags are subcommand-local: pass them after `server`
|
|
|
76
76
|
|
|
77
77
|
### Defaults
|
|
78
78
|
|
|
79
|
-
- Per-query timeout: **30 seconds
|
|
80
|
-
`408 Request Timeout`.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
- Per-query timeout: **30 seconds**, in server mode only. A query exceeding
|
|
80
|
+
it returns `408 Request Timeout`. One-shot [`dirsql query`](#dirsql-query)
|
|
81
|
+
has no built-in timeout.
|
|
82
|
+
- `on-file` command hooks run **unbounded**; bound one by wrapping its
|
|
83
|
+
command in `timeout(1)` (see
|
|
84
|
+
[Bounding a hook](./hooks.md#bounding-a-hook)).
|
|
84
85
|
|
|
85
86
|
### Configless mode
|
|
86
87
|
|
|
@@ -166,13 +167,17 @@ uses**, so behavior is identical to `POST /query` by construction:
|
|
|
166
167
|
(`--persist=/path`) so it does not swallow the SQL argument.
|
|
167
168
|
- **`--no-ignore`** is honored: path-tables in the query scan files a
|
|
168
169
|
`.gitignore` would hide. See [Skip rules](./path-tables.md#skip-rules).
|
|
169
|
-
- **`on-file` hooks**
|
|
170
|
-
[
|
|
171
|
-
- The **
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
- **`on-file` hooks** apply identically (unbounded; wrap in `timeout(1)` to
|
|
171
|
+
bound — see [Bounding a hook](./hooks.md#bounding-a-hook)).
|
|
172
|
+
- The **read-only rule** and the `_dirsql_*` **internal-table denial** apply
|
|
173
|
+
identically. A rejected read is an error, not empty output. The read-only
|
|
174
|
+
rule here governs SQL statements; dirsql separately never modifies the
|
|
175
|
+
files it indexes — see
|
|
175
176
|
[Read-only by design](../explanation#read-only-by-design).
|
|
177
|
+
- **No per-query timeout.** Unlike the server's 30-second bound (`408`),
|
|
178
|
+
a one-shot query runs to completion — the process *is* the query, so
|
|
179
|
+
cap it from the shell if you want one: `timeout 60 dirsql query "<sql>"`
|
|
180
|
+
(see `timeout(1)`).
|
|
176
181
|
|
|
177
182
|
#### `--on-file <command>`
|
|
178
183
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Configuration file (`.dirsql.toml`)
|
|
2
2
|
|
|
3
3
|
`.dirsql.toml` is a TOML file with one optional `[dirsql]` section, zero or
|
|
4
|
-
more `[[dirsql.extension]]` entries,
|
|
4
|
+
more `[[dirsql.extension]]` entries, zero or more `[[dirsql.function]]`
|
|
5
|
+
entries, and zero or more `[[table]]` entries.
|
|
5
6
|
An empty file is valid. A missing `[dirsql]` section behaves as an
|
|
6
7
|
all-defaults one. Unknown keys are a parse error at every level (top level,
|
|
7
|
-
`[dirsql]`, `[[table]]`, `[[dirsql.extension]]`) — a
|
|
8
|
-
fails loudly, naming the offending key, rather than
|
|
8
|
+
`[dirsql]`, `[[table]]`, `[[dirsql.extension]]`, `[[dirsql.function]]`) — a
|
|
9
|
+
typo or a removed key fails loudly, naming the offending key, rather than
|
|
10
|
+
silently no-opping.
|
|
9
11
|
|
|
10
12
|
The [CLI](./cli.md) loads a config only when you pass it with `-c/--config`;
|
|
11
13
|
with none given [no named tables](./cli.md#configless-mode) are defined (a
|
|
@@ -23,7 +25,12 @@ the config file's location. See [`--config`](./cli.md#flags).
|
|
|
23
25
|
| Key | Type | Default | Description |
|
|
24
26
|
|---|---|---|---|
|
|
25
27
|
| `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
|
-
|
|
28
|
+
|
|
29
|
+
There is no timeout key. `on-file` hook runs are unbounded; to bound one, wrap
|
|
30
|
+
its command in `timeout(1)` (see [Command hooks](./hooks.md#bounding-a-hook)).
|
|
31
|
+
A config that still declares the removed `hook-timeout` key fails to load with
|
|
32
|
+
an error naming that replacement. [`[[dirsql.function]]`](#dirsql-function)
|
|
33
|
+
worker calls have their own per-call `timeout` key (default 30 seconds).
|
|
27
34
|
|
|
28
35
|
The top-level `.dirsql/` directory under the root is always excluded from
|
|
29
36
|
scanning, whether or not it appears in `ignore` — it is reserved for
|
|
@@ -34,7 +41,6 @@ directory.
|
|
|
34
41
|
```toml
|
|
35
42
|
[dirsql]
|
|
36
43
|
ignore = ["node_modules/**", ".git/**"]
|
|
37
|
-
hook-timeout = 300
|
|
38
44
|
```
|
|
39
45
|
|
|
40
46
|
Persistence is not a config key. Keep the SQLite index on disk between runs
|
|
@@ -86,6 +92,72 @@ extension-backed **virtual table** cannot be declared as a `[[table]]` —
|
|
|
86
92
|
`dirsql` tables are per-file row tables, so a `CREATE VIRTUAL TABLE` DDL is
|
|
87
93
|
rejected; call the extension's functions in queries instead.
|
|
88
94
|
|
|
95
|
+
## `[[dirsql.function]]`
|
|
96
|
+
|
|
97
|
+
Each entry declares a **worker-backed SQL scalar function**: a function
|
|
98
|
+
queries can call by name, whose values are computed by an external worker
|
|
99
|
+
process you (or a [plugin](../plugins.md)) provide. This is how a plugin adds
|
|
100
|
+
computed values — an embedding, a hash, a classification — to SQL without
|
|
101
|
+
`dirsql` knowing anything about the domain: the config names the function and
|
|
102
|
+
the command, the worker does the work. The first-party
|
|
103
|
+
[`dirsql-plugin-embeddings`](../plugins.md#dirsql-plugin-embeddings) declares
|
|
104
|
+
its `embed()` function exactly this way.
|
|
105
|
+
|
|
106
|
+
| Key | Required | Description |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| `name` | yes | The SQL name queries call. Must be a plain identifier — an ASCII letter or underscore followed by ASCII letters, digits, or underscores. |
|
|
109
|
+
| `args` | yes | The accepted arities (argument counts), each `0`–`127`. The function is registered once per listed arity, so `args = [1, 2]` makes both `f(x)` and `f(x, y)` callable and any other count a SQL error. An empty list, an out-of-range value, or a repeated value is a config error. |
|
|
110
|
+
| `command` | yes (non-empty) | The worker command. Argv-split with the same no-shell quoting rules as [command hooks](./hooks.md#argv-not-a-shell); runs in the config file's directory. |
|
|
111
|
+
| `deterministic` | no (default `false`) | When `true`, the function is registered with `SQLITE_DETERMINISTIC`, letting SQLite cache and reuse results for identical arguments within a query. Only set it when the worker really is a pure function of its arguments. |
|
|
112
|
+
| `timeout` | no | Per-**call** time bound: a positive integer is whole seconds (`timeout = 600`), a string is an integer suffixed `s` or `ms` (`"600s"`, `"250ms"`). When absent, the function mechanism's own 30-second default applies. |
|
|
113
|
+
|
|
114
|
+
```toml
|
|
115
|
+
[[dirsql.function]]
|
|
116
|
+
name = "embed"
|
|
117
|
+
args = [1, 2]
|
|
118
|
+
command = "dirsql-plugin-embeddings worker"
|
|
119
|
+
deterministic = true
|
|
120
|
+
timeout = "600s" # generous: absorbs a first-call model download
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Worker lifecycle
|
|
124
|
+
|
|
125
|
+
Declaring a function is **inert**: at startup the function is registered on
|
|
126
|
+
the connection and nothing else happens. No process is spawned and nothing is
|
|
127
|
+
read until a query actually calls the function — a declared function nobody
|
|
128
|
+
calls costs nothing.
|
|
129
|
+
|
|
130
|
+
On the **first call**, `dirsql` spawns `command` and keeps that one worker
|
|
131
|
+
process alive for the rest of the invocation, sending it every subsequent
|
|
132
|
+
call — one process total, never one per row or per file. The worker is torn
|
|
133
|
+
down when the invocation ends.
|
|
134
|
+
|
|
135
|
+
The `timeout` bounds each **round-trip call**, not the query: a query that
|
|
136
|
+
calls the function on 10 000 rows is 10 000 individually timed calls. A call
|
|
137
|
+
that times out, or a worker that crashes or closes its pipes, fails the query
|
|
138
|
+
with an actionable error naming the function and command; the worker is
|
|
139
|
+
killed and the next call starts a fresh one.
|
|
140
|
+
|
|
141
|
+
Calling a function that no loaded config declares (say, the plugin providing
|
|
142
|
+
it is not installed) is SQLite's ordinary `no such function` error.
|
|
143
|
+
|
|
144
|
+
### Worker protocol
|
|
145
|
+
|
|
146
|
+
The worker speaks **newline-delimited JSON** over its stdin/stdout — one
|
|
147
|
+
request line in, one response line out, per call:
|
|
148
|
+
|
|
149
|
+
- **Request:** `{"call": [<arg>, ...]}` with the call's SQL arguments
|
|
150
|
+
encoded as: TEXT → JSON string, INTEGER/REAL → JSON number, NULL → `null`,
|
|
151
|
+
BLOB → `{"$bytes": "<base64>"}`.
|
|
152
|
+
- **Response:** `{"ok": <value>}` with the same scalar encodings — a JSON
|
|
153
|
+
array or any other object is bound as TEXT, its JSON text (which is how an
|
|
154
|
+
embedding worker returns a vector: `sqlite-vec`'s distance functions accept
|
|
155
|
+
JSON-text vectors) — or `{"err": "message"}`, which **fails the query**
|
|
156
|
+
with that message. An `{"err": ...}` response leaves the healthy worker
|
|
157
|
+
running; only transport failures (timeout, crash) recycle it.
|
|
158
|
+
- **stderr passes through** to `dirsql`'s stderr, so a worker's progress
|
|
159
|
+
bars and download logs reach the terminal.
|
|
160
|
+
|
|
89
161
|
## `[[table]]`
|
|
90
162
|
|
|
91
163
|
Each entry maps a glob pattern to a SQL table. A table's columns are exactly
|
|
@@ -143,16 +215,18 @@ dirsql -c ./.dirsql.toml -c ~/team/embeddings.toml -c ./local.toml
|
|
|
143
215
|
|
|
144
216
|
The configs load and merge in **argv order**:
|
|
145
217
|
|
|
146
|
-
- **`[[table]]`, `ignore`, and `[[dirsql.
|
|
147
|
-
all configs, in order.
|
|
148
|
-
- **Each config's `on-file` hooks
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
218
|
+
- **`[[table]]`, `ignore`, `[[dirsql.extension]]`, and `[[dirsql.function]]`
|
|
219
|
+
entries accumulate** across all configs, in order.
|
|
220
|
+
- **Each config's `on-file` hooks and `[[dirsql.function]]` workers run from
|
|
221
|
+
that config file's own directory** — so a relative command like
|
|
222
|
+
`on-file = "sh ./extract.sh"` resolves against the config that declared it,
|
|
223
|
+
wherever it lives.
|
|
152
224
|
- Each config is **validated on its own** (the [parse errors](#parse-errors)
|
|
153
|
-
below apply per file). There is no cross-file merge validation, with
|
|
154
|
-
structural
|
|
155
|
-
error**, naming the table
|
|
225
|
+
below apply per file). There is no cross-file merge validation, with two
|
|
226
|
+
structural exceptions: **two configs defining a table of the same name is
|
|
227
|
+
an error**, naming the table, and **two configs declaring a function of the
|
|
228
|
+
same name is an error**, naming the function and both sources — never a
|
|
229
|
+
silent last-writer-wins.
|
|
156
230
|
|
|
157
231
|
The index [root](./cli.md#flags) is the invocation directory regardless of where
|
|
158
232
|
any config lives. With no `-c`, [no named tables](./cli.md#configless-mode) are
|
|
@@ -174,20 +248,32 @@ SDKs raise/reject) when:
|
|
|
174
248
|
> `[[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 './'``
|
|
175
249
|
|
|
176
250
|
- A `[[dirsql.extension]]` entry omits `path`, or `path` is empty.
|
|
177
|
-
- `
|
|
251
|
+
- A `[[dirsql.function]]` entry omits `name`, `command`, or `args` (or
|
|
252
|
+
`command` is empty/whitespace); its `name` is not a plain identifier; its
|
|
253
|
+
`args` list is empty, repeats an arity, or lists one outside `0`–`127`; or
|
|
254
|
+
its `timeout` is not positive whole seconds / a positive-integer `"...s"` or
|
|
255
|
+
`"...ms"` string.
|
|
256
|
+
- `[dirsql]` declares the removed `hook-timeout` key (the error names the
|
|
257
|
+
`timeout(1)` replacement).
|
|
178
258
|
|
|
179
259
|
## Full example
|
|
180
260
|
|
|
181
261
|
```toml
|
|
182
262
|
[dirsql]
|
|
183
263
|
ignore = ["node_modules/**", ".git/**", "dist/**"]
|
|
184
|
-
hook-timeout = 120
|
|
185
264
|
|
|
186
265
|
[[dirsql.extension]]
|
|
187
266
|
path = "sqlite_vec" # Python module name; on Node use the
|
|
188
267
|
# platform package, e.g. sqlite-vec-linux-x64
|
|
189
268
|
entrypoint = "sqlite3_vec_init"
|
|
190
269
|
|
|
270
|
+
[[dirsql.function]]
|
|
271
|
+
name = "embed"
|
|
272
|
+
args = [1, 2]
|
|
273
|
+
command = "dirsql-plugin-embeddings worker"
|
|
274
|
+
deterministic = true
|
|
275
|
+
timeout = "600s"
|
|
276
|
+
|
|
191
277
|
[[table]]
|
|
192
278
|
ddl = "CREATE TABLE comments (author TEXT, body TEXT)"
|
|
193
279
|
glob = "_comments/*/*.jsonl"
|
|
@@ -58,18 +58,30 @@ everything above the last line. `jq` users: pass `-c` so the JSON is emitted
|
|
|
58
58
|
compactly on one line.
|
|
59
59
|
:::
|
|
60
60
|
|
|
61
|
-
###
|
|
61
|
+
### Bounding a hook
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
Hook runs are **unbounded** — `dirsql` imposes no timeout of its own. To
|
|
64
|
+
bound a hook, make the bound part of the command by wrapping it in
|
|
65
|
+
`timeout(1)`:
|
|
66
66
|
|
|
67
67
|
```toml
|
|
68
|
-
|
|
69
|
-
hook-timeout = 300 # positive whole seconds
|
|
68
|
+
on-file = "timeout 30 my-extractor {path}"
|
|
70
69
|
```
|
|
71
70
|
|
|
72
|
-
|
|
71
|
+
When the wrapper kills an overrunning command, the run exits non-zero and
|
|
72
|
+
the ordinary [failure semantics](#failure-semantics) apply — the file is
|
|
73
|
+
skipped, the scan continues.
|
|
74
|
+
|
|
75
|
+
::: warning Windows
|
|
76
|
+
Windows's built-in `timeout` command is a *sleep*, not a bound — it cannot
|
|
77
|
+
wrap another command. On Windows, bound the work inside the command itself
|
|
78
|
+
(or accept unbounded runs).
|
|
79
|
+
:::
|
|
80
|
+
|
|
81
|
+
[`[[dirsql.function]]`](./config.md#dirsql-function) worker calls are
|
|
82
|
+
different: a call is a round-trip on a persistent worker process, which
|
|
83
|
+
`timeout(1)` cannot express, so the function mechanism carries its own
|
|
84
|
+
per-call `timeout` key with a 30-second default.
|
|
73
85
|
|
|
74
86
|
### Failure semantics
|
|
75
87
|
|
|
@@ -77,8 +89,8 @@ A hook run fails when the command:
|
|
|
77
89
|
|
|
78
90
|
- cannot be spawned (e.g. the program is not found),
|
|
79
91
|
- exits non-zero (the exit code — or `signal`, if killed by one — and the
|
|
80
|
-
stderr tail are reported)
|
|
81
|
-
|
|
92
|
+
stderr tail are reported; a `timeout(1)` wrapper killing an overrun lands
|
|
93
|
+
here),
|
|
82
94
|
- exits zero but prints no non-empty stdout line,
|
|
83
95
|
- or prints output that does not parse as a JSON array of row objects.
|
|
84
96
|
|
|
@@ -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.
|
|
7
|
+
version = "0.4.18"
|
|
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
|
|
@@ -54,6 +54,7 @@ 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' },
|
|
57
58
|
{ text: "Skip files you don't want indexed", link: '/howto/skip-files' },
|
|
58
59
|
{ text: 'Load a SQLite extension', link: '/howto/load-extension' },
|
|
59
60
|
{ text: 'Keep the index across restarts', link: '/howto/persist' },
|