amalgm 0.1.245 → 0.1.246

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 (157) hide show
  1. package/README.md +12 -0
  2. package/lib/cli.js +146 -8
  3. package/lib/layout.js +89 -4
  4. package/lib/shared-realtime-tunnel.js +384 -43
  5. package/lib/supervisor.js +0 -3
  6. package/package.json +2 -2
  7. package/runtime/scripts/amalgm-mcp/adapters/contract.js +197 -0
  8. package/runtime/scripts/amalgm-mcp/adapters/filesystem.js +135 -0
  9. package/runtime/scripts/amalgm-mcp/adapters/git.js +84 -0
  10. package/runtime/scripts/amalgm-mcp/adapters/index.js +43 -0
  11. package/runtime/scripts/amalgm-mcp/adapters/reference.js +31 -0
  12. package/runtime/scripts/amalgm-mcp/adapters/truth.js +19 -0
  13. package/runtime/scripts/amalgm-mcp/browser/cookie-jar.js +20 -68
  14. package/runtime/scripts/amalgm-mcp/index.js +4 -0
  15. package/runtime/scripts/amalgm-mcp/lib/layout.js +89 -4
  16. package/runtime/scripts/amalgm-mcp/observer/README.md +259 -0
  17. package/runtime/scripts/amalgm-mcp/observer/apply.js +150 -0
  18. package/runtime/scripts/amalgm-mcp/observer/continuity.js +111 -0
  19. package/runtime/scripts/amalgm-mcp/observer/edges.js +111 -0
  20. package/runtime/scripts/amalgm-mcp/observer/index.js +1146 -0
  21. package/runtime/scripts/amalgm-mcp/observer/scan.js +387 -0
  22. package/runtime/scripts/amalgm-mcp/observer/store.js +262 -0
  23. package/runtime/scripts/amalgm-mcp/observer/verify.js +200 -0
  24. package/runtime/scripts/amalgm-mcp/observer/watch.js +62 -0
  25. package/runtime/scripts/amalgm-mcp/project-context/store.js +19 -87
  26. package/runtime/scripts/amalgm-mcp/registration/classify.js +33 -0
  27. package/runtime/scripts/amalgm-mcp/registration/entity-cloud.js +456 -0
  28. package/runtime/scripts/amalgm-mcp/registration/entity-content.js +345 -0
  29. package/runtime/scripts/amalgm-mcp/registration/index.js +752 -0
  30. package/runtime/scripts/amalgm-mcp/registration/refusal.js +42 -0
  31. package/runtime/scripts/amalgm-mcp/registration/repo-followers.js +127 -0
  32. package/runtime/scripts/amalgm-mcp/registration/repo-states.js +109 -0
  33. package/runtime/scripts/amalgm-mcp/registration/service.js +310 -0
  34. package/runtime/scripts/amalgm-mcp/registration/tree.js +178 -0
  35. package/runtime/scripts/amalgm-mcp/registry/evidence.js +826 -0
  36. package/runtime/scripts/amalgm-mcp/registry/index.js +666 -0
  37. package/runtime/scripts/amalgm-mcp/registry/store.js +290 -0
  38. package/runtime/scripts/amalgm-mcp/repocard/README.md +103 -0
  39. package/runtime/scripts/amalgm-mcp/repocard/apply.js +111 -0
  40. package/runtime/scripts/amalgm-mcp/repocard/capture-worker.js +94 -0
  41. package/runtime/scripts/amalgm-mcp/repocard/capture.js +149 -0
  42. package/runtime/scripts/amalgm-mcp/repocard/follow.js +310 -0
  43. package/runtime/scripts/amalgm-mcp/repocard/git.js +48 -0
  44. package/runtime/scripts/amalgm-mcp/repocard/index.js +48 -0
  45. package/runtime/scripts/amalgm-mcp/server/local-service-router.js +2 -0
  46. package/runtime/scripts/amalgm-mcp/server/routes/entities.js +287 -0
  47. package/runtime/scripts/amalgm-mcp/server/routes/state.js +0 -13
  48. package/runtime/scripts/amalgm-mcp/state/attachments.js +11 -45
  49. package/runtime/scripts/amalgm-mcp/state/db.js +46 -215
  50. package/runtime/scripts/amalgm-mcp/state/docs.js +301 -1101
  51. package/runtime/scripts/amalgm-mcp/state/mutation-contracts.js +0 -99
  52. package/runtime/scripts/amalgm-mcp/state/mutations.js +130 -507
  53. package/runtime/scripts/amalgm-mcp/state/promotions.js +1 -21
  54. package/runtime/scripts/amalgm-mcp/state/replicas.js +13 -134
  55. package/runtime/scripts/amalgm-mcp/state/shared-rest.js +3 -46
  56. package/runtime/scripts/amalgm-mcp/tests/adapters.test.js +379 -0
  57. package/runtime/scripts/amalgm-mcp/tests/browser-cookie-cloud.test.js +0 -193
  58. package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.life.test.js +449 -0
  59. package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.rig.js +107 -0
  60. package/runtime/scripts/amalgm-mcp/tests/doorbell.matrix.watch.test.js +213 -0
  61. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/adapter.js +72 -0
  62. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/assert.js +497 -0
  63. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/bind.js +91 -0
  64. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/graph.js +1031 -0
  65. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/ledger.js +234 -0
  66. package/runtime/scripts/amalgm-mcp/tests/entity-oracle/referee.js +118 -0
  67. package/runtime/scripts/amalgm-mcp/tests/entity.oracle.test.js +1365 -0
  68. package/runtime/scripts/amalgm-mcp/tests/entity.registry.test.js +967 -0
  69. package/runtime/scripts/amalgm-mcp/tests/entity.rig.js +239 -0
  70. package/runtime/scripts/amalgm-mcp/tests/entity.storm.test.js +486 -0
  71. package/runtime/scripts/amalgm-mcp/tests/fake-watch.js +35 -0
  72. package/runtime/scripts/amalgm-mcp/tests/observer.links.test.js +289 -0
  73. package/runtime/scripts/amalgm-mcp/tests/observer.rig.js +103 -0
  74. package/runtime/scripts/amalgm-mcp/tests/observer.roots.test.js +505 -0
  75. package/runtime/scripts/amalgm-mcp/tests/observer.storm.test.js +389 -0
  76. package/runtime/scripts/amalgm-mcp/tests/observer.territory.test.js +845 -0
  77. package/runtime/scripts/amalgm-mcp/tests/observer.test.js +657 -0
  78. package/runtime/scripts/amalgm-mcp/tests/project-context.test.js +17 -32
  79. package/runtime/scripts/amalgm-mcp/tests/registration.service.test.js +256 -0
  80. package/runtime/scripts/amalgm-mcp/tests/registration.test.js +931 -0
  81. package/runtime/scripts/amalgm-mcp/tests/repocard.storm.test.js +284 -0
  82. package/runtime/scripts/amalgm-mcp/tests/repocard.test.js +371 -0
  83. package/runtime/scripts/amalgm-mcp/tests/repofollow.storm.test.js +435 -0
  84. package/runtime/scripts/amalgm-mcp/tests/repofollow.test.js +675 -0
  85. package/runtime/scripts/amalgm-mcp/tests/shared-tunnel-rehydration.test.js +0 -84
  86. package/runtime/scripts/amalgm-mcp/tests/state-docs.test.js +13 -376
  87. package/runtime/scripts/amalgm-mcp/tests/state-mutations.test.js +0 -309
  88. package/runtime/scripts/amalgm-mcp/tests/state-shared-replica.test.js +30 -758
  89. package/runtime/scripts/amalgm-mcp/tests/workspace-cards-store.test.js +3 -72
  90. package/runtime/scripts/amalgm-mcp/tests/workspace-cards.test.js +1 -89
  91. package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint-reducer.test.js +24 -55
  92. package/runtime/scripts/amalgm-mcp/tests/workspace-checkpoint.test.js +141 -424
  93. package/runtime/scripts/amalgm-mcp/tests/workspace-object-tunnel.test.js +3 -171
  94. package/runtime/scripts/amalgm-mcp/tests/workspace-objects.test.js +7 -220
  95. package/runtime/scripts/amalgm-mcp/tests/workspace-publication-invariants.test.js +236 -179
  96. package/runtime/scripts/amalgm-mcp/tests/workspace-reducer.test.js +326 -2228
  97. package/runtime/scripts/amalgm-mcp/tests/workspace-tree-cloud.test.js +3 -5319
  98. package/runtime/scripts/amalgm-mcp/tests/workspace-tree-core.test.js +1 -191
  99. package/runtime/scripts/amalgm-mcp/tests/workspace-tree-store.test.js +17 -3140
  100. package/runtime/scripts/amalgm-mcp/tests/workspace-wall.test.js +740 -137
  101. package/runtime/scripts/amalgm-mcp/workspace/access-store.js +1 -5
  102. package/runtime/scripts/amalgm-mcp/workspace/card.js +11 -35
  103. package/runtime/scripts/amalgm-mcp/workspace/cards.js +14 -39
  104. package/runtime/scripts/amalgm-mcp/workspace/checkpoint.js +147 -587
  105. package/runtime/scripts/amalgm-mcp/workspace/git.js +34 -406
  106. package/runtime/scripts/amalgm-mcp/workspace/merge.js +181 -102
  107. package/runtime/scripts/amalgm-mcp/workspace/objects.js +56 -221
  108. package/runtime/scripts/amalgm-mcp/workspace/reducer.js +538 -1964
  109. package/runtime/scripts/amalgm-mcp/workspace/rest.js +28 -49
  110. package/runtime/scripts/amalgm-mcp/workspace/store.js +4 -77
  111. package/runtime/scripts/amalgm-mcp/workspace/transition.js +192 -1734
  112. package/runtime/scripts/amalgm-mcp/workspace/tree/inclusion.js +1 -7
  113. package/runtime/scripts/amalgm-mcp/workspace/tree/local-state.js +61 -73
  114. package/runtime/scripts/amalgm-mcp/workspace/tree/reducer.js +6 -51
  115. package/runtime/scripts/amalgm-mcp/workspace/tree/snapshot.js +8 -79
  116. package/runtime/scripts/amalgm-mcp/workspace/tree-cloud.js +146 -3461
  117. package/runtime/scripts/amalgm-mcp/workspace/tree-store.js +71 -899
  118. package/runtime/scripts/amalgm-mcp/workspace/wall.js +538 -370
  119. package/runtime/scripts/local-gateway.js +1 -0
  120. package/runtime/scripts/amalgm-mcp/state/doc-disk.js +0 -550
  121. package/runtime/scripts/amalgm-mcp/tests/code-project-stream.test.js +0 -399
  122. package/runtime/scripts/amalgm-mcp/tests/fixtures/code-project-stream-v2.json +0 -1
  123. package/runtime/scripts/amalgm-mcp/tests/workspace-durable.test.js +0 -24
  124. package/runtime/scripts/amalgm-mcp/tests/workspace-local-intent.test.js +0 -1999
  125. package/runtime/scripts/amalgm-mcp/tests/workspace-native-file-transaction.test.js +0 -364
  126. package/runtime/scripts/amalgm-mcp/tests/workspace-provenance.test.js +0 -185
  127. package/runtime/scripts/amalgm-mcp/tests/workspace-reducer-liveness.test.js +0 -26
  128. package/runtime/scripts/amalgm-mcp/tests/workspace-sync-stats.test.js +0 -119
  129. package/runtime/scripts/amalgm-mcp/tests/workspace-transition.test.js +0 -1446
  130. package/runtime/scripts/amalgm-mcp/workspace/content.js +0 -32
  131. package/runtime/scripts/amalgm-mcp/workspace/durable.js +0 -45
  132. package/runtime/scripts/amalgm-mcp/workspace/intent.js +0 -535
  133. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/BUILD.md +0 -31
  134. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/darwin-arm64/amalgm-file-transaction +0 -0
  135. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/bin/linux-x64/amalgm-file-transaction +0 -0
  136. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/build.mjs +0 -72
  137. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/client.js +0 -165
  138. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.mod +0 -5
  139. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/go.sum +0 -2
  140. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/main.go +0 -2201
  141. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/manifest.json +0 -19
  142. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_darwin.go +0 -18
  143. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/move_linux.go +0 -18
  144. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_darwin.go +0 -33
  145. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/process_linux.go +0 -47
  146. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/verify.mjs +0 -43
  147. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_darwin.go +0 -114
  148. package/runtime/scripts/amalgm-mcp/workspace/native-file-transaction/writers_linux.go +0 -84
  149. package/runtime/scripts/amalgm-mcp/workspace/project-stream.js +0 -771
  150. package/runtime/scripts/amalgm-mcp/workspace/provenance.js +0 -240
  151. package/runtime/scripts/amalgm-mcp/workspace/sync-stats.js +0 -240
  152. package/runtime/scripts/amalgm-mcp/workspace/tree/floor.js +0 -100
  153. package/runtime/scripts/amalgm-mcp/workspace/tree/observation-holds.js +0 -127
  154. package/runtime/scripts/amalgm-mcp/workspace/tree/path-state.js +0 -12
  155. package/runtime/scripts/amalgm-mcp/workspace/tree/root-binding.js +0 -125
  156. package/runtime/scripts/amalgm-mcp/workspace/tree/symlinks.js +0 -76
  157. package/runtime/scripts/amalgm-mcp/workspace/tree-materialization.js +0 -3766
