dsh-compound-engineering 0.0.0-stage → 0.1.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 (461) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -2
  3. package/README.zh.md +161 -0
  4. package/cordis.patch.yml +6 -0
  5. package/lib/frontmatter.js +167 -0
  6. package/lib/index.js +46 -0
  7. package/lib/provider.js +201 -0
  8. package/package.json +62 -4
  9. package/skills/CODING_STANDARDS.md +68 -0
  10. package/skills/ce-babysit-pr/SKILL.md +59 -0
  11. package/skills/ce-babysit-pr/references/branch-currency.md +22 -0
  12. package/skills/ce-babysit-pr/references/envelope.md +44 -0
  13. package/skills/ce-babysit-pr/references/pipeline.md +15 -0
  14. package/skills/ce-babysit-pr/references/report.md +20 -0
  15. package/skills/ce-babysit-pr/references/settle.md +37 -0
  16. package/skills/ce-babysit-pr/references/setup.md +33 -0
  17. package/skills/ce-babysit-pr/references/stack-commands.md +39 -0
  18. package/skills/ce-babysit-pr/references/stack.md +43 -0
  19. package/skills/ce-babysit-pr/references/tick.md +102 -0
  20. package/skills/ce-babysit-pr/references/watch-loop.md +222 -0
  21. package/skills/ce-babysit-pr/scripts/pr-snapshot +3656 -0
  22. package/skills/ce-bakeoff/SKILL.md +48 -0
  23. package/skills/ce-bakeoff/references/candidates.md +37 -0
  24. package/skills/ce-bakeoff/references/judging.md +19 -0
  25. package/skills/ce-bakeoff/references/output.md +11 -0
  26. package/skills/ce-bakeoff/references/verification.md +15 -0
  27. package/skills/ce-brainstorm/SKILL.md +69 -0
  28. package/skills/ce-brainstorm/references/agents/slack-researcher.md +127 -0
  29. package/skills/ce-brainstorm/references/approaches.md +57 -0
  30. package/skills/ce-brainstorm/references/bakeoff.md +9 -0
  31. package/skills/ce-brainstorm/references/blindspot-pass.md +70 -0
  32. package/skills/ce-brainstorm/references/brainstorm-sections.md +458 -0
  33. package/skills/ce-brainstorm/references/dialogue.md +89 -0
  34. package/skills/ce-brainstorm/references/handoff.md +187 -0
  35. package/skills/ce-brainstorm/references/html-rendering.md +638 -0
  36. package/skills/ce-brainstorm/references/interaction-rules.md +33 -0
  37. package/skills/ce-brainstorm/references/markdown-rendering.md +242 -0
  38. package/skills/ce-brainstorm/references/model-tiers.md +13 -0
  39. package/skills/ce-brainstorm/references/output-mode.md +26 -0
  40. package/skills/ce-brainstorm/references/phase-0.md +104 -0
  41. package/skills/ce-brainstorm/references/plan-write.md +32 -0
  42. package/skills/ce-brainstorm/references/product-pressure-test.md +42 -0
  43. package/skills/ce-brainstorm/references/reasoning-elevation.md +124 -0
  44. package/skills/ce-brainstorm/references/settled-decisions.md +45 -0
  45. package/skills/ce-brainstorm/references/synthesis-summary.md +149 -0
  46. package/skills/ce-brainstorm/references/universal-brainstorming.md +72 -0
  47. package/skills/ce-brainstorm/references/verdict-routing.md +26 -0
  48. package/skills/ce-brainstorm/references/visual-probes.md +164 -0
  49. package/skills/ce-brainstorm/scripts/elevation-dispatch.sh +288 -0
  50. package/skills/ce-brainstorm/scripts/light-webserver.js +1275 -0
  51. package/skills/ce-brainstorm/scripts/packs-resolve.py +737 -0
  52. package/skills/ce-brainstorm/scripts/peer-job-runner.py +2594 -0
  53. package/skills/ce-code-review/SKILL.md +40 -0
  54. package/skills/ce-code-review/references/action-class-rubric.md +67 -0
  55. package/skills/ce-code-review/references/cross-model-recovery.md +38 -0
  56. package/skills/ce-code-review/references/cross-model-review.md +191 -0
  57. package/skills/ce-code-review/references/depth-paths.md +32 -0
  58. package/skills/ce-code-review/references/diff-scope.md +59 -0
  59. package/skills/ce-code-review/references/dispatch-reviewers.md +135 -0
  60. package/skills/ce-code-review/references/findings-schema.json +125 -0
  61. package/skills/ce-code-review/references/finish-input.md +118 -0
  62. package/skills/ce-code-review/references/finish-review.md +202 -0
  63. package/skills/ce-code-review/references/intent-and-plan.md +73 -0
  64. package/skills/ce-code-review/references/modes-and-output.md +156 -0
  65. package/skills/ce-code-review/references/persona-catalog.md +66 -0
  66. package/skills/ce-code-review/references/personas/adversarial-reviewer.md +111 -0
  67. package/skills/ce-code-review/references/personas/agent-native-reviewer.md +173 -0
  68. package/skills/ce-code-review/references/personas/api-contract-reviewer.md +44 -0
  69. package/skills/ce-code-review/references/personas/correctness-reviewer.md +48 -0
  70. package/skills/ce-code-review/references/personas/data-migration-reviewer.md +111 -0
  71. package/skills/ce-code-review/references/personas/deployment-verification-agent.md +157 -0
  72. package/skills/ce-code-review/references/personas/julik-frontend-races-reviewer.md +45 -0
  73. package/skills/ce-code-review/references/personas/learnings-researcher.md +260 -0
  74. package/skills/ce-code-review/references/personas/maintainability-reviewer.md +85 -0
  75. package/skills/ce-code-review/references/personas/performance-reviewer.md +45 -0
  76. package/skills/ce-code-review/references/personas/previous-comments-reviewer.md +59 -0
  77. package/skills/ce-code-review/references/personas/project-standards-reviewer.md +77 -0
  78. package/skills/ce-code-review/references/personas/reliability-reviewer.md +49 -0
  79. package/skills/ce-code-review/references/personas/security-reviewer.md +50 -0
  80. package/skills/ce-code-review/references/personas/swift-ios-reviewer.md +99 -0
  81. package/skills/ce-code-review/references/personas/testing-reviewer.md +51 -0
  82. package/skills/ce-code-review/references/review-output-template.md +172 -0
  83. package/skills/ce-code-review/references/scope.md +176 -0
  84. package/skills/ce-code-review/references/select-and-route.md +93 -0
  85. package/skills/ce-code-review/references/subagent-template.md +206 -0
  86. package/skills/ce-code-review/references/validator-batch-template.md +67 -0
  87. package/skills/ce-code-review/scripts/cross-model-adversarial-review.sh +1275 -0
  88. package/skills/ce-code-review/scripts/findings-mechanics.py +274 -0
  89. package/skills/ce-code-review/scripts/packs-resolve.py +737 -0
  90. package/skills/ce-code-review/scripts/peer-job-runner.py +2594 -0
  91. package/skills/ce-code-review/scripts/review-scope.py +419 -0
  92. package/skills/ce-code-review/scripts/run-log.py +280 -0
  93. package/skills/ce-commit/SKILL.md +60 -0
  94. package/skills/ce-commit-push-pr/SKILL.md +69 -0
  95. package/skills/ce-commit-push-pr/references/apply-and-handoff.md +79 -0
  96. package/skills/ce-commit-push-pr/references/branch-creation.md +47 -0
  97. package/skills/ce-commit-push-pr/references/commit-and-push.md +26 -0
  98. package/skills/ce-commit-push-pr/references/compose.md +29 -0
  99. package/skills/ce-commit-push-pr/references/context.md +42 -0
  100. package/skills/ce-commit-push-pr/references/gh-stack-cli.md +83 -0
  101. package/skills/ce-commit-push-pr/references/pr-description-writing.md +208 -0
  102. package/skills/ce-commit-push-pr/references/stack-submit.md +81 -0
  103. package/skills/ce-compound/SKILL.md +79 -0
  104. package/skills/ce-compound/assets/resolution-template.md +96 -0
  105. package/skills/ce-compound/references/agents/best-practices-researcher.md +115 -0
  106. package/skills/ce-compound/references/agents/data-integrity-guardian.md +68 -0
  107. package/skills/ce-compound/references/agents/framework-docs-researcher.md +93 -0
  108. package/skills/ce-compound/references/agents/pattern-recognition-specialist.md +55 -0
  109. package/skills/ce-compound/references/agents/performance-oracle.md +108 -0
  110. package/skills/ce-compound/references/agents/security-sentinel.md +91 -0
  111. package/skills/ce-compound/references/agents/session-historian.md +82 -0
  112. package/skills/ce-compound/references/assembly.md +127 -0
  113. package/skills/ce-compound/references/concepts-vocabulary.md +98 -0
  114. package/skills/ce-compound/references/enhancement.md +42 -0
  115. package/skills/ce-compound/references/grounding-validation.md +89 -0
  116. package/skills/ce-compound/references/lightweight.md +56 -0
  117. package/skills/ce-compound/references/modes.md +13 -0
  118. package/skills/ce-compound/references/refresh-and-discoverability.md +96 -0
  119. package/skills/ce-compound/references/report.md +115 -0
  120. package/skills/ce-compound/references/research.md +144 -0
  121. package/skills/ce-compound/references/schema.yaml +236 -0
  122. package/skills/ce-compound/references/session-history.md +73 -0
  123. package/skills/ce-compound/references/yaml-schema.md +130 -0
  124. package/skills/ce-compound/scripts/packs-resolve.py +737 -0
  125. package/skills/ce-compound/scripts/session-history/__pycache__/dsh_session.cpython-314.pyc +0 -0
  126. package/skills/ce-compound/scripts/session-history/discover-sessions.sh +290 -0
  127. package/skills/ce-compound/scripts/session-history/discover_dsh.py +123 -0
  128. package/skills/ce-compound/scripts/session-history/dsh_session.py +225 -0
  129. package/skills/ce-compound/scripts/session-history/extract-errors.py +178 -0
  130. package/skills/ce-compound/scripts/session-history/extract-metadata.py +301 -0
  131. package/skills/ce-compound/scripts/session-history/extract-skeleton.py +346 -0
  132. package/skills/ce-compound/scripts/validate-doc-claims.py +497 -0
  133. package/skills/ce-compound/scripts/validate-frontmatter.py +137 -0
  134. package/skills/ce-compound-refresh/SKILL.md +88 -0
  135. package/skills/ce-compound-refresh/assets/resolution-template.md +96 -0
  136. package/skills/ce-compound-refresh/references/classify.md +42 -0
  137. package/skills/ce-compound-refresh/references/commit.md +7 -0
  138. package/skills/ce-compound-refresh/references/concepts-vocabulary.md +116 -0
  139. package/skills/ce-compound-refresh/references/discoverability.md +15 -0
  140. package/skills/ce-compound-refresh/references/investigate.md +23 -0
  141. package/skills/ce-compound-refresh/references/modes.md +27 -0
  142. package/skills/ce-compound-refresh/references/per-action-flows.md +142 -0
  143. package/skills/ce-compound-refresh/references/report.md +23 -0
  144. package/skills/ce-compound-refresh/references/schema.yaml +236 -0
  145. package/skills/ce-compound-refresh/references/scope.md +18 -0
  146. package/skills/ce-compound-refresh/references/worth-audit.md +35 -0
  147. package/skills/ce-compound-refresh/references/yaml-schema.md +130 -0
  148. package/skills/ce-compound-refresh/scripts/validate-doc-claims.py +497 -0
  149. package/skills/ce-compound-refresh/scripts/validate-frontmatter.py +137 -0
  150. package/skills/ce-debug/SKILL.md +122 -0
  151. package/skills/ce-debug/references/anti-patterns.md +91 -0
  152. package/skills/ce-debug/references/defense-in-depth.md +39 -0
  153. package/skills/ce-debug/references/fix.md +21 -0
  154. package/skills/ce-debug/references/investigate.md +114 -0
  155. package/skills/ce-debug/references/investigation-techniques.md +384 -0
  156. package/skills/ce-debug/references/pipeline-mode.md +78 -0
  157. package/skills/ce-debug/references/post-fix-handoff.md +60 -0
  158. package/skills/ce-debug/references/return-to-caller.md +57 -0
  159. package/skills/ce-doc-review/SKILL.md +75 -0
  160. package/skills/ce-doc-review/references/bulk-preview.md +146 -0
  161. package/skills/ce-doc-review/references/cross-model-review.md +207 -0
  162. package/skills/ce-doc-review/references/decision-primer.md +47 -0
  163. package/skills/ce-doc-review/references/dispatch.md +56 -0
  164. package/skills/ce-doc-review/references/document-intake.md +44 -0
  165. package/skills/ce-doc-review/references/findings-schema.json +85 -0
  166. package/skills/ce-doc-review/references/modes.md +20 -0
  167. package/skills/ce-doc-review/references/open-questions-defer.md +158 -0
  168. package/skills/ce-doc-review/references/persona-selection.md +41 -0
  169. package/skills/ce-doc-review/references/personas/adversarial-document-reviewer.md +109 -0
  170. package/skills/ce-doc-review/references/personas/coherence-reviewer.md +69 -0
  171. package/skills/ce-doc-review/references/personas/design-lens-reviewer.md +48 -0
  172. package/skills/ce-doc-review/references/personas/feasibility-reviewer.md +50 -0
  173. package/skills/ce-doc-review/references/personas/product-lens-reviewer.md +85 -0
  174. package/skills/ce-doc-review/references/personas/scope-guardian-reviewer.md +83 -0
  175. package/skills/ce-doc-review/references/personas/security-lens-reviewer.md +41 -0
  176. package/skills/ce-doc-review/references/personas/whole-doc-reviewer.md +25 -0
  177. package/skills/ce-doc-review/references/rendering-floor.md +175 -0
  178. package/skills/ce-doc-review/references/review-output-template.md +123 -0
  179. package/skills/ce-doc-review/references/subagent-template.md +188 -0
  180. package/skills/ce-doc-review/references/synthesis-and-presentation.md +350 -0
  181. package/skills/ce-doc-review/references/walkthrough.md +347 -0
  182. package/skills/ce-doc-review/scripts/cross-model-doc-review.sh +1270 -0
  183. package/skills/ce-doc-review/scripts/packs-resolve.py +737 -0
  184. package/skills/ce-doc-review/scripts/peer-job-runner.py +2594 -0
  185. package/skills/ce-dogfood/SKILL.md +66 -0
  186. package/skills/ce-dogfood/agents/openai.yaml +2 -0
  187. package/skills/ce-dogfood/references/dogfood-report-template.md +97 -0
  188. package/skills/ce-dogfood/references/phases.md +167 -0
  189. package/skills/ce-dogfood/references/test-matrix-taxonomy.md +62 -0
  190. package/skills/ce-dogfood/scripts/packs-resolve.py +737 -0
  191. package/skills/ce-explain/SKILL.md +81 -0
  192. package/skills/ce-explain/references/agents/behavior-trace-scout.md +19 -0
  193. package/skills/ce-explain/references/agents/work-recap-scout.md +23 -0
  194. package/skills/ce-explain/references/check-in.md +18 -0
  195. package/skills/ce-explain/references/destinations.md +35 -0
  196. package/skills/ce-explain/references/explainer-html.md +29 -0
  197. package/skills/ce-explain/references/explainer-markdown.md +24 -0
  198. package/skills/ce-explain/references/intake.md +50 -0
  199. package/skills/ce-explain/references/orchestration.md +46 -0
  200. package/skills/ce-handoff/SKILL.md +54 -0
  201. package/skills/ce-handoff/references/create.md +88 -0
  202. package/skills/ce-handoff/references/resume.md +46 -0
  203. package/skills/ce-ideate/SKILL.md +75 -0
  204. package/skills/ce-ideate/references/agents/issue-intelligence-analyst.md +166 -0
  205. package/skills/ce-ideate/references/agents/learnings-researcher.md +247 -0
  206. package/skills/ce-ideate/references/agents/slack-researcher.md +127 -0
  207. package/skills/ce-ideate/references/agents/web-researcher.md +121 -0
  208. package/skills/ce-ideate/references/decomposition.md +39 -0
  209. package/skills/ce-ideate/references/divergent-ideation.md +112 -0
  210. package/skills/ce-ideate/references/grounding.md +138 -0
  211. package/skills/ce-ideate/references/html-rendering.md +638 -0
  212. package/skills/ce-ideate/references/ideation-sections.md +191 -0
  213. package/skills/ce-ideate/references/issue-intelligence.md +44 -0
  214. package/skills/ce-ideate/references/markdown-rendering.md +242 -0
  215. package/skills/ce-ideate/references/output-mode.md +34 -0
  216. package/skills/ce-ideate/references/post-ideation-workflow.md +169 -0
  217. package/skills/ce-ideate/references/scope-gates.md +148 -0
  218. package/skills/ce-ideate/references/universal-ideation.md +119 -0
  219. package/skills/ce-ideate/references/user-research-artifacts.md +28 -0
  220. package/skills/ce-ideate/references/web-research-cache.md +56 -0
  221. package/skills/ce-noslop/SKILL.md +45 -0
  222. package/skills/ce-noslop/references/patterns.md +61 -0
  223. package/skills/ce-noslop/references/terminology.md +3 -0
  224. package/skills/ce-optimize/SKILL.md +64 -0
  225. package/skills/ce-optimize/references/agents/learnings-researcher.md +247 -0
  226. package/skills/ce-optimize/references/agents/repo-research-analyst.md +258 -0
  227. package/skills/ce-optimize/references/example-expensive-benchmark-spec.yaml +88 -0
  228. package/skills/ce-optimize/references/example-hard-spec.yaml +64 -0
  229. package/skills/ce-optimize/references/example-judge-spec.yaml +83 -0
  230. package/skills/ce-optimize/references/example-text-target-spec.yaml +80 -0
  231. package/skills/ce-optimize/references/experiment-log-schema.yaml +563 -0
  232. package/skills/ce-optimize/references/experiment-prompt-template.md +143 -0
  233. package/skills/ce-optimize/references/judge-prompt-template.md +117 -0
  234. package/skills/ce-optimize/references/loop.md +286 -0
  235. package/skills/ce-optimize/references/measurement.md +168 -0
  236. package/skills/ce-optimize/references/optimize-spec-schema.yaml +570 -0
  237. package/skills/ce-optimize/references/persistence.md +93 -0
  238. package/skills/ce-optimize/references/spec.md +107 -0
  239. package/skills/ce-optimize/references/text-targets.md +51 -0
  240. package/skills/ce-optimize/references/usage-guide.md +147 -0
  241. package/skills/ce-optimize/references/wrap-up.md +54 -0
  242. package/skills/ce-optimize/scripts/decide.mjs +676 -0
  243. package/skills/ce-optimize/scripts/experiment-worktree.sh +330 -0
  244. package/skills/ce-optimize/scripts/measure.sh +140 -0
  245. package/skills/ce-optimize/scripts/parallel-probe.sh +134 -0
  246. package/skills/ce-plan/SKILL.md +60 -0
  247. package/skills/ce-plan/references/agents/agent-native-planning-strategist.md +66 -0
  248. package/skills/ce-plan/references/agents/architecture-strategist.md +46 -0
  249. package/skills/ce-plan/references/agents/best-practices-researcher.md +118 -0
  250. package/skills/ce-plan/references/agents/data-integrity-guardian.md +68 -0
  251. package/skills/ce-plan/references/agents/framework-docs-researcher.md +97 -0
  252. package/skills/ce-plan/references/agents/git-history-analyzer.md +40 -0
  253. package/skills/ce-plan/references/agents/learnings-researcher.md +268 -0
  254. package/skills/ce-plan/references/agents/pattern-recognition-specialist.md +55 -0
  255. package/skills/ce-plan/references/agents/performance-oracle.md +108 -0
  256. package/skills/ce-plan/references/agents/repo-research-analyst.md +262 -0
  257. package/skills/ce-plan/references/agents/security-sentinel.md +91 -0
  258. package/skills/ce-plan/references/agents/slack-researcher.md +131 -0
  259. package/skills/ce-plan/references/agents/spec-flow-analyzer.md +84 -0
  260. package/skills/ce-plan/references/agents/web-researcher.md +125 -0
  261. package/skills/ce-plan/references/approach-altitude.md +55 -0
  262. package/skills/ce-plan/references/bakeoff.md +9 -0
  263. package/skills/ce-plan/references/deepening-workflow.md +263 -0
  264. package/skills/ce-plan/references/final-review.md +134 -0
  265. package/skills/ce-plan/references/html-rendering.md +638 -0
  266. package/skills/ce-plan/references/intake.md +158 -0
  267. package/skills/ce-plan/references/markdown-rendering.md +242 -0
  268. package/skills/ce-plan/references/output-contracts.md +29 -0
  269. package/skills/ce-plan/references/output-mode.md +45 -0
  270. package/skills/ce-plan/references/plan-handoff.md +116 -0
  271. package/skills/ce-plan/references/plan-sections.md +489 -0
  272. package/skills/ce-plan/references/reasoning-elevation.md +124 -0
  273. package/skills/ce-plan/references/research.md +211 -0
  274. package/skills/ce-plan/references/resume.md +61 -0
  275. package/skills/ce-plan/references/settled-decisions.md +45 -0
  276. package/skills/ce-plan/references/structure.md +207 -0
  277. package/skills/ce-plan/references/synthesis-summary.md +260 -0
  278. package/skills/ce-plan/references/universal-planning.md +170 -0
  279. package/skills/ce-plan/scripts/elevation-dispatch.sh +288 -0
  280. package/skills/ce-plan/scripts/packs-resolve.py +737 -0
  281. package/skills/ce-plan/scripts/peer-job-runner.py +2594 -0
  282. package/skills/ce-polish/SKILL.md +22 -0
  283. package/skills/ce-polish/agents/openai.yaml +2 -0
  284. package/skills/ce-polish/references/dev-server-astro.md +58 -0
  285. package/skills/ce-polish/references/dev-server-detection.md +40 -0
  286. package/skills/ce-polish/references/dev-server-next.md +61 -0
  287. package/skills/ce-polish/references/dev-server-nuxt.md +58 -0
  288. package/skills/ce-polish/references/dev-server-procfile.md +59 -0
  289. package/skills/ce-polish/references/dev-server-rails.md +50 -0
  290. package/skills/ce-polish/references/dev-server-remix.md +58 -0
  291. package/skills/ce-polish/references/dev-server-sveltekit.md +58 -0
  292. package/skills/ce-polish/references/dev-server-vite.md +48 -0
  293. package/skills/ce-polish/references/install-riffrec.md +35 -0
  294. package/skills/ce-polish/references/launch-json-schema.md +177 -0
  295. package/skills/ce-polish/references/live-loop.md +98 -0
  296. package/skills/ce-polish/references/live-remote.md +35 -0
  297. package/skills/ce-polish/references/live-start.md +93 -0
  298. package/skills/ce-polish/references/live-stream-contract.md +253 -0
  299. package/skills/ce-polish/references/run.md +67 -0
  300. package/skills/ce-polish/scripts/detect-project-type.sh +277 -0
  301. package/skills/ce-polish/scripts/detect-riffrec.sh +225 -0
  302. package/skills/ce-polish/scripts/live-endpoint.js +2841 -0
  303. package/skills/ce-polish/scripts/read-launch-json.sh +117 -0
  304. package/skills/ce-polish/scripts/resolve-package-manager.sh +95 -0
  305. package/skills/ce-polish/scripts/resolve-port.sh +307 -0
  306. package/skills/ce-pov/SKILL.md +64 -0
  307. package/skills/ce-pov/references/agents/external-evidence-researcher.md +26 -0
  308. package/skills/ce-pov/references/agents/pov-peer.md +43 -0
  309. package/skills/ce-pov/references/agents/precedent-activity-scout.md +21 -0
  310. package/skills/ce-pov/references/agents/project-grounding-scout.md +32 -0
  311. package/skills/ce-pov/references/boundaries.md +36 -0
  312. package/skills/ce-pov/references/cross-model-panel.md +596 -0
  313. package/skills/ce-pov/references/followup.md +9 -0
  314. package/skills/ce-pov/references/grounding.md +47 -0
  315. package/skills/ce-pov/references/intake.md +61 -0
  316. package/skills/ce-pov/references/invocation.md +47 -0
  317. package/skills/ce-pov/references/method.md +68 -0
  318. package/skills/ce-pov/references/pov-schema.json +56 -0
  319. package/skills/ce-pov/references/report.md +7 -0
  320. package/skills/ce-pov/scripts/cross-model-pov.sh +1110 -0
  321. package/skills/ce-pov/scripts/peer-job-runner.py +2594 -0
  322. package/skills/ce-product-pulse/SKILL.md +81 -0
  323. package/skills/ce-product-pulse/agents/openai.yaml +2 -0
  324. package/skills/ce-product-pulse/references/config.md +20 -0
  325. package/skills/ce-product-pulse/references/interview.md +260 -0
  326. package/skills/ce-product-pulse/references/report-template.md +89 -0
  327. package/skills/ce-product-pulse/references/run.md +46 -0
  328. package/skills/ce-product-pulse/references/setup.md +43 -0
  329. package/skills/ce-promote/SKILL.md +90 -0
  330. package/skills/ce-promote/agents/openai.yaml +2 -0
  331. package/skills/ce-promote/references/spiral-cli.md +149 -0
  332. package/skills/ce-proof/SKILL.md +65 -0
  333. package/skills/ce-proof/references/api.md +176 -0
  334. package/skills/ce-proof/references/workflows.md +124 -0
  335. package/skills/ce-prototype/SKILL.md +59 -0
  336. package/skills/ce-prototype/assets/annotate.css +206 -0
  337. package/skills/ce-prototype/assets/annotate.js +837 -0
  338. package/skills/ce-prototype/references/annotation-loop.md +32 -0
  339. package/skills/ce-prototype/references/build.md +39 -0
  340. package/skills/ce-prototype/references/craft-floor.md +43 -0
  341. package/skills/ce-prototype/references/preview.md +118 -0
  342. package/skills/ce-prototype/references/scoping.md +38 -0
  343. package/skills/ce-prototype/references/write-back.md +37 -0
  344. package/skills/ce-prototype/scripts/light-webserver.js +1275 -0
  345. package/skills/ce-resolve-pr-feedback/SKILL.md +60 -0
  346. package/skills/ce-resolve-pr-feedback/references/agents/pr-comment-resolver.md +59 -0
  347. package/skills/ce-resolve-pr-feedback/references/evaluation-rubric.md +141 -0
  348. package/skills/ce-resolve-pr-feedback/references/full-mode.md +336 -0
  349. package/skills/ce-resolve-pr-feedback/references/pipeline-mode.md +23 -0
  350. package/skills/ce-resolve-pr-feedback/references/resume.md +60 -0
  351. package/skills/ce-resolve-pr-feedback/references/return-to-caller.md +111 -0
  352. package/skills/ce-resolve-pr-feedback/references/targeted-mode.md +48 -0
  353. package/skills/ce-resolve-pr-feedback/scripts/get-pr-comments +176 -0
  354. package/skills/ce-resolve-pr-feedback/scripts/get-thread-for-comment +84 -0
  355. package/skills/ce-resolve-pr-feedback/scripts/pending-feedback.py +287 -0
  356. package/skills/ce-resolve-pr-feedback/scripts/reply-to-pr-thread +57 -0
  357. package/skills/ce-resolve-pr-feedback/scripts/resolve-pr-thread +23 -0
  358. package/skills/ce-retune/SKILL.md +42 -0
  359. package/skills/ce-retune/agents/openai.yaml +2 -0
  360. package/skills/ce-retune/references/baseline-mining.md +122 -0
  361. package/skills/ce-retune/references/corpus-audit.md +128 -0
  362. package/skills/ce-retune/references/cut-passes.md +129 -0
  363. package/skills/ce-retune/references/halt-taxonomy.md +123 -0
  364. package/skills/ce-retune/references/noise-floor.md +131 -0
  365. package/skills/ce-retune/references/workflow-shapes.md +73 -0
  366. package/skills/ce-riffrec-feedback-analysis/SKILL.md +33 -0
  367. package/skills/ce-riffrec-feedback-analysis/references/analyzer.md +18 -0
  368. package/skills/ce-riffrec-feedback-analysis/references/compound-engineering-feedback-format.md +116 -0
  369. package/skills/ce-riffrec-feedback-analysis/references/extensive-analysis.md +98 -0
  370. package/skills/ce-riffrec-feedback-analysis/references/install-riffrec.md +27 -0
  371. package/skills/ce-riffrec-feedback-analysis/references/quick-bug-report.md +38 -0
  372. package/skills/ce-riffrec-feedback-analysis/scripts/analyze_riffrec_zip.py +1306 -0
  373. package/skills/ce-setup/SKILL.md +103 -0
  374. package/skills/ce-setup/agents/openai.yaml +2 -0
  375. package/skills/ce-setup/assets/compounding-directive.md +11 -0
  376. package/skills/ce-setup/assets/noslop-directive.md +7 -0
  377. package/skills/ce-setup/assets/pack-rule-template.md +11 -0
  378. package/skills/ce-setup/references/acpx-cache-warm.md +14 -0
  379. package/skills/ce-setup/references/config-template.yaml +210 -0
  380. package/skills/ce-setup/references/legacy-codex-tool-map.md +15 -0
  381. package/skills/ce-setup/references/pack-scaffold.md +45 -0
  382. package/skills/ce-setup/references/repo-fixes.md +121 -0
  383. package/skills/ce-setup/scripts/check-health +929 -0
  384. package/skills/ce-setup/scripts/packs-resolve.py +737 -0
  385. package/skills/ce-simplify-code/SKILL.md +76 -0
  386. package/skills/ce-simplify-code/references/personas/code-quality-reviewer.md +17 -0
  387. package/skills/ce-simplify-code/references/personas/code-reuse-reviewer.md +7 -0
  388. package/skills/ce-simplify-code/references/personas/comment-reviewer.md +24 -0
  389. package/skills/ce-simplify-code/references/personas/efficiency-reviewer.md +11 -0
  390. package/skills/ce-simplify-code/references/personas/test-value-reviewer.md +23 -0
  391. package/skills/ce-simplify-code/references/reviewer-dispatch.md +11 -0
  392. package/skills/ce-simplify-code/references/standalone-report.md +25 -0
  393. package/skills/ce-strategy/SKILL.md +61 -0
  394. package/skills/ce-strategy/references/grounding.md +22 -0
  395. package/skills/ce-strategy/references/interview.md +179 -0
  396. package/skills/ce-strategy/references/strategy-template.md +94 -0
  397. package/skills/ce-strategy/references/update-run.md +33 -0
  398. package/skills/ce-sweep/SKILL.md +93 -0
  399. package/skills/ce-sweep/agents/openai.yaml +2 -0
  400. package/skills/ce-sweep/references/agents/media-analyzer.md +54 -0
  401. package/skills/ce-sweep/references/interview.md +208 -0
  402. package/skills/ce-sweep/references/model-tiers.md +13 -0
  403. package/skills/ce-sweep/references/plan-template.md +62 -0
  404. package/skills/ce-sweep/references/run.md +126 -0
  405. package/skills/ce-sweep/references/sources/email.md +57 -0
  406. package/skills/ce-sweep/references/sources/github-issues.md +59 -0
  407. package/skills/ce-sweep/references/sources/slack.md +61 -0
  408. package/skills/ce-sweep/references/state-schema.md +157 -0
  409. package/skills/ce-sweep/references/subagent-template.md +60 -0
  410. package/skills/ce-sweep/scripts/analyze_riffrec_zip.py +1306 -0
  411. package/skills/ce-sweep/scripts/sweep-state.py +793 -0
  412. package/skills/ce-test-browser/SKILL.md +50 -0
  413. package/skills/ce-test-browser/references/agent-browser-driver.md +47 -0
  414. package/skills/ce-test-browser/references/pipeline-orchestration.md +45 -0
  415. package/skills/ce-test-browser/references/route-and-report.md +129 -0
  416. package/skills/ce-test-browser/scripts/resolve-port.sh +41 -0
  417. package/skills/ce-test-xcode/SKILL.md +26 -0
  418. package/skills/ce-test-xcode/agents/openai.yaml +2 -0
  419. package/skills/ce-test-xcode/references/setup-and-build.md +32 -0
  420. package/skills/ce-test-xcode/references/test-and-report.md +64 -0
  421. package/skills/ce-work/SKILL.md +62 -0
  422. package/skills/ce-work/references/agents/figma-design-sync.md +27 -0
  423. package/skills/ce-work/references/agents/implementation-worker.md +17 -0
  424. package/skills/ce-work/references/cross-model-execution.md +191 -0
  425. package/skills/ce-work/references/execution-engines.md +64 -0
  426. package/skills/ce-work/references/execution-strategy.md +73 -0
  427. package/skills/ce-work/references/implementation-loop.md +107 -0
  428. package/skills/ce-work/references/implementation-result-schema.json +52 -0
  429. package/skills/ce-work/references/input-triage.md +50 -0
  430. package/skills/ce-work/references/non-code-execution.md +23 -0
  431. package/skills/ce-work/references/return-to-caller.md +33 -0
  432. package/skills/ce-work/references/review-findings-followup.md +82 -0
  433. package/skills/ce-work/references/shipping-workflow.md +89 -0
  434. package/skills/ce-work/references/tracker-defer.md +150 -0
  435. package/skills/ce-work/references/work-intake.md +51 -0
  436. package/skills/ce-work/references/workspace-setup.md +27 -0
  437. package/skills/ce-work/scripts/__pycache__/unit_workspace_jobs.cpython-314.pyc +0 -0
  438. package/skills/ce-work/scripts/__pycache__/unit_workspace_state.cpython-314.pyc +0 -0
  439. package/skills/ce-work/scripts/cross-model-work.sh +1385 -0
  440. package/skills/ce-work/scripts/peer-job-runner.py +2594 -0
  441. package/skills/ce-work/scripts/unit-workspace.py +215 -0
  442. package/skills/ce-work/scripts/unit_workspace_ignored.py +93 -0
  443. package/skills/ce-work/scripts/unit_workspace_integration.py +677 -0
  444. package/skills/ce-work/scripts/unit_workspace_jobs.py +1216 -0
  445. package/skills/ce-work/scripts/unit_workspace_lifecycle.py +981 -0
  446. package/skills/ce-work/scripts/unit_workspace_state.py +1379 -0
  447. package/skills/ce-work/scripts/unit_workspace_transaction.py +612 -0
  448. package/skills/ce-worktree/SKILL.md +54 -0
  449. package/skills/lfg/SKILL.md +59 -0
  450. package/skills/lfg/references/debug-return.md +25 -0
  451. package/skills/lfg/references/intake.md +30 -0
  452. package/skills/lfg/references/next-work-handoff.md +96 -0
  453. package/skills/lfg/references/plan-brief.md +36 -0
  454. package/skills/lfg/references/review-followup.md +78 -0
  455. package/skills/lfg/references/shipping.md +65 -0
  456. package/skills/lfg/references/stage-routing.md +49 -0
  457. package/skills/lfg/references/task-visibility.md +11 -0
  458. package/skills/lfg/references/tracker-defer.md +150 -0
  459. package/skills/lfg/references/work-return.md +27 -0
  460. package/skills/wtf/SKILL.md +33 -0
  461. package/skills/wtf/agents/openai.yaml +2 -0
