dirsql 0.3.70__tar.gz → 0.3.71__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.3.70 → dirsql-0.3.71}/Cargo.lock +1 -1
- {dirsql-0.3.70 → dirsql-0.3.71}/PKG-INFO +1 -1
- {dirsql-0.3.70/packages/rust → dirsql-0.3.71}/docs/reference/cli.md +42 -1
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/Cargo.toml +1 -1
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/reference/cli.md +42 -1
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/e2e-attestation.json +2 -2
- {dirsql-0.3.70 → dirsql-0.3.71/packages/rust}/docs/reference/cli.md +42 -1
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/bin/dirsql.rs +89 -7
- {dirsql-0.3.70 → dirsql-0.3.71}/Cargo.toml +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/README.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/__init__.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/_async.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/cli/binary_path.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/cli/is_windows.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/cli/main.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/py.typed +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/resolve_config_extensions.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/AGENTS.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/explanation.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/getting-started.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/howto/define-tables.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/howto/embed.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/howto/load-extension.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/howto/persist.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/howto/skip-files.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/index.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/migrations.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/package.json +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/playwright.config.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/reference/columns.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/reference/config.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/reference/hooks.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/reference/http-api.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/reference/sdk.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/tests/integration/sidebar.spec.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/docs/vitest.config.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/README.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/conftest.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/howto/define-tables.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/index.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/package.json +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/playwright.config.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/reference/config.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/reference/hooks.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/reference/sdk.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/tests/integration/sidebar.spec.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/vitest.config.ts +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/src/lib.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/tests/binding/__init__.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/python/tests/smoke/__init__.py +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/Cargo.toml +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/README.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/howto/define-tables.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/index.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/migrations.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/reference/config.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/reference/hooks.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/docs/reference/sdk.md +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/command.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/config.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/db.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.3.70 → dirsql-0.3.71}/pyproject.toml +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# CLI
|
|
2
2
|
|
|
3
|
-
The `dirsql` binary has
|
|
3
|
+
The `dirsql` binary has three modes:
|
|
4
4
|
|
|
5
5
|
| Invocation | Behavior |
|
|
6
6
|
|---|---|
|
|
7
7
|
| `dirsql` (no subcommand) | Start a long-lived HTTP server exposing a SQL view of a directory. See [HTTP API](./http-api.md). |
|
|
8
|
+
| `dirsql query "<sql>"` | Build the index, run one query, print the rows as JSON, exit. No server, no watch. |
|
|
8
9
|
| `dirsql init` | Generate a starter `.dirsql.toml` by running `claude` over a directory. |
|
|
9
10
|
|
|
10
11
|
## Installation
|
|
@@ -97,6 +98,46 @@ with a JSON body describing the failure:
|
|
|
97
98
|
| `0` | Clean shutdown after `SIGINT` / `SIGTERM`. |
|
|
98
99
|
| `1` | Failed to bind `host:port`, or an error during shutdown. |
|
|
99
100
|
|
|
101
|
+
## `dirsql query`
|
|
102
|
+
|
|
103
|
+
Run one SQL query from the shell — for ad-hoc inspection, scripting, and
|
|
104
|
+
docs verification snippets — without booting the server and `curl`ing it:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
dirsql query "SELECT _basename, _size FROM files ORDER BY _size DESC LIMIT 5"
|
|
108
|
+
# [{"_basename":"model.bin","_size":104857600}, …]
|
|
109
|
+
|
|
110
|
+
dirsql query "SELECT COUNT(*) AS n FROM posts" | jq '.[0].n'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The subcommand builds the index, runs the SQL, prints the result rows as a
|
|
114
|
+
JSON array on stdout (byte-identical to the [`POST /query`](./http-api.md)
|
|
115
|
+
response body), and exits `0`.
|
|
116
|
+
|
|
117
|
+
`dirsql query` is a thin adapter over the **same query pipeline the server
|
|
118
|
+
uses**, so behavior is identical to `POST /query` by construction:
|
|
119
|
+
|
|
120
|
+
- **Config discovery** honors `--config` (default `./.dirsql.toml`),
|
|
121
|
+
[zero-config mode](#zero-config-mode), and `--extension` overrides,
|
|
122
|
+
exactly as server mode does.
|
|
123
|
+
- **Hooks** ([`pre-query`](./hooks.md#pre-query) /
|
|
124
|
+
[`post-query`](./hooks.md#post-query)) and the
|
|
125
|
+
[`[dirsql].hook-timeout`](./config.md#dirsql-keys) apply identically.
|
|
126
|
+
- The **30-second query timeout**, the **read-only rule**, and the
|
|
127
|
+
`_dirsql_*` **internal-table denial** apply identically. A rejected read
|
|
128
|
+
is an error, not empty output.
|
|
129
|
+
|
|
130
|
+
Errors print the same diagnostic the HTTP `{"error": …}` body carries —
|
|
131
|
+
config failures, SQL errors, rejected reads, hook failures, timeouts — to
|
|
132
|
+
stderr, with exit code `1`.
|
|
133
|
+
|
|
134
|
+
### Exit codes
|
|
135
|
+
|
|
136
|
+
| Code | Meaning |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `0` | Query succeeded; rows printed on stdout. |
|
|
139
|
+
| `1` | Any failure: config, SQL, rejected read, hook, or timeout. The diagnostic is on stderr. |
|
|
140
|
+
|
|
100
141
|
## `dirsql init`
|
|
101
142
|
|
|
102
143
|
Generates a `.dirsql.toml` by running the `claude` CLI over the target
|
|
@@ -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.3.
|
|
7
|
+
version = "0.3.71"
|
|
8
8
|
edition.workspace = true
|
|
9
9
|
publish = false
|
|
10
10
|
readme = "README.md"
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# CLI
|
|
2
2
|
|
|
3
|
-
The `dirsql` binary has
|
|
3
|
+
The `dirsql` binary has three modes:
|
|
4
4
|
|
|
5
5
|
| Invocation | Behavior |
|
|
6
6
|
|---|---|
|
|
7
7
|
| `dirsql` (no subcommand) | Start a long-lived HTTP server exposing a SQL view of a directory. See [HTTP API](./http-api.md). |
|
|
8
|
+
| `dirsql query "<sql>"` | Build the index, run one query, print the rows as JSON, exit. No server, no watch. |
|
|
8
9
|
| `dirsql init` | Generate a starter `.dirsql.toml` by running `claude` over a directory. |
|
|
9
10
|
|
|
10
11
|
## Installation
|
|
@@ -97,6 +98,46 @@ with a JSON body describing the failure:
|
|
|
97
98
|
| `0` | Clean shutdown after `SIGINT` / `SIGTERM`. |
|
|
98
99
|
| `1` | Failed to bind `host:port`, or an error during shutdown. |
|
|
99
100
|
|
|
101
|
+
## `dirsql query`
|
|
102
|
+
|
|
103
|
+
Run one SQL query from the shell — for ad-hoc inspection, scripting, and
|
|
104
|
+
docs verification snippets — without booting the server and `curl`ing it:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
dirsql query "SELECT _basename, _size FROM files ORDER BY _size DESC LIMIT 5"
|
|
108
|
+
# [{"_basename":"model.bin","_size":104857600}, …]
|
|
109
|
+
|
|
110
|
+
dirsql query "SELECT COUNT(*) AS n FROM posts" | jq '.[0].n'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The subcommand builds the index, runs the SQL, prints the result rows as a
|
|
114
|
+
JSON array on stdout (byte-identical to the [`POST /query`](./http-api.md)
|
|
115
|
+
response body), and exits `0`.
|
|
116
|
+
|
|
117
|
+
`dirsql query` is a thin adapter over the **same query pipeline the server
|
|
118
|
+
uses**, so behavior is identical to `POST /query` by construction:
|
|
119
|
+
|
|
120
|
+
- **Config discovery** honors `--config` (default `./.dirsql.toml`),
|
|
121
|
+
[zero-config mode](#zero-config-mode), and `--extension` overrides,
|
|
122
|
+
exactly as server mode does.
|
|
123
|
+
- **Hooks** ([`pre-query`](./hooks.md#pre-query) /
|
|
124
|
+
[`post-query`](./hooks.md#post-query)) and the
|
|
125
|
+
[`[dirsql].hook-timeout`](./config.md#dirsql-keys) apply identically.
|
|
126
|
+
- The **30-second query timeout**, the **read-only rule**, and the
|
|
127
|
+
`_dirsql_*` **internal-table denial** apply identically. A rejected read
|
|
128
|
+
is an error, not empty output.
|
|
129
|
+
|
|
130
|
+
Errors print the same diagnostic the HTTP `{"error": …}` body carries —
|
|
131
|
+
config failures, SQL errors, rejected reads, hook failures, timeouts — to
|
|
132
|
+
stderr, with exit code `1`.
|
|
133
|
+
|
|
134
|
+
### Exit codes
|
|
135
|
+
|
|
136
|
+
| Code | Meaning |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `0` | Query succeeded; rows printed on stdout. |
|
|
139
|
+
| `1` | Any failure: config, SQL, rejected read, hook, or timeout. The diagnostic is on stderr. |
|
|
140
|
+
|
|
100
141
|
## `dirsql init`
|
|
101
142
|
|
|
102
143
|
Generates a `.dirsql.toml` by running the `claude` CLI over the target
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# CLI
|
|
2
2
|
|
|
3
|
-
The `dirsql` binary has
|
|
3
|
+
The `dirsql` binary has three modes:
|
|
4
4
|
|
|
5
5
|
| Invocation | Behavior |
|
|
6
6
|
|---|---|
|
|
7
7
|
| `dirsql` (no subcommand) | Start a long-lived HTTP server exposing a SQL view of a directory. See [HTTP API](./http-api.md). |
|
|
8
|
+
| `dirsql query "<sql>"` | Build the index, run one query, print the rows as JSON, exit. No server, no watch. |
|
|
8
9
|
| `dirsql init` | Generate a starter `.dirsql.toml` by running `claude` over a directory. |
|
|
9
10
|
|
|
10
11
|
## Installation
|
|
@@ -97,6 +98,46 @@ with a JSON body describing the failure:
|
|
|
97
98
|
| `0` | Clean shutdown after `SIGINT` / `SIGTERM`. |
|
|
98
99
|
| `1` | Failed to bind `host:port`, or an error during shutdown. |
|
|
99
100
|
|
|
101
|
+
## `dirsql query`
|
|
102
|
+
|
|
103
|
+
Run one SQL query from the shell — for ad-hoc inspection, scripting, and
|
|
104
|
+
docs verification snippets — without booting the server and `curl`ing it:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
dirsql query "SELECT _basename, _size FROM files ORDER BY _size DESC LIMIT 5"
|
|
108
|
+
# [{"_basename":"model.bin","_size":104857600}, …]
|
|
109
|
+
|
|
110
|
+
dirsql query "SELECT COUNT(*) AS n FROM posts" | jq '.[0].n'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The subcommand builds the index, runs the SQL, prints the result rows as a
|
|
114
|
+
JSON array on stdout (byte-identical to the [`POST /query`](./http-api.md)
|
|
115
|
+
response body), and exits `0`.
|
|
116
|
+
|
|
117
|
+
`dirsql query` is a thin adapter over the **same query pipeline the server
|
|
118
|
+
uses**, so behavior is identical to `POST /query` by construction:
|
|
119
|
+
|
|
120
|
+
- **Config discovery** honors `--config` (default `./.dirsql.toml`),
|
|
121
|
+
[zero-config mode](#zero-config-mode), and `--extension` overrides,
|
|
122
|
+
exactly as server mode does.
|
|
123
|
+
- **Hooks** ([`pre-query`](./hooks.md#pre-query) /
|
|
124
|
+
[`post-query`](./hooks.md#post-query)) and the
|
|
125
|
+
[`[dirsql].hook-timeout`](./config.md#dirsql-keys) apply identically.
|
|
126
|
+
- The **30-second query timeout**, the **read-only rule**, and the
|
|
127
|
+
`_dirsql_*` **internal-table denial** apply identically. A rejected read
|
|
128
|
+
is an error, not empty output.
|
|
129
|
+
|
|
130
|
+
Errors print the same diagnostic the HTTP `{"error": …}` body carries —
|
|
131
|
+
config failures, SQL errors, rejected reads, hook failures, timeouts — to
|
|
132
|
+
stderr, with exit code `1`.
|
|
133
|
+
|
|
134
|
+
### Exit codes
|
|
135
|
+
|
|
136
|
+
| Code | Meaning |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `0` | Query succeeded; rows printed on stdout. |
|
|
139
|
+
| `1` | Any failure: config, SQL, rejected read, hook, or timeout. The diagnostic is on stderr. |
|
|
140
|
+
|
|
100
141
|
## `dirsql init`
|
|
101
142
|
|
|
102
143
|
Generates a `.dirsql.toml` by running the `claude` CLI over the target
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
//! `dirsql` CLI binary.
|
|
1
|
+
//! `dirsql` CLI binary. Three modes:
|
|
2
2
|
//! - No subcommand: HTTP server documented in `docs/reference/cli.md`.
|
|
3
|
+
//! - `query`: one-shot query over the same pipeline the server uses; see
|
|
4
|
+
//! `docs/reference/cli.md`.
|
|
3
5
|
//! - `init`: starter `.dirsql.toml` generation; see `docs/reference/cli.md`.
|
|
4
6
|
//!
|
|
5
7
|
//! Only compiled with `--features cli`.
|
|
@@ -9,7 +11,8 @@ use std::process::ExitCode;
|
|
|
9
11
|
|
|
10
12
|
use clap::{Args, Parser, Subcommand};
|
|
11
13
|
use dirsql::cli::{
|
|
12
|
-
AppState, PostQuery, PreQuery, ServerConfig, init::InitOptions,
|
|
14
|
+
AppState, PostQuery, PreQuery, ServerConfig, execute::execute_query, init::InitOptions,
|
|
15
|
+
serve_with_state,
|
|
13
16
|
};
|
|
14
17
|
use dirsql::{DirSQL, Extension, Row, Table};
|
|
15
18
|
|
|
@@ -31,9 +34,9 @@ struct Cli {
|
|
|
31
34
|
|
|
32
35
|
/// Path to the config file (default: `./.dirsql.toml`). The index is
|
|
33
36
|
/// rooted at the directory containing this file. When the file does
|
|
34
|
-
/// not exist, a default `files` table is served. Used
|
|
35
|
-
///
|
|
36
|
-
#[arg(long, default_value = "./.dirsql.toml")]
|
|
37
|
+
/// not exist, a default `files` table is served. Used by server mode
|
|
38
|
+
/// and by the `query` subcommand.
|
|
39
|
+
#[arg(long, default_value = "./.dirsql.toml", global = true)]
|
|
37
40
|
config: PathBuf,
|
|
38
41
|
|
|
39
42
|
/// Bind address. Used when no subcommand is given.
|
|
@@ -53,8 +56,9 @@ struct Cli {
|
|
|
53
56
|
/// which need an interpreter this compiled binary lacks (see #227) — and
|
|
54
57
|
/// passes the resolved literal paths here. When any are present, the TOML
|
|
55
58
|
/// config's own extension entries are not loaded (the launcher already
|
|
56
|
-
/// merged and resolved them).
|
|
57
|
-
|
|
59
|
+
/// merged and resolved them). Used by server mode and by the `query`
|
|
60
|
+
/// subcommand.
|
|
61
|
+
#[arg(long = "extension", global = true)]
|
|
58
62
|
extension: Vec<String>,
|
|
59
63
|
}
|
|
60
64
|
|
|
@@ -63,6 +67,19 @@ enum Command {
|
|
|
63
67
|
/// Generate a starter `.dirsql.toml` by running `claude` over the
|
|
64
68
|
/// target directory.
|
|
65
69
|
Init(InitArgs),
|
|
70
|
+
|
|
71
|
+
/// Run one SQL query against the indexed directory, print the result
|
|
72
|
+
/// rows as JSON on stdout, and exit. No server, no watch. Shares the
|
|
73
|
+
/// server's query pipeline, so config discovery, hooks, the query
|
|
74
|
+
/// timeout, the read-only rule, and error classification are identical
|
|
75
|
+
/// to `POST /query`.
|
|
76
|
+
Query(QueryArgs),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#[derive(Debug, Args)]
|
|
80
|
+
struct QueryArgs {
|
|
81
|
+
/// The SQL to run (a single read-only statement).
|
|
82
|
+
sql: String,
|
|
66
83
|
}
|
|
67
84
|
|
|
68
85
|
#[derive(Debug, Args)]
|
|
@@ -86,10 +103,51 @@ async fn main() -> ExitCode {
|
|
|
86
103
|
|
|
87
104
|
match cli.command.take() {
|
|
88
105
|
Some(Command::Init(args)) => run_init(args),
|
|
106
|
+
Some(Command::Query(args)) => run_query(&cli, args).await,
|
|
89
107
|
None => run_server(cli).await,
|
|
90
108
|
}
|
|
91
109
|
}
|
|
92
110
|
|
|
111
|
+
/// One-shot `dirsql query`: build the index exactly as server mode would
|
|
112
|
+
/// (same `load_state` / hook loading), run the SQL through the shared
|
|
113
|
+
/// [`execute_query`] pipeline, print the result JSON on stdout, and exit.
|
|
114
|
+
/// Any [`QueryFailure`](dirsql::cli::execute::QueryFailure) prints its
|
|
115
|
+
/// message — the same string the HTTP `{"error": …}` body carries — to
|
|
116
|
+
/// stderr with a non-zero exit.
|
|
117
|
+
async fn run_query(cli: &Cli, args: QueryArgs) -> ExitCode {
|
|
118
|
+
let state = load_state(cli);
|
|
119
|
+
let pre_query = load_pre_query(cli);
|
|
120
|
+
let post_query = load_post_query(cli);
|
|
121
|
+
// Same default the server binds with; the pipeline enforces it.
|
|
122
|
+
let timeout = ServerConfig::default().query_timeout;
|
|
123
|
+
|
|
124
|
+
match execute_query(
|
|
125
|
+
&state,
|
|
126
|
+
query_body(&args.sql),
|
|
127
|
+
timeout,
|
|
128
|
+
pre_query.as_ref(),
|
|
129
|
+
post_query.as_ref(),
|
|
130
|
+
)
|
|
131
|
+
.await
|
|
132
|
+
{
|
|
133
|
+
Ok(value) => {
|
|
134
|
+
println!("{value}");
|
|
135
|
+
ExitCode::SUCCESS
|
|
136
|
+
}
|
|
137
|
+
Err(failure) => {
|
|
138
|
+
eprintln!("dirsql query: {}", failure.message());
|
|
139
|
+
ExitCode::from(1)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/// Synthesize the exact `POST /query` body for a positional SQL argument,
|
|
145
|
+
/// so the shared pipeline's intake validation and `pre-query` hook see
|
|
146
|
+
/// byte-for-byte what an HTTP client would send.
|
|
147
|
+
fn query_body(sql: &str) -> String {
|
|
148
|
+
serde_json::json!({ "sql": sql }).to_string()
|
|
149
|
+
}
|
|
150
|
+
|
|
93
151
|
fn run_init(args: InitArgs) -> ExitCode {
|
|
94
152
|
let root = match args.root {
|
|
95
153
|
Some(p) => p,
|
|
@@ -322,6 +380,30 @@ async fn wait_for_shutdown() -> std::io::Result<()> {
|
|
|
322
380
|
mod tests {
|
|
323
381
|
use super::*;
|
|
324
382
|
|
|
383
|
+
#[test]
|
|
384
|
+
fn query_body_wraps_sql_in_the_http_request_shape() {
|
|
385
|
+
// The subcommand must feed the pipeline the exact body a curl'd
|
|
386
|
+
// `POST /query` carries, so intake validation stays single-sourced.
|
|
387
|
+
assert_eq!(query_body("SELECT 1"), r#"{"sql":"SELECT 1"}"#);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
#[test]
|
|
391
|
+
fn query_body_escapes_sql_as_json() {
|
|
392
|
+
// SQL containing quotes/newlines must arrive as valid JSON, not be
|
|
393
|
+
// spliced raw into the body.
|
|
394
|
+
assert_eq!(
|
|
395
|
+
query_body("SELECT \"a\"\nFROM t"),
|
|
396
|
+
r#"{"sql":"SELECT \"a\"\nFROM t"}"#
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
#[test]
|
|
401
|
+
fn query_body_preserves_blank_sql_for_the_shared_rejection() {
|
|
402
|
+
// Blank SQL is NOT rejected here: it flows to the pipeline's shared
|
|
403
|
+
// empty-rejection so both surfaces emit the identical message.
|
|
404
|
+
assert_eq!(query_body(" "), r#"{"sql":" "}"#);
|
|
405
|
+
}
|
|
406
|
+
|
|
325
407
|
#[test]
|
|
326
408
|
fn parse_extension_specs_handles_bare_path_and_entrypoint() {
|
|
327
409
|
let specs = vec![
|
|
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
|
|
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
|
|
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
|
{dirsql-0.3.70 → dirsql-0.3.71}/packages/python/docs/tests/integration/language-flag.spec.ts
RENAMED
|
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
|
|
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
|