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.
- {dirsql-0.4.8 → dirsql-0.4.10}/Cargo.lock +1 -1
- {dirsql-0.4.8 → dirsql-0.4.10}/PKG-INFO +1 -1
- dirsql-0.4.10/dirsql/cli/resolve_config_extensions.py +70 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/.vitepress/config.ts +7 -0
- dirsql-0.4.10/docs/plugins.md +123 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/Cargo.toml +1 -1
- dirsql-0.4.10/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +8 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/.vitepress/config.ts +7 -0
- dirsql-0.4.10/packages/python/docs/plugins.md +123 -0
- dirsql-0.4.10/packages/python/e2e-attestations/fix-754-discovery-ext-resolution.json +7 -0
- dirsql-0.4.10/packages/rust/docs/plugins.md +123 -0
- dirsql-0.4.8/dirsql/cli/resolve_config_extensions.py +0 -55
- {dirsql-0.4.8 → dirsql-0.4.10}/Cargo.toml +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/README.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/__init__.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/_async.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/binary_path.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/is_windows.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/py.typed +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/resolve_config_extensions.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/AGENTS.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/explanation.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/getting-started.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/embed.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/persist.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/index.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/migrations.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/package.json +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/cli.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/columns.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/hooks.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/docs/reference/sdk.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/README.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/conftest.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/cli.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/hooks.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/docs/reference/sdk.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/e2e-attestations/feat-745-python-no-ignore.json +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/src/lib.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/Cargo.toml +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/README.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-batch-ingest-transaction.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-chained-pre-post-query-hooks.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-fan-out-file-table-matching.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-persist-wal.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-repeatable-builder-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-repeatable-cli-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-13-subcommand-local-config-flags.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-19-path-table-query-fallback.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-19-path-table-vtab.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-20-path-table-glob-semantics.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-20-schema-inference.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-21-on-file-flag.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-23-init-escalation-example.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-23-query-default-cli.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-07-29-on-file-failures-accumulate.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-02-drop-regex.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-02-per-file-scan-failures.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-03-gitignore-by-default.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/2026-08-03-nested-default-ignores.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/changelog.d/README.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/migrations.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/cli.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/hooks.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/docs/reference/sdk.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-fan-out-file-table-matching.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-persist-wal.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-13-subcommand-local-config-flags.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-20-path-table-glob-semantics.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-23-init-escalation-example.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-23-query-default-cli.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-08-02-per-file-scan-failures.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-08-03-gitignore-by-default.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/2026-08-03-nested-default-ignores.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/migrations.d/README.md +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/command.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/config.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/db.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/default_config.toml +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/parsed_vtab.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.8 → dirsql-0.4.10}/pyproject.toml +0 -0
|
@@ -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.
|
|
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,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
|
|
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
|