@1aboveio/skills 0.19.3 → 0.20.2

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