@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,131 @@
1
+ // Shared read-only validator for exact-head CI artifacts. The mutating adapter lives
2
+ // in resolve-issues; consumers import this contract so review and integration use the
3
+ // same fail-closed definition of valid evidence.
4
+ import { locallyReproducedJobs, validatePublishOnlyEvidence, validateRequiredCheckExecution, validateRequiredCheckPlan } from './required-check-plan.mjs'
5
+
6
+ export const EXACT_HEAD_ARTIFACT_VERSION = 2
7
+ export const EXACT_HEAD_COLLECTION_MODES = Object.freeze(['choreographed', 'observed-existing-run'])
8
+
9
+ function isObject(value) {
10
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
11
+ }
12
+
13
+ function stable(value) {
14
+ if (Array.isArray(value)) return value.map(stable)
15
+ if (!isObject(value)) return value
16
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])]))
17
+ }
18
+
19
+ export function sameExactHeadState(left, right) {
20
+ return JSON.stringify(stable(left)) === JSON.stringify(stable(right))
21
+ }
22
+
23
+ export function providerWorkflowIdentityMatches(expected, identity) {
24
+ if (typeof expected !== 'string' || !expected.trim() || !isObject(identity)) return false
25
+ const aliases = [identity.id, identity.name, identity.path]
26
+ .filter((value) => (typeof value === 'string' && value.trim()) || typeof value === 'number')
27
+ .map(String)
28
+ if (typeof identity.path === 'string') aliases.push(identity.path.split('/').at(-1))
29
+ return aliases.includes(expected)
30
+ }
31
+
32
+ function validateProviderWorkflowIdentity(identity) {
33
+ const errors = []
34
+ if (!isObject(identity)) return ['artifact.workflow.provider must preserve provider-issued workflow identity']
35
+ if ((typeof identity.id !== 'string' && typeof identity.id !== 'number') || !String(identity.id).trim()) errors.push('artifact.workflow.provider.id must identify the provider workflow')
36
+ if (typeof identity.name !== 'string' || !identity.name.trim()) errors.push('artifact.workflow.provider.name must preserve the provider workflow name')
37
+ if (identity.path !== undefined && (typeof identity.path !== 'string' || !identity.path.trim())) errors.push('artifact.workflow.provider.path must be a non-empty string when present')
38
+ return errors
39
+ }
40
+
41
+ function classifyRawJobs(jobs, policy) {
42
+ const errors = []
43
+ if (!Array.isArray(jobs)) return { outcome: 'failure', errors: ['artifact.jobs must be an array'] }
44
+ if (!isObject(policy) || !Array.isArray(policy.requiredJobs) || !Array.isArray(policy.allowedSkippedJobs)) {
45
+ return { outcome: 'failure', errors: ['artifact.policy must preserve requiredJobs and allowedSkippedJobs arrays'] }
46
+ }
47
+ const byName = new Map()
48
+ for (const [index, job] of jobs.entries()) {
49
+ if (!isObject(job) || typeof job.name !== 'string' || !Object.hasOwn(job, 'conclusion')) {
50
+ errors.push(`artifact.jobs[${index}] must preserve name and conclusion`)
51
+ continue
52
+ }
53
+ if (byName.has(job.name)) errors.push(`artifact.jobs has duplicate/ambiguous evidence for ${job.name}`)
54
+ else byName.set(job.name, job)
55
+ }
56
+ const missing = policy.requiredJobs.filter((name) => !byName.has(name))
57
+ const notSuccessful = policy.requiredJobs.filter((name) => byName.has(name) && byName.get(name).conclusion !== 'success')
58
+ const allowedSkipped = new Set(policy.allowedSkippedJobs)
59
+ const disallowedSkipped = jobs.filter((job) => job?.conclusion === 'skipped' && !allowedSkipped.has(job.name)).map((job) => job.name)
60
+ const failed = jobs.filter((job) => job && !['success', 'skipped'].includes(job.conclusion)).map((job) => `${job.name} (${job.conclusion ?? 'pending'})`)
61
+ if (missing.length) errors.push(`required jobs missing: ${missing.join(', ')}`)
62
+ if (notSuccessful.length) errors.push(`required jobs not successful: ${notSuccessful.join(', ')}`)
63
+ if (disallowedSkipped.length) errors.push(`jobs skipped without policy allowance: ${disallowedSkipped.join(', ')}`)
64
+ if (failed.length) errors.push(`raw jobs contain failure states: ${failed.join(', ')}`)
65
+ let outcome = 'success'
66
+ if (jobs.length === 0) outcome = 'zero-job-workflow-failure'
67
+ else if (jobs.some((job) => job?.conclusion === 'cancelled')) outcome = 'cancelled'
68
+ else if (errors.length) outcome = 'failure'
69
+ else if (jobs.some((job) => job?.conclusion === 'skipped')) outcome = 'success-with-skipped'
70
+ return { outcome, errors }
71
+ }
72
+
73
+ export function validateExactHeadArtifact(artifact, { expectedHeadSha } = {}) {
74
+ const errors = []
75
+ if (!isObject(artifact)) return { ok: false, errors: ['exact-head artifact must be an object'] }
76
+ if (artifact.version !== EXACT_HEAD_ARTIFACT_VERSION) errors.push(`unsupported exact-head artifact version ${artifact.version}`)
77
+ if (artifact.kind !== 'exact-head-ci') errors.push('exact-head artifact kind must be "exact-head-ci"')
78
+ if (!EXACT_HEAD_COLLECTION_MODES.includes(artifact.collectionMode)) errors.push(`artifact.collectionMode must be one of ${EXACT_HEAD_COLLECTION_MODES.join('|')}`)
79
+ if (typeof artifact.repository !== 'string' || !/^[^/\s]+\/[^/\s]+$/.test(artifact.repository)) errors.push('artifact.repository must be owner/name')
80
+ if (!Number.isInteger(artifact.pr) || artifact.pr < 1) errors.push('artifact.pr must be a positive integer')
81
+ if (typeof artifact.headSha !== 'string' || !/^[0-9a-f]{40}$/i.test(artifact.headSha)) errors.push('artifact.headSha must be a full 40-character commit SHA')
82
+ if (expectedHeadSha && artifact.headSha !== expectedHeadSha) errors.push(`exact-head artifact is STALE: stamped ${artifact.headSha}, expected ${expectedHeadSha}`)
83
+ const plan = validateRequiredCheckPlan(artifact.requiredCheckPlan, { expectedHeadSha: artifact.headSha })
84
+ errors.push(...plan.errors)
85
+ if (artifact.requiredCheckPlan?.repository !== artifact.repository) errors.push('requiredCheckPlan repository does not match artifact.repository')
86
+ const execution = validateRequiredCheckExecution(artifact.requiredCheckPlan, artifact.jobs, { expectedHeadSha: artifact.headSha })
87
+ errors.push(...execution.errors.filter((error) => !plan.errors.includes(error)))
88
+ const publishOnly = validatePublishOnlyEvidence(artifact.requiredCheckPlan, artifact.publishOnlyEvidence, { expectedHeadSha: artifact.headSha, expectedRepository: artifact.repository, expectedPr: artifact.pr })
89
+ errors.push(...publishOnly.errors)
90
+ if (!isObject(artifact.workflow) || typeof artifact.workflow.id !== 'string' || !artifact.workflow.id.trim()) errors.push('artifact.workflow.id must identify the requested provider workflow')
91
+ errors.push(...validateProviderWorkflowIdentity(artifact.workflow?.provider))
92
+ if (isObject(artifact.workflow?.provider) && !providerWorkflowIdentityMatches(artifact.workflow?.id, artifact.workflow.provider)) errors.push('provider workflow identity does not match artifact.workflow.id')
93
+ if (typeof artifact.workflow?.runId !== 'string' && typeof artifact.workflow?.runId !== 'number') errors.push('artifact.workflow.runId must identify the provider run')
94
+ if (artifact.workflow?.headSha !== artifact.headSha) errors.push('workflow headSha does not match artifact headSha')
95
+ if (!Array.isArray(artifact.jobs)) errors.push('artifact.jobs must be an array')
96
+ else for (const [index, job] of artifact.jobs.entries()) {
97
+ if (!isObject(job) || typeof job.name !== 'string' || !Object.hasOwn(job, 'conclusion')) errors.push(`artifact.jobs[${index}] must preserve name and conclusion`)
98
+ }
99
+ const expectedPolicy = {
100
+ requiredJobs: locallyReproducedJobs(artifact.requiredCheckPlan),
101
+ allowedSkippedJobs: artifact.requiredCheckPlan?.allowedSkippedJobs,
102
+ }
103
+ if (!sameExactHeadState(artifact.policy, expectedPolicy)) errors.push('artifact.policy must be derived exactly from requiredCheckPlan')
104
+ const raw = classifyRawJobs(artifact.jobs, artifact.policy)
105
+ errors.push(...raw.errors)
106
+ if (artifact.summary?.outcome !== raw.outcome) errors.push(`summary outcome "${artifact.summary?.outcome ?? 'missing'}" contradicts raw jobs outcome "${raw.outcome}"`)
107
+
108
+ if (artifact.collectionMode === 'choreographed') {
109
+ if (!Array.isArray(artifact.choreography) || artifact.choreography.length === 0) errors.push('choreographed artifacts must preserve the mutation choreography')
110
+ if (Object.hasOwn(artifact, 'observation')) errors.push('choreographed artifacts cannot claim observed-existing-run provenance')
111
+ if (artifact.restoration?.proved !== true) errors.push('live restoration was not proved')
112
+ if (!sameExactHeadState(artifact.snapshot, artifact.restoration?.observed)) errors.push('restoration observation does not equal the original snapshot')
113
+ }
114
+ if (artifact.collectionMode === 'observed-existing-run') {
115
+ if (Object.hasOwn(artifact, 'choreography')) errors.push('observed-existing-run artifacts cannot claim mutation choreography')
116
+ if (Object.hasOwn(artifact, 'restoration')) errors.push('observed-existing-run artifacts cannot contain a restoration claim')
117
+ if (Object.hasOwn(artifact, 'snapshot')) errors.push('observed-existing-run artifacts must use before/after observation provenance, not a choreography snapshot')
118
+ if (!isObject(artifact.observation) || !isObject(artifact.observation.before) || !isObject(artifact.observation.after)) {
119
+ errors.push('observed-existing-run artifacts require live PR observations before and after provider evidence acquisition')
120
+ } else {
121
+ if (artifact.observation.before.headSha !== artifact.headSha) errors.push('observed-existing-run before observation does not match artifact.headSha')
122
+ if (artifact.observation.after.headSha !== artifact.headSha) errors.push('observed-existing-run after observation does not match artifact.headSha')
123
+ }
124
+ }
125
+ if (!Array.isArray(artifact.errors)) errors.push('artifact.errors must be an array')
126
+ else if (artifact.errors.length) errors.push('passing exact-head artifacts cannot preserve collection errors')
127
+ if (artifact.status !== 'pass') errors.push(`exact-head status is "${artifact.status ?? 'missing'}", needs "pass"`)
128
+ if (!['success', 'success-with-skipped'].includes(artifact.summary?.outcome)) errors.push(`exact-head outcome is "${artifact.summary?.outcome ?? 'missing'}", not a passing outcome`)
129
+ if (!['success', 'success-with-skipped'].includes(raw.outcome)) errors.push(`raw jobs outcome "${raw.outcome}" is not passing`)
130
+ return { ok: errors.length === 0, errors }
131
+ }
@@ -0,0 +1,398 @@
1
+ // head-check-set — the FULL observed state of one commit, not the named subset of it.
2
+ //
3
+ // A required-check plan answers "are the checks I named green?". #1081 is what that
4
+ // question cannot see. Two release workflows were rejected by GitHub at validation
5
+ // time; every push produced two runs that completed in the same second having executed
6
+ // ZERO jobs, named after the file path instead of the declared `name:`. That was
7
+ // visible for seven hours across fourteen commits, and the unit still earned an
8
+ // independent PASS and a merge-ready mark, because the one check anybody read
9
+ // (`skill-script-tests`) was green — and it genuinely was.
10
+ //
11
+ // THE SUBTLETY THAT DEFEATS THE OBVIOUS FIX. "Read every check-run instead of the
12
+ // named ones" would ALSO have missed #1081. A workflow GitHub cannot parse produces no
13
+ // check-run at all — not a red one, none. The real observation at that SHA:
14
+ //
15
+ // GET /commits/ee5dd91a…/check-runs → 4 entries, every one success/neutral/skipped
16
+ // GET /commits/ee5dd91a…/status → state "pending", zero statuses
17
+ // GET /actions/runs?head_sha=ee5dd91a… → 3 runs, TWO of them conclusion "failure"
18
+ // with name == path and zero jobs
19
+ //
20
+ // So the full state of a commit is the union of three channels — check-runs, legacy
21
+ // commit statuses, and Actions runs — and the third is the only one where a startup
22
+ // failure lives. This module classifies that union. Both halves are load-bearing: the
23
+ // union is what makes undeclared red visible, and the zero-job run is what makes the
24
+ // #1081 class NAMEABLE rather than a number in a count.
25
+ //
26
+ // WHAT THIS DELIBERATELY DOES NOT DO. It does not gate. Whether a red check nobody
27
+ // declared required should block a merge is a policy decision belonging to the human
28
+ // and to `.mergify.yml`, and a reporting script that quietly changed what merges would
29
+ // be a worse defect than the one it fixes. The partition names `undeclaredRed`
30
+ // separately from `requiredRed` precisely so a caller can act on the difference; the
31
+ // only outcome this module calls failing is the one the existing contract already
32
+ // blocks on — a REQUIRED check red or absent.
33
+
34
+ export const HEAD_CHECK_SET_VERSION = 1
35
+ export const HEAD_CHECK_SET_KIND = 'head-check-set'
36
+ export const OBSERVATION_SOURCES = Object.freeze(['check-run', 'commit-status', 'actions-run'])
37
+ export const OBSERVATION_STATES = Object.freeze(['green', 'red', 'neutral', 'pending'])
38
+
39
+ // Why `cancelled` counts as red: a cancelled required check is not a passed one, and
40
+ // the surrounding contract has said "skipped is never success" since epic-892. Neutral
41
+ // and skipped stay `neutral` — they are not passes either, but they are not evidence of
42
+ // breakage, and conflating the two is how a report gets ignored.
43
+ const RED_CONCLUSIONS = new Set(['failure', 'timed_out', 'action_required', 'startup_failure', 'stale', 'cancelled'])
44
+ const NEUTRAL_CONCLUSIONS = new Set(['skipped', 'neutral'])
45
+ const COMPLETED = new Set(['completed'])
46
+
47
+ // A run GitHub could not parse is reported with its file path where its name belongs,
48
+ // because there is no parsed `name:` to report. Corroborating, never sufficient: a
49
+ // workflow may legitimately declare no `name:`, in which case GitHub also uses the path.
50
+ const WORKFLOW_PATH = /^\.github\/workflows\/[^/]+\.ya?ml$/
51
+
52
+ const isObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
53
+ const nonEmpty = (value) => typeof value === 'string' && value.trim().length > 0
54
+ const SHA = /^[0-9a-f]{40}$/i
55
+ const lower = (value) => (value == null ? null : String(value).toLowerCase())
56
+
57
+ function stateOf(status, conclusion) {
58
+ const normalizedStatus = lower(status)
59
+ const normalizedConclusion = lower(conclusion)
60
+ if (normalizedStatus !== null && !COMPLETED.has(normalizedStatus)) return 'pending'
61
+ if (normalizedConclusion === null) return 'pending'
62
+ if (normalizedConclusion === 'success') return 'green'
63
+ if (NEUTRAL_CONCLUSIONS.has(normalizedConclusion)) return 'neutral'
64
+ if (RED_CONCLUSIONS.has(normalizedConclusion)) return 'red'
65
+ // Deny-by-default on a conclusion this module has never seen: an unknown conclusion
66
+ // read as green is exactly the failure this file exists to remove.
67
+ return 'red'
68
+ }
69
+
70
+ function commitStatusState(state) {
71
+ const normalized = lower(state)
72
+ if (normalized === 'success') return 'green'
73
+ if (normalized === 'pending') return 'pending'
74
+ return 'red'
75
+ }
76
+
77
+ /** Every check name the plan declares required, in any phase. */
78
+ export function requiredCheckNames(plan) {
79
+ const fromChecks = (plan?.checks || [])
80
+ .filter((check) => check?.admission === 'required' && nonEmpty(check?.name))
81
+ .map((check) => check.name)
82
+ const fromDiscovery = (plan?.discovery?.requiredChecks || []).filter(nonEmpty)
83
+ return [...new Set([...fromChecks, ...fromDiscovery])].sort()
84
+ }
85
+
86
+ function checkRunObservation(run) {
87
+ return {
88
+ source: 'check-run',
89
+ name: String(run?.name ?? ''),
90
+ state: stateOf(run?.status, run?.conclusion),
91
+ status: run?.status ?? null,
92
+ conclusion: run?.conclusion ?? null,
93
+ app: run?.app?.slug ?? null,
94
+ checkSuiteId: run?.check_suite?.id ?? null,
95
+ url: run?.html_url ?? null,
96
+ }
97
+ }
98
+
99
+ function commitStatusObservation(status) {
100
+ return {
101
+ source: 'commit-status',
102
+ name: String(status?.context ?? ''),
103
+ state: commitStatusState(status?.state),
104
+ status: 'completed',
105
+ conclusion: status?.state ?? null,
106
+ app: status?.creator?.login ?? null,
107
+ checkSuiteId: null,
108
+ url: status?.target_url ?? null,
109
+ }
110
+ }
111
+
112
+ /**
113
+ * An Actions run, plus the two facts that make #1081 nameable.
114
+ *
115
+ * `jobCount` is supplied by the caller because it costs one extra API call per run and
116
+ * this module is pure. A run that has completed with `jobCount === 0` executed nothing:
117
+ * that is the startup-failure signature, and it is the whole reason the Actions channel
118
+ * is read at all. `null` means the caller could not determine it — reported as unknown,
119
+ * never as zero, because "we did not look" and "there were none" must not render alike.
120
+ */
121
+ function actionsRunObservation(run) {
122
+ const name = String(run?.name ?? '')
123
+ const path = run?.path ?? null
124
+ const jobCount = Number.isInteger(run?.jobCount) ? run.jobCount : null
125
+ const state = stateOf(run?.status, run?.conclusion)
126
+ const completed = COMPLETED.has(lower(run?.status) ?? '')
127
+ return {
128
+ source: 'actions-run',
129
+ name,
130
+ state,
131
+ status: run?.status ?? null,
132
+ conclusion: run?.conclusion ?? null,
133
+ app: 'github-actions',
134
+ checkSuiteId: run?.check_suite_id ?? null,
135
+ url: run?.html_url ?? null,
136
+ runId: run?.id ?? null,
137
+ path,
138
+ event: run?.event ?? null,
139
+ jobCount,
140
+ // Recorded, never classified on. The obvious reading of "is this run attached to the
141
+ // pull request?" is the API's `pull_requests` array, and it is not usable: at
142
+ // ee5dd91a the perfectly healthy `pull_request`-event `Skill gates` run also carries
143
+ // `pull_requests: []`. Deriving an attachment boolean from it would report every
144
+ // healthy run as unattached. `event` is what actually distinguishes an out-of-band
145
+ // dispatch, and it is what `absenceReason` uses.
146
+ pullRequests: Array.isArray(run?.pull_requests) ? run.pull_requests.map((entry) => entry?.number ?? null) : [],
147
+ nameEqualsPath: nonEmpty(path) && name === path,
148
+ looksLikeWorkflowPath: WORKFLOW_PATH.test(name),
149
+ zeroJobs: completed && jobCount === 0,
150
+ }
151
+ }
152
+
153
+ /** Raw Actions runs (each optionally carrying an integer `jobCount`) as observations. */
154
+ export function observeActionsRuns(runs) {
155
+ return (Array.isArray(runs) ? runs : []).map(actionsRunObservation)
156
+ }
157
+
158
+ /**
159
+ * The #1081 signature: a run that COMPLETED, executed zero jobs, and did not succeed.
160
+ *
161
+ * Kept distinct from "a red run" on purpose. A red run with jobs failed while doing its
162
+ * work and its jobs say why; a red run with no jobs never started, and nothing else in
163
+ * the system says so — no check-run exists to be red. The name-equals-path corroboration
164
+ * is reported alongside rather than required, because a workflow with no declared `name:`
165
+ * produces the same coincidence honestly.
166
+ */
167
+ export function startupFailures(observations) {
168
+ return observations
169
+ .filter((entry) => entry.source === 'actions-run' && entry.zeroJobs && entry.state !== 'green')
170
+ .map((entry) => ({
171
+ runId: entry.runId,
172
+ name: entry.name,
173
+ path: entry.path,
174
+ event: entry.event,
175
+ conclusion: entry.conclusion,
176
+ state: entry.state,
177
+ nameEqualsPath: entry.nameEqualsPath,
178
+ looksLikeWorkflowPath: entry.looksLikeWorkflowPath,
179
+ url: entry.url,
180
+ }))
181
+ }
182
+
183
+ /**
184
+ * Why a required check produced no observation at all. This is #1058's distinction and
185
+ * it falls out of the same union: the three answers call for opposite responses, and the
186
+ * single string they share today ("no workflow run found") reads as *still queued* for
187
+ * all three.
188
+ */
189
+ export function ciAbsence(observations) {
190
+ const actionsRuns = (observations || []).filter((entry) => entry.source === 'actions-run')
191
+ return absenceReason(observations || [], actionsRuns)
192
+ }
193
+
194
+ function absenceReason(observations, actionsRuns) {
195
+ if (observations.some((entry) => entry.state === 'pending')) {
196
+ return {
197
+ reason: 'pending',
198
+ detail: 'a run for this SHA has not finished; waiting is correct and dispatching another would waste a run',
199
+ }
200
+ }
201
+ if (observations.length === 0) {
202
+ return {
203
+ reason: 'no-run-anywhere',
204
+ detail: 'no check-run, commit status or Actions run exists for this SHA — the triggering event was most likely never delivered; waiting is futile, a workflow_dispatch or a close/reopen at the same head is the intervention',
205
+ }
206
+ }
207
+ // #1058's third state: a run exists at this SHA, but it got there by hand. The check
208
+ // it produced is honest exact-head evidence and satisfies no merge-queue condition,
209
+ // and the situation is actionable NOW rather than something to wait out.
210
+ const dispatched = actionsRuns.filter((entry) => entry.event === 'workflow_dispatch')
211
+ if (dispatched.length && dispatched.length === actionsRuns.length) {
212
+ return {
213
+ reason: 'dispatched-out-of-band',
214
+ detail: `every Actions run at this SHA was started by workflow_dispatch (${dispatched.map((entry) => entry.runId).join(', ')}) — the event that would have created this check was never delivered; the dispatched run is honest exact-head evidence but satisfies no merge-queue check condition, so delivery still needs the event`,
215
+ }
216
+ }
217
+ return {
218
+ reason: 'absent-though-runs-completed',
219
+ detail: 'runs for this SHA have completed without ever producing this check — inspect the workflow trigger and path filters, and the startupFailures channel: a workflow GitHub refuses to parse creates a run and produces no check-run at all',
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Classify the full observed state of one head SHA.
225
+ *
226
+ * @param {object} input
227
+ * @param {string} input.repository owner/name
228
+ * @param {string} input.headSha the 40-character commit being described
229
+ * @param {object[]} [input.checkRuns] raw `GET /commits/{sha}/check-runs` entries
230
+ * @param {object[]} [input.statuses] raw `GET /commits/{sha}/status` `.statuses` entries
231
+ * @param {object[]} [input.actionsRuns] raw `GET /actions/runs?head_sha=` entries, each
232
+ * optionally carrying an integer `jobCount`
233
+ * @param {object|null} [input.plan] a required-check plan; OPTIONAL — with none, nothing
234
+ * is required and this degrades to a pure observation
235
+ * report rather than calling every red undeclared
236
+ * @param {string} [input.collectedAt]
237
+ */
238
+ export function classifyHeadCheckSet({
239
+ repository,
240
+ headSha,
241
+ checkRuns = [],
242
+ statuses = [],
243
+ actionsRuns = [],
244
+ plan = null,
245
+ collectedAt = new Date().toISOString(),
246
+ }) {
247
+ const observations = [
248
+ ...checkRuns.map(checkRunObservation),
249
+ ...statuses.map(commitStatusObservation),
250
+ ...actionsRuns.map(actionsRunObservation),
251
+ ]
252
+ const required = requiredCheckNames(plan)
253
+ const requiredSet = new Set(required)
254
+ for (const entry of observations) entry.required = requiredSet.has(entry.name)
255
+
256
+ const observedNames = new Set(observations.map((entry) => entry.name))
257
+ const actionsObservations = observations.filter((entry) => entry.source === 'actions-run')
258
+
259
+ const red = observations.filter((entry) => entry.state === 'red')
260
+ const partition = {
261
+ requiredRed: red.filter((entry) => entry.required),
262
+ // The #1081 case. Informational by contract — see this file's header — but never silent.
263
+ undeclaredRed: red.filter((entry) => !entry.required),
264
+ neverRan: required
265
+ .filter((name) => !observedNames.has(name))
266
+ .map((name) => ({ name, ...absenceReason(observations, actionsObservations) })),
267
+ pending: observations.filter((entry) => entry.state === 'pending'),
268
+ neutral: observations.filter((entry) => entry.state === 'neutral'),
269
+ green: observations.filter((entry) => entry.state === 'green'),
270
+ }
271
+ const signatures = { startupFailures: startupFailures(observations) }
272
+
273
+ // Outcome ordering is the caller's decision order, and `green-with-undeclared-red` is
274
+ // deliberately its own value rather than folded into either neighbour: it is the state
275
+ // #1081 was in for seven hours, and it must be neither "failure" (it does not block)
276
+ // nor "green" (it is not).
277
+ let outcome = 'green'
278
+ if (partition.requiredRed.length) outcome = 'required-red'
279
+ else if (partition.neverRan.length) outcome = 'required-missing'
280
+ else if (partition.pending.length) outcome = 'pending'
281
+ else if (partition.undeclaredRed.length || signatures.startupFailures.length) outcome = 'green-with-undeclared-red'
282
+
283
+ return {
284
+ version: HEAD_CHECK_SET_VERSION,
285
+ kind: HEAD_CHECK_SET_KIND,
286
+ repository,
287
+ headSha,
288
+ collectedAt,
289
+ planned: { required, planPresent: plan != null },
290
+ observations,
291
+ signatures,
292
+ partition,
293
+ summary: {
294
+ outcome,
295
+ counts: {
296
+ observations: observations.length,
297
+ checkRuns: checkRuns.length,
298
+ commitStatuses: statuses.length,
299
+ actionsRuns: actionsRuns.length,
300
+ requiredRed: partition.requiredRed.length,
301
+ undeclaredRed: partition.undeclaredRed.length,
302
+ neverRan: partition.neverRan.length,
303
+ pending: partition.pending.length,
304
+ startupFailures: signatures.startupFailures.length,
305
+ },
306
+ },
307
+ }
308
+ }
309
+
310
+ /**
311
+ * True when the REQUIRED set — and only the required set — is unsatisfied.
312
+ *
313
+ * This is the whole of the blocking judgement, isolated here so that the one place a
314
+ * caller could turn undeclared red into a merge decision is a single named function
315
+ * rather than an exit-code expression buried in a CLI.
316
+ */
317
+ export function blocksOnRequiredSet(artifact) {
318
+ return (artifact?.partition?.requiredRed?.length ?? 0) > 0
319
+ || (artifact?.partition?.neverRan?.length ?? 0) > 0
320
+ }
321
+
322
+ export function validateHeadCheckSetArtifact(artifact, { expectedHeadSha, label = 'headCheckSet' } = {}) {
323
+ const errors = []
324
+ if (!isObject(artifact)) return { ok: false, errors: [`${label} must be an object`] }
325
+ if (artifact.version !== HEAD_CHECK_SET_VERSION) errors.push(`${label}.version must be ${HEAD_CHECK_SET_VERSION}`)
326
+ if (artifact.kind !== HEAD_CHECK_SET_KIND) errors.push(`${label}.kind must be "${HEAD_CHECK_SET_KIND}"`)
327
+ if (!nonEmpty(artifact.repository) || !/^[^/\s]+\/[^/\s]+$/.test(artifact.repository)) errors.push(`${label}.repository must be owner/name`)
328
+ if (!nonEmpty(artifact.headSha) || !SHA.test(artifact.headSha)) errors.push(`${label}.headSha must be a full 40-character commit SHA`)
329
+ else if (expectedHeadSha && artifact.headSha !== expectedHeadSha) errors.push(`${label} is STALE: stamped ${artifact.headSha}, expected ${expectedHeadSha}`)
330
+ if (!Array.isArray(artifact.observations)) errors.push(`${label}.observations must be an array`)
331
+ else {
332
+ for (const [index, entry] of artifact.observations.entries()) {
333
+ const at = `${label}.observations[${index}]`
334
+ if (!isObject(entry)) { errors.push(`${at} must be an object`); continue }
335
+ if (!OBSERVATION_SOURCES.includes(entry.source)) errors.push(`${at}.source must be ${OBSERVATION_SOURCES.join('|')}`)
336
+ if (!nonEmpty(entry.name)) errors.push(`${at}.name must be a non-empty string`)
337
+ if (!OBSERVATION_STATES.includes(entry.state)) errors.push(`${at}.state must be ${OBSERVATION_STATES.join('|')}`)
338
+ if (typeof entry.required !== 'boolean') errors.push(`${at}.required must be boolean`)
339
+ }
340
+ }
341
+ if (!isObject(artifact.partition)) errors.push(`${label}.partition must be an object`)
342
+ else {
343
+ for (const key of ['requiredRed', 'undeclaredRed', 'neverRan', 'pending', 'neutral', 'green']) {
344
+ if (!Array.isArray(artifact.partition[key])) errors.push(`${label}.partition.${key} must be an array`)
345
+ }
346
+ for (const [index, entry] of (artifact.partition.neverRan || []).entries()) {
347
+ const at = `${label}.partition.neverRan[${index}]`
348
+ if (!isObject(entry) || !nonEmpty(entry.name)) errors.push(`${at}.name must be a non-empty string`)
349
+ // The reason is the entire point of the row: an absence without one reads as
350
+ // "still queued" for all three of #1058's cases.
351
+ else if (!nonEmpty(entry.reason) || !nonEmpty(entry.detail)) errors.push(`${at} requires an actionable reason and detail`)
352
+ }
353
+ }
354
+ if (!isObject(artifact.signatures) || !Array.isArray(artifact.signatures.startupFailures)) errors.push(`${label}.signatures.startupFailures must be an array`)
355
+ if (!isObject(artifact.summary) || !nonEmpty(artifact.summary.outcome)) errors.push(`${label}.summary.outcome must be a non-empty string`)
356
+ return { ok: errors.length === 0, errors }
357
+ }
358
+
359
+ function describe(entry) {
360
+ const detail = entry.source === 'actions-run'
361
+ ? ` — run ${entry.runId ?? '?'}, event ${entry.event ?? '?'}, ${entry.jobCount === null ? 'job count unknown' : `${entry.jobCount} job(s)`}`
362
+ : ''
363
+ return `${entry.name} [${entry.source}] ${entry.conclusion ?? entry.status ?? 'pending'}${detail}`
364
+ }
365
+
366
+ export function renderHeadCheckSet(artifact) {
367
+ const lines = [
368
+ '<!-- generated by head-check-set.mjs — do not hand-edit; re-run collect -->',
369
+ `**Full check set at \`${artifact.headSha}\`** (${artifact.repository}, collected ${artifact.collectedAt})`,
370
+ '',
371
+ `- Outcome: **${artifact.summary?.outcome}** — ${artifact.summary?.counts?.observations ?? 0} observation(s) across `
372
+ + `${artifact.summary?.counts?.checkRuns ?? 0} check-run(s), ${artifact.summary?.counts?.commitStatuses ?? 0} commit status(es), `
373
+ + `${artifact.summary?.counts?.actionsRuns ?? 0} Actions run(s)`,
374
+ `- Required by the plan: ${artifact.planned?.planPresent ? (artifact.planned.required.join(', ') || 'none') : 'NO PLAN SUPPLIED — nothing is classified required, so this is an observation report only'}`,
375
+ ]
376
+ const section = (title, rows) => {
377
+ if (!rows.length) return
378
+ lines.push(`- ${title}:`)
379
+ for (const row of rows) lines.push(` - ${row}`)
380
+ }
381
+ section('REQUIRED and red (blocking under the existing contract)', artifact.partition?.requiredRed?.map(describe) ?? [])
382
+ section(
383
+ 'NOT required and red (informational — surfaced, never gated here; whether it should block belongs to `.mergify.yml` and the human)',
384
+ artifact.partition?.undeclaredRed?.map(describe) ?? [],
385
+ )
386
+ section(
387
+ 'Required but never ran at all',
388
+ artifact.partition?.neverRan?.map((row) => `${row.name}: ${row.reason} — ${row.detail}`) ?? [],
389
+ )
390
+ section(
391
+ 'Workflow runs that completed having executed ZERO jobs (the #1081 startup-failure signature)',
392
+ artifact.signatures?.startupFailures?.map((row) =>
393
+ `run ${row.runId} \`${row.name}\` (${row.conclusion}) executed no jobs`
394
+ + `${row.nameEqualsPath ? ' and its name equals its file path — corroborating a workflow GitHub refused to parse' : ''}`) ?? [],
395
+ )
396
+ section('Pending', artifact.partition?.pending?.map(describe) ?? [])
397
+ return lines.join('\n')
398
+ }
@@ -0,0 +1,80 @@
1
+ // The one ESM main-module guard every skill script in this repo uses.
2
+ //
3
+ // Not a style preference — the hand-written versions of this three-line check had two opposite
4
+ // silent failure modes in production, and both shipped:
5
+ //
6
+ // #718 `import.meta.url === pathToFileURL(process.argv[1]).href`
7
+ // Node resolves `import.meta.url` to the REAL path; `argv[1]` keeps whatever the caller
8
+ // typed. A skills install is a symlink farm (`~/.claude/skills/<skill>` → the checkout),
9
+ // so through the install path the two never match: the CLI does not run and node exits 0.
10
+ // `coverage-ledger.mjs` shipped this and recorded a false pass in the wild
11
+ // (a consumer product repo: epic #352, unit #379, PR #384) on a gate whose only job is to
12
+ // say no. Fails OPEN, invisibly — "passed" and "never ran" are byte-identical evidence.
13
+ //
14
+ // #446 `fs.realpathSync(process.argv[1]) === …`, unguarded.
15
+ // `node -` sets `argv[1]` to the literal string `"-"` — truthy, so the usual
16
+ // `process.argv[1] &&` prefix does not save it — and realpath throws ENOENT at MODULE
17
+ // LOAD, before a line of the module's own code runs. The module cannot be imported by
18
+ // anything that does not launch it as a file. Fails CLOSED, at load.
19
+ //
20
+ // So the contract has exactly two obligations, one per failure mode:
21
+ // 1. realpath BOTH sides before comparing, so a symlinked invocation is still the main module;
22
+ // 2. degrade to `false` — "not the main module" — for anything that does not resolve, never throw.
23
+ //
24
+ // WHY IT IS SHARED RATHER THAN COPIED. PR #278 fixed twelve copies of failure mode #718 by hand and
25
+ // mechanized nothing. Five weeks later `mergify/scripts/audit.mjs` was written with the pre-#278
26
+ // form, and `coverage-ledger.mjs` survived the whole pass because it spelled the same bug a third
27
+ // way that #278's grep did not match. One module plus `main-guard-hygiene.test.mjs` is what stops
28
+ // the next copy: there is now no second place for this logic to drift to, and adding one fails CI.
29
+ //
30
+ // WHERE IT LIVES, AND WHY HERE. Native Skills CLI installation flattens selected packages into
31
+ // sibling directories under `~/.agents/skills`, while this repository nests them under
32
+ // `skills/engineering`. A Workflow consumer at `<skill>/scripts` therefore imports
33
+ // `../../engineering-runtime/scripts/main-module.mjs`: the same specifier reaches this package in
34
+ // both layouts. Claude Code launches through a per-skill symlink into the canonical store; node's
35
+ // realpath-aware module resolution and this predicate preserve that path as well.
36
+ //
37
+ // `engineering-runtime` owns the helper as an installable support package rather than a user
38
+ // capability. `resolve-issues/scripts/sandbox-selftest.mjs` reconstructs the same sibling layout and
39
+ // links this package beside the skill under test. Every consumer imports this package directly.
40
+ import fs from 'node:fs';
41
+ import { fileURLToPath } from 'node:url';
42
+
43
+ /**
44
+ * Is the module identified by `importMetaUrl` the script node was launched with?
45
+ *
46
+ * Symlink-transparent, and total: any input that does not resolve to a real file answers `false`
47
+ * instead of throwing, so importing a CLI module is always safe.
48
+ *
49
+ * @param {string} importMetaUrl the caller's own `import.meta.url`
50
+ * @returns {boolean}
51
+ */
52
+ export function isMainModule(importMetaUrl) {
53
+ const entry = process.argv[1];
54
+ if (typeof entry !== 'string' || entry === '') return false; // imported, or an embedding harness
55
+
56
+ let entryPath;
57
+ try {
58
+ entryPath = fs.realpathSync(entry);
59
+ } catch {
60
+ return false; // #446: `node -` gives "-"; some harnesses give a path that is not on disk
61
+ }
62
+
63
+ let selfPath;
64
+ try {
65
+ selfPath = fileURLToPath(importMetaUrl);
66
+ } catch {
67
+ return false; // a data:/http: module has no path to compare, so it is never the launched script
68
+ }
69
+ try {
70
+ // #718: the launched side is resolved above, so this side must be too. Under Node's default
71
+ // resolution `import.meta.url` is already real and this is a no-op; under `--preserve-symlinks`
72
+ // it is the half that makes the comparison hold.
73
+ selfPath = fs.realpathSync(selfPath);
74
+ } catch {
75
+ // The module is executing, so it existed a moment ago. Compare what we have rather than
76
+ // claiming "not main" — a vanished file should not silently disable a running CLI.
77
+ }
78
+
79
+ return entryPath === selfPath;
80
+ }
@@ -0,0 +1,11 @@
1
+ import { DEFAULT_SCHEMA, load } from "js-yaml"
2
+
3
+ export function parseMergifyYaml(yaml) {
4
+ try {
5
+ const value = load(String(yaml || ""), { schema: DEFAULT_SCHEMA, json: false })
6
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Mergify YAML root must be a mapping")
7
+ return value
8
+ } catch (error) {
9
+ throw new Error(`Mergify YAML structural parse failed closed: ${String(error.message || error).trim()}`)
10
+ }
11
+ }