blq-cli 0.11.2__tar.gz → 0.12.0__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.
- {blq_cli-0.11.2 → blq_cli-0.12.0}/.gitignore +2 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/CLAUDE.md +9 -9
- {blq_cli-0.11.2 → blq_cli-0.12.0}/PKG-INFO +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/plans/roadmap-to-1.0.md +2 -2
- {blq_cli-0.11.2 → blq_cli-0.12.0}/pyproject.toml +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/bird.py +7 -7
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/bird_schema.sql +2 -2
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/cli.py +6 -6
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/ci_cmd.py +3 -3
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/clean_cmd.py +4 -4
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/config_cmd.py +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/core.py +66 -37
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/execution.py +4 -4
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/hooks_cmd.py +17 -17
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/hooks_gen.py +2 -2
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/init_cmd.py +28 -24
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/management.py +6 -6
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/migrate.py +2 -2
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/query_cmd.py +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/registry.py +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/serve_cmd.py +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/sync_cmd.py +4 -4
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/locks.py +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/query.py +14 -14
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/schema.sql +3 -3
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/serve.py +15 -10
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/storage.py +22 -14
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/templates/drone.yml.j2 +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/templates/git_hook.sh.j2 +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/templates/github_workflow.yml.j2 +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/templates/gitlab_ci.yml.j2 +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/templates/hook_script.sh.j2 +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/user_config.py +2 -2
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/conftest.py +2 -2
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_attempts_outcomes.py +31 -31
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_auto_init.py +3 -3
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_autoprune.py +10 -10
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_bird.py +19 -19
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_ci_generators.py +5 -5
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_core.py +20 -20
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_ext_integration.py +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_ext_types.py +3 -3
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_hooks.py +4 -4
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_hooks_gen.py +5 -5
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_inspect.py +4 -4
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_phase2_command_registry.py +4 -4
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_query_api.py +2 -2
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_query_filter.py +3 -3
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_record_invocation.py +7 -7
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_sandbox_ext.py +1 -1
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_storage.py +2 -2
- {blq_cli-0.11.2 → blq_cli-0.12.0}/.claude/hooks/blq-suggest.sh +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/.github/workflows/ci.yml +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/.github/workflows/docs.yml +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/.github/workflows/publish.yml +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/.mcp.json +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/.readthedocs.yml +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/AGENT.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/AGENTS.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/CONTRIBUTING.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/README.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/SKILL.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/capture.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/ci.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/completions.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/errors.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/exec.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/filter.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/index.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/init.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/maintenance.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/query.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/registry.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/report.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/run.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/sql.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/status.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/sync.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/commands/watch.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-bird-migration.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-commands.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-config-command.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-extensions.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-git-integration.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-hooks-v2.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-live-inspection.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-parameterized-commands.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-run-args.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-sandbox-specs.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-sync.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/design-track-save.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/duck-hunt-v2-migration.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/duck-hunt-v3-migration.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/proposal-bird-v5.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/design/skill-inspect-enrichment.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/getting-started.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/index.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/integration.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/mcp.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/plans/explore-nsjail-python-wrapper.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/plans/explore-nsjail-spack-package.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/plans/patterns-integration-prompt.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/python-api.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/query-guide.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/requirements.txt +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/sandbox.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/schema.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/superpowers/plans/2026-03-22-extension-system.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/superpowers/plans/2026-03-28-bwrap-engine.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/superpowers/plans/2026-03-28-command-locks.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/superpowers/plans/2026-03-29-annotators-and-tighten.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/superpowers/plans/2026-03-29-service-layer-phase1.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/superpowers/plans/2026-03-29-strace-profiling.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/superpowers/specs/2026-03-22-extension-system-design.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/docs/superpowers/specs/2026-03-29-unified-service-layer-design.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/experiments/agent-build-test.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/mkdocs.yml +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/__init__.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/__main__.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/README.md +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/__init__.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/events.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/management_cmd.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/mcp_cmd.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/record_cmd.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/report_cmd.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/sandbox_cmd.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/commands/watch_cmd.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/config_format.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/ext/__init__.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/ext/annotator.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/ext/discovery.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/ext/local_executor.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/ext/pipeline.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/git.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/github.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/output.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/services/__init__.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/services/execution.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/services/inspect.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/services/query.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq/services/refs.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox/__init__.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox/engines.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox/profile.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox/source_annotator.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox/spec.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox/strace_parser.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox/tighten.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox/violations.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox_bwrap/__init__.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox_bwrap/args.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/src/blq_sandbox_systemd/__init__.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/__init__.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/sql/test_duck_hunt_v2_migration.sql +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_annotator.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_bwrap_args.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_bwrap_engine.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_ci.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_command_args.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_command_lock_field.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_execution_locks.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_exit_code_reason.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_ext_discovery.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_ext_local_executor.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_ext_pipeline.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_git.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_json_null_filter.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_locks.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_mcp_ci_tools.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_mcp_merge.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_mcp_server.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_phase1_structured_output.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_report.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_sandbox.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_sandbox_cmd.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_sandbox_events.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_sandbox_profile.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_sandbox_register.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_sandbox_systemd.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_sandbox_tighten.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_sandbox_violations.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_services_execution.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_services_inspect.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_services_query.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_services_refs.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_source_annotator.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_storage_prune.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_strace_parser.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_user_config.py +0 -0
- {blq_cli-0.11.2 → blq_cli-0.12.0}/tests/test_watch.py +0 -0
|
@@ -98,7 +98,7 @@ This is the initial scaffolding for `blq` (Build Log Query) - a CLI tool for cap
|
|
|
98
98
|
- [ ] Consider integration with duckdb_mcp for ATTACH/DETACH workflow
|
|
99
99
|
|
|
100
100
|
**BIRD Spec:**
|
|
101
|
-
- [
|
|
101
|
+
- [x] Migrated from `.lq/` to `.bird/` directory (auto-migration from legacy)
|
|
102
102
|
- [ ] Running process tracking (pending BIRD spec)
|
|
103
103
|
- [ ] Migrate to updated BIRD spec (when ready)
|
|
104
104
|
|
|
@@ -111,13 +111,13 @@ This is the initial scaffolding for `blq` (Build Log Query) - a CLI tool for cap
|
|
|
111
111
|
```
|
|
112
112
|
blq (Python CLI)
|
|
113
113
|
│
|
|
114
|
-
├── .
|
|
114
|
+
├── .bird/blq.duckdb - BIRD database with tables and macros
|
|
115
115
|
│ ├── sessions - Invoker sessions (shell, CLI, MCP)
|
|
116
116
|
│ ├── invocations - Command executions with metadata
|
|
117
117
|
│ ├── outputs - Captured stdout/stderr (content-addressed)
|
|
118
118
|
│ └── events - Parsed diagnostics (errors, warnings)
|
|
119
119
|
│
|
|
120
|
-
├── .
|
|
120
|
+
├── .bird/blobs/ - Content-addressed blob storage
|
|
121
121
|
│ └── content/ab/{hash}.bin
|
|
122
122
|
│
|
|
123
123
|
├── Uses duckdb Python API directly
|
|
@@ -171,7 +171,7 @@ All SQL macros use the `blq_` prefix:
|
|
|
171
171
|
|
|
172
172
|
Direct DuckDB access:
|
|
173
173
|
```bash
|
|
174
|
-
duckdb .
|
|
174
|
+
duckdb .bird/blq.duckdb "SELECT * FROM blq_status()"
|
|
175
175
|
```
|
|
176
176
|
|
|
177
177
|
## Run Metadata
|
|
@@ -193,7 +193,7 @@ Each `blq run` captures comprehensive execution context:
|
|
|
193
193
|
|
|
194
194
|
### Environment Capture
|
|
195
195
|
|
|
196
|
-
Configurable in `.
|
|
196
|
+
Configurable in `.bird/config.toml`:
|
|
197
197
|
```toml
|
|
198
198
|
capture_env = [
|
|
199
199
|
"PATH",
|
|
@@ -221,7 +221,7 @@ SELECT ci['provider'], ci['run_id'] FROM blq_load_events() WHERE ci IS NOT NULL
|
|
|
221
221
|
|
|
222
222
|
## Project Identification
|
|
223
223
|
|
|
224
|
-
Detected at `blq init` and stored in `.
|
|
224
|
+
Detected at `blq init` and stored in `.bird/config.toml`:
|
|
225
225
|
|
|
226
226
|
```toml
|
|
227
227
|
[project]
|
|
@@ -265,7 +265,7 @@ Runtime override: `blq run --no-capture <cmd>` or `blq run --capture <cmd>`
|
|
|
265
265
|
|
|
266
266
|
1. **BIRD as default storage**: DuckDB tables for simpler queries, content-addressed blobs for outputs
|
|
267
267
|
2. **Parquet mode available**: For multi-writer scenarios (legacy, use `--parquet` flag)
|
|
268
|
-
3. **Project-local storage**: `.
|
|
268
|
+
3. **Project-local storage**: `.bird/` directory in project root
|
|
269
269
|
4. **blq.duckdb for everything**: Tables, views, and macros in single database file
|
|
270
270
|
5. **Table-returning macros**: `blq_load_events()` evaluated at query time, not view creation
|
|
271
271
|
6. **Backward-compatible views**: `blq_events_flat` provides v1-compatible schema
|
|
@@ -334,7 +334,7 @@ blq mcp serve -D exec,clean # Disable specific tools
|
|
|
334
334
|
blq mcp serve -S -D custom_tool # Combine safe mode with additional tools
|
|
335
335
|
```
|
|
336
336
|
|
|
337
|
-
Or via `.
|
|
337
|
+
Or via `.bird/config.toml`:
|
|
338
338
|
```toml
|
|
339
339
|
[mcp]
|
|
340
340
|
disabled_tools = ["clean", "register_command", "unregister_command"]
|
|
@@ -441,7 +441,7 @@ ruff format src/blq/
|
|
|
441
441
|
|
|
442
442
|
### Config Options
|
|
443
443
|
|
|
444
|
-
Key `.
|
|
444
|
+
Key `.bird/config.toml` options:
|
|
445
445
|
```toml
|
|
446
446
|
[storage]
|
|
447
447
|
keep_raw = true # Always keep raw output
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blq-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Buidl Log Query - capture and query build/test logs with DuckDB
|
|
5
5
|
Project-URL: Homepage, https://blq-cli.readthedocs.com/
|
|
6
6
|
Project-URL: Repository, https://github.com/teaguesterling/blq-cli
|
|
@@ -52,11 +52,11 @@ Fetch and query logs from CI systems. This is the last major feature gap.
|
|
|
52
52
|
|
|
53
53
|
**Why before 1.0:** Users expect to query CI logs the same way they query local logs. Without sync, blq is local-only, which limits its value for teams.
|
|
54
54
|
|
|
55
|
-
### 0.
|
|
55
|
+
### 0.12.x — BIRD Spec Finalization
|
|
56
56
|
|
|
57
57
|
Settle the storage format before committing to API stability.
|
|
58
58
|
|
|
59
|
-
- [
|
|
59
|
+
- [x] `.lq/` → `.bird/` directory migration (#35) — auto-migration on first access
|
|
60
60
|
- [ ] Finalize schema version, document storage guarantees (#36)
|
|
61
61
|
|
|
62
62
|
**Why before 1.0:** Changing the storage directory or schema after 1.0 would be a breaking change. Lock it down now.
|
|
@@ -314,7 +314,7 @@ class BirdStore:
|
|
|
314
314
|
It handles sessions, invocations, outputs, and events tables.
|
|
315
315
|
|
|
316
316
|
Example:
|
|
317
|
-
store = BirdStore.open(".
|
|
317
|
+
store = BirdStore.open(".bird/")
|
|
318
318
|
|
|
319
319
|
# Register session (once per CLI invocation)
|
|
320
320
|
store.ensure_session("test", "blq-shell", "blq", "cli")
|
|
@@ -330,7 +330,7 @@ class BirdStore:
|
|
|
330
330
|
"""Initialize BirdStore.
|
|
331
331
|
|
|
332
332
|
Args:
|
|
333
|
-
lq_dir: Path to .
|
|
333
|
+
lq_dir: Path to .bird directory
|
|
334
334
|
conn: Open DuckDB connection
|
|
335
335
|
"""
|
|
336
336
|
self._lq_dir = lq_dir
|
|
@@ -355,7 +355,7 @@ class BirdStore:
|
|
|
355
355
|
"""Open or create a BirdStore.
|
|
356
356
|
|
|
357
357
|
Args:
|
|
358
|
-
lq_dir: Path to .
|
|
358
|
+
lq_dir: Path to .bird directory
|
|
359
359
|
|
|
360
360
|
Returns:
|
|
361
361
|
BirdStore instance
|
|
@@ -384,7 +384,7 @@ class BirdStore:
|
|
|
384
384
|
writers (e.g., parallel command execution, hooks).
|
|
385
385
|
|
|
386
386
|
Args:
|
|
387
|
-
lq_dir: Path to .
|
|
387
|
+
lq_dir: Path to .bird directory
|
|
388
388
|
max_retries: Maximum number of retry attempts
|
|
389
389
|
initial_delay: Initial delay between retries in seconds
|
|
390
390
|
|
|
@@ -408,7 +408,7 @@ class BirdStore:
|
|
|
408
408
|
|
|
409
409
|
Args:
|
|
410
410
|
conn: DuckDB connection
|
|
411
|
-
lq_dir: Path to .
|
|
411
|
+
lq_dir: Path to .bird directory
|
|
412
412
|
force: If True, reload schema even if it exists (for reinit)
|
|
413
413
|
"""
|
|
414
414
|
# Check if schema is already initialized (skip on force)
|
|
@@ -936,7 +936,7 @@ class BirdStore:
|
|
|
936
936
|
attempt_id: The attempt UUID
|
|
937
937
|
|
|
938
938
|
Returns:
|
|
939
|
-
Path to live output directory (.
|
|
939
|
+
Path to live output directory (.bird/live/{attempt_id}/)
|
|
940
940
|
"""
|
|
941
941
|
return self._lq_dir / "live" / attempt_id
|
|
942
942
|
|
|
@@ -1617,7 +1617,7 @@ def write_bird_invocation(
|
|
|
1617
1617
|
Args:
|
|
1618
1618
|
events: Parsed events from the command output
|
|
1619
1619
|
run_meta: Run metadata dict (same format as write_run_parquet)
|
|
1620
|
-
lq_dir: Path to .
|
|
1620
|
+
lq_dir: Path to .bird directory
|
|
1621
1621
|
output: Optional raw output bytes to store
|
|
1622
1622
|
|
|
1623
1623
|
Returns:
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
-- All reads go through views, writes go directly to tables.
|
|
5
5
|
--
|
|
6
6
|
-- Directory structure:
|
|
7
|
-
-- .
|
|
7
|
+
-- .bird/
|
|
8
8
|
-- ├── blq.duckdb # Database with tables and views
|
|
9
9
|
-- ├── blobs/ # Content-addressed output storage
|
|
10
10
|
-- │ └── content/
|
|
@@ -30,7 +30,7 @@ INSERT OR IGNORE INTO blq_metadata VALUES ('schema_version', '2.4.0');
|
|
|
30
30
|
INSERT OR IGNORE INTO blq_metadata VALUES ('storage_mode', 'duckdb');
|
|
31
31
|
|
|
32
32
|
-- Base path for blob storage (set at runtime)
|
|
33
|
-
CREATE OR REPLACE MACRO blq_blob_root() AS '.
|
|
33
|
+
CREATE OR REPLACE MACRO blq_blob_root() AS '.bird/blobs/content';
|
|
34
34
|
|
|
35
35
|
-- ============================================================================
|
|
36
36
|
-- CORE TABLES (BIRD Schema)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
blq CLI - Build Log Query command-line interface.
|
|
3
3
|
|
|
4
4
|
Usage:
|
|
5
|
-
blq init [--mcp] Initialize .
|
|
5
|
+
blq init [--mcp] Initialize .bird directory
|
|
6
6
|
blq run <command> Run registered command (alias: r)
|
|
7
7
|
blq exec <command> Execute ad-hoc command (alias: e)
|
|
8
8
|
blq import <file> [--name NAME] Import existing log file
|
|
@@ -201,7 +201,7 @@ def main() -> None:
|
|
|
201
201
|
"--lq-dir",
|
|
202
202
|
metavar="PATH",
|
|
203
203
|
dest="lq_dir",
|
|
204
|
-
help="Use specific .
|
|
204
|
+
help="Use specific .bird directory (overrides discovery)",
|
|
205
205
|
)
|
|
206
206
|
parser.add_argument(
|
|
207
207
|
"-F",
|
|
@@ -214,7 +214,7 @@ def main() -> None:
|
|
|
214
214
|
"--global",
|
|
215
215
|
action="store_true",
|
|
216
216
|
dest="global_",
|
|
217
|
-
help="Query global store (~/.
|
|
217
|
+
help="Query global store (~/.bird/projects/) instead of local .bird",
|
|
218
218
|
)
|
|
219
219
|
parser.add_argument(
|
|
220
220
|
"-d",
|
|
@@ -226,7 +226,7 @@ def main() -> None:
|
|
|
226
226
|
subparsers = parser.add_subparsers(dest="command", help="Command")
|
|
227
227
|
|
|
228
228
|
# init
|
|
229
|
-
p_init = subparsers.add_parser("init", help="Initialize .
|
|
229
|
+
p_init = subparsers.add_parser("init", help="Initialize .bird directory")
|
|
230
230
|
mcp_group = p_init.add_mutually_exclusive_group()
|
|
231
231
|
mcp_group.add_argument(
|
|
232
232
|
"--mcp", "-m", action="store_true", help="Create .mcp.json for MCP server discovery"
|
|
@@ -272,7 +272,7 @@ def main() -> None:
|
|
|
272
272
|
action="store_true",
|
|
273
273
|
dest="gitignore",
|
|
274
274
|
default=True,
|
|
275
|
-
help="Add .
|
|
275
|
+
help="Add .bird/ to .gitignore (default)",
|
|
276
276
|
)
|
|
277
277
|
gitignore_group.add_argument(
|
|
278
278
|
"--no-gitignore",
|
|
@@ -919,7 +919,7 @@ def main() -> None:
|
|
|
919
919
|
)
|
|
920
920
|
|
|
921
921
|
# clean full - full reset
|
|
922
|
-
p_clean_full = clean_subparsers.add_parser("full", help="Delete and recreate .
|
|
922
|
+
p_clean_full = clean_subparsers.add_parser("full", help="Delete and recreate .bird directory")
|
|
923
923
|
p_clean_full.add_argument(
|
|
924
924
|
"--confirm", "-y", action="store_true", help="Confirm destructive operation"
|
|
925
925
|
)
|
|
@@ -498,7 +498,7 @@ def _generate_simple_script(cmd: RegisteredCommand, shell: str = "bash") -> str:
|
|
|
498
498
|
set -euo pipefail
|
|
499
499
|
|
|
500
500
|
# Check if blq is available for log capture
|
|
501
|
-
if command -v blq &> /dev/null && [ -d ".
|
|
501
|
+
if command -v blq &> /dev/null && [ -d ".bird" ]; then
|
|
502
502
|
# Use blq to capture and parse output
|
|
503
503
|
if [ $# -gt 0 ]; then
|
|
504
504
|
blq run {name} -- "$@"
|
|
@@ -645,7 +645,7 @@ done
|
|
|
645
645
|
{required_block}
|
|
646
646
|
|
|
647
647
|
# Check if blq is available for log capture
|
|
648
|
-
if command -v blq &> /dev/null && [ -d ".
|
|
648
|
+
if command -v blq &> /dev/null && [ -d ".bird" ]; then
|
|
649
649
|
# Build blq run command with parameters
|
|
650
650
|
BLQ_ARGS="{cmd.name}"
|
|
651
651
|
"""
|
|
@@ -709,7 +709,7 @@ def cmd_ci_generate(args: argparse.Namespace) -> None:
|
|
|
709
709
|
"""
|
|
710
710
|
config = BlqConfig.find()
|
|
711
711
|
if config is None:
|
|
712
|
-
print("Error: .
|
|
712
|
+
print("Error: .bird not initialized. Run 'blq init' first.", file=sys.stderr)
|
|
713
713
|
sys.exit(1)
|
|
714
714
|
|
|
715
715
|
commands = config.commands
|
|
@@ -28,7 +28,7 @@ def cmd_clean(args: argparse.Namespace) -> None:
|
|
|
28
28
|
print(" prune Remove data older than N days", file=sys.stderr)
|
|
29
29
|
print(" orphans Mark stale pending runs as orphaned", file=sys.stderr)
|
|
30
30
|
print(" schema Recreate database schema", file=sys.stderr)
|
|
31
|
-
print(" full Delete and recreate .
|
|
31
|
+
print(" full Delete and recreate .bird directory", file=sys.stderr)
|
|
32
32
|
sys.exit(1)
|
|
33
33
|
|
|
34
34
|
config = BlqConfig.ensure()
|
|
@@ -240,9 +240,9 @@ def _clean_schema(lq_dir: Path, confirm: bool) -> None:
|
|
|
240
240
|
|
|
241
241
|
|
|
242
242
|
def _clean_full(lq_dir: Path, confirm: bool) -> None:
|
|
243
|
-
"""Delete and recreate .
|
|
243
|
+
"""Delete and recreate .bird directory."""
|
|
244
244
|
if not confirm:
|
|
245
|
-
print("This will delete the entire .
|
|
245
|
+
print("This will delete the entire .bird directory and reinitialize.", file=sys.stderr)
|
|
246
246
|
print("ALL data including config and commands will be lost.", file=sys.stderr)
|
|
247
247
|
print("", file=sys.stderr)
|
|
248
248
|
print("Run with --confirm to proceed.", file=sys.stderr)
|
|
@@ -259,7 +259,7 @@ def _clean_full(lq_dir: Path, confirm: bool) -> None:
|
|
|
259
259
|
)
|
|
260
260
|
|
|
261
261
|
if result.returncode == 0:
|
|
262
|
-
print("Fully reinitialized .
|
|
262
|
+
print("Fully reinitialized .bird directory.")
|
|
263
263
|
else:
|
|
264
264
|
print(f"Init failed: {result.stderr}", file=sys.stderr)
|
|
265
265
|
sys.exit(1)
|
|
@@ -39,7 +39,7 @@ CONFIG_SCHEMA: dict[str, dict[str, Any]] = {
|
|
|
39
39
|
"attr": "auto_gitignore",
|
|
40
40
|
"section": "init",
|
|
41
41
|
"key": "auto_gitignore",
|
|
42
|
-
"description": "Add .
|
|
42
|
+
"description": "Add .bird/ to .gitignore",
|
|
43
43
|
},
|
|
44
44
|
"init.default_storage": {
|
|
45
45
|
"type": "str",
|
|
@@ -8,6 +8,7 @@ that are shared across multiple commands.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
|
+
import logging
|
|
11
12
|
import os
|
|
12
13
|
import re
|
|
13
14
|
import shutil
|
|
@@ -33,11 +34,15 @@ from blq.git import GitInfo, capture_git_info # noqa: F401
|
|
|
33
34
|
if TYPE_CHECKING:
|
|
34
35
|
pass
|
|
35
36
|
|
|
37
|
+
logger = logging.getLogger("blq")
|
|
38
|
+
|
|
36
39
|
# ============================================================================
|
|
37
40
|
# Configuration
|
|
38
41
|
# ============================================================================
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
BIRD_DIR = ".bird"
|
|
44
|
+
LQ_DIR = BIRD_DIR # Backward-compatible alias
|
|
45
|
+
LEGACY_DIR = ".lq" # Old directory name for auto-migration
|
|
41
46
|
LOGS_DIR = "logs"
|
|
42
47
|
RAW_DIR = "raw"
|
|
43
48
|
SCHEMA_FILE = "schema.sql"
|
|
@@ -45,9 +50,10 @@ DB_FILE = "blq.duckdb"
|
|
|
45
50
|
# Re-export from config_format for compatibility
|
|
46
51
|
# COMMANDS_FILE = "commands.toml"
|
|
47
52
|
# CONFIG_FILE = "config.toml"
|
|
48
|
-
|
|
53
|
+
GLOBAL_BIRD_DIR = Path.home() / BIRD_DIR
|
|
54
|
+
GLOBAL_LQ_DIR = GLOBAL_BIRD_DIR # Backward-compatible alias
|
|
49
55
|
PROJECTS_DIR = "projects"
|
|
50
|
-
GLOBAL_PROJECTS_PATH =
|
|
56
|
+
GLOBAL_PROJECTS_PATH = GLOBAL_BIRD_DIR / PROJECTS_DIR
|
|
51
57
|
|
|
52
58
|
# ============================================================================
|
|
53
59
|
# Result Types
|
|
@@ -548,7 +554,7 @@ class WatchConfig:
|
|
|
548
554
|
"**/__pycache__/**",
|
|
549
555
|
"**/*.pyc",
|
|
550
556
|
"**/.git/**",
|
|
551
|
-
".
|
|
557
|
+
".bird/**",
|
|
552
558
|
"**/*.egg-info/**",
|
|
553
559
|
"**/node_modules/**",
|
|
554
560
|
"**/.venv/**",
|
|
@@ -620,32 +626,32 @@ class BlqConfig:
|
|
|
620
626
|
# Computed paths
|
|
621
627
|
@property
|
|
622
628
|
def logs_dir(self) -> Path:
|
|
623
|
-
"""Path to logs directory (.
|
|
629
|
+
"""Path to logs directory (.bird/logs)."""
|
|
624
630
|
return self.lq_dir / LOGS_DIR
|
|
625
631
|
|
|
626
632
|
@property
|
|
627
633
|
def raw_dir(self) -> Path:
|
|
628
|
-
"""Path to raw logs directory (.
|
|
634
|
+
"""Path to raw logs directory (.bird/raw)."""
|
|
629
635
|
return self.lq_dir / RAW_DIR
|
|
630
636
|
|
|
631
637
|
@property
|
|
632
638
|
def schema_path(self) -> Path:
|
|
633
|
-
"""Path to schema file (.
|
|
639
|
+
"""Path to schema file (.bird/schema.sql)."""
|
|
634
640
|
return self.lq_dir / SCHEMA_FILE
|
|
635
641
|
|
|
636
642
|
@property
|
|
637
643
|
def db_path(self) -> Path:
|
|
638
|
-
"""Path to database file (.
|
|
644
|
+
"""Path to database file (.bird/blq.duckdb)."""
|
|
639
645
|
return self.lq_dir / DB_FILE
|
|
640
646
|
|
|
641
647
|
@property
|
|
642
648
|
def config_path(self) -> Path:
|
|
643
|
-
"""Path to config file (.
|
|
649
|
+
"""Path to config file (.bird/config.toml)."""
|
|
644
650
|
return self.lq_dir / CONFIG_FILE
|
|
645
651
|
|
|
646
652
|
@property
|
|
647
653
|
def commands_path(self) -> Path:
|
|
648
|
-
"""Path to commands file (.
|
|
654
|
+
"""Path to commands file (.bird/commands.toml)."""
|
|
649
655
|
return self.lq_dir / COMMANDS_FILE
|
|
650
656
|
|
|
651
657
|
@property
|
|
@@ -705,7 +711,7 @@ class BlqConfig:
|
|
|
705
711
|
"**/__pycache__/**",
|
|
706
712
|
"**/*.pyc",
|
|
707
713
|
"**/.git/**",
|
|
708
|
-
".
|
|
714
|
+
".bird/**",
|
|
709
715
|
"**/*.egg-info/**",
|
|
710
716
|
"**/node_modules/**",
|
|
711
717
|
"**/.venv/**",
|
|
@@ -769,7 +775,7 @@ class BlqConfig:
|
|
|
769
775
|
def storage_config(self) -> dict[str, Any]:
|
|
770
776
|
"""Get project-level [storage] config as a raw dict.
|
|
771
777
|
|
|
772
|
-
This exposes .
|
|
778
|
+
This exposes .bird/config.toml's [storage] section for merging
|
|
773
779
|
with user config during autoprune.
|
|
774
780
|
|
|
775
781
|
Returns:
|
|
@@ -802,7 +808,10 @@ class BlqConfig:
|
|
|
802
808
|
|
|
803
809
|
@classmethod
|
|
804
810
|
def find(cls, start_dir: Path | None = None) -> BlqConfig | None:
|
|
805
|
-
"""Find .
|
|
811
|
+
"""Find .bird directory in start_dir or parents and load config.
|
|
812
|
+
|
|
813
|
+
Searches for .bird/ first. If not found but .lq/ exists,
|
|
814
|
+
auto-migrates by renaming .lq/ to .bird/.
|
|
806
815
|
|
|
807
816
|
Args:
|
|
808
817
|
start_dir: Directory to start searching from (default: cwd)
|
|
@@ -815,21 +824,38 @@ class BlqConfig:
|
|
|
815
824
|
|
|
816
825
|
# Search current directory and parents
|
|
817
826
|
for p in [start_dir, *list(start_dir.parents)]:
|
|
818
|
-
|
|
819
|
-
if
|
|
820
|
-
return cls.load(
|
|
827
|
+
bird_path = p / BIRD_DIR
|
|
828
|
+
if bird_path.exists() and bird_path.is_dir():
|
|
829
|
+
return cls.load(bird_path)
|
|
830
|
+
|
|
831
|
+
# Auto-migrate from legacy .lq/ to .bird/
|
|
832
|
+
legacy_path = p / LEGACY_DIR
|
|
833
|
+
if legacy_path.exists() and legacy_path.is_dir():
|
|
834
|
+
try:
|
|
835
|
+
legacy_path.rename(bird_path)
|
|
836
|
+
logger.info(f"Migrated {legacy_path} → {bird_path}")
|
|
837
|
+
print(
|
|
838
|
+
f" Migrated {LEGACY_DIR}/ → {BIRD_DIR}/ "
|
|
839
|
+
f"(legacy directory renamed)",
|
|
840
|
+
file=sys.stderr,
|
|
841
|
+
)
|
|
842
|
+
return cls.load(bird_path)
|
|
843
|
+
except OSError as e:
|
|
844
|
+
logger.warning(f"Failed to migrate {legacy_path}: {e}")
|
|
845
|
+
# Fall back to loading from legacy path
|
|
846
|
+
return cls.load(legacy_path)
|
|
821
847
|
|
|
822
848
|
return None
|
|
823
849
|
|
|
824
850
|
@classmethod
|
|
825
851
|
def load(cls, lq_dir: Path) -> BlqConfig:
|
|
826
|
-
"""Load configuration from an existing .
|
|
852
|
+
"""Load configuration from an existing .bird directory.
|
|
827
853
|
|
|
828
854
|
Merges user-level defaults (from ~/.config/blq/config.toml) with
|
|
829
|
-
project-level config (from .
|
|
855
|
+
project-level config (from .bird/config.toml).
|
|
830
856
|
|
|
831
857
|
Args:
|
|
832
|
-
lq_dir: Path to the .
|
|
858
|
+
lq_dir: Path to the .bird directory
|
|
833
859
|
|
|
834
860
|
Returns:
|
|
835
861
|
BlqConfig loaded from config.toml (or defaults)
|
|
@@ -891,25 +917,25 @@ class BlqConfig:
|
|
|
891
917
|
|
|
892
918
|
Args:
|
|
893
919
|
start_dir: Directory to start searching from (default: cwd)
|
|
894
|
-
lq_dir: Explicit .
|
|
920
|
+
lq_dir: Explicit .bird directory to use (overrides discovery)
|
|
895
921
|
|
|
896
922
|
Returns:
|
|
897
923
|
BlqConfig if found
|
|
898
924
|
|
|
899
925
|
Raises:
|
|
900
|
-
SystemExit: If .
|
|
926
|
+
SystemExit: If .bird directory not found
|
|
901
927
|
"""
|
|
902
928
|
# If explicit lq_dir is provided, use it directly
|
|
903
929
|
if lq_dir is not None:
|
|
904
930
|
lq_path = Path(lq_dir).expanduser()
|
|
905
931
|
if not lq_path.exists():
|
|
906
|
-
print(f"Error: .
|
|
932
|
+
print(f"Error: .bird directory does not exist: {lq_path}", file=sys.stderr)
|
|
907
933
|
sys.exit(1)
|
|
908
934
|
return cls.load(lq_path)
|
|
909
935
|
|
|
910
936
|
config = cls.find(start_dir)
|
|
911
937
|
if config is None:
|
|
912
|
-
print("Error: .
|
|
938
|
+
print("Error: .bird not initialized. Run 'blq init' first.", file=sys.stderr)
|
|
913
939
|
sys.exit(1)
|
|
914
940
|
return config
|
|
915
941
|
|
|
@@ -1474,15 +1500,18 @@ def get_all_suppressed_fingerprints(config: BlqConfig) -> list[str]:
|
|
|
1474
1500
|
|
|
1475
1501
|
|
|
1476
1502
|
def get_lq_dir() -> Path | None:
|
|
1477
|
-
"""Find .lq directory in current or parent directories.
|
|
1503
|
+
"""Find .bird (or legacy .lq) directory in current or parent directories.
|
|
1478
1504
|
|
|
1479
|
-
Returns None if no
|
|
1505
|
+
Returns None if no directory is found.
|
|
1480
1506
|
"""
|
|
1481
1507
|
cwd = Path.cwd()
|
|
1482
1508
|
for p in [cwd, *list(cwd.parents)]:
|
|
1483
|
-
|
|
1484
|
-
if
|
|
1485
|
-
return
|
|
1509
|
+
bird_path = p / BIRD_DIR
|
|
1510
|
+
if bird_path.exists():
|
|
1511
|
+
return bird_path
|
|
1512
|
+
legacy_path = p / LEGACY_DIR
|
|
1513
|
+
if legacy_path.exists():
|
|
1514
|
+
return legacy_path
|
|
1486
1515
|
return None
|
|
1487
1516
|
|
|
1488
1517
|
|
|
@@ -1597,7 +1626,7 @@ class ConnectionFactory:
|
|
|
1597
1626
|
"""Create a properly initialized DuckDB connection.
|
|
1598
1627
|
|
|
1599
1628
|
Args:
|
|
1600
|
-
lq_dir: Path to .
|
|
1629
|
+
lq_dir: Path to .bird directory (for schema loading)
|
|
1601
1630
|
load_schema: Whether to load the schema (for stored data queries)
|
|
1602
1631
|
require_duck_hunt: If True, raise error if duck_hunt unavailable
|
|
1603
1632
|
install_duck_hunt: If True, attempt to install duck_hunt if missing
|
|
@@ -1705,7 +1734,7 @@ def get_connection(lq_dir: Path | None = None) -> duckdb.DuckDBPyConnection:
|
|
|
1705
1734
|
|
|
1706
1735
|
|
|
1707
1736
|
def get_lq_dir_from_args(args) -> Path | None:
|
|
1708
|
-
"""Get the .
|
|
1737
|
+
"""Get the .bird directory path from parsed arguments.
|
|
1709
1738
|
|
|
1710
1739
|
Handles the --lq-dir flag.
|
|
1711
1740
|
|
|
@@ -1713,7 +1742,7 @@ def get_lq_dir_from_args(args) -> Path | None:
|
|
|
1713
1742
|
args: Parsed arguments with optional 'lq_dir' attribute
|
|
1714
1743
|
|
|
1715
1744
|
Returns:
|
|
1716
|
-
Path to .
|
|
1745
|
+
Path to .bird directory if --lq-dir was specified, None otherwise
|
|
1717
1746
|
"""
|
|
1718
1747
|
lq_dir = getattr(args, "lq_dir", None)
|
|
1719
1748
|
if lq_dir:
|
|
@@ -1729,14 +1758,14 @@ def get_data_root(args) -> tuple[Path | None, bool]:
|
|
|
1729
1758
|
|
|
1730
1759
|
Returns:
|
|
1731
1760
|
Tuple of (path, is_raw_parquet):
|
|
1732
|
-
- path: Path to data root, or None for local .
|
|
1761
|
+
- path: Path to data root, or None for local .bird
|
|
1733
1762
|
- is_raw_parquet: True if path is a raw parquet directory (no schema.sql)
|
|
1734
1763
|
"""
|
|
1735
1764
|
# Check for --database flag first (explicit path)
|
|
1736
1765
|
database = getattr(args, "database", None)
|
|
1737
1766
|
if database:
|
|
1738
1767
|
db_path = Path(database).expanduser()
|
|
1739
|
-
# Raw parquet directory (no .
|
|
1768
|
+
# Raw parquet directory (no .bird structure)
|
|
1740
1769
|
return db_path, True
|
|
1741
1770
|
|
|
1742
1771
|
# Check for --global flag
|
|
@@ -1744,7 +1773,7 @@ def get_data_root(args) -> tuple[Path | None, bool]:
|
|
|
1744
1773
|
if use_global:
|
|
1745
1774
|
return GLOBAL_PROJECTS_PATH, True
|
|
1746
1775
|
|
|
1747
|
-
# Default: local .
|
|
1776
|
+
# Default: local .bird directory
|
|
1748
1777
|
return None, False
|
|
1749
1778
|
|
|
1750
1779
|
|
|
@@ -1761,12 +1790,12 @@ def get_store_for_args(args):
|
|
|
1761
1790
|
"""
|
|
1762
1791
|
from blq.storage import BlqStorage
|
|
1763
1792
|
|
|
1764
|
-
# Check for --lq-dir flag first (explicit .
|
|
1793
|
+
# Check for --lq-dir flag first (explicit .bird directory)
|
|
1765
1794
|
lq_dir = getattr(args, "lq_dir", None)
|
|
1766
1795
|
if lq_dir:
|
|
1767
1796
|
lq_path = Path(lq_dir).expanduser()
|
|
1768
1797
|
if not lq_path.exists():
|
|
1769
|
-
print(f"Error: .
|
|
1798
|
+
print(f"Error: .bird directory does not exist: {lq_path}", file=sys.stderr)
|
|
1770
1799
|
sys.exit(1)
|
|
1771
1800
|
return BlqStorage.open(lq_path)
|
|
1772
1801
|
|
|
@@ -1785,7 +1814,7 @@ def get_store_for_args(args):
|
|
|
1785
1814
|
)
|
|
1786
1815
|
return LogStore.from_parquet_root(data_root)
|
|
1787
1816
|
else:
|
|
1788
|
-
# Standard .
|
|
1817
|
+
# Standard .bird directory - use BlqStorage
|
|
1789
1818
|
# Check for --lq-dir override
|
|
1790
1819
|
lq_dir_override = getattr(args, "lq_dir", None)
|
|
1791
1820
|
if lq_dir_override:
|
|
@@ -569,7 +569,7 @@ def _execute_with_live_output(
|
|
|
569
569
|
store.cleanup_live_dir(attempt_id)
|
|
570
570
|
# Connection closed
|
|
571
571
|
|
|
572
|
-
# Save raw output to .
|
|
572
|
+
# Save raw output to .bird/raw/ if requested (filesystem only, no DB)
|
|
573
573
|
if keep_raw:
|
|
574
574
|
raw_file = lq_dir / RAW_DIR / f"{run_id:03d}.log"
|
|
575
575
|
raw_file.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -1350,7 +1350,7 @@ def cmd_run(args: argparse.Namespace) -> None:
|
|
|
1350
1350
|
def _resolve_prune_config(config: BlqConfig, user_config) -> dict:
|
|
1351
1351
|
"""Merge user config with project-level storage overrides.
|
|
1352
1352
|
|
|
1353
|
-
Project-level .
|
|
1353
|
+
Project-level .bird/config.toml [storage] keys override user defaults.
|
|
1354
1354
|
|
|
1355
1355
|
Returns:
|
|
1356
1356
|
Dict with auto_prune, prune_days, max_runs, max_size_mb, prune_interval_minutes
|
|
@@ -1383,7 +1383,7 @@ def _should_prune(lq_dir: Path, interval_minutes: int) -> bool:
|
|
|
1383
1383
|
"""Check if enough time has passed since last auto-prune.
|
|
1384
1384
|
|
|
1385
1385
|
Args:
|
|
1386
|
-
lq_dir: Path to .
|
|
1386
|
+
lq_dir: Path to .bird directory
|
|
1387
1387
|
interval_minutes: Minimum minutes between prunes
|
|
1388
1388
|
|
|
1389
1389
|
Returns:
|
|
@@ -1403,7 +1403,7 @@ def _should_prune(lq_dir: Path, interval_minutes: int) -> bool:
|
|
|
1403
1403
|
|
|
1404
1404
|
|
|
1405
1405
|
def _mark_pruned(lq_dir: Path) -> None:
|
|
1406
|
-
"""Write current timestamp to .
|
|
1406
|
+
"""Write current timestamp to .bird/.last_prune."""
|
|
1407
1407
|
stamp_file = lq_dir / ".last_prune"
|
|
1408
1408
|
try:
|
|
1409
1409
|
stamp_file.write_text(datetime.now().isoformat())
|