@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,498 @@
1
+ #!/usr/bin/env node
2
+ // Pre-flight readiness probes: the questions a release discovers the hard way if nobody asks
3
+ // them first.
4
+ //
5
+ // Every one of these comes from pi session 019faea6, where each was found mid-flight instead of
6
+ // before the attempt opened:
7
+ //
8
+ // 1. CREDENTIAL LIVENESS. `gcloud` reauthentication expired after the rc tag was pushed, so
9
+ // every Cloud Build and Cloud Run read failed for the next forty minutes. Pre-flight item 3
10
+ // already declares WHICH identity performs the exposure; nothing checked that the credential
11
+ // it names still works. A release whose credential dies mid-flight cannot verify what it
12
+ // deployed, which is principle 5 with no way to satisfy it.
13
+ //
14
+ // 2. TAG DIVERGENCE. `git fetch` refused `v0.3.1-rc.1` as a clobbering update — the local tag
15
+ // pointed at `43fc5398`, the remote at `06dd1b3d`. Tags are immutable by principle 10, so a
16
+ // divergence means one of the two is lying about what a version names, and version.mjs is
17
+ // about to read the local one.
18
+ //
19
+ // 3. TARGET-BRANCH GATE COLOUR. Post-deploy validation was already red on `main` for four
20
+ // consecutive SHAs before the release began. The release turned into a repair job — correct
21
+ // behaviour, but it should be a decision taken at pre-flight with the state named, not a
22
+ // surprise after the envelope was approved.
23
+ //
24
+ // 4. EXPOSURE-GATE CAPABILITY. The run reached a healthy candidate at 0% traffic and only then
25
+ // discovered the repo could not produce a deployed-profile verdict at all, so the attempt
26
+ // parked at `blocked-manual` having minted a tag and burned a build. The gate that cannot
27
+ // run is principle 13, and principle 13 is much cheaper to hit in the first thirty seconds.
28
+ //
29
+ // WHY A SCRIPT RATHER THAN SIX MORE SENTENCES OF PROSE. Each of these was already implied by an
30
+ // existing rule; prose did not stop any of them, because "confirm the envelope" reads as a
31
+ // conversation and these are commands. A probe that returns `blocked` with a remedy is not a
32
+ // reminder to check — it is the check. This is the same reasoning as `run-state.mjs` mechanizing
33
+ // the manifest rules instead of describing them.
34
+ //
35
+ // FAIL CLOSED, AND SAY WHICH KIND. `unknown` is not `ok`. A probe that could not run leaves the
36
+ // question unanswered, and an unanswered readiness question is exactly principle 13's shape — so
37
+ // `summarize` treats `unknown` as not-ready, and the CLI exits non-zero. What it does NOT do is
38
+ // pretend to know the remedy: an `unknown` reports the raw failure so an operator can see whether
39
+ // the probe or the world is broken.
40
+ //
41
+ // The exposure-gate probe (4) is a COMMAND THE CALLER SUPPLIES, not something inferred here.
42
+ // Whether a repo can emit a deployed-profile verdict is a fact about that repo's smoke tooling,
43
+ // and guessing at it from file paths is how a probe becomes confidently wrong. So the repo names
44
+ // the command (`--exposure-gate-probe`), this script runs it, and an ABSENT command is `unknown`
45
+ // rather than `ok` — a repo that never answers cannot silently release on the weaker path, the
46
+ // same rule pre-flight item 3 applies to the identity legs.
47
+ //
48
+ // Issue #823: when the exposure executor is this skill (the smoke gate runs here, not in the
49
+ // pipeline), a smoke secret that resolved to its resource-name string instead of its value will
50
+ // fail at 4a with 401/403. That is a cannot-run, not a DEAD candidate — but it is still cheaper
51
+ // to catch before the candidate is built. Probe declared smoke secrets with one dry fetch.
52
+ import fs from 'node:fs'
53
+ import { execFileSync } from 'node:child_process'
54
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
55
+ // Same blocking predicate as ensure-target-green — pending / empty-conclusion required
56
+ // gates must never silent-green on either surface (#807 class pending-checks-not-green).
57
+ import { isCheckBlocking } from './ensure-target-green.mjs'
58
+
59
+ export const PROBE_STATES = { OK: 'ok', BLOCKED: 'blocked', UNKNOWN: 'unknown' }
60
+
61
+ const probe = (id, state, detail, remedy = null) => ({ id, state, detail, remedy })
62
+
63
+ // ---- 1. credential liveness -------------------------------------------------------------------
64
+ //
65
+ // The signal is specific and worth matching rather than treating any failure alike: gcloud's
66
+ // expired-credential path prints "Reauthentication failed" / "cannot prompt during
67
+ // non-interactive execution" and tells you to run `gcloud auth login`. That is BLOCKED with a
68
+ // known remedy. A gcloud that is missing entirely, or fails some other way, is UNKNOWN — the
69
+ // difference matters because the first is fixed by a human logging in and the second may mean the
70
+ // probe is wrong about the platform.
71
+ export function classifyCredential({ ok, stdout = '', stderr = '', missing = false } = {}) {
72
+ const text = `${stdout}\n${stderr}`
73
+ if (missing) {
74
+ return probe('credential-liveness', PROBE_STATES.UNKNOWN,
75
+ 'the credential tool is not on PATH, so its liveness could not be read',
76
+ 'install/configure the platform CLI, or declare a different exposure identity at pre-flight item 3')
77
+ }
78
+ if (ok) {
79
+ return probe('credential-liveness', PROBE_STATES.OK, 'the credential answered a token request')
80
+ }
81
+ if (/reauthentication failed|cannot prompt during non-interactive|auth login|invalid_grant|credentials.*expired/i.test(text)) {
82
+ return probe('credential-liveness', PROBE_STATES.BLOCKED,
83
+ `the credential requires interactive reauthentication: ${firstLine(text)}`,
84
+ 'run `gcloud auth login` (or the platform equivalent) BEFORE opening the attempt — a credential that dies mid-release cannot verify what it deployed')
85
+ }
86
+ return probe('credential-liveness', PROBE_STATES.UNKNOWN,
87
+ `the credential check failed for a reason this probe does not recognise: ${firstLine(text)}`,
88
+ 'read the error; an unrecognised failure is not evidence the credential is good')
89
+ }
90
+
91
+ // ---- 2. tag divergence ------------------------------------------------------------------------
92
+ //
93
+ // Compares local tag SHAs against the remote's. Only tags present on BOTH sides can diverge: a
94
+ // local-only tag is an unpushed rc (ordinary mid-release state), and a remote-only tag is simply
95
+ // not fetched yet. Neither is a lie about a version; a *differing* SHA is.
96
+ export function classifyTagDivergence({ local = {}, remote = {}, readable = true } = {}) {
97
+ if (!readable) {
98
+ return probe('tag-divergence', PROBE_STATES.UNKNOWN,
99
+ 'local or remote tags could not be listed',
100
+ 'fix the git remote read; unlistable tags cannot be shown to agree')
101
+ }
102
+ const diverged = []
103
+ for (const [tag, sha] of Object.entries(local)) {
104
+ const remoteSha = remote[tag]
105
+ if (remoteSha && remoteSha !== sha) diverged.push({ tag, local: sha, remote: remoteSha })
106
+ }
107
+ if (diverged.length === 0) {
108
+ return probe('tag-divergence', PROBE_STATES.OK, `${Object.keys(local).length} local tag(s) agree with the remote`)
109
+ }
110
+ const named = diverged.map((d) => `${d.tag} (local ${d.local.slice(0, 8)} vs remote ${d.remote.slice(0, 8)})`).join('; ')
111
+ return probe('tag-divergence', PROBE_STATES.BLOCKED,
112
+ `tag(s) name different commits locally and remotely: ${named}`,
113
+ 'tags are immutable (principle 10), so one side is wrong about what a version names — delete the local tag and re-fetch, and resolve it BEFORE version.mjs reads it')
114
+ }
115
+
116
+ // ---- 3. target-branch gate colour -------------------------------------------------------------
117
+ //
118
+ // A red target branch is not automatically a refusal — the release may legitimately be the thing
119
+ // that repairs it, which is the repair lane. What it must not be is a discovery. So this reports
120
+ // BLOCKED with the failing gates named, and the caller decides at pre-flight whether to repair
121
+ // first or hand back. `--gate` narrows it to the gates that actually gate a release; with no
122
+ // `--gate` every failing check-run counts, which is the conservative reading.
123
+ export function classifyTargetGate({ checks, readable = true, gates = [] } = {}) {
124
+ if (!readable || !Array.isArray(checks)) {
125
+ return probe('target-gate-colour', PROBE_STATES.UNKNOWN,
126
+ 'the target branch check-runs could not be read',
127
+ 'fix the read; an unread gate is not a green gate')
128
+ }
129
+ const relevant = gates.length > 0 ? checks.filter((c) => gates.includes(c.name)) : checks
130
+ if (gates.length > 0) {
131
+ const missing = gates.filter((g) => !checks.some((c) => c.name === g))
132
+ if (missing.length > 0) {
133
+ // An ABSENT required gate reads as permanently unmet, which is a documented trap in this
134
+ // toolchain — never silently the same as passing.
135
+ return probe('target-gate-colour', PROBE_STATES.BLOCKED,
136
+ `required gate(s) reported no check-run on the target head: ${missing.join(', ')}`,
137
+ 'an absent check is not a passing check — find out why it did not run before releasing off this head')
138
+ }
139
+ }
140
+ // Share isCheckBlocking with ensure-target-green so empty conclusion / IN_PROGRESS /
141
+ // non-COMPLETED status cannot silent-green here while that surface blocks (class:
142
+ // pending-checks-not-green). Pre-flight item 0 short-circuits before ensure-target-green
143
+ // when this probe reports ok — so this surface MUST use the same predicate.
144
+ const failing = relevant.filter((c) => isCheckBlocking(c))
145
+ if (failing.length === 0) {
146
+ return probe('target-gate-colour', PROBE_STATES.OK, `${relevant.length} check-run(s) on the target head are green or skipped`)
147
+ }
148
+ const label = (c) => {
149
+ const conclusion = String(c.conclusion || '').trim()
150
+ const status = String(c.status || '').trim()
151
+ if (conclusion) return `${c.name}=${conclusion}`
152
+ if (status) return `${c.name}=${status}`
153
+ return `${c.name}=PENDING`
154
+ }
155
+ return probe('target-gate-colour', PROBE_STATES.BLOCKED,
156
+ `the target branch head is red: ${failing.map(label).join(', ')}`,
157
+ 'decide at pre-flight: run ensure-target-green (classify → repair/brief → re-probe) or hand back — do not discover it after the envelope is approved')
158
+ }
159
+
160
+ // ---- 4. tag-trigger topology -----------------------------------------------------------------
161
+ //
162
+ // The production build is owned by Cloud Build's tag trigger, not a controller-submitted
163
+ // `gcloud builds submit`. The repository supplies a read-only command that evaluates its trigger
164
+ // substitutions for one representative RC and prints the structured record below. This probe
165
+ // verifies the specific path that failed in fmm-express: TAG_NAME → _DEPLOYED_VERSION (final
166
+ // SemVer) and TAG_NAME → RC candidate tag. A source-SHA image can coexist, but cannot substitute
167
+ // for this evidence.
168
+ const RC_TAG_RE = /^v?(\d+\.\d+\.\d+)-rc\.[1-9]\d*$/
169
+
170
+ export function classifyTagTopology({ topology = null, readable = true } = {}) {
171
+ if (!readable || topology == null || typeof topology !== 'object' || Array.isArray(topology)) {
172
+ return probe('rc-tag-topology', PROBE_STATES.UNKNOWN,
173
+ 'the production build topology could not be read as a Cloud Build substitution record',
174
+ 'run --topology-probe with the repository read that emits prodBuildTrigger, versionSource, candidateTagSource, and substitutions; an unread topology cannot authorize an RC tag')
175
+ }
176
+
177
+ const prodBuildTrigger = topology.prodBuildTrigger
178
+ const versionSource = topology.versionSource
179
+ const candidateTagSource = topology.candidateTagSource
180
+ const substitutions = topology.substitutions
181
+ const fields = { prodBuildTrigger, versionSource, candidateTagSource }
182
+ if (prodBuildTrigger !== 'tag-trigger' || versionSource !== 'TAG_NAME' || candidateTagSource !== 'TAG_NAME') {
183
+ return {
184
+ ...probe('rc-tag-topology', PROBE_STATES.BLOCKED,
185
+ 'the production build topology is not tag-trigger / TAG_NAME / TAG_NAME',
186
+ 'fix the trigger-owned Cloud Build derivation before minting an RC; controller-submitted substitutions and source-SHA images are not RC candidate evidence'),
187
+ ...fields,
188
+ }
189
+ }
190
+ if (substitutions == null || typeof substitutions !== 'object' || Array.isArray(substitutions)) {
191
+ return {
192
+ ...probe('rc-tag-topology', PROBE_STATES.BLOCKED,
193
+ 'the topology record has no Cloud Build substitutions to prove the TAG_NAME derivation',
194
+ 'emit TAG_NAME, _DEPLOYED_VERSION, and _CANDIDATE_TAG from the tag-trigger configuration before minting an RC'),
195
+ ...fields,
196
+ }
197
+ }
198
+
199
+ const tagName = String(substitutions.TAG_NAME || '')
200
+ const deployedVersion = String(substitutions._DEPLOYED_VERSION || '')
201
+ const candidateTag = String(substitutions._CANDIDATE_TAG || '')
202
+ const match = RC_TAG_RE.exec(tagName)
203
+ if (!match || deployedVersion !== match[1] || candidateTag !== tagName) {
204
+ return {
205
+ ...probe('rc-tag-topology', PROBE_STATES.BLOCKED,
206
+ `TAG_NAME does not derive the final _DEPLOYED_VERSION and RC candidate tag (TAG_NAME=${tagName || '(missing)'}, _DEPLOYED_VERSION=${deployedVersion || '(missing)'}, _CANDIDATE_TAG=${candidateTag || '(missing)'})`,
207
+ 'make the tag-trigger build derive final SemVer and the RC candidate tag from TAG_NAME; a plain source-SHA image is informational, not candidate evidence'),
208
+ ...fields,
209
+ }
210
+ }
211
+ return {
212
+ ...probe('rc-tag-topology', PROBE_STATES.OK,
213
+ 'Cloud Build tag trigger derives final SemVer and the RC candidate tag from TAG_NAME'),
214
+ ...fields,
215
+ substitutions: { TAG_NAME: tagName, _DEPLOYED_VERSION: deployedVersion, _CANDIDATE_TAG: candidateTag },
216
+ }
217
+ }
218
+
219
+ // ---- 5. exposure-gate capability --------------------------------------------------------------
220
+ //
221
+ // Asks the repo's own tooling whether the exposure profile can produce a verdict, by running the
222
+ // command the repo names. Exit 0 is capable. A non-zero exit is BLOCKED — and the output is
223
+ // quoted verbatim rather than interpreted, because the tool's own refusal id (`BLOCKED`,
224
+ // `DEPLOYED_PROFILE_UNAUTHORIZED`, …) is the diagnosis and paraphrasing it loses the one string an
225
+ // operator can search for.
226
+ // ---- 5. smoke secrets (optional — only when exposure executor is this skill) ---------------
227
+ //
228
+ // Issue #823. When this skill runs the smoke gate (pre-flight item 3: exposure executor = skill),
229
+ // the smoke manifest's `setup.env` names secrets/credentials the gate needs. A common failure
230
+ // is an env var that contains the secret *resource name* (`projects/.../secrets/...`) instead
231
+ // of the secret *value*, which produces 401/403 at drive time. A pre-flight dry fetch catches
232
+ // that before a tag is minted and a candidate is built.
233
+ //
234
+ // The probe is intentionally platform-agnostic: by default it checks that each declared env
235
+ // var is set and that its value does not look like a secret resource path. A repo that wants a
236
+ // stronger check supplies `--smoke-secrets-command '<cmd> <name>'` and the probe substitutes
237
+ // `<name>` with each env var name. If the command exits non-zero, the secret is BLOCKED.
238
+ //
239
+ // A missing manifest or absent env var is UNKNOWN, not ok: the question was not answered.
240
+ const SECRET_RESOURCE_PATH_RE = /^projects\/[^/]+\/secrets\/[^/]+(\/versions\/[^/]+)?$/i
241
+
242
+ export function classifySmokeSecrets({
243
+ manifestPath = null,
244
+ env = [],
245
+ values = {},
246
+ command = null,
247
+ // When the caller supplied a path but could not read/parse it, fail closed — never
248
+ // treat that as "no secrets to verify" (the empty-env OK path). Issue #823 review.
249
+ manifestError = null,
250
+ } = {}) {
251
+ if (!manifestPath) {
252
+ return probe('smoke-secrets', PROBE_STATES.UNKNOWN,
253
+ 'no smoke manifest was supplied, so declared smoke secrets were not dry-fetched',
254
+ 'pass --smoke-manifest <path> when the exposure executor is this skill, so declared smoke secrets can be verified before the candidate is built')
255
+ }
256
+ if (manifestError) {
257
+ return probe('smoke-secrets', PROBE_STATES.UNKNOWN,
258
+ `smoke manifest at ${manifestPath} could not be read or parsed: ${manifestError}`,
259
+ 'fix the --smoke-manifest path (file must exist and be valid JSON with setup.env) and re-run — an unreadable manifest is not "no secrets to verify"')
260
+ }
261
+ if (!Array.isArray(env) || env.length === 0) {
262
+ return probe('smoke-secrets', PROBE_STATES.OK, 'smoke manifest declares no env/secrets to verify')
263
+ }
264
+ const bad = []
265
+ for (const name of env) {
266
+ const value = values[name]
267
+ if (value === undefined || value === null || value === '') {
268
+ bad.push({ name, reason: 'not set' })
269
+ continue
270
+ }
271
+ if (typeof value === 'string' && SECRET_RESOURCE_PATH_RE.test(value.trim())) {
272
+ bad.push({ name, reason: 'value looks like a secret resource path, not the secret value' })
273
+ }
274
+ }
275
+ if (command) {
276
+ for (const name of env) {
277
+ const result = sh(command.replace(/<name>/g, name), 30_000)
278
+ if (!result.ok) {
279
+ bad.push({ name, reason: `dry-fetch command failed: ${firstLine(`${result.stdout}\n${result.stderr}`)}` })
280
+ }
281
+ }
282
+ }
283
+ if (bad.length === 0) {
284
+ return probe('smoke-secrets', PROBE_STATES.OK, `${env.length} declared smoke secret(s) look resolvable`)
285
+ }
286
+ const named = bad.map((b) => `${b.name} (${b.reason})`).join('; ')
287
+ return probe('smoke-secrets', PROBE_STATES.BLOCKED,
288
+ `declared smoke secret(s) are misconfigured or could not be dry-fetched: ${named}`,
289
+ 'fix the smoke secret (the env var must hold the secret value, not its resource name) and re-run — a 401/403 at 4a is a CANNOT-RUN gate failure, not a DEAD candidate')
290
+ }
291
+
292
+ export function classifyExposureGate({ command = null, ok = false, stdout = '', stderr = '' } = {}) {
293
+ if (!command) {
294
+ return probe('exposure-gate-capability', PROBE_STATES.UNKNOWN,
295
+ 'no exposure-gate probe command was supplied, so whether this repo can produce a deployed-profile verdict is unknown',
296
+ 'pass --exposure-gate-probe "<command>" (the repo\'s own check that its exposure profile is authorized). Unknown is not ok: a repo that cannot produce the verdict parks at blocked-manual AFTER minting a tag and building a candidate')
297
+ }
298
+ if (ok) {
299
+ return probe('exposure-gate-capability', PROBE_STATES.OK, 'the repo reports its exposure profile can produce a verdict')
300
+ }
301
+ return probe('exposure-gate-capability', PROBE_STATES.BLOCKED,
302
+ `the repo cannot produce a verdict for its exposure profile: ${firstLine(`${stdout}\n${stderr}`)}`,
303
+ 'this release can only end blocked-manual — close the capability gap first (the deployment verifier / authorized profile), or declare a different exposure executor at pre-flight item 3')
304
+ }
305
+
306
+ function firstLine(text) {
307
+ const line = String(text || '').split('\n').map((l) => l.trim()).find((l) => l.length > 0)
308
+ return line ? line.slice(0, 300) : '(no output)'
309
+ }
310
+
311
+ // `unknown` counts as not-ready, deliberately. The whole failure this script addresses is a
312
+ // question nobody asked, and "we could not ask it" leaves the release in exactly that state.
313
+ export function summarize(probes) {
314
+ const list = Array.isArray(probes) ? probes : []
315
+ const blocked = list.filter((p) => p.state === PROBE_STATES.BLOCKED)
316
+ const unknown = list.filter((p) => p.state === PROBE_STATES.UNKNOWN)
317
+ return {
318
+ ready: list.length > 0 && blocked.length === 0 && unknown.length === 0,
319
+ blocked: blocked.map((p) => p.id),
320
+ unknown: unknown.map((p) => p.id),
321
+ probes: list,
322
+ }
323
+ }
324
+
325
+ export function parseArgs(argv) {
326
+ const args = { gates: [] }
327
+ for (let i = 0; i < argv.length; i += 1) {
328
+ const a = argv[i]
329
+ if (a === '--repo') args.repo = argv[++i]
330
+ else if (a === '--target-branch') args.targetBranch = argv[++i]
331
+ else if (a === '--credential-command') args.credentialCommand = argv[++i]
332
+ else if (a === '--exposure-gate-probe') args.exposureGateProbe = argv[++i]
333
+ else if (a === '--topology-probe') args.topologyProbe = argv[++i]
334
+ else if (a === '--smoke-manifest') args.smokeManifest = argv[++i]
335
+ else if (a === '--smoke-secrets-command') args.smokeSecretsCommand = argv[++i]
336
+ else if (a === '--gate') args.gates.push(argv[++i])
337
+ else if (a === '--json') args.json = true
338
+ else if (a === '--help' || a === '-h') args.help = true
339
+ else args.unknown = a
340
+ }
341
+ return args
342
+ }
343
+
344
+ export const DEFAULT_CREDENTIAL_COMMAND = 'gcloud auth print-access-token'
345
+
346
+ // Exported so the `-d` can be asserted. The bug it prevents lives in the COMMAND, not the
347
+ // parser, so no amount of parser testing catches its removal — see the comment at the call site.
348
+ export const LOCAL_TAGS_COMMAND = 'git show-ref --tags -d'
349
+
350
+ export function sh(command, timeout = 60_000) {
351
+ try {
352
+ const stdout = execFileSync('/bin/sh', ['-c', command], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout })
353
+ return { ok: true, stdout, stderr: '' }
354
+ } catch (error) {
355
+ return {
356
+ ok: false,
357
+ stdout: error.stdout?.toString?.() || '',
358
+ stderr: error.stderr?.toString?.() || error.message || '',
359
+ missing: /not found|ENOENT/i.test(error.message || ''),
360
+ }
361
+ }
362
+ }
363
+
364
+ function help() {
365
+ return `preflight-probes check --repo <owner/name> --target-branch <branch> [options]
366
+
367
+ The readiness questions a release otherwise discovers mid-flight. Run BEFORE opening the
368
+ attempt; the first four were found the hard way in pi session 019faea6, the topology probe catches
369
+ tag-trigger drift before an RC is minted (#1025), and smoke-secrets catches misconfiguration before
370
+ a candidate is built (#823).
371
+
372
+ Options:
373
+ --credential-command <cmd> liveness check, default: ${DEFAULT_CREDENTIAL_COMMAND}
374
+ --exposure-gate-probe <cmd> the repo's own check that its exposure profile can produce a
375
+ verdict. ABSENT is "unknown", which is NOT ready.
376
+ --topology-probe <cmd> read-only repository command that prints JSON for one representative
377
+ RC: prodBuildTrigger, versionSource, candidateTagSource, and
378
+ substitutions.TAG_NAME/_DEPLOYED_VERSION/_CANDIDATE_TAG. ABSENT is
379
+ "unknown", which is NOT ready.
380
+ --smoke-manifest <path> smoke manifest to read declared env/secrets from. Use when the
381
+ exposure executor is this skill.
382
+ --smoke-secrets-command <cmd> optional per-secret dry-fetch command; '<name>' is substituted
383
+ with each env var name declared in the smoke manifest.
384
+ --gate <name> a gate that must be present and green on the target head
385
+ (repeatable). With none, every failing check-run counts.
386
+ --json machine-readable summary on stdout
387
+
388
+ Exit codes:
389
+ 0 ready — every probe ok
390
+ 1 not ready — at least one blocked or unknown probe, each with a remedy
391
+ 2 usage error
392
+
393
+ "unknown" is never "ok": an unasked readiness question is the state this script exists to end.`
394
+ }
395
+
396
+ export async function runCli(argv) {
397
+ const args = parseArgs(argv)
398
+ if (args.help) { console.log(help()); return 0 }
399
+ const cmd = argv[0]
400
+ if (args.unknown && args.unknown !== cmd) { console.error(help()); return 2 }
401
+ if (cmd !== 'check') { console.error(help()); return 2 }
402
+ if (!args.repo || !args.targetBranch) { console.error(help()); return 2 }
403
+
404
+ const probes = []
405
+
406
+ const cred = sh(args.credentialCommand || DEFAULT_CREDENTIAL_COMMAND)
407
+ probes.push(classifyCredential(cred))
408
+
409
+ // `-d` (--dereference) is load-bearing, not tidiness: without it `show-ref --tags` prints only
410
+ // the TAG OBJECT sha for an annotated tag, while `ls-remote --tags` prints the tag object AND
411
+ // the `^{}` commit. Comparing one side's tag object against the other side's commit reports a
412
+ // divergence for every annotated tag in the repo — verified live against this skills repo, which
413
+ // returned six false positives (v0.1.0 "local 88493d4f vs remote a4afcc5d" is the same tag:
414
+ // 88493d4f is its tag object, a4afcc5d the commit). A probe that cries wolf on every release is
415
+ // a probe someone switches off, so both sides must dereference the same way.
416
+ const localTags = sh(`${LOCAL_TAGS_COMMAND} || true`)
417
+ const remoteTags = sh(`git ls-remote --tags ${shellQuote(`https://github.com/${args.repo}.git`)} || git ls-remote --tags origin`)
418
+ probes.push(classifyTagDivergence({
419
+ local: parseShowRef(localTags.stdout),
420
+ remote: parseLsRemote(remoteTags.stdout),
421
+ readable: localTags.ok && remoteTags.ok,
422
+ }))
423
+
424
+ // Fetch status alongside conclusion — IN_PROGRESS/QUEUED gates have conclusion:"" and
425
+ // must be classifiable by isCheckBlocking (same shape ensure-target-green fetchTip uses).
426
+ const checks = sh(`gh api repos/${args.repo}/commits/${shellQuote(args.targetBranch)}/check-runs --jq '[.check_runs[] | {name: .name, status: (.status // ""), conclusion: (.conclusion // "")}]'`)
427
+ probes.push(classifyTargetGate({
428
+ checks: checks.ok ? safeJson(checks.stdout) : null,
429
+ readable: checks.ok,
430
+ gates: args.gates,
431
+ }))
432
+
433
+ const topologyRead = args.topologyProbe ? sh(args.topologyProbe, 300_000) : {}
434
+ probes.push(classifyTagTopology({
435
+ topology: topologyRead.ok ? safeJson(topologyRead.stdout) : null,
436
+ readable: Boolean(args.topologyProbe) && topologyRead.ok,
437
+ }))
438
+
439
+ const exposure = args.exposureGateProbe ? sh(args.exposureGateProbe, 300_000) : {}
440
+ probes.push(classifyExposureGate({ command: args.exposureGateProbe || null, ...exposure }))
441
+
442
+ // Issue #823: optional smoke-secrets dry fetch when this skill runs the exposure gate.
443
+ // We read the manifest and the current process env values; the optional command lets a repo
444
+ // do a platform-specific real fetch if it wants one stronger than the resource-path heuristic.
445
+ if (args.smokeManifest) {
446
+ let manifest = null
447
+ let manifestError = null
448
+ try {
449
+ manifest = JSON.parse(fs.readFileSync(args.smokeManifest, 'utf8'))
450
+ } catch (err) {
451
+ // Prefer a short, actionable detail over a stack.
452
+ if (err && err.code === 'ENOENT') manifestError = 'file not found'
453
+ else if (err instanceof SyntaxError) manifestError = 'invalid JSON'
454
+ else manifestError = err && err.message ? err.message : String(err)
455
+ }
456
+ const env = !manifestError && manifest && Array.isArray(manifest.setup && manifest.setup.env)
457
+ ? manifest.setup.env
458
+ : []
459
+ probes.push(classifySmokeSecrets({
460
+ manifestPath: args.smokeManifest,
461
+ env,
462
+ values: Object.fromEntries(env.map((name) => [name, process.env[name]])),
463
+ command: args.smokeSecretsCommand || null,
464
+ manifestError,
465
+ }))
466
+ }
467
+
468
+ const summary = summarize(probes)
469
+ if (args.json) console.log(JSON.stringify(summary, null, 2))
470
+ else {
471
+ for (const p of summary.probes) {
472
+ console.log(`${p.state.toUpperCase().padEnd(7)} ${p.id} — ${p.detail}`)
473
+ if (p.remedy && p.state !== PROBE_STATES.OK) console.log(` remedy: ${p.remedy}`)
474
+ }
475
+ console.log(summary.ready ? '\nREADY — every probe ok' : `\nNOT READY — blocked: [${summary.blocked}] unknown: [${summary.unknown}]`)
476
+ }
477
+ return summary.ready ? 0 : 1
478
+ }
479
+
480
+ const shellQuote = (s) => `'${String(s).replace(/'/g, "'\\''")}'`
481
+ const safeJson = (t) => { try { return JSON.parse(t) } catch { return null } }
482
+
483
+ export function parseShowRef(text) {
484
+ const out = {}
485
+ for (const line of String(text || '').split('\n')) {
486
+ const m = /^([0-9a-f]{40})\s+refs\/tags\/(.+?)(\^\{\})?$/.exec(line.trim())
487
+ // Annotated tags list twice: the tag object, then `^{}` for the commit it points at. The
488
+ // dereferenced line is the comparable one, so it wins where both appear.
489
+ if (m) { if (m[3] || !(m[2] in out)) out[m[2]] = m[1] }
490
+ }
491
+ return out
492
+ }
493
+
494
+ export const parseLsRemote = parseShowRef
495
+
496
+ if (isMainModule(import.meta.url)) {
497
+ runCli(process.argv.slice(2)).then((code) => { process.exitCode = code })
498
+ }