driftseal 1.1.1 → 1.1.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 (2) hide show
  1. package/bin/driftseal.js +30 -10
  2. package/package.json +1 -1
package/bin/driftseal.js CHANGED
@@ -1686,7 +1686,7 @@ function directoryDigest(directory) {
1686
1686
  function visit(current, relative) {
1687
1687
  const stat = fs.lstatSync(current);
1688
1688
  if (stat.isDirectory()) {
1689
- digest.update(`directory\0${relative}\0${stat.mode & 0o777}\0`);
1689
+ digest.update(`directory\0${relative}\0`);
1690
1690
  for (const name of fs.readdirSync(current).sort()) {
1691
1691
  visit(path.join(current, name), relative ? path.join(relative, name) : name);
1692
1692
  }
@@ -2301,6 +2301,7 @@ function planDecisionAbsorb({ oursEntries, theirsEntries, baseEntries = [], base
2301
2301
  const mappings = [];
2302
2302
  const copies = [];
2303
2303
  const decisionMap = new Map();
2304
+ const hashMap = new Map();
2304
2305
  const usedIds = new Set(oursEntries.map((entry) => entry.id));
2305
2306
  const oursById = new Map();
2306
2307
  const baseById = new Map();
@@ -2377,17 +2378,21 @@ function planDecisionAbsorb({ oursEntries, theirsEntries, baseEntries = [], base
2377
2378
  usedIds.add(newId);
2378
2379
  decisionMap.set(entry.id, newId);
2379
2380
  mappings.push({ kind: 'decision', from: entry.id, to: newId });
2381
+ const rewritten = rewriteDecisionId(theirsContent, newId);
2382
+ const originalHash = contentHash(theirsContent);
2383
+ const rewrittenHash = contentHash(rewritten);
2384
+ if (originalHash !== rewrittenHash) hashMap.set(originalHash, rewrittenHash);
2380
2385
  copies.push({
2381
2386
  fromFile: entry.file,
2382
2387
  toFile: `${newId}-${decisionSlugFromFile(entry.file)}.md`,
2383
- content: rewriteDecisionId(theirsContent, newId),
2388
+ content: rewritten,
2384
2389
  removeFile: entry.file !== ours.file ? entry.file : null,
2385
2390
  });
2386
2391
  }
2387
- return { decisionMap, mappings, copies };
2392
+ return { decisionMap, hashMap, mappings, copies };
2388
2393
  }
2389
2394
 
2390
- function remapEvent(event, intentMap, decisionMap) {
2395
+ function remapEvent(event, intentMap, decisionMap, hashMap = new Map()) {
2391
2396
  const next = { ...event };
2392
2397
  if (intentMap.has(event.id)) next.id = intentMap.get(event.id);
2393
2398
  if (Array.isArray(next.decisions) && next.decisions.length > 0) {
@@ -2400,10 +2405,15 @@ function remapEvent(event, intentMap, decisionMap) {
2400
2405
  const normalized = normalizeDecisionId(next.decisionId);
2401
2406
  if (decisionMap.has(normalized)) next.decisionId = decisionMap.get(normalized);
2402
2407
  }
2408
+ for (const field of ['oldHash', 'newHash', 'fileHash']) {
2409
+ if (typeof next[field] === 'string' && hashMap.has(next[field])) {
2410
+ next[field] = hashMap.get(next[field]);
2411
+ }
2412
+ }
2403
2413
  return next;
2404
2414
  }
2405
2415
 
2406
- function remapTheirsRecords(theirsNew, oursUsedEvents, decisionMap) {
2416
+ function remapTheirsRecords(theirsNew, oursUsedEvents, decisionMap, hashMap = new Map()) {
2407
2417
  const intentMap = new Map();
2408
2418
  const mappings = [];
2409
2419
  const used = [...oursUsedEvents];
@@ -2415,14 +2425,14 @@ function remapTheirsRecords(theirsNew, oursUsedEvents, decisionMap) {
2415
2425
  intentMap.set(event.id, newId);
2416
2426
  mappings.push({ kind: 'intent', from: event.id, to: newId });
2417
2427
  }
2418
- event = remapEvent(event, intentMap, decisionMap);
2428
+ event = remapEvent(event, intentMap, decisionMap, hashMap);
2419
2429
  used.push(event);
2420
2430
  return { event };
2421
2431
  });
2422
2432
  return { records, mappings };
2423
2433
  }
2424
2434
 
2425
- function repairDuplicateIntentRecords(records, decisionMap) {
2435
+ function repairDuplicateIntentRecords(records, decisionMap, hashMap = new Map()) {
2426
2436
  const seenBegins = new Set();
2427
2437
  const intentMap = new Map();
2428
2438
  const used = [];
@@ -2440,7 +2450,12 @@ function repairDuplicateIntentRecords(records, decisionMap) {
2440
2450
  } else if (event.type === 'begin') {
2441
2451
  seenBegins.add(event.id);
2442
2452
  }
2443
- const remapped = remapEvent(event, intentMap, incomingSide ? decisionMap : new Map());
2453
+ const remapped = remapEvent(
2454
+ event,
2455
+ intentMap,
2456
+ incomingSide ? decisionMap : new Map(),
2457
+ incomingSide ? hashMap : new Map()
2458
+ );
2444
2459
  const changed = remapped !== event && JSON.stringify(remapped) !== JSON.stringify(event);
2445
2460
  result.push(changed ? { event: remapped } : record);
2446
2461
  used.push(result.at(-1).event);
@@ -2658,7 +2673,8 @@ function absorbFromStreams(ours, theirs, baseRecords, options) {
2658
2673
  const remapped = remapTheirsRecords(
2659
2674
  streams.theirsNew,
2660
2675
  [...streams.base, ...streams.oursNew].map((record) => record.event),
2661
- decisionPlan.decisionMap
2676
+ decisionPlan.decisionMap,
2677
+ decisionPlan.hashMap
2662
2678
  );
2663
2679
  const result = [...streams.base, ...streams.oursNew, ...remapped.records];
2664
2680
  return finishAbsorb({
@@ -2755,7 +2771,11 @@ function absorbLogs(otherFile, otherDecisions, { abandon, dryRun }) {
2755
2771
  baseEntries: gitBase ? gitDecisionEntries(gitBase) : [],
2756
2772
  baseIds: gitBase ? gitDecisionIds(gitBase) : new Set(),
2757
2773
  });
2758
- const repaired = repairDuplicateIntentRecords(loaded.records, decisionPlan.decisionMap);
2774
+ const repaired = repairDuplicateIntentRecords(
2775
+ loaded.records,
2776
+ decisionPlan.decisionMap,
2777
+ decisionPlan.hashMap
2778
+ );
2759
2779
  if (decisionPlan.mappings.length > 0 && !repaired.incomingSide) {
2760
2780
  fail(
2761
2781
  'cannot determine which intent records own the duplicate decision; ' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "driftseal",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Seal intent, verification, and decisions into an auditable workflow for agentic coding",
5
5
  "keywords": [
6
6
  "driftseal",