@1aboveio/skills 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (397) hide show
  1. package/LICENSE +3 -0
  2. package/README.md +90 -0
  3. package/bin/1aboveio-skills.mjs +18 -0
  4. package/package.json +28 -0
  5. package/runtime/skills/distribution/generated/recipes.json +1189 -0
  6. package/runtime/skills/distribution/scripts/bundles.mjs +280 -0
  7. package/runtime/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
  8. package/skills/backend/airflow-dag-develop/LICENSE +3 -0
  9. package/skills/backend/airflow-dag-develop/SKILL.md +111 -0
  10. package/skills/backend/app-debug/LICENSE +3 -0
  11. package/skills/backend/app-debug/SKILL.md +109 -0
  12. package/skills/backend/app-debug/references/common-errors.md +128 -0
  13. package/skills/backend/python-backend/LICENSE +3 -0
  14. package/skills/backend/python-backend/SKILL.md +326 -0
  15. package/skills/cicd-pipeline/cloud-build/LICENSE +3 -0
  16. package/skills/cicd-pipeline/cloud-build/SKILL.md +707 -0
  17. package/skills/cicd-pipeline/cloud-debug/LICENSE +3 -0
  18. package/skills/cicd-pipeline/cloud-debug/SKILL.md +316 -0
  19. package/skills/cicd-pipeline/cloud-debug/references/build-failures.md +238 -0
  20. package/skills/cicd-pipeline/cloud-debug/references/deploy-failures.md +376 -0
  21. package/skills/cicd-pipeline/cloud-debug/references/pipeline-failures.md +378 -0
  22. package/skills/cicd-pipeline/cloud-deploy/LICENSE +3 -0
  23. package/skills/cicd-pipeline/cloud-deploy/SKILL.md +229 -0
  24. package/skills/cicd-pipeline/cloud-deploy/references/config-templates.md +257 -0
  25. package/skills/cicd-pipeline/docker/LICENSE +3 -0
  26. package/skills/cicd-pipeline/docker/SKILL.md +126 -0
  27. package/skills/cicd-pipeline/google-cloud/LICENSE +3 -0
  28. package/skills/cicd-pipeline/google-cloud/SKILL.md +118 -0
  29. package/skills/cicd-pipeline/google-cloud/references/gcs.md +469 -0
  30. package/skills/cicd-pipeline/google-cloud/references/iam.md +451 -0
  31. package/skills/cicd-pipeline/google-cloud/references/project.md +349 -0
  32. package/skills/cicd-pipeline/google-cloud/references/secrets.md +336 -0
  33. package/skills/cicd-pipeline/google-cloud/references/vpc.md +312 -0
  34. package/skills/cicd-pipeline/google-cloud/scripts/create-sa.sh +36 -0
  35. package/skills/cicd-pipeline/google-cloud/scripts/gcp-config.sh +31 -0
  36. package/skills/cicd-pipeline/google-cloud/scripts/grant-iap.sh +41 -0
  37. package/skills/cicd-pipeline/google-cloud/scripts/setup-secrets.sh +48 -0
  38. package/skills/cicd-pipeline/mergify/LICENSE +3 -0
  39. package/skills/cicd-pipeline/mergify/SKILL.md +138 -0
  40. package/skills/cicd-pipeline/mergify/assets/templates/mergify.yml +237 -0
  41. package/skills/cicd-pipeline/mergify/assets/templates/ruleset.json +46 -0
  42. package/skills/cicd-pipeline/mergify/references/branch-protection.md +277 -0
  43. package/skills/cicd-pipeline/mergify/references/configuration.md +183 -0
  44. package/skills/cicd-pipeline/mergify/references/diagnosis.md +73 -0
  45. package/skills/cicd-pipeline/mergify/references/traps.md +78 -0
  46. package/skills/cicd-pipeline/mergify/references/watch-contract.md +218 -0
  47. package/skills/cicd-pipeline/mergify/scripts/audit-core.mjs +131 -0
  48. package/skills/cicd-pipeline/mergify/scripts/audit.mjs +4 -0
  49. package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery-core.mjs +663 -0
  50. package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery.mjs +4 -0
  51. package/skills/cicd-pipeline/podman/LICENSE +3 -0
  52. package/skills/cicd-pipeline/podman/SKILL.md +70 -0
  53. package/skills/cicd-pipeline/podman/agents/openai.yaml +4 -0
  54. package/skills/cicd-pipeline/podman/assets/templates/podman-compose-socket-directory.yml +6 -0
  55. package/skills/cicd-pipeline/podman/assets/templates/podman-service-override.conf +3 -0
  56. package/skills/cicd-pipeline/podman/references/compose-compatibility.md +70 -0
  57. package/skills/cicd-pipeline/podman/references/networking-and-ports.md +74 -0
  58. package/skills/cicd-pipeline/podman/references/rootless-services-and-sockets.md +156 -0
  59. package/skills/cicd-pipeline/podman/references/troubleshooting.md +98 -0
  60. package/skills/engineering/e2e-test/LICENSE +3 -0
  61. package/skills/engineering/e2e-test/SKILL.md +156 -0
  62. package/skills/engineering/e2e-test/assets/ci-gates.cloudbuild.yaml +272 -0
  63. package/skills/engineering/e2e-test/assets/ci-gates.github.yml +451 -0
  64. package/skills/engineering/e2e-test/assets/e2e-workflow.yml +282 -0
  65. package/skills/engineering/e2e-test/references/authoring/auth-flows.md +159 -0
  66. package/skills/engineering/e2e-test/references/authoring/playwright-config.md +71 -0
  67. package/skills/engineering/e2e-test/references/authoring/playwright-patterns.md +219 -0
  68. package/skills/engineering/e2e-test/references/authoring/test-skipping.md +44 -0
  69. package/skills/engineering/e2e-test/references/ci-integration.md +121 -0
  70. package/skills/engineering/e2e-test/references/ci-playwright-container.md +280 -0
  71. package/skills/engineering/e2e-test/references/debugging.md +36 -0
  72. package/skills/engineering/e2e-test/references/presentation-sweep.md +131 -0
  73. package/skills/engineering/e2e-test/references/reviewing.md +39 -0
  74. package/skills/engineering/e2e-test/references/route-discovery.md +50 -0
  75. package/skills/engineering/e2e-test/references/route-manifest.md +44 -0
  76. package/skills/engineering/e2e-test/scripts/detect-routes-fastapi.py +290 -0
  77. package/skills/engineering/e2e-test/scripts/detect-routes-nextjs.mjs +200 -0
  78. package/skills/engineering/e2e-test/scripts/post-visual-evidence.mjs +158 -0
  79. package/skills/engineering/e2e-test/scripts/presentation-checks.mjs +171 -0
  80. package/skills/engineering/e2e-test/scripts/presentation-perceivability.mjs +179 -0
  81. package/skills/engineering/e2e-test/scripts/presentation-reachability.mjs +154 -0
  82. package/skills/engineering/e2e-test/scripts/presentation-render-health.mjs +141 -0
  83. package/skills/engineering/e2e-test/scripts/presentation-sweep.mjs +148 -0
  84. package/skills/engineering/e2e-test/scripts/presentation-temporal.mjs +127 -0
  85. package/skills/engineering/e2e-test/scripts/presentation-visual.mjs +84 -0
  86. package/skills/engineering/e2e-test/scripts/project-route-manifest.mjs +75 -0
  87. package/skills/engineering/e2e-test/scripts/validate-manifest.mjs +106 -0
  88. package/skills/engineering/engineering-runtime/LICENSE +3 -0
  89. package/skills/engineering/engineering-runtime/SKILL.md +10 -0
  90. package/skills/engineering/engineering-runtime/agents/openai.yaml +6 -0
  91. package/skills/engineering/engineering-runtime/coherence/workflow.json +553 -0
  92. package/skills/engineering/engineering-runtime/scripts/exact-head-artifact.mjs +131 -0
  93. package/skills/engineering/engineering-runtime/scripts/head-check-set.mjs +398 -0
  94. package/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
  95. package/skills/engineering/engineering-runtime/scripts/mergify-yaml.mjs +11 -0
  96. package/skills/engineering/engineering-runtime/scripts/package-lock.json +43 -0
  97. package/skills/engineering/engineering-runtime/scripts/package.json +10 -0
  98. package/skills/engineering/engineering-runtime/scripts/required-check-plan.mjs +223 -0
  99. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +576 -0
  100. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +166 -0
  101. package/skills/engineering/ensure-coverage/LICENSE +3 -0
  102. package/skills/engineering/ensure-coverage/SKILL.md +136 -0
  103. package/skills/engineering/ensure-coverage/evals/evals.json +125 -0
  104. package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +91 -0
  105. package/skills/engineering/ensure-coverage/references/breadth/inventory-contract.md +83 -0
  106. package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +44 -0
  107. package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +16 -0
  108. package/skills/engineering/ensure-coverage/references/depth/characterization.md +68 -0
  109. package/skills/engineering/ensure-coverage/references/depth/coverage.config.example.json +25 -0
  110. package/skills/engineering/ensure-coverage/references/depth/grading.md +35 -0
  111. package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +87 -0
  112. package/skills/engineering/ensure-coverage/references/depth/test-smells.md +23 -0
  113. package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +164 -0
  114. package/skills/engineering/ensure-coverage/references/enforcement/hooks.md +85 -0
  115. package/skills/engineering/ensure-coverage/references/examples/coverage-ledger.md +109 -0
  116. package/skills/engineering/ensure-coverage/references/examples/refund-flow.md +33 -0
  117. package/skills/engineering/ensure-coverage/references/presentation/axis.md +78 -0
  118. package/skills/engineering/ensure-coverage/references/presentation/runner-contract.md +74 -0
  119. package/skills/engineering/ensure-coverage/references/process/audit-mode.md +33 -0
  120. package/skills/engineering/ensure-coverage/references/process/output-template.md +139 -0
  121. package/skills/engineering/ensure-coverage/references/process/review-contract-template.md +119 -0
  122. package/skills/engineering/ensure-coverage/references/process/scope-class.md +178 -0
  123. package/skills/engineering/ensure-coverage/references/process/test-strategy.md +55 -0
  124. package/skills/engineering/ensure-coverage/schemas/coverage-config.schema.json +45 -0
  125. package/skills/engineering/ensure-coverage/schemas/coverage-file.schema.json +93 -0
  126. package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.mjs +178 -0
  127. package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.mjs +101 -0
  128. package/skills/engineering/ensure-coverage/scripts/ci-audit.mjs +358 -0
  129. package/skills/engineering/ensure-coverage/scripts/coverage-checklist.mjs +494 -0
  130. package/skills/engineering/ensure-coverage/scripts/coverage-ledger.mjs +663 -0
  131. package/skills/engineering/ensure-coverage/scripts/design-parity.mjs +591 -0
  132. package/skills/engineering/ensure-coverage/scripts/evidence-block.mjs +367 -0
  133. package/skills/engineering/ensure-coverage/scripts/lint-tests.mjs +269 -0
  134. package/skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs +176 -0
  135. package/skills/engineering/ensure-coverage/scripts/package-lock.json +76 -0
  136. package/skills/engineering/ensure-coverage/scripts/package.json +19 -0
  137. package/skills/engineering/ensure-coverage/scripts/scope-class.mjs +554 -0
  138. package/skills/engineering/harness-runtime/LICENSE +3 -0
  139. package/skills/engineering/harness-runtime/SKILL.md +18 -0
  140. package/skills/engineering/harness-runtime/agents/openai.yaml +6 -0
  141. package/skills/engineering/harness-runtime/bin/discover-models.mjs +4 -0
  142. package/skills/engineering/harness-runtime/bin/model-catalog.mjs +4 -0
  143. package/skills/engineering/harness-runtime/contracts.md +15 -0
  144. package/skills/engineering/harness-runtime/discover-models.mjs +392 -0
  145. package/skills/engineering/harness-runtime/fixtures/native-question-schemas.json +33 -0
  146. package/skills/engineering/harness-runtime/fixtures/question-responses.json +54 -0
  147. package/skills/engineering/harness-runtime/index.mjs +767 -0
  148. package/skills/engineering/harness-runtime/model-catalog.mjs +787 -0
  149. package/skills/engineering/harness-runtime/native-question-contracts.md +37 -0
  150. package/skills/engineering/harness-runtime/references/model-catalog-seed.json +159 -0
  151. package/skills/engineering/harness-runtime/references/model-catalog.md +57 -0
  152. package/skills/engineering/implement-and-pr/LICENSE +3 -0
  153. package/skills/engineering/implement-and-pr/SKILL.md +176 -0
  154. package/skills/engineering/implement-and-pr/references/ci-iteration.md +10 -0
  155. package/skills/engineering/implement-and-pr/references/closeout.md +27 -0
  156. package/skills/engineering/implement-and-pr/references/contract-complete-fix-rounds.md +34 -0
  157. package/skills/engineering/implement-and-pr/references/evidence-rules.md +39 -0
  158. package/skills/engineering/implement-and-pr/references/incremental-plan.md +16 -0
  159. package/skills/engineering/implement-and-pr/references/self-review.md +23 -0
  160. package/skills/engineering/implement-and-pr/references/tdd-mode.md +18 -0
  161. package/skills/engineering/resolve-issues/LICENSE +3 -0
  162. package/skills/engineering/resolve-issues/SKILL.md +167 -0
  163. package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +448 -0
  164. package/skills/engineering/resolve-issues/references/breaker.md +82 -0
  165. package/skills/engineering/resolve-issues/references/deliverables.md +27 -0
  166. package/skills/engineering/resolve-issues/references/delivery.md +108 -0
  167. package/skills/engineering/resolve-issues/references/evidence-lane.md +21 -0
  168. package/skills/engineering/resolve-issues/references/exact-head-ci.md +287 -0
  169. package/skills/engineering/resolve-issues/references/fan-out.md +33 -0
  170. package/skills/engineering/resolve-issues/references/finalization.md +68 -0
  171. package/skills/engineering/resolve-issues/references/guarantees.md +10 -0
  172. package/skills/engineering/resolve-issues/references/high-risk.md +29 -0
  173. package/skills/engineering/resolve-issues/references/incidents/848/README.md +156 -0
  174. package/skills/engineering/resolve-issues/references/intake.md +86 -0
  175. package/skills/engineering/resolve-issues/references/integration-gate.md +53 -0
  176. package/skills/engineering/resolve-issues/references/interference.md +87 -0
  177. package/skills/engineering/resolve-issues/references/loop.md +134 -0
  178. package/skills/engineering/resolve-issues/references/model-catalog.md +9 -0
  179. package/skills/engineering/resolve-issues/references/postmortem.md +27 -0
  180. package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +41 -0
  181. package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +48 -0
  182. package/skills/engineering/resolve-issues/references/pre-flight.md +41 -0
  183. package/skills/engineering/resolve-issues/references/regression-checklist.md +26 -0
  184. package/skills/engineering/resolve-issues/references/run-state.md +288 -0
  185. package/skills/engineering/resolve-issues/references/sandboxed-testing.md +48 -0
  186. package/skills/engineering/resolve-issues/references/spawn-contract.md +96 -0
  187. package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +40 -0
  188. package/skills/engineering/resolve-issues/references/why.md +653 -0
  189. package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +49 -0
  190. package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +721 -0
  191. package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +962 -0
  192. package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +220 -0
  193. package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +420 -0
  194. package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +256 -0
  195. package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +168 -0
  196. package/skills/engineering/resolve-issues/scripts/discover-models.mjs +9 -0
  197. package/skills/engineering/resolve-issues/scripts/doctrine.mjs +62 -0
  198. package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +191 -0
  199. package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +413 -0
  200. package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +332 -0
  201. package/skills/engineering/resolve-issues/scripts/finalize.mjs +488 -0
  202. package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +3307 -0
  203. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +16 -0
  204. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +51 -0
  205. package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +17 -0
  206. package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +166 -0
  207. package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +92 -0
  208. package/skills/engineering/resolve-issues/scripts/guide-index.mjs +73 -0
  209. package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +159 -0
  210. package/skills/engineering/resolve-issues/scripts/interference.mjs +427 -0
  211. package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +9 -0
  212. package/skills/engineering/resolve-issues/scripts/next-operations.mjs +419 -0
  213. package/skills/engineering/resolve-issues/scripts/postmortem.mjs +909 -0
  214. package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +322 -0
  215. package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +415 -0
  216. package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +697 -0
  217. package/skills/engineering/resolve-issues/scripts/report.mjs +494 -0
  218. package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +172 -0
  219. package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +79 -0
  220. package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +334 -0
  221. package/skills/engineering/resolve-issues/scripts/run-state.mjs +4784 -0
  222. package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +395 -0
  223. package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +290 -0
  224. package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +170 -0
  225. package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +293 -0
  226. package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +197 -0
  227. package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +127 -0
  228. package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +893 -0
  229. package/skills/engineering/resolve-issues/scripts/workspaces.mjs +829 -0
  230. package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +290 -0
  231. package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +80 -0
  232. package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +102 -0
  233. package/skills/engineering/resolve-release/LICENSE +3 -0
  234. package/skills/engineering/resolve-release/SKILL.md +112 -0
  235. package/skills/engineering/resolve-release/references/assembly.md +137 -0
  236. package/skills/engineering/resolve-release/references/auto-when-green.md +56 -0
  237. package/skills/engineering/resolve-release/references/candidate.md +167 -0
  238. package/skills/engineering/resolve-release/references/exposure.md +178 -0
  239. package/skills/engineering/resolve-release/references/handoff.md +24 -0
  240. package/skills/engineering/resolve-release/references/postmortem.md +230 -0
  241. package/skills/engineering/resolve-release/references/preflight.md +207 -0
  242. package/skills/engineering/resolve-release/references/principles.md +94 -0
  243. package/skills/engineering/resolve-release/references/regression-checklist.md +36 -0
  244. package/skills/engineering/resolve-release/references/related-skills.md +12 -0
  245. package/skills/engineering/resolve-release/references/routing.md +149 -0
  246. package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +285 -0
  247. package/skills/engineering/resolve-release/references/versioning.md +202 -0
  248. package/skills/engineering/resolve-release/references/why.md +53 -0
  249. package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +389 -0
  250. package/skills/engineering/resolve-release/scripts/build-changes.mjs +209 -0
  251. package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +407 -0
  252. package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +904 -0
  253. package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +81 -0
  254. package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +612 -0
  255. package/skills/engineering/resolve-release/scripts/close-attempt.mjs +135 -0
  256. package/skills/engineering/resolve-release/scripts/closeout-release.mjs +161 -0
  257. package/skills/engineering/resolve-release/scripts/doctrine.mjs +106 -0
  258. package/skills/engineering/resolve-release/scripts/durable-processing.mjs +522 -0
  259. package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +659 -0
  260. package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +1014 -0
  261. package/skills/engineering/resolve-release/scripts/finalize-release.mjs +526 -0
  262. package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +169 -0
  263. package/skills/engineering/resolve-release/scripts/green-gate.mjs +599 -0
  264. package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +752 -0
  265. package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +56 -0
  266. package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +1538 -0
  267. package/skills/engineering/resolve-release/scripts/postmortem.mjs +381 -0
  268. package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +498 -0
  269. package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +326 -0
  270. package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +272 -0
  271. package/skills/engineering/resolve-release/scripts/report.mjs +417 -0
  272. package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +114 -0
  273. package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +238 -0
  274. package/skills/engineering/resolve-release/scripts/review-packet.mjs +503 -0
  275. package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +263 -0
  276. package/skills/engineering/resolve-release/scripts/version-assert.mjs +339 -0
  277. package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +485 -0
  278. package/skills/engineering/resolve-release/scripts/version.mjs +1199 -0
  279. package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +449 -0
  280. package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +21 -0
  281. package/skills/engineering/resolve-release/vendor/README.md +60 -0
  282. package/skills/engineering/resolve-release/vendor/acorn.mjs +6233 -0
  283. package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +21 -0
  284. package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +341 -0
  285. package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +70 -0
  286. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +2 -0
  287. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +1 -0
  288. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +7 -0
  289. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +1 -0
  290. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +2033 -0
  291. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +2033 -0
  292. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +7 -0
  293. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +1 -0
  294. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +2 -0
  295. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +1 -0
  296. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +2 -0
  297. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +1 -0
  298. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +2 -0
  299. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +1 -0
  300. package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +49 -0
  301. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +21 -0
  302. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +5 -0
  303. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +549 -0
  304. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +549 -0
  305. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +2 -0
  306. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +1 -0
  307. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +2 -0
  308. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +1 -0
  309. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +36 -0
  310. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +47 -0
  311. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +82 -0
  312. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +11 -0
  313. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +22 -0
  314. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +21 -0
  315. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +21 -0
  316. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +11 -0
  317. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +11 -0
  318. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +25 -0
  319. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
  320. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +85 -0
  321. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +85 -0
  322. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +2 -0
  323. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +1 -0
  324. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +2 -0
  325. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +1 -0
  326. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +20 -0
  327. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +20 -0
  328. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +2 -0
  329. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +1 -0
  330. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +2 -0
  331. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +1 -0
  332. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +61 -0
  333. package/skills/engineering/review-pr/LICENSE +3 -0
  334. package/skills/engineering/review-pr/SKILL.md +123 -0
  335. package/skills/engineering/review-pr/references/adversarial-reviewer-prompt.md +42 -0
  336. package/skills/engineering/review-pr/references/code-correctness.md +5 -0
  337. package/skills/engineering/review-pr/references/contract-freshness.md +9 -0
  338. package/skills/engineering/review-pr/references/coordination.md +18 -0
  339. package/skills/engineering/review-pr/references/domain-hazards.md +123 -0
  340. package/skills/engineering/review-pr/references/finding-themes.md +7 -0
  341. package/skills/engineering/review-pr/references/github-posting.md +98 -0
  342. package/skills/engineering/review-pr/references/golden-path-smoke.md +5 -0
  343. package/skills/engineering/review-pr/references/incremental-output.md +16 -0
  344. package/skills/engineering/review-pr/references/inputs-and-discovery.md +31 -0
  345. package/skills/engineering/review-pr/references/output-format.md +99 -0
  346. package/skills/engineering/review-pr/references/over-mock-screen.md +7 -0
  347. package/skills/engineering/review-pr/references/promotion-prs.md +16 -0
  348. package/skills/engineering/review-pr/references/re-review.md +18 -0
  349. package/skills/engineering/review-pr/references/review-method.md +199 -0
  350. package/skills/engineering/review-pr/references/review-mode.md +30 -0
  351. package/skills/engineering/review-pr/references/review-posture.md +53 -0
  352. package/skills/engineering/review-pr/references/round1-depth.md +62 -0
  353. package/skills/engineering/review-pr/references/scripts.md +17 -0
  354. package/skills/engineering/review-pr/references/workflow.md +16 -0
  355. package/skills/engineering/review-pr/schemas/findings.schema.json +282 -0
  356. package/skills/engineering/review-pr/scripts/finding-contract.mjs +285 -0
  357. package/skills/engineering/review-pr/scripts/post-review.mjs +405 -0
  358. package/skills/engineering/review-pr/scripts/pr-context.mjs +207 -0
  359. package/skills/engineering/review-pr/scripts/scan-diff.mjs +365 -0
  360. package/skills/engineering/review-pr/scripts/theme-contract.mjs +57 -0
  361. package/skills/engineering/smoke/LICENSE +3 -0
  362. package/skills/engineering/smoke/SKILL.md +131 -0
  363. package/skills/engineering/smoke/assets/smoke.manifest.example.json +53 -0
  364. package/skills/engineering/smoke/references/manifest.md +192 -0
  365. package/skills/engineering/smoke/scripts/smoke.mjs +713 -0
  366. package/skills/fullstack/better-auth/LICENSE +3 -0
  367. package/skills/fullstack/better-auth/SKILL.md +601 -0
  368. package/skills/fullstack/better-auth/references/feishu-api.md +270 -0
  369. package/skills/fullstack/monorepo/LICENSE +3 -0
  370. package/skills/fullstack/monorepo/SKILL.md +465 -0
  371. package/skills/fullstack/nextjs-fullstack/LICENSE +3 -0
  372. package/skills/fullstack/nextjs-fullstack/SKILL.md +210 -0
  373. package/skills/fullstack/nextjs-fullstack/conventions.md +318 -0
  374. package/skills/fullstack/nextjs-fullstack/frontend-conventions.md +61 -0
  375. package/skills/fullstack/nextjs-fullstack/nextjs16.md +287 -0
  376. package/skills/fullstack/nextjs-fullstack/server-actions.md +409 -0
  377. package/skills/fullstack/prisma-setup/LICENSE +3 -0
  378. package/skills/fullstack/prisma-setup/SKILL.md +180 -0
  379. package/skills/fullstack/prisma-setup/nextjs.md +258 -0
  380. package/skills/fullstack/prisma-setup/turborepo.md +301 -0
  381. package/skills/fullstack/shadcn/LICENSE +3 -0
  382. package/skills/fullstack/shadcn/SKILL.md +119 -0
  383. package/skills/fullstack/shadcn/assets/shadcn-small.png +0 -0
  384. package/skills/fullstack/shadcn/assets/shadcn.png +0 -0
  385. package/skills/fullstack/shadcn/cli.md +411 -0
  386. package/skills/fullstack/shadcn/customization.md +224 -0
  387. package/skills/fullstack/shadcn/evals/evals.json +90 -0
  388. package/skills/fullstack/shadcn/mcp.md +101 -0
  389. package/skills/fullstack/shadcn/rules/base-vs-radix.md +323 -0
  390. package/skills/fullstack/shadcn/rules/component-selection.md +67 -0
  391. package/skills/fullstack/shadcn/rules/composition.md +195 -0
  392. package/skills/fullstack/shadcn/rules/data-table.md +201 -0
  393. package/skills/fullstack/shadcn/rules/forms.md +255 -0
  394. package/skills/fullstack/shadcn/rules/icons.md +103 -0
  395. package/skills/fullstack/shadcn/rules/styling.md +167 -0
  396. package/skills/fullstack/zod-v4/LICENSE +3 -0
  397. package/skills/fullstack/zod-v4/SKILL.md +287 -0
