@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,405 @@
1
+ // Post a review-pr verdict + findings to GitHub as ONE review (inline comments +
2
+ // summary + verdict event), handling the self-authored-PR downgrade. The fiddly,
3
+ // error-prone glue that should be code, not prose. Pure core is unit-tested; the
4
+ // `gh` calls live only in the CLI.
5
+ //
6
+ // node post-review.mjs --findings review.json --pr 482 [--repo owner/name]
7
+ // [--pr-context pr-context.json] [--dry-run] [--file-issues]
8
+ //
9
+ // `review.json` matches schemas/findings.schema.json: { verdict, summary, findings[] }.
10
+ // Verification is enforced upstream by that schema — a finding with no file/line is
11
+ // invalid and this script refuses to post it. The BLOCK-n/NOTE-n label and the
12
+ // verdict are DERIVED here from each finding's {priority, in_scope}; the reviewer
13
+ // never writes them. Non-blocking notes and out-of-scope criticals route to tracked
14
+ // issues — but ONLY under --file-issues (default OFF prints what it WOULD open),
15
+ // because opening an issue is an outward action. --pr-context reuses pr-context.mjs's
16
+ // own changed-file list to catch a finding whose path is not actually in the diff
17
+ // (in_scope alone is not a reliable proxy for that — #635); never anchored inline
18
+ // either way, only where the detail lands (comment vs. review-body section) changes.
19
+
20
+ import fs from 'node:fs'
21
+ import { execFileSync } from 'node:child_process'
22
+ import {
23
+ validateFinding,
24
+ validateReviewDocument,
25
+ reviewDocumentWarnings,
26
+ isBlockingFinding,
27
+ isOutOfScopeCritical,
28
+ findingInScope,
29
+ } from './finding-contract.mjs'
30
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
31
+
32
+ // ---- pure core ----
33
+
34
+ export const VERDICT_EVENT = {
35
+ PASS: 'APPROVE',
36
+ NEEDS_CHANGES: 'REQUEST_CHANGES',
37
+ FAIL: 'REQUEST_CHANGES',
38
+ BLOCKED: 'COMMENT',
39
+ }
40
+
41
+ // Map verdict -> GitHub review event, downgrading to COMMENT on a self-authored PR
42
+ // (GitHub forbids APPROVE/REQUEST_CHANGES on your own PR).
43
+ export function resolveEvent(verdict, { selfAuthored = false } = {}) {
44
+ const base = VERDICT_EVENT[verdict]
45
+ if (!base) throw new Error(`unknown verdict: ${verdict}`)
46
+ if (selfAuthored && (base === 'APPROVE' || base === 'REQUEST_CHANGES')) {
47
+ return { event: 'COMMENT', downgraded: true, intended: base }
48
+ }
49
+ return { event: base, downgraded: false, intended: base }
50
+ }
51
+
52
+ // Enforce the finding contract (the part the schema guarantees, re-checked here so a
53
+ // hand-built file can't post a location-less "finding").
54
+ export function validateFindings(findings) {
55
+ if (!Array.isArray(findings)) return ['findings is not an array']
56
+ return findings.flatMap((finding, index) => validateFinding(finding, index))
57
+ }
58
+
59
+ export { validateReviewDocument }
60
+
61
+ // ---- rendered contract: label, verdict, and issue routing are DERIVED here ----
62
+ //
63
+ // The reviewer model returns JSON only ({priority, in_scope, ...}); it never
64
+ // writes a label prefix or the final verdict. post-review.mjs renders both, so
65
+ // any reviewer model maps to one output (#399). `blocking` is not a stored field:
66
+ // it is `in_scope && priority <= 1`, computed by isBlockingFinding.
67
+
68
+ // Assign a rendered label to each finding, sequenced per class:
69
+ // in_scope && priority<=1 → BLOCK-n (holds the PR)
70
+ // everything else → NOTE-n
71
+ // An out-of-scope critical (!in_scope && priority<=1) is a NOTE-n label but is
72
+ // surfaced loudly (its own issue + a warning), never buried — see planIssues.
73
+ export function renderFindings(findings) {
74
+ let blockN = 0
75
+ let noteN = 0
76
+ return findings.map((finding) => {
77
+ const blocking = isBlockingFinding(finding)
78
+ const outOfScopeCritical = isOutOfScopeCritical(finding)
79
+ const label = blocking ? `BLOCK-${++blockN}` : `NOTE-${++noteN}`
80
+ return { finding, label, blocking, outOfScopeCritical }
81
+ })
82
+ }
83
+
84
+ // Verdict is mechanized: NEEDS_CHANGES iff ≥1 BLOCK-n, else PASS. FAIL/BLOCKED are
85
+ // structural reviewer calls (unusable contract / unreachable evidence) and pass
86
+ // through untouched.
87
+ export function deriveVerdict(declaredVerdict, findings) {
88
+ if (declaredVerdict === 'FAIL' || declaredVerdict === 'BLOCKED') return declaredVerdict
89
+ return findings.some((finding) => isBlockingFinding(finding)) ? 'NEEDS_CHANGES' : 'PASS'
90
+ }
91
+
92
+ function prLink({ pr, repo } = {}) {
93
+ if (repo && pr != null) return `https://github.com/${repo}/pull/${pr}`
94
+ if (pr != null) return `#${pr}`
95
+ return 'this PR'
96
+ }
97
+
98
+ // The loud, free warning: prints regardless of any flag, and rides in the review
99
+ // body + handoff. An out-of-scope critical does not block the PR, so nothing else
100
+ // forces a human to look at it — the warning is that forcing function.
101
+ export function outOfScopeCriticalWarnings(findings, context = {}) {
102
+ return renderFindings(findings)
103
+ .filter(({ outOfScopeCritical }) => outOfScopeCritical)
104
+ .map(({ finding: f, label }) =>
105
+ `> ⚠️ **OUT-OF-SCOPE CRITICAL — ${label} (does NOT block this PR):** ${f.title} — \`${f.file}:${f.line_start}\` ` +
106
+ `(priority ${f.priority}, confidence ${f.confidence}). A dedicated critical/security issue is owed; do not fold it into the refactor-later batch.`)
107
+ }
108
+
109
+ // Plan the tracked issues a set of findings should open — pure, returns intended
110
+ // payloads (never shells out). The CLI decides whether to create them (--file-issues)
111
+ // or print them (default). Two kinds:
112
+ // refactor-later — ONE batched issue for every priority>=2 note (both scopes).
113
+ // out-of-scope-critical — ONE dedicated issue per !in_scope && priority<=1 finding.
114
+ export function planIssues(findings, context = {}) {
115
+ const rendered = renderFindings(findings)
116
+ const link = prLink(context)
117
+ const notes = rendered.filter(({ finding }) => Number.isInteger(finding.priority) && finding.priority >= 2)
118
+ const criticals = rendered.filter(({ outOfScopeCritical }) => outOfScopeCritical)
119
+ const issues = []
120
+ if (notes.length) {
121
+ const rows = notes.map(({ finding: f, label }) =>
122
+ `- **${label}** ${f.in_scope === false ? '(out-of-scope) ' : ''}${f.title} — \`${f.file}:${f.line_start}\`` +
123
+ (f.recommendation ? ` — ${f.recommendation}` : ''))
124
+ issues.push({
125
+ kind: 'refactor-later',
126
+ labels: ['refactor-later'],
127
+ title: `refactor-later: ${notes.length} deferred note${notes.length === 1 ? '' : 's'} from ${link}`,
128
+ body: `Deferred non-blocking notes batched from ${link} — not merge-blocking, tracked so they are neither lost nor left holding attention on the PR.\n\n${rows.join('\n')}`,
129
+ })
130
+ }
131
+ for (const { finding: f, label } of criticals) {
132
+ issues.push({
133
+ kind: 'out-of-scope-critical',
134
+ labels: ['critical', 'security'],
135
+ title: `out-of-scope critical: ${f.title}`,
136
+ body: `Surfaced as ${label} from ${link} — a priority-${f.priority} issue in code the PR did not change, so it does NOT block that PR but must not be buried in a refactor batch.\n\n` +
137
+ `**Location:** \`${f.file}:${f.line_start}\`\n**Why:** ${f.why}` +
138
+ (f.consequence ? `\n**Consequence:** ${f.consequence}` : '') +
139
+ (f.recommendation ? `\n**Fix:** ${f.recommendation}` : ''),
140
+ })
141
+ }
142
+ return issues
143
+ }
144
+
145
+ export function commentBody(f, label) {
146
+ const prefix = label ? `${label}: ` : ''
147
+ let body = `**${prefix}${f.title}** _(priority ${f.priority}, confidence ${f.confidence})_` +
148
+ (f.theme?.contract ? `\n\n**Governing contract:** ${f.theme.contract}` : '') +
149
+ `\n\n${f.why}` +
150
+ (f.consequence ? `\n\n**Consequence:** ${f.consequence}` : '') +
151
+ (f.recommendation ? `\n\n**Fix:** ${f.recommendation}` : '')
152
+ // A domain-semantic blocker's hazard_candidate is the ready-to-paste repo-hazards row the
153
+ // fix commit owes (docs/domain-hazards.md). The posted review is the durable form the fix
154
+ // agent works from — dropping the row here would force the fixer to reinvent it and leave
155
+ // the re-reviewer nothing to verify the written row against.
156
+ const h = f.hazard_candidate
157
+ if (h && (h.covered_by || h.rule)) {
158
+ body += h.covered_by
159
+ ? `\n\n**Hazard row:** covered by \`${h.covered_by}\` in \`docs/domain-hazards.md\` — no new row owed.`
160
+ : `\n\n**Hazard row owed** (\`docs/domain-hazards.md\` → ${h.section || 'cross-cutting'}):\n\n\`\`\`markdown\n| ${h.id || '<id>'} | ${h.rule} | ${h.prove || '<what to prove>'} | <this PR> |\n\`\`\``
161
+ }
162
+ return body
163
+ }
164
+
165
+ // ---- #635: is a finding's file actually IN the diff? ----
166
+ //
167
+ // `pr-context.mjs` computes the changed-file list once, at review-establishment
168
+ // time, as `changedFiles: [{status, path}]` (see its --base CLI). Reuse that same
169
+ // list here rather than recomputing it — post-review.mjs never shells out to git
170
+ // or `gh` to rediscover the diff; the CLI accepts it via `--pr-context <file>`
171
+ // (pr-context.mjs's own JSON output) so the two steps of one review share one
172
+ // computation instead of drifting.
173
+
174
+ // Normalize a path for changed-file/finding-file comparison. The diff list and a
175
+ // finding's `file` can name the same path while disagreeing on a leading `./`,
176
+ // backslashes, a leading `/` (repo-relative vs. an absolute path the reviewer
177
+ // pasted), or case (a case-insensitive checkout vs. GitHub's committed case).
178
+ export function normalizeDiffPath(p) {
179
+ if (!p) return ''
180
+ return String(p).replace(/\\/g, '/').replace(/^(\.\/)+/, '').replace(/^\/+/, '').toLowerCase()
181
+ }
182
+
183
+ // Build the changed-file set from pr-context.mjs's own `changedFiles` shape
184
+ // ([{status, path}]), or a bare array of path strings. `null` (not an array at
185
+ // all) means "the diff is unknown" — distinct from an empty Set ("known: nothing
186
+ // changed") — so `anchorable` below can tell "can't verify" from "verified: not
187
+ // in the diff".
188
+ export function changedFileSet(changedFiles) {
189
+ if (!Array.isArray(changedFiles)) return null
190
+ const set = new Set()
191
+ for (const entry of changedFiles) {
192
+ const p = typeof entry === 'string' ? entry : entry?.path
193
+ if (p) set.add(normalizeDiffPath(p))
194
+ }
195
+ return set
196
+ }
197
+
198
+ // Can this finding be anchored as an inline comment? Two independent gates:
199
+ // - in_scope (the reviewer's judgment — unchanged from #628/#399), and
200
+ // - the file is actually in the diff, when the diff is known (#635) — an
201
+ // in_scope finding earned by tracing into unchanged code to prove impact can
202
+ // still name a file the diff never touched, and GitHub 422s on that path
203
+ // exactly like it does for an out-of-scope one.
204
+ // `knownChangedFiles === null` means the caller could not establish the diff (no
205
+ // `--pr-context`, an unreadable/malformed file, a git/gh error upstream of it) —
206
+ // fail TOWARD POSTING: keep the pre-#635 permissive behavior (in_scope alone
207
+ // decides) rather than guessing either way about a diff this run cannot see. A
208
+ // finding is never dropped either way — undecidable-but-in-scope still anchors
209
+ // (old behavior); anything that fails the check lands in the body instead.
210
+ export function anchorable(finding, knownChangedFiles) {
211
+ if (!findingInScope(finding)) return false
212
+ if (knownChangedFiles === null) return true
213
+ return knownChangedFiles.has(normalizeDiffPath(finding.file))
214
+ }
215
+
216
+ // An out-of-scope finding's file is by definition absent from the diff — GitHub
217
+ // refuses to anchor a review comment there and 422s the ENTIRE review, losing the
218
+ // verdict, the summary, and every in-scope comment with it (#628). So an
219
+ // out-of-scope finding never reaches `comments`; this renders the detail an
220
+ // inline comment would have carried (why/consequence/fix) into the review body
221
+ // instead — the only place left for it, since a `NOTE-n` label alone would bury
222
+ // it and, for a non-critical note, `--file-issues` is opt-in and OFF by default.
223
+ // An out-of-scope CRITICAL still gets this in addition to its existing loud
224
+ // warning above (`outOfScopeCriticalWarnings`) — that warning alone omits
225
+ // why/consequence/recommendation, so without this section a critical's full
226
+ // reasoning would vanish along with its inline comment.
227
+ //
228
+ // #635: `in_scope` was only ever a proxy for "this file is in the diff", and the
229
+ // proxy is inexact in the direction that still 422s the whole review — review-pr's
230
+ // own doctrine (SKILL.md § Review Posture) permits tracing into UNCHANGED code to
231
+ // *prove* impact, so a finding can be `in_scope: true` and still name a file the
232
+ // diff never touched. So this section now also catches any finding — in scope or
233
+ // not — whose `file` isn't in the known changed-file list, subsuming the in_scope
234
+ // check rather than sitting beside it: the question is no longer "is this in
235
+ // scope?" (a judgment) but "is this path in the diff?" (a fact `changedFiles`,
236
+ // when known, settles). `in_scope`'s own effect is unchanged either way.
237
+ export function outOfScopeFindingsBody(rendered, { changedFiles } = {}) {
238
+ const knownChangedFiles = changedFileSet(changedFiles)
239
+ const diverted = rendered.filter(({ finding: f }) => !anchorable(f, knownChangedFiles))
240
+ if (!diverted.length) return ''
241
+ const blocks = diverted.map(({ finding: f, label }) => {
242
+ const reason = !findingInScope(f) ? 'out-of-scope — not anchored inline' : 'file not in diff — not anchored inline'
243
+ return `**${label} — \`${f.file}:${f.line_start}\`** _(${reason})_\n\n${commentBody(f, null)}`
244
+ })
245
+ return `## Findings not anchored inline\n\n${blocks.join('\n\n---\n\n')}`
246
+ }
247
+
248
+ // Build the single-review payload for POST /repos/{o}/{r}/pulls/{n}/reviews.
249
+ // The verdict is DERIVED from the findings ({priority, in_scope}), not taken from
250
+ // the reviewer's declared field; each inline comment carries its rendered
251
+ // BLOCK-n/NOTE-n label; out-of-scope criticals ride a loud warning at the top.
252
+ // `changedFiles` is the diff's changed-file list (pr-context.mjs's own shape,
253
+ // [{status, path}]) — optional, and never part of the reviewer's document (like
254
+ // `pr`/`repo`, it's a posting-time input, not something the model emits).
255
+ export function buildReviewPayload({ verdict, summary = '', findings = [], selfAuthored = false, pr, repo, changedFiles, ...metadata }) {
256
+ const documentErrors = validateReviewDocument({ verdict, summary, findings, ...metadata })
257
+ if (documentErrors.length) throw new Error(`invalid review document: ${documentErrors.join('; ')}`)
258
+ const derivedVerdict = deriveVerdict(verdict, findings)
259
+ const { event, downgraded, intended } = resolveEvent(derivedVerdict, { selfAuthored })
260
+ const rendered = renderFindings(findings)
261
+ const knownChangedFiles = changedFileSet(changedFiles)
262
+ let body = summary || `Review verdict: ${derivedVerdict}`
263
+ if (downgraded) {
264
+ const kind = intended === 'APPROVE' ? 'approve' : 'request changes on'
265
+ body = `> **Intended verdict: ${derivedVerdict}** — posted as a comment because the reviewer authored this PR and GitHub does not allow you to ${kind} your own PR. Treat the findings below as binding.\n\n${body}`
266
+ }
267
+ const warnings = outOfScopeCriticalWarnings(findings, { pr, repo })
268
+ if (warnings.length) body = `${warnings.join('\n\n')}\n\n${body}`
269
+ const oosBody = outOfScopeFindingsBody(rendered, { changedFiles })
270
+ if (oosBody) body = `${body}\n\n${oosBody}`
271
+ const comments = rendered
272
+ .filter(({ finding: f }) => anchorable(f, knownChangedFiles)) // never anchor out-of-scope or off-diff — see outOfScopeFindingsBody
273
+ .map(({ finding: f, label }) => {
274
+ const lineCount = f.line_count ?? 1 // line_count is optional; a bare line_start anchors one line
275
+ return {
276
+ path: f.file,
277
+ line: f.line_start + lineCount - 1,
278
+ side: 'RIGHT',
279
+ ...(lineCount > 1
280
+ ? { start_line: f.line_start, start_side: 'RIGHT' }
281
+ : {}),
282
+ body: commentBody(f, label),
283
+ }
284
+ })
285
+ // #941 / epic-876: self-authored downgrade is a first-class posting fact for guarantee 2.
286
+ // Orchestrators must record reviewPostedAs on the unit when downgraded — COMMENT + intended
287
+ // PASS + model read-back is the proof, not a GitHub APPROVE event (which GitHub forbids).
288
+ return {
289
+ event,
290
+ body,
291
+ comments,
292
+ verdict: derivedVerdict,
293
+ reviewPostedAs: downgraded ? 'comment-self-authored' : (event === 'COMMENT' ? 'comment' : 'review-event'),
294
+ selfAuthored: !!selfAuthored,
295
+ intendedEvent: intended,
296
+ }
297
+ }
298
+
299
+ // ---- CLI (gh side effects) ----
300
+
301
+ function gh(args, opts = {}) {
302
+ return execFileSync('gh', args, { encoding: 'utf8', ...opts }).trim()
303
+ }
304
+
305
+ function parseArgs(argv) {
306
+ const f = {}
307
+ for (let i = 2; i < argv.length; i++) {
308
+ const a = argv[i]
309
+ if (a === '--dry-run') f.dryRun = true
310
+ else if (a === '--no-self-check') f.noSelfCheck = true
311
+ else if (a === '--file-issues') f.fileIssues = true
312
+ else if (a.startsWith('--')) f[a.slice(2)] = argv[++i]
313
+ }
314
+ return f
315
+ }
316
+
317
+ // Load the changed-file list from a saved `pr-context.mjs` JSON output (its own
318
+ // `--base <target>` invocation, piped to a file at review-establishment time — see
319
+ // SKILL.md § Review Workflow step 1). Never throws: a missing/unreadable/malformed
320
+ // file is exactly the "unavailable" case `anchorable` already handles by failing
321
+ // TOWARD POSTING, so this warns and returns `undefined` rather than crashing a run
322
+ // that would otherwise post cleanly.
323
+ function loadChangedFiles(prContextPath) {
324
+ if (!prContextPath) return undefined
325
+ try {
326
+ const ctx = JSON.parse(fs.readFileSync(prContextPath, 'utf8'))
327
+ if (Array.isArray(ctx.changedFiles)) return ctx.changedFiles
328
+ console.error(`warning: --pr-context ${prContextPath} has no changedFiles array; not validating comment paths against the diff`)
329
+ } catch (e) {
330
+ console.error(`warning: could not read --pr-context ${prContextPath} (${e.message}); not validating comment paths against the diff`)
331
+ }
332
+ return undefined
333
+ }
334
+
335
+ // Print, or actually open, the tracked issues these findings route to. Issue
336
+ // creation is an OUTWARD action, so it is gated behind --file-issues and DEFAULTS
337
+ // OFF: without the flag we only print what WOULD open. The loud out-of-scope
338
+ // warnings print in EITHER mode — a warning is free; opening an issue is not.
339
+ function routeIssues(findings, { pr, repo, fileIssues, ghImpl = gh }) {
340
+ for (const warning of outOfScopeCriticalWarnings(findings, { pr, repo })) console.error(warning)
341
+ const issues = planIssues(findings, { pr, repo })
342
+ if (!issues.length) return
343
+ if (!fileIssues) {
344
+ console.log(`\n--file-issues not set (default) — would open ${issues.length} issue(s); pass --file-issues to create them:`)
345
+ for (const issue of issues) console.log(` [${issue.kind}] ${issue.title} labels: ${issue.labels.join(',')}`)
346
+ return
347
+ }
348
+ for (const issue of issues) {
349
+ const args = ['issue', 'create', '--title', issue.title, '--body', issue.body]
350
+ if (repo) args.push('--repo', repo)
351
+ for (const label of issue.labels) args.push('--label', label)
352
+ const url = ghImpl(args)
353
+ console.log(`opened [${issue.kind}] ${url}`)
354
+ }
355
+ }
356
+
357
+ function main() {
358
+ const a = parseArgs(process.argv)
359
+ if (!a.findings || !a.pr) {
360
+ console.error('usage: post-review.mjs --findings <file.json> --pr <number> [--repo owner/name] [--pr-context <pr-context.json>] [--dry-run] [--no-self-check] [--file-issues]')
361
+ process.exit(2)
362
+ }
363
+ const data = JSON.parse(fs.readFileSync(a.findings, 'utf8'))
364
+ const errs = validateReviewDocument(data)
365
+ if (errs.length) {
366
+ console.error('Refusing to post — invalid findings:\n ' + errs.join('\n '))
367
+ process.exit(2)
368
+ }
369
+ // Read-tolerance: a finding still carrying a removed field (e.g. blocking) warns
370
+ // but never blocks posting; the derived value is used.
371
+ for (const w of reviewDocumentWarnings(data)) console.error(`warn: ${w}`)
372
+ let selfAuthored = false
373
+ if (!a.noSelfCheck) {
374
+ try {
375
+ const me = gh(['api', 'user', '--jq', '.login'])
376
+ const author = gh(['pr', 'view', String(a.pr), '--json', 'author', '--jq', '.author.login'])
377
+ selfAuthored = me === author
378
+ } catch {
379
+ console.error('warning: could not determine reviewer vs author; not downgrading. Pass --no-self-check to silence.')
380
+ }
381
+ }
382
+ // --repo is optional for the review post and for opening issues (resolved from
383
+ // gh when actually posting); --dry-run resolves nothing (PR links fall back to #n).
384
+ const repo = a.repo || (a.dryRun ? undefined : gh(['repo', 'view', '--json', 'nameWithOwner', '--jq', '.nameWithOwner']))
385
+ // --pr-context reuses the changed-file list pr-context.mjs already computed at
386
+ // review-establishment time (its own JSON stdout, saved to a file) — this script
387
+ // never recomputes the diff itself. Omitted/unreadable => undefined => anchorable()
388
+ // falls back to the pre-#635 in_scope-only check (see its doc comment).
389
+ const changedFiles = loadChangedFiles(a['pr-context'])
390
+ const { verdict, reviewPostedAs, selfAuthored: postedSelf, intendedEvent, ...payload } = buildReviewPayload({ ...data, selfAuthored, pr: a.pr, repo, changedFiles })
391
+ if (a.dryRun) {
392
+ // --dry-run touches nothing: it never posts the review and never opens an
393
+ // issue, even with --file-issues — it prints what both would do.
394
+ console.log(JSON.stringify({ ...payload, verdict, reviewPostedAs, selfAuthored: postedSelf, intendedEvent }, null, 2))
395
+ console.log(`\nDerived verdict: ${verdict} (from ${data.findings.length} finding(s)); reviewPostedAs=${reviewPostedAs}`)
396
+ routeIssues(data.findings, { pr: a.pr, repo, fileIssues: false })
397
+ return
398
+ }
399
+ // Strip orchestrator-only fields before the GitHub reviews API body.
400
+ execFileSync('gh', ['api', `repos/${repo}/pulls/${a.pr}/reviews`, '--method', 'POST', '--input', '-'], { input: JSON.stringify(payload), stdio: ['pipe', 'inherit', 'inherit'] })
401
+ console.log(`posted ${payload.event} (verdict ${verdict}; reviewPostedAs=${reviewPostedAs})${postedSelf ? ' (self-authored → downgraded)' : ''} with ${payload.comments.length} inline comment(s)`)
402
+ routeIssues(data.findings, { pr: a.pr, repo, fileIssues: a.fileIssues })
403
+ }
404
+
405
+ if (isMainModule(import.meta.url)) main()
@@ -0,0 +1,207 @@
1
+ // Establish the review SUBJECT correctly, every time: the net three-dot diff from
2
+ // the merge-base, the changed files, and the commit list (for the history scan).
3
+ // Pure git — language-agnostic. Pure parsers are unit-tested; git calls live in
4
+ // the CLI. Removes the classic diff-discipline footgun (two-dot vs three-dot, wrong
5
+ // base) so the reviewer reasons over the right change-set.
6
+ //
7
+ // node pr-context.mjs --base main [--head HEAD] [--head-ref <branch-name>]
8
+ // # prints JSON review context
9
+ //
10
+ // The range it emits is `<merge-base>...HEAD` (three-dot = what would merge), which
11
+ // is what review-method.md requires.
12
+ //
13
+ // PROMOTION SIGNAL. `promotion: true` marks a release/integration branch being merged
14
+ // into production (review as a release: fast-forward gate + readiness checklist, not a
15
+ // line-by-line re-review). It requires BOTH halves: the BASE is a production branch
16
+ // (main/master/production/prod) AND the HEAD is a recognized integration/release branch
17
+ // (dev, develop, release/*, hotfix/*, staging, staging/*). A base check alone is wrong
18
+ // in a trunk-based repo, where every feature PR targets `main` — those are feature PRs,
19
+ // not promotions (see issue #392).
20
+ //
21
+ // The head is classified by its BRANCH NAME. `--head` is a rev (default HEAD); the name
22
+ // is resolved from it (`git rev-parse --abbrev-ref`), or you may pass it explicitly with
23
+ // `--head-ref`. When the name cannot be resolved (a detached HEAD or a bare SHA — nothing
24
+ // to classify), the SAFE DEFAULT is `promotion: false`: treating a real promotion as a
25
+ // feature PR just runs the normal review; the reverse (issue #392's bug) mis-routes it.
26
+
27
+ import { execFileSync } from 'node:child_process'
28
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
29
+
30
+ // ---- pure core ----
31
+
32
+ export function threeDotRange(base, head = 'HEAD') {
33
+ return `${base}...${head}`
34
+ }
35
+
36
+ // Parse `git diff --name-status <range>` → [{status, path}] (handles rename "R100\told\tnew").
37
+ export function parseNameStatus(text) {
38
+ return (text || '').split(/\r?\n/).filter(Boolean).map((line) => {
39
+ const parts = line.split('\t')
40
+ const status = parts[0]
41
+ const path = status.startsWith('R') || status.startsWith('C') ? parts[parts.length - 1] : parts[1]
42
+ return { status, path }
43
+ })
44
+ }
45
+
46
+ // Parse `git log --oneline <base>..HEAD` → [{sha, subject}] (two-dot here is correct:
47
+ // the commits unique to the PR head).
48
+ export function parseLog(text) {
49
+ return (text || '').split(/\r?\n/).filter(Boolean).map((line) => {
50
+ const sp = line.indexOf(' ')
51
+ return sp === -1 ? { sha: line, subject: '' } : { sha: line.slice(0, sp), subject: line.slice(sp + 1) }
52
+ })
53
+ }
54
+
55
+ // A promotion (e.g. dev→main) must FAST-FORWARD: the base must be an ancestor of
56
+ // HEAD, i.e. no commits live on base that HEAD lacks. A non-empty list = base has
57
+ // commits (usually hotfixes) the promotion would REVERT — hold and back-merge first.
58
+ export function fastForwardable(commitsOnBaseNotInHead) {
59
+ return (commitsOnBaseNotInHead || []).length === 0
60
+ }
61
+
62
+ // A promotion TARGET: the base is a production branch. Necessary but NOT sufficient —
63
+ // a promotion also needs an integration/release HEAD (see isPromotion). Keying on this
64
+ // alone flags every feature PR in a trunk-based repo as a promotion (issue #392).
65
+ export function isPromotionTarget(baseRef) {
66
+ return /(^|\/)(main|master|production|prod)$/.test(baseRef || '')
67
+ }
68
+
69
+ // Conventional remote names recognized in the SHORT remote-tracking form
70
+ // (`origin/dev`). The full `refs/remotes/<remote>/…` form strips any remote segment
71
+ // because the namespace is explicit and unambiguous; the short form is ambiguous with
72
+ // an ordinary namespaced branch (`jsmith/dev`), so we only strip a KNOWN remote — never
73
+ // an arbitrary first segment. This is normalization, not part of the integration
74
+ // allowlist.
75
+ const KNOWN_REMOTES = ['origin', 'upstream']
76
+
77
+ // Normalize a head ref to a bare branch name by stripping ONLY known ref prefixes, so
78
+ // the integration/release name (if any) lands at the START of the string. Handles the
79
+ // three git ref shapes: `refs/heads/<name>`, `refs/remotes/<remote>/<name>`, and the
80
+ // short remote-tracking `<known-remote>/<name>`. It NEVER strips an arbitrary leading
81
+ // path segment — that is exactly the any-prefix hole (issue #392) this closes: a
82
+ // namespaced feature branch like `feature/release/notes` or `jsmith/dev` keeps its
83
+ // namespace and so cannot masquerade as an integration branch.
84
+ export function normalizeHeadName(headRef) {
85
+ const name = headRef || ''
86
+ if (name.startsWith('refs/heads/')) return name.slice('refs/heads/'.length)
87
+ if (name.startsWith('refs/remotes/')) {
88
+ // drop `refs/remotes/` + exactly ONE remote segment
89
+ return name.slice('refs/remotes/'.length).replace(/^[^/]+\//, '')
90
+ }
91
+ for (const remote of KNOWN_REMOTES) {
92
+ if (name.startsWith(`${remote}/`)) return name.slice(remote.length + 1)
93
+ }
94
+ return name
95
+ }
96
+
97
+ // A promotion HEAD: an integration or release branch, by NAME. A small, documented
98
+ // allowlist of integration/release shapes — dev/develop, staging, and release/hotfix/
99
+ // staging/*. After normalizing away known ref prefixes (`refs/heads/`, `refs/remotes/`,
100
+ // and short `origin/`-style remotes), the integration name is matched ANCHORED AT THE
101
+ // START (`^`): the exact whole-name shapes (`dev`/`develop`/`staging`) and the path
102
+ // shapes (`release/`/`hotfix/`/`staging/`). The name must OPEN the branch, never be
103
+ // buried under a namespace — so `origin/dev` and `refs/heads/develop` resolve, but a
104
+ // namespaced feature branch like `feature/release/notes` or `jsmith/dev` does not.
105
+ // Anything else (the common case: an ordinary feature branch, or an unresolvable bare
106
+ // SHA) → false.
107
+ export function isIntegrationBranch(headRef) {
108
+ const name = normalizeHeadName(headRef)
109
+ // exact whole-name integration branches: dev, develop, staging
110
+ if (/^(dev|develop|staging)$/.test(name)) return true
111
+ // release-family branches with a version/name suffix, name at the START: release/*, hotfix/*, staging/*
112
+ if (/^(release|hotfix|staging)\//.test(name)) return true
113
+ return false
114
+ }
115
+
116
+ // A PROMOTION = a production BASE receiving an integration/release HEAD. Both halves
117
+ // required. Review it as a release (fast-forward gate + readiness checklist), not a
118
+ // line-by-line re-review of feature code already merged & green on the integration
119
+ // branch. An unresolvable head (bare SHA → not integration-shaped) yields false, the
120
+ // documented safe default.
121
+ export function isPromotion(baseRef, headRef) {
122
+ return isPromotionTarget(baseRef) && isIntegrationBranch(headRef)
123
+ }
124
+
125
+ // The reviewer-facing note for the emitted context. Pure so the promotion branches are
126
+ // unit-testable without git. The PROMOTION + NOT fast-forwardable hold-and-back-merge
127
+ // guidance is unchanged — only the trigger (isPromotion) is corrected.
128
+ export function reviewNote({ promotion, fastForwardable: ff, base, head, commitsOnBaseNotInHead }) {
129
+ if (promotion && !ff) {
130
+ const n = (commitsOnBaseNotInHead || []).length
131
+ return `PROMOTION + NOT fast-forwardable: ${base} has ${n} commit(s) not in ${head} (likely hotfixes). HOLD — back-merge ${base} → ${head} first; promoting would revert them. Then apply the release-readiness checklist (migrations/secrets/flag-defaults/version/rollback).`
132
+ }
133
+ if (promotion) {
134
+ return 'PROMOTION (fast-forwardable): do not re-review feature code already merged & green on the integration branch. Run only the release-readiness checklist on the content: migrations/backfills, secrets & config, feature-flag defaults, version/changelog, rollback.'
135
+ }
136
+ return 'Review the NET diff (range above), not commit-by-commit. Scope findings to what this range introduces; pre-existing issues (present at mergeBase) are notes, not blockers. Scan `commits` for secrets added-then-removed / unsafe intermediate states.'
137
+ }
138
+
139
+ // ---- CLI ----
140
+
141
+ function git(args) {
142
+ return execFileSync('git', args, { encoding: 'utf8' }).trim()
143
+ }
144
+
145
+ function parseArgs(argv) {
146
+ const f = { head: 'HEAD' }
147
+ for (let i = 2; i < argv.length; i++) {
148
+ const a = argv[i]
149
+ if (a.startsWith('--')) f[a.slice(2)] = argv[++i]
150
+ }
151
+ return f
152
+ }
153
+
154
+ // Resolve the head's symbolic BRANCH NAME (what isIntegrationBranch classifies), or null
155
+ // when there is nothing to classify. Prefer an explicit --head-ref; otherwise ask git for
156
+ // the symbolic name of --head. A detached HEAD (`git rev-parse --abbrev-ref` → "HEAD") or a
157
+ // bare SHA (echoed back unchanged) has no branch name → null → promotion defaults false.
158
+ function resolveHeadName(a) {
159
+ if (a['head-ref']) return a['head-ref']
160
+ const head = a.head || 'HEAD'
161
+ let name
162
+ try {
163
+ name = git(['rev-parse', '--abbrev-ref', head])
164
+ } catch {
165
+ return null
166
+ }
167
+ if (!name || name === 'HEAD' || /^[0-9a-f]{7,40}$/i.test(name)) return null
168
+ return name
169
+ }
170
+
171
+ function main() {
172
+ const a = parseArgs(process.argv)
173
+ if (!a.base) {
174
+ console.error('usage: pr-context.mjs --base <target-branch-or-ref> [--head HEAD] [--head-ref <branch-name>]')
175
+ process.exit(2)
176
+ }
177
+ const base = git(['merge-base', a.base, a.head])
178
+ const range = threeDotRange(base, a.head)
179
+ const files = parseNameStatus(git(['diff', '--name-status', range]))
180
+ const commits = parseLog(git(['log', '--oneline', `${base}..${a.head}`]))
181
+ const diffstat = git(['diff', '--shortstat', range])
182
+ // commits on the base that HEAD lacks (in base, not in head) — the fast-forward / drift signal
183
+ const commitsOnBaseNotInHead = parseLog(git(['log', '--oneline', `${a.head}..${a.base}`]))
184
+ const ff = fastForwardable(commitsOnBaseNotInHead)
185
+ // Promotion requires BOTH a production base AND an integration/release head — a base
186
+ // check alone flags every feature→main PR (issue #392). headRef is the resolved head
187
+ // branch name (null when unresolvable → not integration-shaped → promotion false).
188
+ const headRef = resolveHeadName(a)
189
+ const promotion = isPromotion(a.base, headRef)
190
+ const ctx = {
191
+ targetRef: a.base,
192
+ headRef,
193
+ mergeBase: base,
194
+ range,
195
+ diffCommand: `git diff ${range}`,
196
+ changedFiles: files,
197
+ commits,
198
+ diffstat,
199
+ promotion,
200
+ fastForwardable: ff,
201
+ commitsOnBaseNotInHead,
202
+ note: reviewNote({ promotion, fastForwardable: ff, base: a.base, head: a.head, commitsOnBaseNotInHead }),
203
+ }
204
+ console.log(JSON.stringify(ctx, null, 2))
205
+ }
206
+
207
+ if (isMainModule(import.meta.url)) main()