@1aboveio/skills 0.19.3 → 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 (197) 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 +5 -3
  13. package/skills/payment/tld-detection/SKILL.md +163 -0
  14. package/skills/payment/tld-detection/agents/openai.yaml +9 -0
  15. package/skills/payment/tld-detection/evals/evals.json +107 -0
  16. package/skills/payment/tld-detection/references/clean.md +51 -0
  17. package/skills/payment/tld-detection/references/clustering.md +219 -0
  18. package/skills/payment/tld-detection/references/decision.md +85 -0
  19. package/skills/payment/tld-detection/references/report-template.md +169 -0
  20. package/skills/payment/tld-detection/references/terminology.md +69 -0
  21. package/skills/payment/tld-detection/references/workflow.md +78 -0
  22. package/skills/payment/tld-detection/scripts/detect_ladders.py +390 -0
  23. package/skills/payment/tld-detection/tests/test_detect_ladders.py +132 -0
  24. package/skills/engineering/resolve-issues/SKILL.md +0 -168
  25. package/skills/engineering/resolve-issues/agents/openai.yaml +0 -9
  26. package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +0 -499
  27. package/skills/engineering/resolve-issues/references/breaker.md +0 -82
  28. package/skills/engineering/resolve-issues/references/deliverables.md +0 -27
  29. package/skills/engineering/resolve-issues/references/delivery.md +0 -108
  30. package/skills/engineering/resolve-issues/references/evidence-lane.md +0 -21
  31. package/skills/engineering/resolve-issues/references/exact-head-ci.md +0 -287
  32. package/skills/engineering/resolve-issues/references/fan-out.md +0 -33
  33. package/skills/engineering/resolve-issues/references/finalization.md +0 -68
  34. package/skills/engineering/resolve-issues/references/guarantees.md +0 -10
  35. package/skills/engineering/resolve-issues/references/high-risk.md +0 -29
  36. package/skills/engineering/resolve-issues/references/incidents/848/README.md +0 -156
  37. package/skills/engineering/resolve-issues/references/intake.md +0 -86
  38. package/skills/engineering/resolve-issues/references/integration-gate.md +0 -53
  39. package/skills/engineering/resolve-issues/references/interference.md +0 -87
  40. package/skills/engineering/resolve-issues/references/loop.md +0 -134
  41. package/skills/engineering/resolve-issues/references/model-catalog.md +0 -9
  42. package/skills/engineering/resolve-issues/references/postmortem.md +0 -27
  43. package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +0 -41
  44. package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +0 -48
  45. package/skills/engineering/resolve-issues/references/pre-flight.md +0 -41
  46. package/skills/engineering/resolve-issues/references/regression-checklist.md +0 -26
  47. package/skills/engineering/resolve-issues/references/run-state.md +0 -288
  48. package/skills/engineering/resolve-issues/references/sandboxed-testing.md +0 -48
  49. package/skills/engineering/resolve-issues/references/spawn-contract.md +0 -96
  50. package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +0 -40
  51. package/skills/engineering/resolve-issues/references/why.md +0 -653
  52. package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +0 -49
  53. package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +0 -721
  54. package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +0 -962
  55. package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +0 -220
  56. package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +0 -420
  57. package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +0 -256
  58. package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +0 -168
  59. package/skills/engineering/resolve-issues/scripts/discover-models.mjs +0 -9
  60. package/skills/engineering/resolve-issues/scripts/doctrine.mjs +0 -62
  61. package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +0 -191
  62. package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +0 -413
  63. package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +0 -332
  64. package/skills/engineering/resolve-issues/scripts/finalize.mjs +0 -488
  65. package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +0 -3307
  66. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +0 -16
  67. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +0 -51
  68. package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +0 -17
  69. package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +0 -166
  70. package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +0 -92
  71. package/skills/engineering/resolve-issues/scripts/guide-index.mjs +0 -73
  72. package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +0 -159
  73. package/skills/engineering/resolve-issues/scripts/interference.mjs +0 -427
  74. package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +0 -9
  75. package/skills/engineering/resolve-issues/scripts/next-operations.mjs +0 -419
  76. package/skills/engineering/resolve-issues/scripts/postmortem.mjs +0 -909
  77. package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +0 -345
  78. package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +0 -415
  79. package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +0 -697
  80. package/skills/engineering/resolve-issues/scripts/report.mjs +0 -494
  81. package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +0 -172
  82. package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +0 -79
  83. package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +0 -334
  84. package/skills/engineering/resolve-issues/scripts/run-state.mjs +0 -4792
  85. package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +0 -395
  86. package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +0 -290
  87. package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +0 -170
  88. package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +0 -293
  89. package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +0 -197
  90. package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +0 -127
  91. package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +0 -893
  92. package/skills/engineering/resolve-issues/scripts/workspaces.mjs +0 -829
  93. package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +0 -290
  94. package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +0 -80
  95. package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +0 -102
  96. package/skills/engineering/resolve-release/LICENSE +0 -3
  97. package/skills/engineering/resolve-release/SKILL.md +0 -113
  98. package/skills/engineering/resolve-release/agents/openai.yaml +0 -9
  99. package/skills/engineering/resolve-release/references/assembly.md +0 -137
  100. package/skills/engineering/resolve-release/references/auto-when-green.md +0 -56
  101. package/skills/engineering/resolve-release/references/candidate.md +0 -167
  102. package/skills/engineering/resolve-release/references/exposure.md +0 -178
  103. package/skills/engineering/resolve-release/references/handoff.md +0 -24
  104. package/skills/engineering/resolve-release/references/postmortem.md +0 -230
  105. package/skills/engineering/resolve-release/references/preflight.md +0 -208
  106. package/skills/engineering/resolve-release/references/principles.md +0 -94
  107. package/skills/engineering/resolve-release/references/regression-checklist.md +0 -36
  108. package/skills/engineering/resolve-release/references/related-skills.md +0 -13
  109. package/skills/engineering/resolve-release/references/routing.md +0 -149
  110. package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +0 -285
  111. package/skills/engineering/resolve-release/references/versioning.md +0 -202
  112. package/skills/engineering/resolve-release/references/why.md +0 -53
  113. package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +0 -389
  114. package/skills/engineering/resolve-release/scripts/build-changes.mjs +0 -209
  115. package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +0 -407
  116. package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +0 -904
  117. package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +0 -81
  118. package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +0 -612
  119. package/skills/engineering/resolve-release/scripts/close-attempt.mjs +0 -135
  120. package/skills/engineering/resolve-release/scripts/closeout-release.mjs +0 -161
  121. package/skills/engineering/resolve-release/scripts/doctrine.mjs +0 -106
  122. package/skills/engineering/resolve-release/scripts/durable-processing.mjs +0 -522
  123. package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +0 -659
  124. package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +0 -1014
  125. package/skills/engineering/resolve-release/scripts/finalize-release.mjs +0 -526
  126. package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +0 -169
  127. package/skills/engineering/resolve-release/scripts/green-gate.mjs +0 -599
  128. package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +0 -752
  129. package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +0 -56
  130. package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +0 -1538
  131. package/skills/engineering/resolve-release/scripts/postmortem.mjs +0 -381
  132. package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +0 -510
  133. package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +0 -326
  134. package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +0 -272
  135. package/skills/engineering/resolve-release/scripts/report.mjs +0 -417
  136. package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +0 -114
  137. package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +0 -238
  138. package/skills/engineering/resolve-release/scripts/review-packet.mjs +0 -503
  139. package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +0 -263
  140. package/skills/engineering/resolve-release/scripts/version-assert.mjs +0 -339
  141. package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +0 -485
  142. package/skills/engineering/resolve-release/scripts/version.mjs +0 -1199
  143. package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +0 -449
  144. package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +0 -21
  145. package/skills/engineering/resolve-release/vendor/README.md +0 -60
  146. package/skills/engineering/resolve-release/vendor/acorn.mjs +0 -6233
  147. package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +0 -21
  148. package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +0 -341
  149. package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +0 -70
  150. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +0 -2
  151. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +0 -1
  152. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +0 -7
  153. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +0 -1
  154. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +0 -2033
  155. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +0 -2033
  156. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +0 -7
  157. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +0 -1
  158. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +0 -2
  159. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +0 -1
  160. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +0 -2
  161. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +0 -1
  162. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +0 -2
  163. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +0 -1
  164. package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +0 -49
  165. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +0 -21
  166. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +0 -5
  167. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +0 -549
  168. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +0 -549
  169. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +0 -2
  170. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +0 -1
  171. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +0 -2
  172. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +0 -1
  173. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +0 -36
  174. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +0 -47
  175. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +0 -82
  176. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +0 -11
  177. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +0 -22
  178. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +0 -21
  179. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +0 -21
  180. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +0 -11
  181. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +0 -11
  182. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +0 -25
  183. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
  184. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +0 -85
  185. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +0 -85
  186. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +0 -2
  187. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +0 -1
  188. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +0 -2
  189. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +0 -1
  190. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +0 -20
  191. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +0 -20
  192. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +0 -2
  193. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +0 -1
  194. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +0 -2
  195. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +0 -1
  196. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +0 -61
  197. /package/skills/{engineering/resolve-issues → payment/tld-detection}/LICENSE +0 -0
