@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,407 @@
1
+ // candidate-hygiene — pre-locate cleanup of stale candidate-* traffic tags.
2
+ //
3
+ // Previous successful releases can leave `candidate-<sha>` tags on the now-100% revision
4
+ // (the incumbent) or on an orphan 0% revision. Those tags are NOT a second release in flight,
5
+ // but they make `candidate-identity.mjs locate` report `e:second-candidate-in-flight`. This
6
+ // script reads the same traffic capture `locate` uses, classifies the foreign tags, and emits the
7
+ // `gcloud run services update-traffic --remove-tags` command that removes only the stale ones.
8
+ //
9
+ // A foreign tag is stale only when the shared traffic parser proves it has 0%, matching
10
+ // terminal release evidence identifies the same tag and revision, and the product-scoped lease
11
+ // report is valid and empty. Traffic, ambiguous traffic, missing/nonterminal evidence, or a
12
+ // held/unknown lease remains a competing release and refuses. A missing lease report after the
13
+ // other proofs reports `decision: "needs-lease-report"` and exits 3.
14
+ //
15
+ // The script is PURE: it does not shell out to gcloud or change production. The release lane runs
16
+ // the emitted command, then re-runs `candidate-identity.mjs locate` on the cleaned traffic.
17
+ //
18
+ // Usage:
19
+ // candidate-hygiene locate --sha <shipped> --traffic <file>
20
+ // [--candidate-tag-prefix <prefix-ending-in-hyphen>]
21
+ // [--lease-report <file>] [--terminal-evidence <file>] [--service <svc>] [--region <r>]
22
+ //
23
+ // Input `--traffic` is the same flattened / JSON form accepted by `candidate-identity.mjs`.
24
+ // `--lease-report` is the JSON output of `run-state.mjs check-release-lease-scoped` for the
25
+ // same product. `--terminal-evidence` is a JSON array of canonical resolve-release manifests
26
+ // or immutable release evidence bundles. Each stale candidate must match one verified terminal
27
+ // attempt by exact tag and revision. Without either proof, cleanup is not authorized.
28
+ //
29
+ // Exit codes:
30
+ // 0 clean / no-action — only stale tags (or none), and no true rival
31
+ // 1 refuse — a true second release is present; the failing ids are in `refuse`
32
+ // 2 usage / unreadable input
33
+ // 3 needs-lease-report — a 0% foreign candidate requires a lease report to classify; supply one and re-run
34
+
35
+ import fs from 'node:fs'
36
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
37
+ import { parseTraffic, normalizeTrafficPercents } from './candidate-traffic.mjs'
38
+ import { MIN_SHORT_SHA } from './candidate-identity.mjs'
39
+ import { RELEASE_STATE_CONTRACT } from '../../resolve-issues/scripts/release-state-contract.mjs'
40
+ import { validateBundle } from './evidence-bundle.mjs'
41
+
42
+ const SHA_RE = new RegExp(`^[0-9a-f]{${MIN_SHORT_SHA},40}$`, 'i')
43
+ const isSha = (s) => typeof s === 'string' && SHA_RE.test(s)
44
+
45
+ const shaMatches = (a, b) => {
46
+ if (!isSha(a) || !isSha(b)) return false
47
+ const [x, y] = [a.toLowerCase(), b.toLowerCase()]
48
+ const short = x.length <= y.length ? x : y
49
+ const long = short === x ? y : x
50
+ return long.startsWith(short)
51
+ }
52
+
53
+ const DEFAULT_CANDIDATE_TAG_PREFIX = 'candidate-'
54
+
55
+ function validCandidateTagPrefix(prefix) {
56
+ return typeof prefix === 'string' && /^[a-z][a-z0-9-]{0,30}-$/.test(prefix)
57
+ }
58
+
59
+ function classifyTag(tag, sha, candidateTagPrefix = DEFAULT_CANDIDATE_TAG_PREFIX) {
60
+ if (tag === 'candidate') return 'shared'
61
+ if (!validCandidateTagPrefix(candidateTagPrefix) || !tag.startsWith(candidateTagPrefix)) {
62
+ return 'other'
63
+ }
64
+ const suffix = tag.slice(candidateTagPrefix.length)
65
+ if (!/^[0-9a-f]{4,40}$/i.test(suffix) || !isSha(suffix)) return 'other'
66
+ return shaMatches(suffix, sha) ? 'ours' : 'foreign'
67
+ }
68
+
69
+ function readJson(file, what) {
70
+ if (!file) return { error: `usage: --${what} <file> is required` }
71
+ let raw
72
+ try {
73
+ raw = fs.readFileSync(file, 'utf8')
74
+ } catch {
75
+ return { error: `${what} not readable: ${file}` }
76
+ }
77
+ try {
78
+ return { value: JSON.parse(raw) }
79
+ } catch {
80
+ return { error: `${what} is not valid JSON: ${file}` }
81
+ }
82
+ }
83
+
84
+ const isObject = (value) => value != null && typeof value === 'object' && !Array.isArray(value)
85
+ const hasText = (value) => typeof value === 'string' && value.trim().length > 0
86
+
87
+ function matchingTerminalEvidence(terminalEvidence, candidate) {
88
+ if (!Array.isArray(terminalEvidence)) return null
89
+ const { leaseClosingStates, closeCauses } = RELEASE_STATE_CONTRACT.attempt
90
+ for (const evidence of terminalEvidence) {
91
+ if (!isObject(evidence)) continue
92
+
93
+ if (evidence.skill === 'resolve-release') {
94
+ const release = isObject(evidence.release) ? evidence.release : null
95
+ const attempt = release && isObject(release.attempt) ? release.attempt : null
96
+ const identity = release && isObject(release.candidateIdentity) ? release.candidateIdentity : null
97
+ if (
98
+ attempt && identity && hasText(attempt.id) && leaseClosingStates.includes(attempt.state) &&
99
+ attempt.closedBy === closeCauses[attempt.state] && hasText(attempt.evidence) &&
100
+ identity.tag === candidate.tag && identity.revision === candidate.revision
101
+ ) {
102
+ return { attemptId: attempt.id, source: 'manifest' }
103
+ }
104
+ continue
105
+ }
106
+
107
+ const bundle = validateBundle(evidence)
108
+ if (!bundle.valid) continue
109
+ const receipt = isObject(evidence.candidateReceipt) ? evidence.candidateReceipt : null
110
+ if (
111
+ hasText(evidence.attemptId) && receipt && leaseClosingStates.includes(evidence.terminalState) &&
112
+ evidence.closedBy === closeCauses[evidence.terminalState] &&
113
+ receipt.tag === candidate.tag && receipt.revision === candidate.revision
114
+ ) {
115
+ return { attemptId: evidence.attemptId, source: 'evidence-bundle' }
116
+ }
117
+ }
118
+ return null
119
+ }
120
+
121
+ function classifyLeaseReport(leaseReport) {
122
+ if (leaseReport === null || leaseReport === undefined) return { state: 'missing' }
123
+ if (!Array.isArray(leaseReport)) return { state: 'unknown', reason: 'product lease report is not an array' }
124
+ if (leaseReport.length === 0) return { state: 'clear' }
125
+
126
+ let held = false
127
+ for (const entry of leaseReport) {
128
+ if (!isObject(entry) || !isObject(entry.lease) || !isObject(entry.productMatch)) {
129
+ return { state: 'unknown', reason: 'product lease report contains an unreadable matching entry' }
130
+ }
131
+ if (entry.productMatch.repo === 'unknown' || entry.productMatch.service === 'unknown') {
132
+ return { state: 'unknown', reason: 'product lease identity is unknown' }
133
+ }
134
+ if (entry.productMatch.repo === false || entry.productMatch.service === false) {
135
+ return { state: 'unknown', reason: 'product lease report contains an entry outside its declared scope' }
136
+ }
137
+ if (entry.lease.code === 2 || entry.lease.state === 'unknown' || entry.lease.state === 'ambiguous') {
138
+ return { state: 'unknown', reason: entry.lease.reason || 'matching product lease is ambiguous' }
139
+ }
140
+ if (entry.lease.code === 1 || entry.lease.state === 'held') held = true
141
+ else return { state: 'unknown', reason: 'product lease report contains an unrecognized lease state' }
142
+ }
143
+ return held
144
+ ? { state: 'held', reason: 'a release attempt holds the matching product lease' }
145
+ : { state: 'unknown', reason: 'product lease report did not prove the matching product free' }
146
+ }
147
+
148
+ export function evaluateHygiene({
149
+ sha,
150
+ traffic,
151
+ leaseReport = null,
152
+ terminalEvidence = null,
153
+ incumbentRevision = null,
154
+ candidateTagPrefix = DEFAULT_CANDIDATE_TAG_PREFIX,
155
+ }) {
156
+ if (!isSha(sha)) {
157
+ return { decision: 'usage', refuse: [], sha, evidence: { error: 'e:unusable-shipped-sha' } }
158
+ }
159
+ if (!validCandidateTagPrefix(candidateTagPrefix)) {
160
+ return {
161
+ decision: 'usage',
162
+ refuse: [],
163
+ sha,
164
+ evidence: { error: 'e:invalid-candidate-tag-prefix', candidateTagPrefix },
165
+ }
166
+ }
167
+ const rows = normalizeTrafficPercents(traffic.rows)
168
+ const classified = rows.map((row) => ({
169
+ ...row,
170
+ kind: classifyTag(row.tag, sha, candidateTagPrefix),
171
+ }))
172
+ const ours = classified.filter((row) => row.kind === 'ours')
173
+ const foreign = classified.filter((row) => row.kind === 'foreign')
174
+
175
+ let incumbent = incumbentRevision
176
+ if (!incumbent) {
177
+ const hundredRows = classified.filter((row) => row.percent === 100 && row.revision)
178
+ if (hundredRows.length === 1) incumbent = hundredRows[0].revision
179
+ }
180
+
181
+ const lease = classifyLeaseReport(leaseReport)
182
+ const staleTags = []
183
+ const rivals = []
184
+ let needsLeaseReport = false
185
+
186
+ for (const row of foreign) {
187
+ if (
188
+ row.percent === null || !Number.isFinite(row.percent) ||
189
+ row.percent < 0 || row.percent > 100
190
+ ) {
191
+ rivals.push({ ...candidateConflict(row, 'foreign candidate has ambiguous traffic') })
192
+ continue
193
+ }
194
+ if (row.percent !== 0) {
195
+ rivals.push({ ...candidateConflict(row, 'foreign candidate has non-zero traffic') })
196
+ continue
197
+ }
198
+
199
+ const terminal = matchingTerminalEvidence(terminalEvidence, row)
200
+ if (!terminal) {
201
+ rivals.push({ ...candidateConflict(row, 'foreign zero-traffic candidate has no matching terminal release evidence') })
202
+ continue
203
+ }
204
+ if (lease.state === 'missing') {
205
+ needsLeaseReport = true
206
+ continue
207
+ }
208
+ if (lease.state === 'held' || lease.state === 'unknown') {
209
+ rivals.push({ ...candidateConflict(row, `foreign zero-traffic candidate is competing because the matching product lease is ${lease.state}: ${lease.reason}`) })
210
+ continue
211
+ }
212
+
213
+ staleTags.push({
214
+ tag: row.tag,
215
+ revision: row.revision,
216
+ percent: row.percent,
217
+ kind: row.revision && row.revision === incumbent ? 'stale-on-incumbent' : 'stale-foreign-zero',
218
+ terminalAttempt: terminal.attemptId,
219
+ })
220
+ }
221
+
222
+ const shared = classified.filter((row) => row.kind === 'shared')
223
+ if (ours.length > 0) {
224
+ for (const row of shared) {
225
+ if (row.revision && row.revision !== ours[0].revision) {
226
+ rivals.push(candidateConflict(row, 'shared candidate tag resolves to a different revision'))
227
+ }
228
+ }
229
+ }
230
+ if (ours.length > 1) {
231
+ rivals.push({
232
+ tag: ours.map((row) => row.tag).join(', '),
233
+ revision: null,
234
+ percent: null,
235
+ reason: 'multiple entries claim this SHA-keyed candidate tag',
236
+ })
237
+ }
238
+
239
+ const cleanupCommand = staleTags.length > 0
240
+ ? `gcloud run services update-traffic <service> --region <region> --remove-tags ${staleTags.map((tag) => tag.tag).join(',')}`
241
+ : null
242
+ const evidence = {
243
+ trafficEntries: classified.length,
244
+ ourTagCount: ours.length,
245
+ staleTagCount: staleTags.length,
246
+ ...(rivals.length > 0 ? { rivalCount: rivals.length } : {}),
247
+ }
248
+
249
+ if (rivals.length > 0) {
250
+ return {
251
+ decision: 'refuse', sha, incumbentRevision: incumbent || null, staleTags, rivals,
252
+ cleanupCommand: null, refuse: ['e:second-candidate-in-flight'], evidence,
253
+ }
254
+ }
255
+ if (needsLeaseReport) {
256
+ return {
257
+ decision: 'needs-lease-report', sha, incumbentRevision: incumbent || null, staleTags, rivals,
258
+ cleanupCommand: null, refuse: [], evidence: { ...evidence, foreignZeroWithoutLeaseReport: true },
259
+ }
260
+ }
261
+ return {
262
+ decision: staleTags.length > 0 ? 'clean' : 'no-action',
263
+ sha,
264
+ incumbentRevision: incumbent || null,
265
+ staleTags,
266
+ rivals,
267
+ cleanupCommand,
268
+ refuse: [],
269
+ evidence,
270
+ }
271
+ }
272
+
273
+ function candidateConflict(row, reason) {
274
+ return { tag: row.tag, revision: row.revision, percent: row.percent, reason }
275
+ }
276
+
277
+ const USAGE = `candidate-hygiene — pre-locate cleanup of stale candidate-* traffic tags.
278
+
279
+ Reads the same normalized traffic capture as candidate identity. A foreign \`candidate-*\`
280
+ tag is stale only with proven zero traffic, matching terminal release evidence, and a valid
281
+ empty product-scoped lease report; every ambiguous or competing shape refuses.
282
+
283
+ Usage:
284
+ candidate-hygiene locate --sha <shipped> --traffic <file>
285
+ [--candidate-tag-prefix <prefix-ending-in-hyphen>]
286
+ [--lease-report <file>] [--terminal-evidence <file>]
287
+ [--service <svc>] [--region <r>]
288
+
289
+ Options:
290
+ --sha <shipped> the promoted SHA
291
+ --traffic <file> the flattened or JSON traffic capture (same form as locate)
292
+ --candidate-tag-prefix repository SHA-keyed namespace; defaults to candidate-
293
+ --lease-report <file> JSON output of run-state.mjs check-release-lease-scoped for the
294
+ same product; without it, a 0% foreign candidate cannot be
295
+ classified as stale and the script reports "needs-lease-report"
296
+ --terminal-evidence <file> JSON array of canonical resolve-release manifests or immutable
297
+ evidence bundles; exact candidate tag/revision must match a verified
298
+ terminal close
299
+ --service <svc> Cloud Run service name (used to render a concrete cleanup command)
300
+ --region <r> Cloud Run region (used to render a concrete cleanup command)
301
+
302
+ Exit codes:
303
+ 0 clean or no-action — stale tags were found (or none) and no true rival
304
+ 1 refuse — a true second release is present; \`refuse\` contains e:second-candidate-in-flight
305
+ 2 usage / unreadable input
306
+ 3 needs-lease-report — a 0% foreign candidate requires a lease report to classify; supply one and re-run
307
+ `
308
+
309
+ function parseArgs(argv) {
310
+ const opts = {}
311
+ const positional = []
312
+ for (let i = 0; i < argv.length; i++) {
313
+ const a = argv[i]
314
+ if (a === '--help' || a === '-h') opts.help = true
315
+ else if (a.startsWith('--')) opts[a.slice(2)] = argv[++i]
316
+ else positional.push(a)
317
+ }
318
+ return { opts, positional }
319
+ }
320
+
321
+ export function main(argv) {
322
+ const { opts, positional } = parseArgs(argv)
323
+ const cmd = positional[0]
324
+ if (opts.help || cmd === 'help') {
325
+ console.log(USAGE)
326
+ return 0
327
+ }
328
+ if (cmd !== 'locate') {
329
+ const what = cmd ? `unknown command "${cmd}"` : 'no subcommand given'
330
+ console.error(`candidate-hygiene: ${what}. Use locate (see --help).`)
331
+ return 2
332
+ }
333
+ if (!opts.sha) {
334
+ console.error('candidate-hygiene: usage: locate requires --sha <shipped>')
335
+ return 2
336
+ }
337
+ if (
338
+ 'candidate-tag-prefix' in opts &&
339
+ (typeof opts['candidate-tag-prefix'] !== 'string' ||
340
+ !opts['candidate-tag-prefix'] ||
341
+ opts['candidate-tag-prefix'].startsWith('--'))
342
+ ) {
343
+ console.error('candidate-hygiene: --candidate-tag-prefix requires a value')
344
+ return 2
345
+ }
346
+ if (!opts.traffic) {
347
+ console.error('candidate-hygiene: usage: locate requires --traffic <file>')
348
+ return 2
349
+ }
350
+
351
+ let text
352
+ try {
353
+ text = fs.readFileSync(opts.traffic, 'utf8')
354
+ } catch {
355
+ console.error(`candidate-hygiene: traffic read not readable: ${opts.traffic}`)
356
+ return 2
357
+ }
358
+ const traffic = parseTraffic(text)
359
+ if (traffic.error) {
360
+ console.error(`candidate-hygiene: ${traffic.error}`)
361
+ return 2
362
+ }
363
+
364
+ let leaseReport = null
365
+ let terminalEvidence = null
366
+ if (opts['lease-report']) {
367
+ const read = readJson(opts['lease-report'], 'lease-report')
368
+ if (read.error) {
369
+ console.error(`candidate-hygiene: ${read.error}`)
370
+ return 2
371
+ }
372
+ leaseReport = read.value
373
+ }
374
+
375
+ if (opts['terminal-evidence']) {
376
+ const read = readJson(opts['terminal-evidence'], 'terminal-evidence')
377
+ if (read.error) {
378
+ console.error(`candidate-hygiene: ${read.error}`)
379
+ return 2
380
+ }
381
+ terminalEvidence = read.value
382
+ }
383
+
384
+ const result = evaluateHygiene({
385
+ sha: opts.sha,
386
+ traffic,
387
+ leaseReport,
388
+ terminalEvidence,
389
+ incumbentRevision: opts['incumbent-revision'] || null,
390
+ candidateTagPrefix: opts['candidate-tag-prefix'] || DEFAULT_CANDIDATE_TAG_PREFIX,
391
+ })
392
+
393
+ // Replace the <service>/<region> placeholders with concrete values if the caller supplied them.
394
+ if (result.cleanupCommand && opts.service && opts.region) {
395
+ result.cleanupCommand = result.cleanupCommand.replace('<service>', opts.service).replace('<region>', opts.region)
396
+ }
397
+
398
+ console.log(JSON.stringify(result, null, 2))
399
+ if (result.decision === 'refuse') return 1
400
+ if (result.decision === 'usage') return 2
401
+ if (result.decision === 'needs-lease-report') return 3
402
+ return 0
403
+ }
404
+
405
+ if (isMainModule(import.meta.url)) {
406
+ process.exit(main(process.argv.slice(2)))
407
+ }