@@ -0,0 +1,290 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Detect all FastAPI routes via static analysis and compare against endpoint manifest.
4
+ Fails CI if any route exists in the app but not in the manifest.
5
+
6
+ Scans Python files for:
7
+ - @router.get("/path") @router.post("/path")
8
+ - @app.get("/path") @app.post("/path")
9
+ - @api.get("/path") @api.post("/path")
10
+ - app.include_router(router, prefix="/prefix")
11
+
12
+ Handles:
13
+ - Decorator-based route definitions
14
+ - Router prefixes from include_router calls
15
+ - String literals and f-strings (partial — extracts static prefix)
16
+ - Commented-out routes (skipped)
17
+
18
+ Usage:
19
+ python detect-routes-fastapi.py [options]
20
+
21
+ Options:
22
+ --src-dir <path> Path to scan for Python files (default: .)
23
+ --manifest <path> Path to endpoint-manifest.json (default: tests/e2e/endpoint-manifest.json)
24
+ --exclude <pattern> Glob pattern to exclude (repeatable, default: tests/*, **/test_*)
25
+ --strict Exit 1 if any route missing from manifest (default)
26
+ --no-strict Only warn, don't fail
27
+
28
+ Exit codes:
29
+ 0 = all routes accounted for
30
+ 1 = routes missing from manifest (strict mode)
31
+ """
32
+
33
+ import argparse
34
+ import ast
35
+ import json
36
+ import os
37
+ import re
38
+ import sys
39
+ from pathlib import Path
40
+ from fnmatch import fnmatch
41
+
42
+
43
+ def parse_args():
44
+ parser = argparse.ArgumentParser(description="Detect FastAPI routes")
45
+ parser.add_argument("--src-dir", default=".", help="Source directory to scan")
46
+ parser.add_argument(
47
+ "--manifest",
48
+ default="tests/e2e/endpoint-manifest.json",
49
+ help="Path to endpoint manifest",
50
+ )
51
+ parser.add_argument(
52
+ "--exclude",
53
+ action="append",
54
+ default=None,
55
+ help="Glob patterns to exclude (repeatable)",
56
+ )
57
+ parser.add_argument(
58
+ "--strict",
59
+ dest="strict",
60
+ action="store_true",
61
+ default=True,
62
+ help="Fail on missing routes (default)",
63
+ )
64
+ parser.add_argument(
65
+ "--no-strict", dest="strict", action="store_false", help="Warn only"
66
+ )
67
+ return parser.parse_args()
68
+
69
+
70
+ # ─── Route extraction ────────────────────────────────────────
71
+
72
+ HTTP_METHODS = {"get", "post", "put", "delete", "patch", "head", "options"}
73
+
74
+ # Pattern: @something.method("path") or @something.method("path", ...)
75
+ ROUTE_DECORATOR_RE = re.compile(
76
+ r"^\s*@(\w+)\.(get|post|put|delete|patch|head|options)\(\s*"
77
+ r'["\']([^"\']*)["\']',
78
+ re.MULTILINE,
79
+ )
80
+
81
+ # Pattern: app.include_router(var, prefix="path")
82
+ INCLUDE_ROUTER_RE = re.compile(
83
+ r'\.include_router\(\s*(\w+)(?:.*?prefix\s*=\s*["\']([^"\']*)["\'])?',
84
+ re.DOTALL,
85
+ )
86
+
87
+
88
+ def extract_routes_from_file(filepath: str) -> list[dict]:
89
+ """Extract route definitions from a Python file using regex.
90
+
91
+ Returns list of { method, path, file, line }
92
+ """
93
+ routes = []
94
+ try:
95
+ content = Path(filepath).read_text(encoding="utf-8")
96
+ except Exception:
97
+ return routes
98
+
99
+ lines = content.split("\n")
100
+ for i, line in enumerate(lines, 1):
101
+ # Skip comments
102
+ stripped = line.lstrip()
103
+ if stripped.startswith("#"):
104
+ continue
105
+
106
+ match = ROUTE_DECORATOR_RE.match(stripped)
107
+ if match:
108
+ _var_name, method, path = match.groups()
109
+ routes.append(
110
+ {
111
+ "method": method.upper(),
112
+ "path": path,
113
+ "file": filepath,
114
+ "line": i,
115
+ "router_var": _var_name,
116
+ }
117
+ )
118
+
119
+ return routes
120
+
121
+
122
+ def find_router_prefixes(filepath: str) -> dict[str, str]:
123
+ """Find include_router calls and their prefixes.
124
+
125
+ Returns { router_var_name: prefix }
126
+ """
127
+ prefixes = {}
128
+ try:
129
+ content = Path(filepath).read_text(encoding="utf-8")
130
+ except Exception:
131
+ return prefixes
132
+
133
+ for match in INCLUDE_ROUTER_RE.finditer(content):
134
+ var_name = match.group(1)
135
+ prefix = match.group(2) or ""
136
+ if prefix:
137
+ prefixes[var_name] = prefix
138
+
139
+ return prefixes
140
+
141
+
142
+ def scan_directory(src_dir: str, excludes: list[str]) -> tuple[list[dict], dict]:
143
+ """Scan all Python files for routes and router prefixes."""
144
+ all_routes = []
145
+ all_prefixes = {}
146
+
147
+ for root, dirs, files in os.walk(src_dir):
148
+ # Skip common non-source directories
149
+ dirs[:] = [
150
+ d
151
+ for d in dirs
152
+ if d not in {"__pycache__", ".git", "node_modules", ".venv", "venv"}
153
+ ]
154
+
155
+ for fname in files:
156
+ if not fname.endswith(".py"):
157
+ continue
158
+
159
+ filepath = os.path.join(root, fname)
160
+ rel_path = os.path.relpath(filepath, src_dir)
161
+
162
+ # Check excludes
163
+ if any(fnmatch(rel_path, pat) for pat in excludes):
164
+ continue
165
+
166
+ routes = extract_routes_from_file(filepath)
167
+ if routes:
168
+ all_routes.extend(routes)
169
+
170
+ prefixes = find_router_prefixes(filepath)
171
+ all_prefixes.update(prefixes)
172
+
173
+ return all_routes, all_prefixes
174
+
175
+
176
+ def resolve_full_paths(
177
+ routes: list[dict], prefixes: dict[str, str]
178
+ ) -> list[dict]:
179
+ """Apply router prefixes to route paths to get full paths."""
180
+ resolved = []
181
+ for route in routes:
182
+ prefix = prefixes.get(route["router_var"], "")
183
+ full_path = prefix.rstrip("/") + "/" + route["path"].lstrip("/")
184
+ # Normalize double slashes
185
+ full_path = re.sub(r"//+", "/", full_path)
186
+ if not full_path.startswith("/"):
187
+ full_path = "/" + full_path
188
+ resolved.append(
189
+ {
190
+ "method": route["method"],
191
+ "path": full_path,
192
+ "file": route["file"],
193
+ "line": route["line"],
194
+ }
195
+ )
196
+ return resolved
197
+
198
+
199
+ # ─── Manifest comparison ─────────────────────────────────────
200
+
201
+
202
+ def load_manifest(path: str) -> set[tuple[str, str]]:
203
+ """Load endpoint manifest. Returns set of (METHOD, path) tuples."""
204
+ if not os.path.exists(path):
205
+ print(f"❌ Manifest not found: {path}")
206
+ print(f' Create it with: {{ "version": 1, "endpoints": [] }}')
207
+ sys.exit(1)
208
+
209
+ try:
210
+ with open(path) as f:
211
+ data = json.load(f)
212
+ except json.JSONDecodeError as e:
213
+ print(f"❌ Invalid JSON in manifest: {e}")
214
+ sys.exit(1)
215
+
216
+ endpoints = data.get("endpoints", [])
217
+ return {(ep.get("method", "GET").upper(), ep["path"]) for ep in endpoints}
218
+
219
+
220
+ # ─── Main ────────────────────────────────────────────────────
221
+
222
+
223
+ def main():
224
+ args = parse_args()
225
+ src_dir = os.path.abspath(args.src_dir)
226
+ manifest_path = os.path.abspath(args.manifest)
227
+ excludes = args.exclude or ["tests/*", "**/test_*", "**/*_test.py"]
228
+
229
+ print(f"🔍 Scanning: {os.path.relpath(src_dir)}/")
230
+ print(f"📋 Manifest: {os.path.relpath(manifest_path)}")
231
+ print(f"🚫 Excluding: {', '.join(excludes)}\n")
232
+
233
+ # Scan
234
+ raw_routes, prefixes = scan_directory(src_dir, excludes)
235
+ routes = resolve_full_paths(raw_routes, prefixes)
236
+
237
+ # Deduplicate
238
+ seen = set()
239
+ unique_routes = []
240
+ for r in routes:
241
+ key = (r["method"], r["path"])
242
+ if key not in seen:
243
+ seen.add(key)
244
+ unique_routes.append(r)
245
+
246
+ # Load manifest
247
+ manifest_entries = load_manifest(manifest_path)
248
+
249
+ # Compare
250
+ missing = []
251
+ accounted = []
252
+ for route in unique_routes:
253
+ key = (route["method"], route["path"])
254
+ if key in manifest_entries:
255
+ accounted.append(route)
256
+ else:
257
+ missing.append(route)
258
+
259
+ print(
260
+ f"Found {len(unique_routes)} routes "
261
+ f"({len(set(r['method'] for r in unique_routes))} methods)"
262
+ )
263
+ print(f"Manifest has {len(manifest_entries)} entries")
264
+ print(f"Accounted: {len(accounted)} | Missing: {len(missing)}\n")
265
+
266
+ if missing:
267
+ print("─" * 60)
268
+ print("❌ Routes in app but NOT in manifest:\n")
269
+ for route in sorted(missing, key=lambda r: r["path"]):
270
+ print(f" {route['method']} {route['path']}")
271
+ print(f" └─ {os.path.relpath(route['file'])}:{route['line']}")
272
+ print(f"\n{'─' * 60}")
273
+ print(f"\nAdd these to {os.path.relpath(manifest_path)}:")
274
+ print(
275
+ ' { "method": "<METHOD>", "path": "<path>", "tier": 1, "specs": [] }\n'
276
+ )
277
+ print("Endpoints with specs: [] will pass CI but show as uncovered")
278
+ print("in the E2E PR comment.\n")
279
+
280
+ if args.strict:
281
+ print("🚫 Failing CI (strict mode). Use --no-strict to warn only.")
282
+ sys.exit(1)
283
+ else:
284
+ print("⚠️ Warning only (non-strict mode).")
285
+ else:
286
+ print("✅ All API routes are accounted for in the manifest.")
287
+
288
+
289
+ if __name__ == "__main__":
290
+ main()
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+
3
+ /*
4
+ detect-routes-nextjs.mjs
5
+
6
+ Detect all Next.js App Router routes and compare against route manifest.
7
+ Fails CI if any route exists in the app but not in the manifest.
8
+
9
+ Scans for page routes (page.tsx) and API routes (route.ts).
10
+
11
+ Handles Next.js conventions:
12
+ Route groups (auth)/ -- stripped from path
13
+ Dynamic segments [id]/ -- preserved
14
+ Catch-all [...slug]/ -- preserved
15
+ Parallel routes @panel/ -- skipped
16
+ Intercepting routes (.)/ -- skipped
17
+ Private folders _components/ -- skipped
18
+
19
+ Usage:
20
+ node detect-routes-nextjs.mjs [options]
21
+
22
+ Options:
23
+ --app-dir <path> Path to app/ directory (default: src/app or app)
24
+ --manifest <path> Path to route-manifest.json (default: e2e/route-manifest.json)
25
+ --strict Exit 1 if any route is missing (default: true)
26
+ --no-strict Only warn, don't fail
27
+
28
+ Exit codes:
29
+ 0 -- all routes accounted for
30
+ 1 -- routes missing from manifest (strict mode)
31
+ */
32
+
33
+ import { readdirSync, existsSync, readFileSync, statSync } from 'fs';
34
+ import { join, resolve, relative, sep } from 'path';
35
+
36
+ // ─── CLI args ───────────────────────────────────────────────
37
+ const args = process.argv.slice(2);
38
+ function getArg(name, defaultVal) {
39
+ const idx = args.indexOf(`--${name}`);
40
+ return idx >= 0 && args[idx + 1] ? args[idx + 1] : defaultVal;
41
+ }
42
+ const hasFlag = (name) => args.includes(`--${name}`);
43
+ const strict = !hasFlag('no-strict');
44
+
45
+ // Auto-detect app directory
46
+ function findAppDir() {
47
+ const explicit = getArg('app-dir', '');
48
+ if (explicit) return resolve(explicit);
49
+ if (existsSync('src/app')) return resolve('src/app');
50
+ if (existsSync('app')) return resolve('app');
51
+ return null;
52
+ }
53
+
54
+ const appDir = findAppDir();
55
+ const manifestPath = resolve(getArg('manifest', 'e2e/route-manifest.json'));
56
+
57
+ if (!appDir || !existsSync(appDir)) {
58
+ console.error(`❌ App directory not found. Use --app-dir <path>`);
59
+ process.exit(1);
60
+ }
61
+
62
+ // ─── Route scanning ─────────────────────────────────────────
63
+
64
+ /**
65
+ * Recursively scan the app directory for page.tsx/ts and route.ts/tsx files.
66
+ * Returns an array of { path: string, type: 'page' | 'api', file: string }
67
+ */
68
+ function scanRoutes(dir, segments = []) {
69
+ const routes = [];
70
+ let entries;
71
+ try {
72
+ entries = readdirSync(dir, { withFileTypes: true });
73
+ } catch {
74
+ return routes;
75
+ }
76
+
77
+ // Check for route files in current directory
78
+ const pageFile = entries.find(
79
+ (e) => e.isFile() && /^page\.(tsx?|jsx?)$/.test(e.name)
80
+ );
81
+ const routeFile = entries.find(
82
+ (e) => e.isFile() && /^route\.(tsx?|jsx?)$/.test(e.name)
83
+ );
84
+
85
+ if (pageFile) {
86
+ const routePath = '/' + segments.join('/') || '/';
87
+ routes.push({
88
+ path: routePath === '/' ? '/' : routePath,
89
+ type: 'page',
90
+ file: relative(process.cwd(), join(dir, pageFile.name)),
91
+ });
92
+ }
93
+
94
+ if (routeFile) {
95
+ const routePath = '/' + segments.join('/') || '/';
96
+ routes.push({
97
+ path: routePath,
98
+ type: 'api',
99
+ file: relative(process.cwd(), join(dir, routeFile.name)),
100
+ });
101
+ }
102
+
103
+ // Recurse into subdirectories
104
+ for (const entry of entries) {
105
+ if (!entry.isDirectory()) continue;
106
+ const name = entry.name;
107
+
108
+ // Skip private folders (Next.js convention: _name)
109
+ if (name.startsWith('_')) continue;
110
+
111
+ // Skip parallel routes (@panel, @modal — not independent routes)
112
+ if (name.startsWith('@')) continue;
113
+
114
+ // Skip intercepting routes ((.), (..), (..)(..))
115
+ if (/^\(\.+\)/.test(name)) continue;
116
+
117
+ // Route groups: (groupName) => strip from path
118
+ if (/^\([^)]+\)$/.test(name) && !name.startsWith('(.)')) {
119
+ routes.push(...scanRoutes(join(dir, name), segments));
120
+ continue;
121
+ }
122
+
123
+ // Normal segment (including [dynamic], [...catchAll], [[...optional]])
124
+ routes.push(...scanRoutes(join(dir, name), [...segments, name]));
125
+ }
126
+
127
+ return routes;
128
+ }
129
+
130
+ // ─── Manifest comparison ────────────────────────────────────
131
+
132
+ // Load manifest
133
+ let manifest = { routes: [] };
134
+ if (existsSync(manifestPath)) {
135
+ try {
136
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
137
+ } catch (e) {
138
+ console.error(`❌ Invalid JSON in manifest: ${e.message}`);
139
+ process.exit(1);
140
+ }
141
+ } else {
142
+ console.error(`❌ Manifest not found: ${manifestPath}`);
143
+ console.error(` Create it with at minimum: { "version": 1, "routes": [] }`);
144
+ process.exit(1);
145
+ }
146
+
147
+ const manifestRoutes = new Set(
148
+ (manifest.routes || []).map((r) => r.path)
149
+ );
150
+ // Also check endpoints (for API routes in combined manifests)
151
+ const manifestEndpoints = new Set(
152
+ (manifest.endpoints || []).map((r) => r.path)
153
+ );
154
+ const allManifestPaths = new Set([...manifestRoutes, ...manifestEndpoints]);
155
+
156
+ // Scan
157
+ console.log(`🔍 Scanning: ${relative(process.cwd(), appDir)}/`);
158
+ console.log(`📋 Manifest: ${relative(process.cwd(), manifestPath)}\n`);
159
+
160
+ const appRoutes = scanRoutes(appDir);
161
+ const missing = [];
162
+ const accounted = [];
163
+
164
+ for (const route of appRoutes) {
165
+ if (allManifestPaths.has(route.path)) {
166
+ accounted.push(route);
167
+ } else {
168
+ missing.push(route);
169
+ }
170
+ }
171
+
172
+ // ─── Report ─────────────────────────────────────────────────
173
+
174
+ console.log(`Found ${appRoutes.length} routes in app (${appRoutes.filter(r => r.type === 'page').length} pages, ${appRoutes.filter(r => r.type === 'api').length} API routes)`);
175
+ console.log(`Manifest has ${allManifestPaths.size} entries`);
176
+ console.log(`Accounted: ${accounted.length} | Missing: ${missing.length}\n`);
177
+
178
+ if (missing.length > 0) {
179
+ console.log(`${'─'.repeat(60)}`);
180
+ console.log(`❌ Routes in app but NOT in manifest:\n`);
181
+ for (const route of missing) {
182
+ const tag = route.type === 'api' ? ' [API]' : '';
183
+ console.log(` ${route.path}${tag}`);
184
+ console.log(` └─ ${route.file}`);
185
+ }
186
+ console.log(`\n${'─'.repeat(60)}`);
187
+ console.log(`\nAdd these to ${relative(process.cwd(), manifestPath)}:`);
188
+ console.log(` { "path": "<route>", "tier": 1, "specs": [] }\n`);
189
+ console.log(`Routes with specs: [] will pass CI but show as uncovered`);
190
+ console.log(`in the E2E PR comment.\n`);
191
+
192
+ if (strict) {
193
+ console.log('🚫 Failing CI (strict mode). Use --no-strict to warn only.');
194
+ process.exit(1);
195
+ } else {
196
+ console.log('⚠️ Warning only (non-strict mode).');
197
+ }
198
+ } else {
199
+ console.log('✅ All app routes are accounted for in the manifest.');
200
+ }
@@ -0,0 +1,158 @@
1
+ // Evidence-posting step for `presentation:visual` (runs after `visual-baseline-regen`).
2
+ //
3
+ // Closes the visual evidence loop: after baselines are regenerated, persist the
4
+ // rendered evidence back to the work item — MECHANIZED, not a prose reminder (a
5
+ // described step degrades to a lookalike that silently no-ops).
6
+ //
7
+ // It UPSERTS a single marker-tagged comment (never appends) to BOTH the source
8
+ // issue and the PR, carrying:
9
+ // - the DURABLE committed-baseline link at the regenerated SHA (canonical —
10
+ // survives artifact expiry), and
11
+ // - the EPHEMERAL diff/preview artifact URL with its expiry noted.
12
+ // The same two URLs are RETURNED as a value (`--evidence-out <file>`, and always on
13
+ // stdout behind the `visual-evidence:` prefix) for the resolve-issues orchestrator to
14
+ // record as the unit's visual proof-of-execution. This step runs inside a spawn/CI
15
+ // job, and a spawn never writes the run manifest — the orchestrator is its only
16
+ // writer (ADR 0001 decision 5, issue #579). It used to shell out to the orchestrator's
17
+ // manifest CLI from here — the read-modify-write nothing guards once producers stop
18
+ // being serialized.
19
+ //
20
+ // Idempotent upsert is what keeps CI re-runs from spamming the work item — the
21
+ // marker `<!-- visual-evidence:<unit> -->` is matched and the comment edited in
22
+ // place. Posting a comment is outward-facing, but it is a CI bot writing an
23
+ // evidence comment this lane explicitly defines.
24
+ //
25
+ // Contract: ensure-coverage references/enforcement/ci-contract.md → "Evidence-
26
+ // posting step (after baseline-regen)".
27
+
28
+ import fs from 'node:fs'
29
+ import { execFileSync } from 'node:child_process'
30
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
31
+
32
+ // ---- pure, unit-testable core (no gh / no network) ----
33
+
34
+ export const MARKER = (unit) => `<!-- visual-evidence:${unit} -->`
35
+
36
+ // Build the durable, SHA-pinned link to a committed baseline PNG. Survives artifact
37
+ // expiry because it points at the file in git, not a CI artifact store.
38
+ export function durableBaselineLink({ repo, sha, path }) {
39
+ return `https://github.com/${repo}/blob/${sha}/${path}`
40
+ }
41
+
42
+ // Render the evidence comment body. Durable link is canonical (always present);
43
+ // the diff artifact is ephemeral and annotated with its expiry. `cells` is the
44
+ // list of regenerated (route, viewport, baselinePath) plus optional diffArtifact.
45
+ export function renderComment({ unit, repo, sha, cells, diffArtifact, diffExpiry }) {
46
+ const lines = [MARKER(unit), '', '### 🖼️ Visual baselines', '']
47
+ lines.push('**Durable** (committed at the regenerated SHA — survives artifact expiry):', '')
48
+ for (const c of cells) {
49
+ lines.push(`- \`${c.route}\` @${c.viewport} — [baseline](${durableBaselineLink({ repo, sha, path: c.baselinePath })})`)
50
+ }
51
+ if (diffArtifact) {
52
+ lines.push('', `**Preview** (ephemeral diff/render artifact — expires ${diffExpiry || 'per CI retention'}): ${diffArtifact}`)
53
+ }
54
+ lines.push('', '_A baseline change is reviewable evidence — it must correspond to a declared intended UI change, not a silent `--update-snapshots` to green._')
55
+ return lines.join('\n')
56
+ }
57
+
58
+ // The two URLs this step RETURNS, for the orchestrator to record as the unit's
59
+ // visual proof-of-execution. Named for the return, not the manifest: nothing in a
60
+ // leaf skill may write the manifest, and a helper called `manifestEvidence` invites
61
+ // exactly the call that was removed here.
62
+ export function returnedEvidence({ unit, repo, sha, cells, diffArtifact }) {
63
+ return {
64
+ unit,
65
+ visual: {
66
+ durableBaselines: cells.map((c) => ({
67
+ route: c.route, viewport: c.viewport,
68
+ url: durableBaselineLink({ repo, sha, path: c.baselinePath }),
69
+ })),
70
+ diffArtifact: diffArtifact || null,
71
+ },
72
+ }
73
+ }
74
+
75
+ // Decide upsert vs create from the existing comments on a target. Returns the id
76
+ // to edit, or null to create. `comments` is [{ id, body }].
77
+ export function findUpsertTarget(comments, unit) {
78
+ const marker = MARKER(unit)
79
+ const hit = (comments || []).find((c) => (c.body || '').includes(marker))
80
+ return hit ? hit.id : null
81
+ }
82
+
83
+ // Pure: extract the visual (route, viewport, baselinePath) cells from a
84
+ // presentation-results.json the sweep emitted (runner-contract.md result shape).
85
+ // Only `presentation:visual` rows carry a `baseline`; the floor levels don't.
86
+ export function cellsFromResults(results) {
87
+ const rows = (results && Array.isArray(results.results)) ? results.results : []
88
+ return rows
89
+ .filter((r) => r.level === 'presentation:visual' && r.baseline)
90
+ .map((r) => ({ route: r.route, viewport: r.viewport, baselinePath: r.baseline }))
91
+ }
92
+
93
+ // Pure: parse argv into the options the CLI needs. Kept pure so it's tested.
94
+ export function parseArgs(argv) {
95
+ const o = {}
96
+ for (let i = 0; i < argv.length; i++) {
97
+ const a = argv[i]
98
+ if (a.startsWith('--')) o[a.slice(2)] = (argv[i + 1] && !argv[i + 1].startsWith('--')) ? argv[++i] : 'true'
99
+ }
100
+ return o
101
+ }
102
+
103
+ // ---- gh + fs wrapper (thin; the pure core above is what doctrine pins) ----
104
+
105
+ function gh(args) {
106
+ return execFileSync('gh', args, { encoding: 'utf8' })
107
+ }
108
+
109
+ // Upsert the marker comment on one target (issue or PR — both are "issues" to gh).
110
+ // Edits in place when the marker already exists (idempotent across CI re-runs),
111
+ // else creates. Listing is via `gh api` so we can match the hidden marker.
112
+ function upsertComment(repo, number, unit, body) {
113
+ let existing = []
114
+ try {
115
+ existing = JSON.parse(gh(['api', `repos/${repo}/issues/${number}/comments`, '--paginate',
116
+ '--jq', '[.[] | {id: .id, body: .body}]']))
117
+ } catch { existing = [] }
118
+ const id = findUpsertTarget(existing, unit)
119
+ if (id) gh(['api', '--method', 'PATCH', `repos/${repo}/issues/comments/${id}`, '-f', `body=${body}`])
120
+ else gh(['issue', 'comment', String(number), '--repo', repo, '--body', body])
121
+ }
122
+
123
+ function main() {
124
+ const o = parseArgs(process.argv.slice(2))
125
+ const required = ['unit', 'repo', 'sha', 'results']
126
+ const missing = required.filter((k) => !o[k])
127
+ if (missing.length) { console.error(`post-visual-evidence: missing --${missing.join(', --')}`); process.exit(2) }
128
+
129
+ const results = JSON.parse(fs.readFileSync(o.results, 'utf8'))
130
+ const cells = cellsFromResults(results)
131
+
132
+ // Zero cells is a real answer ("this unit has no `presentation:visual` surface"), not
133
+ // an absence of one — so it still travels the return channel. Bailing before the
134
+ // marker and the file made the two indistinguishable to the orchestrator, and left
135
+ // the lane's `if: always()` artifact upload warning on a path that had simply
136
+ // finished. Only the outward-facing comment is skipped: there is nothing to say.
137
+ if (cells.length > 0) {
138
+ const body = renderComment({
139
+ unit: o.unit, repo: o.repo, sha: o.sha, cells,
140
+ diffArtifact: o['diff-artifact'], diffExpiry: o['diff-expiry'],
141
+ })
142
+ for (const target of [o.issue, o.pr].filter(Boolean)) upsertComment(o.repo, target, o.unit, body)
143
+ }
144
+
145
+ // Return the same URLs as a value. The orchestrator records them on the unit; this
146
+ // step does not touch the run manifest, because the orchestrator is its only writer
147
+ // (ADR 0001 decision 5). Always on stdout (so a spawn can quote it back in its
148
+ // result), and to a file when the caller wants it as a CI artifact.
149
+ const evidence = returnedEvidence({ unit: o.unit, repo: o.repo, sha: o.sha, cells, diffArtifact: o['diff-artifact'] })
150
+ console.log(`visual-evidence: ${JSON.stringify(evidence)}`)
151
+ if (o['evidence-out']) fs.writeFileSync(o['evidence-out'], `${JSON.stringify(evidence, null, 2)}\n`)
152
+
153
+ console.log(cells.length === 0
154
+ ? 'post-visual-evidence: no presentation:visual cells in results — nothing to comment; returned an empty evidence value'
155
+ : `post-visual-evidence: upserted visual evidence for ${cells.length} cell(s)`)
156
+ }
157
+
158
+ if (isMainModule(import.meta.url)) main()