@@ -1,81 +0,0 @@
1
- // Shared Cloud Run traffic capture parser for candidate discovery and hygiene.
2
-
3
- // Cloud Run omits percent for zero-traffic tagged targets. Absence remains null unless the
4
- // complete observation proves every omitted target has the only remaining share: zero.
5
- export function parseTraffic(text) {
6
- const trimmed = String(text ?? '').trim()
7
- if (trimmed.startsWith('[') || trimmed.startsWith('{')) {
8
- let parsed
9
- try {
10
- parsed = JSON.parse(trimmed)
11
- } catch {
12
- return { error: 'traffic read is not parseable as JSON' }
13
- }
14
- // Accept either a bare traffic array or a full service describe whose status.traffic is
15
- // the array — the JSON recipe pipes either shape without a second jq pass.
16
- if (parsed && !Array.isArray(parsed) && typeof parsed === 'object') {
17
- const traffic = parsed.status && parsed.status.traffic
18
- if (Array.isArray(traffic)) parsed = traffic
19
- else return { error: 'traffic JSON object has no status.traffic array' }
20
- }
21
- if (!Array.isArray(parsed)) return { error: 'traffic JSON is not an array of traffic targets' }
22
- const rows = parsed.map((r) => ({
23
- tag: str(r && r.tag),
24
- url: str(r && r.url),
25
- revision: str(r && (r.revisionName ?? r.revision)),
26
- percent: r && Object.hasOwn(r, 'percent') ? explicitPercent(r.percent) : null,
27
- }))
28
- return { rows: normalizeTrafficPercents(rows) }
29
- }
30
- const rows = trimmed
31
- .split('\n')
32
- .map((l) => l.replace(/\r$/, ''))
33
- .filter((l) => l.trim().length > 0)
34
- .map((l) => {
35
- // gcloud separates value() columns with TABs; tolerate a multi-space separator too,
36
- // which is what a human pasting a terminal capture into a file produces.
37
- const cells = l.includes('\t') ? l.split('\t') : l.split(/\s{2,}/)
38
- const [tag, url, revision, percent] = cells
39
- return { tag: str(tag), url: str(url), revision: str(revision), percent: num(percent) }
40
- })
41
- return { rows: normalizeTrafficPercents(rows) }
42
- }
43
-
44
- // A conservation proof is valid only when every explicit target is a finite percentage in
45
- // [0, 100] and those explicit targets already account for the full 100%. The remaining
46
- // omitted rows must then each be zero; any partial, overfull, negative, or invalid observation
47
- // remains ambiguous.
48
- export function normalizeTrafficPercents(rows) {
49
- if (!Array.isArray(rows) || rows.length === 0) return rows
50
- const omitted = []
51
- let explicitSum = 0
52
- for (let i = 0; i < rows.length; i++) {
53
- const percent = rows[i].percent
54
- if (percent === null) {
55
- omitted.push(i)
56
- continue
57
- }
58
- if (!Number.isFinite(percent) || percent < 0 || percent > 100) return rows
59
- explicitSum += percent
60
- }
61
- if (omitted.length === 0 || explicitSum !== 100) return rows
62
- const normalized = rows.map((row) => ({ ...row }))
63
- for (const index of omitted) normalized[index].percent = 0
64
- return normalized
65
- }
66
-
67
- const explicitPercent = (value) => {
68
- const parsed = num(value)
69
- return parsed === null ? Number.NaN : parsed
70
- }
71
-
72
- export const str = (v) => (typeof v === 'string' ? v.trim() : v === undefined || v === null ? '' : String(v).trim())
73
- // An ABSENT percent is null, not 0. `Number('')` is 0, so the obvious form reads a column the
74
- // platform never supplied as the one value that means "no users are reaching this" — absent
75
- // evidence rendered as the passing answer, which is the failure this whole script exists to stop.
76
- const num = (v) => {
77
- const s = str(v)
78
- if (s.length === 0) return null
79
- const n = Number(s)
80
- return Number.isFinite(n) ? n : Number.NaN
81
- }
@@ -1,612 +0,0 @@
1
- import crypto from 'node:crypto'
2
- import fs from 'node:fs'
3
- import path from 'node:path'
4
- import { TextDecoder } from 'node:util'
5
- import { parse, version as acornVersion } from '../vendor/acorn.mjs'
6
- import { inspectIsolatedAdapter } from './isolated-adapter-evaluator.mjs'
7
-
8
- // Adapters are deliberately small policy modules. The bound prevents an approved path
9
- // from becoming an unbounded memory/input surface before JavaScript parsing.
10
- export const CHECKED_ADAPTER_MAX_BYTES = 256 * 1024
11
- export const CHECKED_ADAPTER_PARSER = Object.freeze({
12
- name: 'acorn',
13
- version: acornVersion,
14
- })
15
-
16
- const FORBIDDEN_DEPENDENCY = 'e:adapter-dependency-forbidden'
17
- const FORBIDDEN_CAPABILITY = 'e:adapter-capability-forbidden'
18
- export const CHECKED_ADAPTER_ALLOWED_GLOBALS = Object.freeze([
19
- 'AggregateError', 'Array', 'BigInt', 'Boolean', 'Date', 'Error', 'EvalError',
20
- 'Infinity', 'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError',
21
- 'ReferenceError', 'RegExp', 'String', 'SyntaxError', 'TypeError', 'URIError',
22
- 'console', 'undefined',
23
- ])
24
- const ALLOWED_GLOBALS = new Set(CHECKED_ADAPTER_ALLOWED_GLOBALS)
25
- const FORBIDDEN_PROPERTIES = new Set([
26
- '__proto__',
27
- '_linkedBinding',
28
- '__defineGetter__',
29
- '__defineSetter__',
30
- '__lookupGetter__',
31
- '__lookupSetter__',
32
- 'AsyncFunction',
33
- 'AsyncGeneratorFunction',
34
- 'apply',
35
- 'bind',
36
- 'binding',
37
- 'call',
38
- 'compile',
39
- 'compileFunction',
40
- 'compileStreaming',
41
- 'constructor',
42
- 'createRequire',
43
- 'dlopen',
44
- 'eval',
45
- 'Function',
46
- 'GeneratorFunction',
47
- 'getBuiltinModule',
48
- 'getOwnPropertyDescriptor',
49
- 'getOwnPropertyDescriptors',
50
- 'getOwnPropertyNames',
51
- 'getOwnPropertySymbols',
52
- 'getPrototypeOf',
53
- 'global',
54
- 'globalThis',
55
- 'instantiate',
56
- 'instantiateStreaming',
57
- 'module',
58
- 'Module',
59
- '_load',
60
- '_resolveFilename',
61
- 'register',
62
- 'registerHooks',
63
- 'runInContext',
64
- 'runInNewContext',
65
- 'runInThisContext',
66
- 'SourceTextModule',
67
- 'SyntheticModule',
68
- 'process',
69
- 'prototype',
70
- 'require',
71
- 'setPrototypeOf',
72
- 'WebAssembly',
73
- ])
74
- const UTF8_DECODER = new TextDecoder('utf-8', { fatal: true })
75
- const MODULE_CACHE = new Map()
76
-
77
- export class CheckedAdapterError extends Error {
78
- constructor(code) {
79
- super(code)
80
- this.name = 'CheckedAdapterError'
81
- this.code = code
82
- }
83
- }
84
-
85
- function fail(code) {
86
- throw new CheckedAdapterError(code)
87
- }
88
-
89
- function contained(root, candidate) {
90
- const relative = path.relative(root, candidate)
91
- return relative !== '..'
92
- && !relative.startsWith(`..${path.sep}`)
93
- && !path.isAbsolute(relative)
94
- }
95
-
96
- function canonical(file, code) {
97
- try {
98
- return fs.realpathSync(file)
99
- } catch {
100
- fail(code)
101
- }
102
- }
103
-
104
- function stat(file, code) {
105
- try {
106
- return fs.statSync(file, { bigint: true })
107
- } catch {
108
- fail(code)
109
- }
110
- }
111
-
112
- function sameIdentity(left, right) {
113
- return left.dev === right.dev
114
- && left.ino === right.ino
115
- && left.mode === right.mode
116
- && left.size === right.size
117
- && left.mtimeNs === right.mtimeNs
118
- && left.ctimeNs === right.ctimeNs
119
- }
120
-
121
- function notifyFilesystemBoundary(hook, phase) {
122
- if (hook == null) return
123
- if (typeof hook !== 'function') fail('e:adapter-loader-seam-invalid')
124
- hook(Object.freeze({ phase }))
125
- }
126
-
127
- function openChecked(file) {
128
- const noFollow = Number.isInteger(fs.constants.O_NOFOLLOW) ? fs.constants.O_NOFOLLOW : 0
129
- const nonblock = Number.isInteger(fs.constants.O_NONBLOCK) ? fs.constants.O_NONBLOCK : 0
130
- try {
131
- return fs.openSync(file, fs.constants.O_RDONLY | noFollow | nonblock)
132
- } catch {
133
- fail('e:adapter-unloadable')
134
- }
135
- }
136
-
137
- function readBounded(fd, expectedSize) {
138
- const size = Number(expectedSize)
139
- const bytes = Buffer.alloc(size)
140
- let offset = 0
141
- while (offset < size) {
142
- const count = fs.readSync(fd, bytes, offset, size - offset, offset)
143
- if (count === 0) fail('e:adapter-changed-during-acquisition')
144
- offset += count
145
- }
146
- const extra = Buffer.alloc(1)
147
- if (fs.readSync(fd, extra, 0, 1, offset) !== 0) fail('e:adapter-changed-during-acquisition')
148
- return bytes
149
- }
150
-
151
- function acquireSource(repositoryRoot, adapterPath, hook) {
152
- if (typeof repositoryRoot !== 'string' || repositoryRoot.trim() === '') {
153
- fail('e:repository-root-unreadable')
154
- }
155
- if (typeof adapterPath !== 'string' || adapterPath.trim() === '') fail('e:adapter-undeclared')
156
- if (path.isAbsolute(adapterPath)) fail('e:adapter-outside-repository')
157
-
158
- const lexicalRoot = path.resolve(repositoryRoot)
159
- const lexicalAdapter = path.resolve(lexicalRoot, adapterPath)
160
- if (!contained(lexicalRoot, lexicalAdapter)) fail('e:adapter-outside-repository')
161
-
162
- const canonicalRoot = canonical(lexicalRoot, 'e:repository-root-unreadable')
163
- const canonicalAdapter = canonical(lexicalAdapter, 'e:adapter-unloadable')
164
- if (!contained(canonicalRoot, canonicalAdapter)) fail('e:adapter-outside-repository')
165
- if (path.extname(canonicalAdapter) !== '.mjs') fail('e:adapter-not-module')
166
-
167
- const approved = stat(canonicalAdapter, 'e:adapter-unloadable')
168
- if (!approved.isFile()) fail('e:adapter-not-regular-file')
169
- if (approved.size > BigInt(CHECKED_ADAPTER_MAX_BYTES)) fail('e:adapter-too-large')
170
-
171
- notifyFilesystemBoundary(hook, 'before-open')
172
- const fd = openChecked(canonicalAdapter)
173
- let bytes
174
- let opened
175
- let acquisitionError
176
- try {
177
- opened = fs.fstatSync(fd, { bigint: true })
178
- if (!opened.isFile()) fail('e:adapter-not-regular-file')
179
- if (opened.size > BigInt(CHECKED_ADAPTER_MAX_BYTES)) fail('e:adapter-too-large')
180
- if (!sameIdentity(approved, opened)) fail('e:adapter-replaced-before-open')
181
- notifyFilesystemBoundary(hook, 'after-open')
182
- const afterOpenPath = stat(canonicalAdapter, 'e:adapter-replaced-after-open')
183
- if (!sameIdentity(opened, afterOpenPath)) {
184
- fail('e:adapter-replaced-after-open')
185
- }
186
- notifyFilesystemBoundary(hook, 'before-read')
187
- bytes = readBounded(fd, opened.size)
188
- const afterRead = fs.fstatSync(fd, { bigint: true })
189
- if (!sameIdentity(opened, afterRead)) fail('e:adapter-changed-during-acquisition')
190
- } catch (error) {
191
- acquisitionError = error instanceof CheckedAdapterError
192
- ? error
193
- : new CheckedAdapterError('e:adapter-unloadable')
194
- } finally {
195
- try {
196
- fs.closeSync(fd)
197
- } catch {
198
- if (acquisitionError == null) acquisitionError = new CheckedAdapterError('e:adapter-close-failed')
199
- }
200
- }
201
- if (acquisitionError != null) throw acquisitionError
202
-
203
- const finalCanonical = canonical(lexicalAdapter, 'e:adapter-replaced-after-open')
204
- if (finalCanonical !== canonicalAdapter || !contained(canonicalRoot, finalCanonical)) {
205
- fail('e:adapter-replaced-after-open')
206
- }
207
- const finalStat = stat(finalCanonical, 'e:adapter-replaced-after-open')
208
- if (!sameIdentity(opened, finalStat)) fail('e:adapter-replaced-after-open')
209
-
210
- return Object.freeze({ bytes, canonicalPath: canonicalAdapter })
211
- }
212
-
213
- function decodeStrictUtf8(bytes) {
214
- try {
215
- return UTF8_DECODER.decode(bytes)
216
- } catch {
217
- fail('e:adapter-invalid-utf8')
218
- }
219
- }
220
-
221
- function children(node) {
222
- const values = []
223
- for (const [key, value] of Object.entries(node)) {
224
- if (key === 'start' || key === 'end' || key === 'loc') continue
225
- if (Array.isArray(value)) values.push(...value)
226
- else values.push(value)
227
- }
228
- return values.filter((value) => value != null && typeof value === 'object')
229
- }
230
-
231
- function staticPropertyName(node) {
232
- if (node == null) return null
233
- if (node.type === 'Identifier' || node.type === 'PrivateIdentifier') return node.name
234
- if (node.type === 'Literal' && (typeof node.value === 'string' || typeof node.value === 'number')) {
235
- return String(node.value)
236
- }
237
- return null
238
- }
239
-
240
- function childEntries(node) {
241
- const entries = []
242
- for (const [key, value] of Object.entries(node)) {
243
- if (key === 'start' || key === 'end' || key === 'loc') continue
244
- if (Array.isArray(value)) {
245
- for (const child of value) {
246
- if (child != null && typeof child === 'object') entries.push([key, child])
247
- }
248
- } else if (value != null && typeof value === 'object') {
249
- entries.push([key, value])
250
- }
251
- }
252
- return entries
253
- }
254
-
255
- function newScope(parent, varScope = false) {
256
- const scope = { parent, bindings: new Set(), varScope: null }
257
- scope.varScope = varScope ? scope : parent?.varScope
258
- return scope
259
- }
260
-
261
- function declarePattern(pattern, scope) {
262
- if (pattern == null) return
263
- if (pattern.type === 'Identifier') {
264
- scope.bindings.add(pattern.name)
265
- return
266
- }
267
- if (pattern.type === 'RestElement') {
268
- declarePattern(pattern.argument, scope)
269
- return
270
- }
271
- if (pattern.type === 'AssignmentPattern') {
272
- declarePattern(pattern.left, scope)
273
- return
274
- }
275
- if (pattern.type === 'ArrayPattern') {
276
- for (const element of pattern.elements) declarePattern(element, scope)
277
- return
278
- }
279
- if (pattern.type === 'ObjectPattern') {
280
- for (const property of pattern.properties) {
281
- if (property.type === 'RestElement') declarePattern(property.argument, scope)
282
- else declarePattern(property.value, scope)
283
- }
284
- }
285
- }
286
-
287
- function buildScopeModel(ast) {
288
- const scopeAt = new WeakMap()
289
- const root = newScope(null, true)
290
-
291
- function scanPatternExpressions(pattern, scope) {
292
- if (pattern == null) return
293
- if (pattern.type === 'AssignmentPattern') {
294
- scanPatternExpressions(pattern.left, scope)
295
- scan(pattern.right, scope)
296
- } else if (pattern.type === 'RestElement') {
297
- scanPatternExpressions(pattern.argument, scope)
298
- } else if (pattern.type === 'ArrayPattern') {
299
- for (const element of pattern.elements) scanPatternExpressions(element, scope)
300
- } else if (pattern.type === 'ObjectPattern') {
301
- for (const property of pattern.properties) {
302
- if (property.type === 'RestElement') scanPatternExpressions(property.argument, scope)
303
- else {
304
- if (property.computed) scan(property.key, scope)
305
- scanPatternExpressions(property.value, scope)
306
- }
307
- }
308
- }
309
- }
310
-
311
- function scanFunction(node, outerScope) {
312
- const parameterScope = newScope(outerScope, true)
313
- scopeAt.set(node, parameterScope)
314
- if (node.type !== 'ArrowFunctionExpression') parameterScope.bindings.add('arguments')
315
- if (node.type === 'FunctionExpression' && node.id != null) parameterScope.bindings.add(node.id.name)
316
- for (const parameter of node.params) declarePattern(parameter, parameterScope)
317
- for (const parameter of node.params) scanPatternExpressions(parameter, parameterScope)
318
- if (node.body.type === 'BlockStatement') {
319
- const bodyScope = newScope(parameterScope, true)
320
- scopeAt.set(node.body, bodyScope)
321
- for (const statement of node.body.body) scan(statement, bodyScope)
322
- } else {
323
- scan(node.body, parameterScope)
324
- }
325
- }
326
-
327
- function scanClass(node, outerScope) {
328
- if (node.type === 'ClassDeclaration' && node.id != null) outerScope.bindings.add(node.id.name)
329
- if (node.superClass != null) scan(node.superClass, outerScope)
330
- const scope = newScope(outerScope)
331
- scopeAt.set(node, scope)
332
- scopeAt.set(node.body, scope)
333
- if (node.id != null) scope.bindings.add(node.id.name)
334
- for (const element of node.body.body) scan(element, scope)
335
- }
336
-
337
- function scan(node, scope) {
338
- if (node == null) return
339
- scopeAt.set(node, scope)
340
- if (node.type === 'Program') {
341
- scopeAt.set(node, root)
342
- for (const statement of node.body) scan(statement, root)
343
- return
344
- }
345
- if (node.type === 'BlockStatement') {
346
- const block = newScope(scope)
347
- scopeAt.set(node, block)
348
- for (const statement of node.body) scan(statement, block)
349
- return
350
- }
351
- if (node.type === 'StaticBlock') {
352
- const block = newScope(scope, true)
353
- scopeAt.set(node, block)
354
- for (const statement of node.body) scan(statement, block)
355
- return
356
- }
357
- if (node.type === 'FunctionDeclaration') {
358
- if (node.id != null) scope.bindings.add(node.id.name)
359
- scanFunction(node, scope)
360
- return
361
- }
362
- if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
363
- scanFunction(node, scope)
364
- return
365
- }
366
- if (node.type === 'VariableDeclaration') {
367
- for (const declaration of node.declarations) {
368
- const bindingScope = node.kind === 'var' ? scope.varScope : scope
369
- declarePattern(declaration.id, bindingScope)
370
- scanPatternExpressions(declaration.id, scope)
371
- if (declaration.init != null) scan(declaration.init, scope)
372
- }
373
- return
374
- }
375
- if (node.type === 'CatchClause') {
376
- const catchScope = newScope(scope)
377
- scopeAt.set(node, catchScope)
378
- declarePattern(node.param, catchScope)
379
- scanPatternExpressions(node.param, catchScope)
380
- scopeAt.set(node.body, catchScope)
381
- for (const statement of node.body.body) scan(statement, catchScope)
382
- return
383
- }
384
- if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') {
385
- scanClass(node, scope)
386
- return
387
- }
388
- if (node.type === 'ForStatement' || node.type === 'ForInStatement' || node.type === 'ForOfStatement') {
389
- const loopScope = newScope(scope)
390
- scopeAt.set(node, loopScope)
391
- for (const [, child] of childEntries(node)) scan(child, loopScope)
392
- return
393
- }
394
- if (node.type === 'SwitchStatement') {
395
- const switchScope = newScope(scope)
396
- scopeAt.set(node, switchScope)
397
- scan(node.discriminant, switchScope)
398
- for (const switchCase of node.cases) scan(switchCase, switchScope)
399
- return
400
- }
401
- for (const [, child] of childEntries(node)) scan(child, scope)
402
- }
403
-
404
- scan(ast, root)
405
- return scopeAt
406
- }
407
-
408
- function isBound(scope, name) {
409
- for (let current = scope; current != null; current = current.parent) {
410
- if (current.bindings.has(name)) return true
411
- }
412
- return false
413
- }
414
-
415
- function visitBindingPatternExpressions(pattern, scope, visit) {
416
- if (pattern == null) return
417
- if (pattern.type === 'AssignmentPattern') {
418
- visitBindingPatternExpressions(pattern.left, scope, visit)
419
- visit(pattern.right, scope)
420
- } else if (pattern.type === 'RestElement') {
421
- visitBindingPatternExpressions(pattern.argument, scope, visit)
422
- } else if (pattern.type === 'ArrayPattern') {
423
- for (const element of pattern.elements) visitBindingPatternExpressions(element, scope, visit)
424
- } else if (pattern.type === 'ObjectPattern') {
425
- for (const property of pattern.properties) {
426
- if (property.type === 'RestElement') visitBindingPatternExpressions(property.argument, scope, visit)
427
- else {
428
- if (property.computed) visit(property.key, scope)
429
- visitBindingPatternExpressions(property.value, scope, visit)
430
- }
431
- }
432
- }
433
- }
434
-
435
- function validateUnresolvedReferences(ast) {
436
- const scopeAt = buildScopeModel(ast)
437
-
438
- function validateIdentifier(node, scope) {
439
- if (isBound(scope, node.name) || ALLOWED_GLOBALS.has(node.name)) return
440
- fail(FORBIDDEN_CAPABILITY)
441
- }
442
-
443
- function visitAssignmentTarget(node, scope) {
444
- if (node.type === 'Identifier') {
445
- validateIdentifier(node, scope)
446
- } else if (node.type === 'MemberExpression') {
447
- visit(node.object, scope)
448
- if (node.computed) visit(node.property, scope)
449
- } else if (node.type === 'RestElement') {
450
- visitAssignmentTarget(node.argument, scope)
451
- } else if (node.type === 'AssignmentPattern') {
452
- visitAssignmentTarget(node.left, scope)
453
- visit(node.right, scope)
454
- } else if (node.type === 'ArrayPattern') {
455
- for (const element of node.elements) if (element != null) visitAssignmentTarget(element, scope)
456
- } else if (node.type === 'ObjectPattern') {
457
- for (const property of node.properties) {
458
- if (property.type === 'RestElement') visitAssignmentTarget(property.argument, scope)
459
- else {
460
- if (property.computed) visit(property.key, scope)
461
- visitAssignmentTarget(property.value, scope)
462
- }
463
- }
464
- }
465
- }
466
-
467
- function visitFunction(node) {
468
- const scope = scopeAt.get(node)
469
- for (const parameter of node.params) visitBindingPatternExpressions(parameter, scope, visit)
470
- visit(node.body, scope)
471
- }
472
-
473
- function visitClass(node, outerScope) {
474
- if (node.superClass != null) visit(node.superClass, outerScope)
475
- visit(node.body, scopeAt.get(node))
476
- }
477
-
478
- function visit(node, inheritedScope, parent = null) {
479
- if (node == null) return
480
- const scope = scopeAt.get(node) ?? inheritedScope
481
- if (node.type === 'Identifier') {
482
- validateIdentifier(node, scope)
483
- return
484
- }
485
- if (node.type === 'VariableDeclaration') {
486
- for (const declaration of node.declarations) {
487
- visitBindingPatternExpressions(declaration.id, scope, visit)
488
- if (declaration.init != null) visit(declaration.init, scope, declaration)
489
- }
490
- return
491
- }
492
- if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression'
493
- || node.type === 'ArrowFunctionExpression') {
494
- visitFunction(node)
495
- return
496
- }
497
- if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') {
498
- visitClass(node, inheritedScope)
499
- return
500
- }
501
- if (node.type === 'CatchClause') {
502
- visitBindingPatternExpressions(node.param, scope, visit)
503
- visit(node.body, scope, node)
504
- return
505
- }
506
- if (node.type === 'MemberExpression') {
507
- visit(node.object, scope, node)
508
- if (node.computed) visit(node.property, scope, node)
509
- return
510
- }
511
- if (node.type === 'Property') {
512
- if (node.computed) visit(node.key, scope, node)
513
- visit(node.value, scope, node)
514
- return
515
- }
516
- if (node.type === 'MethodDefinition' || node.type === 'PropertyDefinition') {
517
- if (node.computed) visit(node.key, scope, node)
518
- if (node.value != null) visit(node.value, scope, node)
519
- return
520
- }
521
- if (node.type === 'AssignmentExpression') {
522
- visitAssignmentTarget(node.left, scope)
523
- visit(node.right, scope, node)
524
- return
525
- }
526
- if (node.type === 'UpdateExpression') {
527
- visitAssignmentTarget(node.argument, scope)
528
- return
529
- }
530
- if (node.type === 'LabeledStatement') {
531
- visit(node.body, scope, node)
532
- return
533
- }
534
- if (node.type === 'BreakStatement' || node.type === 'ContinueStatement'
535
- || node.type === 'PrivateIdentifier' || node.type === 'MetaProperty') return
536
- if (node.type === 'ExportSpecifier') {
537
- visit(node.local, scope, node)
538
- return
539
- }
540
- if (node.type === 'ImportSpecifier' || node.type === 'ImportDefaultSpecifier'
541
- || node.type === 'ImportNamespaceSpecifier') return
542
- for (const [, child] of childEntries(node)) visit(child, scope, node)
543
- }
544
-
545
- visit(ast, scopeAt.get(ast))
546
- }
547
-
548
- function validateCapabilityNode(node, parent) {
549
- if ((node.type === 'MemberExpression' || node.type === 'Property'
550
- || node.type === 'MethodDefinition' || node.type === 'PropertyDefinition') && node.computed) {
551
- fail(FORBIDDEN_CAPABILITY)
552
- }
553
- if ((node.type === 'MemberExpression' || node.type === 'Property'
554
- || node.type === 'MethodDefinition' || node.type === 'PropertyDefinition')
555
- && FORBIDDEN_PROPERTIES.has(staticPropertyName(node.type === 'MemberExpression' ? node.property : node.key))) {
556
- fail(FORBIDDEN_CAPABILITY)
557
- }
558
- }
559
-
560
- function validateAdapterPolicy(source) {
561
- let ast
562
- try {
563
- ast = parse(source, { ecmaVersion: 'latest', sourceType: 'module' })
564
- } catch {
565
- fail('e:adapter-invalid-syntax')
566
- }
567
- const pending = [{ node: ast, parent: null }]
568
- while (pending.length > 0) {
569
- const { node, parent } = pending.pop()
570
- if (node.type === 'ImportDeclaration'
571
- || node.type === 'ImportExpression'
572
- || node.type === 'ExportAllDeclaration'
573
- || (node.type === 'ExportNamedDeclaration' && node.source != null)
574
- || (node.type === 'MetaProperty' && node.meta?.name === 'import')) {
575
- fail(FORBIDDEN_DEPENDENCY)
576
- }
577
- validateCapabilityNode(node, parent)
578
- pending.push(...children(node).map((child) => ({ node: child, parent: node })))
579
- }
580
- validateUnresolvedReferences(ast)
581
- }
582
-
583
- async function executeBytes(bytes, source, contentHash) {
584
- let cached = MODULE_CACHE.get(contentHash)
585
- if (cached == null) {
586
- const boundBytes = Buffer.from(bytes)
587
- cached = inspectIsolatedAdapter({ source, bytes: boundBytes, contentHash })
588
- .then(({ module }) => module)
589
- .catch((error) => {
590
- MODULE_CACHE.delete(contentHash)
591
- if (typeof error?.code === 'string' && error.code.startsWith('e:adapter-')) fail(error.code)
592
- fail('e:adapter-execution-failed')
593
- })
594
- MODULE_CACHE.set(contentHash, cached)
595
- }
596
- try {
597
- return await cached
598
- } catch (error) {
599
- if (error instanceof CheckedAdapterError) throw error
600
- fail('e:adapter-execution-failed')
601
- }
602
- }
603
-
604
- export async function loadCheckedAdapter({ repositoryRoot, adapterPath, onFilesystemBoundary } = {}) {
605
- const acquired = acquireSource(repositoryRoot, adapterPath, onFilesystemBoundary)
606
- const source = decodeStrictUtf8(acquired.bytes)
607
- validateAdapterPolicy(source)
608
- const contentHash = crypto.createHash('sha256').update(acquired.bytes).digest('hex')
609
- notifyFilesystemBoundary(onFilesystemBoundary, 'after-acquire')
610
- const module = await executeBytes(acquired.bytes, source, contentHash)
611
- return Object.freeze({ module, canonicalPath: acquired.canonicalPath, contentHash })
612
- }