@@ -17,6 +17,10 @@ const CLAIM_LIMIT = 16;
17
17
  const CLAIM_LEASE_MS = 30_000;
18
18
  const RETRY_MS = 1_000;
19
19
  const REAUTHORIZE_MS = 30_000;
20
+ const REPO_OBJECT_REQUEST_TIMEOUT_MS = 15_000;
21
+ const COOKIE_PRIVATE_CONTRACT = 'browser-cookie-jar@1';
22
+ const USER_HOME_PRIVATE_CONTRACT = 'amalgm-user-home@1';
23
+ const ENTITY_REGISTRY_PRIVATE_CONTRACT = 'amalgm-entity-registry@1';
20
24
 
21
25
  function createSharedRealtimeTunnel({
22
26
  send,
@@ -24,8 +28,11 @@ function createSharedRealtimeTunnel({
24
28
  localPort,
25
29
  localHeaders,
26
30
  warn,
31
+ repoObjectRequestTimeoutMs = REPO_OBJECT_REQUEST_TIMEOUT_MS,
27
32
  }) {
28
33
  const mutationInflight = new Map();
34
+ const entityMutationInflight = new Map();
35
+ const entityContentInflight = new Map();
29
36
  const promotionInflight = new Map();
30
37
  const attachmentInflight = new Map();
31
38
  const privateEnsureInflight = new Map();
@@ -37,19 +44,28 @@ function createSharedRealtimeTunnel({
37
44
  let enabled = false;
38
45
  let presenceEnabled = false;
39
46
  let mutationDrain = null;
47
+ let entityMutationDrain = null;
48
+ let entityContentDrain = null;
40
49
  let promotionDrain = null;
41
50
  let attachmentDrain = null;
42
51
  let wakeRequest = null;
43
52
  let wakeRetryTimer = null;
44
53
  let mutationRetryTimer = null;
54
+ let entityMutationRetryTimer = null;
55
+ let entityContentRetryTimer = null;
45
56
  let promotionRetryTimer = null;
46
57
  let attachmentRetryTimer = null;
47
58
  let reauthorizeTimer = null;
48
59
  let repoObjectTimer = null;
49
60
  let localFailures = 0;
61
+ let userHomeReady = false;
62
+
63
+ function privateInflightFor(contract) {
64
+ return [...privateEnsureInflight.values()].some((entry) => entry.contract === contract);
65
+ }
50
66
 
51
67
  async function ensurePrivateCookieResource() {
52
- if (!enabled || privateEnsureInflight.size > 0) return;
68
+ if (!enabled || privateInflightFor(COOKIE_PRIVATE_CONTRACT)) return;
53
69
  try {
54
70
  const bootstrap = await localStateJson('GET', '/browser/cookie-jar/cloud/bootstrap');
55
71
  if (!bootstrap?.enabled || !bootstrap.resourceId) return;
@@ -67,12 +83,131 @@ function createSharedRealtimeTunnel({
67
83
  scheduleMutationDrain(RETRY_MS);
68
84
  return;
69
85
  }
70
- privateEnsureInflight.set(requestId, bootstrap.resourceId);
86
+ privateEnsureInflight.set(requestId, {
87
+ resourceId: bootstrap.resourceId,
88
+ contract: COOKIE_PRIVATE_CONTRACT,
89
+ phase: 'ensure',
90
+ });
71
91
  } catch (error) {
72
92
  warn(`private cookie bootstrap unavailable: ${error?.message || error}`);
73
93
  }
74
94
  }
75
95
 
96
+ async function ensurePrivateUserHome() {
97
+ if (!enabled || privateInflightFor(USER_HOME_PRIVATE_CONTRACT)) return;
98
+ try {
99
+ const identity = await localStateJson('GET', '/entities/user-home/cloud/identity');
100
+ if (!identity?.enabled || !identity.resourceId) return;
101
+ const requestId = `private_home_lookup_${crypto.randomBytes(12).toString('hex')}`;
102
+ if (!sendLarge({
103
+ type: 'private.resource.lookup',
104
+ request_id: requestId,
105
+ resource_id: identity.resourceId,
106
+ contract: identity.contract,
107
+ })) {
108
+ scheduleMutationDrain(RETRY_MS);
109
+ return;
110
+ }
111
+ privateEnsureInflight.set(requestId, {
112
+ resourceId: identity.resourceId,
113
+ contract: USER_HOME_PRIVATE_CONTRACT,
114
+ phase: 'lookup',
115
+ });
116
+ } catch (error) {
117
+ warn(`private user-home lookup unavailable: ${error?.message || error}`);
118
+ }
119
+ }
120
+
121
+ async function createPrivateUserHome(resourceId) {
122
+ try {
123
+ const bootstrap = await localStateJson('GET', '/entities/user-home/cloud/bootstrap');
124
+ if (!bootstrap?.enabled || bootstrap.resourceId !== resourceId) {
125
+ throw new Error('local user-home bootstrap identity changed');
126
+ }
127
+ const requestId = `private_home_ensure_${crypto.randomBytes(12).toString('hex')}`;
128
+ if (!sendLarge({
129
+ type: 'private.resource.ensure',
130
+ request_id: requestId,
131
+ resource_id: bootstrap.resourceId,
132
+ contract: bootstrap.contract,
133
+ schema_version: bootstrap.schemaVersion,
134
+ snapshot_b64: bootstrap.snapshotBase64,
135
+ snapshot_checksum: bootstrap.snapshotChecksum,
136
+ snapshot_bytes: bootstrap.snapshotBytes,
137
+ })) {
138
+ scheduleMutationDrain(RETRY_MS);
139
+ return;
140
+ }
141
+ privateEnsureInflight.set(requestId, {
142
+ resourceId: bootstrap.resourceId,
143
+ contract: USER_HOME_PRIVATE_CONTRACT,
144
+ phase: 'ensure',
145
+ });
146
+ } catch (error) {
147
+ warn(`private user-home bootstrap unavailable: ${error?.message || error}`);
148
+ setTimeout(() => enabled && void ensurePrivateUserHome(), RETRY_MS).unref?.();
149
+ }
150
+ }
151
+
152
+ async function ensurePrivateEntityRegistry() {
153
+ // The user-home snapshot is the root UUID handshake. Creating the
154
+ // universal graph before it lands risks minting a competing bootstrap
155
+ // graph on a newly reinstalled machine.
156
+ if (!enabled || !userHomeReady || privateInflightFor(ENTITY_REGISTRY_PRIVATE_CONTRACT)) return;
157
+ try {
158
+ const identity = await localStateJson('GET', '/entities/cloud/identity');
159
+ if (!identity?.enabled || !identity.resourceId) return;
160
+ const requestId = `private_entities_lookup_${crypto.randomBytes(12).toString('hex')}`;
161
+ if (!sendLarge({
162
+ type: 'private.resource.lookup',
163
+ request_id: requestId,
164
+ resource_id: identity.resourceId,
165
+ contract: identity.contract,
166
+ })) {
167
+ scheduleEntityMutationDrain(RETRY_MS);
168
+ return;
169
+ }
170
+ privateEnsureInflight.set(requestId, {
171
+ resourceId: identity.resourceId,
172
+ contract: ENTITY_REGISTRY_PRIVATE_CONTRACT,
173
+ phase: 'lookup',
174
+ });
175
+ } catch (error) {
176
+ warn(`private entity registry lookup unavailable: ${error?.message || error}`);
177
+ }
178
+ }
179
+
180
+ async function createPrivateEntityRegistry(resourceId) {
181
+ try {
182
+ const bootstrap = await localStateJson('GET', '/entities/cloud/bootstrap');
183
+ if (!bootstrap?.enabled || bootstrap.resourceId !== resourceId) {
184
+ throw new Error('local entity registry bootstrap identity changed');
185
+ }
186
+ const requestId = `private_entities_ensure_${crypto.randomBytes(12).toString('hex')}`;
187
+ if (!sendLarge({
188
+ type: 'private.resource.ensure',
189
+ request_id: requestId,
190
+ resource_id: bootstrap.resourceId,
191
+ contract: bootstrap.contract,
192
+ schema_version: bootstrap.schemaVersion,
193
+ snapshot_b64: bootstrap.snapshotBase64,
194
+ snapshot_checksum: bootstrap.snapshotChecksum,
195
+ snapshot_bytes: bootstrap.snapshotBytes,
196
+ })) {
197
+ scheduleEntityMutationDrain(RETRY_MS);
198
+ return;
199
+ }
200
+ privateEnsureInflight.set(requestId, {
201
+ resourceId: bootstrap.resourceId,
202
+ contract: ENTITY_REGISTRY_PRIVATE_CONTRACT,
203
+ phase: 'ensure',
204
+ });
205
+ } catch (error) {
206
+ warn(`private entity registry bootstrap unavailable: ${error?.message || error}`);
207
+ setTimeout(() => enabled && void ensurePrivateEntityRegistry(), RETRY_MS).unref?.();
208
+ }
209
+ }
210
+
76
211
  function localStateJson(method, requestPath, body) {
77
212
  const payload = body === undefined ? null : Buffer.from(JSON.stringify(body));
78
213
  return new Promise((resolve, reject) => {
@@ -124,6 +259,24 @@ function createSharedRealtimeTunnel({
124
259
  mutationRetryTimer.unref?.();
125
260
  }
126
261
 
262
+ function scheduleEntityMutationDrain(delay = 0) {
263
+ if (!enabled || entityMutationRetryTimer) return;
264
+ entityMutationRetryTimer = setTimeout(() => {
265
+ entityMutationRetryTimer = null;
266
+ void drainEntityCloudMutations();
267
+ }, delay);
268
+ entityMutationRetryTimer.unref?.();
269
+ }
270
+
271
+ function scheduleEntityContentDrain(delay = 0) {
272
+ if (!enabled || entityContentRetryTimer) return;
273
+ entityContentRetryTimer = setTimeout(() => {
274
+ entityContentRetryTimer = null;
275
+ void drainEntityContent();
276
+ }, delay);
277
+ entityContentRetryTimer.unref?.();
278
+ }
279
+
127
280
  function schedulePromotionDrain(delay = 0) {
128
281
  if (!enabled || promotionRetryTimer) return;
129
282
  promotionRetryTimer = setTimeout(() => {
@@ -142,10 +295,6 @@ function createSharedRealtimeTunnel({
142
295
  attachmentRetryTimer.unref?.();
143
296
  }
144
297
 
145
- function alreadyInflight(inflight, matches) {
146
- return [...inflight.values()].some(matches);
147
- }
148
-
149
298
  async function drainMutations() {
150
299
  if (!enabled || mutationDrain) return;
151
300
  mutationDrain = (async () => {
@@ -156,10 +305,6 @@ function createSharedRealtimeTunnel({
156
305
  for (const claim of Array.isArray(result?.mutations) ? result.mutations : []) {
157
306
  const envelope = claim?.envelope;
158
307
  if (!envelope?.resourceId || !envelope?.mutationId) continue;
159
- if (alreadyInflight(mutationInflight, (entry) => (
160
- entry.resourceId === envelope.resourceId
161
- && entry.mutationId === envelope.mutationId
162
- ))) continue;
163
308
  const requestId = `shared_${crypto.randomBytes(12).toString('hex')}`;
164
309
  if (!sendLarge({ type: 'shared.mutation.submit', request_id: requestId, envelope })) {
165
310
  await failMutationClaim(claim, 'shared tunnel backpressure: mutation was not queued');
@@ -184,6 +329,103 @@ function createSharedRealtimeTunnel({
184
329
  await mutationDrain;
185
330
  }
186
331
 
332
+ async function drainEntityCloudMutations() {
333
+ if (!enabled || entityMutationDrain) return;
334
+ entityMutationDrain = (async () => {
335
+ const result = await localStateJson('POST', '/entities/cloud/mutations/claim', {
336
+ limit: CLAIM_LIMIT,
337
+ leaseMs: CLAIM_LEASE_MS,
338
+ });
339
+ for (const envelope of Array.isArray(result?.mutations) ? result.mutations : []) {
340
+ if (!envelope?.resourceId || !envelope?.mutationId) continue;
341
+ const requestId = `entities_${crypto.randomBytes(12).toString('hex')}`;
342
+ if (!sendLarge({ type: 'shared.mutation.submit', request_id: requestId, envelope })) {
343
+ await failEntityMutation(envelope, 'shared tunnel backpressure: entity mutation was not queued');
344
+ scheduleEntityMutationDrain(RETRY_MS);
345
+ continue;
346
+ }
347
+ entityMutationInflight.set(requestId, {
348
+ resourceId: envelope.resourceId,
349
+ mutationId: envelope.mutationId,
350
+ });
351
+ }
352
+ localFailures = 0;
353
+ })().catch((error) => {
354
+ localFailures += 1;
355
+ if (localFailures === 1 || localFailures % 20 === 0) {
356
+ warn(`entity outbox unavailable (attempt ${localFailures}): ${error?.message || error}`);
357
+ }
358
+ scheduleEntityMutationDrain(RETRY_MS);
359
+ }).finally(() => {
360
+ entityMutationDrain = null;
361
+ });
362
+ await entityMutationDrain;
363
+ }
364
+
365
+ async function drainEntityContent() {
366
+ if (!enabled || entityContentDrain) return;
367
+ entityContentDrain = (async () => {
368
+ const result = await localStateJson('POST', '/entities/cloud/content/claim', {
369
+ leaseMs: CLAIM_LEASE_MS,
370
+ });
371
+ const upload = result?.upload;
372
+ if (!upload?.resourceId || !upload?.contentHash || !upload?.kind) return;
373
+ const requestId = `entity_content_${crypto.randomBytes(12).toString('hex')}`;
374
+ if (!sendLarge({
375
+ type: 'private.entity-content.put',
376
+ request_id: requestId,
377
+ resource_id: upload.resourceId,
378
+ content_hash: upload.contentHash,
379
+ kind: upload.kind,
380
+ part_index: upload.partIndex,
381
+ part_count: upload.partCount,
382
+ sha256: upload.sha256,
383
+ bytes: upload.bytes,
384
+ data_b64: upload.dataBase64,
385
+ })) {
386
+ await failEntityContent(upload, 'shared tunnel backpressure: entity content was not queued');
387
+ scheduleEntityContentDrain(RETRY_MS);
388
+ return;
389
+ }
390
+ entityContentInflight.set(requestId, upload);
391
+ })().catch((error) => {
392
+ localFailures += 1;
393
+ if (localFailures === 1 || localFailures % 20 === 0) {
394
+ warn(`entity content outbox unavailable (attempt ${localFailures}): ${error?.message || error}`);
395
+ }
396
+ scheduleEntityContentDrain(RETRY_MS);
397
+ }).finally(() => {
398
+ entityContentDrain = null;
399
+ });
400
+ await entityContentDrain;
401
+ }
402
+
403
+ async function failEntityContent(upload, message) {
404
+ try {
405
+ await localStateJson('POST', '/entities/cloud/content/fail', {
406
+ resourceId: upload.resourceId,
407
+ contentHash: upload.contentHash,
408
+ message,
409
+ });
410
+ } catch {
411
+ // The durable local content ledger leaves the upload claimable after
412
+ // its lease, even if this failure response cannot reach the runtime.
413
+ }
414
+ }
415
+
416
+ async function failEntityMutation(envelope, message) {
417
+ try {
418
+ await localStateJson('POST', '/entities/cloud/mutations/fail', {
419
+ resourceId: envelope.resourceId,
420
+ mutationId: envelope.mutationId,
421
+ message,
422
+ retryable: true,
423
+ });
424
+ } catch {
425
+ // The durable identity-db lease makes the row claimable after expiry.
426
+ }
427
+ }
428
+
187
429
  async function failMutationClaim(claim, message) {
188
430
  try {
189
431
  await localStateJson('POST', '/state/mutations/fail', {
@@ -207,9 +449,6 @@ function createSharedRealtimeTunnel({
207
449
  for (const claim of Array.isArray(result?.promotions) ? result.promotions : []) {
208
450
  const promotion = claim?.frame;
209
451
  if (!promotion?.promotionId || !promotion?.resourceId) continue;
210
- if (alreadyInflight(promotionInflight, (entry) => (
211
- entry.promotionId === promotion.promotionId
212
- ))) continue;
213
452
  const requestId = `promote_${crypto.randomBytes(12).toString('hex')}`;
214
453
  const queued = sendLarge({
215
454
  type: 'shared.resource.promote',
@@ -256,9 +495,6 @@ function createSharedRealtimeTunnel({
256
495
  });
257
496
  for (const attachment of Array.isArray(result?.attachments) ? result.attachments : []) {
258
497
  if (!attachment?.attachmentId || !attachment?.resourceId) continue;
259
- if (alreadyInflight(attachmentInflight, (entry) => (
260
- entry.attachmentId === attachment.attachmentId
261
- ))) continue;
262
498
  const requestId = `attach_${crypto.randomBytes(12).toString('hex')}`;
263
499
  if (!send({
264
500
  type: 'shared.resource.attach',
@@ -291,10 +527,17 @@ function createSharedRealtimeTunnel({
291
527
  repoObjectTimer.unref?.();
292
528
  }
293
529
 
530
+ function expireRepoObjectRequests(now = Date.now()) {
531
+ for (const inflight of [repoUploadInflight, repoDownloadInflight]) {
532
+ for (const [requestId, object] of inflight) {
533
+ if (now - object.sentAt >= repoObjectRequestTimeoutMs) inflight.delete(requestId);
534
+ }
535
+ }
536
+ }
537
+
294
538
  async function drainRepoObjects() {
295
539
  if (!enabled) return;
296
- // One ordered WebSocket carries one request until its reply. A disconnect
297
- // clears this map and the durable local queue resends after reconnect.
540
+ expireRepoObjectRequests();
298
541
  if (repoUploadInflight.size === 0) {
299
542
  const result = await localStateJson('POST', '/state/repo-objects/uploads/claim', {});
300
543
  const upload = result?.upload;
@@ -311,6 +554,7 @@ function createSharedRealtimeTunnel({
311
554
  repoUploadInflight.set(requestId, {
312
555
  resourceId: upload.resourceId,
313
556
  sha256: upload.sha256,
557
+ sentAt: Date.now(),
314
558
  });
315
559
  }
316
560
  }
@@ -329,6 +573,7 @@ function createSharedRealtimeTunnel({
329
573
  repoDownloadInflight.set(requestId, {
330
574
  resourceId: download.resourceId,
331
575
  sha256: download.sha256,
576
+ sentAt: Date.now(),
332
577
  });
333
578
  }
334
579
  }
@@ -470,10 +715,14 @@ function createSharedRealtimeTunnel({
470
715
  if (!enabled) return;
471
716
  startWakeStream();
472
717
  void ensurePrivateCookieResource();
718
+ void ensurePrivateUserHome();
719
+ if (userHomeReady) void ensurePrivateEntityRegistry();
473
720
  void joinReplicas();
474
721
  scheduleAttachmentDrain();
475
722
  schedulePromotionDrain();
476
723
  scheduleMutationDrain();
724
+ scheduleEntityContentDrain();
725
+ scheduleEntityMutationDrain();
477
726
  scheduleRepoObjects();
478
727
  }
479
728
 
@@ -521,6 +770,26 @@ function createSharedRealtimeTunnel({
521
770
  });
522
771
  }
523
772
 
773
+ function handlePrivateEntityContentStored(frame) {
774
+ const upload = entityContentInflight.get(frame.request_id);
775
+ if (!upload || upload.contentHash !== frame.content_hash || upload.kind !== frame.kind
776
+ || upload.partIndex !== frame.part_index) return;
777
+ void localStateJson('POST', '/entities/cloud/content/ack', {
778
+ resourceId: upload.resourceId,
779
+ contentHash: upload.contentHash,
780
+ kind: upload.kind,
781
+ partIndex: upload.partIndex,
782
+ }).then(() => {
783
+ entityContentInflight.delete(frame.request_id);
784
+ // A completed manifest may unblock the first entity mutation that
785
+ // names this exact head, so advance both rails immediately.
786
+ scheduleEntityContentDrain();
787
+ scheduleEntityMutationDrain();
788
+ }).catch(() => {
789
+ setTimeout(() => enabled && handlePrivateEntityContentStored(frame), RETRY_MS).unref?.();
790
+ });
791
+ }
792
+
524
793
  function handleAttached(frame) {
525
794
  const identity = attachmentInflight.get(frame.request_id);
526
795
  if (!identity) return;
@@ -545,13 +814,9 @@ function createSharedRealtimeTunnel({
545
814
  void localStateJson('POST', '/state/shared/attachments/fail', {
546
815
  attachmentId: identity.attachmentId,
547
816
  message: error?.message || 'local snapshot materialization failed',
548
- // The gateway already authorized and completed this attachment.
549
- // A local materialization failure is weather (busy disk, concurrent
550
- // save, restart), never proof that the binding is permanently bad.
551
- retryable: true,
817
+ retryable: false,
552
818
  }).catch(() => {});
553
819
  attachmentInflight.delete(frame.request_id);
554
- scheduleAttachmentDrain(RETRY_MS);
555
820
  });
556
821
  }
557
822
 
@@ -576,9 +841,17 @@ function createSharedRealtimeTunnel({
576
841
  }
577
842
 
578
843
  function handlePrivateReady(frame) {
579
- const resourceId = privateEnsureInflight.get(frame.request_id);
580
- if (!resourceId || resourceId !== frame.resource_id) return;
581
- void localStateJson('POST', '/browser/cookie-jar/cloud/install', {
844
+ const inflight = privateEnsureInflight.get(frame.request_id);
845
+ if (!inflight || inflight.resourceId !== frame.resource_id) return;
846
+ const installPath = inflight.contract === COOKIE_PRIVATE_CONTRACT
847
+ ? '/browser/cookie-jar/cloud/install'
848
+ : inflight.contract === USER_HOME_PRIVATE_CONTRACT
849
+ ? '/entities/user-home/cloud/install'
850
+ : inflight.contract === ENTITY_REGISTRY_PRIVATE_CONTRACT
851
+ ? '/entities/cloud/install'
852
+ : null;
853
+ if (!installPath) return;
854
+ void localStateJson('POST', installPath, {
582
855
  resourceId: frame.resource_id,
583
856
  authorityEpoch: frame.authority_epoch,
584
857
  headVersion: frame.head_version,
@@ -589,15 +862,47 @@ function createSharedRealtimeTunnel({
589
862
  schemaVersion: frame.schema_version,
590
863
  }).then(() => {
591
864
  privateEnsureInflight.delete(frame.request_id);
865
+ if (inflight.contract === USER_HOME_PRIVATE_CONTRACT) {
866
+ userHomeReady = true;
867
+ void ensurePrivateEntityRegistry();
868
+ }
592
869
  void joinReplicas();
593
870
  scheduleMutationDrain();
871
+ scheduleEntityContentDrain();
872
+ scheduleEntityMutationDrain();
594
873
  }).catch((error) => {
595
- warn(`private cookie snapshot was not installed: ${error?.message || error}`);
874
+ warn(`private ${inflight.contract} snapshot was not installed: ${error?.message || error}`);
596
875
  setTimeout(() => enabled && handlePrivateReady(frame), RETRY_MS).unref?.();
597
876
  });
598
877
  }
599
878
 
879
+ function handlePrivateMissing(frame) {
880
+ const inflight = privateEnsureInflight.get(frame.request_id);
881
+ if (!inflight || inflight.resourceId !== frame.resource_id || inflight.phase !== 'lookup') return;
882
+ privateEnsureInflight.delete(frame.request_id);
883
+ if (inflight.contract === USER_HOME_PRIVATE_CONTRACT) {
884
+ void createPrivateUserHome(inflight.resourceId);
885
+ } else if (inflight.contract === ENTITY_REGISTRY_PRIVATE_CONTRACT) {
886
+ void createPrivateEntityRegistry(inflight.resourceId);
887
+ }
888
+ }
889
+
600
890
  function handleAck(frame) {
891
+ const entityIdentity = entityMutationInflight.get(frame.request_id);
892
+ if (entityIdentity) {
893
+ void localStateJson('POST', '/entities/cloud/mutations/ack', {
894
+ resourceId: entityIdentity.resourceId,
895
+ mutationId: entityIdentity.mutationId,
896
+ version: frame.version,
897
+ committedAt: frame.committed_at,
898
+ }).then(() => {
899
+ entityMutationInflight.delete(frame.request_id);
900
+ scheduleEntityMutationDrain();
901
+ }).catch(() => {
902
+ setTimeout(() => enabled && handleAck(frame), RETRY_MS).unref?.();
903
+ });
904
+ return;
905
+ }
601
906
  const identity = mutationInflight.get(frame.request_id) || {
602
907
  resourceId: frame.resource_id,
603
908
  mutationId: frame.mutation_id,
@@ -618,18 +923,9 @@ function createSharedRealtimeTunnel({
618
923
  }
619
924
 
620
925
  function handleError(frame) {
621
- const failedUpload = repoUploadInflight.get(frame.request_id);
622
- if (failedUpload) {
623
- void localStateJson('POST', '/state/repo-objects/uploads/fail', {
624
- resourceId: failedUpload.resourceId,
625
- sha256: failedUpload.sha256,
626
- retryable: frame.retryable !== false,
627
- code: frame.code,
628
- message: frame.message,
629
- }).finally(() => {
630
- repoUploadInflight.delete(frame.request_id);
631
- scheduleRepoObjects();
632
- });
926
+ if (repoUploadInflight.has(frame.request_id)) {
927
+ repoUploadInflight.delete(frame.request_id);
928
+ scheduleRepoObjects(RETRY_MS);
633
929
  return;
634
930
  }
635
931
  if (repoDownloadInflight.has(frame.request_id)) {
@@ -637,12 +933,26 @@ function createSharedRealtimeTunnel({
637
933
  scheduleRepoObjects(RETRY_MS);
638
934
  return;
639
935
  }
936
+ const content = entityContentInflight.get(frame.request_id);
937
+ if (content) {
938
+ void failEntityContent(content, `${frame.code || 'shared_error'}: ${frame.message || 'entity content failed'}`)
939
+ .finally(() => {
940
+ entityContentInflight.delete(frame.request_id);
941
+ if (frame.retryable !== false) scheduleEntityContentDrain(RETRY_MS);
942
+ });
943
+ return;
944
+ }
640
945
  const privateResource = privateEnsureInflight.get(frame.request_id);
641
946
  if (privateResource) {
642
947
  privateEnsureInflight.delete(frame.request_id);
643
- warn(`private cookie bootstrap failed for ${privateResource}: ${frame.code || 'shared_error'}: ${frame.message || ''}`);
948
+ warn(`private ${privateResource.contract} bootstrap failed for ${privateResource.resourceId}: ${frame.code || 'shared_error'}: ${frame.message || ''}`);
644
949
  if (frame.retryable !== false) {
645
- setTimeout(() => enabled && void ensurePrivateCookieResource(), RETRY_MS).unref?.();
950
+ const retry = privateResource.contract === USER_HOME_PRIVATE_CONTRACT
951
+ ? ensurePrivateUserHome
952
+ : privateResource.contract === ENTITY_REGISTRY_PRIVATE_CONTRACT
953
+ ? ensurePrivateEntityRegistry
954
+ : ensurePrivateCookieResource;
955
+ setTimeout(() => enabled && void retry(), RETRY_MS).unref?.();
646
956
  }
647
957
  return;
648
958
  }
@@ -702,6 +1012,20 @@ function createSharedRealtimeTunnel({
702
1012
  return;
703
1013
  }
704
1014
 
1015
+ const entityIdentity = entityMutationInflight.get(frame.request_id);
1016
+ if (entityIdentity) {
1017
+ void localStateJson('POST', '/entities/cloud/mutations/fail', {
1018
+ resourceId: entityIdentity.resourceId,
1019
+ mutationId: entityIdentity.mutationId,
1020
+ message: `${frame.code || 'shared_error'}: ${frame.message || 'entity cloud mutation failed'}`,
1021
+ retryable: frame.retryable !== false,
1022
+ }).finally(() => {
1023
+ entityMutationInflight.delete(frame.request_id);
1024
+ if (frame.retryable !== false) scheduleEntityMutationDrain(RETRY_MS);
1025
+ });
1026
+ return;
1027
+ }
1028
+
705
1029
  const identity = mutationInflight.get(frame.request_id) || {
706
1030
  resourceId: frame.resource_id,
707
1031
  mutationId: frame.mutation_id,
@@ -710,7 +1034,6 @@ function createSharedRealtimeTunnel({
710
1034
  void localStateJson('POST', '/state/mutations/fail', {
711
1035
  resourceId: identity.resourceId,
712
1036
  mutationId: identity.mutationId,
713
- code: frame.code,
714
1037
  message: `${frame.code || 'shared_error'}: ${frame.message || 'shared mutation failed'}`,
715
1038
  retryable: frame.retryable !== false,
716
1039
  }).finally(() => {
@@ -722,8 +1045,11 @@ function createSharedRealtimeTunnel({
722
1045
  function handleCommitted(frame) {
723
1046
  const resourceId = frame.resource_id || frame.envelope?.resourceId;
724
1047
  if (!resourceId) return;
1048
+ const endpoint = frame.envelope?.contract === ENTITY_REGISTRY_PRIVATE_CONTRACT
1049
+ ? '/entities/cloud/mutations/ingest'
1050
+ : '/state/mutations/ingest';
725
1051
  const prior = inboundChains.get(resourceId) || Promise.resolve();
726
- const next = prior.then(() => localStateJson('POST', '/state/mutations/ingest', {
1052
+ const next = prior.then(() => localStateJson('POST', endpoint, {
727
1053
  envelope: frame.envelope,
728
1054
  version: frame.version,
729
1055
  committedAt: frame.committed_at,
@@ -803,6 +1129,12 @@ function createSharedRealtimeTunnel({
803
1129
  case 'private.resource.ready':
804
1130
  handlePrivateReady(frame);
805
1131
  return true;
1132
+ case 'private.resource.missing':
1133
+ handlePrivateMissing(frame);
1134
+ return true;
1135
+ case 'private.entity-content.stored':
1136
+ handlePrivateEntityContentStored(frame);
1137
+ return true;
806
1138
  case 'repo.object.stored':
807
1139
  handleRepoObjectStored(frame);
808
1140
  return true;
@@ -828,6 +1160,8 @@ function createSharedRealtimeTunnel({
828
1160
  enabled = false;
829
1161
  presenceEnabled = false;
830
1162
  mutationInflight.clear();
1163
+ entityMutationInflight.clear();
1164
+ entityContentInflight.clear();
831
1165
  promotionInflight.clear();
832
1166
  attachmentInflight.clear();
833
1167
  privateEnsureInflight.clear();
@@ -839,12 +1173,19 @@ function createSharedRealtimeTunnel({
839
1173
  wakeRequest = null;
840
1174
  clearTimeout(wakeRetryTimer);
841
1175
  clearTimeout(mutationRetryTimer);
1176
+ clearTimeout(entityMutationRetryTimer);
1177
+ clearTimeout(entityContentRetryTimer);
842
1178
  clearTimeout(promotionRetryTimer);
843
1179
  clearTimeout(attachmentRetryTimer);
844
1180
  clearTimeout(reauthorizeTimer);
845
1181
  clearTimeout(repoObjectTimer);
846
1182
  wakeRetryTimer = null;
847
1183
  mutationRetryTimer = null;
1184
+ entityMutationRetryTimer = null;
1185
+ entityMutationDrain = null;
1186
+ entityContentRetryTimer = null;
1187
+ entityContentDrain = null;
1188
+ userHomeReady = false;
848
1189
  promotionRetryTimer = null;
849
1190
  attachmentRetryTimer = null;
850
1191
  reauthorizeTimer = null;
package/lib/supervisor.js CHANGED
@@ -174,8 +174,6 @@ const SAFE_PROCESS_ENV_KEYS = [
174
174
  'LANG',
175
175
  'LC_ALL',
176
176
  'LOGNAME',
177
- 'AMALGM_AUTO_UPDATE',
178
- 'AMALGM_DISABLE_AUTO_UPDATE',
179
177
  'AMALGM_NATIVE_NODE_MODULES',
180
178
  'AMALGM_SKIP_NATIVE_INSTALL',
181
179
  'ELECTRON_RUN_AS_NODE',
@@ -1345,6 +1343,5 @@ module.exports = {
1345
1343
  liveDeclaredRuntimePorts,
1346
1344
  runtimeStateFilesUnder,
1347
1345
  runtimeStateSearchRoots,
1348
- safeBaseProcessEnv,
1349
1346
  },
1350
1347
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amalgm",
3
- "version": "0.1.245",
3
+ "version": "0.1.246",
4
4
  "description": "Amalgm local computer runtime: login, MCP, chat, events, previews, and tunnels.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -17,7 +17,7 @@
17
17
  "sync-runtime": "node ../../scripts/sync-npm-package-runtime.mjs",
18
18
  "prepack": "node ../../scripts/sync-npm-package-runtime.mjs",
19
19
  "pack:dry": "npm pack --dry-run",
20
- "check": "node --check bin/amalgm.js && node --check lib/app-chat.js && node --check lib/react.js && node --check lib/auth-store.js && node --check lib/cli.js && node --check lib/identity-adopt.js && node --check lib/layout.js && node --check lib/migrate-layout.js && node --check lib/paths.js && node --check lib/process-cleanup.js && node --check lib/runtime-identity.js && node --check lib/runtime-manifest.js && node --check lib/service.js && node --check lib/state-migration.js && node --check lib/supervisor.js && node --check lib/tunnel-chat.js && node --check lib/tunnel-events.js && node --check lib/updater.js && node --check runtime/lib/runtime-manifest.js && node --check runtime/scripts/runtime-auth.js && node --check runtime/scripts/proxy-token-store.js && node --check runtime/scripts/local-gateway.js && node --check runtime/scripts/port-monitor.js && node --check runtime/scripts/chat-server.js && node --check runtime/scripts/chat-server/index.js && node --check runtime/scripts/chat-server/config.js && node --check runtime/scripts/chat-core/tooling/native-binaries.js && node --check runtime/scripts/chat-core/tooling/package-import.js && node --check runtime/scripts/chat-core/tooling/runtime-home.js && node --check runtime/scripts/amalgm-mcp/index.js && node --check runtime/scripts/amalgm-mcp/config.js && node --check runtime/scripts/amalgm-mcp/events/pr-check-runner.js && node --check runtime/scripts/lib/project-paths.js && node --check runtime/scripts/lib/runtime-paths.js"
20
+ "check": "node --check bin/amalgm.js && node --check lib/app-chat.js && node --check lib/react.js && node --check lib/auth-store.js && node --check lib/cli.js && node --check lib/identity-adopt.js && node --check lib/layout.js && node --check lib/migrate-layout.js && node --check lib/paths.js && node --check lib/process-cleanup.js && node --check lib/runtime-identity.js && node --check lib/runtime-manifest.js && node --check lib/service.js && node --check lib/state-migration.js && node --check lib/supervisor.js && node --check lib/tunnel-chat.js && node --check lib/tunnel-events.js && node --check lib/updater.js && node --check runtime/lib/runtime-manifest.js && node --check runtime/scripts/runtime-auth.js && node --check runtime/scripts/proxy-token-store.js && node --check runtime/scripts/local-gateway.js && node --check runtime/scripts/port-monitor.js && node --check runtime/scripts/chat-server.js && node --check runtime/scripts/chat-server/index.js && node --check runtime/scripts/chat-server/config.js && node --check runtime/scripts/chat-core/tooling/native-binaries.js && node --check runtime/scripts/chat-core/tooling/package-import.js && node --check runtime/scripts/chat-core/tooling/runtime-home.js && node --check runtime/scripts/amalgm-mcp/index.js && node --check runtime/scripts/amalgm-mcp/config.js && node --check runtime/scripts/amalgm-mcp/events/pr-check-runner.js && node --check runtime/scripts/amalgm-mcp/registration/entity-cloud.js && node --check runtime/scripts/amalgm-mcp/registration/entity-content.js && node --check runtime/scripts/amalgm-mcp/registration/service.js && node --check runtime/scripts/amalgm-mcp/server/routes/entities.js && node --check runtime/scripts/lib/project-paths.js && node --check runtime/scripts/lib/runtime-paths.js"
21
21
  },
22
22
  "engines": {
23
23
  "node": ">=20"