dirsql 0.3.3__tar.gz → 0.3.5__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.3 → dirsql-0.3.5}/Cargo.lock +1 -1
- {dirsql-0.3.3 → dirsql-0.3.5}/PKG-INFO +2 -2
- {dirsql-0.3.3/packages/python → dirsql-0.3.5}/README.md +1 -1
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/.vitepress/config.ts +1 -0
- {dirsql-0.3.3/packages/python → dirsql-0.3.5}/docs/guide/cli.md +7 -0
- dirsql-0.3.5/docs/guide/init.md +84 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/Cargo.toml +1 -1
- {dirsql-0.3.3 → dirsql-0.3.5/packages/python}/README.md +1 -1
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/.vitepress/config.ts +1 -0
- {dirsql-0.3.3 → dirsql-0.3.5/packages/python}/docs/guide/cli.md +7 -0
- dirsql-0.3.5/packages/python/docs/guide/init.md +84 -0
- dirsql-0.3.5/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/Cargo.toml +5 -1
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/cli.md +7 -0
- dirsql-0.3.5/packages/rust/docs/guide/init.md +84 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/bin/dirsql.rs +75 -10
- dirsql-0.3.5/packages/rust/src/cli/init.rs +152 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/cli/mod.rs +1 -0
- dirsql-0.3.5/packages/rust/tests/init_e2e.rs +85 -0
- dirsql-0.3.5/packages/rust/tests/init_integration.rs +301 -0
- dirsql-0.3.5/pyproject.toml +71 -0
- dirsql-0.3.3/pyproject.toml +0 -59
- dirsql-0.3.3/python/dirsql/_cli/binary_path_test.py +0 -70
- dirsql-0.3.3/python/dirsql/_cli/is_windows_test.py +0 -15
- dirsql-0.3.3/python/dirsql/_cli/main_test.py +0 -77
- {dirsql-0.3.3 → dirsql-0.3.5}/Cargo.toml +0 -0
- {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/__init__.py +0 -0
- {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_async.py +0 -0
- {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_cli/__init__.py +0 -0
- {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_cli/binary_path.py +0 -0
- {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_cli/is_windows.py +0 -0
- {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_cli/main.py +0 -0
- {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/test_async.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/AGENTS.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/api/index.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/getting-started.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/async.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/config.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/crdt.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/persistence.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/querying.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/tables.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/watching.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/index.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/migrations.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/package.json +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/playwright.config.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/docs/vitest.config.ts +0 -0
- {dirsql-0.3.3/packages/python → dirsql-0.3.5/packages}/python/conftest.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/api/index.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/async.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/config.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/crdt.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/persistence.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/querying.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/tables.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/watching.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/index.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/package.json +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/playwright.config.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/vitest.config.ts +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/src/lib.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_async_dirsql.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_binding.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_dirsql.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_docs_examples.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_docs_gaps.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_from_config.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_persist.py +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/README.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/api/index.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/async.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/config.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/crdt.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/persistence.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/querying.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/tables.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/watching.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/index.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/migrations.md +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/config.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/db.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/async_sdk.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/cli_e2e.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/cli_integration.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/docs_examples.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/docs_gaps.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/from_config.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/persist.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/readonly_query.rs +0 -0
- {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/sdk.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dirsql
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
4
4
|
Requires-Dist: pytest>=8 ; extra == 'dev'
|
|
5
5
|
Requires-Dist: pytest-describe>=2 ; extra == 'dev'
|
|
6
6
|
Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
|
|
@@ -33,7 +33,7 @@ Each wheel also bundles the `dirsql` HTTP-server CLI as a console script, so `pi
|
|
|
33
33
|
|
|
34
34
|
## Publishing (maintainers)
|
|
35
35
|
|
|
36
|
-
Handled by `.github/workflows/publish.yml` (invoked from `minor-release.yml` / `patch-release.yml`). For each target triple the `build` job `cargo build`s the Rust CLI with `--features cli`, stages the binary into `
|
|
36
|
+
Handled by `.github/workflows/publish.yml` (invoked from `minor-release.yml` / `patch-release.yml`). For each target triple the `build` job `cargo build`s the Rust CLI with `--features cli`, stages the binary into `dirsql/_binary/`, runs `maturin build` (which picks the binary up via the `[tool.maturin] include` rule in `pyproject.toml`), and the wheels + sdist are then trusted-published to PyPI.
|
|
37
37
|
|
|
38
38
|
## Quick Start
|
|
39
39
|
|
|
@@ -16,7 +16,7 @@ Each wheel also bundles the `dirsql` HTTP-server CLI as a console script, so `pi
|
|
|
16
16
|
|
|
17
17
|
## Publishing (maintainers)
|
|
18
18
|
|
|
19
|
-
Handled by `.github/workflows/publish.yml` (invoked from `minor-release.yml` / `patch-release.yml`). For each target triple the `build` job `cargo build`s the Rust CLI with `--features cli`, stages the binary into `
|
|
19
|
+
Handled by `.github/workflows/publish.yml` (invoked from `minor-release.yml` / `patch-release.yml`). For each target triple the `build` job `cargo build`s the Rust CLI with `--features cli`, stages the binary into `dirsql/_binary/`, runs `maturin build` (which picks the binary up via the `[tool.maturin] include` rule in `pyproject.toml`), and the wheels + sdist are then trusted-published to PyPI.
|
|
20
20
|
|
|
21
21
|
## Quick Start
|
|
22
22
|
|
|
@@ -29,6 +29,7 @@ export default defineConfig({
|
|
|
29
29
|
text: 'How-to Guides',
|
|
30
30
|
items: [
|
|
31
31
|
{ text: 'Configuration File', link: '/guide/config' },
|
|
32
|
+
{ text: 'Generating a Config (`init`)', link: '/guide/init' },
|
|
32
33
|
{ text: 'Defining Tables', link: '/guide/tables' },
|
|
33
34
|
{ text: 'Querying', link: '/guide/querying' },
|
|
34
35
|
{ text: 'File Watching', link: '/guide/watching' },
|
|
@@ -32,6 +32,13 @@ dirsql
|
|
|
32
32
|
The `cli` feature is **opt-in**. Adding `dirsql` as a library dependency (`cargo add dirsql`) pulls no CLI dependencies — only the core library. See the [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust) for details.
|
|
33
33
|
:::
|
|
34
34
|
|
|
35
|
+
## Subcommands
|
|
36
|
+
|
|
37
|
+
| Command | Purpose |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `dirsql` (no subcommand) | Start the long-lived HTTP server (default behavior, see below). |
|
|
40
|
+
| `dirsql init` | Generate a starter `.dirsql.toml` from the contents of a directory. See [Generating a Config](./init.md). |
|
|
41
|
+
|
|
35
42
|
## Running the server
|
|
36
43
|
|
|
37
44
|
Run `dirsql` from the directory containing your files:
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
canonical: https://thekevinscott.github.io/dirsql/guide/init
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Generating a config with `dirsql init`
|
|
6
|
+
|
|
7
|
+
> Online: <https://thekevinscott.github.io/dirsql/guide/init>
|
|
8
|
+
|
|
9
|
+
`dirsql init` generates a `.dirsql.toml` by running `claude` over the target directory.
|
|
10
|
+
|
|
11
|
+
The output is limited to filesystem-fact tables. For content-aware schemas, see [Defining Tables](./tables.md).
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Mixed files
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
my-downloads/
|
|
19
|
+
├── archive.zip
|
|
20
|
+
├── invoice.pdf
|
|
21
|
+
├── notes.txt
|
|
22
|
+
└── photo.jpg
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```toml
|
|
26
|
+
[[table]]
|
|
27
|
+
ddl = "CREATE TABLE files (_path TEXT, _ext TEXT, _size INTEGER)"
|
|
28
|
+
glob = "*"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Path captures
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
photos/
|
|
35
|
+
├── 2024-01/
|
|
36
|
+
│ ├── beach.jpg
|
|
37
|
+
│ └── sunset.jpg
|
|
38
|
+
└── 2024-02/
|
|
39
|
+
├── snow.jpg
|
|
40
|
+
└── mountain.jpg
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```toml
|
|
44
|
+
[[table]]
|
|
45
|
+
ddl = "CREATE TABLE photos (month TEXT, _basename TEXT, _mtime INTEGER)"
|
|
46
|
+
glob = "{month}/*.jpg"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Multiple tables
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
my-blog/
|
|
53
|
+
├── posts/
|
|
54
|
+
│ ├── hello-world.md
|
|
55
|
+
│ └── second.md
|
|
56
|
+
└── _comments/
|
|
57
|
+
└── hello-world/
|
|
58
|
+
├── 2024-01-15.jsonl
|
|
59
|
+
└── 2024-02-03.jsonl
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```toml
|
|
63
|
+
[[table]]
|
|
64
|
+
ddl = "CREATE TABLE posts (_basename TEXT, _mtime INTEGER, _size INTEGER)"
|
|
65
|
+
glob = "posts/*.md"
|
|
66
|
+
|
|
67
|
+
[[table]]
|
|
68
|
+
ddl = "CREATE TABLE comments (thread_id TEXT, _basename TEXT, _mtime INTEGER)"
|
|
69
|
+
glob = "_comments/{thread_id}/*.jsonl"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`init` will not overwrite an existing config without `--force`.
|
|
73
|
+
|
|
74
|
+
## Flags
|
|
75
|
+
|
|
76
|
+
| Flag | Default | Description |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `--root <path>` | cwd | Directory to scan |
|
|
79
|
+
| `--output <path>` | `<root>/.dirsql.toml` | Output path |
|
|
80
|
+
| `--force` | off | Overwrite if the output exists |
|
|
81
|
+
|
|
82
|
+
## Authentication
|
|
83
|
+
|
|
84
|
+
Requires `claude` on `PATH` and signed in. There is no separate API key. If `claude` is missing, `dirsql init` raises an exception.
|
|
@@ -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.5"
|
|
8
8
|
edition.workspace = true
|
|
9
9
|
publish = false
|
|
10
10
|
readme = "README.md"
|
|
@@ -16,7 +16,7 @@ Each wheel also bundles the `dirsql` HTTP-server CLI as a console script, so `pi
|
|
|
16
16
|
|
|
17
17
|
## Publishing (maintainers)
|
|
18
18
|
|
|
19
|
-
Handled by `.github/workflows/publish.yml` (invoked from `minor-release.yml` / `patch-release.yml`). For each target triple the `build` job `cargo build`s the Rust CLI with `--features cli`, stages the binary into `
|
|
19
|
+
Handled by `.github/workflows/publish.yml` (invoked from `minor-release.yml` / `patch-release.yml`). For each target triple the `build` job `cargo build`s the Rust CLI with `--features cli`, stages the binary into `dirsql/_binary/`, runs `maturin build` (which picks the binary up via the `[tool.maturin] include` rule in `pyproject.toml`), and the wheels + sdist are then trusted-published to PyPI.
|
|
20
20
|
|
|
21
21
|
## Quick Start
|
|
22
22
|
|
|
@@ -29,6 +29,7 @@ export default defineConfig({
|
|
|
29
29
|
text: 'How-to Guides',
|
|
30
30
|
items: [
|
|
31
31
|
{ text: 'Configuration File', link: '/guide/config' },
|
|
32
|
+
{ text: 'Generating a Config (`init`)', link: '/guide/init' },
|
|
32
33
|
{ text: 'Defining Tables', link: '/guide/tables' },
|
|
33
34
|
{ text: 'Querying', link: '/guide/querying' },
|
|
34
35
|
{ text: 'File Watching', link: '/guide/watching' },
|
|
@@ -32,6 +32,13 @@ dirsql
|
|
|
32
32
|
The `cli` feature is **opt-in**. Adding `dirsql` as a library dependency (`cargo add dirsql`) pulls no CLI dependencies — only the core library. See the [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust) for details.
|
|
33
33
|
:::
|
|
34
34
|
|
|
35
|
+
## Subcommands
|
|
36
|
+
|
|
37
|
+
| Command | Purpose |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `dirsql` (no subcommand) | Start the long-lived HTTP server (default behavior, see below). |
|
|
40
|
+
| `dirsql init` | Generate a starter `.dirsql.toml` from the contents of a directory. See [Generating a Config](./init.md). |
|
|
41
|
+
|
|
35
42
|
## Running the server
|
|
36
43
|
|
|
37
44
|
Run `dirsql` from the directory containing your files:
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
canonical: https://thekevinscott.github.io/dirsql/guide/init
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Generating a config with `dirsql init`
|
|
6
|
+
|
|
7
|
+
> Online: <https://thekevinscott.github.io/dirsql/guide/init>
|
|
8
|
+
|
|
9
|
+
`dirsql init` generates a `.dirsql.toml` by running `claude` over the target directory.
|
|
10
|
+
|
|
11
|
+
The output is limited to filesystem-fact tables. For content-aware schemas, see [Defining Tables](./tables.md).
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Mixed files
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
my-downloads/
|
|
19
|
+
├── archive.zip
|
|
20
|
+
├── invoice.pdf
|
|
21
|
+
├── notes.txt
|
|
22
|
+
└── photo.jpg
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```toml
|
|
26
|
+
[[table]]
|
|
27
|
+
ddl = "CREATE TABLE files (_path TEXT, _ext TEXT, _size INTEGER)"
|
|
28
|
+
glob = "*"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Path captures
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
photos/
|
|
35
|
+
├── 2024-01/
|
|
36
|
+
│ ├── beach.jpg
|
|
37
|
+
│ └── sunset.jpg
|
|
38
|
+
└── 2024-02/
|
|
39
|
+
├── snow.jpg
|
|
40
|
+
└── mountain.jpg
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```toml
|
|
44
|
+
[[table]]
|
|
45
|
+
ddl = "CREATE TABLE photos (month TEXT, _basename TEXT, _mtime INTEGER)"
|
|
46
|
+
glob = "{month}/*.jpg"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Multiple tables
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
my-blog/
|
|
53
|
+
├── posts/
|
|
54
|
+
│ ├── hello-world.md
|
|
55
|
+
│ └── second.md
|
|
56
|
+
└── _comments/
|
|
57
|
+
└── hello-world/
|
|
58
|
+
├── 2024-01-15.jsonl
|
|
59
|
+
└── 2024-02-03.jsonl
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```toml
|
|
63
|
+
[[table]]
|
|
64
|
+
ddl = "CREATE TABLE posts (_basename TEXT, _mtime INTEGER, _size INTEGER)"
|
|
65
|
+
glob = "posts/*.md"
|
|
66
|
+
|
|
67
|
+
[[table]]
|
|
68
|
+
ddl = "CREATE TABLE comments (thread_id TEXT, _basename TEXT, _mtime INTEGER)"
|
|
69
|
+
glob = "_comments/{thread_id}/*.jsonl"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`init` will not overwrite an existing config without `--force`.
|
|
73
|
+
|
|
74
|
+
## Flags
|
|
75
|
+
|
|
76
|
+
| Flag | Default | Description |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `--root <path>` | cwd | Directory to scan |
|
|
79
|
+
| `--output <path>` | `<root>/.dirsql.toml` | Output path |
|
|
80
|
+
| `--force` | off | Overwrite if the output exists |
|
|
81
|
+
|
|
82
|
+
## Authentication
|
|
83
|
+
|
|
84
|
+
Requires `claude` on `PATH` and signed in. There is no separate API key. If `claude` is missing, `dirsql init` raises an exception.
|
|
File without changes
|
|
@@ -6,7 +6,11 @@ description = "Ephemeral SQL index over a local directory"
|
|
|
6
6
|
# version stays for the binding crates (publish = false).
|
|
7
7
|
version = "0.2.7"
|
|
8
8
|
edition.workspace = true
|
|
9
|
-
license.workspace = true
|
|
9
|
+
# Literal `license` (not `license.workspace = true`) because
|
|
10
|
+
# putitoutthere's preflight check reads `[package].license` directly
|
|
11
|
+
# from the crate's Cargo.toml and does not resolve workspace
|
|
12
|
+
# inheritance, surfacing PIOT_CRATES_MISSING_METADATA otherwise.
|
|
13
|
+
license = "MIT"
|
|
10
14
|
repository.workspace = true
|
|
11
15
|
# `docs/` is a symlink to the workspace `docs/` so the markdown ships with the
|
|
12
16
|
# crate; everything below is the VitePress build tooling we don't want to ship.
|
|
@@ -32,6 +32,13 @@ dirsql
|
|
|
32
32
|
The `cli` feature is **opt-in**. Adding `dirsql` as a library dependency (`cargo add dirsql`) pulls no CLI dependencies — only the core library. See the [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust) for details.
|
|
33
33
|
:::
|
|
34
34
|
|
|
35
|
+
## Subcommands
|
|
36
|
+
|
|
37
|
+
| Command | Purpose |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `dirsql` (no subcommand) | Start the long-lived HTTP server (default behavior, see below). |
|
|
40
|
+
| `dirsql init` | Generate a starter `.dirsql.toml` from the contents of a directory. See [Generating a Config](./init.md). |
|
|
41
|
+
|
|
35
42
|
## Running the server
|
|
36
43
|
|
|
37
44
|
Run `dirsql` from the directory containing your files:
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
canonical: https://thekevinscott.github.io/dirsql/guide/init
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Generating a config with `dirsql init`
|
|
6
|
+
|
|
7
|
+
> Online: <https://thekevinscott.github.io/dirsql/guide/init>
|
|
8
|
+
|
|
9
|
+
`dirsql init` generates a `.dirsql.toml` by running `claude` over the target directory.
|
|
10
|
+
|
|
11
|
+
The output is limited to filesystem-fact tables. For content-aware schemas, see [Defining Tables](./tables.md).
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### Mixed files
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
my-downloads/
|
|
19
|
+
├── archive.zip
|
|
20
|
+
├── invoice.pdf
|
|
21
|
+
├── notes.txt
|
|
22
|
+
└── photo.jpg
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```toml
|
|
26
|
+
[[table]]
|
|
27
|
+
ddl = "CREATE TABLE files (_path TEXT, _ext TEXT, _size INTEGER)"
|
|
28
|
+
glob = "*"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Path captures
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
photos/
|
|
35
|
+
├── 2024-01/
|
|
36
|
+
│ ├── beach.jpg
|
|
37
|
+
│ └── sunset.jpg
|
|
38
|
+
└── 2024-02/
|
|
39
|
+
├── snow.jpg
|
|
40
|
+
└── mountain.jpg
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```toml
|
|
44
|
+
[[table]]
|
|
45
|
+
ddl = "CREATE TABLE photos (month TEXT, _basename TEXT, _mtime INTEGER)"
|
|
46
|
+
glob = "{month}/*.jpg"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Multiple tables
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
my-blog/
|
|
53
|
+
├── posts/
|
|
54
|
+
│ ├── hello-world.md
|
|
55
|
+
│ └── second.md
|
|
56
|
+
└── _comments/
|
|
57
|
+
└── hello-world/
|
|
58
|
+
├── 2024-01-15.jsonl
|
|
59
|
+
└── 2024-02-03.jsonl
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```toml
|
|
63
|
+
[[table]]
|
|
64
|
+
ddl = "CREATE TABLE posts (_basename TEXT, _mtime INTEGER, _size INTEGER)"
|
|
65
|
+
glob = "posts/*.md"
|
|
66
|
+
|
|
67
|
+
[[table]]
|
|
68
|
+
ddl = "CREATE TABLE comments (thread_id TEXT, _basename TEXT, _mtime INTEGER)"
|
|
69
|
+
glob = "_comments/{thread_id}/*.jsonl"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`init` will not overwrite an existing config without `--force`.
|
|
73
|
+
|
|
74
|
+
## Flags
|
|
75
|
+
|
|
76
|
+
| Flag | Default | Description |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `--root <path>` | cwd | Directory to scan |
|
|
79
|
+
| `--output <path>` | `<root>/.dirsql.toml` | Output path |
|
|
80
|
+
| `--force` | off | Overwrite if the output exists |
|
|
81
|
+
|
|
82
|
+
## Authentication
|
|
83
|
+
|
|
84
|
+
Requires `claude` on `PATH` and signed in. There is no separate API key. If `claude` is missing, `dirsql init` raises an exception.
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
//! `dirsql` CLI binary.
|
|
2
|
-
//! `docs/guide/cli.md`.
|
|
1
|
+
//! `dirsql` CLI binary. Two modes:
|
|
2
|
+
//! - No subcommand: HTTP server documented in `docs/guide/cli.md`.
|
|
3
|
+
//! - `init`: starter `.dirsql.toml` generation; see `docs/guide/init.md`.
|
|
4
|
+
//!
|
|
5
|
+
//! Only compiled with `--features cli`.
|
|
3
6
|
|
|
4
7
|
use std::path::PathBuf;
|
|
5
8
|
use std::process::ExitCode;
|
|
6
9
|
|
|
7
|
-
use clap::Parser;
|
|
10
|
+
use clap::{Args, Parser, Subcommand};
|
|
8
11
|
use dirsql::DirSQL;
|
|
9
|
-
use dirsql::cli::{AppState, ServerConfig, serve_with_state};
|
|
12
|
+
use dirsql::cli::{AppState, ServerConfig, init::InitOptions, serve_with_state};
|
|
10
13
|
|
|
11
14
|
#[derive(Debug, Parser)]
|
|
12
15
|
#[command(
|
|
@@ -14,28 +17,90 @@ use dirsql::cli::{AppState, ServerConfig, serve_with_state};
|
|
|
14
17
|
version,
|
|
15
18
|
about = "Ephemeral SQL index over a local directory, exposed over HTTP.",
|
|
16
19
|
long_about = "Runs an HTTP server that exposes a SQL view of the directory \
|
|
17
|
-
described by `.dirsql.toml`.
|
|
18
|
-
|
|
20
|
+
described by `.dirsql.toml`. With the `init` subcommand, \
|
|
21
|
+
generates a starter `.dirsql.toml` by running `claude` over \
|
|
22
|
+
the target directory."
|
|
19
23
|
)]
|
|
20
24
|
struct Cli {
|
|
25
|
+
#[command(subcommand)]
|
|
26
|
+
command: Option<Command>,
|
|
27
|
+
|
|
21
28
|
/// Path to the config file (default: `./.dirsql.toml`). The index is
|
|
22
|
-
/// rooted at the directory containing this file.
|
|
29
|
+
/// rooted at the directory containing this file. Used when no
|
|
30
|
+
/// subcommand is given.
|
|
23
31
|
#[arg(long, default_value = "./.dirsql.toml")]
|
|
24
32
|
config: PathBuf,
|
|
25
33
|
|
|
26
|
-
/// Bind address.
|
|
34
|
+
/// Bind address. Used when no subcommand is given.
|
|
27
35
|
#[arg(long, default_value = "localhost")]
|
|
28
36
|
host: String,
|
|
29
37
|
|
|
30
|
-
/// TCP port to bind.
|
|
38
|
+
/// TCP port to bind. Used when no subcommand is given.
|
|
31
39
|
#[arg(long, default_value_t = 7117)]
|
|
32
40
|
port: u16,
|
|
33
41
|
}
|
|
34
42
|
|
|
43
|
+
#[derive(Debug, Subcommand)]
|
|
44
|
+
enum Command {
|
|
45
|
+
/// Generate a starter `.dirsql.toml` by running `claude` over the
|
|
46
|
+
/// target directory.
|
|
47
|
+
Init(InitArgs),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[derive(Debug, Args)]
|
|
51
|
+
struct InitArgs {
|
|
52
|
+
/// Directory to scan (default: current directory).
|
|
53
|
+
#[arg(long)]
|
|
54
|
+
root: Option<PathBuf>,
|
|
55
|
+
|
|
56
|
+
/// Where to write the generated config (default: `<root>/.dirsql.toml`).
|
|
57
|
+
#[arg(long)]
|
|
58
|
+
output: Option<PathBuf>,
|
|
59
|
+
|
|
60
|
+
/// Overwrite the output file if it already exists.
|
|
61
|
+
#[arg(long)]
|
|
62
|
+
force: bool,
|
|
63
|
+
}
|
|
64
|
+
|
|
35
65
|
#[tokio::main]
|
|
36
66
|
async fn main() -> ExitCode {
|
|
37
|
-
let cli = Cli::parse();
|
|
67
|
+
let mut cli = Cli::parse();
|
|
68
|
+
|
|
69
|
+
match cli.command.take() {
|
|
70
|
+
Some(Command::Init(args)) => run_init(args),
|
|
71
|
+
None => run_server(cli).await,
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
fn run_init(args: InitArgs) -> ExitCode {
|
|
76
|
+
let root = match args.root {
|
|
77
|
+
Some(p) => p,
|
|
78
|
+
None => match std::env::current_dir() {
|
|
79
|
+
Ok(p) => p,
|
|
80
|
+
Err(err) => {
|
|
81
|
+
eprintln!("dirsql init: failed to read current directory: {err}");
|
|
82
|
+
return ExitCode::from(1);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
let output = args.output.unwrap_or_else(|| root.join(".dirsql.toml"));
|
|
87
|
+
|
|
88
|
+
let opts = InitOptions {
|
|
89
|
+
root,
|
|
90
|
+
output,
|
|
91
|
+
force: args.force,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
match dirsql::cli::init::run(opts) {
|
|
95
|
+
Ok(()) => ExitCode::SUCCESS,
|
|
96
|
+
Err(err) => {
|
|
97
|
+
eprintln!("dirsql init: {err}");
|
|
98
|
+
ExitCode::from(1)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
38
102
|
|
|
103
|
+
async fn run_server(cli: Cli) -> ExitCode {
|
|
39
104
|
let state = load_state(&cli);
|
|
40
105
|
let server_config = ServerConfig::bind(cli.host.clone(), cli.port);
|
|
41
106
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
//! `dirsql init` — generate a starter `.dirsql.toml` by shelling out to
|
|
2
|
+
//! the `claude` CLI. See `docs/guide/init.md` for the user-facing
|
|
3
|
+
//! contract.
|
|
4
|
+
//!
|
|
5
|
+
//! The agent's only required responsibility is to print a valid
|
|
6
|
+
//! filesystem-fact-only `.dirsql.toml` to stdout. We invoke `claude -p`
|
|
7
|
+
//! with the working directory set to the target root, capture stdout,
|
|
8
|
+
//! and write it verbatim to the configured output path.
|
|
9
|
+
//!
|
|
10
|
+
//! Failure modes:
|
|
11
|
+
//! - Output already exists and `--force` was not passed: bail before
|
|
12
|
+
//! spawning the agent (no point burning a paid LLM call).
|
|
13
|
+
//! - `claude` is not on PATH: surface a descriptive error pointing at
|
|
14
|
+
//! the install docs.
|
|
15
|
+
//! - `claude` exits non-zero: surface its stderr; do not write any
|
|
16
|
+
//! partial config.
|
|
17
|
+
|
|
18
|
+
use std::path::PathBuf;
|
|
19
|
+
use std::process::Command;
|
|
20
|
+
|
|
21
|
+
#[derive(Debug, thiserror::Error)]
|
|
22
|
+
pub enum InitError {
|
|
23
|
+
#[error("{}: already exists; pass --force to overwrite", path.display())]
|
|
24
|
+
AlreadyExists { path: PathBuf },
|
|
25
|
+
|
|
26
|
+
#[error(
|
|
27
|
+
"`claude` not found on PATH; install Claude Code (https://docs.claude.com/en/docs/claude-code/quickstart)"
|
|
28
|
+
)]
|
|
29
|
+
ClaudeNotFound,
|
|
30
|
+
|
|
31
|
+
#[error("failed to spawn `claude`: {0}")]
|
|
32
|
+
Spawn(std::io::Error),
|
|
33
|
+
|
|
34
|
+
#[error("`claude` exited with {status}\n{stderr}")]
|
|
35
|
+
ClaudeFailed {
|
|
36
|
+
status: std::process::ExitStatus,
|
|
37
|
+
stderr: String,
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
#[error("`claude` produced non-UTF8 output")]
|
|
41
|
+
InvalidUtf8(#[from] std::string::FromUtf8Error),
|
|
42
|
+
|
|
43
|
+
#[error("failed to write {}: {source}", path.display())]
|
|
44
|
+
Write {
|
|
45
|
+
path: PathBuf,
|
|
46
|
+
source: std::io::Error,
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#[derive(Debug, Clone)]
|
|
51
|
+
pub struct InitOptions {
|
|
52
|
+
/// Directory to scan. Resolved by the caller (default: cwd).
|
|
53
|
+
pub root: PathBuf,
|
|
54
|
+
/// Path the generated config is written to. Resolved by the caller
|
|
55
|
+
/// (default: `<root>/.dirsql.toml`).
|
|
56
|
+
pub output: PathBuf,
|
|
57
|
+
/// Overwrite `output` if it already exists.
|
|
58
|
+
pub force: bool,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pub fn run(opts: InitOptions) -> Result<(), InitError> {
|
|
62
|
+
if !opts.force && opts.output.exists() {
|
|
63
|
+
return Err(InitError::AlreadyExists { path: opts.output });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let prompt = build_prompt();
|
|
67
|
+
let output = Command::new("claude")
|
|
68
|
+
.arg("-p")
|
|
69
|
+
.arg(&prompt)
|
|
70
|
+
.current_dir(&opts.root)
|
|
71
|
+
.output()
|
|
72
|
+
.map_err(|err| match err.kind() {
|
|
73
|
+
std::io::ErrorKind::NotFound => InitError::ClaudeNotFound,
|
|
74
|
+
_ => InitError::Spawn(err),
|
|
75
|
+
})?;
|
|
76
|
+
|
|
77
|
+
if !output.status.success() {
|
|
78
|
+
return Err(InitError::ClaudeFailed {
|
|
79
|
+
status: output.status,
|
|
80
|
+
stderr: String::from_utf8_lossy(&output.stderr).to_string(),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let toml = String::from_utf8(output.stdout)?;
|
|
85
|
+
std::fs::write(&opts.output, toml.as_bytes()).map_err(|source| InitError::Write {
|
|
86
|
+
path: opts.output.clone(),
|
|
87
|
+
source,
|
|
88
|
+
})?;
|
|
89
|
+
|
|
90
|
+
Ok(())
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fn build_prompt() -> String {
|
|
94
|
+
PROMPT.to_string()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const PROMPT: &str = r#"You are running inside a directory. Your job is to produce a `.dirsql.toml` config file that defines SQL tables over that directory's filesystem.
|
|
98
|
+
|
|
99
|
+
Inspect the directory structure (files and subdirectories). Then produce a `.dirsql.toml` with one or more `[[table]]` blocks.
|
|
100
|
+
|
|
101
|
+
Each `[[table]]` block has:
|
|
102
|
+
- `ddl`: a SQLite CREATE TABLE statement.
|
|
103
|
+
- `glob`: a glob pattern matching files relative to the directory root.
|
|
104
|
+
|
|
105
|
+
Each row is one matched file. Columns come from these sources ONLY:
|
|
106
|
+
- Glob path captures: `{name}` segments in the glob become columns named `name`.
|
|
107
|
+
- Stat virtuals (reserved column names): `_path`, `_basename`, `_dir`, `_ext`, `_size`, `_mtime`, `_ctime`.
|
|
108
|
+
|
|
109
|
+
Do NOT include columns sourced from file content (JSON keys, CSV headers, frontmatter, etc.). Content parsing is not configured in `.dirsql.toml`.
|
|
110
|
+
|
|
111
|
+
Output ONLY the TOML, with no surrounding prose, no markdown fences, no explanation.
|
|
112
|
+
|
|
113
|
+
Example for a flat directory of mixed files:
|
|
114
|
+
[[table]]
|
|
115
|
+
ddl = "CREATE TABLE files (_path TEXT, _ext TEXT, _size INTEGER)"
|
|
116
|
+
glob = "*"
|
|
117
|
+
|
|
118
|
+
Example with path captures:
|
|
119
|
+
[[table]]
|
|
120
|
+
ddl = "CREATE TABLE photos (month TEXT, _basename TEXT, _mtime INTEGER)"
|
|
121
|
+
glob = "{month}/*.jpg"
|
|
122
|
+
"#;
|
|
123
|
+
|
|
124
|
+
#[cfg(test)]
|
|
125
|
+
mod tests {
|
|
126
|
+
use super::*;
|
|
127
|
+
|
|
128
|
+
#[test]
|
|
129
|
+
fn prompt_mentions_filesystem_fact_constraints() {
|
|
130
|
+
let p = build_prompt();
|
|
131
|
+
assert!(p.contains("[[table]]"));
|
|
132
|
+
assert!(p.contains("_path"));
|
|
133
|
+
assert!(p.contains("Output ONLY the TOML"));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
#[test]
|
|
137
|
+
fn already_exists_error_mentions_force() {
|
|
138
|
+
let err = InitError::AlreadyExists {
|
|
139
|
+
path: PathBuf::from("/tmp/foo.toml"),
|
|
140
|
+
};
|
|
141
|
+
let msg = format!("{err}");
|
|
142
|
+
assert!(msg.contains("already exists"));
|
|
143
|
+
assert!(msg.contains("--force"));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
#[test]
|
|
147
|
+
fn claude_not_found_error_mentions_claude() {
|
|
148
|
+
let err = InitError::ClaudeNotFound;
|
|
149
|
+
let msg = format!("{err}").to_lowercase();
|
|
150
|
+
assert!(msg.contains("claude"));
|
|
151
|
+
}
|
|
152
|
+
}
|