@caddis/cli 0.3.0 → 0.4.1

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 (244) hide show
  1. package/bundles/antigravity-plugin/agents/knowledge-transfer.md +17 -32
  2. package/bundles/antigravity-plugin/caddis_statusline.py +25 -3
  3. package/bundles/antigravity-plugin/guard_agy.py +41 -9
  4. package/bundles/antigravity-plugin/plugin.json +1 -1
  5. package/bundles/antigravity-plugin/scripts/caddis_inventory.py +73 -3
  6. package/bundles/antigravity-plugin/scripts/caddis_statusline.py +25 -3
  7. package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +1 -1
  8. package/bundles/antigravity-plugin/scripts/claudster_config.py +0 -5
  9. package/bundles/antigravity-plugin/scripts/hook_log.py +1 -1
  10. package/bundles/antigravity-plugin/scripts/new-machine.ps1 +170 -0
  11. package/bundles/antigravity-plugin/scripts/oss_ask.py +1 -1
  12. package/bundles/antigravity-plugin/scripts/oss_model.py +10 -2
  13. package/bundles/antigravity-plugin/scripts/oss_review.py +1 -1
  14. package/bundles/antigravity-plugin/scripts/setup_project_ai.py +42 -10
  15. package/bundles/antigravity-plugin/session_end_agy.py +31 -6
  16. package/bundles/antigravity-plugin/skills/_registry.md +1 -0
  17. package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +44 -0
  18. package/bundles/antigravity-plugin/skills/code-review/SKILL.md +11 -0
  19. package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +21 -0
  20. package/bundles/antigravity-plugin/skills/gate-review/SKILL.md +11 -0
  21. package/bundles/antigravity-plugin/skills/implement/SKILL.md +36 -0
  22. package/bundles/antigravity-plugin/skills/safe-cleanup/SKILL.md +186 -0
  23. package/bundles/antigravity-plugin/skills/security-review/SKILL.md +9 -0
  24. package/bundles/antigravity-plugin/skills/validate-phase/SKILL.md +31 -0
  25. package/bundles/antigravity-plugin/warm_start_agy.py +96 -9
  26. package/bundles/antigravity-plugin-extras/plugin.json +1 -1
  27. package/bundles/antigravity-plugin-extras/skills/_registry.md +1 -0
  28. package/bundles/antigravity-plugin-extras/skills/safe-cleanup/SKILL.md +186 -0
  29. package/bundles/codex/.codex/config.toml.example +36 -0
  30. package/bundles/codex/.codex/skills/coding/api-design/SKILL.md +249 -0
  31. package/bundles/codex/.codex/skills/coding/backend-development/SKILL.md +305 -0
  32. package/bundles/codex/.codex/skills/coding/code-review/SKILL.md +140 -0
  33. package/bundles/codex/.codex/skills/coding/codebase-audit/SKILL.md +204 -0
  34. package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/SKILL.md +132 -0
  35. package/bundles/codex/.codex/skills/coding/dashboard-perf-sweep/scripts/perf_sweep.py +249 -0
  36. package/bundles/codex/.codex/skills/coding/error-handling/SKILL.md +260 -0
  37. package/bundles/codex/.codex/skills/coding/fastapi-dev/SKILL.md +300 -0
  38. package/bundles/codex/.codex/skills/coding/javascript-typescript/SKILL.md +142 -0
  39. package/bundles/codex/.codex/skills/coding/python/SKILL.md +388 -0
  40. package/bundles/codex/.codex/skills/coding/refactoring/SKILL.md +486 -0
  41. package/bundles/codex/.codex/skills/coding/security-review/SKILL.md +205 -0
  42. package/bundles/codex/.codex/skills/coding/sql/SKILL.md +321 -0
  43. package/bundles/codex/.codex/skills/data/database-design/SKILL.md +177 -0
  44. package/bundles/codex/.codex/skills/data/db-diagram/SKILL.md +148 -0
  45. package/bundles/codex/.codex/skills/data/db-diagram/scripts/sql_to_graph.py +1212 -0
  46. package/bundles/codex/.codex/skills/devops/ci-cd-pipeline/SKILL.md +315 -0
  47. package/bundles/codex/.codex/skills/devops/gh-cli/SKILL.md +195 -0
  48. package/bundles/codex/.codex/skills/devops/git-commit/SKILL.md +285 -0
  49. package/bundles/codex/.codex/skills/devops/safe-cleanup/SKILL.md +186 -0
  50. package/bundles/codex/.codex/skills/devops/using-git-worktrees/SKILL.md +217 -0
  51. package/bundles/codex/.codex/skills/devops/windows-deployment/SKILL.md +880 -0
  52. package/bundles/codex/.codex/skills/docs/code-documentation/SKILL.md +271 -0
  53. package/bundles/codex/.codex/skills/docs/explainer-doc/SKILL.md +97 -0
  54. package/bundles/codex/.codex/skills/docs/technical-writing/SKILL.md +286 -0
  55. package/bundles/codex/.codex/skills/docs/writing-plans/SKILL.md +387 -0
  56. package/bundles/codex/.codex/skills/frontend/css-architecture/SKILL.md +305 -0
  57. package/bundles/codex/.codex/skills/frontend/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
  58. package/bundles/codex/.codex/skills/frontend/frontend-design/SKILL.md +193 -0
  59. package/bundles/codex/.codex/skills/frontend/frontend-design/references/my-tech-stack.md +127 -0
  60. package/bundles/codex/.codex/skills/frontend/mockup/SKILL.md +242 -0
  61. package/bundles/codex/.codex/skills/frontend/react-best-practices/SKILL.md +269 -0
  62. package/bundles/codex/.codex/skills/frontend/react-dev/README.md +404 -0
  63. package/bundles/codex/.codex/skills/frontend/react-dev/SKILL.md +459 -0
  64. package/bundles/codex/.codex/skills/frontend/react-dev/examples/generic-components.md +579 -0
  65. package/bundles/codex/.codex/skills/frontend/react-dev/examples/server-components.md +579 -0
  66. package/bundles/codex/.codex/skills/frontend/react-dev/references/event-handlers.md +574 -0
  67. package/bundles/codex/.codex/skills/frontend/react-dev/references/hooks.md +456 -0
  68. package/bundles/codex/.codex/skills/frontend/react-dev/references/react-19-patterns.md +638 -0
  69. package/bundles/codex/.codex/skills/frontend/react-dev/references/react-router.md +1002 -0
  70. package/bundles/codex/.codex/skills/frontend/react-dev/references/tanstack-router.md +587 -0
  71. package/bundles/codex/.codex/skills/frontend/ui-review/SKILL.md +176 -0
  72. package/bundles/codex/.codex/skills/frontend/ui-review/references/framework-fixes.md +471 -0
  73. package/bundles/codex/.codex/skills/frontend/ui-review/references/visual-checklist.md +236 -0
  74. package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
  75. package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
  76. package/bundles/codex/.codex/skills/frontend/warm-editorial-ui/SKILL.md +732 -0
  77. package/bundles/codex/.codex/skills/media/draw-io/SKILL.md +162 -0
  78. package/bundles/codex/.codex/skills/media/draw-io/references/aws-icons.md +677 -0
  79. package/bundles/codex/.codex/skills/media/draw-io/references/layout-guidelines.md +142 -0
  80. package/bundles/codex/.codex/skills/media/draw-io/references/troubleshooting.md +118 -0
  81. package/bundles/codex/.codex/skills/media/draw-io/references/workflows.md +103 -0
  82. package/bundles/codex/.codex/skills/media/draw-io/scripts/convert-drawio-to-png.sh +25 -0
  83. package/bundles/codex/.codex/skills/media/draw-io/scripts/find_aws_icon.py +79 -0
  84. package/bundles/codex/.codex/skills/media/mermaid-diagrams/SKILL.md +292 -0
  85. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
  86. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
  87. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/advanced-features.md +556 -0
  88. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/architecture-diagrams.md +192 -0
  89. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/c4-diagrams.md +410 -0
  90. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/class-diagrams.md +361 -0
  91. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/erd-diagrams.md +510 -0
  92. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/flowcharts.md +450 -0
  93. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/sequence-diagrams.md +394 -0
  94. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/troubleshooting.md +335 -0
  95. package/bundles/codex/.codex/skills/media/mermaid-diagrams/references/workflows.md +418 -0
  96. package/bundles/codex/.codex/skills/media/particle-art/SKILL.md +243 -0
  97. package/bundles/codex/.codex/skills/media/particle-art/references/canvas-utils.ts +171 -0
  98. package/bundles/codex/.codex/skills/media/particle-art/references/dot-field.template.tsx +203 -0
  99. package/bundles/codex/.codex/skills/media/particle-art/references/flow-field.template.tsx +263 -0
  100. package/bundles/codex/.codex/skills/media/particle-art/references/node-shape.template.tsx +261 -0
  101. package/bundles/codex/.codex/skills/media/particle-art/references/shape-sampler.ts +281 -0
  102. package/bundles/codex/.codex/skills/media/particle-art/references/stipple-morph.template.tsx +167 -0
  103. package/bundles/codex/.codex/skills/media/particle-art/references/stipple.template.tsx +175 -0
  104. package/bundles/codex/.codex/skills/media/particle-art/references/trail-ghost.template.tsx +266 -0
  105. package/bundles/codex/.codex/skills/media/particle-art/references/usage-examples.md +320 -0
  106. package/bundles/codex/.codex/skills/testing/playwright/API_REFERENCE.md +653 -0
  107. package/bundles/codex/.codex/skills/testing/playwright/SKILL.md +454 -0
  108. package/bundles/codex/.codex/skills/testing/playwright/lib/helpers.js +441 -0
  109. package/bundles/codex/.codex/skills/testing/playwright/package.json +26 -0
  110. package/bundles/codex/.codex/skills/testing/playwright/run.js +228 -0
  111. package/bundles/codex/.codex/skills/testing/tdd-workflow/SKILL.md +188 -0
  112. package/bundles/codex/.codex/skills/testing/test-strategy/SKILL.md +155 -0
  113. package/bundles/codex/.codex/skills/testing/webapp-testing/LICENSE.txt +202 -0
  114. package/bundles/codex/.codex/skills/testing/webapp-testing/SKILL.md +97 -0
  115. package/bundles/codex/.codex/skills/testing/webapp-testing/examples/console_logging.py +35 -0
  116. package/bundles/codex/.codex/skills/testing/webapp-testing/examples/element_discovery.py +40 -0
  117. package/bundles/codex/.codex/skills/testing/webapp-testing/examples/static_html_automation.py +33 -0
  118. package/bundles/codex/.codex/skills/testing/webapp-testing/scripts/with_server.py +106 -0
  119. package/bundles/codex/.codex/skills/workflow/advisory-hub/SKILL.md +227 -0
  120. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/context-template.md +214 -0
  121. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/hub-handbook.md +233 -0
  122. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/report-contract.md +94 -0
  123. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/succession.md +118 -0
  124. package/bundles/codex/.codex/skills/workflow/best-practices/SKILL.md +500 -0
  125. package/bundles/codex/.codex/skills/workflow/best-practices/agents/best-practices-referencer.md +263 -0
  126. package/bundles/codex/.codex/skills/workflow/best-practices/agents/codebase-context-builder.md +326 -0
  127. package/bundles/codex/.codex/skills/workflow/best-practices/agents/task-intent-analyzer.md +245 -0
  128. package/bundles/codex/.codex/skills/workflow/best-practices/references/anti-patterns.md +571 -0
  129. package/bundles/codex/.codex/skills/workflow/best-practices/references/before-after-examples.md +1114 -0
  130. package/bundles/codex/.codex/skills/workflow/best-practices/references/best-practices-guide.md +513 -0
  131. package/bundles/codex/.codex/skills/workflow/best-practices/references/common-workflows.md +692 -0
  132. package/bundles/codex/.codex/skills/workflow/best-practices/references/prompt-patterns.md +547 -0
  133. package/bundles/codex/.codex/skills/workflow/brainstorming/SKILL.md +57 -0
  134. package/bundles/codex/.codex/skills/workflow/context-curator/SKILL.md +157 -0
  135. package/bundles/codex/.codex/skills/workflow/golden-plan/SKILL.md +586 -0
  136. package/bundles/codex/.codex/skills/workflow/preflight/SKILL.md +440 -0
  137. package/bundles/codex/.codex/skills/workflow/skill-creator/LICENSE.txt +202 -0
  138. package/bundles/codex/.codex/skills/workflow/skill-creator/SKILL.md +491 -0
  139. package/bundles/codex/.codex/skills/workflow/skill-creator/agents/analyzer.md +274 -0
  140. package/bundles/codex/.codex/skills/workflow/skill-creator/agents/comparator.md +202 -0
  141. package/bundles/codex/.codex/skills/workflow/skill-creator/agents/grader.md +223 -0
  142. package/bundles/codex/.codex/skills/workflow/skill-creator/assets/eval_review.html +146 -0
  143. package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/generate_review.py +471 -0
  144. package/bundles/codex/.codex/skills/workflow/skill-creator/eval-viewer/viewer.html +1325 -0
  145. package/bundles/codex/.codex/skills/workflow/skill-creator/references/schemas.md +430 -0
  146. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/__init__.py +0 -0
  147. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/aggregate_benchmark.py +401 -0
  148. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/generate_report.py +326 -0
  149. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/improve_description.py +247 -0
  150. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/package_skill.py +136 -0
  151. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/quick_validate.py +103 -0
  152. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_eval.py +310 -0
  153. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/run_loop.py +328 -0
  154. package/bundles/codex/.codex/skills/workflow/skill-creator/scripts/utils.py +47 -0
  155. package/bundles/codex/AGENTS.md +146 -0
  156. package/bundles/manifest.json +4 -3
  157. package/dist/claude-deepseek.js +2 -2
  158. package/dist/claude-glm.js +2 -2
  159. package/dist/claude-oss.js +2 -2
  160. package/dist/cli.js +187 -56
  161. package/package.json +1 -1
  162. package/bundles/antigravity-plugin/scripts/dream_capture.py +0 -249
  163. package/bundles/antigravity-plugin/scripts/dream_memory.py +0 -438
  164. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  165. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  166. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  167. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  168. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  169. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  170. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  171. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  172. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  173. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  174. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  175. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  176. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  177. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  178. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  179. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  180. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  181. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  182. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  183. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  184. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  185. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  186. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  187. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  188. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  189. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  190. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  191. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  192. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  193. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  194. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  195. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  196. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  197. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  198. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  199. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  200. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  201. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  202. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  203. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  204. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  205. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  206. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  207. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  208. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  209. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  210. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  211. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  212. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  213. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  214. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  215. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  216. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  217. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  218. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  219. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  220. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  221. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  222. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  223. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  224. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  225. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  226. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  227. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  228. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  229. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  230. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  231. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  232. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  233. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  234. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  235. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  236. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  237. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  238. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  239. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  240. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  241. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  242. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  243. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  244. package/bundles/antigravity-plugin-extras/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
