@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,522 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import crypto from 'node:crypto'
|
|
4
|
-
import fs from 'node:fs'
|
|
5
|
-
import path from 'node:path'
|
|
6
|
-
import { CheckedAdapterError, loadCheckedAdapter } from './checked-adapter-loader.mjs'
|
|
7
|
-
import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
|
|
8
|
-
|
|
9
|
-
export const ADAPTER_EXPORT = 'DURABLE_PROCESSING_ADAPTER'
|
|
10
|
-
export const ADAPTER_SCHEMA_VERSION = 1
|
|
11
|
-
export const RECEIPT_SCHEMA = 'resolve-release/durable-processing-receipt@1'
|
|
12
|
-
export const PAUSE_ORDER = Object.freeze(['database-admission', 'worker-scheduling'])
|
|
13
|
-
export const RESUME_ORDER = Object.freeze([...PAUSE_ORDER].reverse())
|
|
14
|
-
|
|
15
|
-
const CLI_WRITER = Object.freeze({ id: 'resolve-release/durable-processing' })
|
|
16
|
-
|
|
17
|
-
const USAGE = `durable-processing.mjs - drive a repository-declared durable-processing adapter
|
|
18
|
-
|
|
19
|
-
Usage:
|
|
20
|
-
durable-processing.mjs preflight --declaration <release.json>
|
|
21
|
-
durable-processing.mjs status --declaration <release.json> [options]
|
|
22
|
-
durable-processing.mjs pause --declaration <release.json> [options]
|
|
23
|
-
durable-processing.mjs quiescence --declaration <release.json> [options]
|
|
24
|
-
durable-processing.mjs resume --declaration <release.json> [options]
|
|
25
|
-
durable-processing.mjs down --declaration <release.json> [options]
|
|
26
|
-
durable-processing.mjs up --declaration <release.json> [options]
|
|
27
|
-
durable-processing.mjs unwind-pre-shift --declaration <release.json> [options]
|
|
28
|
-
|
|
29
|
-
The declaration must decide durableProcessing.present as true or false. A true
|
|
30
|
-
declaration names an ES module exporting DURABLE_PROCESSING_ADAPTER. The adapter
|
|
31
|
-
contains typed data and an execute(request) function; declarations contain no shell
|
|
32
|
-
commands, credentials, timestamps, or platform-specific snippets. The adapter is a
|
|
33
|
-
dependency-free strict-UTF-8 .mjs file no larger than 256 KiB. Execution receives
|
|
34
|
-
only the declared config and isolated snapshot-backed readTextFile/writeTextFile operations;
|
|
35
|
-
validated final write intents commit in the host only after receipt validation. The host stages
|
|
36
|
-
same-directory final and original files, validates every target identity immediately before the
|
|
37
|
-
first deterministic replacement, and restores replaced targets in reverse if a later operation
|
|
38
|
-
fails. Rollback failure is reported as ambiguous with affected targets. This recoverable
|
|
39
|
-
transaction cannot provide cross-file kernel atomicity or guaranteed recovery from process crash
|
|
40
|
-
or power loss during the replacement window.`
|
|
41
|
-
|
|
42
|
-
const isObject = (value) => value != null && typeof value === 'object' && !Array.isArray(value)
|
|
43
|
-
const nonEmptyString = (value) => typeof value === 'string' && value.trim() !== ''
|
|
44
|
-
const safeGeneration = (value) => Number.isSafeInteger(value) && value >= 0
|
|
45
|
-
const isoTimestamp = (value) => nonEmptyString(value) && Number.isFinite(Date.parse(value))
|
|
46
|
-
const exactArray = (actual, expected) => Array.isArray(actual)
|
|
47
|
-
&& actual.length === expected.length
|
|
48
|
-
&& actual.every((value, index) => value === expected[index])
|
|
49
|
-
|
|
50
|
-
function written(state, fields = {}) {
|
|
51
|
-
return {
|
|
52
|
-
schema: RECEIPT_SCHEMA,
|
|
53
|
-
state,
|
|
54
|
-
...fields,
|
|
55
|
-
writer: CLI_WRITER,
|
|
56
|
-
writtenAt: new Date().toISOString(),
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function refused(...failed) {
|
|
61
|
-
return written('refused', { failed: [...new Set(failed)] })
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function readJson(file, failedId) {
|
|
65
|
-
try {
|
|
66
|
-
const value = JSON.parse(fs.readFileSync(file, 'utf8'))
|
|
67
|
-
return { value }
|
|
68
|
-
} catch (error) {
|
|
69
|
-
return { error: refused(failedId), cause: error }
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function validateAdapter(adapter) {
|
|
74
|
-
const failed = []
|
|
75
|
-
if (!isObject(adapter) || adapter.schemaVersion !== ADAPTER_SCHEMA_VERSION) {
|
|
76
|
-
failed.push('e:invalid-adapter-schema-version')
|
|
77
|
-
}
|
|
78
|
-
if (!nonEmptyString(adapter?.writerId)) failed.push('e:invalid-writer-id')
|
|
79
|
-
if (!exactArray(adapter?.pauseOrder, PAUSE_ORDER)) failed.push('e:invalid-pause-order')
|
|
80
|
-
if (!exactArray(adapter?.resumeOrder, RESUME_ORDER)) failed.push('e:resume-not-exact-reverse')
|
|
81
|
-
const quiescence = adapter?.quiescence
|
|
82
|
-
if (
|
|
83
|
-
!isObject(quiescence)
|
|
84
|
-
|| !nonEmptyString(quiescence.component)
|
|
85
|
-
|| !nonEmptyString(quiescence.blockerField)
|
|
86
|
-
|| typeof quiescence.readyValue !== 'number'
|
|
87
|
-
|| !Number.isSafeInteger(quiescence.timeoutMs)
|
|
88
|
-
|| quiescence.timeoutMs <= 0
|
|
89
|
-
) failed.push('e:invalid-quiescence')
|
|
90
|
-
if (adapter?.evidenceSchema !== RECEIPT_SCHEMA) failed.push('e:invalid-evidence-schema')
|
|
91
|
-
if (typeof adapter?.execute !== 'function') failed.push('e:adapter-not-executable')
|
|
92
|
-
return failed
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export async function loadDeclaration(file, { onFilesystemBoundary } = {}) {
|
|
96
|
-
const read = readJson(file, 'e:declaration-unreadable')
|
|
97
|
-
if (read.error) return read
|
|
98
|
-
const declaration = read.value
|
|
99
|
-
if (!isObject(declaration) || declaration.schemaVersion !== 1) {
|
|
100
|
-
return { error: refused('e:invalid-declaration-schema') }
|
|
101
|
-
}
|
|
102
|
-
if (!nonEmptyString(declaration.repositoryRoot)) {
|
|
103
|
-
return { error: refused('e:repository-root-undeclared') }
|
|
104
|
-
}
|
|
105
|
-
const durable = declaration.durableProcessing
|
|
106
|
-
if (!isObject(durable) || typeof durable.present !== 'boolean') {
|
|
107
|
-
return { error: refused('e:durable-processing-undecided') }
|
|
108
|
-
}
|
|
109
|
-
if (durable.config != null && !isObject(durable.config)) {
|
|
110
|
-
return { error: refused('e:adapter-config-invalid') }
|
|
111
|
-
}
|
|
112
|
-
if (durable.present === false) return { declaration, durable }
|
|
113
|
-
if (!nonEmptyString(durable.adapter)) return { error: refused('e:adapter-undeclared') }
|
|
114
|
-
|
|
115
|
-
const declarationDir = path.dirname(path.resolve(file))
|
|
116
|
-
const repositoryRoot = path.isAbsolute(declaration.repositoryRoot)
|
|
117
|
-
? path.resolve(declaration.repositoryRoot)
|
|
118
|
-
: path.resolve(declarationDir, declaration.repositoryRoot)
|
|
119
|
-
let loaded
|
|
120
|
-
try {
|
|
121
|
-
loaded = await loadCheckedAdapter({
|
|
122
|
-
repositoryRoot,
|
|
123
|
-
adapterPath: durable.adapter,
|
|
124
|
-
onFilesystemBoundary,
|
|
125
|
-
})
|
|
126
|
-
} catch (error) {
|
|
127
|
-
const code = error instanceof CheckedAdapterError ? error.code : 'e:adapter-unloadable'
|
|
128
|
-
return { error: refused(code) }
|
|
129
|
-
}
|
|
130
|
-
const adapter = loaded.module[ADAPTER_EXPORT]
|
|
131
|
-
const failed = validateAdapter(adapter)
|
|
132
|
-
if (failed.length) return { error: refused(...failed) }
|
|
133
|
-
return { declaration, durable, adapter, adapterPath: loaded.canonicalPath }
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export async function preflight(file) {
|
|
137
|
-
const loaded = await loadDeclaration(file)
|
|
138
|
-
if (loaded.error) return loaded.error
|
|
139
|
-
if (loaded.durable.present === false) return written('ready', { present: false })
|
|
140
|
-
const { adapter, adapterPath } = loaded
|
|
141
|
-
return written('ready', {
|
|
142
|
-
present: true,
|
|
143
|
-
adapter: adapterPath,
|
|
144
|
-
adapterSchemaVersion: adapter.schemaVersion,
|
|
145
|
-
pauseOrder: [...adapter.pauseOrder],
|
|
146
|
-
resumeOrder: [...adapter.resumeOrder],
|
|
147
|
-
quiescence: { ...adapter.quiescence },
|
|
148
|
-
evidenceSchema: adapter.evidenceSchema,
|
|
149
|
-
adapterWriter: { id: adapter.writerId },
|
|
150
|
-
})
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export function normalizePlatformOutput(output) {
|
|
154
|
-
if (!isObject(output)) return { error: 'e:platform-output-malformed' }
|
|
155
|
-
const hasPayload = Object.hasOwn(output, 'payload')
|
|
156
|
-
const hasText = Object.hasOwn(output, 'text')
|
|
157
|
-
if (hasPayload === hasText) return { error: 'e:platform-output-ambiguous' }
|
|
158
|
-
if (hasPayload) {
|
|
159
|
-
if (!isObject(output.payload)) return { error: 'e:platform-output-malformed' }
|
|
160
|
-
return { receipt: output.payload }
|
|
161
|
-
}
|
|
162
|
-
if (!nonEmptyString(output.text)) return { error: 'e:platform-output-malformed' }
|
|
163
|
-
try {
|
|
164
|
-
const receipt = JSON.parse(output.text)
|
|
165
|
-
return isObject(receipt) ? { receipt } : { error: 'e:platform-output-malformed' }
|
|
166
|
-
} catch {
|
|
167
|
-
return { error: 'e:platform-output-malformed' }
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function validateReceipt(receipt, request, writerId) {
|
|
172
|
-
const required = [
|
|
173
|
-
'schema', 'state', 'operation', 'component', 'requestId', 'writer', 'writtenAt',
|
|
174
|
-
'generation', 'fence', 'observed',
|
|
175
|
-
]
|
|
176
|
-
if (!isObject(receipt) || required.some((field) => receipt[field] == null)) {
|
|
177
|
-
return ['e:receipt-partial']
|
|
178
|
-
}
|
|
179
|
-
const failed = []
|
|
180
|
-
if (receipt.schema !== RECEIPT_SCHEMA) failed.push('e:receipt-schema-mismatch')
|
|
181
|
-
if (!['observed', 'applied', 'refused'].includes(receipt.state)) failed.push('e:receipt-state-invalid')
|
|
182
|
-
if (receipt.operation !== request.operation) failed.push('e:receipt-operation-mismatch')
|
|
183
|
-
if (receipt.component !== request.component) failed.push('e:receipt-component-mismatch')
|
|
184
|
-
if (receipt.requestId !== request.requestId) failed.push('e:receipt-request-mismatch')
|
|
185
|
-
if (!isObject(receipt.writer) || receipt.writer.id !== writerId) failed.push('e:receipt-writer-mismatch')
|
|
186
|
-
if (!isoTimestamp(receipt.writtenAt)) failed.push('e:receipt-timestamp-invalid')
|
|
187
|
-
if (!safeGeneration(receipt.generation)) failed.push('e:receipt-generation-invalid')
|
|
188
|
-
if (!nonEmptyString(receipt.fence)) failed.push('e:receipt-fence-invalid')
|
|
189
|
-
if (!isObject(receipt.observed)) failed.push('e:receipt-observation-invalid')
|
|
190
|
-
if (receipt.state === 'refused' && (
|
|
191
|
-
!Array.isArray(receipt.failed) || receipt.failed.length === 0 || receipt.failed.some((id) => !nonEmptyString(id))
|
|
192
|
-
)) failed.push('e:receipt-partial')
|
|
193
|
-
if (receipt.state !== 'refused') {
|
|
194
|
-
if (['pause', 'resume'].includes(request.operation) && receipt.state !== 'applied') {
|
|
195
|
-
failed.push('e:receipt-effect-unproven')
|
|
196
|
-
}
|
|
197
|
-
if (request.operation === 'pause' && receipt.observed?.paused !== true) failed.push('e:receipt-effect-unproven')
|
|
198
|
-
if (request.operation === 'resume' && receipt.observed?.resumed !== true) failed.push('e:receipt-effect-unproven')
|
|
199
|
-
if (['status', 'quiescence'].includes(request.operation) && receipt.state !== 'observed') {
|
|
200
|
-
failed.push('e:receipt-observation-unproven')
|
|
201
|
-
}
|
|
202
|
-
if (request.operation === 'quiescence'
|
|
203
|
-
&& (!Number.isSafeInteger(receipt.observed?.blockers) || receipt.observed.blockers < 0)) {
|
|
204
|
-
failed.push('e:receipt-observation-incomplete')
|
|
205
|
-
}
|
|
206
|
-
if (request.operation === 'status' && (
|
|
207
|
-
typeof receipt.observed?.admissionPaused !== 'boolean'
|
|
208
|
-
|| typeof receipt.observed?.schedulingPaused !== 'boolean'
|
|
209
|
-
|| !Number.isSafeInteger(receipt.observed?.blockers)
|
|
210
|
-
|| receipt.observed.blockers < 0
|
|
211
|
-
|| !isObject(receipt.observed?.traffic)
|
|
212
|
-
)) failed.push('e:receipt-observation-incomplete')
|
|
213
|
-
}
|
|
214
|
-
return failed
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export async function executeOperation(file, operation, options) {
|
|
218
|
-
const loaded = await loadDeclaration(file)
|
|
219
|
-
if (loaded.error) return loaded.error
|
|
220
|
-
if (loaded.durable.present === false) return refused('e:durable-processing-not-present')
|
|
221
|
-
const request = Object.freeze({
|
|
222
|
-
schemaVersion: 1,
|
|
223
|
-
operation,
|
|
224
|
-
component: options.component,
|
|
225
|
-
requestId: options.requestId ?? crypto.randomUUID(),
|
|
226
|
-
expectedGeneration: options.generation,
|
|
227
|
-
expectedFence: options.fence,
|
|
228
|
-
servingRevision: options.servingRevision,
|
|
229
|
-
})
|
|
230
|
-
if (!nonEmptyString(request.component) || !nonEmptyString(request.requestId)) {
|
|
231
|
-
return refused('e:request-invalid')
|
|
232
|
-
}
|
|
233
|
-
let isolated
|
|
234
|
-
try {
|
|
235
|
-
isolated = await loaded.adapter.execute(
|
|
236
|
-
request,
|
|
237
|
-
Object.freeze({ ...(loaded.durable.config ?? {}) }),
|
|
238
|
-
)
|
|
239
|
-
} catch (error) {
|
|
240
|
-
const code = typeof error?.code === 'string' && error.code.startsWith('e:adapter-')
|
|
241
|
-
? error.code
|
|
242
|
-
: 'e:adapter-execution-failed'
|
|
243
|
-
return refused(code)
|
|
244
|
-
}
|
|
245
|
-
if (!isObject(isolated) || !Object.hasOwn(isolated, 'output')
|
|
246
|
-
|| typeof isolated.commit !== 'function') {
|
|
247
|
-
return refused('e:adapter-execution-failed')
|
|
248
|
-
}
|
|
249
|
-
const normalized = normalizePlatformOutput(isolated.output)
|
|
250
|
-
if (normalized.error) return refused(normalized.error)
|
|
251
|
-
const failed = validateReceipt(normalized.receipt, request, loaded.adapter.writerId)
|
|
252
|
-
if (failed.length) return refused(...failed)
|
|
253
|
-
try {
|
|
254
|
-
isolated.commit()
|
|
255
|
-
} catch (error) {
|
|
256
|
-
const code = typeof error?.code === 'string' && error.code.startsWith('e:adapter-')
|
|
257
|
-
? error.code
|
|
258
|
-
: 'e:adapter-file-changed'
|
|
259
|
-
if (error?.ambiguousEffects === true || error?.committedEffects === true) {
|
|
260
|
-
return written('refused', {
|
|
261
|
-
failed: [code],
|
|
262
|
-
effects: error.ambiguousEffects === true ? 'ambiguous' : 'committed',
|
|
263
|
-
affectedTargets: Array.isArray(error.affectedTargets) ? [...error.affectedTargets] : [],
|
|
264
|
-
})
|
|
265
|
-
}
|
|
266
|
-
return refused(code)
|
|
267
|
-
}
|
|
268
|
-
return normalized.receipt
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function sequenceReceipt(state, fields) {
|
|
272
|
-
return written(state, fields)
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function isSuccess(receipt) {
|
|
276
|
-
return receipt.state === 'observed' || receipt.state === 'applied'
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
function identityFrom(receipt) {
|
|
280
|
-
return { generation: receipt.generation, fence: receipt.fence }
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
async function status(file) {
|
|
284
|
-
return executeOperation(file, 'status', { component: 'durable-state' })
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
export async function down(file, options) {
|
|
288
|
-
const release = readJson(options.releaseState, 'e:release-state-unreadable')
|
|
289
|
-
if (release.error) return release.error
|
|
290
|
-
if (release.value?.skill !== 'resolve-release' || release.value?.step !== 'expose') {
|
|
291
|
-
return refused('e:expose-step-not-recorded')
|
|
292
|
-
}
|
|
293
|
-
const initial = await status(file)
|
|
294
|
-
if (!isSuccess(initial)) return initial
|
|
295
|
-
const receipts = []
|
|
296
|
-
let identity = identityFrom(initial)
|
|
297
|
-
for (const component of PAUSE_ORDER) {
|
|
298
|
-
const receipt = await executeOperation(file, 'pause', { component, ...identity })
|
|
299
|
-
receipts.push(receipt)
|
|
300
|
-
if (!isSuccess(receipt)) return sequenceReceipt('blocked', {
|
|
301
|
-
failed: receipt.failed,
|
|
302
|
-
pausedAt: receipts.find((item) => isSuccess(item))?.writtenAt,
|
|
303
|
-
pauseOrder: [...PAUSE_ORDER],
|
|
304
|
-
receipts,
|
|
305
|
-
proof: receipt,
|
|
306
|
-
})
|
|
307
|
-
identity = identityFrom(receipt)
|
|
308
|
-
}
|
|
309
|
-
const loaded = await loadDeclaration(file)
|
|
310
|
-
if (loaded.error) return loaded.error
|
|
311
|
-
const deadline = Date.now() + loaded.adapter.quiescence.timeoutMs
|
|
312
|
-
let proof
|
|
313
|
-
do {
|
|
314
|
-
proof = await executeOperation(file, 'quiescence', {
|
|
315
|
-
component: 'durable-state',
|
|
316
|
-
...identity,
|
|
317
|
-
})
|
|
318
|
-
receipts.push(proof)
|
|
319
|
-
if (!isSuccess(proof)) return sequenceReceipt('blocked', {
|
|
320
|
-
failed: proof.failed,
|
|
321
|
-
pausedAt: receipts[0]?.writtenAt,
|
|
322
|
-
pauseOrder: [...PAUSE_ORDER],
|
|
323
|
-
receipts,
|
|
324
|
-
})
|
|
325
|
-
if (proof.observed.blockers === 0) break
|
|
326
|
-
if (Date.now() < deadline) await new Promise((resolve) => setTimeout(resolve, 25))
|
|
327
|
-
} while (Date.now() < deadline)
|
|
328
|
-
if (proof.observed.blockers !== 0) {
|
|
329
|
-
return sequenceReceipt('blocked', {
|
|
330
|
-
failed: ['e:quiescence-timeout'],
|
|
331
|
-
pausedAt: receipts[0]?.writtenAt,
|
|
332
|
-
pauseOrder: [...PAUSE_ORDER],
|
|
333
|
-
receipts,
|
|
334
|
-
proof,
|
|
335
|
-
})
|
|
336
|
-
}
|
|
337
|
-
return sequenceReceipt('ready-to-shift', {
|
|
338
|
-
pausedAt: receipts[0]?.writtenAt,
|
|
339
|
-
pauseOrder: [...PAUSE_ORDER],
|
|
340
|
-
receipts,
|
|
341
|
-
proof,
|
|
342
|
-
shiftFence: identityFrom(proof),
|
|
343
|
-
})
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
function trafficMatches(traffic, expected) {
|
|
347
|
-
return isObject(traffic)
|
|
348
|
-
&& traffic.incumbentRevision === expected.incumbentRevision
|
|
349
|
-
&& traffic.incumbentPercent === expected.incumbentPercent
|
|
350
|
-
&& traffic.candidateRevision === expected.candidateRevision
|
|
351
|
-
&& traffic.candidatePercent === expected.candidatePercent
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
async function resumeSequence(file, options, initialStatus) {
|
|
355
|
-
const receipts = [initialStatus]
|
|
356
|
-
let identity = identityFrom(initialStatus)
|
|
357
|
-
if (
|
|
358
|
-
!safeGeneration(options.generation)
|
|
359
|
-
|| !nonEmptyString(options.fence)
|
|
360
|
-
|| options.generation !== identity.generation
|
|
361
|
-
|| options.fence !== identity.fence
|
|
362
|
-
) {
|
|
363
|
-
return sequenceReceipt('ambiguous', {
|
|
364
|
-
failed: ['e:serving-generation-mismatch'],
|
|
365
|
-
receipts,
|
|
366
|
-
})
|
|
367
|
-
}
|
|
368
|
-
for (const component of RESUME_ORDER) {
|
|
369
|
-
const receipt = await executeOperation(file, 'resume', {
|
|
370
|
-
component,
|
|
371
|
-
...identity,
|
|
372
|
-
servingRevision: options.servingRevision,
|
|
373
|
-
})
|
|
374
|
-
receipts.push(receipt)
|
|
375
|
-
if (!isSuccess(receipt)) {
|
|
376
|
-
return sequenceReceipt('ambiguous', { failed: receipt.failed, receipts })
|
|
377
|
-
}
|
|
378
|
-
identity = identityFrom(receipt)
|
|
379
|
-
}
|
|
380
|
-
const confirmation = await status(file)
|
|
381
|
-
receipts.push(confirmation)
|
|
382
|
-
if (
|
|
383
|
-
!isSuccess(confirmation)
|
|
384
|
-
|| confirmation.observed.schedulingPaused !== false
|
|
385
|
-
|| confirmation.observed.admissionPaused !== false
|
|
386
|
-
) {
|
|
387
|
-
return sequenceReceipt('ambiguous', {
|
|
388
|
-
failed: ['e:processing-restoration-ambiguous'],
|
|
389
|
-
receipts,
|
|
390
|
-
})
|
|
391
|
-
}
|
|
392
|
-
return sequenceReceipt('restored', {
|
|
393
|
-
resumedAt: receipts.find((receipt) => receipt.operation === 'resume')?.writtenAt,
|
|
394
|
-
resumeOrder: [...RESUME_ORDER],
|
|
395
|
-
receipts,
|
|
396
|
-
servingRevisionAtResume: options.servingRevision,
|
|
397
|
-
restorationFence: identityFrom(confirmation),
|
|
398
|
-
})
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
export async function up(file, options) {
|
|
402
|
-
const observed = await status(file)
|
|
403
|
-
if (!isSuccess(observed)) return observed
|
|
404
|
-
const traffic = observed.observed.traffic
|
|
405
|
-
const identitiesDeclared = nonEmptyString(options.incumbentRevision)
|
|
406
|
-
&& nonEmptyString(options.candidateRevision)
|
|
407
|
-
&& options.incumbentRevision !== options.candidateRevision
|
|
408
|
-
const namedCandidateServes = options.servingRevision === options.candidateRevision
|
|
409
|
-
&& trafficMatches(traffic, {
|
|
410
|
-
incumbentRevision: options.incumbentRevision,
|
|
411
|
-
incumbentPercent: 0,
|
|
412
|
-
candidateRevision: options.candidateRevision,
|
|
413
|
-
candidatePercent: 100,
|
|
414
|
-
})
|
|
415
|
-
const namedIncumbentServes = options.servingRevision === options.incumbentRevision
|
|
416
|
-
&& trafficMatches(traffic, {
|
|
417
|
-
incumbentRevision: options.incumbentRevision,
|
|
418
|
-
incumbentPercent: 100,
|
|
419
|
-
candidateRevision: options.candidateRevision,
|
|
420
|
-
candidatePercent: 0,
|
|
421
|
-
})
|
|
422
|
-
if (!identitiesDeclared || (!namedCandidateServes && !namedIncumbentServes)) {
|
|
423
|
-
return sequenceReceipt('ambiguous', {
|
|
424
|
-
failed: ['e:serving-revision-unproven'],
|
|
425
|
-
trafficProof: traffic,
|
|
426
|
-
receipts: [observed],
|
|
427
|
-
})
|
|
428
|
-
}
|
|
429
|
-
const resumed = await resumeSequence(file, options, observed)
|
|
430
|
-
return resumed.state === 'restored'
|
|
431
|
-
? {
|
|
432
|
-
...resumed,
|
|
433
|
-
trafficProof: traffic,
|
|
434
|
-
incumbentRevision: options.incumbentRevision,
|
|
435
|
-
candidateRevision: options.candidateRevision,
|
|
436
|
-
}
|
|
437
|
-
: resumed
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
export async function unwindPreShift(file, options) {
|
|
441
|
-
const observed = await status(file)
|
|
442
|
-
if (!isSuccess(observed)) return observed
|
|
443
|
-
const trafficProof = observed.observed.traffic
|
|
444
|
-
const expected = {
|
|
445
|
-
incumbentRevision: options.incumbentRevision,
|
|
446
|
-
incumbentPercent: 100,
|
|
447
|
-
candidateRevision: options.candidateRevision,
|
|
448
|
-
candidatePercent: 0,
|
|
449
|
-
}
|
|
450
|
-
if (!trafficMatches(trafficProof, expected)) {
|
|
451
|
-
return sequenceReceipt('ambiguous', {
|
|
452
|
-
failed: ['e:traffic-split-ambiguous'],
|
|
453
|
-
trafficProof,
|
|
454
|
-
receipts: [observed],
|
|
455
|
-
})
|
|
456
|
-
}
|
|
457
|
-
const resumed = await resumeSequence(file, {
|
|
458
|
-
...options,
|
|
459
|
-
servingRevision: options.incumbentRevision,
|
|
460
|
-
}, observed)
|
|
461
|
-
if (resumed.state !== 'restored') return resumed
|
|
462
|
-
return { ...resumed, state: 'unwound', trafficProof }
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
function parseArgs(argv) {
|
|
466
|
-
const positional = []
|
|
467
|
-
const options = {}
|
|
468
|
-
const unknown = []
|
|
469
|
-
for (let index = 0; index < argv.length; index++) {
|
|
470
|
-
const value = argv[index]
|
|
471
|
-
if (value === '--help' || value === '-h') options.help = true
|
|
472
|
-
else if (value === '--declaration') options.declaration = argv[++index]
|
|
473
|
-
else if (value === '--component') options.component = argv[++index]
|
|
474
|
-
else if (value === '--generation') options.generation = Number(argv[++index])
|
|
475
|
-
else if (value === '--fence') options.fence = argv[++index]
|
|
476
|
-
else if (value === '--serving-revision') options.servingRevision = argv[++index]
|
|
477
|
-
else if (value === '--request-id') options.requestId = argv[++index]
|
|
478
|
-
else if (value === '--release-state') options.releaseState = argv[++index]
|
|
479
|
-
else if (value === '--incumbent-revision') options.incumbentRevision = argv[++index]
|
|
480
|
-
else if (value === '--candidate-revision') options.candidateRevision = argv[++index]
|
|
481
|
-
else if (value.startsWith('--')) unknown.push(value)
|
|
482
|
-
else positional.push(value)
|
|
483
|
-
}
|
|
484
|
-
return { positional, options, unknown }
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
export async function main(argv) {
|
|
488
|
-
const { positional, options, unknown } = parseArgs(argv)
|
|
489
|
-
if (options.help || positional[0] === 'help') {
|
|
490
|
-
console.log(USAGE)
|
|
491
|
-
return 0
|
|
492
|
-
}
|
|
493
|
-
if (unknown.length) {
|
|
494
|
-
console.log(JSON.stringify(refused('e:unknown-option')))
|
|
495
|
-
return 2
|
|
496
|
-
}
|
|
497
|
-
if (!nonEmptyString(options.declaration)) {
|
|
498
|
-
console.log(JSON.stringify(refused('e:declaration-required')))
|
|
499
|
-
return 2
|
|
500
|
-
}
|
|
501
|
-
const command = positional[0]
|
|
502
|
-
const operations = ['status', 'pause', 'quiescence', 'resume']
|
|
503
|
-
const sequences = ['down', 'up', 'unwind-pre-shift']
|
|
504
|
-
if (command !== 'preflight' && !operations.includes(command) && !sequences.includes(command)) {
|
|
505
|
-
console.log(JSON.stringify(refused('e:unknown-command')))
|
|
506
|
-
return 2
|
|
507
|
-
}
|
|
508
|
-
let receipt
|
|
509
|
-
if (command === 'preflight') receipt = await preflight(options.declaration)
|
|
510
|
-
else if (operations.includes(command)) receipt = await executeOperation(options.declaration, command, options)
|
|
511
|
-
else if (command === 'down') receipt = await down(options.declaration, options)
|
|
512
|
-
else if (command === 'up') receipt = await up(options.declaration, options)
|
|
513
|
-
else receipt = await unwindPreShift(options.declaration, options)
|
|
514
|
-
console.log(JSON.stringify(receipt))
|
|
515
|
-
return ['ready', 'observed', 'applied', 'ready-to-shift', 'restored', 'unwound'].includes(receipt.state)
|
|
516
|
-
? 0
|
|
517
|
-
: 1
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
if (isMainModule(import.meta.url)) {
|
|
521
|
-
main(process.argv.slice(2)).then((code) => { process.exitCode = code })
|
|
522
|
-
}
|