@1aboveio/skills 0.19.2 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/README.md +9 -4
  2. package/package.json +1 -1
  3. package/runtime/skills/distribution/generated/recipes.json +54 -48
  4. package/runtime/skills/distribution/scripts/bundles.mjs +113 -7
  5. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
  6. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
  7. package/skills/cicd-pipeline/mergify/SKILL.md +1 -1
  8. package/skills/engineering/engineering-runtime/coherence/workflow.json +14 -83
  9. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +4 -6
  10. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +3 -36
  11. package/skills/engineering/smoke/SKILL.md +1 -1
  12. package/skills/payment/payment-analysis/SKILL.md +13 -7
  13. package/skills/payment/payment-analysis/references/chargebacks.md +43 -18
  14. package/skills/payment/payment-analysis/references/event-layers.md +4 -0
  15. package/skills/payment/payment-analysis/references/metrics.md +9 -7
  16. package/skills/payment/payment-analysis/references/report-template.md +3 -3
  17. package/skills/payment/payment-analysis/references/terminology.md +6 -1
  18. package/skills/payment/payment-analysis/references/visualization.md +1 -1
  19. package/skills/payment/tld-detection/SKILL.md +163 -0
  20. package/skills/payment/tld-detection/agents/openai.yaml +9 -0
  21. package/skills/payment/tld-detection/evals/evals.json +107 -0
  22. package/skills/payment/tld-detection/references/clean.md +51 -0
  23. package/skills/payment/tld-detection/references/clustering.md +219 -0
  24. package/skills/payment/tld-detection/references/decision.md +85 -0
  25. package/skills/payment/tld-detection/references/report-template.md +169 -0
  26. package/skills/payment/tld-detection/references/terminology.md +69 -0
  27. package/skills/payment/tld-detection/references/workflow.md +78 -0
  28. package/skills/payment/tld-detection/scripts/detect_ladders.py +390 -0
  29. package/skills/payment/tld-detection/tests/test_detect_ladders.py +132 -0
  30. package/skills/engineering/resolve-issues/SKILL.md +0 -168
  31. package/skills/engineering/resolve-issues/agents/openai.yaml +0 -9
  32. package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +0 -499
  33. package/skills/engineering/resolve-issues/references/breaker.md +0 -82
  34. package/skills/engineering/resolve-issues/references/deliverables.md +0 -27
  35. package/skills/engineering/resolve-issues/references/delivery.md +0 -108
  36. package/skills/engineering/resolve-issues/references/evidence-lane.md +0 -21
  37. package/skills/engineering/resolve-issues/references/exact-head-ci.md +0 -287
  38. package/skills/engineering/resolve-issues/references/fan-out.md +0 -33
  39. package/skills/engineering/resolve-issues/references/finalization.md +0 -68
  40. package/skills/engineering/resolve-issues/references/guarantees.md +0 -10
  41. package/skills/engineering/resolve-issues/references/high-risk.md +0 -29
  42. package/skills/engineering/resolve-issues/references/incidents/848/README.md +0 -156
  43. package/skills/engineering/resolve-issues/references/intake.md +0 -86
  44. package/skills/engineering/resolve-issues/references/integration-gate.md +0 -53
  45. package/skills/engineering/resolve-issues/references/interference.md +0 -87
  46. package/skills/engineering/resolve-issues/references/loop.md +0 -134
  47. package/skills/engineering/resolve-issues/references/model-catalog.md +0 -9
  48. package/skills/engineering/resolve-issues/references/postmortem.md +0 -27
  49. package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +0 -41
  50. package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +0 -48
  51. package/skills/engineering/resolve-issues/references/pre-flight.md +0 -41
  52. package/skills/engineering/resolve-issues/references/regression-checklist.md +0 -26
  53. package/skills/engineering/resolve-issues/references/run-state.md +0 -288
  54. package/skills/engineering/resolve-issues/references/sandboxed-testing.md +0 -48
  55. package/skills/engineering/resolve-issues/references/spawn-contract.md +0 -96
  56. package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +0 -40
  57. package/skills/engineering/resolve-issues/references/why.md +0 -653
  58. package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +0 -49
  59. package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +0 -721
  60. package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +0 -962
  61. package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +0 -220
  62. package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +0 -420
  63. package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +0 -256
  64. package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +0 -168
  65. package/skills/engineering/resolve-issues/scripts/discover-models.mjs +0 -9
  66. package/skills/engineering/resolve-issues/scripts/doctrine.mjs +0 -62
  67. package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +0 -191
  68. package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +0 -413
  69. package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +0 -332
  70. package/skills/engineering/resolve-issues/scripts/finalize.mjs +0 -488
  71. package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +0 -3307
  72. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +0 -16
  73. package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +0 -51
  74. package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +0 -17
  75. package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +0 -166
  76. package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +0 -92
  77. package/skills/engineering/resolve-issues/scripts/guide-index.mjs +0 -73
  78. package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +0 -159
  79. package/skills/engineering/resolve-issues/scripts/interference.mjs +0 -427
  80. package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +0 -9
  81. package/skills/engineering/resolve-issues/scripts/next-operations.mjs +0 -419
  82. package/skills/engineering/resolve-issues/scripts/postmortem.mjs +0 -909
  83. package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +0 -345
  84. package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +0 -415
  85. package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +0 -697
  86. package/skills/engineering/resolve-issues/scripts/report.mjs +0 -494
  87. package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +0 -172
  88. package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +0 -79
  89. package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +0 -334
  90. package/skills/engineering/resolve-issues/scripts/run-state.mjs +0 -4792
  91. package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +0 -395
  92. package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +0 -290
  93. package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +0 -170
  94. package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +0 -293
  95. package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +0 -197
  96. package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +0 -127
  97. package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +0 -893
  98. package/skills/engineering/resolve-issues/scripts/workspaces.mjs +0 -829
  99. package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +0 -290
  100. package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +0 -80
  101. package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +0 -102
  102. package/skills/engineering/resolve-release/LICENSE +0 -3
  103. package/skills/engineering/resolve-release/SKILL.md +0 -113
  104. package/skills/engineering/resolve-release/agents/openai.yaml +0 -9
  105. package/skills/engineering/resolve-release/references/assembly.md +0 -137
  106. package/skills/engineering/resolve-release/references/auto-when-green.md +0 -56
  107. package/skills/engineering/resolve-release/references/candidate.md +0 -167
  108. package/skills/engineering/resolve-release/references/exposure.md +0 -178
  109. package/skills/engineering/resolve-release/references/handoff.md +0 -24
  110. package/skills/engineering/resolve-release/references/postmortem.md +0 -230
  111. package/skills/engineering/resolve-release/references/preflight.md +0 -208
  112. package/skills/engineering/resolve-release/references/principles.md +0 -94
  113. package/skills/engineering/resolve-release/references/regression-checklist.md +0 -36
  114. package/skills/engineering/resolve-release/references/related-skills.md +0 -13
  115. package/skills/engineering/resolve-release/references/routing.md +0 -149
  116. package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +0 -285
  117. package/skills/engineering/resolve-release/references/versioning.md +0 -202
  118. package/skills/engineering/resolve-release/references/why.md +0 -53
  119. package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +0 -389
  120. package/skills/engineering/resolve-release/scripts/build-changes.mjs +0 -209
  121. package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +0 -407
  122. package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +0 -904
  123. package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +0 -81
  124. package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +0 -612
  125. package/skills/engineering/resolve-release/scripts/close-attempt.mjs +0 -135
  126. package/skills/engineering/resolve-release/scripts/closeout-release.mjs +0 -161
  127. package/skills/engineering/resolve-release/scripts/doctrine.mjs +0 -106
  128. package/skills/engineering/resolve-release/scripts/durable-processing.mjs +0 -522
  129. package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +0 -659
  130. package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +0 -1014
  131. package/skills/engineering/resolve-release/scripts/finalize-release.mjs +0 -526
  132. package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +0 -169
  133. package/skills/engineering/resolve-release/scripts/green-gate.mjs +0 -599
  134. package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +0 -752
  135. package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +0 -56
  136. package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +0 -1538
  137. package/skills/engineering/resolve-release/scripts/postmortem.mjs +0 -381
  138. package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +0 -510
  139. package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +0 -326
  140. package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +0 -272
  141. package/skills/engineering/resolve-release/scripts/report.mjs +0 -417
  142. package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +0 -114
  143. package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +0 -238
  144. package/skills/engineering/resolve-release/scripts/review-packet.mjs +0 -503
  145. package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +0 -263
  146. package/skills/engineering/resolve-release/scripts/version-assert.mjs +0 -339
  147. package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +0 -485
  148. package/skills/engineering/resolve-release/scripts/version.mjs +0 -1199
  149. package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +0 -449
  150. package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +0 -21
  151. package/skills/engineering/resolve-release/vendor/README.md +0 -60
  152. package/skills/engineering/resolve-release/vendor/acorn.mjs +0 -6233
  153. package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +0 -21
  154. package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +0 -341
  155. package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +0 -70
  156. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +0 -2
  157. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +0 -1
  158. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +0 -7
  159. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +0 -1
  160. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +0 -2033
  161. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +0 -2033
  162. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +0 -7
  163. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +0 -1
  164. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +0 -2
  165. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +0 -1
  166. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +0 -2
  167. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +0 -1
  168. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +0 -2
  169. package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +0 -1
  170. package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +0 -49
  171. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +0 -21
  172. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +0 -5
  173. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +0 -549
  174. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +0 -549
  175. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +0 -2
  176. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +0 -1
  177. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +0 -2
  178. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +0 -1
  179. package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +0 -36
  180. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +0 -47
  181. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +0 -82
  182. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +0 -11
  183. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +0 -22
  184. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +0 -21
  185. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +0 -21
  186. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +0 -11
  187. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +0 -11
  188. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +0 -25
  189. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
  190. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +0 -85
  191. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +0 -85
  192. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +0 -2
  193. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +0 -1
  194. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +0 -2
  195. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +0 -1
  196. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +0 -20
  197. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +0 -20
  198. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +0 -2
  199. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +0 -1
  200. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +0 -2
  201. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +0 -1
  202. package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +0 -61
  203. /package/skills/{engineering/resolve-issues → payment/tld-detection}/LICENSE +0 -0
@@ -1,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
- }