dirsql 0.4.75__tar.gz → 0.4.77__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 (329) hide show
  1. {dirsql-0.4.75 → dirsql-0.4.77}/Cargo.lock +3 -2
  2. {dirsql-0.4.75 → dirsql-0.4.77}/PKG-INFO +1 -1
  3. {dirsql-0.4.75 → dirsql-0.4.77}/docs/.vitepress/config.ts +2 -1
  4. dirsql-0.4.77/docs/howto/agent-skill.md +64 -0
  5. {dirsql-0.4.75 → dirsql-0.4.77}/docs/reference/cli.md +1 -6
  6. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/Cargo.toml +1 -1
  7. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/.vitepress/config.ts +2 -1
  8. dirsql-0.4.77/packages/python/docs/howto/agent-skill.md +64 -0
  9. {dirsql-0.4.75/packages/rust → dirsql-0.4.77/packages/python}/docs/reference/cli.md +1 -6
  10. dirsql-0.4.77/packages/python/e2e-attestations/claude-1305-glob-speed.json +7 -0
  11. dirsql-0.4.77/packages/python/e2e-attestations/claude-1308-glob-speed.json +7 -0
  12. dirsql-0.4.77/packages/python/e2e-attestations/claude-1310-glob-speed.json +7 -0
  13. dirsql-0.4.77/packages/python/e2e-attestations/claude-1311-glob-speed.json +7 -0
  14. dirsql-0.4.77/packages/python/e2e-attestations/claude-1312-glob-speed.json +7 -0
  15. dirsql-0.4.77/packages/python/e2e-attestations/claude-1318-lazy-stat.json +7 -0
  16. dirsql-0.4.77/packages/python/e2e-attestations/claude-1320-walk-speed.json +7 -0
  17. dirsql-0.4.77/packages/python/e2e-attestations/claude-1322-walk-readdir.json +7 -0
  18. dirsql-0.4.77/packages/python/e2e-attestations/claude-1325-parallel-walk.json +7 -0
  19. dirsql-0.4.77/packages/python/e2e-attestations/claude-1326-stream-rows.json +7 -0
  20. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/testing-conventions.toml +1 -1
  21. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/Cargo.toml +5 -1
  22. dirsql-0.4.77/packages/rust/docs/howto/agent-skill.md +64 -0
  23. {dirsql-0.4.75/packages/python → dirsql-0.4.77/packages/rust}/docs/reference/cli.md +1 -6
  24. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/execute.rs +23 -1
  25. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/run.rs +84 -17
  26. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/serialize.rs +134 -0
  27. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/db.rs +125 -19
  28. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/lib.rs +15 -0
  29. dirsql-0.4.77/packages/rust/src/listing.rs +217 -0
  30. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/scanner.rs +451 -122
  31. dirsql-0.4.77/packages/rust/src/tree_walk.rs +239 -0
  32. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/vtab.rs +176 -66
  33. {dirsql-0.4.75 → dirsql-0.4.77}/Cargo.toml +0 -0
  34. {dirsql-0.4.75 → dirsql-0.4.77}/README.md +0 -0
  35. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/__init__.py +0 -0
  36. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/_async.py +0 -0
  37. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/_dirsql.pyi +0 -0
  38. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/cli/__init__.py +0 -0
  39. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/cli/discover_plugins/__init__.py +0 -0
  40. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  41. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  42. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  43. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/cli/discover_plugins/user_passed_config.py +0 -0
  44. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  45. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/cli/main.py +0 -0
  46. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/cli/resolve_config_extensions.py +0 -0
  47. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/plan_entry_path.py +0 -0
  48. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/py.typed +0 -0
  49. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/read_config.py +0 -0
  50. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/resolve_configs_extension_specs.py +0 -0
  51. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/resolve_extension.py +0 -0
  52. {dirsql-0.4.75 → dirsql-0.4.77}/dirsql/resolve_package.py +0 -0
  53. {dirsql-0.4.75 → dirsql-0.4.77}/docs/.claude/CLAUDE.md +0 -0
  54. {dirsql-0.4.75 → dirsql-0.4.77}/docs/.vitepress/theme/index.ts +0 -0
  55. {dirsql-0.4.75 → dirsql-0.4.77}/docs/.vitepress/theme/lang.ts +0 -0
  56. {dirsql-0.4.75 → dirsql-0.4.77}/docs/AGENTS.md +0 -0
  57. {dirsql-0.4.75 → dirsql-0.4.77}/docs/context/.gitattributes +0 -0
  58. {dirsql-0.4.75 → dirsql-0.4.77}/docs/context/recipes.md +0 -0
  59. {dirsql-0.4.75 → dirsql-0.4.77}/docs/context/troubleshooting.md +0 -0
  60. {dirsql-0.4.75 → dirsql-0.4.77}/docs/context/usage.md +0 -0
  61. {dirsql-0.4.75 → dirsql-0.4.77}/docs/explanation.md +0 -0
  62. {dirsql-0.4.75 → dirsql-0.4.77}/docs/getting-started.md +0 -0
  63. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/columns-from-paths.md +0 -0
  64. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/define-tables.md +0 -0
  65. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/embed.md +0 -0
  66. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/extract-from-contents.md +0 -0
  67. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/load-extension.md +0 -0
  68. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/parse-files-into-columns.md +0 -0
  69. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/persist.md +0 -0
  70. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/query-json.md +0 -0
  71. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/query-without-config.md +0 -0
  72. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/react-to-changes.md +0 -0
  73. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/search-by-meaning.md +0 -0
  74. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/search-indexes.md +0 -0
  75. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/skip-files.md +0 -0
  76. {dirsql-0.4.75 → dirsql-0.4.77}/docs/howto/write-a-plugin.md +0 -0
  77. {dirsql-0.4.75 → dirsql-0.4.77}/docs/index.md +0 -0
  78. {dirsql-0.4.75 → dirsql-0.4.77}/docs/package.json +0 -0
  79. {dirsql-0.4.75 → dirsql-0.4.77}/docs/plugins.md +0 -0
  80. {dirsql-0.4.75 → dirsql-0.4.77}/docs/pnpm-lock.yaml +0 -0
  81. {dirsql-0.4.75 → dirsql-0.4.77}/docs/pnpm-workspace.yaml +0 -0
  82. {dirsql-0.4.75 → dirsql-0.4.77}/docs/reference/columns.md +0 -0
  83. {dirsql-0.4.75 → dirsql-0.4.77}/docs/reference/config.md +0 -0
  84. {dirsql-0.4.75 → dirsql-0.4.77}/docs/reference/hooks.md +0 -0
  85. {dirsql-0.4.75 → dirsql-0.4.77}/docs/reference/http-api.md +0 -0
  86. {dirsql-0.4.75 → dirsql-0.4.77}/docs/reference/path-tables.md +0 -0
  87. {dirsql-0.4.75 → dirsql-0.4.77}/docs/reference/sdk.md +0 -0
  88. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/CHANGELOG.md +0 -0
  89. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/MIGRATIONS.md +0 -0
  90. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/README.md +0 -0
  91. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  92. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  93. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  94. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  95. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  96. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  97. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  98. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  99. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  100. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  101. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  102. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  103. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
  104. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
  105. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  106. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
  107. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
  108. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
  109. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
  110. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
  111. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
  112. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
  113. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
  114. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
  115. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
  116. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
  117. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
  118. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
  119. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
  120. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
  121. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-02-readme-docs-host.md +0 -0
  122. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
  123. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-03-path-table-directory-one-level.md +0 -0
  124. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
  125. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-05-brace-groups-follow-bash.md +0 -0
  126. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-05-cli-context.md +0 -0
  127. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-05-gitignore-requires-repo.md +0 -0
  128. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-05-path-table-node-modules-named.md +0 -0
  129. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-05-path-table-symlinks.md +0 -0
  130. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/2026-10-05-path-table-trailing-slash.md +0 -0
  131. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/changelog.d/README.md +0 -0
  132. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/conftest.py +0 -0
  133. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/.claude/CLAUDE.md +0 -0
  134. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  135. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  136. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/AGENTS.md +0 -0
  137. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/context/.gitattributes +0 -0
  138. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/context/recipes.md +0 -0
  139. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/context/troubleshooting.md +0 -0
  140. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/context/usage.md +0 -0
  141. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/explanation.md +0 -0
  142. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/getting-started.md +0 -0
  143. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/columns-from-paths.md +0 -0
  144. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/define-tables.md +0 -0
  145. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/embed.md +0 -0
  146. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/extract-from-contents.md +0 -0
  147. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/load-extension.md +0 -0
  148. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
  149. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/persist.md +0 -0
  150. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/query-json.md +0 -0
  151. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/query-without-config.md +0 -0
  152. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/react-to-changes.md +0 -0
  153. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/search-by-meaning.md +0 -0
  154. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/search-indexes.md +0 -0
  155. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/skip-files.md +0 -0
  156. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/howto/write-a-plugin.md +0 -0
  157. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/index.md +0 -0
  158. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/package.json +0 -0
  159. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/plugins.md +0 -0
  160. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/pnpm-lock.yaml +0 -0
  161. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/pnpm-workspace.yaml +0 -0
  162. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/reference/columns.md +0 -0
  163. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/reference/config.md +0 -0
  164. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/reference/hooks.md +0 -0
  165. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/reference/http-api.md +0 -0
  166. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/reference/path-tables.md +0 -0
  167. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/docs/reference/sdk.md +0 -0
  168. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
  169. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
  170. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
  171. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
  172. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
  173. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
  174. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
  175. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
  176. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
  177. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
  178. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
  179. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
  180. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
  181. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
  182. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
  183. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
  184. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
  185. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
  186. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
  187. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
  188. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
  189. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
  190. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
  191. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
  192. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1196-join-index.json +0 -0
  193. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1199-glob-prefix.json +0 -0
  194. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1201-single-walk.json +0 -0
  195. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1204-embed-batch.json +0 -0
  196. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
  197. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
  198. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1215-on-file-batch.json +0 -0
  199. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1216-on-file-cleanup.json +0 -0
  200. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1223-config-glob-rule.json +0 -0
  201. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1223-dir-one-level.json +0 -0
  202. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1226-stale-docs.json +0 -0
  203. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1238-parallel-walk.json +0 -0
  204. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1241-content-prefetch.json +0 -0
  205. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1243-ingest-perf.json +0 -0
  206. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1249-dotfiles.json +0 -0
  207. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1256-symlinks.json +0 -0
  208. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1257-trailing-slash.json +0 -0
  209. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1262-brace-literal.json +0 -0
  210. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1264-context.json +0 -0
  211. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1267-posix-classes.json +0 -0
  212. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1269-utf8-chars.json +0 -0
  213. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1271-node-modules-named.json +0 -0
  214. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1272-ancestor-gitignore.json +0 -0
  215. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1273-walk-prune.json +0 -0
  216. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1285-ingest-fast.json +0 -0
  217. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-1286-nested-repo.json +0 -0
  218. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
  219. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
  220. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
  221. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
  222. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
  223. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
  224. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
  225. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
  226. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
  227. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
  228. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
  229. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
  230. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
  231. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
  232. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
  233. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  234. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  235. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  236. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  237. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  238. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  239. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  240. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  241. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
  242. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
  243. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
  244. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
  245. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-02-readme-docs-host.md +0 -0
  246. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
  247. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-03-path-table-directory-one-level.md +0 -0
  248. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
  249. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-05-brace-groups-follow-bash.md +0 -0
  250. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-05-cli-context.md +0 -0
  251. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-05-gitignore-requires-repo.md +0 -0
  252. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-05-path-table-node-modules-named.md +0 -0
  253. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-05-path-table-symlinks.md +0 -0
  254. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/2026-10-05-path-table-trailing-slash.md +0 -0
  255. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/migrations.d/README.md +0 -0
  256. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/src/lib.rs +0 -0
  257. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/tests/__init__.py +0 -0
  258. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/tests/conftest.py +0 -0
  259. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/tests/e2e/__init__.py +0 -0
  260. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  261. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
  262. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/tests/e2e/speed_of_light.py +0 -0
  263. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/tests/integration/__init__.py +0 -0
  264. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/tests/integration/binding/__init__.py +0 -0
  265. {dirsql-0.4.75 → dirsql-0.4.77}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  266. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/CHANGELOG.md +0 -0
  267. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/MIGRATIONS.md +0 -0
  268. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/README.md +0 -0
  269. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/benches/db_bench.rs +0 -0
  270. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/benches/differ_bench.rs +0 -0
  271. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/benches/matcher_bench.rs +0 -0
  272. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/benches/scanner_bench.rs +0 -0
  273. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/context/.gitattributes +0 -0
  274. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/context/recipes.md +0 -0
  275. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/context/troubleshooting.md +0 -0
  276. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/context/usage.md +0 -0
  277. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/explanation.md +0 -0
  278. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/getting-started.md +0 -0
  279. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  280. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/define-tables.md +0 -0
  281. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/embed.md +0 -0
  282. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/extract-from-contents.md +0 -0
  283. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/load-extension.md +0 -0
  284. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
  285. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/persist.md +0 -0
  286. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/query-json.md +0 -0
  287. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/query-without-config.md +0 -0
  288. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/react-to-changes.md +0 -0
  289. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  290. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/search-indexes.md +0 -0
  291. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/skip-files.md +0 -0
  292. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/howto/write-a-plugin.md +0 -0
  293. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/index.md +0 -0
  294. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/plugins.md +0 -0
  295. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/reference/columns.md +0 -0
  296. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/reference/config.md +0 -0
  297. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/reference/hooks.md +0 -0
  298. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/reference/http-api.md +0 -0
  299. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/reference/path-tables.md +0 -0
  300. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/docs/reference/sdk.md +0 -0
  301. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/bin/dirsql.rs +0 -0
  302. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/brace.rs +0 -0
  303. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/context.rs +0 -0
  304. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/init.rs +0 -0
  305. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/mod.rs +0 -0
  306. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/repl.rs +0 -0
  307. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/router.rs +0 -0
  308. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/server.rs +0 -0
  309. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/cli/table.rs +0 -0
  310. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/command.rs +0 -0
  311. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/config.rs +0 -0
  312. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/default_config.toml +0 -0
  313. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/differ.rs +0 -0
  314. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/extension_resolution.rs +0 -0
  315. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/functions.rs +0 -0
  316. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/infer.rs +0 -0
  317. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/launcher.rs +0 -0
  318. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/matcher.rs +0 -0
  319. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/on_file.rs +0 -0
  320. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/parsed_vtab.rs +0 -0
  321. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/path_table.rs +0 -0
  322. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/persist.rs +0 -0
  323. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/posix_class.rs +0 -0
  324. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/progress.rs +0 -0
  325. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/row_event_flat.rs +0 -0
  326. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/sql_literal.rs +0 -0
  327. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/vtab_scaffold.rs +0 -0
  328. {dirsql-0.4.75 → dirsql-0.4.77}/packages/rust/src/watcher.rs +0 -0
  329. {dirsql-0.4.75 → dirsql-0.4.77}/pyproject.toml +0 -0