package/dist/cli.js CHANGED
@@ -3764,8 +3764,11 @@ function packageInfo() {
3764
3764
  cached = { root, name: parsed.name, version: parsed.version };
3765
3765
  return cached;
3766
3766
  }
3767
- function bundlePath(name) {
3767
+ function bundlePath(name, options = {}) {
3768
+ const { requireManifest = true } = options;
3768
3769
  const dir = path.join(packageInfo().root, "bundles", name);
3770
+ if (!existsSync(dir)) return null;
3771
+ if (!requireManifest) return dir;
3769
3772
  return existsSync(path.join(dir, "plugin.json")) ? dir : null;
3770
3773
  }
3771
3774
  function bundleManifest() {
@@ -4605,14 +4608,14 @@ async function checkCliUpdate(currentVersion) {
4605
4608
  if (!latest || latest === currentVersion) return null;
4606
4609
  return { current: currentVersion, latest };
4607
4610
  }
4608
- function classify(adapter, detection, status4, poolVersion) {
4611
+ function classify(adapter, detection, status5, poolVersion) {
4609
4612
  if (!detection.present) return "absent";
4610
4613
  if (!adapter.supported) return "unsupported";
4611
- if (!status4.installed) return "missing";
4612
- if (!status4.version) return "unknown";
4614
+ if (!status5.installed) return "missing";
4615
+ if (!status5.version) return "unknown";
4613
4616
  if (poolVersion === "unknown") return "unknown";
4614
- const order = compareVersions(status4.version, poolVersion);
4615
- if (order === null) return status4.version === poolVersion ? "current" : "stale";
4617
+ const order = compareVersions(status5.version, poolVersion);
4618
+ if (order === null) return status5.version === poolVersion ? "current" : "stale";
4616
4619
  if (order === 0) return "current";
4617
4620
  return order > 0 ? "ahead" : "stale";
4618
4621
  }
@@ -4625,13 +4628,13 @@ async function gather(adapters, options = {}) {
4625
4628
  Promise.all(
4626
4629
  adapters.map(async (adapter) => {
4627
4630
  const detection = await adapter.detect();
4628
- const status4 = detection.present ? await adapter.status() : { installed: false, note: "agent not installed" };
4631
+ const status5 = detection.present ? await adapter.status() : { installed: false, note: "agent not installed" };
4629
4632
  return {
4630
4633
  adapter,
4631
4634
  detection,
4632
- status: status4,
4633
- drift: classify(adapter, detection, status4, poolVersion),
4634
- extrasDrift: classifyExtras(adapter, detection, status4, extrasVersion)
4635
+ status: status5,
4636
+ drift: classify(adapter, detection, status5, poolVersion),
4637
+ extrasDrift: classifyExtras(adapter, detection, status5, extrasVersion)
4635
4638
  };
4636
4639
  })
4637
4640
  ),
@@ -4639,14 +4642,14 @@ async function gather(adapters, options = {}) {
4639
4642
  ]);
4640
4643
  return { cliVersion, poolVersion, extrasVersion, agents, cliUpdate: cliUpdate ?? void 0 };
4641
4644
  }
4642
- function classifyExtras(adapter, detection, status4, extrasVersion) {
4643
- if (!status4.extras) return void 0;
4645
+ function classifyExtras(adapter, detection, status5, extrasVersion) {
4646
+ if (!status5.extras) return void 0;
4644
4647
  if (!detection.present) return "absent";
4645
4648
  if (!adapter.supported) return "unsupported";
4646
- if (!status4.extras.installed) return "missing";
4647
- if (!status4.extras.version || !extrasVersion) return "unknown";
4648
- const order = compareVersions(status4.extras.version, extrasVersion);
4649
- if (order === null) return status4.extras.version === extrasVersion ? "current" : "stale";
4649
+ if (!status5.extras.installed) return "missing";
4650
+ if (!status5.extras.version || !extrasVersion) return "unknown";
4651
+ const order = compareVersions(status5.extras.version, extrasVersion);
4652
+ if (order === null) return status5.extras.version === extrasVersion ? "current" : "stale";
4650
4653
  if (order === 0) return "current";
4651
4654
  return order > 0 ? "ahead" : "stale";
4652
4655
  }
@@ -4734,7 +4737,7 @@ var init_init = __esm({
4734
4737
  });
4735
4738
 
4736
4739
  // src/providers/resolve.ts
4737
- import { readFileSync as readFileSync3 } from "fs";
4740
+ import { readFileSync as readFileSync4 } from "fs";
4738
4741
  import { homedir } from "os";
4739
4742
  import { isAbsolute, join } from "path";
4740
4743
  function expandHome(p2) {
@@ -4750,7 +4753,7 @@ function keysFilePath(env) {
4750
4753
  function parseKeysFile(path5) {
4751
4754
  let text;
4752
4755
  try {
4753
- text = readFileSync3(path5, "utf8");
4756
+ text = readFileSync4(path5, "utf8");
4754
4757
  } catch {
4755
4758
  return {};
4756
4759
  }
@@ -4779,12 +4782,12 @@ var init_resolve = __esm({
4779
4782
  PROVIDERS = {
4780
4783
  deepseek: {
4781
4784
  baseUrl: "https://api.deepseek.com/anthropic",
4782
- model: "deepseek-v4-flash",
4785
+ model: "deepseek-v4-flash[1m]",
4783
4786
  keyEnv: "DEEPSEEK_API_KEY"
4784
4787
  },
4785
4788
  glm: {
4786
4789
  baseUrl: "https://api.z.ai/api/anthropic",
4787
- model: "glm-5.2",
4790
+ model: "glm-5.3[1m]",
4788
4791
  keyEnv: "GLM_API_KEY"
4789
4792
  },
4790
4793
  // OpenRouter has no Anthropic-protocol endpoint. It works only through an
@@ -4808,7 +4811,7 @@ __export(keys_exports, {
4808
4811
  probeKey: () => probeKey,
4809
4812
  upsertKeyLines: () => upsertKeyLines
4810
4813
  });
4811
- import { chmodSync, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
4814
+ import { chmodSync, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
4812
4815
  import { dirname } from "path";
4813
4816
  async function probeKey(baseUrl, model, apiKey) {
4814
4817
  if (!baseUrl) return { ok: false, rejected: false, detail: "no endpoint for this provider" };
@@ -4969,12 +4972,12 @@ async function keys(options = {}) {
4969
4972
  }
4970
4973
  let existing = "";
4971
4974
  try {
4972
- existing = readFileSync4(path5, "utf8");
4975
+ existing = readFileSync5(path5, "utf8");
4973
4976
  } catch {
4974
4977
  existing = "";
4975
4978
  }
4976
- mkdirSync(dirname(path5), { recursive: true });
4977
- writeFileSync(path5, upsertKeyLines(existing, collected), { encoding: "utf8" });
4979
+ mkdirSync2(dirname(path5), { recursive: true });
4980
+ writeFileSync2(path5, upsertKeyLines(existing, collected), { encoding: "utf8" });
4978
4981
  const permWarning = restrictPermissions(path5);
4979
4982
  process.stdout.write(`
4980
4983
  wrote ${Object.keys(collected).join(", ")} to ${path5}
@@ -5104,13 +5107,13 @@ function renderEnvironment(report, problems) {
5104
5107
  function renderAgents(report, problems) {
5105
5108
  heading("Agents");
5106
5109
  for (const entry of report.agents) {
5107
- const { adapter, detection, status: status4 } = entry;
5110
+ const { adapter, detection, status: status5 } = entry;
5108
5111
  item(markFor(entry.drift), `${color.bold(adapter.name)} \u2014 ${describe(entry, report.poolVersion)}`);
5109
5112
  if (detection.path) detail(detection.path);
5110
5113
  if (detection.agentVersion) detail(`agent version ${detection.agentVersion}`);
5111
- if (status4.source) detail(`read from ${status4.source}`);
5112
- if (status4.note) detail(status4.note);
5113
- if (detection.note && detection.note !== status4.note) detail(detection.note);
5114
+ if (status5.source) detail(`read from ${status5.source}`);
5115
+ if (status5.note) detail(status5.note);
5116
+ if (detection.note && detection.note !== status5.note) detail(detection.note);
5114
5117
  if (entry.extrasDrift) detail(describeExtras(entry, report.extrasVersion));
5115
5118
  const problem = problemFor(entry, report.poolVersion);
5116
5119
  if (problem) {
@@ -5322,9 +5325,9 @@ var init_table = __esm({
5322
5325
  // src/commands/status.ts
5323
5326
  var status_exports = {};
5324
5327
  __export(status_exports, {
5325
- status: () => status3
5328
+ status: () => status4
5326
5329
  });
5327
- async function status3(options) {
5330
+ async function status4(options) {
5328
5331
  const report = await gather(options.adapters);
5329
5332
  if (options.json) {
5330
5333
  line(JSON.stringify(toJson2(report), null, 2));
@@ -5457,8 +5460,8 @@ function parsePluginList(stdout, plugin = PLUGIN) {
5457
5460
  if (version?.[1] && entry.version === void 0) {
5458
5461
  entry.version = version[1] === "unknown" ? void 0 : version[1];
5459
5462
  }
5460
- const status4 = line2.match(/^\s*Status\s*:\s*(.+?)\s*$/i);
5461
- if (status4?.[1]) entry.disabled = /disabled/i.test(status4[1]);
5463
+ const status5 = line2.match(/^\s*Status\s*:\s*(.+?)\s*$/i);
5464
+ if (status5?.[1]) entry.disabled = /disabled/i.test(status5[1]);
5462
5465
  }
5463
5466
  return entry;
5464
5467
  }
@@ -5735,32 +5738,170 @@ var agyAdapter = {
5735
5738
  };
5736
5739
 
5737
5740
  // src/agents/codex.ts
5741
+ init_exec();
5742
+ import { cpSync as cpSync2, existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, rmSync as rmSync2, writeFileSync } from "fs";
5738
5743
  import os2 from "os";
5739
5744
  import path3 from "path";
5745
+ init_pkg();
5746
+ var BIN3 = "codex";
5747
+ var BUNDLE2 = "codex";
5748
+ function caddisSkillsDir(home = os2.homedir()) {
5749
+ return path3.join(home, ".codex", "skills", "caddis");
5750
+ }
5751
+ function versionFile(home = os2.homedir()) {
5752
+ return path3.join(caddisSkillsDir(home), ".caddis-version");
5753
+ }
5754
+ async function detect3() {
5755
+ const binPath = await findBin(BIN3);
5756
+ if (!binPath) {
5757
+ const configDir = path3.join(os2.homedir(), ".codex");
5758
+ if (existsSync3(configDir)) {
5759
+ return { present: false, path: configDir, note: "no `codex` binary on PATH, but ~/.codex exists" };
5760
+ }
5761
+ return { present: false, note: "no `codex` binary on PATH" };
5762
+ }
5763
+ const version = await run(BIN3, ["--version"], { timeout: 2e4 });
5764
+ return {
5765
+ present: true,
5766
+ path: binPath,
5767
+ // `codex --version` prints "codex-cli 0.150.1"; take the trailing token.
5768
+ agentVersion: version.ok ? version.stdout.trim().split(/\s+/).pop() || void 0 : void 0,
5769
+ note: version.ok ? void 0 : "binary found but `codex --version` failed"
5770
+ };
5771
+ }
5772
+ function shortenHome2(target) {
5773
+ const home = os2.homedir();
5774
+ return target.startsWith(home) ? path3.join("~", target.slice(home.length)) : target;
5775
+ }
5776
+ function statusFromHome2(home) {
5777
+ const marker = versionFile(home);
5778
+ const dir = caddisSkillsDir(home);
5779
+ if (existsSync3(marker)) {
5780
+ try {
5781
+ const version = readFileSync3(marker, "utf8").trim();
5782
+ if (version) return { installed: true, version, source: shortenHome2(marker) };
5783
+ } catch {
5784
+ }
5785
+ return { installed: true, source: shortenHome2(marker), note: "version marker present but unreadable" };
5786
+ }
5787
+ if (existsSync3(dir)) {
5788
+ return {
5789
+ installed: true,
5790
+ source: shortenHome2(dir),
5791
+ note: "skills present but no version marker \u2014 installed by hand, or by a caddis older than this one"
5792
+ };
5793
+ }
5794
+ return { installed: false, source: shortenHome2(dir), note: "caddis skills not installed into codex" };
5795
+ }
5796
+ async function status3() {
5797
+ const detected = await detect3();
5798
+ if (!detected.present) return { installed: false, note: "agent not installed" };
5799
+ return statusFromHome2(os2.homedir());
5800
+ }
5801
+ async function drive3(action, options) {
5802
+ const detected = await detect3();
5803
+ if (!detected.present) {
5804
+ return { ok: true, skipped: true, steps: [], message: "codex not installed \u2014 skipped" };
5805
+ }
5806
+ const bundle = bundlePath(BUNDLE2, { requireManifest: false });
5807
+ if (!bundle) {
5808
+ return {
5809
+ ok: false,
5810
+ skipped: false,
5811
+ steps: [],
5812
+ message: `the ${BUNDLE2} bundle is missing from this package \u2014 reinstall @caddis/cli`
5813
+ };
5814
+ }
5815
+ const source = path3.join(bundle, ".codex", "skills");
5816
+ if (!existsSync3(source)) {
5817
+ return {
5818
+ ok: false,
5819
+ skipped: false,
5820
+ steps: [],
5821
+ message: `the ${BUNDLE2} bundle has no .codex/skills directory \u2014 the export shape changed`
5822
+ };
5823
+ }
5824
+ const home = os2.homedir();
5825
+ const dest = caddisSkillsDir(home);
5826
+ const version = bundleManifest().poolVersion || "unknown";
5827
+ const label = `copy ${BUNDLE2} skills -> ${shortenHome2(dest)}`;
5828
+ const steps2 = [];
5829
+ if (options.dryRun) {
5830
+ return {
5831
+ ok: true,
5832
+ skipped: true,
5833
+ steps: [{ command: label, ok: true, code: 0 }],
5834
+ message: `dry run \u2014 would ${action} caddis ${version} into ${shortenHome2(dest)}`
5835
+ };
5836
+ }
5837
+ try {
5838
+ if (existsSync3(dest)) rmSync2(dest, { recursive: true, force: true });
5839
+ mkdirSync(path3.dirname(dest), { recursive: true });
5840
+ cpSync2(source, dest, { recursive: true });
5841
+ writeFileSync(versionFile(home), `${version}
5842
+ `, "utf8");
5843
+ steps2.push({ command: label, ok: true, code: 0 });
5844
+ } catch (error) {
5845
+ const message = error instanceof Error ? error.message : String(error);
5846
+ steps2.push({ command: label, ok: false, code: null, output: message });
5847
+ return { ok: false, skipped: false, steps: steps2, message: `could not install into codex: ${message}` };
5848
+ }
5849
+ const notes = [];
5850
+ for (const asset of ["AGENTS.md", path3.join(".codex", "config.toml.example")]) {
5851
+ const from = path3.join(bundle, asset);
5852
+ if (!existsSync3(from)) continue;
5853
+ const to = path3.join(dest, `caddis-${path3.basename(asset)}`);
5854
+ try {
5855
+ cpSync2(from, to);
5856
+ notes.push(path3.basename(to));
5857
+ } catch {
5858
+ }
5859
+ }
5860
+ const extrasNote = options.extras ? " (--extras has no codex bundle yet; core only)" : "";
5861
+ const referenceNote = notes.length ? ` Reference copies beside it: ${notes.join(", ")} \u2014 config.toml is NEVER merged for you.` : "";
5862
+ return {
5863
+ ok: true,
5864
+ skipped: false,
5865
+ steps: steps2,
5866
+ message: `caddis ${version} ${action === "install" ? "installed" : "updated"} in ${shortenHome2(dest)}.${referenceNote}${extrasNote}`
5867
+ };
5868
+ }
5869
+ var codexAdapter = {
5870
+ id: "codex",
5871
+ name: "Codex",
5872
+ supported: true,
5873
+ summary: "copy the caddis skill pool into ~/.codex/skills/caddis/ (config.toml never merged)",
5874
+ detect: detect3,
5875
+ drive: drive3,
5876
+ status: status3
5877
+ };
5878
+
5879
+ // src/agents/copilot.ts
5880
+ import path4 from "path";
5740
5881
 
5741
5882
  // src/agents/stub.ts
5742
- import { existsSync as existsSync3 } from "fs";
5883
+ import { existsSync as existsSync4 } from "fs";
5743
5884
  var NOT_YET_SUPPORTED = "not yet supported (v0.2)";
5744
5885
  function createStubAdapter(spec) {
5745
- async function detect3() {
5886
+ async function detect4() {
5746
5887
  for (const bin of spec.bins) {
5747
5888
  const found = await findBin(bin);
5748
5889
  if (found) return { present: true, path: found, note: NOT_YET_SUPPORTED };
5749
5890
  }
5750
5891
  for (const configPath of spec.configPaths) {
5751
- if (existsSync3(configPath)) return { present: true, path: configPath, note: NOT_YET_SUPPORTED };
5892
+ if (existsSync4(configPath)) return { present: true, path: configPath, note: NOT_YET_SUPPORTED };
5752
5893
  }
5753
5894
  return { present: false, note: `no ${spec.bins.map((b3) => `\`${b3}\``).join(" / ")} binary or config found` };
5754
5895
  }
5755
- async function status4() {
5756
- const detected = await detect3();
5896
+ async function status5() {
5897
+ const detected = await detect4();
5757
5898
  return {
5758
5899
  installed: false,
5759
5900
  note: detected.present ? NOT_YET_SUPPORTED : "agent not installed"
5760
5901
  };
5761
5902
  }
5762
- async function drive3(_action, _options) {
5763
- const detected = await detect3();
5903
+ async function drive4(_action, _options) {
5904
+ const detected = await detect4();
5764
5905
  return {
5765
5906
  ok: true,
5766
5907
  skipped: true,
@@ -5773,23 +5914,13 @@ function createStubAdapter(spec) {
5773
5914
  name: spec.name,
5774
5915
  supported: false,
5775
5916
  summary: spec.summary,
5776
- detect: detect3,
5777
- drive: drive3,
5778
- status: status4
5917
+ detect: detect4,
5918
+ drive: drive4,
5919
+ status: status5
5779
5920
  };
5780
5921
  }
5781
5922
 
5782
- // src/agents/codex.ts
5783
- var codexAdapter = createStubAdapter({
5784
- id: "codex",
5785
- name: "Codex",
5786
- bins: ["codex"],
5787
- configPaths: [path3.join(os2.homedir(), ".codex")],
5788
- summary: "merge the caddis pool into ~/.codex + AGENTS.md (v0.2)"
5789
- });
5790
-
5791
5923
  // src/agents/copilot.ts
5792
- import path4 from "path";
5793
5924
  var copilotAdapter = createStubAdapter({
5794
5925
  id: "copilot",
5795
5926
  name: "GitHub Copilot",
@@ -5872,8 +6003,8 @@ withGlobalFlags(program2.command("doctor")).description("full health report: eve
5872
6003
  });
5873
6004
  withGlobalFlags(program2.command("status")).description("compact table: cli version, pool version, per-agent version, drift").option("--json", "machine-readable output", false).action(async (options) => {
5874
6005
  const flags = mergeFlags(options);
5875
- const { status: status4 } = await Promise.resolve().then(() => (init_status(), status_exports));
5876
- finish(await status4({ adapters: resolveAdapters(flags), json: options.json }));
6006
+ const { status: status5 } = await Promise.resolve().then(() => (init_status(), status_exports));
6007
+ finish(await status5({ adapters: resolveAdapters(flags), json: options.json }));
5877
6008
  });
5878
6009
  program2.addHelpText(
5879
6010
  "after",
@@ -5919,8 +6050,8 @@ async function maybeNotify(enabled) {
5919
6050
  }
5920
6051
  async function main() {
5921
6052
  if (process.argv.slice(2).length === 0) {
5922
- const { status: status4 } = await Promise.resolve().then(() => (init_status(), status_exports));
5923
- finish(await status4({ adapters: selectAdapters() }));
6053
+ const { status: status5 } = await Promise.resolve().then(() => (init_status(), status_exports));
6054
+ finish(await status5({ adapters: selectAdapters() }));
5924
6055
  await maybeNotify(true);
5925
6056
  return;
5926
6057
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caddis/cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Install, update and diagnose the caddis dev harness across every coding agent you use (Claude Code, agy/Antigravity, and more).",
5
5
  "keywords": [
6
6
  "caddis",
@@ -1,249 +0,0 @@
1
- """Deterministic Dream Memory capture from a Stop transcript (fann Phase 5b).
2
-
3
- Pure, filesystem-free extraction of *high-confidence* fact candidates from a parsed transcript,
4
- plus privacy redaction. The hook (``session_end.py``) does the I/O — read the transcript, call
5
- :func:`extract_facts`, then consolidate via ``dream_memory`` and rewrite the store. Keeping the
6
- logic here (dicts in → dicts out) makes it unit-testable without a tree, mirroring the engine.
7
-
8
- Two kinds are captured (the only ones inferable *without an LLM* — the rich kinds come from the
9
- knowledge-transfer agent in 5d):
10
- • **failure-mode** — a ``Bash`` tool call whose result is an error (``is_error``). One candidate
11
- per distinct command per session; cross-session recurrence is what reinforces it.
12
- • **workflow-success** — a *build/test* command that succeeded after the same command failed
13
- earlier in the same session (the red→green signal).
14
-
15
- PRIVACY (hard constraint, see the design doc): a fact must be safe to print at SessionStart and
16
- (eventually) to commit. So we (1) **skip entirely** any command that touches a secret file
17
- (``.env``, ``**/secrets/**``, ``*.pem``/``*.key``, credential files — guard.py's secret sense),
18
- and (2) **redact** inline secrets (``KEY=…``, ``--token …``, ``Bearer …``, URLs with credentials,
19
- known token shapes, long high-entropy blobs) from both the command head and the error line. The
20
- dedup key derives from the *redacted* command, so a token can never leak into the store's key.
21
- """
22
-
23
- from __future__ import annotations
24
-
25
- import hashlib
26
- import re
27
-
28
- from dream_memory import make_fact, normalize_key # sibling module in scripts/
29
-
30
- # --------------------------------------------------------------------------- #
31
- # Limits — keep the store lean and a single Stop's append bounded.
32
- # --------------------------------------------------------------------------- #
33
- MAX_FACTS_PER_RUN = 15 # cap candidates emitted from one transcript
34
- _HEAD_LEN = 80 # command head kept (we store heads, not full args)
35
- _ERR_LEN = 120 # first error line kept
36
- _SUMMARY_LEN = 200 # final clamp on a summary
37
-
38
-
39
- # --------------------------------------------------------------------------- #
40
- # Privacy — redaction + secret-path skip. Mirrors guard.py's secret sense but
41
- # operates on inline text (value-level scrubbing), not just file-path classing.
42
- # --------------------------------------------------------------------------- #
43
- _URL_CRED = re.compile(r"(\w[\w+.\-]*://)[^/\s:@]+:[^/\s@]+@")
44
- _SENSITIVE_KEY = re.compile(
45
- r"\b([A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|CREDENTIAL|CREDENTIALS|AUTH|APIKEY|PRIVATE)[A-Za-z0-9_]*)"
46
- r"(\s*[=:]\s*)(\"[^\"]*\"|'[^']*'|\S+)",
47
- re.I,
48
- )
49
- _SENSITIVE_FLAG = re.compile(
50
- r"(--?(?:password|passwd|pwd|token|secret|api[-_]?key|access[-_]?key|auth)\b)(\s+|=)(\"[^\"]*\"|'[^']*'|\S+)",
51
- re.I,
52
- )
53
- # MySQL/MariaDB attached-password flag: `-pVALUE` glued to the flag (no separator).
54
- # Scoped to mysql-family commands so `cp -pr`, `mkdir -p`, `docker -p 8080:80`,
55
- # `ssh -p22` are never touched. Value may be quoted (`-p"my pass"`).
56
- _MYSQL_PW = re.compile(
57
- r"(\b(?:mysql|mysqldump|mariadb|mysqladmin)\b[^\n]*?\s-p)(\"[^\"]*\"|'[^']*'|\S+)",
58
- re.I,
59
- )
60
- # curl basic-auth: `-u user:pass` / `--user user:pass` (value may be glued to -u).
61
- # Scoped to curl so `python -u`, `sort -u`, `docker run -u 1000:1000` survive.
62
- _CURL_USERPASS = re.compile(
63
- r"(\bcurl\b[^\n]*?\s(?:--user|-u)\s*)(\"[^\"]*\"|'[^']*'|\S+)",
64
- re.I,
65
- )
66
- # AWS credential keys given WHITESPACE-separated (e.g. `aws configure set
67
- # aws_secret_access_key <k>`); the `=`/`:` form is already caught by _SENSITIVE_KEY.
68
- _AWS_CRED = re.compile(
69
- r"\b(aws_secret_access_key|aws_access_key_id|aws_session_token)\b"
70
- r"(\s+|\s*[=:]\s*)(\"[^\"]*\"|'[^']*'|\S+)",
71
- re.I,
72
- )
73
- _AUTH_HEADER = re.compile(r"\b(authorization|x-api-key)\b(\s*:\s*|\s+)(?:bearer\s+)?\S+", re.I)
74
- _BEARER = re.compile(r"\bbearer\s+[A-Za-z0-9._\-]+", re.I)
75
- _TOKEN_PREFIX = re.compile(
76
- r"\b(?:gh[posru]_[A-Za-z0-9]{6,}|sk-[A-Za-z0-9]{6,}|xox[baprs]-[A-Za-z0-9-]{6,}|AKIA[0-9A-Z]{12,})"
77
- )
78
- # Long high-entropy blob (a letter AND a digit, ≥40 chars). Excludes '/' so file paths survive.
79
- _LONG_TOKEN = re.compile(r"\b(?=[A-Za-z0-9+=_\-]*[A-Za-z])(?=[A-Za-z0-9+=_\-]*[0-9])[A-Za-z0-9+=_\-]{40,}\b")
80
-
81
- _SECRET_PATH = re.compile(
82
- r"(?:^|[\s=:'\"/\\])\.env(?:\.|$|[\s'\"/\\])"
83
- r"|[/\\]\.?secrets?[/\\]"
84
- r"|\b(?:id_rsa|id_dsa|id_ecdsa|id_ed25519|credentials|\.npmrc|\.pypirc|\.netrc|\.pgpass|\.htpasswd)\b"
85
- r"|\.(?:pem|key|p12|pfx|keystore|jks)\b",
86
- re.I,
87
- )
88
-
89
-
90
- def redact(text: str) -> str:
91
- """Scrub inline secrets from ``text`` so it's safe to store, surface, and commit.
92
-
93
- Order matters: credentialed URLs first, then whole-value header/bearer forms (these must run
94
- before the generic ``KEY=…`` rule, else "Authorization" matches as a key and only eats the
95
- word "Bearer", leaking the token), then explicit ``KEY=…`` / ``--token …`` assignments, then
96
- known token prefixes, then a catch-all for long high-entropy blobs. Conservative on file paths
97
- (the blob rule excludes ``/``) so an error line stays useful.
98
- """
99
- if not text:
100
- return ""
101
- t = str(text)
102
- t = _URL_CRED.sub(r"\1***:***@", t)
103
- t = _AUTH_HEADER.sub(r"\1: ***", t)
104
- t = _BEARER.sub("bearer ***", t)
105
- t = _SENSITIVE_KEY.sub(r"\1=***", t)
106
- t = _AWS_CRED.sub(r"\1 ***", t)
107
- t = _SENSITIVE_FLAG.sub(r"\1 ***", t)
108
- t = _CURL_USERPASS.sub(r"\1***", t)
109
- t = _MYSQL_PW.sub(r"\1***", t)
110
- t = _TOKEN_PREFIX.sub("***", t)
111
- t = _LONG_TOKEN.sub("***", t)
112
- return t
113
-
114
-
115
- def touches_secret(command: str) -> bool:
116
- """True if ``command`` references a secret file/path — such a fact is never stored at all."""
117
- return bool(_SECRET_PATH.search(command or ""))
118
-
119
-
120
- # --------------------------------------------------------------------------- #
121
- # Text shaping
122
- # --------------------------------------------------------------------------- #
123
- def command_head(command: str, max_len: int = _HEAD_LEN) -> str:
124
- """Whitespace-collapsed, length-capped command head — we store heads, not full arg lists."""
125
- c = " ".join((command or "").split())
126
- return c[:max_len].rstrip()
127
-
128
-
129
- def command_fp(command: str) -> str:
130
- """Stable dedup fingerprint of the FULL command (whitespace-collapsed, lowercased), hashed so two
131
- distinct commands that share a truncated 80-char head don't merge into one inflated fact. Kept
132
- separate from the display head on purpose. Pass the ALREADY-REDACTED command so no secret is hashed."""
133
- norm = " ".join((command or "").split()).lower()
134
- return hashlib.sha1(norm.encode("utf-8")).hexdigest()[:16]
135
-
136
-
137
- def first_error_line(output: str, max_len: int = _ERR_LEN) -> str:
138
- """First non-empty line of tool output, length-capped — the error's gist, not the whole dump."""
139
- for line in (output or "").splitlines():
140
- s = line.strip()
141
- if s:
142
- return s[:max_len]
143
- return ""
144
-
145
-
146
- # Commands whose non-zero exit is routine control flow / a search miss — not a durable lesson.
147
- _NOISE_FIRST_TOKEN = frozenset({
148
- "grep", "rg", "test", "[", "find", "ls", "cat", "which", "type", "head", "tail", "diff",
149
- })
150
-
151
- # Build/test commands — only these qualify for the red→green workflow-success signal.
152
- _BUILD_TEST = re.compile(
153
- r"\b(?:pytest|tox|nox|unittest|jest|vitest|mocha|"
154
- r"npm\s+(?:run\s+\S+|test|ci)|yarn\s+\S+|pnpm\s+\S+|"
155
- r"vite(?:\s+build)?|tsc\b|go\s+(?:test|build)|cargo\s+(?:test|build)|"
156
- r"make\b|gradle\b|mvn\b|dotnet\s+(?:test|build)|rspec|phpunit)\b",
157
- re.I,
158
- )
159
-
160
-
161
- def _is_noise_failure(command: str) -> bool:
162
- toks = (command or "").strip().split()
163
- return bool(toks) and toks[0] in _NOISE_FIRST_TOKEN
164
-
165
-
166
- # --------------------------------------------------------------------------- #
167
- # Transcript walking
168
- # --------------------------------------------------------------------------- #
169
- def _content_blocks(record: dict) -> list[dict]:
170
- """The list of content blocks in a transcript record (handles the nested ``message`` shape)."""
171
- if not isinstance(record, dict):
172
- return []
173
- msg = record.get("message") if isinstance(record.get("message"), dict) else record
174
- content = msg.get("content") if isinstance(msg, dict) else None
175
- if isinstance(content, list):
176
- return [b for b in content if isinstance(b, dict)]
177
- return []
178
-
179
-
180
- def _result_text(block: dict) -> str:
181
- """Flatten a tool_result's content (string or list-of-{text}) to plain text."""
182
- c = block.get("content")
183
- if isinstance(c, str):
184
- return c
185
- if isinstance(c, list):
186
- parts = [item["text"] for item in c if isinstance(item, dict) and isinstance(item.get("text"), str)]
187
- return "\n".join(parts)
188
- return ""
189
-
190
-
191
- def extract_facts(records: list[dict], observed_at: str) -> list[dict]:
192
- """Mine deterministic fact candidates from parsed transcript ``records`` (in order).
193
-
194
- Returns at most :data:`MAX_FACTS_PER_RUN` ``make_fact`` dicts. Pure: no I/O, no mutation of
195
- inputs. Secret-touching commands are skipped wholesale; all stored text is redacted.
196
- """
197
- # Pass 1: map Bash tool_use id → command.
198
- uses: dict[str, str] = {}
199
- for rec in records:
200
- for b in _content_blocks(rec):
201
- if b.get("type") == "tool_use" and b.get("name") == "Bash":
202
- tid = b.get("id")
203
- inp = b.get("input") if isinstance(b.get("input"), dict) else {}
204
- cmd = inp.get("command")
205
- if tid and isinstance(cmd, str) and cmd.strip():
206
- uses[tid] = cmd
207
-
208
- # Pass 2: walk results in order — failures first feed the red→green check for later successes.
209
- facts: list[dict] = []
210
- failed_keys: set[str] = set()
211
- emitted: set[str] = set()
212
-
213
- for rec in records:
214
- for b in _content_blocks(rec):
215
- if b.get("type") != "tool_result":
216
- continue
217
- cmd = uses.get(b.get("tool_use_id"))
218
- if not cmd or touches_secret(cmd):
219
- continue # unknown tool, or a secret-touching command we refuse to record
220
-
221
- red = redact(cmd)
222
- head = command_head(red)
223
- key = normalize_key(head)
224
- if not key:
225
- continue
226
- fp = command_fp(red) # full-command dedup identity (the display key stays the 80-char head)
227
-
228
- if bool(b.get("is_error")):
229
- if _is_noise_failure(cmd):
230
- continue
231
- failed_keys.add(fp)
232
- if fp in emitted:
233
- continue # one failure candidate per distinct command per session
234
- emitted.add(fp)
235
- errline = redact(first_error_line(_result_text(b)))
236
- summary = (f"`{head}` failed: {errline}" if errline else f"`{head}` failed")[:_SUMMARY_LEN]
237
- facts.append(make_fact("failure-mode", key, summary, observed_at, source="auto", fp=fp))
238
- else:
239
- # Success → only a fact if a build/test command recovered from an earlier failure.
240
- ok_key = "ok:" + fp
241
- if _BUILD_TEST.search(cmd) and fp in failed_keys and ok_key not in emitted:
242
- emitted.add(ok_key)
243
- summary = (f"`{head}` passes now — was failing earlier this session")[:_SUMMARY_LEN]
244
- facts.append(make_fact("workflow-success", key, summary, observed_at, source="auto", fp=fp))
245
-
246
- if len(facts) >= MAX_FACTS_PER_RUN:
247
- return facts
248
-
249
- return facts