@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.
- package/README.md +9 -4
- package/package.json +1 -1
- package/runtime/skills/distribution/generated/recipes.json +54 -48
- package/runtime/skills/distribution/scripts/bundles.mjs +113 -7
- package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
- package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
- package/skills/cicd-pipeline/mergify/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +14 -83
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
- package/skills/engineering/smoke/SKILL.md +1 -1
- package/skills/payment/payment-analysis/SKILL.md +13 -7
- package/skills/payment/payment-analysis/references/chargebacks.md +43 -18
- package/skills/payment/payment-analysis/references/event-layers.md +4 -0
- package/skills/payment/payment-analysis/references/metrics.md +9 -7
- package/skills/payment/payment-analysis/references/report-template.md +3 -3
- package/skills/payment/payment-analysis/references/terminology.md +6 -1
- package/skills/payment/payment-analysis/references/visualization.md +1 -1
- package/skills/payment/tld-detection/SKILL.md +163 -0
- package/skills/payment/tld-detection/agents/openai.yaml +9 -0
- package/skills/payment/tld-detection/evals/evals.json +107 -0
- package/skills/payment/tld-detection/references/clean.md +51 -0
- package/skills/payment/tld-detection/references/clustering.md +219 -0
- package/skills/payment/tld-detection/references/decision.md +85 -0
- package/skills/payment/tld-detection/references/report-template.md +169 -0
- package/skills/payment/tld-detection/references/terminology.md +69 -0
- package/skills/payment/tld-detection/references/workflow.md +78 -0
- package/skills/payment/tld-detection/scripts/detect_ladders.py +390 -0
- package/skills/payment/tld-detection/tests/test_detect_ladders.py +132 -0
- package/skills/engineering/resolve-issues/SKILL.md +0 -168
- package/skills/engineering/resolve-issues/agents/openai.yaml +0 -9
- package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +0 -499
- package/skills/engineering/resolve-issues/references/breaker.md +0 -82
- package/skills/engineering/resolve-issues/references/deliverables.md +0 -27
- package/skills/engineering/resolve-issues/references/delivery.md +0 -108
- package/skills/engineering/resolve-issues/references/evidence-lane.md +0 -21
- package/skills/engineering/resolve-issues/references/exact-head-ci.md +0 -287
- package/skills/engineering/resolve-issues/references/fan-out.md +0 -33
- package/skills/engineering/resolve-issues/references/finalization.md +0 -68
- package/skills/engineering/resolve-issues/references/guarantees.md +0 -10
- package/skills/engineering/resolve-issues/references/high-risk.md +0 -29
- package/skills/engineering/resolve-issues/references/incidents/848/README.md +0 -156
- package/skills/engineering/resolve-issues/references/intake.md +0 -86
- package/skills/engineering/resolve-issues/references/integration-gate.md +0 -53
- package/skills/engineering/resolve-issues/references/interference.md +0 -87
- package/skills/engineering/resolve-issues/references/loop.md +0 -134
- package/skills/engineering/resolve-issues/references/model-catalog.md +0 -9
- package/skills/engineering/resolve-issues/references/postmortem.md +0 -27
- package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +0 -41
- package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +0 -48
- package/skills/engineering/resolve-issues/references/pre-flight.md +0 -41
- package/skills/engineering/resolve-issues/references/regression-checklist.md +0 -26
- package/skills/engineering/resolve-issues/references/run-state.md +0 -288
- package/skills/engineering/resolve-issues/references/sandboxed-testing.md +0 -48
- package/skills/engineering/resolve-issues/references/spawn-contract.md +0 -96
- package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +0 -40
- package/skills/engineering/resolve-issues/references/why.md +0 -653
- package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +0 -49
- package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +0 -721
- package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +0 -962
- package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +0 -220
- package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +0 -420
- package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +0 -256
- package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +0 -168
- package/skills/engineering/resolve-issues/scripts/discover-models.mjs +0 -9
- package/skills/engineering/resolve-issues/scripts/doctrine.mjs +0 -62
- package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +0 -191
- package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +0 -413
- package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +0 -332
- package/skills/engineering/resolve-issues/scripts/finalize.mjs +0 -488
- package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +0 -3307
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +0 -16
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +0 -51
- package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +0 -17
- package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +0 -166
- package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +0 -92
- package/skills/engineering/resolve-issues/scripts/guide-index.mjs +0 -73
- package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +0 -159
- package/skills/engineering/resolve-issues/scripts/interference.mjs +0 -427
- package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +0 -9
- package/skills/engineering/resolve-issues/scripts/next-operations.mjs +0 -419
- package/skills/engineering/resolve-issues/scripts/postmortem.mjs +0 -909
- package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +0 -345
- package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +0 -415
- package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +0 -697
- package/skills/engineering/resolve-issues/scripts/report.mjs +0 -494
- package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +0 -172
- package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +0 -79
- package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +0 -334
- package/skills/engineering/resolve-issues/scripts/run-state.mjs +0 -4792
- package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +0 -395
- package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +0 -290
- package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +0 -170
- package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +0 -293
- package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +0 -197
- package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +0 -127
- package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +0 -893
- package/skills/engineering/resolve-issues/scripts/workspaces.mjs +0 -829
- package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +0 -290
- package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +0 -80
- package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +0 -102
- package/skills/engineering/resolve-release/LICENSE +0 -3
- package/skills/engineering/resolve-release/SKILL.md +0 -113
- package/skills/engineering/resolve-release/agents/openai.yaml +0 -9
- package/skills/engineering/resolve-release/references/assembly.md +0 -137
- package/skills/engineering/resolve-release/references/auto-when-green.md +0 -56
- package/skills/engineering/resolve-release/references/candidate.md +0 -167
- package/skills/engineering/resolve-release/references/exposure.md +0 -178
- package/skills/engineering/resolve-release/references/handoff.md +0 -24
- package/skills/engineering/resolve-release/references/postmortem.md +0 -230
- package/skills/engineering/resolve-release/references/preflight.md +0 -208
- package/skills/engineering/resolve-release/references/principles.md +0 -94
- package/skills/engineering/resolve-release/references/regression-checklist.md +0 -36
- package/skills/engineering/resolve-release/references/related-skills.md +0 -13
- package/skills/engineering/resolve-release/references/routing.md +0 -149
- package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +0 -285
- package/skills/engineering/resolve-release/references/versioning.md +0 -202
- package/skills/engineering/resolve-release/references/why.md +0 -53
- package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +0 -389
- package/skills/engineering/resolve-release/scripts/build-changes.mjs +0 -209
- package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +0 -407
- package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +0 -904
- package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +0 -81
- package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +0 -612
- package/skills/engineering/resolve-release/scripts/close-attempt.mjs +0 -135
- package/skills/engineering/resolve-release/scripts/closeout-release.mjs +0 -161
- package/skills/engineering/resolve-release/scripts/doctrine.mjs +0 -106
- package/skills/engineering/resolve-release/scripts/durable-processing.mjs +0 -522
- package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +0 -659
- package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +0 -1014
- package/skills/engineering/resolve-release/scripts/finalize-release.mjs +0 -526
- package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +0 -169
- package/skills/engineering/resolve-release/scripts/green-gate.mjs +0 -599
- package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +0 -752
- package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +0 -56
- package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +0 -1538
- package/skills/engineering/resolve-release/scripts/postmortem.mjs +0 -381
- package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +0 -510
- package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +0 -326
- package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +0 -272
- package/skills/engineering/resolve-release/scripts/report.mjs +0 -417
- package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +0 -114
- package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +0 -238
- package/skills/engineering/resolve-release/scripts/review-packet.mjs +0 -503
- package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +0 -263
- package/skills/engineering/resolve-release/scripts/version-assert.mjs +0 -339
- package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +0 -485
- package/skills/engineering/resolve-release/scripts/version.mjs +0 -1199
- package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +0 -449
- package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +0 -21
- package/skills/engineering/resolve-release/vendor/README.md +0 -60
- package/skills/engineering/resolve-release/vendor/acorn.mjs +0 -6233
- package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +0 -21
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +0 -341
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +0 -70
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +0 -7
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +0 -2033
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +0 -2033
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +0 -7
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +0 -49
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +0 -21
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +0 -5
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +0 -549
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +0 -549
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +0 -36
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +0 -47
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +0 -82
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +0 -11
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +0 -22
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +0 -21
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +0 -21
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +0 -11
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +0 -11
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +0 -25
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +0 -85
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +0 -85
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +0 -20
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +0 -20
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +0 -2
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +0 -1
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +0 -61
- /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())
|