@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.
Files changed (265) hide show
  1. package/bundles/antigravity-plugin/agents/claude-md-curator.md +1 -1
  2. package/bundles/antigravity-plugin/agents/knowledge-transfer.md +17 -32
  3. package/bundles/antigravity-plugin/caddis_statusline.py +825 -0
  4. package/bundles/antigravity-plugin/claude-md/folder-agents.md.tmpl +21 -0
  5. package/bundles/antigravity-plugin/guard_agy.py +60 -9
  6. package/bundles/antigravity-plugin/plugin.json +1 -1
  7. package/bundles/antigravity-plugin/scripts/caddis_gate.py +524 -0
  8. package/bundles/antigravity-plugin/scripts/caddis_inventory.py +439 -0
  9. package/bundles/antigravity-plugin/scripts/caddis_migrate_dir.py +270 -0
  10. package/bundles/antigravity-plugin/scripts/caddis_spawn.py +300 -0
  11. package/bundles/antigravity-plugin/scripts/caddis_statusline.py +825 -0
  12. package/bundles/antigravity-plugin/scripts/caddis_tidy.py +366 -0
  13. package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +924 -0
  14. package/bundles/antigravity-plugin/scripts/claude-deepseek.ps1 +4 -0
  15. package/bundles/antigravity-plugin/scripts/claude-deepseek.sh +3 -0
  16. package/bundles/antigravity-plugin/scripts/claude-glm.ps1 +4 -0
  17. package/bundles/antigravity-plugin/scripts/claude-glm.sh +3 -0
  18. package/bundles/antigravity-plugin/scripts/claude-oss.ps1 +64 -0
  19. package/bundles/antigravity-plugin/scripts/claude-oss.sh +60 -0
  20. package/bundles/antigravity-plugin/scripts/claudster_config.py +121 -0
  21. package/bundles/antigravity-plugin/scripts/claudster_doctor.py +356 -0
  22. package/bundles/antigravity-plugin/scripts/claudster_init.py +400 -0
  23. package/bundles/antigravity-plugin/scripts/claudster_migrate_rules.py +300 -0
  24. package/bundles/antigravity-plugin/scripts/enforcement_inventory.py +261 -0
  25. package/bundles/antigravity-plugin/scripts/hook_log.py +156 -0
  26. package/bundles/antigravity-plugin/scripts/new-machine.ps1 +170 -0
  27. package/bundles/antigravity-plugin/scripts/oss_ask.py +98 -0
  28. package/bundles/antigravity-plugin/scripts/oss_model.py +174 -0
  29. package/bundles/antigravity-plugin/scripts/oss_review.py +718 -0
  30. package/bundles/antigravity-plugin/scripts/setup_project_ai.py +1432 -0
  31. package/bundles/antigravity-plugin/scripts/usage_review.py +1323 -0
  32. package/bundles/antigravity-plugin/session_end_agy.py +52 -8
  33. package/bundles/antigravity-plugin/skills/_registry.md +1 -0
  34. package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +44 -0
  35. package/bundles/antigravity-plugin/skills/code-review/SKILL.md +11 -0
  36. package/bundles/antigravity-plugin/skills/fastapi-dev/SKILL.md +1 -1
  37. package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +21 -0
  38. package/bundles/antigravity-plugin/skills/gate-review/SKILL.md +11 -0
  39. package/bundles/antigravity-plugin/skills/implement/SKILL.md +36 -0
  40. package/bundles/antigravity-plugin/skills/security-review/SKILL.md +9 -0
  41. package/bundles/antigravity-plugin/skills/ship/SKILL.md +1 -1
  42. package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +1 -1
  43. package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +1 -1
  44. package/bundles/antigravity-plugin/skills/statusline/SKILL.md +105 -0
  45. package/bundles/antigravity-plugin/skills/use-model/SKILL.md +15 -3
  46. package/bundles/antigravity-plugin/skills/validate-phase/SKILL.md +31 -0
  47. package/bundles/antigravity-plugin/warm_start_agy.py +117 -11
  48. package/bundles/antigravity-plugin-extras/plugin.json +1 -1
  49. package/bundles/antigravity-plugin-extras/skills/architecture-design/SKILL.md +1 -1
  50. package/bundles/antigravity-plugin-extras/skills/caching-patterns/SKILL.md +1 -1
  51. package/bundles/antigravity-plugin-extras/skills/webapp-development/SKILL.md +1 -1
  52. package/bundles/codex/.codex/config.toml.example +36 -0
  53. package/bundles/codex/.codex/skills/coding/api-design/SKILL.md +249 -0
  54. package/bundles/codex/.codex/skills/coding/backend-development/SKILL.md +305 -0
  55. package/bundles/codex/.codex/skills/coding/code-review/SKILL.md +140 -0
  56. package/bundles/codex/.codex/skills/coding/codebase-audit/SKILL.md +204 -0
  57. package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/SKILL.md +132 -0
  58. package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/scripts/perf_sweep.py +249 -0
  59. package/bundles/codex/.codex/skills/coding/error-handling/SKILL.md +260 -0
  60. package/bundles/codex/.codex/skills/coding/fastapi-dev/SKILL.md +300 -0
  61. package/bundles/codex/.codex/skills/coding/javascript-typescript/SKILL.md +142 -0
  62. package/bundles/codex/.codex/skills/coding/python/SKILL.md +388 -0
  63. package/bundles/codex/.codex/skills/coding/refactoring/SKILL.md +486 -0
  64. package/bundles/codex/.codex/skills/coding/security-review/SKILL.md +205 -0
  65. package/bundles/codex/.codex/skills/coding/sql/SKILL.md +321 -0
  66. package/bundles/codex/.codex/skills/data/database-design/SKILL.md +177 -0
  67. package/bundles/codex/.codex/skills/data/db-diagram/SKILL.md +148 -0
  68. package/bundles/codex/.codex/skills/data/db-diagram/scripts/sql_to_graph.py +1212 -0
  69. package/bundles/codex/.codex/skills/devops/ci-cd-pipeline/SKILL.md +315 -0
  70. package/bundles/codex/.codex/skills/devops/gh-cli/SKILL.md +195 -0
  71. package/bundles/codex/.codex/skills/devops/git-commit/SKILL.md +285 -0
  72. package/bundles/codex/.codex/skills/devops/using-git-worktrees/SKILL.md +217 -0
  73. package/bundles/codex/.codex/skills/devops/windows-deployment/SKILL.md +880 -0
  74. package/bundles/codex/.codex/skills/docs/code-documentation/SKILL.md +271 -0
  75. package/bundles/codex/.codex/skills/docs/explainer-doc/SKILL.md +97 -0
  76. package/bundles/codex/.codex/skills/docs/technical-writing/SKILL.md +286 -0
  77. package/bundles/codex/.codex/skills/docs/writing-plans/SKILL.md +387 -0
  78. package/bundles/codex/.codex/skills/frontend/css-architecture/SKILL.md +305 -0
  79. package/bundles/codex/.codex/skills/frontend/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
  80. package/bundles/codex/.codex/skills/frontend/frontend-design/SKILL.md +193 -0
  81. package/bundles/codex/.codex/skills/frontend/frontend-design/references/my-tech-stack.md +127 -0
  82. package/bundles/codex/.codex/skills/frontend/mockup/SKILL.md +242 -0
  83. package/bundles/codex/.codex/skills/frontend/react-best-practices/SKILL.md +269 -0
  84. package/bundles/codex/.codex/skills/frontend/react-dev/README.md +404 -0
  85. package/bundles/codex/.codex/skills/frontend/react-dev/SKILL.md +459 -0
  86. package/bundles/codex/.codex/skills/frontend/react-dev/examples/generic-components.md +579 -0
  87. package/bundles/codex/.codex/skills/frontend/react-dev/examples/server-components.md +579 -0
  88. package/bundles/codex/.codex/skills/frontend/react-dev/references/event-handlers.md +574 -0
  89. package/bundles/codex/.codex/skills/frontend/react-dev/references/hooks.md +456 -0
  90. package/bundles/codex/.codex/skills/frontend/react-dev/references/react-19-patterns.md +638 -0
  91. package/bundles/codex/.codex/skills/frontend/react-dev/references/react-router.md +1002 -0
  92. package/bundles/codex/.codex/skills/frontend/react-dev/references/tanstack-router.md +587 -0
  93. package/bundles/codex/.codex/skills/frontend/ui-review/SKILL.md +176 -0
  94. package/bundles/codex/.codex/skills/frontend/ui-review/references/framework-fixes.md +471 -0
  95. package/bundles/codex/.codex/skills/frontend/ui-review/references/visual-checklist.md +236 -0
  96. package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
  97. package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
  98. package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/SKILL.md +732 -0
  99. package/bundles/codex/.codex/skills/media/draw-io/SKILL.md +162 -0
  100. package/bundles/codex/.codex/skills/media/draw-io/references/aws-icons.md +677 -0
  101. package/bundles/codex/.codex/skills/media/draw-io/references/layout-guidelines.md +142 -0
  102. package/bundles/codex/.codex/skills/media/draw-io/references/troubleshooting.md +118 -0
  103. package/bundles/codex/.codex/skills/media/draw-io/references/workflows.md +103 -0
  104. package/bundles/codex/.codex/skills/media/draw-io/scripts/convert-drawio-to-png.sh +25 -0
  105. package/bundles/codex/.codex/skills/media/draw-io/scripts/find_aws_icon.py +79 -0
  106. package/bundles/codex/.codex/skills/media/mermaid-diagrams/SKILL.md +292 -0
  107. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
  108. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
  109. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/advanced-features.md +556 -0
  110. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/architecture-diagrams.md +192 -0
  111. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/c4-diagrams.md +410 -0
  112. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/class-diagrams.md +361 -0
  113. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/erd-diagrams.md +510 -0
  114. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/flowcharts.md +450 -0
  115. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/sequence-diagrams.md +394 -0
  116. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/troubleshooting.md +335 -0
  117. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/workflows.md +418 -0
  118. package/bundles/codex/.codex/skills/media/particle-art/SKILL.md +243 -0
  119. package/bundles/codex/.codex/skills/media/particle-art/references/canvas-utils.ts +171 -0
  120. package/bundles/codex/.codex/skills/media/particle-art/references/dot-field.template.tsx +203 -0
  121. package/bundles/codex/.codex/skills/media/particle-art/references/flow-field.template.tsx +263 -0
  122. package/bundles/codex/.codex/skills/media/particle-art/references/node-shape.template.tsx +261 -0
  123. package/bundles/codex/.codex/skills/media/particle-art/references/shape-sampler.ts +281 -0
  124. package/bundles/codex/.codex/skills/media/particle-art/references/stipple-morph.template.tsx +167 -0
  125. package/bundles/codex/.codex/skills/media/particle-art/references/stipple.template.tsx +175 -0
  126. package/bundles/codex/.codex/skills/media/particle-art/references/trail-ghost.template.tsx +266 -0
  127. package/bundles/codex/.codex/skills/media/particle-art/references/usage-examples.md +320 -0
  128. package/bundles/codex/.codex/skills/testing/playwright/API_REFERENCE.md +653 -0
  129. package/bundles/codex/.codex/skills/testing/playwright/SKILL.md +454 -0
  130. package/bundles/codex/.codex/skills/testing/playwright/lib/helpers.js +441 -0
  131. package/bundles/codex/.codex/skills/testing/playwright/package.json +26 -0
  132. package/bundles/codex/.codex/skills/testing/playwright/run.js +228 -0
  133. package/bundles/codex/.codex/skills/testing/tdd-workflow/SKILL.md +188 -0
  134. package/bundles/codex/.codex/skills/testing/test-strategy/SKILL.md +155 -0
  135. package/bundles/codex/.codex/skills/testing/webapp-testing/LICENSE.txt +202 -0
  136. package/bundles/codex/.codex/skills/testing/webapp-testing/SKILL.md +97 -0
  137. package/bundles/codex/.codex/skills/testing/webapp-testing/examples/console_logging.py +35 -0
  138. package/bundles/codex/.codex/skills/testing/webapp-testing/examples/element_discovery.py +40 -0
  139. package/bundles/codex/.codex/skills/testing/webapp-testing/examples/static_html_automation.py +33 -0
  140. package/bundles/codex/.codex/skills/testing/webapp-testing/scripts/with_server.py +106 -0
  141. package/bundles/codex/.codex/skills/workflow/advisory-hub/SKILL.md +227 -0
  142. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/context-template.md +214 -0
  143. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/hub-handbook.md +233 -0
  144. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/report-contract.md +94 -0
  145. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/succession.md +118 -0
  146. package/bundles/codex/.codex/skills/workflow/best-practices/SKILL.md +500 -0
  147. package/bundles/codex/.codex/skills/workflow/best-practices/agents/best-practices-referencer.md +263 -0
  148. package/bundles/codex/.codex/skills/workflow/best-practices/agents/codebase-context-builder.md +326 -0
  149. package/bundles/codex/.codex/skills/workflow/best-practices/agents/task-intent-analyzer.md +245 -0
  150. package/bundles/codex/.codex/skills/workflow/best-practices/references/anti-patterns.md +571 -0
  151. package/bundles/codex/.codex/skills/workflow/best-practices/references/before-after-examples.md +1114 -0
  152. package/bundles/codex/.codex/skills/workflow/best-practices/references/best-practices-guide.md +513 -0
  153. package/bundles/codex/.codex/skills/workflow/best-practices/references/common-workflows.md +692 -0
  154. package/bundles/codex/.codex/skills/workflow/best-practices/references/prompt-patterns.md +547 -0
  155. package/bundles/codex/.codex/skills/workflow/brainstorming/SKILL.md +57 -0
  156. package/bundles/codex/.codex/skills/workflow/context-curator/SKILL.md +157 -0
  157. package/bundles/codex/.codex/skills/workflow/golden-plan/SKILL.md +586 -0
  158. package/bundles/codex/.codex/skills/workflow/preflight/SKILL.md +440 -0
  159. package/bundles/codex/.codex/skills/workflow/skill-creator/LICENSE.txt +202 -0
  160. package/bundles/codex/.codex/skills/workflow/skill-creator/SKILL.md +491 -0
  161. package/bundles/codex/.codex/skills/workflow/skill-creator/agents/analyzer.md +274 -0
  162. package/bundles/codex/.codex/skills/workflow/skill-creator/agents/comparator.md +202 -0
  163. package/bundles/codex/.codex/skills/workflow/skill-creator/agents/grader.md +223 -0
  164. package/bundles/codex/.codex/skills/workflow/skill-creator/assets/eval_review.html +146 -0
  165. package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/generate_review.py +471 -0
  166. package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/viewer.html +1325 -0
  167. package/bundles/codex/.codex/skills/workflow/skill-creator/references/schemas.md +430 -0
  168. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/__init__.py +0 -0
  169. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/aggregate_benchmark.py +401 -0
  170. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/generate_report.py +326 -0
  171. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/improve_description.py +247 -0
  172. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/package_skill.py +136 -0
  173. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/quick_validate.py +103 -0
  174. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_eval.py +310 -0
  175. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_loop.py +328 -0
  176. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/utils.py +47 -0
  177. package/bundles/codex/AGENTS.md +146 -0
  178. package/bundles/manifest.json +4 -3
  179. package/dist/claude-deepseek.js +544 -0
  180. package/dist/claude-glm.js +544 -0
  181. package/dist/claude-oss.js +544 -0
  182. package/dist/cli.js +542 -90
  183. package/package.json +5 -2
  184. package/bundles/antigravity-plugin/statusline-command-agy.sh +0 -91
  185. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  186. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  187. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  188. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  189. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  190. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  191. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  192. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  193. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  194. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  195. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  196. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  197. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  198. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  199. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  200. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  201. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  202. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  203. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  204. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  205. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  206. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  207. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  208. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  209. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  210. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  211. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  212. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  213. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  214. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  215. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  216. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  217. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  218. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  219. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  220. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  221. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  222. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  223. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  224. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  225. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  226. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  227. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  228. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  229. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  230. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  231. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  232. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  233. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  234. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  235. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  236. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  237. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  238. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  239. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  240. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  241. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  242. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  243. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  244. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  245. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  246. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  247. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  248. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  249. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  250. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  251. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  252. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  253. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  254. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  255. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  256. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  257. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  258. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  259. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  260. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  261. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  262. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  263. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  264. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  265. 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())