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.
Files changed (129) hide show
  1. {dirsql-0.3.3 → dirsql-0.3.5}/Cargo.lock +1 -1
  2. {dirsql-0.3.3 → dirsql-0.3.5}/PKG-INFO +2 -2
  3. {dirsql-0.3.3/packages/python → dirsql-0.3.5}/README.md +1 -1
  4. {dirsql-0.3.3 → dirsql-0.3.5}/docs/.vitepress/config.ts +1 -0
  5. {dirsql-0.3.3/packages/python → dirsql-0.3.5}/docs/guide/cli.md +7 -0
  6. dirsql-0.3.5/docs/guide/init.md +84 -0
  7. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/Cargo.toml +1 -1
  8. {dirsql-0.3.3 → dirsql-0.3.5/packages/python}/README.md +1 -1
  9. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/.vitepress/config.ts +1 -0
  10. {dirsql-0.3.3 → dirsql-0.3.5/packages/python}/docs/guide/cli.md +7 -0
  11. dirsql-0.3.5/packages/python/docs/guide/init.md +84 -0
  12. dirsql-0.3.5/packages/python/tests/e2e/__init__.py +0 -0
  13. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/Cargo.toml +5 -1
  14. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/cli.md +7 -0
  15. dirsql-0.3.5/packages/rust/docs/guide/init.md +84 -0
  16. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/bin/dirsql.rs +75 -10
  17. dirsql-0.3.5/packages/rust/src/cli/init.rs +152 -0
  18. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/cli/mod.rs +1 -0
  19. dirsql-0.3.5/packages/rust/tests/init_e2e.rs +85 -0
  20. dirsql-0.3.5/packages/rust/tests/init_integration.rs +301 -0
  21. dirsql-0.3.5/pyproject.toml +71 -0
  22. dirsql-0.3.3/pyproject.toml +0 -59
  23. dirsql-0.3.3/python/dirsql/_cli/binary_path_test.py +0 -70
  24. dirsql-0.3.3/python/dirsql/_cli/is_windows_test.py +0 -15
  25. dirsql-0.3.3/python/dirsql/_cli/main_test.py +0 -77
  26. {dirsql-0.3.3 → dirsql-0.3.5}/Cargo.toml +0 -0
  27. {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/__init__.py +0 -0
  28. {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_async.py +0 -0
  29. {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_cli/__init__.py +0 -0
  30. {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_cli/binary_path.py +0 -0
  31. {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_cli/is_windows.py +0 -0
  32. {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/_cli/main.py +0 -0
  33. {dirsql-0.3.3/python → dirsql-0.3.5}/dirsql/test_async.py +0 -0
  34. {dirsql-0.3.3 → dirsql-0.3.5}/docs/.claude/CLAUDE.md +0 -0
  35. {dirsql-0.3.3 → dirsql-0.3.5}/docs/.vitepress/theme/index.ts +0 -0
  36. {dirsql-0.3.3 → dirsql-0.3.5}/docs/.vitepress/theme/lang.ts +0 -0
  37. {dirsql-0.3.3 → dirsql-0.3.5}/docs/AGENTS.md +0 -0
  38. {dirsql-0.3.3 → dirsql-0.3.5}/docs/api/index.md +0 -0
  39. {dirsql-0.3.3 → dirsql-0.3.5}/docs/getting-started.md +0 -0
  40. {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/async.md +0 -0
  41. {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/config.md +0 -0
  42. {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/crdt.md +0 -0
  43. {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/persistence.md +0 -0
  44. {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/querying.md +0 -0
  45. {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/tables.md +0 -0
  46. {dirsql-0.3.3 → dirsql-0.3.5}/docs/guide/watching.md +0 -0
  47. {dirsql-0.3.3 → dirsql-0.3.5}/docs/index.md +0 -0
  48. {dirsql-0.3.3 → dirsql-0.3.5}/docs/migrations.md +0 -0
  49. {dirsql-0.3.3 → dirsql-0.3.5}/docs/package.json +0 -0
  50. {dirsql-0.3.3 → dirsql-0.3.5}/docs/playwright.config.ts +0 -0
  51. {dirsql-0.3.3 → dirsql-0.3.5}/docs/pnpm-lock.yaml +0 -0
  52. {dirsql-0.3.3 → dirsql-0.3.5}/docs/pnpm-workspace.yaml +0 -0
  53. {dirsql-0.3.3 → dirsql-0.3.5}/docs/tests/integration/home.spec.ts +0 -0
  54. {dirsql-0.3.3 → dirsql-0.3.5}/docs/tests/integration/language-flag.spec.ts +0 -0
  55. {dirsql-0.3.3 → dirsql-0.3.5}/docs/tests/unit/config.test.ts +0 -0
  56. {dirsql-0.3.3 → dirsql-0.3.5}/docs/tests/unit/lang.test.ts +0 -0
  57. {dirsql-0.3.3 → dirsql-0.3.5}/docs/vitest.config.ts +0 -0
  58. {dirsql-0.3.3/packages/python → dirsql-0.3.5/packages}/python/conftest.py +0 -0
  59. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/.claude/CLAUDE.md +0 -0
  60. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  61. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  62. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/AGENTS.md +0 -0
  63. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/api/index.md +0 -0
  64. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/getting-started.md +0 -0
  65. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/async.md +0 -0
  66. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/config.md +0 -0
  67. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/crdt.md +0 -0
  68. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/persistence.md +0 -0
  69. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/querying.md +0 -0
  70. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/tables.md +0 -0
  71. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/guide/watching.md +0 -0
  72. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/index.md +0 -0
  73. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/migrations.md +0 -0
  74. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/package.json +0 -0
  75. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/playwright.config.ts +0 -0
  76. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/pnpm-lock.yaml +0 -0
  77. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/pnpm-workspace.yaml +0 -0
  78. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/tests/integration/home.spec.ts +0 -0
  79. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
  80. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/tests/unit/config.test.ts +0 -0
  81. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/tests/unit/lang.test.ts +0 -0
  82. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/docs/vitest.config.ts +0 -0
  83. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/src/lib.rs +0 -0
  84. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/__init__.py +0 -0
  85. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/conftest.py +0 -0
  86. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/__init__.py +0 -0
  87. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_async_dirsql.py +0 -0
  88. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_binding.py +0 -0
  89. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_dirsql.py +0 -0
  90. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_docs_examples.py +0 -0
  91. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_docs_gaps.py +0 -0
  92. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_from_config.py +0 -0
  93. {dirsql-0.3.3 → dirsql-0.3.5}/packages/python/tests/integration/test_persist.py +0 -0
  94. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/README.md +0 -0
  95. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/benches/db_bench.rs +0 -0
  96. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/benches/differ_bench.rs +0 -0
  97. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/benches/matcher_bench.rs +0 -0
  98. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/benches/scanner_bench.rs +0 -0
  99. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/api/index.md +0 -0
  100. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/getting-started.md +0 -0
  101. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/async.md +0 -0
  102. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/config.md +0 -0
  103. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/crdt.md +0 -0
  104. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/persistence.md +0 -0
  105. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/querying.md +0 -0
  106. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/tables.md +0 -0
  107. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/guide/watching.md +0 -0
  108. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/index.md +0 -0
  109. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/docs/migrations.md +0 -0
  110. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/cli/router.rs +0 -0
  111. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/cli/serialize.rs +0 -0
  112. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/cli/server.rs +0 -0
  113. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/config.rs +0 -0
  114. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/db.rs +0 -0
  115. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/differ.rs +0 -0
  116. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/lib.rs +0 -0
  117. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/matcher.rs +0 -0
  118. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/persist.rs +0 -0
  119. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/scanner.rs +0 -0
  120. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/src/watcher.rs +0 -0
  121. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/async_sdk.rs +0 -0
  122. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/cli_e2e.rs +0 -0
  123. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/cli_integration.rs +0 -0
  124. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/docs_examples.rs +0 -0
  125. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/docs_gaps.rs +0 -0
  126. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/from_config.rs +0 -0
  127. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/persist.rs +0 -0
  128. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/readonly_query.rs +0 -0
  129. {dirsql-0.3.3 → dirsql-0.3.5}/packages/rust/tests/sdk.rs +0 -0
@@ -499,7 +499,7 @@ dependencies = [
499
499
 
500
500
  [[package]]
501
501
  name = "dirsql-py-ext"
502
- version = "0.3.3"
502
+ version = "0.3.5"
503
503
  dependencies = [
504
504
  "dirsql",
505
505
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.3.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 `python/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.
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 `python/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.
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.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 `python/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.
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. Starts the HTTP server documented in
2
- //! `docs/guide/cli.md`. Only compiled with `--features cli`.
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`. See the CLI guide for endpoints \
18
- and SSE schema."
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
+ }
@@ -27,6 +27,7 @@ use tokio::task::JoinHandle;
27
27
 
28
28
  use crate::DirSQL;
29
29
 
30
+ pub mod init;
30
31
  pub mod router;
31
32
  pub mod serialize;
32
33
  pub mod server;