@@ -0,0 +1,737 @@
1
+ #!/usr/bin/env python3
2
+ """Resolve the Compound Packs declared in this repo's CE config into pack roots.
3
+
4
+ Reads the `packs:` list from `<repo-root>/.compound-engineering/config.yaml`
5
+ and `config.local.yaml` (both layers concatenate; local adds, never replaces),
6
+ validates each entry, resolves path and git sources, enumerates the packs each
7
+ source publishes, applies selection, and prints one JSON object to stdout:
8
+
9
+ {"roots": [{"id": "...", "dir": "/abs/path", "nested_rule_shaped": 0}],
10
+ "warnings": [...], "errors": [...], "entries": <number of parsed packs entries>}
11
+
12
+ `nested_rule_shaped` counts the rule-shaped `.md` files one level below the
13
+ pack's top level. Discovery never reads them (subdirectories are storage), so
14
+ the count is informational and is reported by the health check, not warned.
15
+
16
+ Exit 0 whenever resolution ran (per-entry failures are data in `errors` /
17
+ `warnings`); non-zero only when the resolver itself cannot run. Consumers treat
18
+ `errors` as loud per-entry configuration problems and `warnings` as degraded
19
+ availability (e.g. an unreachable git source skipped per the warn-and-continue
20
+ contract).
21
+
22
+ `--declared-only` answers the config-only question without touching git or the
23
+ cache: it parses both config layers, shape-checks each entry, and prints
24
+
25
+ {"declared": <bool|null>, "entries": <n>, "errors": [...]}
26
+
27
+ where `declared` is true when any entry parsed or the `packs:` block is
28
+ malformed (a broken declaration is still a declaration the consumer should
29
+ surface), false when neither config layer names packs, and null when no
30
+ repository -- and so no config -- could be located.
31
+
32
+ Entry shape (documented subset -- anything else under `packs:` is a loud error):
33
+
34
+ packs:
35
+ - source: packs/local-rules # repo-relative path
36
+ - source: ~/packs/kk-style # ~ or absolute path
37
+ - source: https://github.com/o/r # git URL: ref required
38
+ ref: v1.2.0 # tag, sha, or branch
39
+ path: packs # optional subfolder (git only)
40
+ pack: [rails, inertia] # one id, a list, or omit = all
41
+ id: rails-core # rename (single-pack entries)
42
+ - source: https://github.com/o/r/tree/main/packs # tree-URL sugar
43
+
44
+ Git sources cache under `<scratch-root>/ce-packs/<sha256(url\\nref)>` with an
45
+ atomic temp-clone-then-rename, so a keyed path's existence proves a complete
46
+ clone. All git subprocesses run non-interactively (GIT_TERMINAL_PROMPT=0, ssh
47
+ BatchMode, bounded timeout): missing credentials degrade to a warning, never a
48
+ hang. A missing `git` binary degrades git sources only (each warns and is
49
+ skipped); path sources still resolve, with the repository located by walking up
50
+ from the working directory to the nearest `.git` entry. Environment overrides:
51
+ CE_PACKS_CACHE_ROOT (cache base for tests), CE_PACKS_GIT_TIMEOUT (seconds,
52
+ default 60).
53
+
54
+ A published pack is a directory a consumer lists and reads itself, so nothing
55
+ in it may link outside its source: a pack whose tree holds such a link is not
56
+ published (a loud per-entry error), never trimmed a file at a time.
57
+ """
58
+
59
+ from __future__ import annotations
60
+
61
+ import argparse
62
+ import functools
63
+ import hashlib
64
+ import json
65
+ import os
66
+ import re
67
+ import shutil
68
+ import stat
69
+ import subprocess
70
+ import sys
71
+ import tempfile
72
+
73
+ IS_WINDOWS = os.name == "nt"
74
+ _uid_getter = getattr(os, "geteuid", None) or getattr(os, "getuid", None)
75
+ _EFFECTIVE_UID = _uid_getter() if _uid_getter is not None else None
76
+ GIT_TIMEOUT = float(os.environ.get("CE_PACKS_GIT_TIMEOUT") or 60)
77
+
78
+ CONFIG_FILES = ("config.yaml", "config.local.yaml")
79
+ KNOWN_KEYS = {"source", "ref", "path", "pack", "id"}
80
+ SCALAR_KEYS = ("source", "ref", "path", "id") # every known key but the list-valued `pack`
81
+ _TREE_URL_RE = re.compile(
82
+ r"^(?P<base>https?://github\.com/[^/\s]+/[^/\s]+?)(?:\.git)?/tree/(?P<ref>[^/\s]+)(?:/(?P<path>[^\s]*))?/?$"
83
+ )
84
+
85
+
86
+ def _is_git_url(source: str) -> bool:
87
+ return bool(
88
+ re.match(r"^(https?|ssh|git|file)://", source) or re.match(r"^[\w.-]+@[\w.-]+:", source)
89
+ )
90
+
91
+
92
+ def _within(path: str, parent: str) -> bool:
93
+ """True when `path` is `parent` or lies below it (both already realpath'd)."""
94
+ return path == parent or path.startswith(parent + os.sep)
95
+
96
+
97
+ # --- scratch root (peer-job-runner shape: probe /tmp, fall back to TMPDIR) ---
98
+
99
+ def _owned_dir(path: str) -> bool:
100
+ """Directory, not a symlink, owned by the effective uid (POSIX)."""
101
+ try:
102
+ st = os.lstat(path)
103
+ except OSError:
104
+ return False
105
+ if not stat.S_ISDIR(st.st_mode):
106
+ return False
107
+ if _EFFECTIVE_UID is not None and st.st_uid != _EFFECTIVE_UID:
108
+ return False
109
+ return True
110
+
111
+
112
+ def _private_root_usable(path: str) -> bool:
113
+ """Create or repair `path` as a private (0700) root owned by this user."""
114
+ try:
115
+ os.mkdir(path, 0o700)
116
+ except FileExistsError:
117
+ pass
118
+ except OSError:
119
+ return False
120
+ if not IS_WINDOWS:
121
+ if not _owned_dir(path):
122
+ return False
123
+ try:
124
+ os.chmod(path, 0o700)
125
+ except OSError:
126
+ return False
127
+ return os.path.isdir(path) and os.access(path, os.W_OK)
128
+
129
+
130
+ def _trusted_checkout(path: str) -> bool:
131
+ """A real directory (never a symlink) that this user owns; ownership is POSIX-only."""
132
+ if os.path.islink(path) or not os.path.isdir(path):
133
+ return False
134
+ return IS_WINDOWS or _owned_dir(path)
135
+
136
+
137
+ @functools.lru_cache(maxsize=None)
138
+ def cache_base() -> str | None:
139
+ configured = os.environ.get("CE_PACKS_CACHE_ROOT")
140
+ if configured:
141
+ root = os.path.abspath(configured)
142
+ os.makedirs(root, exist_ok=True)
143
+ return root
144
+ if IS_WINDOWS:
145
+ base = os.environ.get("LOCALAPPDATA") or tempfile.gettempdir()
146
+ root = os.path.join(base, "compound-engineering-packs")
147
+ return root if _private_root_usable(root) else None
148
+ if _EFFECTIVE_UID is None:
149
+ return None
150
+ for base in ("/tmp", os.environ.get("TMPDIR") or "/tmp"):
151
+ root = os.path.join(base, f"compound-engineering-{_EFFECTIVE_UID}")
152
+ if _private_root_usable(root):
153
+ packs = os.path.join(root, "ce-packs")
154
+ if _private_root_usable(packs):
155
+ return packs
156
+ return None
157
+
158
+
159
+ # --- minimal YAML reader for the documented packs: subset --------------------
160
+
161
+ def _strip_comment(line: str) -> str:
162
+ """Drop a trailing comment (a # preceded by whitespace, outside quotes).
163
+
164
+ A quote toggles quoted state only when it opens a value (start of line or
165
+ after `: `/`- `/`[`/`,`) or closes one it opened -- a mid-word apostrophe
166
+ (``it's``) is ordinary content and must not absorb a later comment.
167
+ """
168
+ out, quote = [], ""
169
+ for i, ch in enumerate(line):
170
+ prev = line[i - 1] if i else " "
171
+ if quote:
172
+ if ch == quote:
173
+ quote = ""
174
+ elif ch in "'\"" and prev in " \t[,:":
175
+ quote = ch
176
+ elif ch == "#" and prev in " \t":
177
+ break
178
+ out.append(ch)
179
+ return "".join(out).rstrip()
180
+
181
+
182
+ def _scalar(raw: str):
183
+ raw = raw.strip()
184
+ if len(raw) >= 2 and raw[0] == raw[-1] and raw[0] in "'\"":
185
+ return raw[1:-1]
186
+ if raw.lower() in ("true", "false"):
187
+ return raw.lower() == "true"
188
+ return raw
189
+
190
+
191
+ def _parse_value(raw: str):
192
+ raw = raw.strip()
193
+ if raw.startswith("[") and raw.endswith("]"):
194
+ inner = raw[1:-1].strip()
195
+ return [] if not inner else [_scalar(part) for part in inner.split(",")]
196
+ return _scalar(raw)
197
+
198
+
199
+ def parse_packs_block(path: str, errors: list) -> list:
200
+ """Return the entry dicts under this file's top-level `packs:` key."""
201
+ if not os.path.isfile(path):
202
+ return []
203
+ with open(path, encoding="utf-8-sig", errors="replace") as fh:
204
+ lines = fh.read().splitlines()
205
+ entries, in_packs, current, pending_list_key = [], False, None, None
206
+ for lineno, raw in enumerate(lines, 1):
207
+ line = _strip_comment(raw)
208
+ if not line.strip():
209
+ continue
210
+ indent = len(line) - len(line.lstrip())
211
+ if indent == 0 and not (in_packs and line.lstrip().startswith("-")):
212
+ # A new top-level key ends the packs block; a zero-indent list item
213
+ # (`- source: ...`) is still part of it -- YAML allows both styles.
214
+ key, sep, rest = line.partition(":")
215
+ in_packs = bool(sep) and key.strip() == "packs" and rest.strip() in ("", "[]")
216
+ if sep and key.strip() == "packs" and not in_packs:
217
+ # `packs: <inline value>` is malformed, not absent: say so rather
218
+ # than letting a flow list or a bare path declare nothing.
219
+ errors.append(
220
+ f"{os.path.basename(path)}:{lineno}: `packs:` must be a block list of"
221
+ f" `- source: ...` entries (got `{line.strip()}`)"
222
+ )
223
+ current, pending_list_key = None, None
224
+ continue
225
+ if not in_packs:
226
+ continue
227
+ stripped = line.strip()
228
+ loc = f"{os.path.basename(path)}:{lineno}"
229
+ if stripped.startswith("- ") or stripped == "-":
230
+ body = stripped[1:].strip()
231
+ if pending_list_key and current is not None and ":" not in body:
232
+ current[pending_list_key].append(_scalar(body))
233
+ continue
234
+ current, pending_list_key = {"_origin": os.path.basename(path), "_line": lineno}, None
235
+ entries.append(current)
236
+ if body:
237
+ if ":" not in body:
238
+ errors.append(f"{loc}: unrecognized packs entry `{stripped}` -- expected `key: value`")
239
+ continue
240
+ key, _, val = body.partition(":")
241
+ _set_key(current, key.strip(), val, loc, errors)
242
+ continue
243
+ if current is None:
244
+ errors.append(f"{loc}: unrecognized line under packs: `{stripped}` -- expected a `- source: ...` entry")
245
+ continue
246
+ if ":" not in stripped:
247
+ errors.append(f"{loc}: unrecognized line under packs: `{stripped}` -- expected `key: value`")
248
+ continue
249
+ key, _, val = stripped.partition(":")
250
+ key = key.strip()
251
+ if val.strip() == "" and key == "pack":
252
+ current[key] = []
253
+ pending_list_key = key
254
+ continue
255
+ pending_list_key = None
256
+ _set_key(current, key, val, loc, errors)
257
+ return entries
258
+
259
+
260
+ def _set_key(entry: dict, key: str, raw_val: str, loc: str, errors: list) -> None:
261
+ if key not in KNOWN_KEYS:
262
+ errors.append(f"{loc}: unknown packs entry key `{key}:` -- accepted keys: {', '.join(sorted(KNOWN_KEYS))}")
263
+ return
264
+ entry[key] = _parse_value(raw_val)
265
+
266
+
267
+ # --- git ---------------------------------------------------------------------
268
+
269
+ @functools.lru_cache(maxsize=None)
270
+ def _git_env() -> dict:
271
+ env = dict(os.environ)
272
+ env["GIT_TERMINAL_PROMPT"] = "0"
273
+ env["GIT_ASKPASS"] = env.get("GIT_ASKPASS") or "true"
274
+ ssh = env.get("GIT_SSH_COMMAND") or "ssh"
275
+ if "BatchMode" not in ssh:
276
+ env["GIT_SSH_COMMAND"] = ssh + " -o BatchMode=yes"
277
+ return env
278
+
279
+
280
+ def _run_git(args: list, cwd: str | None = None):
281
+ return subprocess.run(
282
+ ["git", *args], cwd=cwd, env=_git_env(), timeout=GIT_TIMEOUT,
283
+ capture_output=True, text=True,
284
+ )
285
+
286
+
287
+ def resolve_git_source(url: str, ref: str, warnings: list, label: str) -> str | None:
288
+ """Return the cached checkout dir for url@ref, cloning on miss. None = warn+skip."""
289
+ if shutil.which("git") is None:
290
+ warnings.append(f"{label}: git binary not found; source skipped")
291
+ return None
292
+ base = cache_base()
293
+ if base is None:
294
+ warnings.append(f"{label}: no writable cache root for git sources; source skipped")
295
+ return None
296
+ key = hashlib.sha256(f"{url}\n{ref}".encode()).hexdigest()
297
+ dest = os.path.join(base, key)
298
+ if os.path.lexists(dest):
299
+ if _trusted_checkout(dest):
300
+ return dest
301
+ warnings.append(f"{label}: cached checkout {dest} is a symlink or not owned by this user; refetching")
302
+ # rmtree refuses to follow a symlink (and ignores a plain file); unlink
303
+ # those explicitly so a planted link is removed, never its target.
304
+ shutil.rmtree(dest, ignore_errors=True)
305
+ if os.path.islink(dest) or os.path.isfile(dest):
306
+ try:
307
+ os.unlink(dest)
308
+ except OSError:
309
+ pass
310
+ if os.path.lexists(dest):
311
+ warnings.append(f"{label}: cannot replace untrusted cached checkout {dest}; source skipped")
312
+ return None
313
+ tmp = tempfile.mkdtemp(prefix=f"{key}.part-", dir=base)
314
+ try:
315
+ try:
316
+ proc = _run_git(["clone", "--quiet", "--depth", "1", "--no-recurse-submodules",
317
+ "--branch", ref, "--end-of-options", url, tmp])
318
+ except subprocess.TimeoutExpired:
319
+ warnings.append(f"{label}: git clone timed out after {int(GIT_TIMEOUT)}s; source skipped")
320
+ return None
321
+ if proc.returncode != 0:
322
+ # tag/branch clone failed -- retry treating ref as a commit sha
323
+ try:
324
+ fetched = (
325
+ _run_git(["init", "--quiet", tmp]).returncode == 0
326
+ and _run_git(["fetch", "--quiet", "--depth", "1", "--end-of-options", url, ref], cwd=tmp).returncode == 0
327
+ and _run_git(["checkout", "--quiet", "FETCH_HEAD"], cwd=tmp).returncode == 0
328
+ )
329
+ if not fetched:
330
+ warnings.append(f"{label}: cannot fetch `{ref}` from {url}; source skipped")
331
+ return None
332
+ except subprocess.TimeoutExpired:
333
+ warnings.append(f"{label}: git fetch timed out after {int(GIT_TIMEOUT)}s; source skipped")
334
+ return None
335
+ if not os.path.lexists(dest):
336
+ try:
337
+ os.replace(tmp, dest)
338
+ except OSError:
339
+ # Expected when another resolver published the same key
340
+ # concurrently; anything else leaves no checkout to return.
341
+ if not os.path.lexists(dest):
342
+ warnings.append(f"{label}: could not publish the clone to {dest}; source skipped")
343
+ return None
344
+ if _trusted_checkout(dest):
345
+ return dest
346
+ warnings.append(
347
+ f"{label}: cached checkout {dest} appeared during the clone and is a symlink or not owned by this user; source skipped"
348
+ )
349
+ return None
350
+ finally:
351
+ if os.path.isdir(tmp):
352
+ shutil.rmtree(tmp, ignore_errors=True)
353
+
354
+
355
+ # --- pack enumeration --------------------------------------------------------
356
+
357
+ _FRONTMATTER_KEYS = ("title:", "applies_when:")
358
+ _FRONTMATTER_CAP = 64 * 1024 # frontmatter must close within this many characters
359
+ # A pack's README is its description, never a rule, whatever frontmatter it
360
+ # carries: it is not published, not reported as skipped, and not counted.
361
+ _README = "readme.md"
362
+
363
+
364
+ @functools.lru_cache(maxsize=None)
365
+ def _is_knowledge_file(path: str) -> bool:
366
+ """True when the file opens with a `---` frontmatter block, closed by a `---`
367
+ line within the cap, that carries `title:` and `applies_when:`. A UTF-8 BOM
368
+ is not part of the content."""
369
+ try:
370
+ with open(path, encoding="utf-8-sig", errors="replace") as fh:
371
+ lines = fh.read(_FRONTMATTER_CAP).splitlines()
372
+ except OSError:
373
+ return False
374
+ if not lines or lines[0].strip() != "---":
375
+ return False
376
+ for end, line in enumerate(lines[1:], 1):
377
+ if line.strip() == "---":
378
+ fm = "\n".join(lines[1:end])
379
+ break
380
+ else:
381
+ return False
382
+ return all(re.search(rf"^\s*{re.escape(k)}", fm, re.MULTILINE) for k in _FRONTMATTER_KEYS)
383
+
384
+
385
+ def _contained_md_files(directory: str, boundary: str, escaped: list) -> list:
386
+ """Paths of the `.md` entries directly under `directory`, minus its README,
387
+ whose real path stays within `boundary` (a realpath). An entry that links
388
+ outside it is appended to `escaped` and never opened, so a pack cannot read
389
+ files off the user's machine."""
390
+ try:
391
+ names = sorted(os.listdir(directory))
392
+ except OSError:
393
+ return []
394
+ files = []
395
+ for name in names:
396
+ if not name.endswith(".md") or name.lower() == _README:
397
+ continue
398
+ child = os.path.join(directory, name)
399
+ if _within(os.path.realpath(child), boundary):
400
+ files.append(child)
401
+ else:
402
+ escaped.append(child)
403
+ return files
404
+
405
+
406
+ def _contained_child_dirs(directory: str, boundary: str, escaped: list) -> list:
407
+ """`(name, path)` of the non-hidden directories directly under `directory`
408
+ whose real path stays within `boundary`; one that links outside it is
409
+ appended to `escaped` and never entered."""
410
+ try:
411
+ names = sorted(os.listdir(directory))
412
+ except OSError:
413
+ return []
414
+ dirs = []
415
+ for name in names:
416
+ child = os.path.join(directory, name)
417
+ if name.startswith(".") or not os.path.isdir(child):
418
+ continue
419
+ if _within(os.path.realpath(child), boundary):
420
+ dirs.append((name, child))
421
+ else:
422
+ escaped.append(child)
423
+ return dirs
424
+
425
+
426
+ def _has_knowledge_files(directory: str, boundary: str, escaped: list) -> bool:
427
+ return any(_is_knowledge_file(f) for f in _contained_md_files(directory, boundary, escaped))
428
+
429
+
430
+ def _escaping_links(root: str, boundary: str) -> list:
431
+ """Symlinks anywhere under `root` (walked without following links) whose real
432
+ path leaves `boundary`, sorted. Only a link can leave: every other entry sits
433
+ under `root`, which is already inside the boundary."""
434
+ leaks = []
435
+ for dirpath, dirnames, filenames in os.walk(root, followlinks=False):
436
+ for name in dirnames + filenames:
437
+ child = os.path.join(dirpath, name)
438
+ if os.path.islink(child) and not _within(os.path.realpath(child), boundary):
439
+ leaks.append(child)
440
+ return sorted(leaks)
441
+
442
+
443
+ def enumerate_packs(source_root: str, boundary: str, escaped: list, self_name: str | None = None) -> dict:
444
+ """Map published pack id -> dir. Immediate children only; self = single pack.
445
+
446
+ `boundary` is the realpath every child directory and rule file must stay
447
+ within (the git checkout, the repository, or the source root itself); a
448
+ child that links outside it is recorded in `escaped` and skipped. Symlinks
449
+ that stay inside the boundary are ordinary content.
450
+ """
451
+ if _has_knowledge_files(source_root, boundary, escaped):
452
+ name = self_name or os.path.basename(os.path.abspath(source_root))
453
+ return {name: source_root}
454
+ return {
455
+ name: child
456
+ for name, child in _contained_child_dirs(source_root, boundary, escaped)
457
+ if _has_knowledge_files(child, boundary, escaped)
458
+ }
459
+
460
+
461
+ def nested_rule_shaped(pack_dir: str, boundary: str) -> tuple:
462
+ """`(total, subdirs)`: how many rule-shaped files sit in the immediate
463
+ subdirectories of `pack_dir`, and which subdirectories hold them. Scans one
464
+ level down only, inside `boundary`, so the pack's data is never walked.
465
+ Subdirectories are storage, so these files are counted, never published."""
466
+ hits, total = [], 0
467
+ for name, child in _contained_child_dirs(pack_dir, boundary, []):
468
+ count = sum(1 for f in _contained_md_files(child, boundary, []) if _is_knowledge_file(f))
469
+ if count:
470
+ hits.append(name)
471
+ total += count
472
+ return total, hits
473
+
474
+
475
+ def nested_rules_warning(pack_id: str, pack_dir: str, boundary: str) -> str | None:
476
+ """The warning for a pack directory with no rule at its top level whose
477
+ subdirectories hold rule-shaped files: it registers, yet nothing can ever be
478
+ discovered. None when the subdirectories hold none. The caller establishes
479
+ that the top level is empty of rules; a pack with top-level rules keeps its
480
+ nested files as storage and gets `nested_rule_shaped` instead."""
481
+ total, hits = nested_rule_shaped(pack_dir, boundary)
482
+ if not hits:
483
+ return None
484
+ where = ", ".join(f"`{name}/`" for name in hits)
485
+ return (
486
+ f"pack `{pack_id}` has {total} rule-shaped file(s) under {where} that discovery"
487
+ " never reads -- move rules to the pack's top level (see https://everyinc.github.io/compound-engineering-plugin/guides/packs/, Pack layout)"
488
+ )
489
+
490
+
491
+ # --- entry resolution --------------------------------------------------------
492
+
493
+ def _entry_label(entry: dict) -> str:
494
+ return f"{entry.get('_origin', 'config')}:{entry.get('_line', '?')}"
495
+
496
+
497
+ def _entry_shape_ok(entry: dict, label: str, errors: list) -> bool:
498
+ """I/O-free checks on one parsed entry: `source:` present, and the scalar
499
+ keys actually scalar. False after appending the error."""
500
+ for key in SCALAR_KEYS:
501
+ val = entry.get(key)
502
+ if val is not None and not isinstance(val, str):
503
+ errors.append(f"{label}: `{key}:` must be a single string (got {val!r})")
504
+ return False
505
+ if not entry.get("source"):
506
+ errors.append(f"{label}: entry has no `source:`")
507
+ return False
508
+ return True
509
+
510
+
511
+ def resolve_entry(entry: dict, repo_root: str, roots: list, warnings: list, errors: list) -> None:
512
+ label = _entry_label(entry)
513
+ if not _entry_shape_ok(entry, label, errors):
514
+ return
515
+ source, ref, sub_path = entry["source"], entry.get("ref"), entry.get("path")
516
+
517
+ tree = _TREE_URL_RE.match(source)
518
+ if tree:
519
+ t_ref, t_path = tree.group("ref"), tree.group("path") or ""
520
+ if isinstance(ref, str) and ref != t_ref:
521
+ errors.append(f"{label}: tree URL pins ref `{t_ref}` but entry says `ref: {ref}` -- remove one")
522
+ return
523
+ if isinstance(sub_path, str) and sub_path.strip("/") != t_path.strip("/"):
524
+ errors.append(f"{label}: tree URL path `{t_path}` conflicts with `path: {sub_path}` -- remove one")
525
+ return
526
+ source, ref, sub_path = tree.group("base"), t_ref, t_path or None
527
+
528
+ if _is_git_url(source):
529
+ if not isinstance(ref, str) or not ref:
530
+ errors.append(f"{label}: git source `{source}` requires `ref:` (tag, sha, or branch)")
531
+ return
532
+ if ref.startswith("-") or source.startswith("-"):
533
+ errors.append(f"{label}: git source/ref may not begin with `-`")
534
+ return
535
+ checkout = resolve_git_source(source, ref, warnings, label)
536
+ if checkout is None:
537
+ if tree:
538
+ warnings.append(
539
+ f"{label}: if the branch name contains `/`, tree-URL parsing splits it wrong -- use explicit `ref:` and `path:` fields"
540
+ )
541
+ return
542
+ git_meta = {"url": source, "ref": ref}
543
+ source_root = os.path.join(checkout, sub_path) if sub_path else checkout
544
+ real_root, real_checkout = os.path.realpath(source_root), os.path.realpath(checkout)
545
+ if not _within(real_root, real_checkout):
546
+ errors.append(f"{label}: path `{sub_path}` escapes the source checkout")
547
+ return
548
+ source_root, boundary = real_root, real_checkout
549
+ if not os.path.isdir(source_root):
550
+ errors.append(f"{label}: path `{sub_path}` does not exist in {source}@{ref}")
551
+ return
552
+ else:
553
+ git_meta = None
554
+ if ref is not None:
555
+ errors.append(f"{label}: `ref:` is only valid on git sources; path sources are read live")
556
+ return
557
+ if sub_path is not None:
558
+ errors.append(f"{label}: `path:` is only valid on git sources; point `source:` at the directory instead")
559
+ return
560
+ expanded = os.path.expanduser(source)
561
+ if os.path.isabs(expanded):
562
+ source_root = os.path.realpath(expanded)
563
+ boundary = source_root
564
+ else:
565
+ source_root = os.path.realpath(os.path.join(repo_root, expanded))
566
+ repo_real = os.path.realpath(repo_root)
567
+ if not _within(source_root, repo_real) or _within(source_root, os.path.join(repo_real, ".git")):
568
+ errors.append(f"{label}: repo-relative source `{source}` resolves outside the repository")
569
+ return
570
+ boundary = repo_real
571
+ if not os.path.isdir(source_root):
572
+ errors.append(f"{label}: source directory `{source}` does not exist")
573
+ return
574
+
575
+ if git_meta:
576
+ # Display name for a single-pack git source: the path: subfolder's
577
+ # basename, else the URL's last path segment (never the cache key).
578
+ tail = (sub_path or source).rstrip("/").rsplit("/", 1)[-1]
579
+ self_name = re.sub(r"\.git$", "", tail.split(":")[-1]) or None
580
+ else:
581
+ self_name = None
582
+ escaped = []
583
+ published = enumerate_packs(source_root, boundary, escaped, self_name)
584
+ for link in escaped:
585
+ warnings.append(
586
+ f"{label}: skipped `{os.path.relpath(link, source_root)}` in `{source}` -- it links outside the source"
587
+ )
588
+ if not published:
589
+ warnings.append(f"{label}: source `{source}` publishes no packs (no directories with valid knowledge files)")
590
+ # Each child directory is a would-be pack with no top-level rule (one
591
+ # with a rule would have published); say when its rules sit one level
592
+ # too deep, so the author learns why nothing published.
593
+ for name, child in _contained_child_dirs(source_root, boundary, []):
594
+ nested = nested_rules_warning(name, child, boundary)
595
+ if nested:
596
+ warnings.append(f"{label}: {nested}")
597
+ return
598
+
599
+ selection = entry.get("pack")
600
+ if selection is None:
601
+ selected = dict(published)
602
+ else:
603
+ wanted = selection if isinstance(selection, list) else [selection]
604
+ if not wanted:
605
+ warnings.append(f"{label}: `pack:` lists no ids; nothing installed from `{source}`")
606
+ return
607
+ missing = [w for w in wanted if w not in published]
608
+ if missing:
609
+ errors.append(
610
+ f"{label}: pack id(s) {', '.join(map(str, missing))} not published by `{source}`"
611
+ f" -- available: {', '.join(sorted(published)) or 'none'}"
612
+ )
613
+ return
614
+ selected = {w: published[w] for w in wanted}
615
+
616
+ override = entry.get("id")
617
+ if override is not None:
618
+ if len(selected) != 1:
619
+ errors.append(f"{label}: `id:` override requires the entry to install exactly one pack")
620
+ return
621
+ selected = {str(override): next(iter(selected.values()))}
622
+
623
+ for pack_id, pack_dir in selected.items():
624
+ # Consumers list the pack directory themselves, so a link that leaves
625
+ # the source anywhere inside it would let pack content read files off
626
+ # the user's machine: refuse the whole pack. (Top-level escapes were
627
+ # already named as skipped during enumeration.)
628
+ leaks = _escaping_links(pack_dir, boundary)
629
+ if leaks:
630
+ names = ", ".join(f"`{os.path.relpath(p, pack_dir)}`" for p in leaks)
631
+ errors.append(f"{label}: pack `{pack_id}` not published -- {names} link(s) outside the source")
632
+ continue
633
+ for child in _contained_md_files(pack_dir, boundary, []):
634
+ name = os.path.basename(child)
635
+ if os.path.isfile(child) and not _is_knowledge_file(child):
636
+ warnings.append(
637
+ f"{label}: skipped pack file `{pack_id}/{name}` (missing `title`/`applies_when` frontmatter)"
638
+ )
639
+ # A published pack has a rule at its top level, so rule-shaped files in
640
+ # its subdirectories are storage: counted for the health report, not warned.
641
+ nested_total, _ = nested_rule_shaped(pack_dir, boundary)
642
+ root = {"id": pack_id, "dir": pack_dir, "nested_rule_shaped": nested_total, "_label": label}
643
+ if git_meta:
644
+ root.update(git_meta)
645
+ roots.append(root)
646
+
647
+
648
+ def _emit(declared_only: bool, entries: list, roots: list, warnings: list, errors: list,
649
+ declared: bool | None = None) -> int:
650
+ if declared_only:
651
+ print(json.dumps({"declared": declared, "entries": len(entries), "errors": errors}))
652
+ else:
653
+ print(json.dumps({
654
+ "roots": [{k: v for k, v in r.items() if not k.startswith("_")} for r in roots],
655
+ "warnings": warnings,
656
+ "errors": errors,
657
+ "entries": len(entries),
658
+ }))
659
+ return 0
660
+
661
+
662
+ def _repo_root() -> str | None:
663
+ """The enclosing checkout's top level: git's answer when git is on PATH,
664
+ otherwise the nearest ancestor of the working directory holding a `.git`
665
+ entry (a directory, or the file a worktree or submodule leaves). None when
666
+ the working directory is not inside a checkout."""
667
+ if shutil.which("git") is not None:
668
+ proc = subprocess.run(["git", "rev-parse", "--show-toplevel"],
669
+ stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True)
670
+ return proc.stdout.strip() if proc.returncode == 0 else None
671
+ current = os.getcwd()
672
+ while True:
673
+ if os.path.lexists(os.path.join(current, ".git")):
674
+ return current
675
+ parent = os.path.dirname(current)
676
+ if parent == current:
677
+ return None
678
+ current = parent
679
+
680
+
681
+ def _main(argv: list) -> int:
682
+ parser = argparse.ArgumentParser(description="Resolve the Compound Packs declared in CE config.")
683
+ parser.add_argument(
684
+ "--declared-only", action="store_true",
685
+ help="parse and shape-check the packs: entries only; no git or cache work",
686
+ )
687
+ args = parser.parse_args(argv)
688
+ warnings, errors, roots, entries = [], [], [], []
689
+
690
+ repo_root = _repo_root()
691
+ if repo_root is None:
692
+ warnings.append("not inside a git repository; no CE config to read")
693
+ return _emit(args.declared_only, entries, roots, warnings, errors)
694
+ cfg_dir = os.path.join(repo_root, ".compound-engineering")
695
+ for name in CONFIG_FILES:
696
+ entries.extend(parse_packs_block(os.path.join(cfg_dir, name), errors))
697
+
698
+ if args.declared_only:
699
+ for entry in entries:
700
+ _entry_shape_ok(entry, _entry_label(entry), errors)
701
+ return _emit(True, entries, roots, warnings, errors, declared=bool(entries or errors))
702
+
703
+ for entry in entries:
704
+ try:
705
+ resolve_entry(entry, repo_root, roots, warnings, errors)
706
+ except Exception as exc: # one entry's surprise is that entry's error, not everyone's
707
+ errors.append(f"{_entry_label(entry)}: unexpected error resolving entry: {exc}")
708
+
709
+ # First declaration wins: config.yaml entries precede config.local.yaml in
710
+ # CONFIG_FILES, so a personal pack can never displace the team's.
711
+ by_id = {}
712
+ final = []
713
+ for root in roots:
714
+ prev = by_id.get(root["id"])
715
+ if prev is not None:
716
+ errors.append(
717
+ f"duplicate pack id `{root['id']}`: {root['_label']} ignored, {prev['_label']} kept"
718
+ " -- rename one with `id:`"
719
+ )
720
+ continue
721
+ by_id[root["id"]] = root
722
+ final.append(root)
723
+ return _emit(False, entries, final, warnings, errors)
724
+
725
+
726
+ def main() -> int:
727
+ try:
728
+ return _main(sys.argv[1:])
729
+ except Exception as exc: # never a traceback: consumers need valid JSON
730
+ print(json.dumps({
731
+ "roots": [], "warnings": [], "errors": [f"packs resolver failed unexpectedly: {exc}"], "entries": 0,
732
+ }))
733
+ return 0
734
+
735
+
736
+ if __name__ == "__main__":
737
+ sys.exit(main())