@1aboveio/skills 0.19.2 → 0.20.1

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 (203) hide show
  1. package/README.md +9 -4
  2. package/package.json +1 -1
  3. package/runtime/skills/distribution/generated/recipes.json +54 -48
  4. package/runtime/skills/distribution/scripts/bundles.mjs +113 -7
  5. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
  6. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
  7. package/skills/cicd-pipeline/mergify/SKILL.md +1 -1
  8. package/skills/engineering/engineering-runtime/coherence/workflow.json +14 -83
  9. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
  10. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
  11. package/skills/engineering/smoke/SKILL.md +1 -1
  12. package/skills/payment/payment-analysis/SKILL.md +13 -7
  13. package/skills/payment/payment-analysis/references/chargebacks.md +43 -18
  14. package/skills/payment/payment-analysis/references/event-layers.md +4 -0
  15. package/skills/payment/payment-analysis/references/metrics.md +9 -7
  16. package/skills/payment/payment-analysis/references/report-template.md +3 -3
  17. package/skills/payment/payment-analysis/references/terminology.md +6 -1
  18. package/skills/payment/payment-analysis/references/visualization.md +1 -1
  19. package/skills/payment/tld-detection/SKILL.md +163 -0
  20. package/skills/payment/tld-detection/agents/openai.yaml +9 -0
  21. package/skills/payment/tld-detection/evals/evals.json +107 -0
  22. package/skills/payment/tld-detection/references/clean.md +51 -0
  23. package/skills/payment/tld-detection/references/clustering.md +219 -0
  24. package/skills/payment/tld-detection/references/decision.md +85 -0
  25. package/skills/payment/tld-detection/references/report-template.md +169 -0
  26. package/skills/payment/tld-detection/references/terminology.md +69 -0
  27. package/skills/payment/tld-detection/references/workflow.md +78 -0
  28. package/skills/payment/tld-detection/scripts/detect_ladders.py +390 -0
  29. package/skills/payment/tld-detection/tests/test_detect_ladders.py +132 -0
  30. package/skills/engineering/resolve-issues/SKILL.md +0 -168
  31. package/skills/engineering/resolve-issues/agents/openai.yaml +0 -9
  32. package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +0 -499
  33. package/skills/engineering/resolve-issues/references/breaker.md +0 -82
  34. package/skills/engineering/resolve-issues/references/deliverables.md +0 -27
  35. package/skills/engineering/resolve-issues/references/delivery.md +0 -108
  36. package/skills/engineering/resolve-issues/references/evidence-lane.md +0 -21
  37. package/skills/engineering/resolve-issues/references/exact-head-ci.md +0 -287
  38. package/skills/engineering/resolve-issues/references/fan-out.md +0 -33
  39. package/skills/engineering/resolve-issues/references/finalization.md +0 -68
  40. package/skills/engineering/resolve-issues/references/guarantees.md +0 -10
  41. package/skills/engineering/resolve-issues/references/high-risk.md +0 -29
  42. package/skills/engineering/resolve-issues/references/incidents/848/README.md +0 -156
  43. package/skills/engineering/resolve-issues/references/intake.md +0 -86
  44. package/skills/engineering/resolve-issues/references/integration-gate.md +0 -53
  45. package/skills/engineering/resolve-issues/references/interference.md +0 -87
  46. package/skills/engineering/resolve-issues/references/loop.md +0 -134
  47. package/skills/engineering/resolve-issues/references/model-catalog.md +0 -9
  48. package/skills/engineering/resolve-issues/references/postmortem.md +0 -27
  49. package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +0 -41
  50. package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +0 -48
  51. package/skills/engineering/resolve-issues/references/pre-flight.md +0 -41
  52. package/skills/engineering/resolve-issues/references/regression-checklist.md +0 -26
  53. package/skills/engineering/resolve-issues/references/run-state.md +0 -288
  54. package/skills/engineering/resolve-issues/references/sandboxed-testing.md +0 -48
  55. package/skills/engineering/resolve-issues/references/spawn-contract.md +0 -96
  56. package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +0 -40
  57. package/skills/engineering/resolve-issues/references/why.md +0 -653
  58. package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +0 -49
  59. package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +0 -721
  60. package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +0 -962
  61. package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +0 -220
  62. package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +0 -420
  63. package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +0 -256
  64. package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +0 -168
  65. package/skills/engineering/resolve-issues/scripts/discover-models.mjs +0 -9
  66. package/skills/engineering/resolve-issues/scripts/doctrine.mjs +0 -62
  67. package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +0 -191
  68. package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +0 -413
  69. package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +0 -332
  70. package/skills/engineering/resolve-issues/scripts/finalize.mjs +0 -488
  71. package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +0 -3307
  72. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +0 -16
  73. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +0 -51
  74. package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +0 -17
  75. package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +0 -166
  76. package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +0 -92
  77. package/skills/engineering/resolve-issues/scripts/guide-index.mjs +0 -73
  78. package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +0 -159
  79. package/skills/engineering/resolve-issues/scripts/interference.mjs +0 -427
  80. package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +0 -9
  81. package/skills/engineering/resolve-issues/scripts/next-operations.mjs +0 -419
  82. package/skills/engineering/resolve-issues/scripts/postmortem.mjs +0 -909
  83. package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +0 -345
  84. package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +0 -415
  85. package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +0 -697
  86. package/skills/engineering/resolve-issues/scripts/report.mjs +0 -494
  87. package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +0 -172
  88. package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +0 -79
  89. package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +0 -334
  90. package/skills/engineering/resolve-issues/scripts/run-state.mjs +0 -4792
  91. package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +0 -395
  92. package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +0 -290
  93. package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +0 -170
  94. package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +0 -293
  95. package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +0 -197
  96. package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +0 -127
  97. package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +0 -893
  98. package/skills/engineering/resolve-issues/scripts/workspaces.mjs +0 -829
  99. package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +0 -290
  100. package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +0 -80
  101. package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +0 -102
  102. package/skills/engineering/resolve-release/LICENSE +0 -3
  103. package/skills/engineering/resolve-release/SKILL.md +0 -113
  104. package/skills/engineering/resolve-release/agents/openai.yaml +0 -9
  105. package/skills/engineering/resolve-release/references/assembly.md +0 -137
  106. package/skills/engineering/resolve-release/references/auto-when-green.md +0 -56
  107. package/skills/engineering/resolve-release/references/candidate.md +0 -167
  108. package/skills/engineering/resolve-release/references/exposure.md +0 -178
  109. package/skills/engineering/resolve-release/references/handoff.md +0 -24
  110. package/skills/engineering/resolve-release/references/postmortem.md +0 -230
  111. package/skills/engineering/resolve-release/references/preflight.md +0 -208
  112. package/skills/engineering/resolve-release/references/principles.md +0 -94
  113. package/skills/engineering/resolve-release/references/regression-checklist.md +0 -36
  114. package/skills/engineering/resolve-release/references/related-skills.md +0 -13
  115. package/skills/engineering/resolve-release/references/routing.md +0 -149
  116. package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +0 -285
  117. package/skills/engineering/resolve-release/references/versioning.md +0 -202
  118. package/skills/engineering/resolve-release/references/why.md +0 -53
  119. package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +0 -389
  120. package/skills/engineering/resolve-release/scripts/build-changes.mjs +0 -209
  121. package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +0 -407
  122. package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +0 -904
  123. package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +0 -81
  124. package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +0 -612
  125. package/skills/engineering/resolve-release/scripts/close-attempt.mjs +0 -135
  126. package/skills/engineering/resolve-release/scripts/closeout-release.mjs +0 -161
  127. package/skills/engineering/resolve-release/scripts/doctrine.mjs +0 -106
  128. package/skills/engineering/resolve-release/scripts/durable-processing.mjs +0 -522
  129. package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +0 -659
  130. package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +0 -1014
  131. package/skills/engineering/resolve-release/scripts/finalize-release.mjs +0 -526
  132. package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +0 -169
  133. package/skills/engineering/resolve-release/scripts/green-gate.mjs +0 -599
  134. package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +0 -752
  135. package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +0 -56
  136. package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +0 -1538
  137. package/skills/engineering/resolve-release/scripts/postmortem.mjs +0 -381
  138. package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +0 -510
  139. package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +0 -326
  140. package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +0 -272
  141. package/skills/engineering/resolve-release/scripts/report.mjs +0 -417
  142. package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +0 -114
  143. package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +0 -238
  144. package/skills/engineering/resolve-release/scripts/review-packet.mjs +0 -503
  145. package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +0 -263
  146. package/skills/engineering/resolve-release/scripts/version-assert.mjs +0 -339
  147. package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +0 -485
  148. package/skills/engineering/resolve-release/scripts/version.mjs +0 -1199
  149. package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +0 -449
  150. package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +0 -21
  151. package/skills/engineering/resolve-release/vendor/README.md +0 -60
  152. package/skills/engineering/resolve-release/vendor/acorn.mjs +0 -6233
  153. package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +0 -21
  154. package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +0 -341
  155. package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +0 -70
  156. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +0 -2
  157. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +0 -1
  158. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +0 -7
  159. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +0 -1
  160. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +0 -2033
  161. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +0 -2033
  162. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +0 -7
  163. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +0 -1
  164. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +0 -2
  165. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +0 -1
  166. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +0 -2
  167. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +0 -1
  168. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +0 -2
  169. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +0 -1
  170. package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +0 -49
  171. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +0 -21
  172. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +0 -5
  173. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +0 -549
  174. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +0 -549
  175. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +0 -2
  176. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +0 -1
  177. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +0 -2
  178. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +0 -1
  179. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +0 -36
  180. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +0 -47
  181. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +0 -82
  182. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +0 -11
  183. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +0 -22
  184. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +0 -21
  185. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +0 -21
  186. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +0 -11
  187. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +0 -11
  188. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +0 -25
  189. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
  190. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +0 -85
  191. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +0 -85
  192. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +0 -2
  193. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +0 -1
  194. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +0 -2
  195. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +0 -1
  196. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +0 -20
  197. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +0 -20
  198. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +0 -2
  199. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +0 -1
  200. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +0 -2
  201. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +0 -1
  202. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +0 -61
  203. /package/skills/{engineering/resolve-issues → payment/tld-detection}/LICENSE +0 -0
