amalgm 0.1.192 → 0.1.194

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amalgm",
3
- "version": "0.1.192",
3
+ "version": "0.1.194",
4
4
  "description": "Amalgm local computer runtime: login, MCP, chat, events, previews, and tunnels.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -38,7 +38,9 @@ const {
38
38
  publishedCardFor,
39
39
  publishWall,
40
40
  readWall,
41
+ startWallService,
41
42
  stampCards,
43
+ stopWallService,
42
44
  wallStats,
43
45
  } = require('../workspace/wall');
44
46
 
@@ -179,7 +181,9 @@ test('checkpoint work on the materialized baseline keeps the baseline card and b
179
181
  )[0];
180
182
 
181
183
  assert.equal(stamped.positionMutationId, 'mut_baseline_card');
184
+ assert.equal(stamped.positionVersion, 9);
182
185
  assert.equal(stamped.branches[0].mutationId, 'mut_baseline_ref1');
186
+ assert.equal(stamped.branches[0].version, 9);
183
187
  });
184
188
 
185
189
  test('a collaborator binds the same repo to the owner project, not a parallel project', () => {
@@ -239,11 +243,14 @@ test('a repo project carries exactly one line per machine, replaced in place', a
239
243
  committedAt: '2026-07-23T00:00:00.000Z',
240
244
  });
241
245
  const sealed = publishWall(repoKey);
242
- assert.equal(sealed.published, false);
243
- assert.equal(sealed.reason, 'shared-state-covered');
246
+ assert.equal(sealed.published, true);
244
247
  const sealedCard = readWall(repoKey)[0].cards[0];
245
248
  assert.equal(sealedCard.positionMutationId, first.mutationId);
246
249
  assert.equal(sealedCard.positionVersion, 1);
250
+ assert.equal(
251
+ JSON.parse(getDocText(project.file).trim()).cards[0].positionVersion,
252
+ 1,
253
+ );
247
254
  assert.equal(publishedCardFor(refreshed.cards[0]).positionVersion, 1);
248
255
 
249
256
  const again = publishWall(repoKey);
@@ -288,7 +295,11 @@ test('checkpoint transitions append until the next card and carry their official
288
295
  committedAt: '2026-07-23T00:00:02.000Z',
289
296
  });
290
297
  assert.equal(readWall(repoKey)[0].cards[0].checkpoints[0].version, 2);
291
- assert.equal(publishWall(repoKey).published, false);
298
+ assert.equal(publishWall(repoKey).published, true);
299
+ assert.equal(
300
+ JSON.parse(getDocText(project.file).trim()).cards[0].checkpoints[0].version,
301
+ 2,
302
+ );
292
303
 
