@githolon/runtime 0.110.0

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 (71) hide show
  1. package/LICENSE.md +45 -0
  2. package/dist/RUNTIME-SOURCES.sha256 +289 -0
  3. package/dist/application-reception.js +206 -0
  4. package/dist/nomos-native-runtime.js +22519 -0
  5. package/dist/nomos-runner.html +13 -0
  6. package/dist/nomos-runner.js +34769 -0
  7. package/dist/remote-reception.cjs +582 -0
  8. package/dist/remote-reception.js +555 -0
  9. package/dist/typescript-application-desk.js +796 -0
  10. package/package.json +71 -0
  11. package/runner/README.md +75 -0
  12. package/runner/build.ts +225 -0
  13. package/runner/node-entry.mjs +31858 -0
  14. package/runner/nomos-runner.html +13 -0
  15. package/runner/shims.js +17 -0
  16. package/src/admission_decision.ts +60 -0
  17. package/src/application_reception.ts +134 -0
  18. package/src/nominal_value.ts +122 -0
  19. package/src/protocol/nomos/custody/v1/snapshot_pb.d.ts +67 -0
  20. package/src/protocol/nomos/custody/v1/snapshot_pb.js +18 -0
  21. package/src/protocol/nomos/discovery/v1/workspace_placement_pb.d.ts +56 -0
  22. package/src/protocol/nomos/discovery/v1/workspace_placement_pb.js +18 -0
  23. package/src/protocol/nomos/kernel/v1/kernel_pb.d.ts +11183 -0
  24. package/src/protocol/nomos/kernel/v1/kernel_pb.js +2217 -0
  25. package/src/protocol/nomos/kernel/v1/progress_pb.d.ts +250 -0
  26. package/src/protocol/nomos/kernel/v1/progress_pb.js +66 -0
  27. package/src/protocol/nomos/runtime/v2/application_desk_pb.d.ts +162 -0
  28. package/src/protocol/nomos/runtime/v2/application_desk_pb.js +60 -0
  29. package/src/protocol/nomos/runtime/v2/application_readiness_desk_pb.d.ts +202 -0
  30. package/src/protocol/nomos/runtime/v2/application_readiness_desk_pb.js +67 -0
  31. package/src/protocol/nomos/runtime/v2/authentication_desk_pb.d.ts +158 -0
  32. package/src/protocol/nomos/runtime/v2/authentication_desk_pb.js +50 -0
  33. package/src/protocol/nomos/runtime/v2/compatibility_desk_pb.d.ts +204 -0
  34. package/src/protocol/nomos/runtime/v2/compatibility_desk_pb.js +68 -0
  35. package/src/protocol/nomos/runtime/v2/correspondence_desk_pb.d.ts +3661 -0
  36. package/src/protocol/nomos/runtime/v2/correspondence_desk_pb.js +735 -0
  37. package/src/protocol/nomos/runtime/v2/credentials_desk_pb.d.ts +122 -0
  38. package/src/protocol/nomos/runtime/v2/credentials_desk_pb.js +41 -0
  39. package/src/protocol/nomos/runtime/v2/custody_desk_pb.d.ts +611 -0
  40. package/src/protocol/nomos/runtime/v2/custody_desk_pb.js +123 -0
  41. package/src/protocol/nomos/runtime/v2/framework_pb.d.ts +211 -0
  42. package/src/protocol/nomos/runtime/v2/framework_pb.js +29 -0
  43. package/src/protocol/nomos/runtime/v2/identity_desk_pb.d.ts +305 -0
  44. package/src/protocol/nomos/runtime/v2/identity_desk_pb.js +61 -0
  45. package/src/protocol/nomos/runtime/v2/interaction_desk_pb.d.ts +73 -0
  46. package/src/protocol/nomos/runtime/v2/interaction_desk_pb.js +25 -0
  47. package/src/protocol/nomos/runtime/v2/law_desk_pb.d.ts +133 -0
  48. package/src/protocol/nomos/runtime/v2/law_desk_pb.js +39 -0
  49. package/src/protocol/nomos/runtime/v2/maintenance_desk_pb.d.ts +267 -0
  50. package/src/protocol/nomos/runtime/v2/maintenance_desk_pb.js +84 -0
  51. package/src/protocol/nomos/runtime/v2/model_adoption_desk_pb.d.ts +233 -0
  52. package/src/protocol/nomos/runtime/v2/model_adoption_desk_pb.js +57 -0
  53. package/src/protocol/nomos/runtime/v2/observability_desk_pb.d.ts +1015 -0
  54. package/src/protocol/nomos/runtime/v2/observability_desk_pb.js +230 -0
  55. package/src/protocol/nomos/runtime/v2/placement_desk_pb.d.ts +431 -0
  56. package/src/protocol/nomos/runtime/v2/placement_desk_pb.js +125 -0
  57. package/src/protocol/nomos/runtime/v2/receiving_group_desk_pb.d.ts +336 -0
  58. package/src/protocol/nomos/runtime/v2/receiving_group_desk_pb.js +78 -0
  59. package/src/protocol/nomos/runtime/v2/records_desk_pb.d.ts +716 -0
  60. package/src/protocol/nomos/runtime/v2/records_desk_pb.js +200 -0
  61. package/src/protocol/nomos/runtime/v2/recovery_desk_pb.d.ts +535 -0
  62. package/src/protocol/nomos/runtime/v2/recovery_desk_pb.js +160 -0
  63. package/src/protocol/nomos/runtime/v2/residency_desk_pb.d.ts +1162 -0
  64. package/src/protocol/nomos/runtime/v2/residency_desk_pb.js +212 -0
  65. package/src/protocol/nomos/runtime/v2/runtime_pb.d.ts +796 -0
  66. package/src/protocol/nomos/runtime/v2/runtime_pb.js +72 -0
  67. package/src/protocol/nomos/runtime/v2/sealing_desk_pb.d.ts +581 -0
  68. package/src/protocol/nomos/runtime/v2/sealing_desk_pb.js +149 -0
  69. package/src/remote_reception.public.d.ts +97 -0
  70. package/src/remote_reception.ts +446 -0
  71. package/src/typescript_application_desk.public.d.ts +62 -0
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@githolon/runtime",
3
+ "version": "0.110.0",
4
+ "type": "module",
5
+ "description": "The portable Nomos application runtime, reception contracts, and Node/browser runners.",
6
+ "license": "SEE LICENSE IN LICENSE.md",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Captain-App/nomos2.git",
10
+ "directory": "peer-office"
11
+ },
12
+ "exports": {
13
+ "./application": {
14
+ "types": "./src/application_reception.ts",
15
+ "import": "./dist/application-reception.js"
16
+ },
17
+ "./remote-reception": {
18
+ "types": "./src/remote_reception.public.d.ts",
19
+ "import": "./dist/remote-reception.js",
20
+ "require": "./dist/remote-reception.cjs"
21
+ },
22
+ "./typescript-reception": {
23
+ "types": "./src/typescript_application_desk.public.d.ts",
24
+ "import": "./dist/typescript-application-desk.js"
25
+ },
26
+ "./package.json": "./package.json",
27
+ "./runner/node-entry.mjs": "./runner/node-entry.mjs",
28
+ "./dist/nomos-runner.html": "./dist/nomos-runner.html",
29
+ "./dist/nomos-runner.js": "./dist/nomos-runner.js"
30
+ },
31
+ "typesVersions": {
32
+ "*": {
33
+ "application": [
34
+ "src/application_reception.ts"
35
+ ],
36
+ "remote-reception": [
37
+ "src/remote_reception.public.d.ts"
38
+ ],
39
+ "typescript-reception": [
40
+ "src/typescript_application_desk.public.d.ts"
41
+ ]
42
+ }
43
+ },
44
+ "files": [
45
+ "src",
46
+ "runner",
47
+ "dist"
48
+ ],
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "scripts": {
53
+ "build": "node runner/build.ts",
54
+ "build:runner": "node runner/build.ts",
55
+ "typecheck": "tsc --noEmit -p tsconfig.json",
56
+ "prepare": "npm run build",
57
+ "prepublishOnly": "node runner/build.ts",
58
+ "test:unit": "node --expose-gc --test ../test/*.test.ts",
59
+ "test:runtime": "node --test ../test/peer_runtime_contract.test.ts"
60
+ },
61
+ "dependencies": {
62
+ "@bjorn3/browser_wasi_shim": "0.4.2",
63
+ "@bufbuild/protobuf": "^2.13.0",
64
+ "fast-xml-parser": "5.10.1",
65
+ "uri-js": "^4.4.1"
66
+ },
67
+ "devDependencies": {
68
+ "buffer": "^6.0.3",
69
+ "isomorphic-git": "^1.38.4"
70
+ }
71
+ }
@@ -0,0 +1,75 @@
1
+ # Physical shells for the Nomos peer runtime
2
+
3
+ Every Nomos peer runs the same retained `PeerRuntime` implementation. These
4
+ entry points exist only because browsers, Node processes and app WebViews boot
5
+ code and move bytes differently.
6
+
7
+ ```text
8
+ generated Dart / TypeScript client
9
+ │
10
+ │ Runtime v2 Protobuf frame
11
+ ▼
12
+ ┌──────────────────────────────────────────────────────────┐
13
+ │ one PeerRuntime │
14
+ │ │
15
+ │ sessions · custody lifecycle · offers · queries · sync │
16
+ │ subscriptions · retries · progress │
17
+ └────────────────────────────┬─────────────────────────────┘
18
+ │ typed effect
19
+ ▼
20
+ ┌──────────────────────────────────────────────────────────┐
21
+ │ physical platform shell │
22
+ │ kernel execution · filesystem · network · clock · keys │
23
+ └────────────────────────────┬─────────────────────────────┘
24
+ │ typed receipt
25
+ └──────────────► same runtime
26
+ ```
27
+
28
+ The shell is not a compatibility layer. It must not contain a command map,
29
+ session table, credential cache, sync controller, retry policy, custody model,
30
+ or a second interpretation of a generated request. It may inspect a typed
31
+ initial `Connect.cloud` only to acquire the selected physical kernel artifact;
32
+ the unchanged request is then handled by the shared runtime.
33
+
34
+ ## Entrypoints
35
+
36
+ - `runner-entry.ts` boots the browser/WebView kernel plane and forwards exact
37
+ Runtime v2 frames and events.
38
+ - `node-entry.ts` boots the Node kernel plane and forwards the same frames and
39
+ events over stdin/stdout.
40
+ - Apple embeds `nomos-native-runtime.js`, built from the same
41
+ `peer-office/src/peer_office.ts`; JavaScriptCore runs the office and the
42
+ native host supplies the AOT kernel.
43
+
44
+ Build the distributable shells with:
45
+
46
+ ```bash
47
+ npm run build:runner
48
+ ```
49
+
50
+ This produces `dist/nomos-runner.js`, `dist/nomos-runner.html`, the Node shell,
51
+ and the Apple runtime bundle. Generated applications consume these artifacts;
52
+ they do not implement lifecycle themselves.
53
+
54
+ ## Non-negotiable boundary
55
+
56
+ The only application/runtime messages are generated Runtime v2 Protobuf
57
+ frames. Domain values returned by generated calls remain canonical OpenUSD.
58
+ Base64 is permitted only where a browser API physically accepts strings; it is
59
+ an encoding of the unchanged Protobuf bytes, not a second command language.
60
+
61
+ Inside one Peer Office, desks call typed `RuntimeRequest -> RuntimeResponse`
62
+ functions. Only the external `invoke(bytes)` boundary encodes and decodes
63
+ Runtime v2 frames. Internal sub-requests still pass through the same access,
64
+ recovery, session-binding and observation paths; they do not gain authority by
65
+ being local. Large byte fields are shared read-only, not serialized merely to
66
+ cross a function boundary. The kernel ABI and actual remote HTTP effects are
67
+ separate byte boundaries and still encode their messages.
68
+
69
+ `peer-office/test/peer_office_wire_boundary.test.ts` meters real protobuf calls
70
+ through the bundled office. A local success or refusal must perform exactly
71
+ one external request decode and one external response encode.
72
+
73
+ Git custody remains the durable source of truth. SQLite projections and
74
+ compiled OpenUSD layers are disposable frontier-keyed acceleration. No shell
75
+ may serialize a workspace into a private snapshot format to move or park it.
@@ -0,0 +1,225 @@
1
+ // Build the Nomos client bundles: the @githolon/runtime + a per-host entry + the engine shims, esbuild'd into
2
+ // ONE self-contained IIFE. The browser shell and Apple JavaScriptCore host
3
+ // both retain the same peer-runtime implementation; they differ only in the
4
+ // physical kernel and byte-transport ports they provide.
5
+ // Run: `npm run build:runner`.
6
+ import { build } from "esbuild";
7
+ import { createHash } from "node:crypto";
8
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
9
+ import { fileURLToPath } from "node:url";
10
+ import { isAbsolute, join, relative, resolve } from "node:path";
11
+
12
+ const here = (p: string) => fileURLToPath(new URL(p, import.meta.url));
13
+ const normalizeGeneratedText = (file: string): void => {
14
+ const source = readFileSync(file, "utf8");
15
+ writeFileSync(file, source.replace(/[ \t]+$/gm, ""), "utf8");
16
+ };
17
+ mkdirSync(here("../dist"), { recursive: true });
18
+ // THE BUNDLE STAMP: inject the package version so the runner's ready frame carries exactly the
19
+ // release it was built from (stale-baked-bundle detection — the stamp can never drift or lie).
20
+ const BUNDLE_VERSION = JSON.parse(readFileSync(here("../package.json"), "utf8")).version;
21
+ // The SDK carries the host compatibility contract, not the executable or a fresh-install fallback. Online,
22
+ // the runtime endpoint selects a contract-compatible immutable digest; the runner verifies and durably caches
23
+ // those exact bytes. RAN can therefore promote or roll back compatible kernels without republishing the SDK.
24
+ const KERNEL_RELEASE = {
25
+ contracts: { "nomos.kernel.v1": "1.0.0" },
26
+ };
27
+
28
+ const browserBuild = await build({
29
+ entryPoints: [here("../../../platform-shells/browser/entry.ts")],
30
+ // Resolve node_modules by the path it is reached at, not its real path: a bundle's module
31
+ // comments name that path, so a committed-snapshot build (whose node_modules is a link to the
32
+ // installed one) and a checkout build emit the same bytes.
33
+ preserveSymlinks: true,
34
+ bundle: true,
35
+ platform: "browser",
36
+ format: "iife",
37
+ target: "es2020",
38
+ inject: [here("./shims.js")],
39
+ define: {
40
+ global: "globalThis",
41
+ __NOMOS_BUNDLE_VERSION__: JSON.stringify(BUNDLE_VERSION),
42
+ __NOMOS_KERNEL_RELEASE__: JSON.stringify(KERNEL_RELEASE),
43
+ },
44
+ outfile: here("../dist/nomos-runner.js"),
45
+ legalComments: "none",
46
+ metafile: true,
47
+ });
48
+ copyFileSync(here("./nomos-runner.html"), here("../dist/nomos-runner.html"));
49
+
50
+ // THE TYPED NATIVE RUNTIME — the shared Peer Office executed by the Apple
51
+ // JavaScriptCore host. It accepts only generated Runtime v2
52
+ // protobuf and calls the resident kernel with generated kernel protobuf.
53
+ const nativeBuild = await build({
54
+ entryPoints: [here("../../src/peer_office.ts")],
55
+ // Resolve node_modules by the path it is reached at, not its real path: a bundle's module
56
+ // comments name that path, so a committed-snapshot build (whose node_modules is a link to the
57
+ // installed one) and a checkout build emit the same bytes.
58
+ preserveSymlinks: true,
59
+ bundle: true,
60
+ platform: "neutral",
61
+ format: "iife",
62
+ globalName: "NomosRuntimeComponent",
63
+ target: "es2022",
64
+ outfile: here("../dist/nomos-native-runtime.js"),
65
+ legalComments: "none",
66
+ metafile: true,
67
+ });
68
+ // APPLICATION RECEPTION — generated facades import only this narrow session
69
+ // surface. The Peer Office owns every runtime lifecycle behind its desks.
70
+ const applicationBuild = await build({
71
+ entryPoints: [here("../src/application_reception.ts")],
72
+ // Resolve node_modules by the path it is reached at, not its real path: a bundle's module
73
+ // comments name that path, so a committed-snapshot build (whose node_modules is a link to the
74
+ // installed one) and a checkout build emit the same bytes.
75
+ preserveSymlinks: true,
76
+ bundle: true,
77
+ platform: "neutral",
78
+ format: "esm",
79
+ target: "es2022",
80
+ outfile: here("../dist/application-reception.js"),
81
+ packages: "external",
82
+ legalComments: "none",
83
+ logLevel: "warning",
84
+ metafile: true,
85
+ });
86
+ normalizeGeneratedText(here("../dist/application-reception.js"));
87
+ console.error("✓ built dist/application-reception.js (language-native Reception surface)");
88
+
89
+ const typescriptReceptionBuild = await build({
90
+ entryPoints: [here("../../src/reception/typescript_application_desk.ts")],
91
+ // Resolve node_modules by the path it is reached at, not its real path: a bundle's module
92
+ // comments name that path, so a committed-snapshot build (whose node_modules is a link to the
93
+ // installed one) and a checkout build emit the same bytes.
94
+ preserveSymlinks: true,
95
+ bundle: true,
96
+ platform: "neutral",
97
+ format: "esm",
98
+ target: "es2022",
99
+ outfile: here("../dist/typescript-application-desk.js"),
100
+ packages: "external",
101
+ legalComments: "none",
102
+ logLevel: "warning",
103
+ metafile: true,
104
+ });
105
+ normalizeGeneratedText(here("../dist/typescript-application-desk.js"));
106
+ console.error("✓ built TypeScript Reception application desks");
107
+
108
+ // REMOTE RECEPTION — a scheduler or another non-resident process may hand one
109
+ // generated call to a remote Peer Office. This bundles only protobuf paper and
110
+ // HTTP correspondence; it must never pull a kernel or workspace lifecycle into
111
+ // the caller.
112
+ const remoteReceptionBuild = await build({
113
+ entryPoints: [here("../src/remote_reception.ts")],
114
+ // Resolve node_modules by the path it is reached at, not its real path: a bundle's module
115
+ // comments name that path, so a committed-snapshot build (whose node_modules is a link to the
116
+ // installed one) and a checkout build emit the same bytes.
117
+ preserveSymlinks: true,
118
+ bundle: true,
119
+ platform: "neutral",
120
+ format: "esm",
121
+ target: "es2022",
122
+ outfile: here("../dist/remote-reception.js"),
123
+ packages: "external",
124
+ legalComments: "none",
125
+ logLevel: "warning",
126
+ metafile: true,
127
+ });
128
+ normalizeGeneratedText(here("../dist/remote-reception.js"));
129
+ const remoteReceptionCommonJsBuild = await build({
130
+ entryPoints: [here("../src/remote_reception.ts")],
131
+ // Resolve node_modules by the path it is reached at, not its real path: a bundle's module
132
+ // comments name that path, so a committed-snapshot build (whose node_modules is a link to the
133
+ // installed one) and a checkout build emit the same bytes.
134
+ preserveSymlinks: true,
135
+ bundle: true,
136
+ platform: "node",
137
+ format: "cjs",
138
+ target: "node18",
139
+ outfile: here("../dist/remote-reception.cjs"),
140
+ packages: "external",
141
+ legalComments: "none",
142
+ logLevel: "warning",
143
+ metafile: true,
144
+ });
145
+ normalizeGeneratedText(here("../dist/remote-reception.cjs"));
146
+ console.error("✓ built Remote Reception ESM + CommonJS (typed HTTP correspondence only)");
147
+
148
+ // PROPAGATE the built bundles into nomos_flutter/assets (the Flutter package ships them verbatim — see its
149
+ // pubspec `assets:`). Doing it HERE keeps the asset in lockstep with the build: a stale asset is exactly how a
150
+ // shim fix (e.g. the JSC TextEncoder polyfill) failed to reach the native app and a tenant had to patch the
151
+ // Dart layer instead. One build, one set of bytes, every peer. (nomos_flutter is a sibling package, not an npm
152
+ // dep, so the copy is the sync.)
153
+ const FLUTTER_ASSETS = here("../../../nomos_flutter/assets");
154
+ if (existsSync(FLUTTER_ASSETS)) {
155
+ for (const f of ["nomos-runner.js", "nomos-runner.html", "nomos-native-runtime.js"]) {
156
+ copyFileSync(here(`../dist/${f}`), join(FLUTTER_ASSETS, f));
157
+ }
158
+ console.error("✓ synced browser shell and shared Peer Office assets → nomos_flutter/assets");
159
+ }
160
+
161
+ console.error("✓ built browser shell and shared Peer Office runtime bundles");
162
+
163
+ // ── THE PUBLISHED NODE RUNNER ENTRY (co2 tenant DEFECT P3-002) ────────────────────────────────────────
164
+ // `runner/node-entry.ts` works IN-REPO (node type-strips first-party .ts) but Node REFUSES type-stripping
165
+ // under node_modules (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING) — so every PUBLISHED consumer's runner
166
+ // failed to boot. Bundle a JS twin beside it; consumers (and the Dart harness resolver) prefer the .mjs.
167
+ const nodeBuild = await build({
168
+ entryPoints: [here("../../../platform-shells/node/stdio/entry.ts")],
169
+ // Resolve node_modules by the path it is reached at, not its real path: a bundle's module
170
+ // comments name that path, so a committed-snapshot build (whose node_modules is a link to the
171
+ // installed one) and a checkout build emit the same bytes.
172
+ preserveSymlinks: true,
173
+ bundle: true,
174
+ platform: "node",
175
+ format: "esm",
176
+ define: { __NOMOS_KERNEL_RELEASE__: JSON.stringify(KERNEL_RELEASE) },
177
+ outfile: here("node-entry.mjs"),
178
+ logLevel: "warning",
179
+ metafile: true,
180
+ });
181
+ normalizeGeneratedText(here("node-entry.mjs"));
182
+ console.error("✓ built runner/node-entry.mjs (self-contained published-consumer runner)");
183
+
184
+
185
+ // The Dart package carries the same Node platform shells for its tests. It
186
+ // does not carry a second offline installer or custody lifecycle.
187
+ const DART_RUNNER = here("../../../dsl/dart/lib/src/runner");
188
+ if (existsSync(here("../../../dsl/dart"))) {
189
+ mkdirSync(DART_RUNNER, { recursive: true });
190
+ copyFileSync(here("node-entry.mjs"), join(DART_RUNNER, "node-entry.mjs"));
191
+ console.error("✓ synced the stdio node peer → nomos_client/lib/src/runner");
192
+ }
193
+
194
+ // A cheap, standard freshness proof. Rebuilding bundles merely to discover
195
+ // drift wastes minutes; esbuild already knows the exact source graph it read.
196
+ // Record those inputs as a SHA256SUMS-style manifest so CI can prove both that
197
+ // every source is unchanged and that every delivered copy is byte-identical.
198
+ const repositoryRoot = here("../../../");
199
+ const sourceInputs = new Set<string>([
200
+ ...Object.keys(browserBuild.metafile.inputs),
201
+ ...Object.keys(nativeBuild.metafile.inputs),
202
+ ...Object.keys(applicationBuild.metafile.inputs),
203
+ ...Object.keys(typescriptReceptionBuild.metafile.inputs),
204
+ ...Object.keys(remoteReceptionBuild.metafile.inputs),
205
+ ...Object.keys(remoteReceptionCommonJsBuild.metafile.inputs),
206
+ ...Object.keys(nodeBuild.metafile.inputs),
207
+ here("./build.ts"),
208
+ here("../package.json"),
209
+ here("../src/typescript_application_desk.public.d.ts"),
210
+ ]);
211
+ const sourceLines = [...sourceInputs]
212
+ .filter((input) => !input.startsWith("<"))
213
+ .map((input) => {
214
+ const absolute = isAbsolute(input) ? input : resolve(input);
215
+ const path = relative(repositoryRoot, absolute);
216
+ const digest = createHash("sha256").update(readFileSync(absolute)).digest("hex");
217
+ return `${digest} ${path}`;
218
+ })
219
+ .sort();
220
+ writeFileSync(
221
+ here("../dist/RUNTIME-SOURCES.sha256"),
222
+ `${sourceLines.join("\n")}\n`,
223
+ "utf8",
224
+ );
225
+ console.error("✓ wrote dist/RUNTIME-SOURCES.sha256 (cheap source freshness gate)");