amalgm 0.1.183 → 0.1.185

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.183",
3
+ "version": "0.1.185",
4
4
  "description": "Amalgm local computer runtime: login, MCP, chat, events, previews, and tunnels.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -164,7 +164,7 @@ test('checkpoint captures are local cache; their operations travel on the one wa
164
164
  assert.equal(first, checkpointFile('m1', 'https://github.com/a/b'));
165
165
  assert.notEqual(first, checkpointFile('m2', 'https://github.com/a/b'));
166
166
  assert.notEqual(first, checkpointFile('m1', 'https://github.com/a/c'));
167
- assert.match(first, /repo-checkpoints-v6/);
167
+ assert.match(first, /repo-checkpoints-v7/);
168
168
  });
169
169
 
170
170
  test('an uploading checkpoint payload is not published as a transition', () => {
@@ -133,7 +133,7 @@ test('a stale lower rail card cannot roll back a newer branch and commit', () =>
133
133
  test('checkpoint reduction reads only the current rail contract', () => {
134
134
  const current = card('/current-contract', 'a'.repeat(40), 1);
135
135
  const stale = transition('machine-local', 2, current.head.oid, '', 'stale');
136
- stale.checkpoint = 'repo-checkpoint@5';
136
+ stale.checkpoint = 'repo-checkpoint@6';
137
137
  current.checkpoints = [
138
138
  stale,
139
139
  transition('machine-local', 3, current.head.oid, '', 'current'),
@@ -309,6 +309,41 @@ test('one materializer converges to the reduced checkpoint and later removes a r
309
309
  assert.equal(fs.readFileSync(path.join(repo, 'b.txt'), 'utf8'), 'b1\n');
310
310
  });
311
311
 
312
+ test('a mode-only checkpoint makes the peer working file executable', async () => {
313
+ const { repo, oid } = await makeRepo('materialize-mode');
314
+ fs.chmodSync(path.join(repo, 'a.txt'), 0o755);
315
+ const modePatch = await git(repo, 'diff', 'HEAD', '--binary', '--full-index');
316
+ await git(repo, 'reset', '--hard', 'HEAD');
317
+ const localCard = card(repo, oid, 1);
318
+ const clean = { revision: null, indexDiff: '', worktreeDiff: '' };
319
+ const executable = {
320
+ revision: revisionOf(oid, '', modePatch),
321
+ indexDiff: '',
322
+ worktreeDiff: modePatch,
323
+ };
324
+ const plan = {
325
+ repoKey: 'root:test',
326
+ card: localCard,
327
+ transitions: [{
328
+ checkpoint: CHECKPOINT_CONTRACT,
329
+ machine: 'machine-remote',
330
+ repoKey: 'root:test',
331
+ branch: 'main',
332
+ baseOid: oid,
333
+ from: clean,
334
+ to: executable,
335
+ version: 2,
336
+ mutationId: 'mut_mode_only_02',
337
+ }],
338
+ };
339
+
340
+ const outcome = await materializeRepo(localCard, plan);
341
+ assert.equal(outcome.state, 'in-sync');
342
+ assert.notEqual(fs.statSync(path.join(repo, 'a.txt')).mode & 0o100, 0);
343
+ assert.match(await git(repo, 'diff', '--binary', '--full-index'), /new mode 100755/);
344
+ assert.equal(await git(repo, 'diff', '--cached', '--binary', '--full-index'), '');
345
+ });
346
+
312
347
  test('once local work is on the rail, a checkpoint conflict materializes exactly without echoing', async () => {
313
348
  const { repo, oid } = await makeRepo('materialize-conflict');
314
349
  const localPatch = await patchFor(repo, { 'a.txt': 'local answer\n' });
@@ -155,7 +155,7 @@ test('checkpoint transitions append until the next card and carry their official
155
155
  const file = checkpointFile('machine-a', repoKey);
156
156
  fs.mkdirSync(path.dirname(file), { recursive: true });
157
157
  const firstCheckpoint = {
158
- checkpoint: 'repo-checkpoint@6',
158
+ checkpoint: 'repo-checkpoint@7',
159
159
  machine: 'machine-a',
160
160
  repoKey,
161
161
  branch: card.head.branch,
@@ -25,7 +25,7 @@ const { machineId } = require('./identity');
25
25
  const { listRepoCards } = require('./cards');
26
26
  const { captureCheckpoint } = require('./git');
27
27
 
28
- const CHECKPOINT_CONTRACT = 'repo-checkpoint@6';
28
+ const CHECKPOINT_CONTRACT = 'repo-checkpoint@7';
29
29
  const MAX_INLINE_DIFF_BYTES = 512 * 1024;
30
30
  const PUBLISH_QUIET_MS = 25;
31
31
  const RECONCILE_INTERVAL_MS = 30_000;
@@ -54,7 +54,7 @@ function checkpointFile(machine, repoKey) {
54
54
  .update(`${CHECKPOINT_CONTRACT}|${machine}|${repoKey}`)
55
55
  .digest('hex')
56
56
  .slice(0, 24);
57
- return path.join(AMALGM_DIR, 'state', 'repo-checkpoints-v6', `${digest}.json`);
57
+ return path.join(AMALGM_DIR, 'state', 'repo-checkpoints-v7', `${digest}.json`);
58
58
  }
59
59
 
60
60
  function revisionOf(baseOid, indexDiff, worktreeDiff = '') {
@@ -166,7 +166,9 @@ function workMatches(work, entry, blobBytes) {
166
166
  if (!entry) return work === null;
167
167
  if (work === null) return false;
168
168
  if (entry.mode === '120000') return work.kind === 'symlink' && work.content.equals(blobBytes);
169
- return work.kind === 'file' && work.content.equals(blobBytes);
169
+ return work.kind === 'file'
170
+ && work.exec === (entry.mode === '100755')
171
+ && work.content.equals(blobBytes);
170
172
  }
171
173
 
172
174
  function isText(buffer) {