293
304
  fs.writeFileSync(file, `${JSON.stringify({
294
305
  ...firstCheckpoint,
@@ -374,3 +385,15 @@ test('project stats name every project resource, binding, and publish counter',
374
385
  assert.ok(stats.publishSkips >= 1);
375
386
  assert.ok(stats.paths.includes(project.file));
376
387
  });
388
+
389
+ test('a restarted wall publishes once even when the project is already attached', async () => {
390
+ const before = wallStats();
391
+ startWallService();
392
+ await new Promise((resolve) => setTimeout(resolve, 500));
393
+ stopWallService();
394
+ const after = wallStats();
395
+ assert.ok(
396
+ after.publishes + after.publishSkips
397
+ > before.publishes + before.publishSkips,
398
+ );
399
+ });
@@ -281,6 +281,27 @@ function officialVersion(resourceId, mutationId) {
281
281
  return Number.isInteger(mutation?.officialCloudVersion) ? mutation.officialCloudVersion : null;
282
282
  }
283
283
 
284
+ function sealedVersion(resourceId, mutationId, ...versions) {
285
+ return versions.find(validVersion)
286
+ || officialVersion(resourceId, mutationId)
287
+ || null;
288
+ }
289
+
290
+ function entryNeedsSeal(entry, resourceId) {
291
+ return Boolean(entry?.cards?.some((card) => (
292
+ (!validVersion(card.positionVersion)
293
+ && validVersion(officialVersion(resourceId, card.positionMutationId)))
294
+ || (card.branches || []).some((ref) => (
295
+ !validVersion(ref.version)
296
+ && validVersion(officialVersion(resourceId, ref.mutationId))
297
+ ))
298
+ || (card.checkpoints || []).some((checkpoint) => (
299
+ !validVersion(checkpoint.version)
300
+ && validVersion(officialVersion(resourceId, checkpoint.mutationId))
301
+ ))
302
+ )));
303
+ }
304
+
284
305
  function stampBranches(
285
306
  refs,
286
307
  previousBranches,
@@ -322,6 +343,13 @@ function stampBranches(
322
343
  oid,
323
344
  ...(observed?.objects ? { objects: observed.objects } : {}),
324
345
  mutationId: mutation,
346
+ version: sealedVersion(
347
+ resourceId,
348
+ mutation,
349
+ mutation === before?.mutationId ? before.version : null,
350
+ mutation === onRail?.mutationId ? onRail.version : null,
351
+ mutation === materialized?.mutationId ? materialized.version : null,
352
+ ),
325
353
  };
326
354
  });
327
355
  }
@@ -372,6 +400,15 @@ function stampCards(cards, previousCards, sharedPlan, baseline, mutationId, proj
372
400
  : reusableRailPosition
373
401
  ? sharedPlan.card.positionMutationId
374
402
  : reusableBaselinePosition ? baseline.cardMutationId : mutationId;
403
+ const positionVersion = sealedVersion(
404
+ project.resourceId,
405
+ positionMutationId,
406
+ positionMutationId === previous?.positionMutationId ? previous.positionVersion : null,
407
+ positionMutationId === sharedPlan?.card?.positionMutationId
408
+ ? sharedPlan.card.positionVersion
409
+ : null,
410
+ positionMutationId === baseline?.cardMutationId ? baseline.cardVersion : null,
411
+ );
375
412
  const checkpoint = readCheckpoint(machineId(), project.repoKey);
376
413
  const currentCheckpoint = checkpoint
377
414
  && checkpoint.baseOid === card.head?.oid
@@ -381,7 +418,14 @@ function stampCards(cards, previousCards, sharedPlan, baseline, mutationId, proj
381
418
  const sameBase = previous?.head?.oid === card.head?.oid
382
419
  && previous?.head?.branch === card.head?.branch;
383
420
  const history = sameBase && Array.isArray(previous?.checkpoints)
384
- ? previous.checkpoints.map(({ version: _version, ...entry }) => entry)
421
+ ? previous.checkpoints.map((entry) => ({
422
+ ...entry,
423
+ version: sealedVersion(
424
+ project.resourceId,
425
+ entry.mutationId,
426
+ entry.version,
427
+ ),
428
+ }))
385
429
  : [];
386
430
  const last = history.at(-1);
387
431
  const checkpoints = currentCheckpoint
@@ -392,6 +436,7 @@ function stampCards(cards, previousCards, sharedPlan, baseline, mutationId, proj
392
436
  return {
393
437
  ...sharedCard(card),
394
438
  positionMutationId,
439
+ positionVersion,
395
440
  branches: stampBranches(
396
441
  card.refs,
397
442
  previous?.branches,
@@ -455,7 +500,7 @@ function publishProject(project, rawCards) {
455
500
  return hasLocalContribution(card, sharedPlan, baseline, checkpoint)
456
501
  || hasObjectUpgrade(card, sharedPlan);
457
502
  });
458
- if (!removed && !contributes) {
503
+ if (!removed && !contributes && !entryNeedsSeal(previousEntry, project.resourceId)) {
459
504
  service.counters.publishSkips += 1;
460
505
  return { published: false, reason: 'shared-state-covered', repoKey: project.repoKey };
461
506
  }
@@ -624,6 +669,7 @@ function startWallService() {
624
669
  service.ensureInterval = setInterval(() => ensureProjects().catch(() => {}), ENSURE_INTERVAL_MS);
625
670
  service.ensureInterval.unref?.();
626
671
  ensureProjects().catch(() => {});
672
+ schedulePublish();
627
673
  }
628
674
 
629
675
  function stopWallService() {