@@ -552,7 +552,7 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
552
552
 
553
553
  [[package]]
554
554
  name = "dirsql"
555
- version = "0.4.75"
555
+ version = "0.4.77"
556
556
  dependencies = [
557
557
  "assert_cmd",
558
558
  "axum",
@@ -577,6 +577,7 @@ dependencies = [
577
577
  "regex",
578
578
  "reqwest",
579
579
  "rusqlite",
580
+ "rustix",
580
581
  "serde",
581
582
  "serde_json",
582
583
  "shlex",
@@ -601,7 +602,7 @@ dependencies = [
601
602
 
602
603
  [[package]]
603
604
  name = "dirsql-py-ext"
604
- version = "0.4.75"
605
+ version = "0.4.77"
605
606
  dependencies = [
606
607
  "dirsql",
607
608
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.4.75
3
+ Version: 0.4.77
4
4
  Requires-Dist: bin-shim>=0.1
5
5
  Summary: Ephemeral SQL index over a local directory
6
6
  Keywords: sql,filesystem,directory,sqlite,index
@@ -65,7 +65,8 @@ export default defineConfig({
65
65
  { text: 'Keep the index across restarts', link: '/howto/persist' },
66
66
  { text: 'React to file changes', link: '/howto/react-to-changes' },
67
67
  { text: 'Write a plugin', link: '/howto/write-a-plugin' },
68
- { text: 'Embed dirsql in your application', link: '/howto/embed' }
68
+ { text: 'Embed dirsql in your application', link: '/howto/embed' },
69
+ { text: 'Give your agent the dirsql skill', link: '/howto/agent-skill' }
69
70
  ]
70
71
  },
71
72
  {
@@ -0,0 +1,64 @@
1
+ # Give your coding agent the `dirsql` skill
2
+
3
+ Your coding agent answers questions about many files by reading them one at a
4
+ time. The `dirsql` skill teaches it to write one SQL query instead.
5
+
6
+ ## What it does
7
+
8
+ The skill is a short `SKILL.md`. Its description tells the agent when to use
9
+ it: counting, grouping or aggregating files, "which files are ..." by size,
10
+ mtime or extension, pulling one field out of many JSON or frontmatter files,
11
+ or comparing two directories. It tells the agent not to use it to read one
12
+ known file, hunt for a literal string, or list a few names.
13
+
14
+ When the skill triggers, the agent runs `dirsql context`. That prints a guide
15
+ (usage, recipes, troubleshooting) compiled into the `dirsql` binary, so the
16
+ agent always reads the guide for the version it is about to run. See
17
+ [`dirsql context`](../reference/cli.md#dirsql-context).
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npx skills add thekevinscott/dirsql
23
+ ```
24
+
25
+ This uses [`skills`](https://www.npmjs.com/package/skills), a cross-agent
26
+ skill installer. It installs for the current project by default. Pass `-g` to
27
+ install for your user instead, `-a <agent>` to name
28
+ agents (repeatable), and `-y` to skip the prompts.
29
+
30
+ | Scope | Skill lands in | Claude Code link |
31
+ |---|---|---|
32
+ | Project (default) | `.agents/skills/dirsql` | `.claude/skills/dirsql` |
33
+ | User (`-g`) | `~/.agents/skills/dirsql` | `~/.claude/skills/dirsql` |
34
+
35
+ Codex, Cursor, Gemini CLI, Amp, Cline and other agents that read
36
+ `.agents/skills` use the shared copy directly. Agents with their own skills
37
+ directory, such as Claude Code, get a symlink to it (`--copy` copies instead).
38
+ `npx skills add --help` lists the rest.
39
+
40
+ ## Runners
41
+
42
+ The skill works with whichever runner you have. Its `allowed-tools` lets the
43
+ agent run these commands without a permission prompt:
44
+
45
+ | Runner | Command the agent runs |
46
+ |---|---|
47
+ | `uv` | `uvx dirsql ...` |
48
+ | `npm` | `npx -y dirsql ...` |
49
+ | `cargo` | `dirsql ...` after `cargo install dirsql --features cli` |
50
+
51
+ The grant is `Bash(uvx dirsql:*)`, `Bash(npx -y dirsql:*)` and
52
+ `Bash(dirsql:*)`.
53
+
54
+ ## Check, update, remove
55
+
56
+ ```bash
57
+ npx skills list # installed skills and their agents (-g for user scope)
58
+ npx skills update # refresh to the latest from GitHub
59
+ npx skills remove dirsql
60
+ ```
61
+
62
+ `update` and `remove` accept `-g` for user scope and `-y` to skip prompts.
63
+ The skill itself never needs updating to match the CLI, since the guide comes
64
+ from the installed `dirsql`.
@@ -454,12 +454,7 @@ troubleshooting. The guide is compiled into the binary, so it describes the
454
454
  version that prints it. It takes no flags and exits `0`.
455
455
 
456
456
  The dirsql agent skill tells an agent to run this command before it writes a
457
- query. Install the skill into Claude Code, Codex, Cursor, Gemini CLI and
458
- others with:
459
-
460
- ```sh
461
- npx skills add thekevinscott/dirsql
462
- ```
457
+ query; see [the skill page](../howto/agent-skill.md).
463
458
 
464
459
  ## Plugins
465
460
 
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
4
4
  # pypi/maturin handler can rewrite it via `write-version` before
5
5
  # `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
6
6
  # and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
7
- version = "0.4.75"
7
+ version = "0.4.77"
8
8
  # abi3 note: the `abi3-py310` pyo3 feature (below) builds ONE stable-ABI
9
9
  # `cp310-abi3` wheel per platform that loads on every CPython >= 3.10
10
10
  # (matching `pyproject.toml`'s `requires-python = ">=3.10"`), instead of
@@ -65,7 +65,8 @@ export default defineConfig({
65
65
  { text: 'Keep the index across restarts', link: '/howto/persist' },
66
66
  { text: 'React to file changes', link: '/howto/react-to-changes' },
67
67
  { text: 'Write a plugin', link: '/howto/write-a-plugin' },
68
- { text: 'Embed dirsql in your application', link: '/howto/embed' }
68
+ { text: 'Embed dirsql in your application', link: '/howto/embed' },
69
+ { text: 'Give your agent the dirsql skill', link: '/howto/agent-skill' }
69
70
  ]
70
71
  },
71
72
  {
@@ -0,0 +1,64 @@
1
+ # Give your coding agent the `dirsql` skill
2
+
3
+ Your coding agent answers questions about many files by reading them one at a
4
+ time. The `dirsql` skill teaches it to write one SQL query instead.
5
+
6
+ ## What it does
7
+
8
+ The skill is a short `SKILL.md`. Its description tells the agent when to use
9
+ it: counting, grouping or aggregating files, "which files are ..." by size,
10
+ mtime or extension, pulling one field out of many JSON or frontmatter files,
11
+ or comparing two directories. It tells the agent not to use it to read one
12
+ known file, hunt for a literal string, or list a few names.
13
+
14
+ When the skill triggers, the agent runs `dirsql context`. That prints a guide
15
+ (usage, recipes, troubleshooting) compiled into the `dirsql` binary, so the
16
+ agent always reads the guide for the version it is about to run. See
17
+ [`dirsql context`](../reference/cli.md#dirsql-context).
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npx skills add thekevinscott/dirsql
23
+ ```
24
+
25
+ This uses [`skills`](https://www.npmjs.com/package/skills), a cross-agent
26
+ skill installer. It installs for the current project by default. Pass `-g` to
27
+ install for your user instead, `-a <agent>` to name
28
+ agents (repeatable), and `-y` to skip the prompts.
29
+
30
+ | Scope | Skill lands in | Claude Code link |
31
+ |---|---|---|
32
+ | Project (default) | `.agents/skills/dirsql` | `.claude/skills/dirsql` |
33
+ | User (`-g`) | `~/.agents/skills/dirsql` | `~/.claude/skills/dirsql` |
34
+
35
+ Codex, Cursor, Gemini CLI, Amp, Cline and other agents that read
36
+ `.agents/skills` use the shared copy directly. Agents with their own skills
37
+ directory, such as Claude Code, get a symlink to it (`--copy` copies instead).
38
+ `npx skills add --help` lists the rest.
39
+
40
+ ## Runners
41
+
42
+ The skill works with whichever runner you have. Its `allowed-tools` lets the
43
+ agent run these commands without a permission prompt:
44
+
45
+ | Runner | Command the agent runs |
46
+ |---|---|
47
+ | `uv` | `uvx dirsql ...` |
48
+ | `npm` | `npx -y dirsql ...` |
49
+ | `cargo` | `dirsql ...` after `cargo install dirsql --features cli` |
50
+
51
+ The grant is `Bash(uvx dirsql:*)`, `Bash(npx -y dirsql:*)` and
52
+ `Bash(dirsql:*)`.
53
+
54
+ ## Check, update, remove
55
+
56
+ ```bash
57
+ npx skills list # installed skills and their agents (-g for user scope)
58
+ npx skills update # refresh to the latest from GitHub
59
+ npx skills remove dirsql
60
+ ```
61
+
62
+ `update` and `remove` accept `-g` for user scope and `-y` to skip prompts.
63
+ The skill itself never needs updating to match the CLI, since the guide comes
64
+ from the installed `dirsql`.
@@ -454,12 +454,7 @@ troubleshooting. The guide is compiled into the binary, so it describes the
454
454
  version that prints it. It takes no flags and exits `0`.
455
455
 
456
456
  The dirsql agent skill tells an agent to run this command before it writes a
457
- query. Install the skill into Claude Code, Codex, Cursor, Gemini CLI and
458
- others with:
459
-
460
- ```sh
461
- npx skills add thekevinscott/dirsql
462
- ```
457
+ query; see [the skill page](../howto/agent-skill.md).
463
458
 
464
459
  ## Plugins
465
460
 
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1791292687,
4
+ "exit_code": 0,
5
+ "commit": "59f2b4249816735553d8a2270ded77fc4f9c3e2c",
6
+ "branch": "claude/1305-glob-speed"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1791268015,
4
+ "exit_code": 0,
5
+ "commit": "0cfba3aeec10eac3af444896624084f3432aadaf",
6
+ "branch": "claude/1308-glob-speed"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1791258925,
4
+ "exit_code": 0,
5
+ "commit": "a94c48568f24ccb64acd024d4b6db7f9f2897435",
6
+ "branch": "claude/1310-glob-speed"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1791262582,
4
+ "exit_code": 0,
5
+ "commit": "5dfbe50e4b422eddb2e849841bff78a49946de94",
6
+ "branch": "claude/1311-glob-speed"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1791265213,
4
+ "exit_code": 0,
5
+ "commit": "0fdecf55fbc4c3d7ca1623865ec804fdfb196979",
6
+ "branch": "claude/1312-glob-speed"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "uv run python -m pytest tests/e2e/ -q --deselect tests/e2e/glob_speed_one_level_test.py",
3
+ "ran_at": 1791234677,
4
+ "exit_code": 0,
5
+ "commit": "3d5645d54f19c86ce3fa2ce75d9a8392450b19e4",
6
+ "branch": "claude/1318-lazy-stat"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "uv run python -m pytest tests/e2e/ -q --deselect tests/e2e/glob_speed_one_level_test.py",
3
+ "ran_at": 1791238784,
4
+ "exit_code": 0,
5
+ "commit": "da4c59800ef0c252699acc078738b1b5332dd751",
6
+ "branch": "claude/1320-walk-speed"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "uv run python -m pytest tests/e2e/ -q --deselect tests/e2e/glob_speed_one_level_test.py",
3
+ "ran_at": 1791239586,
4
+ "exit_code": 0,
5
+ "commit": "5320f737098f6359ba10e35cbab508be367116bc",
6
+ "branch": "claude/1322-walk-readdir"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1791242399,
4
+ "exit_code": 0,
5
+ "commit": "05c2e1ad49fa161f2538efdad2c7e42468f001a7",
6
+ "branch": "claude/1325-parallel-walk"
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "just test-e2e",
3
+ "ran_at": 1791241697,
4
+ "exit_code": 0,
5
+ "commit": "55ef5b88f40ba4a5568f1fed86a784caf8129cd7",
6
+ "branch": "claude/1326-stream-rows"
7
+ }
@@ -7,7 +7,7 @@
7
7
  # through it (#721), so every e2e case crosses it. packages/ts/napi is not: it
8
8
  # cannot reach this suite.
9
9
  [e2e]
10
- extra_scope = ["packages/rust/src", "packages/python/src"]
10
+ extra_scope = ["packages/rust/src", "packages/python/src", "packages/python/tests/e2e"]
11
11
 
12
12
  # Same floor as the root file, which this lane no longer reads.
13
13
  [python.coverage]
@@ -6,7 +6,7 @@ description = "Ephemeral SQL index over a local directory"
6
6
  # version stays for the binding crates (publish = false). The literal
7
7
  # intentionally lags the published version: putitoutthere rewrites it to
8
8
  # the planned release version at build time and never commits it back.
9
- version = "0.4.75"
9
+ version = "0.4.77"
10
10
  edition.workspace = true
11
11
  # Literal `license` (not `license.workspace = true`) because
12
12
  # putitoutthere's preflight check reads `[package].license` directly
@@ -89,6 +89,10 @@ tokio-stream = { version = "0.1", features = ["sync"], optional = true }
89
89
  toml = "0.8"
90
90
  typed-path = "0.12"
91
91
 
92
+ # Reads a directory's names into one buffer instead of one allocation each.
93
+ [target.'cfg(unix)'.dependencies]
94
+ rustix = { version = "1", features = ["fs"] }
95
+
92
96
  [lints.rust]
93
97
  # `deny`, not `forbid`: rusqlite's API imposes five unavoidable `unsafe`
94
98
  # sites (the `load_extension` guard and four `unsafe impl VTab`/`VTabCursor`).
@@ -0,0 +1,64 @@
1
+ # Give your coding agent the `dirsql` skill
2
+
3
+ Your coding agent answers questions about many files by reading them one at a
4
+ time. The `dirsql` skill teaches it to write one SQL query instead.
5
+
6
+ ## What it does
7
+
8
+ The skill is a short `SKILL.md`. Its description tells the agent when to use
9
+ it: counting, grouping or aggregating files, "which files are ..." by size,
10
+ mtime or extension, pulling one field out of many JSON or frontmatter files,
11
+ or comparing two directories. It tells the agent not to use it to read one
12
+ known file, hunt for a literal string, or list a few names.
13
+
14
+ When the skill triggers, the agent runs `dirsql context`. That prints a guide
15
+ (usage, recipes, troubleshooting) compiled into the `dirsql` binary, so the
16
+ agent always reads the guide for the version it is about to run. See
17
+ [`dirsql context`](../reference/cli.md#dirsql-context).
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npx skills add thekevinscott/dirsql
23
+ ```
24
+
25
+ This uses [`skills`](https://www.npmjs.com/package/skills), a cross-agent
26
+ skill installer. It installs for the current project by default. Pass `-g` to
27
+ install for your user instead, `-a <agent>` to name
28
+ agents (repeatable), and `-y` to skip the prompts.
29
+
30
+ | Scope | Skill lands in | Claude Code link |
31
+ |---|---|---|
32
+ | Project (default) | `.agents/skills/dirsql` | `.claude/skills/dirsql` |
33
+ | User (`-g`) | `~/.agents/skills/dirsql` | `~/.claude/skills/dirsql` |
34
+
35
+ Codex, Cursor, Gemini CLI, Amp, Cline and other agents that read
36
+ `.agents/skills` use the shared copy directly. Agents with their own skills
37
+ directory, such as Claude Code, get a symlink to it (`--copy` copies instead).
38
+ `npx skills add --help` lists the rest.
39
+
40
+ ## Runners
41
+
42
+ The skill works with whichever runner you have. Its `allowed-tools` lets the
43
+ agent run these commands without a permission prompt:
44
+
45
+ | Runner | Command the agent runs |
46
+ |---|---|
47
+ | `uv` | `uvx dirsql ...` |
48
+ | `npm` | `npx -y dirsql ...` |
49
+ | `cargo` | `dirsql ...` after `cargo install dirsql --features cli` |
50
+
51
+ The grant is `Bash(uvx dirsql:*)`, `Bash(npx -y dirsql:*)` and
52
+ `Bash(dirsql:*)`.
53
+
54
+ ## Check, update, remove
55
+
56
+ ```bash
57
+ npx skills list # installed skills and their agents (-g for user scope)
58
+ npx skills update # refresh to the latest from GitHub
59
+ npx skills remove dirsql
60
+ ```
61
+
62
+ `update` and `remove` accept `-g` for user scope and `-y` to skip prompts.
63
+ The skill itself never needs updating to match the CLI, since the guide comes
64
+ from the installed `dirsql`.
@@ -454,12 +454,7 @@ troubleshooting. The guide is compiled into the binary, so it describes the
454
454
  version that prints it. It takes no flags and exits `0`.
455
455
 
456
456
  The dirsql agent skill tells an agent to run this command before it writes a
457
- query. Install the skill into Claude Code, Codex, Cursor, Gemini CLI and
458
- others with:
459
-
460
- ```sh
461
- npx skills add thekevinscott/dirsql
462
- ```
457
+ query; see [the skill page](../howto/agent-skill.md).
463
458
 
464
459
  ## Plugins
465
460
 
@@ -15,7 +15,7 @@ use serde::Deserialize;
15
15
  use serde_json::Value;
16
16
 
17
17
  use super::AppState;
18
- use super::serialize::result_to_json;
18
+ use super::serialize::{JsonRows, result_to_json};
19
19
  use crate::{DirSQL, DirSqlError};
20
20
 
21
21
  /// Why a query failed, classified independently of transport. The HTTP
@@ -79,6 +79,28 @@ pub async fn execute_query(
79
79
  }
80
80
  }
81
81
 
82
+ /// [`execute_query`] for the one-shot CLI's JSON output: the same intake and
83
+ /// errors, with the rows written as JSON while SQLite yields them. The text
84
+ /// is the `{value}\n` the CLI printed from [`execute_query`]'s array, held
85
+ /// until the statement ends so a failing query still prints no rows.
86
+ pub async fn execute_query_json(
87
+ state: &AppState,
88
+ raw_body: String,
89
+ ) -> Result<Vec<u8>, QueryFailure> {
90
+ let sql = parse_sql_body(&raw_body)?;
91
+ let db = require_ready(state)?;
92
+ let join = tokio::task::spawn_blocking(move || {
93
+ db.query_each(&sql, JsonRows::new, JsonRows::row)
94
+ .map(JsonRows::finish)
95
+ })
96
+ .await;
97
+ match join {
98
+ Ok(Ok(text)) => Ok(text),
99
+ Ok(Err(err)) => Err(classify_query_error(err)),
100
+ Err(join_err) => Err(QueryFailure::Internal(join_err.to_string())),
101
+ }
102
+ }
103
+
82
104
  /// Await `task`, bounded by `timeout` when one is given ([`QueryFailure::Timeout`]
83
105
  /// carrying the bound on expiry) and to completion with `None`.
84
106
  async fn run_bounded<T>(
@@ -15,11 +15,14 @@
15
15
  //! The `dirsql` binary is a shim over [`run_cli`], so `cargo install dirsql
16
16
  //! --features cli` and every other entry path run the same code.
17
17
 
18
- use std::io::IsTerminal;
18
+ use std::io::{IsTerminal, Write};
19
19
  use std::path::PathBuf;
20
20
 
21
21
  use super::{
22
- AppState, ServerConfig, execute::execute_query, init::InitOptions, repl::run_repl,
22
+ AppState, ServerConfig,
23
+ execute::{execute_query, execute_query_json},
24
+ init::InitOptions,
25
+ repl::run_repl,
23
26
  serve_with_state, table,
24
27
  };
25
28
  use crate::{DirSQL, Extension, Row, Table};
@@ -336,13 +339,13 @@ pub fn run_cli(argv: Vec<String>) -> i32 {
336
339
  let code = runtime.block_on(async {
337
340
  match cli.command.take() {
338
341
  Some(Command::Init(args)) => run_init(args),
339
- Some(Command::Query(args)) => run_query(args).await,
342
+ Some(Command::Query(args)) => run_query(args, &mut std::io::stdout()).await,
340
343
  Some(Command::Server(args)) => run_server(args).await,
341
344
  Some(Command::Context) => {
342
345
  print!("{}", super::context::guide());
343
346
  0
344
347
  }
345
- None => run_default(cli).await,
348
+ None => run_default(cli, &mut std::io::stdout()).await,
346
349
  }
347
350
  });
348
351
  i32::from(code)
@@ -356,15 +359,18 @@ pub fn run_cli(argv: Vec<String>) -> i32 {
356
359
  /// The index is built **once**, before the loop, rather than per statement:
357
360
  /// no directory re-scan between statements, and the live watcher keeps it
358
361
  /// fresh across them.
359
- async fn run_default(cli: Cli) -> u8 {
362
+ async fn run_default(cli: Cli, out: &mut impl Write) -> u8 {
360
363
  match cli.sql {
361
364
  Some(sql) => {
362
- run_query(QueryArgs {
363
- sql,
364
- on_file: cli.on_file,
365
- format: cli.format,
366
- common: cli.common,
367
- })
365
+ run_query(
366
+ QueryArgs {
367
+ sql,
368
+ on_file: cli.on_file,
369
+ format: cli.format,
370
+ common: cli.common,
371
+ },
372
+ out,
373
+ )
368
374
  .await
369
375
  }
370
376
  None => {
@@ -382,7 +388,7 @@ async fn run_default(cli: Cli) -> u8 {
382
388
  // `StdinLock` is not `Send`, so it cannot cross into the
383
389
  // blocking read; `BufReader<Stdin>` locks per call and can.
384
390
  std::io::BufReader::new(std::io::stdin()),
385
- &mut std::io::stdout(),
391
+ out,
386
392
  &mut std::io::stderr(),
387
393
  std::io::stdin().is_terminal(),
388
394
  )
@@ -393,11 +399,11 @@ async fn run_default(cli: Cli) -> u8 {
393
399
 
394
400
  /// One-shot `dirsql query`: build the index exactly as server mode would
395
401
  /// (same `load_state` / hook loading), run the SQL through the shared
396
- /// [`execute_query`] pipeline, print the result JSON on stdout, and exit.
402
+ /// [`execute_query`] pipeline, write the result to `out`, and exit.
397
403
  /// Any [`QueryFailure`](super::execute::QueryFailure) prints its
398
404
  /// message — the same string the HTTP `{"error": …}` body carries — to
399
405
  /// stderr with a non-zero exit.
400
- async fn run_query(args: QueryArgs) -> u8 {
406
+ async fn run_query(args: QueryArgs, out: &mut dyn Write) -> u8 {
401
407
  let parser = match resolve_on_file(&args.on_file) {
402
408
  Ok(parser) => parser,
403
409
  Err(message) => {
@@ -411,9 +417,17 @@ async fn run_query(args: QueryArgs) -> u8 {
411
417
  // natively; only the long-lived server enforces `query_timeout` (408).
412
418
  let format = args.format.resolve(std::io::stdout().is_terminal());
413
419
 
414
- match execute_query(&state, query_body(&args.sql), None).await {
415
- Ok(value) => {
416
- print!("{}", render_rows(&value, format));
420
+ let printed = match format {
421
+ Format::Table => execute_query(&state, query_body(&args.sql), None)
422
+ .await
423
+ .map(|value| render_rows(&value, format).into_bytes()),
424
+ _ => execute_query_json(&state, query_body(&args.sql)).await,
425
+ };
426
+ match printed {
427
+ Ok(text) => {
428
+ // A closed pipe (`| head`) is the reader's choice, not a failure.
429
+ let _ = out.write_all(&text);
430
+ let _ = out.flush();
417
431
  0
418
432
  }
419
433
  Err(failure) => {
@@ -664,6 +678,59 @@ mod tests {
664
678
  assert_eq!(query_body(" "), r#"{"sql":" "}"#);
665
679
  }
666
680
 
681
+ fn query_args(argv: &[&str]) -> QueryArgs {
682
+ match Cli::parse_from(argv).command {
683
+ Some(Command::Query(args)) => args,
684
+ other => panic!("expected a query subcommand, got {other:?}"),
685
+ }
686
+ }
687
+
688
+ #[tokio::test]
689
+ async fn run_query_writes_the_rows_as_json_and_exits_zero() {
690
+ let mut out = Vec::new();
691
+ let args = query_args(&[
692
+ "dirsql",
693
+ "query",
694
+ "--format",
695
+ "json",
696
+ "SELECT 1 AS a, 'x' AS b",
697
+ ]);
698
+ assert_eq!(run_query(args, &mut out).await, 0);
699
+ assert_eq!(out, b"[{\"a\":1,\"b\":\"x\"}]\n");
700
+ }
701
+
702
+ #[tokio::test]
703
+ async fn run_query_writes_the_rows_as_a_table_when_asked() {
704
+ let mut out = Vec::new();
705
+ let args = query_args(&["dirsql", "query", "--format", "table", "SELECT 1 AS a"]);
706
+ assert_eq!(run_query(args, &mut out).await, 0);
707
+ assert_eq!(out, b"a\n-\n1\n\n1 row\n");
708
+ }
709
+
710
+ #[tokio::test]
711
+ async fn run_query_exits_one_and_writes_nothing_when_the_query_fails() {
712
+ let mut out = Vec::new();
713
+ let args = query_args(&["dirsql", "query", "--format", "json", "SELECT nope"]);
714
+ assert_eq!(run_query(args, &mut out).await, 1);
715
+ assert!(out.is_empty());
716
+ }
717
+
718
+ #[tokio::test]
719
+ async fn run_default_runs_its_sql_as_a_one_shot_query() {
720
+ let mut out = Vec::new();
721
+ let cli = Cli::parse_from(["dirsql", "--format", "json", "SELECT 1 AS a"]);
722
+ assert_eq!(run_default(cli, &mut out).await, 0);
723
+ assert_eq!(out, b"[{\"a\":1}]\n");
724
+ }
725
+
726
+ #[tokio::test]
727
+ async fn run_default_exits_one_when_its_sql_fails() {
728
+ let mut out = Vec::new();
729
+ let cli = Cli::parse_from(["dirsql", "--format", "json", "SELECT nope"]);
730
+ assert_eq!(run_default(cli, &mut out).await, 1);
731
+ assert!(out.is_empty());
732
+ }
733
+
667
734
  /// The `ConfigArgs` parsed from a `query` subcommand invocation (#609:
668
735
  /// config flags are subcommand-local, so they live on the Query variant).
669
736
  fn query_common(argv: &[&str]) -> ConfigArgs {