@@ -1,332 +0,0 @@
1
- // GitHub provider for exact-head-ci.mjs. Reads one operation as JSON on stdin and
2
- // writes one JSON response. It never exposes enqueue, approve, merge, review-write,
3
- // or queue-write operations.
4
-
5
- import fs from 'node:fs'
6
- import { execFileSync } from 'node:child_process'
7
- import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
8
- import { providerWorkflowIdentityMatches } from '../../engineering-runtime/scripts/exact-head-artifact.mjs'
9
-
10
- const PROVIDER_HANDLERS = Object.freeze({
11
- snapshot,
12
- retarget: mutate,
13
- 'set-open': mutate,
14
- 'set-draft': mutate,
15
- 'set-labels': mutate,
16
- 'set-queue-inactive': deactivateQueue,
17
- 'dispatch-workflow': dispatch,
18
- 'read-workflow': readWorkflow,
19
- 'read-publish-only-checks': readPublishOnlyChecks,
20
- 'read-queue-execution': readQueueExecution,
21
- })
22
-
23
- export const PROVIDER_OPERATIONS = Object.freeze(Object.keys(PROVIDER_HANDLERS))
24
-
25
- function isObject(value) {
26
- return value !== null && typeof value === 'object' && !Array.isArray(value)
27
- }
28
-
29
- function strings(value) {
30
- return Array.isArray(value) && value.every((item) => typeof item === 'string' && item.trim())
31
- }
32
-
33
- export function validateProviderRequest(request) {
34
- const errors = []
35
- if (!isObject(request)) return { ok: false, errors: ['provider request must be an object'] }
36
- if (!PROVIDER_OPERATIONS.includes(request.operation)) errors.push(`unsupported provider operation "${request.operation}"`)
37
- if (typeof request.repository !== 'string' || !/^[^/\s]+\/[^/\s]+$/.test(request.repository)) errors.push('repository must be owner/name')
38
- if (!Number.isInteger(request.pr) || request.pr < 1) errors.push('pr must be a positive integer')
39
- const config = request.providerConfig
40
- const readOnlyQueueExecution = request.operation === 'read-queue-execution'
41
- const needsSnapshotConfig = ['snapshot', 'retarget', 'set-open', 'set-draft', 'set-labels', 'set-queue-inactive', 'read-publish-only-checks'].includes(request.operation)
42
- const needsDeactivationConfig = request.operation === 'set-queue-inactive'
43
- const needsDispatchConfig = request.operation === 'dispatch-workflow'
44
- if (!readOnlyQueueExecution && !isObject(config)) errors.push('providerConfig must be an object')
45
- if (!readOnlyQueueExecution && config?.ghCommand !== undefined && (typeof config.ghCommand !== 'string' || !config.ghCommand.trim())) errors.push('providerConfig.ghCommand must be a non-empty string')
46
-
47
- if (needsSnapshotConfig) {
48
- if (!strings(config?.queueActiveLabels)) errors.push('providerConfig.queueActiveLabels must be an array of strings (use [] when no label represents queue membership)')
49
- if (typeof config?.queueProvider !== 'string' || !config.queueProvider.trim()) errors.push('providerConfig.queueProvider must be a non-empty string')
50
- }
51
-
52
- if (needsDeactivationConfig) {
53
- const deactivateArgs = config?.queueDeactivateArgs
54
- const deactivateBodyIndex = Array.isArray(deactivateArgs) ? deactivateArgs.indexOf('--body') : -1
55
- const deactivateBody = deactivateBodyIndex >= 0 ? deactivateArgs[deactivateBodyIndex + 1] : ''
56
- const nonDeactivationBody = typeof deactivateBody === 'string' ? deactivateBody.replace(/\b(?:dequeue|unqueue)\b/gi, '') : ''
57
- const safeDeactivation = Array.isArray(deactivateArgs)
58
- && deactivateArgs.length === 7
59
- && deactivateArgs.slice(0, 6).every((arg, index) => arg === ['pr', 'comment', '{pr}', '--repo', '{repository}', '--body'][index])
60
- && typeof deactivateBody === 'string'
61
- && /\b(?:dequeue|unqueue)\b/i.test(deactivateBody)
62
- && !/\b(?:queue|enqueue|approve|merge|review)\b/i.test(nonDeactivationBody)
63
- if (!strings(deactivateArgs)) errors.push('providerConfig.queueDeactivateArgs must be an array of strings')
64
- if (Array.isArray(config?.queueActiveLabels) && config.queueActiveLabels.length > 0 && Array.isArray(deactivateArgs) && deactivateArgs.length === 0) errors.push('providerConfig.queueDeactivateArgs cannot be empty when queueActiveLabels can detect active membership')
65
- if (Array.isArray(config?.queueActiveLabels) && config.queueActiveLabels.length > 0 && !safeDeactivation) errors.push('providerConfig.queueDeactivateArgs must be a direct gh pr comment deactivation and cannot enqueue, approve, merge, or write reviews')
66
- }
67
-
68
- if (needsDispatchConfig) {
69
- for (const field of ['creationTimeoutMs', 'creationPollIntervalMs']) {
70
- if (!Number.isInteger(config?.[field]) || config[field] < 1) errors.push(`providerConfig.${field} must be a positive integer`)
71
- }
72
- }
73
- if (request.operation === 'read-workflow') {
74
- if (typeof request.runId !== 'string' && typeof request.runId !== 'number') errors.push('runId must identify the provider run')
75
- if (typeof request.workflowId !== 'string' || !request.workflowId.trim()) errors.push('workflowId must identify the expected provider workflow')
76
- if (typeof request.headSha !== 'string' || !/^[0-9a-f]{40}$/i.test(request.headSha)) errors.push('headSha must be a full 40-character commit SHA')
77
- }
78
- return { ok: errors.length === 0, errors }
79
- }
80
-
81
- const DEFAULT_BOUNDARY = Object.freeze({ execFileSync })
82
-
83
- function gh(request, args, boundary) {
84
- return boundary.execFileSync(request.providerConfig?.ghCommand || 'gh', args, {
85
- encoding: 'utf8', maxBuffer: 32 * 1024 * 1024,
86
- }).trim()
87
- }
88
-
89
- function ghJson(request, args, boundary) {
90
- const text = gh(request, args, boundary)
91
- return text ? JSON.parse(text) : null
92
- }
93
-
94
- function pause(ms) {
95
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms)
96
- }
97
-
98
- export function snapshotFromView(view, config) {
99
- const labels = (view.labels || []).map((label) => typeof label === 'string' ? label : label.name).filter(Boolean).sort()
100
- const activeLabels = new Set(config.queueActiveLabels)
101
- const matchingLabels = labels.filter((label) => activeLabels.has(label))
102
- return {
103
- base: view.baseRefName,
104
- headSha: view.headRefOid,
105
- open: view.state === 'OPEN',
106
- draft: view.isDraft === true,
107
- labels,
108
- queue: {
109
- provider: config.queueProvider,
110
- state: matchingLabels.length ? 'active' : 'inactive',
111
- active: matchingLabels.length > 0,
112
- matchingLabels,
113
- },
114
- reviews: {
115
- decision: view.reviewDecision || null,
116
- latest: (view.latestReviews || []).map(({ id, author, state, submittedAt, commit }) => ({
117
- id: id || null,
118
- author: author?.login || null,
119
- state: state || null,
120
- submittedAt: submittedAt || null,
121
- commitOid: commit?.oid || null,
122
- })),
123
- },
124
- }
125
- }
126
-
127
- export function labelDelta(current, target) {
128
- const have = new Set(current)
129
- const want = new Set(target)
130
- return {
131
- add: [...want].filter((label) => !have.has(label)).sort(),
132
- remove: [...have].filter((label) => !want.has(label)).sort(),
133
- }
134
- }
135
-
136
- export function chooseCreatedRun(runs, { headSha, startedAt }) {
137
- return (runs || [])
138
- .filter((run) => run.headSha === headSha && Date.parse(run.createdAt) >= Date.parse(startedAt))
139
- .sort((left, right) => Date.parse(left.createdAt) - Date.parse(right.createdAt))[0] || null
140
- }
141
-
142
- function snapshot(request, boundary) {
143
- const view = ghJson(request, ['pr', 'view', String(request.pr), '--repo', request.repository, '--json', 'baseRefName,headRefOid,state,isDraft,labels,reviewDecision,latestReviews'], boundary)
144
- return snapshotFromView(view, request.providerConfig)
145
- }
146
-
147
- function mutate(request, boundary) {
148
- const base = ['--repo', request.repository]
149
- const current = snapshot(request, boundary)
150
- if (request.operation === 'retarget') {
151
- if (current.base === request.base) return { ok: true, unchanged: true }
152
- gh(request, ['pr', 'edit', String(request.pr), ...base, '--base', request.base], boundary)
153
- } else if (request.operation === 'set-open') {
154
- if (current.open === request.open) return { ok: true, unchanged: true }
155
- gh(request, ['pr', request.open ? 'reopen' : 'close', String(request.pr), ...base], boundary)
156
- } else if (request.operation === 'set-draft') {
157
- if (current.draft === request.draft) return { ok: true, unchanged: true }
158
- gh(request, request.draft
159
- ? ['pr', 'ready', String(request.pr), ...base, '--undo']
160
- : ['pr', 'ready', String(request.pr), ...base], boundary)
161
- } else if (request.operation === 'set-labels') {
162
- const delta = labelDelta(current.labels, request.labels)
163
- for (const label of delta.remove) gh(request, ['pr', 'edit', String(request.pr), ...base, '--remove-label', label], boundary)
164
- for (const label of delta.add) gh(request, ['pr', 'edit', String(request.pr), ...base, '--add-label', label], boundary)
165
- }
166
- return { ok: true }
167
- }
168
-
169
- function deactivateQueue(request, boundary) {
170
- const current = snapshot(request, boundary)
171
- if (!current.queue.active) return { ok: true, alreadyInactive: true }
172
- const args = request.providerConfig.queueDeactivateArgs.map((arg) => arg
173
- .replaceAll('{pr}', String(request.pr))
174
- .replaceAll('{repository}', request.repository))
175
- gh(request, args, boundary)
176
- return { ok: true, alreadyInactive: false }
177
- }
178
-
179
- function dispatch(request, boundary) {
180
- const startedAt = new Date().toISOString()
181
- const args = ['workflow', 'run', request.workflow, '--repo', request.repository, '--ref', request.ref]
182
- for (const [key, value] of Object.entries(request.inputs || {})) args.push('-f', `${key}=${String(value)}`)
183
- gh(request, args, boundary)
184
- const deadline = Date.now() + request.providerConfig.creationTimeoutMs
185
- while (Date.now() <= deadline) {
186
- const runs = ghJson(request, ['run', 'list', '--repo', request.repository, '--workflow', request.workflow, '--event', 'workflow_dispatch', '--limit', '100', '--json', 'databaseId,status,conclusion,headSha,createdAt'], boundary)
187
- const run = chooseCreatedRun(runs, { headSha: request.headSha, startedAt })
188
- if (run) return { runId: run.databaseId }
189
- pause(request.providerConfig.creationPollIntervalMs)
190
- }
191
- throw new Error(`workflow-creation-failure: no ${request.workflow} run appeared at ${request.headSha} within ${request.providerConfig.creationTimeoutMs}ms`)
192
- }
193
-
194
- function readWorkflow(request, boundary) {
195
- const run = ghJson(request, ['api', `repos/${request.repository}/actions/runs/${request.runId}`], boundary)
196
- const workflow = { id: run?.workflow_id, name: run?.name, path: run?.path }
197
- if (String(run?.id) !== String(request.runId)) throw new Error(`workflow run identity mismatch: expected run ${request.runId}, observed ${run?.id ?? 'missing'}`)
198
- if (run?.head_sha !== request.headSha) throw new Error(`workflow head-drift: expected ${request.headSha}, observed ${run?.head_sha ?? 'missing'}`)
199
- if (!providerWorkflowIdentityMatches(request.workflowId, workflow)) {
200
- throw new Error(`workflow identity mismatch: expected ${request.workflowId}, observed ${workflow.name || workflow.path || workflow.id || 'missing'}`)
201
- }
202
- const pages = ghJson(request, ['api', '--paginate', '--slurp', `repos/${request.repository}/actions/runs/${request.runId}/jobs?per_page=100`], boundary) || []
203
- const jobs = pages.flatMap((page) => page.jobs || []).map(({ id, name, status, conclusion }) => ({ id, name, status, conclusion }))
204
- return { runId: run.id, workflow, status: run.status, conclusion: run.conclusion, headSha: run.head_sha, jobs }
205
- }
206
- const MERGIFY_PAYLOAD_RE = /-\*- Mergify Payload -\*-\s*\n(\{[\s\S]*?\})\s*\n-\*- Mergify Payload End -\*-/
207
-
208
- function mergedQueuePr(comments) {
209
- const status = (comments || []).filter((comment) => comment?.author?.login === 'mergify' && /"state"\s*:\s*"merged"/.test(comment?.body || ''))
210
- const ids = status.map((comment) => /Checks passed\s*[^#]*#(\d+)/i.exec(comment.body || '')?.[1]).filter(Boolean)
211
- return ids.length === 1 ? Number(ids[0]) : null
212
- }
213
-
214
- function queuePrNumber(value) {
215
- return Number.isInteger(value) && value > 0 ? value : null
216
- }
217
-
218
- function activeQueuePr(comments) {
219
- let queuePr = null
220
- for (const comment of Array.isArray(comments) ? comments : []) {
221
- if (comment?.author?.login !== 'mergify') continue
222
- const match = MERGIFY_PAYLOAD_RE.exec(comment?.body || '')
223
- if (!match) continue
224
- let payload
225
- try { payload = JSON.parse(match[1]) } catch { continue }
226
- const candidate = queuePrNumber(payload?.speculative_check_pr)
227
- if (candidate) queuePr = candidate
228
- }
229
- return queuePr
230
- }
231
-
232
- function queueCheckState(run) {
233
- const conclusion = String(run?.conclusion ?? '').toLowerCase()
234
- if (conclusion === 'success') return 'success'
235
- if (['failure', 'error', 'timed_out', 'cancelled', 'action_required', 'startup_failure'].includes(conclusion)) return 'failure'
236
- if (['neutral', 'skipped'].includes(conclusion)) return conclusion
237
- const status = String(run?.status ?? run?.state ?? '').toLowerCase()
238
- if (['queued', 'requested', 'waiting', 'pending'].includes(status)) return 'queued'
239
- if (['in_progress', 'running'].includes(status)) return 'running'
240
- return 'queued'
241
- }
242
-
243
- function queueObservationStatus(checks, wantedCount) {
244
- if (checks.some((check) => check.state === 'failure')) return 'failure'
245
- if (checks.length === wantedCount && checks.every((check) => check.state === 'success')) return 'success'
246
- if (checks.some((check) => check.state === 'running')) return 'running'
247
- return 'queued'
248
- }
249
-
250
- function readQueueExecution(request, boundary) {
251
- const source = ghJson(request, ['pr', 'view', String(request.pr), '--repo', request.repository, '--json', 'headRefOid,comments'], boundary)
252
- if (source?.headRefOid !== request.prHeadSha) throw new Error(`queue-execution PR-head drift: expected ${request.prHeadSha}, observed ${source?.headRefOid ?? 'missing'}`)
253
- const mergedPr = mergedQueuePr(source.comments)
254
- const queuePr = mergedPr ?? activeQueuePr(source.comments)
255
- if (!queuePr) throw new Error('queue-execution unavailable or ambiguous: Mergify status did not identify one synthetic draft PR')
256
- const queue = ghJson(request, ['api', `repos/${request.repository}/pulls/${queuePr}`], boundary)
257
- const queueHeadSha = queue?.head?.sha
258
- if (typeof queueHeadSha !== 'string' || !/^[0-9a-f]{40}$/i.test(queueHeadSha) || queueHeadSha === request.prHeadSha) {
259
- throw new Error('queue-execution unavailable: synthetic queue PR has no distinct full head SHA')
260
- }
261
- const pages = ghJson(request, ['api', '--paginate', '--slurp', `repos/${request.repository}/commits/${queueHeadSha}/check-runs?per_page=100`], boundary) || []
262
- const wanted = new Set(request.names || [])
263
- const runs = pages.flatMap((page) => page.check_runs || []).filter((run) => wanted.has(run.name))
264
- const byName = new Map()
265
- for (const run of runs) {
266
- if (byName.has(run.name)) throw new Error(`queue-execution ambiguous: duplicate check run ${run.name} on synthetic head`)
267
- byName.set(run.name, run)
268
- }
269
- if (mergedPr) {
270
- if (byName.size !== wanted.size) throw new Error('queue-execution unavailable: one or more required queue-head checks are missing')
271
- return {
272
- version: 1, kind: 'queue-execution', repository: request.repository, pr: request.pr,
273
- prHeadSha: request.prHeadSha, queuePr, queueHeadSha, provider: 'github',
274
- checks: [...wanted].sort().map((name) => ({ name, provider: 'github', conclusion: byName.get(name).conclusion, headSha: queueHeadSha })),
275
- status: 'pass',
276
- }
277
- }
278
- const checks = [...wanted].sort().flatMap((name) => {
279
- const run = byName.get(name)
280
- return run ? [{
281
- name, provider: 'github', status: run.status ?? null, conclusion: run.conclusion ?? null,
282
- state: queueCheckState(run), headSha: queueHeadSha,
283
- }] : []
284
- })
285
- return {
286
- version: 1, kind: 'queue-execution-observation', repository: request.repository, pr: request.pr,
287
- prHeadSha: request.prHeadSha, queuePr, queueHeadSha, provider: 'github', checks,
288
- status: queueObservationStatus(checks, wanted.size),
289
- }
290
- }
291
-
292
- function readPublishOnlyChecks(request, boundary) {
293
- const live = snapshot(request, boundary)
294
- if (live.headSha !== request.headSha) throw new Error(`publish-only head-drift: expected ${request.headSha}, observed ${live.headSha}`)
295
- const pages = ghJson(request, ['api', '--paginate', '--slurp', `repos/${request.repository}/commits/${request.headSha}/check-runs?per_page=100`], boundary) || []
296
- const checks = pages.flatMap((page) => page.check_runs || [])
297
- const requested = new Set(request.names || [])
298
- return {
299
- checks: checks.filter((check) => requested.has(check.name)).map((check) => ({
300
- name: check.name,
301
- provider: 'github',
302
- repository: request.repository,
303
- pr: request.pr,
304
- headSha: request.headSha,
305
- conclusion: check.conclusion,
306
- })),
307
- }
308
- }
309
-
310
-
311
- export function handleProviderRequest(request, boundary = DEFAULT_BOUNDARY) {
312
- const verdict = validateProviderRequest(request)
313
- if (!verdict.ok) throw new Error(`invalid GitHub provider request: ${verdict.errors.join('; ')}`)
314
- return PROVIDER_HANDLERS[request.operation](request, boundary)
315
- }
316
-
317
- function main() {
318
- if (process.argv.includes('--help') || process.argv.includes('-h')) {
319
- console.log('usage: exact-head-github-provider.mjs # reads one exact-head provider operation as JSON on stdin')
320
- return 0
321
- }
322
- try {
323
- const request = JSON.parse(fs.readFileSync(0, 'utf8'))
324
- process.stdout.write(`${JSON.stringify(handleProviderRequest(request))}\n`)
325
- return 0
326
- } catch (error) {
327
- console.error(`exact-head-github-provider: ${String(error.message || error)}`)
328
- return 1
329
- }
330
- }
331
-
332
- if (isMainModule(import.meta.url)) process.exit(main())