@caddis/cli 0.2.6 → 0.4.0
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.
- package/bundles/antigravity-plugin/agents/claude-md-curator.md +1 -1
- package/bundles/antigravity-plugin/agents/knowledge-transfer.md +17 -32
- package/bundles/antigravity-plugin/caddis_statusline.py +825 -0
- package/bundles/antigravity-plugin/claude-md/folder-agents.md.tmpl +21 -0
- package/bundles/antigravity-plugin/guard_agy.py +60 -9
- package/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/scripts/caddis_gate.py +524 -0
- package/bundles/antigravity-plugin/scripts/caddis_inventory.py +439 -0
- package/bundles/antigravity-plugin/scripts/caddis_migrate_dir.py +270 -0
- package/bundles/antigravity-plugin/scripts/caddis_spawn.py +300 -0
- package/bundles/antigravity-plugin/scripts/caddis_statusline.py +825 -0
- package/bundles/antigravity-plugin/scripts/caddis_tidy.py +366 -0
- package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +924 -0
- package/bundles/antigravity-plugin/scripts/claude-deepseek.ps1 +4 -0
- package/bundles/antigravity-plugin/scripts/claude-deepseek.sh +3 -0
- package/bundles/antigravity-plugin/scripts/claude-glm.ps1 +4 -0
- package/bundles/antigravity-plugin/scripts/claude-glm.sh +3 -0
- package/bundles/antigravity-plugin/scripts/claude-oss.ps1 +64 -0
- package/bundles/antigravity-plugin/scripts/claude-oss.sh +60 -0
- package/bundles/antigravity-plugin/scripts/claudster_config.py +121 -0
- package/bundles/antigravity-plugin/scripts/claudster_doctor.py +356 -0
- package/bundles/antigravity-plugin/scripts/claudster_init.py +400 -0
- package/bundles/antigravity-plugin/scripts/claudster_migrate_rules.py +300 -0
- package/bundles/antigravity-plugin/scripts/enforcement_inventory.py +261 -0
- package/bundles/antigravity-plugin/scripts/hook_log.py +156 -0
- package/bundles/antigravity-plugin/scripts/new-machine.ps1 +170 -0
- package/bundles/antigravity-plugin/scripts/oss_ask.py +98 -0
- package/bundles/antigravity-plugin/scripts/oss_model.py +174 -0
- package/bundles/antigravity-plugin/scripts/oss_review.py +718 -0
- package/bundles/antigravity-plugin/scripts/setup_project_ai.py +1432 -0
- package/bundles/antigravity-plugin/scripts/usage_review.py +1323 -0
- package/bundles/antigravity-plugin/session_end_agy.py +52 -8
- package/bundles/antigravity-plugin/skills/_registry.md +1 -0
- package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +44 -0
- package/bundles/antigravity-plugin/skills/code-review/SKILL.md +11 -0
- package/bundles/antigravity-plugin/skills/fastapi-dev/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +21 -0
- package/bundles/antigravity-plugin/skills/gate-review/SKILL.md +11 -0
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +36 -0
- package/bundles/antigravity-plugin/skills/security-review/SKILL.md +9 -0
- package/bundles/antigravity-plugin/skills/ship/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/statusline/SKILL.md +105 -0
- package/bundles/antigravity-plugin/skills/use-model/SKILL.md +15 -3
- package/bundles/antigravity-plugin/skills/validate-phase/SKILL.md +31 -0
- package/bundles/antigravity-plugin/warm_start_agy.py +117 -11
- package/bundles/antigravity-plugin-extras/plugin.json +1 -1
- package/bundles/antigravity-plugin-extras/skills/architecture-design/SKILL.md +1 -1
- package/bundles/antigravity-plugin-extras/skills/caching-patterns/SKILL.md +1 -1
- package/bundles/antigravity-plugin-extras/skills/webapp-development/SKILL.md +1 -1
- package/bundles/codex/.codex/config.toml.example +36 -0
- package/bundles/codex/.codex/skills/coding/api-design/SKILL.md +249 -0
- package/bundles/codex/.codex/skills/coding/backend-development/SKILL.md +305 -0
- package/bundles/codex/.codex/skills/coding/code-review/SKILL.md +140 -0
- package/bundles/codex/.codex/skills/coding/codebase-audit/SKILL.md +204 -0
- package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/SKILL.md +132 -0
- package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/scripts/perf_sweep.py +249 -0
- package/bundles/codex/.codex/skills/coding/error-handling/SKILL.md +260 -0
- package/bundles/codex/.codex/skills/coding/fastapi-dev/SKILL.md +300 -0
- package/bundles/codex/.codex/skills/coding/javascript-typescript/SKILL.md +142 -0
- package/bundles/codex/.codex/skills/coding/python/SKILL.md +388 -0
- package/bundles/codex/.codex/skills/coding/refactoring/SKILL.md +486 -0
- package/bundles/codex/.codex/skills/coding/security-review/SKILL.md +205 -0
- package/bundles/codex/.codex/skills/coding/sql/SKILL.md +321 -0
- package/bundles/codex/.codex/skills/data/database-design/SKILL.md +177 -0
- package/bundles/codex/.codex/skills/data/db-diagram/SKILL.md +148 -0
- package/bundles/codex/.codex/skills/data/db-diagram/scripts/sql_to_graph.py +1212 -0
- package/bundles/codex/.codex/skills/devops/ci-cd-pipeline/SKILL.md +315 -0
- package/bundles/codex/.codex/skills/devops/gh-cli/SKILL.md +195 -0
- package/bundles/codex/.codex/skills/devops/git-commit/SKILL.md +285 -0
- package/bundles/codex/.codex/skills/devops/using-git-worktrees/SKILL.md +217 -0
- package/bundles/codex/.codex/skills/devops/windows-deployment/SKILL.md +880 -0
- package/bundles/codex/.codex/skills/docs/code-documentation/SKILL.md +271 -0
- package/bundles/codex/.codex/skills/docs/explainer-doc/SKILL.md +97 -0
- package/bundles/codex/.codex/skills/docs/technical-writing/SKILL.md +286 -0
- package/bundles/codex/.codex/skills/docs/writing-plans/SKILL.md +387 -0
- package/bundles/codex/.codex/skills/frontend/css-architecture/SKILL.md +305 -0
- package/bundles/codex/.codex/skills/frontend/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
- package/bundles/codex/.codex/skills/frontend/frontend-design/SKILL.md +193 -0
- package/bundles/codex/.codex/skills/frontend/frontend-design/references/my-tech-stack.md +127 -0
- package/bundles/codex/.codex/skills/frontend/mockup/SKILL.md +242 -0
- package/bundles/codex/.codex/skills/frontend/react-best-practices/SKILL.md +269 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/README.md +404 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/SKILL.md +459 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/examples/generic-components.md +579 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/examples/server-components.md +579 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/event-handlers.md +574 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/hooks.md +456 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/react-19-patterns.md +638 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/react-router.md +1002 -0
- package/bundles/codex/.codex/skills/frontend/react-dev/references/tanstack-router.md +587 -0
- package/bundles/codex/.codex/skills/frontend/ui-review/SKILL.md +176 -0
- package/bundles/codex/.codex/skills/frontend/ui-review/references/framework-fixes.md +471 -0
- package/bundles/codex/.codex/skills/frontend/ui-review/references/visual-checklist.md +236 -0
- package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
- package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
- package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/SKILL.md +732 -0
- package/bundles/codex/.codex/skills/media/draw-io/SKILL.md +162 -0
- package/bundles/codex/.codex/skills/media/draw-io/references/aws-icons.md +677 -0
- package/bundles/codex/.codex/skills/media/draw-io/references/layout-guidelines.md +142 -0
- package/bundles/codex/.codex/skills/media/draw-io/references/troubleshooting.md +118 -0
- package/bundles/codex/.codex/skills/media/draw-io/references/workflows.md +103 -0
- package/bundles/codex/.codex/skills/media/draw-io/scripts/convert-drawio-to-png.sh +25 -0
- package/bundles/codex/.codex/skills/media/draw-io/scripts/find_aws_icon.py +79 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/SKILL.md +292 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/advanced-features.md +556 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/architecture-diagrams.md +192 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/c4-diagrams.md +410 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/class-diagrams.md +361 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/erd-diagrams.md +510 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/flowcharts.md +450 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/sequence-diagrams.md +394 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/troubleshooting.md +335 -0
- package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/workflows.md +418 -0
- package/bundles/codex/.codex/skills/media/particle-art/SKILL.md +243 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/canvas-utils.ts +171 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/dot-field.template.tsx +203 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/flow-field.template.tsx +263 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/node-shape.template.tsx +261 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/shape-sampler.ts +281 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/stipple-morph.template.tsx +167 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/stipple.template.tsx +175 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/trail-ghost.template.tsx +266 -0
- package/bundles/codex/.codex/skills/media/particle-art/references/usage-examples.md +320 -0
- package/bundles/codex/.codex/skills/testing/playwright/API_REFERENCE.md +653 -0
- package/bundles/codex/.codex/skills/testing/playwright/SKILL.md +454 -0
- package/bundles/codex/.codex/skills/testing/playwright/lib/helpers.js +441 -0
- package/bundles/codex/.codex/skills/testing/playwright/package.json +26 -0
- package/bundles/codex/.codex/skills/testing/playwright/run.js +228 -0
- package/bundles/codex/.codex/skills/testing/tdd-workflow/SKILL.md +188 -0
- package/bundles/codex/.codex/skills/testing/test-strategy/SKILL.md +155 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/LICENSE.txt +202 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/SKILL.md +97 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/examples/console_logging.py +35 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/examples/element_discovery.py +40 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/examples/static_html_automation.py +33 -0
- package/bundles/codex/.codex/skills/testing/webapp-testing/scripts/with_server.py +106 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/SKILL.md +227 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/context-template.md +214 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/hub-handbook.md +233 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/report-contract.md +94 -0
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/succession.md +118 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/SKILL.md +500 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/agents/best-practices-referencer.md +263 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/agents/codebase-context-builder.md +326 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/agents/task-intent-analyzer.md +245 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/anti-patterns.md +571 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/before-after-examples.md +1114 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/best-practices-guide.md +513 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/common-workflows.md +692 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/references/prompt-patterns.md +547 -0
- package/bundles/codex/.codex/skills/workflow/brainstorming/SKILL.md +57 -0
- package/bundles/codex/.codex/skills/workflow/context-curator/SKILL.md +157 -0
- package/bundles/codex/.codex/skills/workflow/golden-plan/SKILL.md +586 -0
- package/bundles/codex/.codex/skills/workflow/preflight/SKILL.md +440 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/LICENSE.txt +202 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/SKILL.md +491 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/agents/analyzer.md +274 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/agents/comparator.md +202 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/agents/grader.md +223 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/assets/eval_review.html +146 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/generate_review.py +471 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/viewer.html +1325 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/references/schemas.md +430 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/__init__.py +0 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/generate_report.py +326 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/improve_description.py +247 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/package_skill.py +136 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/quick_validate.py +103 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_eval.py +310 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_loop.py +328 -0
- package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/utils.py +47 -0
- package/bundles/codex/AGENTS.md +146 -0
- package/bundles/manifest.json +4 -3
- package/dist/claude-deepseek.js +544 -0
- package/dist/claude-glm.js +544 -0
- package/dist/claude-oss.js +544 -0
- package/dist/cli.js +542 -90
- package/package.json +5 -2
- package/bundles/antigravity-plugin/statusline-command-agy.sh +0 -91
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
- package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""caddis_inventory — enumerate what EXISTS in a repo, so a handover stops being a memory test.
|
|
3
|
+
|
|
4
|
+
WHY
|
|
5
|
+
---
|
|
6
|
+
A succession prompt used to be composed from what the outgoing session remembered to mention.
|
|
7
|
+
Anything it forgot, the incoming session never learned — and the incoming session cannot know what
|
|
8
|
+
it was not told. Bringing one Hub to a usable state took **nine** corrective round trips, and the
|
|
9
|
+
user caught six of the nine (`.caddis/parking-lot/004-handover-is-recalled-not-generated.md`).
|
|
10
|
+
|
|
11
|
+
Look at what the user caught, because the pattern is the whole argument:
|
|
12
|
+
|
|
13
|
+
"the handover listed no reports, documents, KB notes or scripts"
|
|
14
|
+
"planned future work is absent"
|
|
15
|
+
"which prompt exists — the legacy one or the contract-shaped one?"
|
|
16
|
+
|
|
17
|
+
None of those are judgement calls. Every one is a directory listing. They were missed because the
|
|
18
|
+
agent was recalling *what it did* rather than enumerating *what exists*, and those are different
|
|
19
|
+
sets. A generator cannot forget the report it never wrote.
|
|
20
|
+
|
|
21
|
+
WHAT THIS IS NOT
|
|
22
|
+
----------------
|
|
23
|
+
This does not write the handover. Judgement — what matters, what to do next, what nearly went
|
|
24
|
+
wrong — is the outgoing session's job and cannot be derived from disk. This produces the half that
|
|
25
|
+
can be, so the human-written half is all judgement and no clerical work.
|
|
26
|
+
|
|
27
|
+
STALENESS IS MEASURED IN COMMITS, NOT MTIMES
|
|
28
|
+
--------------------------------------------
|
|
29
|
+
A git checkout stamps every file with the checkout time, so mtimes say nothing about whether a
|
|
30
|
+
generated report predates the feature it should describe. Last-commit time does. That exact failure
|
|
31
|
+
is item 8 of the nine: reports committed before a feature was added and never rebuilt.
|
|
32
|
+
|
|
33
|
+
Usage:
|
|
34
|
+
python scripts/caddis_inventory.py # markdown to stdout
|
|
35
|
+
python scripts/caddis_inventory.py --format json # machine-readable
|
|
36
|
+
python scripts/caddis_inventory.py --with-tests # also RUN the suite (never quote a
|
|
37
|
+
# remembered test count — one handover
|
|
38
|
+
# claimed 20 when there were 19)
|
|
39
|
+
"""
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
import argparse
|
|
43
|
+
import json
|
|
44
|
+
import re
|
|
45
|
+
import subprocess
|
|
46
|
+
import sys
|
|
47
|
+
from dataclasses import dataclass, field
|
|
48
|
+
from pathlib import Path
|
|
49
|
+
|
|
50
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
51
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
52
|
+
|
|
53
|
+
ART = ".caddis"
|
|
54
|
+
|
|
55
|
+
# Artefact kinds worth enumerating, and what a reader needs from each. Order matters: it is the
|
|
56
|
+
# order a reader wants them in, not alphabetical.
|
|
57
|
+
PLAN_DIRS = ("plans", "prd", "prompts", "handoffs", "agent-docs")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _run(args: list[str], cwd: Path) -> str:
|
|
61
|
+
try:
|
|
62
|
+
r = subprocess.run(args, cwd=str(cwd), capture_output=True, text=True,
|
|
63
|
+
encoding="utf-8", errors="replace", timeout=30)
|
|
64
|
+
return r.stdout.strip() if r.returncode == 0 else ""
|
|
65
|
+
except Exception:
|
|
66
|
+
return ""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def frontmatter(path: Path) -> dict[str, str]:
|
|
70
|
+
try:
|
|
71
|
+
text = path.read_text(encoding="utf-8", errors="ignore").lstrip("")
|
|
72
|
+
except OSError:
|
|
73
|
+
return {}
|
|
74
|
+
if not text.startswith("---"):
|
|
75
|
+
return {}
|
|
76
|
+
end = text.find("\n---", 3)
|
|
77
|
+
out: dict[str, str] = {}
|
|
78
|
+
for line in text[3:end if end > 0 else 800].splitlines():
|
|
79
|
+
if ":" in line and not line.startswith((" ", "\t")):
|
|
80
|
+
k, _, v = line.partition(":")
|
|
81
|
+
out[k.strip()] = v.strip()
|
|
82
|
+
return out
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def title_of(path: Path) -> str:
|
|
86
|
+
"""First markdown H1, else the filename. What a reader scans for."""
|
|
87
|
+
try:
|
|
88
|
+
for line in path.read_text(encoding="utf-8", errors="ignore").splitlines():
|
|
89
|
+
if line.startswith("# "):
|
|
90
|
+
return line[2:].strip()
|
|
91
|
+
except OSError:
|
|
92
|
+
pass
|
|
93
|
+
return path.stem
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass
|
|
97
|
+
class Inventory:
|
|
98
|
+
repo: str = ""
|
|
99
|
+
branch: str = ""
|
|
100
|
+
uncommitted: int = 0
|
|
101
|
+
unpushed: int = 0
|
|
102
|
+
artifacts: dict[str, list[dict]] = field(default_factory=dict)
|
|
103
|
+
parking_lot: list[dict] = field(default_factory=list)
|
|
104
|
+
kb: list[dict] = field(default_factory=list)
|
|
105
|
+
comms_open: list[dict] = field(default_factory=list)
|
|
106
|
+
scripts: list[dict] = field(default_factory=list)
|
|
107
|
+
stale_artifacts: list[dict] = field(default_factory=list)
|
|
108
|
+
environment_map: str = "missing"
|
|
109
|
+
tests: str = "not measured — run the suite, never quote a remembered number"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def scan_artifacts(root: Path) -> dict[str, list[dict]]:
|
|
113
|
+
out: dict[str, list[dict]] = {}
|
|
114
|
+
for kind in PLAN_DIRS:
|
|
115
|
+
d = root / ART / kind
|
|
116
|
+
if not d.is_dir():
|
|
117
|
+
continue
|
|
118
|
+
rows = []
|
|
119
|
+
for f in sorted(d.glob("*.md")):
|
|
120
|
+
if f.name.lower() == "readme.md":
|
|
121
|
+
continue
|
|
122
|
+
fm = frontmatter(f)
|
|
123
|
+
rows.append({"file": f"{ART}/{kind}/{f.name}",
|
|
124
|
+
"title": title_of(f),
|
|
125
|
+
"status": fm.get("status", "(none)")})
|
|
126
|
+
done = len(list((d / "done").glob("*.md"))) if (d / "done").is_dir() else 0
|
|
127
|
+
if rows or done:
|
|
128
|
+
out[kind] = rows
|
|
129
|
+
if done:
|
|
130
|
+
out[kind].append({"file": f"{ART}/{kind}/done/", "title": f"{done} finished",
|
|
131
|
+
"status": "archived"})
|
|
132
|
+
return out
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def scan_parking_lot(root: Path) -> list[dict]:
|
|
136
|
+
"""The backlog. Listed separately from plans because a reader's question is different:
|
|
137
|
+
plans ask "what is running?", the parking lot asks "what did we agree to do and have not?"."""
|
|
138
|
+
d = root / ART / "parking-lot"
|
|
139
|
+
if not d.is_dir():
|
|
140
|
+
return []
|
|
141
|
+
rows = []
|
|
142
|
+
for f in sorted(d.glob("*.md")):
|
|
143
|
+
if f.name.lower() == "readme.md":
|
|
144
|
+
continue
|
|
145
|
+
fm = frontmatter(f)
|
|
146
|
+
rows.append({"file": f.name, "title": title_of(f),
|
|
147
|
+
"status": fm.get("status", "(none)"),
|
|
148
|
+
"severity": fm.get("severity", ""),
|
|
149
|
+
"future": fm.get("future", "")})
|
|
150
|
+
# committed work first, then by severity — the order a reader needs, not the filesystem's
|
|
151
|
+
order = {"high": 0, "medium": 1, "low": 2, "": 3}
|
|
152
|
+
rows.sort(key=lambda r: (r["future"].lower() != "yes", order.get(r["severity"].lower(), 3)))
|
|
153
|
+
return rows
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def scan_kb(root: Path) -> list[dict]:
|
|
157
|
+
d = root / ART / "kb"
|
|
158
|
+
if not d.is_dir():
|
|
159
|
+
return []
|
|
160
|
+
return [{"file": f"{ART}/kb/{f.name}", "title": title_of(f)}
|
|
161
|
+
for f in sorted(d.glob("*.md")) if f.name != "DOC-MAP.md"]
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def environment_map_state(root: Path) -> str:
|
|
165
|
+
"""`missing`, `empty` or `filled` — surfaced because an absent environment map is invisible.
|
|
166
|
+
|
|
167
|
+
Every other gap in a handover shows up as a section with nothing under it. This one shows up as
|
|
168
|
+
nothing at all, which reads exactly like "there was nothing to say". One session searched the
|
|
169
|
+
filesystem for a repository that lived in Gitea while the project's own docs cited a file inside
|
|
170
|
+
it by path — the fact existed, it just had no shelf.
|
|
171
|
+
"""
|
|
172
|
+
f = root / ART / "kb" / "environment-map.md"
|
|
173
|
+
if not f.is_file():
|
|
174
|
+
return "missing"
|
|
175
|
+
try:
|
|
176
|
+
text = f.read_text(encoding="utf-8", errors="ignore")
|
|
177
|
+
except OSError:
|
|
178
|
+
return "missing"
|
|
179
|
+
# The scaffolded template is all headings and "(none recorded yet)" placeholders. A file that
|
|
180
|
+
# still carries every placeholder has never been filled in, and saying "present" would be a lie
|
|
181
|
+
# of exactly the kind this whole item is about.
|
|
182
|
+
return "empty" if "_(none recorded yet)_" in text and text.count("|") < 60 else "filled"
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def scan_comms(root: Path) -> list[dict]:
|
|
186
|
+
"""Rows in the comms register that are not yet ACTIONED or DROPPED — an ask nobody is chasing
|
|
187
|
+
is indistinguishable from a forgotten one, which is the whole reason that register exists."""
|
|
188
|
+
reg = root / ART / "comms" / "register.md"
|
|
189
|
+
if not reg.is_file():
|
|
190
|
+
return []
|
|
191
|
+
out = []
|
|
192
|
+
for line in reg.read_text(encoding="utf-8", errors="ignore").splitlines():
|
|
193
|
+
if not line.startswith("|") or line.startswith("|---") or "_(none yet)_" in line:
|
|
194
|
+
continue
|
|
195
|
+
cells = [c.strip() for c in line.strip("|").split("|")]
|
|
196
|
+
if len(cells) < 4 or cells[0].lower() in ("raised", "status"):
|
|
197
|
+
continue
|
|
198
|
+
status = cells[3].strip("`").upper()
|
|
199
|
+
if status in ("DRAFT", "SENT", "ANSWERED"):
|
|
200
|
+
out.append({"raised": cells[0], "audience": cells[1],
|
|
201
|
+
"subject": cells[2], "status": status})
|
|
202
|
+
return out
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def scan_scripts(root: Path) -> list[dict]:
|
|
206
|
+
"""Every script and the first line of its docstring. A handover that omits these makes the
|
|
207
|
+
next session re-discover the tooling it already owns."""
|
|
208
|
+
d = root / "scripts"
|
|
209
|
+
if not d.is_dir():
|
|
210
|
+
return []
|
|
211
|
+
out = []
|
|
212
|
+
for f in sorted(d.glob("*.py")):
|
|
213
|
+
first = ""
|
|
214
|
+
try:
|
|
215
|
+
text = f.read_text(encoding="utf-8", errors="ignore")
|
|
216
|
+
m = re.search(r'^\s*"""(.+?)$', text, re.M)
|
|
217
|
+
if m:
|
|
218
|
+
first = m.group(1).strip().rstrip('"')
|
|
219
|
+
except OSError:
|
|
220
|
+
pass
|
|
221
|
+
out.append({"file": f"scripts/{f.name}", "purpose": first})
|
|
222
|
+
return out
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# A path literal, not a bare filename. Requiring a directory separator is what stops a script that
|
|
226
|
+
# merely MENTIONS "README.md" in a docstring from being reported as that file's generator — the
|
|
227
|
+
# first version of this did exactly that, and a check with obvious false positives gets switched off
|
|
228
|
+
# before it ever catches a real one.
|
|
229
|
+
_OUTPUT_LITERAL = re.compile(r'["\']((?:[\w.-]+/)+[\w.-]+\.(?:html|json|csv|svg|png|md))["\']')
|
|
230
|
+
# Names that are always somebody else's file, never a generated artefact.
|
|
231
|
+
_NEVER_GENERATED = {"README.md", "AGENTS.md", "CLAUDE.md", "package.json", "pyproject.toml"}
|
|
232
|
+
# A generator often builds its output path from parts (`_HERE.parent / ".caddis" / "page.html"`),
|
|
233
|
+
# so the literal in the source is a bare filename. Accept that shape too, but ONLY for artefact
|
|
234
|
+
# extensions and ONLY when the file really sits in the artefact dir — a bare `.md` literal is
|
|
235
|
+
# almost always prose, which is how the README false positive got in.
|
|
236
|
+
_BARE_ARTIFACT = re.compile(r'["\']([\w.-]+\.(?:html|json|csv|svg|png))["\']')
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def stale_artifacts(root: Path) -> list[dict]:
|
|
240
|
+
"""Generated files whose last commit PREDATES their generator's last commit.
|
|
241
|
+
|
|
242
|
+
Pairing needs no new convention to maintain: a generator names the file it writes, so grepping
|
|
243
|
+
each script for a path literal that actually exists on disk finds the pair. A manifest would be
|
|
244
|
+
more precise and would rot the first time nobody updated it.
|
|
245
|
+
|
|
246
|
+
Uses git commit times, never mtimes — see the module docstring.
|
|
247
|
+
"""
|
|
248
|
+
d = root / "scripts"
|
|
249
|
+
if not d.is_dir() or not (root / ".git").exists():
|
|
250
|
+
return []
|
|
251
|
+
out = []
|
|
252
|
+
for script in sorted(d.glob("*.py")):
|
|
253
|
+
try:
|
|
254
|
+
text = script.read_text(encoding="utf-8", errors="ignore")
|
|
255
|
+
except OSError:
|
|
256
|
+
continue
|
|
257
|
+
candidates = set(_OUTPUT_LITERAL.findall(text))
|
|
258
|
+
candidates |= {f"{ART}/{n}" for n in _BARE_ARTIFACT.findall(text)
|
|
259
|
+
if (root / ART / n).is_file()}
|
|
260
|
+
for m in sorted(candidates):
|
|
261
|
+
if Path(m).name in _NEVER_GENERATED:
|
|
262
|
+
continue
|
|
263
|
+
target = root / m
|
|
264
|
+
if not target.is_file():
|
|
265
|
+
continue
|
|
266
|
+
t_art = _run(["git", "log", "-1", "--format=%ct", "--", m], root)
|
|
267
|
+
t_gen = _run(["git", "log", "-1", "--format=%ct", "--", f"scripts/{script.name}"], root)
|
|
268
|
+
if not t_art or not t_gen:
|
|
269
|
+
continue
|
|
270
|
+
if int(t_art) < int(t_gen):
|
|
271
|
+
out.append({"artifact": m, "generator": f"scripts/{script.name}",
|
|
272
|
+
"behind_seconds": int(t_gen) - int(t_art)})
|
|
273
|
+
return out
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def collect(root: Path, with_tests: bool = False) -> Inventory:
|
|
277
|
+
inv = Inventory(repo=root.name)
|
|
278
|
+
inv.branch = _run(["git", "rev-parse", "--abbrev-ref", "HEAD"], root)
|
|
279
|
+
inv.uncommitted = len([l for l in _run(["git", "status", "--short"], root).splitlines() if l])
|
|
280
|
+
upstream = _run(["git", "rev-parse", "--abbrev-ref", "@{upstream}"], root)
|
|
281
|
+
if upstream:
|
|
282
|
+
inv.unpushed = len(_run(["git", "log", "--oneline", f"{upstream}..HEAD"], root).splitlines())
|
|
283
|
+
inv.artifacts = scan_artifacts(root)
|
|
284
|
+
inv.parking_lot = scan_parking_lot(root)
|
|
285
|
+
inv.kb = scan_kb(root)
|
|
286
|
+
inv.comms_open = scan_comms(root)
|
|
287
|
+
inv.scripts = scan_scripts(root)
|
|
288
|
+
inv.stale_artifacts = stale_artifacts(root)
|
|
289
|
+
inv.environment_map = environment_map_state(root)
|
|
290
|
+
if with_tests:
|
|
291
|
+
# Run it. A handover once claimed 20 tests when there were 19, and the incoming Hub found
|
|
292
|
+
# the discrepancy before anyone else did.
|
|
293
|
+
summary, shown = _run_tests(_test_command(root), root)
|
|
294
|
+
# Name the command. "932 passed" means nothing on its own — a reader who cannot see
|
|
295
|
+
# the command cannot tell a scoped run from a whole-tree one, which is exactly the
|
|
296
|
+
# ambiguity that produced this defect.
|
|
297
|
+
inv.tests = f"{summary} _(`{shown}`)_"
|
|
298
|
+
return inv
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
# Generated/vendored trees hold COPIES of the harness. They have no node_modules and no
|
|
303
|
+
# import path, so collecting them is never right — it only produces collection errors that
|
|
304
|
+
# mask the real result. Excluded by default; `[handover] test_cmd` overrides everything.
|
|
305
|
+
_GENERATED_TREES = ("vscode-extensions", "dist", "node_modules", ".venv")
|
|
306
|
+
|
|
307
|
+
# The suite is the one thing here that is not a directory listing, so it gets its own
|
|
308
|
+
# runner rather than `_run`. Three reasons `_run` is wrong for it:
|
|
309
|
+
# * it returns "" on a non-zero exit — and pytest exits non-zero when tests FAIL, so a
|
|
310
|
+
# genuinely red suite became "did not report a summary", indistinguishable from a
|
|
311
|
+
# broken invocation. A red suite MUST report "3 failed".
|
|
312
|
+
# * its 30s timeout is shorter than a real suite. This repo's takes 112s, so
|
|
313
|
+
# `--with-tests` could never have produced a number here whatever else was fixed.
|
|
314
|
+
# * it discards stderr, where pytest writes collection errors.
|
|
315
|
+
def _run_tests(cmd: list[str], cwd: Path, timeout: int = 900) -> tuple[str, str]:
|
|
316
|
+
"""Return ``(summary_line, command_string)``. Never raises."""
|
|
317
|
+
shown = " ".join(cmd[1:]) if cmd and cmd[0] == sys.executable else " ".join(cmd)
|
|
318
|
+
shown = shown.replace("-m pytest", "pytest", 1)
|
|
319
|
+
try:
|
|
320
|
+
r = subprocess.run(cmd, cwd=str(cwd), capture_output=True, text=True,
|
|
321
|
+
encoding="utf-8", errors="replace", timeout=timeout)
|
|
322
|
+
except subprocess.TimeoutExpired:
|
|
323
|
+
return (f"suite exceeded {timeout}s — not run to completion", shown)
|
|
324
|
+
except Exception as exc:
|
|
325
|
+
return (f"could not run the suite ({type(exc).__name__})", shown)
|
|
326
|
+
|
|
327
|
+
blob = (r.stdout or "") + chr(10) + (r.stderr or "")
|
|
328
|
+
# pytest's summary line is the last one naming passed/failed/error.
|
|
329
|
+
tail = [l.strip() for l in blob.splitlines()
|
|
330
|
+
if ("passed" in l or "failed" in l or "error" in l.lower()) and "==" not in l[:2]]
|
|
331
|
+
if tail:
|
|
332
|
+
return (tail[-1], shown)
|
|
333
|
+
return (f"suite did not report a summary (exit {r.returncode}) — investigate", shown)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _test_command(root: Path) -> list[str]:
|
|
337
|
+
"""The repo's test command.
|
|
338
|
+
|
|
339
|
+
A repo's test command is a PROJECT FACT, and this used to guess it. Bare `pytest` is a
|
|
340
|
+
guess that is right in a single-package repo and wrong in any repo carrying a vendored
|
|
341
|
+
or generated tree — which describes caddis itself and every consumer that vendors
|
|
342
|
+
anything. Set `[handover] test_cmd` in `.caddis/config.toml` to state it.
|
|
343
|
+
"""
|
|
344
|
+
# In the SHIPPED bundle this file and claudster_config.py are co-located under
|
|
345
|
+
# scripts/. In the source repo they are not: this lives in scripts/, that one in
|
|
346
|
+
# claude-harness/scripts/. Try both, or the config is silently never read — which is
|
|
347
|
+
# how the first version of this fix looked like it worked and did not.
|
|
348
|
+
here = Path(__file__).resolve().parent
|
|
349
|
+
configured = ""
|
|
350
|
+
for cand in (here, here.parent / "claude-harness" / "scripts"):
|
|
351
|
+
try:
|
|
352
|
+
if str(cand) not in sys.path:
|
|
353
|
+
sys.path.insert(0, str(cand))
|
|
354
|
+
import claudster_config as _cc # noqa: E402
|
|
355
|
+
configured = _cc.get_str(_cc.load_config(root, "handover"), "test_cmd", "")
|
|
356
|
+
break
|
|
357
|
+
except Exception:
|
|
358
|
+
continue
|
|
359
|
+
if configured:
|
|
360
|
+
import shlex
|
|
361
|
+
return shlex.split(configured)
|
|
362
|
+
cmd = [sys.executable, "-m", "pytest", "-q", "--tb=no"]
|
|
363
|
+
for name in _GENERATED_TREES:
|
|
364
|
+
if (root / name).exists():
|
|
365
|
+
cmd += ["--ignore", name]
|
|
366
|
+
return cmd
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def _table(rows: list[dict], cols: list[tuple[str, str]]) -> list[str]:
|
|
370
|
+
head = "| " + " | ".join(c[0] for c in cols) + " |"
|
|
371
|
+
sep = "|" + "|".join("---" for _ in cols) + "|"
|
|
372
|
+
body = ["| " + " | ".join(str(r.get(c[1], "") or "") for c in cols) + " |" for r in rows]
|
|
373
|
+
return [head, sep, *body, ""]
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def render_md(inv: Inventory) -> str:
|
|
377
|
+
L: list[str] = [
|
|
378
|
+
f"# Repository inventory — {inv.repo}", "",
|
|
379
|
+
"> Generated by `scripts/caddis_inventory.py`. **Do not hand-edit.** Everything here is a",
|
|
380
|
+
"> directory listing, not a judgement — regenerate it rather than correcting it. The",
|
|
381
|
+
"> judgement half of a handover (what matters, what nearly went wrong, what to do next) is",
|
|
382
|
+
"> written by a human or an agent and belongs above this section, not inside it.", "",
|
|
383
|
+
f"**Branch** `{inv.branch}` · **uncommitted** {inv.uncommitted} file(s) · "
|
|
384
|
+
f"**unpushed** {inv.unpushed} commit(s)", "",
|
|
385
|
+
f"**Tests:** {inv.tests}", "",
|
|
386
|
+
]
|
|
387
|
+
if inv.environment_map != "filled":
|
|
388
|
+
why = ("does not exist" if inv.environment_map == "missing"
|
|
389
|
+
else "exists but has never been filled in")
|
|
390
|
+
L += [f"> **Environment map {why}.** Hosts, which login actually works, where other",
|
|
391
|
+
"> repositories really live — none of it is written down, so the next session starts",
|
|
392
|
+
"> from zero and asks you again. Write what you know to",
|
|
393
|
+
f"> `{ART}/kb/environment-map.md` before handing over.", ""]
|
|
394
|
+
if inv.stale_artifacts:
|
|
395
|
+
L += ["## ⚠ Generated artefacts older than their generator", "",
|
|
396
|
+
"Each of these was committed BEFORE the script that builds it last changed, so it may",
|
|
397
|
+
"describe a state that no longer exists. Rebuild before quoting any of them.", ""]
|
|
398
|
+
L += _table(inv.stale_artifacts, [("Artefact", "artifact"), ("Built by", "generator")])
|
|
399
|
+
for kind, rows in inv.artifacts.items():
|
|
400
|
+
if not rows:
|
|
401
|
+
continue
|
|
402
|
+
L += [f"## {kind}", ""] + _table(rows, [("File", "file"), ("Title", "title"),
|
|
403
|
+
("Status", "status")])
|
|
404
|
+
if inv.parking_lot:
|
|
405
|
+
L += ["## Parking lot — the backlog", "",
|
|
406
|
+
"Committed work (`future: yes`) first, then by severity.", ""]
|
|
407
|
+
L += _table(inv.parking_lot, [("Item", "file"), ("Severity", "severity"),
|
|
408
|
+
("Future", "future"), ("Status", "status")])
|
|
409
|
+
if inv.kb:
|
|
410
|
+
L += ["## KB notes", ""] + _table(inv.kb, [("File", "file"), ("Title", "title")])
|
|
411
|
+
if inv.comms_open:
|
|
412
|
+
L += ["## Outbound comms still open", "",
|
|
413
|
+
"Anything not yet ACTIONED or DROPPED. An unanswered ask looks exactly like a",
|
|
414
|
+
"forgotten one unless something tracks it.", ""]
|
|
415
|
+
L += _table(inv.comms_open, [("Raised", "raised"), ("Audience", "audience"),
|
|
416
|
+
("Subject", "subject"), ("Status", "status")])
|
|
417
|
+
if inv.scripts:
|
|
418
|
+
L += ["## Scripts", ""] + _table(inv.scripts, [("Script", "file"), ("Purpose", "purpose")])
|
|
419
|
+
return "\n".join(L) + "\n"
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def main(argv: list[str] | None = None) -> int:
|
|
423
|
+
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
424
|
+
ap.add_argument("--repo-root", default=".")
|
|
425
|
+
ap.add_argument("--format", choices=("md", "json"), default="md")
|
|
426
|
+
ap.add_argument("--with-tests", action="store_true",
|
|
427
|
+
help="RUN the suite and report its real result instead of a placeholder")
|
|
428
|
+
a = ap.parse_args(argv)
|
|
429
|
+
root = Path(a.repo_root).resolve()
|
|
430
|
+
inv = collect(root, with_tests=a.with_tests)
|
|
431
|
+
if a.format == "json":
|
|
432
|
+
print(json.dumps(inv.__dict__, indent=2))
|
|
433
|
+
else:
|
|
434
|
+
print(render_md(inv), end="")
|
|
435
|
+
return 0
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
if __name__ == "__main__":
|
|
439
|
+
raise SystemExit(main())
|