@triedotdev/mcp 1.0.163 → 1.0.165

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 (62) hide show
  1. package/README.md +16 -2
  2. package/dist/{chunk-62JD7MIS.js → chunk-5LRDF2WB.js} +15 -35
  3. package/dist/chunk-5LRDF2WB.js.map +1 -0
  4. package/dist/{chunk-XSKLOBD2.js → chunk-CDG2GVBP.js} +601 -70
  5. package/dist/chunk-CDG2GVBP.js.map +1 -0
  6. package/dist/{chunk-5BYSJ7XT.js → chunk-GTKYBOXL.js} +13 -2
  7. package/dist/{chunk-5BYSJ7XT.js.map → chunk-GTKYBOXL.js.map} +1 -1
  8. package/dist/{chunk-ACU3IXZG.js → chunk-HC5P6FZD.js} +7 -7
  9. package/dist/{chunk-HFVPHQL3.js → chunk-IPNPHPNN.js} +9 -9
  10. package/dist/{chunk-GL62CXU4.js → chunk-IS5UBN2R.js} +86 -12
  11. package/dist/chunk-IS5UBN2R.js.map +1 -0
  12. package/dist/{chunk-LLDZDU2Y.js → chunk-LR5M4RTN.js} +79 -1
  13. package/dist/chunk-LR5M4RTN.js.map +1 -0
  14. package/dist/{chunk-ERMLZJTK.js → chunk-M7HMBZ3R.js} +13 -13
  15. package/dist/chunk-OBQ74FOU.js +27 -0
  16. package/dist/chunk-OBQ74FOU.js.map +1 -0
  17. package/dist/{chunk-5TRCQAOE.js → chunk-RQ6QZBIN.js} +16 -5
  18. package/dist/chunk-RQ6QZBIN.js.map +1 -0
  19. package/dist/{chunk-IRZXBQVQ.js → chunk-SS2O3MTC.js} +134 -101
  20. package/dist/chunk-SS2O3MTC.js.map +1 -0
  21. package/dist/{chunk-LR46VMIE.js → chunk-WRYQHVPD.js} +5 -5
  22. package/dist/{chunk-Y4B3VEL7.js → chunk-YAL3SUBG.js} +435 -202
  23. package/dist/chunk-YAL3SUBG.js.map +1 -0
  24. package/dist/cli/main.js +215 -57
  25. package/dist/cli/main.js.map +1 -1
  26. package/dist/cli/yolo-daemon.js +15 -14
  27. package/dist/cli/yolo-daemon.js.map +1 -1
  28. package/dist/{fast-analyzer-LLZ6FLP5.js → fast-analyzer-54AHLVO5.js} +3 -3
  29. package/dist/{goal-manager-D6XKE3FY.js → goal-manager-563BNILQ.js} +5 -5
  30. package/dist/{goal-validator-4DDL7NBP.js → goal-validator-FJEDIYU7.js} +5 -5
  31. package/dist/{hypothesis-RI3Q33JB.js → hypothesis-4KC7XRBZ.js} +5 -5
  32. package/dist/index.js +16 -15
  33. package/dist/index.js.map +1 -1
  34. package/dist/{issue-store-DUR5UTYK.js → issue-store-FOS4T736.js} +3 -3
  35. package/dist/{ledger-ZTR63P3L.js → ledger-EDLPF6SB.js} +8 -2
  36. package/dist/project-state-AHPA77SM.js +28 -0
  37. package/dist/server/mcp-server.js +16 -15
  38. package/dist/sync-M2FSWPBC.js +12 -0
  39. package/dist/{tiered-storage-FHHAJR4P.js → tiered-storage-OP74NPJY.js} +2 -2
  40. package/dist/tiered-storage-OP74NPJY.js.map +1 -0
  41. package/dist/{trie-agent-NYSPGZYS.js → trie-agent-TM6ATSNR.js} +12 -12
  42. package/dist/trie-agent-TM6ATSNR.js.map +1 -0
  43. package/package.json +1 -1
  44. package/dist/chunk-5TRCQAOE.js.map +0 -1
  45. package/dist/chunk-62JD7MIS.js.map +0 -1
  46. package/dist/chunk-GL62CXU4.js.map +0 -1
  47. package/dist/chunk-IRZXBQVQ.js.map +0 -1
  48. package/dist/chunk-LLDZDU2Y.js.map +0 -1
  49. package/dist/chunk-XSKLOBD2.js.map +0 -1
  50. package/dist/chunk-Y4B3VEL7.js.map +0 -1
  51. /package/dist/{chunk-ACU3IXZG.js.map → chunk-HC5P6FZD.js.map} +0 -0
  52. /package/dist/{chunk-HFVPHQL3.js.map → chunk-IPNPHPNN.js.map} +0 -0
  53. /package/dist/{chunk-ERMLZJTK.js.map → chunk-M7HMBZ3R.js.map} +0 -0
  54. /package/dist/{chunk-LR46VMIE.js.map → chunk-WRYQHVPD.js.map} +0 -0
  55. /package/dist/{fast-analyzer-LLZ6FLP5.js.map → fast-analyzer-54AHLVO5.js.map} +0 -0
  56. /package/dist/{goal-manager-D6XKE3FY.js.map → goal-manager-563BNILQ.js.map} +0 -0
  57. /package/dist/{goal-validator-4DDL7NBP.js.map → goal-validator-FJEDIYU7.js.map} +0 -0
  58. /package/dist/{hypothesis-RI3Q33JB.js.map → hypothesis-4KC7XRBZ.js.map} +0 -0
  59. /package/dist/{issue-store-DUR5UTYK.js.map → issue-store-FOS4T736.js.map} +0 -0
  60. /package/dist/{ledger-ZTR63P3L.js.map → ledger-EDLPF6SB.js.map} +0 -0
  61. /package/dist/{tiered-storage-FHHAJR4P.js.map → project-state-AHPA77SM.js.map} +0 -0
  62. /package/dist/{trie-agent-NYSPGZYS.js.map → sync-M2FSWPBC.js.map} +0 -0
@@ -5,18 +5,146 @@ import {
5
5
  getTrieDirectory,
6
6
  getWorkingDirectory
7
7
  } from "./chunk-VVITXIHN.js";
8
+ import {
9
+ __require
10
+ } from "./chunk-DGUM43GV.js";
8
11
 
9
12
  // src/memory/ledger.ts
10
13
  import { createHash } from "crypto";
11
- import { mkdir, readFile, writeFile, stat, unlink } from "fs/promises";
12
- import { existsSync as existsSync4 } from "fs";
14
+ import { mkdir as mkdir2, readFile as readFile2, writeFile, stat as stat2, unlink as unlink2 } from "fs/promises";
15
+ import { existsSync as existsSync5 } from "fs";
13
16
  import { createGzip, createGunzip } from "zlib";
14
17
  import { pipeline } from "stream/promises";
15
18
  import { createReadStream, createWriteStream } from "fs";
16
19
  import { join as join3 } from "path";
17
20
 
18
- // src/agent/git.ts
21
+ // src/utils/file-lock.ts
22
+ import { open, unlink, readFile, stat, mkdir } from "fs/promises";
19
23
  import { existsSync } from "fs";
24
+ import { dirname } from "path";
25
+ var activeLocks = /* @__PURE__ */ new Set();
26
+ function setupCleanupHandler() {
27
+ const cleanup = () => {
28
+ for (const lockPath of activeLocks) {
29
+ try {
30
+ const fs = __require("fs");
31
+ if (fs.existsSync(lockPath)) {
32
+ fs.unlinkSync(lockPath);
33
+ }
34
+ } catch {
35
+ }
36
+ }
37
+ };
38
+ process.on("exit", cleanup);
39
+ process.on("SIGINT", () => {
40
+ cleanup();
41
+ process.exit(130);
42
+ });
43
+ process.on("SIGTERM", () => {
44
+ cleanup();
45
+ process.exit(143);
46
+ });
47
+ }
48
+ var cleanupHandlerInstalled = false;
49
+ async function withFileLock(filePath, fn, options = {}) {
50
+ const {
51
+ timeout = 1e4,
52
+ retryDelay = 50,
53
+ maxRetryDelay = 500,
54
+ staleTimeout = 3e4
55
+ } = options;
56
+ const lockPath = `${filePath}.lock`;
57
+ const start = Date.now();
58
+ let currentDelay = retryDelay;
59
+ if (!cleanupHandlerInstalled) {
60
+ setupCleanupHandler();
61
+ cleanupHandlerInstalled = true;
62
+ }
63
+ await mkdir(dirname(lockPath), { recursive: true });
64
+ while (true) {
65
+ try {
66
+ await cleanupStaleLock(lockPath, staleTimeout);
67
+ const lockInfo = {
68
+ pid: process.pid,
69
+ timestamp: Date.now(),
70
+ hostname: __require("os").hostname()
71
+ };
72
+ const handle = await open(lockPath, "wx");
73
+ await handle.writeFile(JSON.stringify(lockInfo));
74
+ await handle.close();
75
+ activeLocks.add(lockPath);
76
+ try {
77
+ return await fn();
78
+ } finally {
79
+ activeLocks.delete(lockPath);
80
+ await unlink(lockPath).catch(() => {
81
+ });
82
+ }
83
+ } catch (err) {
84
+ if (err.code !== "EEXIST") {
85
+ throw err;
86
+ }
87
+ if (Date.now() - start > timeout) {
88
+ let lockHolder = "unknown";
89
+ try {
90
+ const content = await readFile(lockPath, "utf-8");
91
+ const info = JSON.parse(content);
92
+ lockHolder = `PID ${info.pid} on ${info.hostname}`;
93
+ } catch {
94
+ }
95
+ throw new Error(
96
+ `Timeout acquiring lock for ${filePath} after ${timeout}ms. Lock held by: ${lockHolder}`
97
+ );
98
+ }
99
+ await new Promise((resolve) => setTimeout(resolve, currentDelay));
100
+ currentDelay = Math.min(currentDelay * 2, maxRetryDelay);
101
+ }
102
+ }
103
+ }
104
+ async function cleanupStaleLock(lockPath, staleTimeout) {
105
+ if (!existsSync(lockPath)) {
106
+ return;
107
+ }
108
+ try {
109
+ const content = await readFile(lockPath, "utf-8");
110
+ const info = JSON.parse(content);
111
+ const lockAge = Date.now() - info.timestamp;
112
+ if (lockAge > staleTimeout) {
113
+ console.warn(`[FileLock] Removing stale lock (age: ${Math.round(lockAge / 1e3)}s): ${lockPath}`);
114
+ await unlink(lockPath);
115
+ return;
116
+ }
117
+ const currentHostname = __require("os").hostname();
118
+ if (info.hostname === currentHostname) {
119
+ if (!isProcessRunning(info.pid)) {
120
+ console.warn(`[FileLock] Removing orphaned lock (PID ${info.pid} not running): ${lockPath}`);
121
+ await unlink(lockPath);
122
+ return;
123
+ }
124
+ }
125
+ } catch {
126
+ try {
127
+ const stats = await stat(lockPath);
128
+ const fileAge = Date.now() - stats.mtimeMs;
129
+ if (fileAge > staleTimeout) {
130
+ console.warn(`[FileLock] Removing stale/corrupted lock: ${lockPath}`);
131
+ await unlink(lockPath);
132
+ }
133
+ } catch {
134
+ }
135
+ }
136
+ }
137
+ function isProcessRunning(pid) {
138
+ try {
139
+ process.kill(pid, 0);
140
+ return true;
141
+ } catch {
142
+ return false;
143
+ }
144
+ }
145
+
146
+ // src/agent/git.ts
147
+ import { existsSync as existsSync2 } from "fs";
20
148
  import path from "path";
21
149
 
22
150
  // src/utils/command-runner.ts
@@ -319,7 +447,7 @@ async function getChangedFilesSinceTimestamp(projectPath, timestamp) {
319
447
  // src/memory/crypto-keys.ts
320
448
  import * as ed25519 from "@noble/ed25519";
321
449
  import { randomBytes } from "crypto";
322
- import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
450
+ import { existsSync as existsSync3, mkdirSync, readFileSync, writeFileSync } from "fs";
323
451
  import { join } from "path";
324
452
  function getKeysDirectory(workDir) {
325
453
  const trieDir = getTrieDirectory(workDir || process.cwd());
@@ -338,7 +466,7 @@ async function generateKeyPair() {
338
466
  }
339
467
  function saveKeyPair(keyPair, workDir) {
340
468
  const keysDir = getKeysDirectory(workDir);
341
- if (!existsSync2(keysDir)) {
469
+ if (!existsSync3(keysDir)) {
342
470
  mkdirSync(keysDir, { recursive: true });
343
471
  }
344
472
  const keyPath = getDefaultKeyPath(workDir);
@@ -353,7 +481,7 @@ function saveKeyPair(keyPair, workDir) {
353
481
  }
354
482
  function loadKeyPair(workDir) {
355
483
  const keyPath = getDefaultKeyPath(workDir);
356
- if (!existsSync2(keyPath)) {
484
+ if (!existsSync3(keyPath)) {
357
485
  return null;
358
486
  }
359
487
  try {
@@ -410,25 +538,29 @@ async function verifyHashSignature(hash, signatureData) {
410
538
  }
411
539
  return await verifySignature(hash, signatureData.signature, signatureData.publicKey);
412
540
  }
541
+ function getPublicKey(workDir) {
542
+ const keyPair = loadKeyPair(workDir);
543
+ return keyPair?.publicKey || null;
544
+ }
413
545
  function hasSigningKey(workDir) {
414
546
  const keyPath = getDefaultKeyPath(workDir);
415
- return existsSync2(keyPath);
547
+ return existsSync3(keyPath);
416
548
  }
417
549
 
418
550
  // src/memory/git-integration.ts
419
551
  import { exec as exec2 } from "child_process";
420
552
  import { promisify as promisify2 } from "util";
421
- import { existsSync as existsSync3 } from "fs";
553
+ import { existsSync as existsSync4 } from "fs";
422
554
  import { join as join2 } from "path";
423
555
  var execAsync2 = promisify2(exec2);
424
556
  async function isGitIntegrationEnabled(workDir) {
425
557
  try {
426
558
  const gitDir = join2(workDir, ".git");
427
- if (!existsSync3(gitDir)) {
559
+ if (!existsSync4(gitDir)) {
428
560
  return false;
429
561
  }
430
562
  const configPath = join2(getTrieDirectory(workDir), "config.json");
431
- if (!existsSync3(configPath)) {
563
+ if (!existsSync4(configPath)) {
432
564
  return true;
433
565
  }
434
566
  const config = JSON.parse(await import("fs/promises").then((fs) => fs.readFile(configPath, "utf-8")));
@@ -473,7 +605,7 @@ async function ensureKeysIgnored(workDir) {
473
605
  const gitignorePath = join2(workDir, ".gitignore");
474
606
  const fs = await import("fs/promises");
475
607
  let gitignore = "";
476
- if (existsSync3(gitignorePath)) {
608
+ if (existsSync4(gitignorePath)) {
477
609
  gitignore = await fs.readFile(gitignorePath, "utf-8");
478
610
  }
479
611
  if (gitignore.includes(".trie/keys/")) {
@@ -493,6 +625,12 @@ var MANIFEST_FILENAME = "ledger-manifest.json";
493
625
  var SYNC_STATE_FILENAME = "ledger-sync.json";
494
626
  var GENESIS_HASH = "0".repeat(64);
495
627
  var LEDGER_VERSION = 2;
628
+ var ConcurrentModificationError = class extends Error {
629
+ constructor(message) {
630
+ super(message);
631
+ this.name = "ConcurrentModificationError";
632
+ }
633
+ };
496
634
  async function signLedgerEntry(entry, workDir) {
497
635
  try {
498
636
  const signatureData = await signHash(entry.hash, workDir);
@@ -541,42 +679,45 @@ async function appendIssuesToLedger(issues, workDir, author) {
541
679
  if (issues.length === 0) return null;
542
680
  const projectDir = workDir || getWorkingDirectory(void 0, true);
543
681
  const memoryDir = join3(getTrieDirectory(projectDir), "memory");
544
- await mkdir(memoryDir, { recursive: true });
545
- const isRepo = await isGitRepo(projectDir);
546
- const lastCommit = isRepo ? await getLastCommit(projectDir) : null;
547
- const blockAuthor = author || lastCommit?.author || "unknown";
548
- const blocks = await loadLedger(projectDir);
549
- const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
550
- const now = (/* @__PURE__ */ new Date()).toISOString();
551
- const shouldSign = hasSigningKey(projectDir);
552
- let entries = issues.map((issue) => ({
553
- id: issue.id,
554
- hash: issue.hash,
555
- severity: issue.severity,
556
- file: issue.file,
557
- agent: issue.agent,
558
- timestamp: issue.timestamp,
559
- status: "active"
560
- }));
561
- if (shouldSign) {
562
- entries = await Promise.all(entries.map((entry) => signLedgerEntry(entry, projectDir)));
563
- }
564
- const previousBlock = blocks[blocks.length - 1];
565
- const block = previousBlock && previousBlock.date === today ? previousBlock : createSyncableBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH, blockAuthor, lastCommit?.hash, blocks.length);
566
- if (block !== previousBlock) {
567
- blocks.push(block);
568
- }
569
- block.entries = [...block.entries, ...entries];
570
- block.merkleRoot = computeMerkleRoot(block.entries.map((entry) => entry.hash));
571
- block.blockHash = computeBlockHash(block.previousHash, block.merkleRoot, block.date, block.version);
572
- block.updatedAt = now;
573
- await saveLedger(blocks, projectDir);
574
- if (await isGitRepo(projectDir)) {
575
- await ensureKeysIgnored(projectDir);
576
- const commitMessage = `ledger: append ${entries.length} ${entries.length === 1 ? "entry" : "entries"}`;
577
- await autoCommitLedger(projectDir, commitMessage);
578
- }
579
- return block;
682
+ await mkdir2(memoryDir, { recursive: true });
683
+ const ledgerPath = join3(memoryDir, LEDGER_FILENAME);
684
+ return withFileLock(ledgerPath, async () => {
685
+ const isRepo = await isGitRepo(projectDir);
686
+ const lastCommit = isRepo ? await getLastCommit(projectDir) : null;
687
+ const blockAuthor = author || lastCommit?.author || "unknown";
688
+ const blocks = await loadLedger(projectDir);
689
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
690
+ const now = (/* @__PURE__ */ new Date()).toISOString();
691
+ const shouldSign = hasSigningKey(projectDir);
692
+ let entries = issues.map((issue) => ({
693
+ id: issue.id,
694
+ hash: issue.hash,
695
+ severity: issue.severity,
696
+ file: issue.file,
697
+ agent: issue.agent,
698
+ timestamp: issue.timestamp,
699
+ status: "active"
700
+ }));
701
+ if (shouldSign) {
702
+ entries = await Promise.all(entries.map((entry) => signLedgerEntry(entry, projectDir)));
703
+ }
704
+ const previousBlock = blocks[blocks.length - 1];
705
+ const block = previousBlock && previousBlock.date === today ? previousBlock : createSyncableBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH, blockAuthor, lastCommit?.hash, blocks.length);
706
+ if (block !== previousBlock) {
707
+ blocks.push(block);
708
+ }
709
+ block.entries = [...block.entries, ...entries];
710
+ block.merkleRoot = computeMerkleRoot(block.entries.map((entry) => entry.hash));
711
+ block.blockHash = computeBlockHash(block.previousHash, block.merkleRoot, block.date, block.version);
712
+ block.updatedAt = now;
713
+ await saveLedgerInternal(blocks, projectDir);
714
+ if (await isGitRepo(projectDir)) {
715
+ await ensureKeysIgnored(projectDir);
716
+ const commitMessage = `ledger: append ${entries.length} ${entries.length === 1 ? "entry" : "entries"}`;
717
+ await autoCommitLedger(projectDir, commitMessage);
718
+ }
719
+ return block;
720
+ }, { timeout: 15e3 });
580
721
  }
581
722
  async function verifyLedger(workDir) {
582
723
  const projectDir = workDir || getWorkingDirectory(void 0, true);
@@ -649,24 +790,80 @@ function createSyncableBlock(date, now, previousHash, author, gitCommit, chainHe
649
790
  };
650
791
  }
651
792
  async function loadLedger(projectDir) {
793
+ const result = await loadLedgerWithHash(projectDir);
794
+ return result.blocks;
795
+ }
796
+ async function loadLedgerWithHash(projectDir) {
652
797
  const ledgerPath = join3(getTrieDirectory(projectDir), "memory", LEDGER_FILENAME);
653
798
  try {
654
- if (!existsSync4(ledgerPath)) return [];
655
- const content = await readFile(ledgerPath, "utf-8");
799
+ if (!existsSync5(ledgerPath)) {
800
+ return { blocks: [], contentHash: sha256("[]") };
801
+ }
802
+ const content = await readFile2(ledgerPath, "utf-8");
656
803
  const parsed = JSON.parse(content);
657
- if (!Array.isArray(parsed)) return [];
658
- return parsed;
804
+ if (parsed && parsed._format === "ledger-v2") {
805
+ const file = parsed;
806
+ return {
807
+ blocks: file.blocks || [],
808
+ contentHash: file._contentHash
809
+ };
810
+ }
811
+ if (!Array.isArray(parsed)) {
812
+ return { blocks: [], contentHash: sha256("[]") };
813
+ }
814
+ const blocks = parsed;
815
+ const contentHash = sha256(JSON.stringify(blocks));
816
+ return { blocks, contentHash };
659
817
  } catch {
660
- return [];
818
+ return { blocks: [], contentHash: sha256("[]") };
661
819
  }
662
820
  }
663
821
  async function getLedgerBlocks(workDir) {
664
822
  const projectDir = workDir || getWorkingDirectory(void 0, true);
665
823
  return loadLedger(projectDir);
666
824
  }
825
+ async function getLedgerBlocksWithHash(workDir) {
826
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
827
+ return loadLedgerWithHash(projectDir);
828
+ }
829
+ async function saveLedgerOptimistic(blocks, expectedHash, workDir) {
830
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
831
+ const memoryDir = join3(getTrieDirectory(projectDir), "memory");
832
+ const ledgerPath = join3(memoryDir, LEDGER_FILENAME);
833
+ await withFileLock(ledgerPath, async () => {
834
+ await saveLedgerWithConcurrencyCheck(blocks, projectDir, expectedHash);
835
+ }, { timeout: 1e4 });
836
+ }
667
837
  async function saveLedger(blocks, projectDir) {
668
838
  const ledgerPath = join3(getTrieDirectory(projectDir), "memory", LEDGER_FILENAME);
669
- await atomicWriteJSON(ledgerPath, blocks);
839
+ await withFileLock(ledgerPath, async () => {
840
+ await saveLedgerWithFormat(ledgerPath, blocks);
841
+ }, { timeout: 1e4 });
842
+ }
843
+ async function saveLedgerInternal(blocks, projectDir) {
844
+ const ledgerPath = join3(getTrieDirectory(projectDir), "memory", LEDGER_FILENAME);
845
+ await saveLedgerWithFormat(ledgerPath, blocks);
846
+ }
847
+ async function saveLedgerWithConcurrencyCheck(blocks, projectDir, expectedHash) {
848
+ const ledgerPath = join3(getTrieDirectory(projectDir), "memory", LEDGER_FILENAME);
849
+ const { contentHash: currentHash } = await loadLedgerWithHash(projectDir);
850
+ if (currentHash !== expectedHash) {
851
+ throw new ConcurrentModificationError(
852
+ `Ledger was modified by another process. Expected hash: ${expectedHash.slice(0, 16)}..., Current hash: ${currentHash.slice(0, 16)}...`
853
+ );
854
+ }
855
+ await saveLedgerWithFormat(ledgerPath, blocks);
856
+ }
857
+ async function saveLedgerWithFormat(ledgerPath, blocks) {
858
+ const blocksJson = JSON.stringify(blocks);
859
+ const contentHash = sha256(blocksJson);
860
+ const ledgerFile = {
861
+ _format: "ledger-v2",
862
+ _contentHash: contentHash,
863
+ _lastModified: (/* @__PURE__ */ new Date()).toISOString(),
864
+ blocks
865
+ };
866
+ await atomicWriteJSON(ledgerPath, ledgerFile);
670
867
  }
671
868
  function sha256(input) {
672
869
  return createHash("sha256").update(input).digest("hex");
@@ -690,15 +887,15 @@ async function ensureSharedStorageStructure(projectDir) {
690
887
  const sharedDir = getSharedLedgerDir(projectDir);
691
888
  const activeDir = getActiveBlocksDir(projectDir);
692
889
  const archivedDir = getArchivedBlocksDir(projectDir);
693
- await mkdir(sharedDir, { recursive: true });
694
- await mkdir(activeDir, { recursive: true });
695
- await mkdir(archivedDir, { recursive: true });
890
+ await mkdir2(sharedDir, { recursive: true });
891
+ await mkdir2(activeDir, { recursive: true });
892
+ await mkdir2(archivedDir, { recursive: true });
696
893
  }
697
894
  async function loadManifest(projectDir) {
698
895
  const manifestPath = getManifestPath(projectDir);
699
896
  try {
700
- if (!existsSync4(manifestPath)) return null;
701
- const content = await readFile(manifestPath, "utf-8");
897
+ if (!existsSync5(manifestPath)) return null;
898
+ const content = await readFile2(manifestPath, "utf-8");
702
899
  return JSON.parse(content);
703
900
  } catch {
704
901
  return null;
@@ -735,8 +932,8 @@ async function createDefaultManifest(_projectDir) {
735
932
  async function loadSyncState(projectDir) {
736
933
  const syncStatePath = getSyncStatePath(projectDir);
737
934
  try {
738
- if (!existsSync4(syncStatePath)) return null;
739
- const content = await readFile(syncStatePath, "utf-8");
935
+ if (!existsSync5(syncStatePath)) return null;
936
+ const content = await readFile2(syncStatePath, "utf-8");
740
937
  return JSON.parse(content);
741
938
  } catch {
742
939
  return null;
@@ -745,7 +942,7 @@ async function loadSyncState(projectDir) {
745
942
  async function saveSyncState(syncState, projectDir) {
746
943
  const syncStatePath = getSyncStatePath(projectDir);
747
944
  const memoryDir = join3(getTrieDirectory(projectDir), "memory");
748
- await mkdir(memoryDir, { recursive: true });
945
+ await mkdir2(memoryDir, { recursive: true });
749
946
  await atomicWriteJSON(syncStatePath, syncState);
750
947
  }
751
948
  async function initializeSharedLedger(workDir) {
@@ -770,54 +967,62 @@ async function initializeSharedLedger(workDir) {
770
967
  }
771
968
  async function syncLedgerFromShared(workDir) {
772
969
  const projectDir = workDir || getWorkingDirectory(void 0, true);
970
+ const memoryDir = join3(getTrieDirectory(projectDir), "memory");
971
+ const ledgerPath = join3(memoryDir, LEDGER_FILENAME);
773
972
  await initializeSharedLedger(projectDir);
774
- const manifest = await loadManifest(projectDir);
775
- const localBlocks = await loadLedger(projectDir);
776
- const sharedBlocks = await loadSharedBlocks(projectDir);
777
- if (!manifest) {
778
- throw new Error("Failed to load ledger manifest");
779
- }
780
- const mergeResult = await mergeChains(localBlocks, sharedBlocks, "timestamp");
781
- await saveLedger(mergeResult.mergedChain, projectDir);
782
- const syncState = {
783
- lastSyncTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
784
- conflicts: mergeResult.conflicts,
785
- localChanges: false,
786
- sharedChanges: false
787
- };
788
- await saveSyncState(syncState, projectDir);
789
- return mergeResult;
973
+ return withFileLock(ledgerPath, async () => {
974
+ const manifest = await loadManifest(projectDir);
975
+ const localBlocks = await loadLedger(projectDir);
976
+ const sharedBlocks = await loadSharedBlocks(projectDir);
977
+ if (!manifest) {
978
+ throw new Error("Failed to load ledger manifest");
979
+ }
980
+ const mergeResult = await mergeChains(localBlocks, sharedBlocks, "timestamp");
981
+ await saveLedgerInternal(mergeResult.mergedChain, projectDir);
982
+ const syncState = {
983
+ lastSyncTimestamp: (/* @__PURE__ */ new Date()).toISOString(),
984
+ conflicts: mergeResult.conflicts,
985
+ localChanges: false,
986
+ sharedChanges: false
987
+ };
988
+ await saveSyncState(syncState, projectDir);
989
+ return mergeResult;
990
+ }, { timeout: 3e4 });
790
991
  }
791
992
  async function pushLedgerToShared(workDir) {
792
993
  const projectDir = workDir || getWorkingDirectory(void 0, true);
994
+ const memoryDir = join3(getTrieDirectory(projectDir), "memory");
995
+ const ledgerPath = join3(memoryDir, LEDGER_FILENAME);
793
996
  await initializeSharedLedger(projectDir);
794
- const localBlocks = await loadLedger(projectDir);
795
- const manifest = await loadManifest(projectDir) || await createDefaultManifest(projectDir);
796
- const activeDir = getActiveBlocksDir(projectDir);
797
- for (const block of localBlocks) {
798
- const blockFilename = `${block.date}.json`;
799
- const blockPath = join3(activeDir, blockFilename);
800
- if (!existsSync4(blockPath) || block.updatedAt > manifest.lastSync) {
801
- await atomicWriteJSON(blockPath, block);
802
- manifest.index.byDate[block.date] = `active/${blockFilename}`;
803
- const blockAuthor = block.author;
804
- if (blockAuthor) {
805
- if (!manifest.index.byAuthor[blockAuthor]) {
806
- manifest.index.byAuthor[blockAuthor] = [];
997
+ await withFileLock(ledgerPath, async () => {
998
+ const localBlocks = await loadLedger(projectDir);
999
+ const manifest = await loadManifest(projectDir) || await createDefaultManifest(projectDir);
1000
+ const activeDir = getActiveBlocksDir(projectDir);
1001
+ for (const block of localBlocks) {
1002
+ const blockFilename = `${block.date}.json`;
1003
+ const blockPath = join3(activeDir, blockFilename);
1004
+ if (!existsSync5(blockPath) || block.updatedAt > manifest.lastSync) {
1005
+ await atomicWriteJSON(blockPath, block);
1006
+ manifest.index.byDate[block.date] = `active/${blockFilename}`;
1007
+ const blockAuthor = block.author;
1008
+ if (blockAuthor) {
1009
+ if (!manifest.index.byAuthor[blockAuthor]) {
1010
+ manifest.index.byAuthor[blockAuthor] = [];
1011
+ }
1012
+ if (!manifest.index.byAuthor[blockAuthor].includes(`active/${blockFilename}`)) {
1013
+ manifest.index.byAuthor[blockAuthor].push(`active/${blockFilename}`);
1014
+ }
807
1015
  }
808
- if (!manifest.index.byAuthor[blockAuthor].includes(`active/${blockFilename}`)) {
809
- manifest.index.byAuthor[blockAuthor].push(`active/${blockFilename}`);
1016
+ if (!manifest.activeBlocks.includes(blockFilename)) {
1017
+ manifest.activeBlocks.push(blockFilename);
810
1018
  }
811
1019
  }
812
- if (!manifest.activeBlocks.includes(blockFilename)) {
813
- manifest.activeBlocks.push(blockFilename);
814
- }
815
1020
  }
816
- }
817
- manifest.lastSync = (/* @__PURE__ */ new Date()).toISOString();
818
- manifest.totalBlocks = manifest.activeBlocks.length + manifest.archivedBlocks.length;
819
- manifest.totalEntries = localBlocks.reduce((sum, block) => sum + block.entries.length, 0);
820
- await saveManifest(manifest, projectDir);
1021
+ manifest.lastSync = (/* @__PURE__ */ new Date()).toISOString();
1022
+ manifest.totalBlocks = manifest.activeBlocks.length + manifest.archivedBlocks.length;
1023
+ manifest.totalEntries = localBlocks.reduce((sum, block) => sum + block.entries.length, 0);
1024
+ await saveManifest(manifest, projectDir);
1025
+ }, { timeout: 3e4 });
821
1026
  }
822
1027
  async function loadSharedBlocks(projectDir) {
823
1028
  const manifest = await loadManifest(projectDir);
@@ -827,8 +1032,8 @@ async function loadSharedBlocks(projectDir) {
827
1032
  for (const filename of manifest.activeBlocks) {
828
1033
  const blockPath = join3(activeDir, filename);
829
1034
  try {
830
- if (existsSync4(blockPath)) {
831
- const content = await readFile(blockPath, "utf-8");
1035
+ if (existsSync5(blockPath)) {
1036
+ const content = await readFile2(blockPath, "utf-8");
832
1037
  const block = JSON.parse(content);
833
1038
  blocks.push(block);
834
1039
  }
@@ -919,16 +1124,29 @@ function resolveConflict(conflict, strategy) {
919
1124
  if (!conflict.localBlock || !conflict.remoteBlock) {
920
1125
  return null;
921
1126
  }
1127
+ const mergedBlock = mergeBlockEntries(conflict.localBlock, conflict.remoteBlock);
1128
+ mergedBlock.conflictResolved = true;
922
1129
  switch (strategy) {
923
- case "longest":
924
- return conflict.localBlock.entries.length >= conflict.remoteBlock.entries.length ? conflict.localBlock : conflict.remoteBlock;
925
1130
  case "timestamp":
926
- return conflict.localBlock.updatedAt >= conflict.remoteBlock.updatedAt ? conflict.localBlock : conflict.remoteBlock;
1131
+ if (conflict.remoteBlock.updatedAt > conflict.localBlock.updatedAt) {
1132
+ mergedBlock.author = `${conflict.remoteBlock.author}+${conflict.localBlock.author}`;
1133
+ } else {
1134
+ mergedBlock.author = `${conflict.localBlock.author}+${conflict.remoteBlock.author}`;
1135
+ }
1136
+ break;
1137
+ case "longest":
1138
+ if (conflict.remoteBlock.entries.length > conflict.localBlock.entries.length) {
1139
+ mergedBlock.author = `${conflict.remoteBlock.author}+${conflict.localBlock.author}`;
1140
+ } else {
1141
+ mergedBlock.author = `${conflict.localBlock.author}+${conflict.remoteBlock.author}`;
1142
+ }
1143
+ break;
927
1144
  case "manual":
928
- return { ...conflict.localBlock, conflictResolved: false };
929
1145
  default:
930
- return conflict.localBlock;
1146
+ mergedBlock.author = `${conflict.localBlock.author}+${conflict.remoteBlock.author}`;
1147
+ break;
931
1148
  }
1149
+ return mergedBlock;
932
1150
  }
933
1151
  function mergeBlockEntries(localBlock, remoteBlock) {
934
1152
  const entryMap = /* @__PURE__ */ new Map();
@@ -959,7 +1177,7 @@ function mergeBlockEntries(localBlock, remoteBlock) {
959
1177
  async function migrateLegacyLedger(workDir) {
960
1178
  const projectDir = workDir || getWorkingDirectory(void 0, true);
961
1179
  const legacyLedgerPath = join3(getTrieDirectory(projectDir), "memory", LEDGER_FILENAME);
962
- if (!existsSync4(legacyLedgerPath)) {
1180
+ if (!existsSync5(legacyLedgerPath)) {
963
1181
  return false;
964
1182
  }
965
1183
  try {
@@ -994,7 +1212,7 @@ async function migrateLegacyLedger(workDir) {
994
1212
  async function detectLegacyLedger(workDir) {
995
1213
  const projectDir = workDir || getWorkingDirectory(void 0, true);
996
1214
  const legacyLedgerPath = join3(getTrieDirectory(projectDir), "memory", LEDGER_FILENAME);
997
- if (!existsSync4(legacyLedgerPath)) {
1215
+ if (!existsSync5(legacyLedgerPath)) {
998
1216
  return false;
999
1217
  }
1000
1218
  try {
@@ -1047,7 +1265,7 @@ async function compressOldBlocks(workDir) {
1047
1265
  }
1048
1266
  for (const [monthKey, blockFiles] of blocksByMonth) {
1049
1267
  const archivePath = join3(archivedDir, `${monthKey}.tar.gz`);
1050
- if (existsSync4(archivePath)) {
1268
+ if (existsSync5(archivePath)) {
1051
1269
  continue;
1052
1270
  }
1053
1271
  console.log(`Archiving ${blockFiles.length} blocks for ${monthKey}...`);
@@ -1055,9 +1273,9 @@ async function compressOldBlocks(workDir) {
1055
1273
  for (const blockFile of blockFiles) {
1056
1274
  const blockPath = join3(activeDir, blockFile);
1057
1275
  try {
1058
- const stats = await stat(blockPath);
1276
+ const stats = await stat2(blockPath);
1059
1277
  originalSize += stats.size;
1060
- const content = await readFile(blockPath, "utf-8");
1278
+ const content = await readFile2(blockPath, "utf-8");
1061
1279
  const block = JSON.parse(content);
1062
1280
  monthlyBlocks.push(block);
1063
1281
  } catch (error) {
@@ -1072,13 +1290,13 @@ async function compressOldBlocks(workDir) {
1072
1290
  createGzip({ level: manifest.compressionConfig.compressionLevel }),
1073
1291
  createWriteStream(tempPath)
1074
1292
  );
1075
- const compressedStats = await stat(tempPath);
1293
+ const compressedStats = await stat2(tempPath);
1076
1294
  compressedSize += compressedStats.size;
1077
- await writeFile(archivePath, await readFile(tempPath));
1078
- await unlink(tempPath);
1295
+ await writeFile(archivePath, await readFile2(tempPath));
1296
+ await unlink2(tempPath);
1079
1297
  for (const blockFile of blockFiles) {
1080
1298
  const blockPath = join3(activeDir, blockFile);
1081
- await unlink(blockPath);
1299
+ await unlink2(blockPath);
1082
1300
  const index = manifest.activeBlocks.indexOf(blockFile);
1083
1301
  if (index > -1) {
1084
1302
  manifest.activeBlocks.splice(index, 1);
@@ -1099,7 +1317,7 @@ async function compressOldBlocks(workDir) {
1099
1317
  async function loadArchivedBlocks(projectDir, monthKey) {
1100
1318
  const archivedDir = getArchivedBlocksDir(projectDir);
1101
1319
  const archivePath = join3(archivedDir, `${monthKey}.tar.gz`);
1102
- if (!existsSync4(archivePath)) {
1320
+ if (!existsSync5(archivePath)) {
1103
1321
  return [];
1104
1322
  }
1105
1323
  try {
@@ -1141,8 +1359,8 @@ async function getStorageStats(workDir) {
1141
1359
  for (const blockFile of manifest.activeBlocks) {
1142
1360
  const blockPath = join3(activeDir, blockFile);
1143
1361
  try {
1144
- if (existsSync4(blockPath)) {
1145
- const stats = await stat(blockPath);
1362
+ if (existsSync5(blockPath)) {
1363
+ const stats = await stat2(blockPath);
1146
1364
  activeSize += stats.size;
1147
1365
  }
1148
1366
  } catch {
@@ -1151,8 +1369,8 @@ async function getStorageStats(workDir) {
1151
1369
  for (const archiveFile of manifest.archivedBlocks) {
1152
1370
  const archivePath = join3(archivedDir, archiveFile);
1153
1371
  try {
1154
- if (existsSync4(archivePath)) {
1155
- const stats = await stat(archivePath);
1372
+ if (existsSync5(archivePath)) {
1373
+ const stats = await stat2(archivePath);
1156
1374
  archivedSize += stats.size;
1157
1375
  }
1158
1376
  } catch {
@@ -1201,94 +1419,100 @@ async function correctLedgerEntries(entryIds, reason, correctionType = "correcte
1201
1419
  };
1202
1420
  }
1203
1421
  const projectDir = workDir || getWorkingDirectory(void 0, true);
1204
- const blocks = await loadLedger(projectDir);
1205
- const entriesToCorrect = [];
1206
- for (const block of blocks) {
1207
- for (const entry of block.entries) {
1208
- if (entryIds.includes(entry.id) && entry.status === "active") {
1209
- entriesToCorrect.push(entry);
1210
- }
1211
- }
1212
- }
1213
- if (entriesToCorrect.length === 0) {
1214
- return {
1215
- success: false,
1216
- correctedEntries: 0,
1217
- error: "No active entries found with the provided IDs"
1218
- };
1219
- }
1220
- try {
1221
- const now = (/* @__PURE__ */ new Date()).toISOString();
1222
- const isRepo = await isGitRepo(projectDir);
1223
- const lastCommit = isRepo ? await getLastCommit(projectDir) : null;
1224
- const correctionAuthor = author || lastCommit?.author || "unknown";
1225
- const correctionEntries = entriesToCorrect.map((entry) => {
1226
- const correctionId = `correction-${entry.id}-${Date.now()}`;
1227
- return {
1228
- id: correctionId,
1229
- hash: sha256(`${correctionId}:${entry.hash}:${reason}:${now}`),
1230
- severity: "info",
1231
- file: entry.file,
1232
- agent: "ledger-correction",
1233
- timestamp: now,
1234
- status: "active",
1235
- correction: `Correcting entry ${entry.id}: ${reason}`,
1236
- correctedBy: entry.id
1237
- };
1238
- });
1422
+ const memoryDir = join3(getTrieDirectory(projectDir), "memory");
1423
+ const ledgerPath = join3(memoryDir, LEDGER_FILENAME);
1424
+ return withFileLock(ledgerPath, async () => {
1425
+ const blocks = await loadLedger(projectDir);
1426
+ const entriesToCorrect = [];
1239
1427
  for (const block of blocks) {
1240
- let blockModified = false;
1241
1428
  for (const entry of block.entries) {
1242
1429
  if (entryIds.includes(entry.id) && entry.status === "active") {
1243
- entry.status = correctionType;
1244
- entry.correctionTimestamp = now;
1245
- entry.correction = reason;
1246
- blockModified = true;
1430
+ entriesToCorrect.push(entry);
1247
1431
  }
1248
1432
  }
1249
- if (blockModified) {
1250
- block.merkleRoot = computeMerkleRoot(block.entries.map((e) => e.hash));
1251
- block.blockHash = computeBlockHash(
1252
- block.previousHash,
1253
- block.merkleRoot,
1254
- block.date,
1255
- block.version
1256
- );
1257
- block.updatedAt = now;
1433
+ }
1434
+ if (entriesToCorrect.length === 0) {
1435
+ return {
1436
+ success: false,
1437
+ correctedEntries: 0,
1438
+ error: "No active entries found with the provided IDs"
1439
+ };
1440
+ }
1441
+ try {
1442
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1443
+ const isRepo = await isGitRepo(projectDir);
1444
+ const lastCommit = isRepo ? await getLastCommit(projectDir) : null;
1445
+ const correctionAuthor = author || lastCommit?.author || "unknown";
1446
+ const correctionEntries = entriesToCorrect.map((entry) => {
1447
+ const correctionId = `correction-${entry.id}-${Date.now()}`;
1448
+ return {
1449
+ id: correctionId,
1450
+ hash: sha256(`${correctionId}:${entry.hash}:${reason}:${now}`),
1451
+ severity: "info",
1452
+ file: entry.file,
1453
+ agent: "ledger-correction",
1454
+ timestamp: now,
1455
+ status: "active",
1456
+ correction: `Correcting entry ${entry.id}: ${reason}`,
1457
+ correctedBy: entry.id
1458
+ };
1459
+ });
1460
+ for (const block of blocks) {
1461
+ let blockModified = false;
1462
+ for (const entry of block.entries) {
1463
+ if (entryIds.includes(entry.id) && entry.status === "active") {
1464
+ entry.status = correctionType;
1465
+ entry.correctionTimestamp = now;
1466
+ entry.correction = reason;
1467
+ blockModified = true;
1468
+ }
1469
+ }
1470
+ if (blockModified) {
1471
+ block.merkleRoot = computeMerkleRoot(block.entries.map((e) => e.hash));
1472
+ block.blockHash = computeBlockHash(
1473
+ block.previousHash,
1474
+ block.merkleRoot,
1475
+ block.date,
1476
+ block.version
1477
+ );
1478
+ block.updatedAt = now;
1479
+ }
1258
1480
  }
1481
+ await saveLedgerInternal(blocks, projectDir);
1482
+ const correctionBlock = await appendCorrectionEntries(
1483
+ correctionEntries,
1484
+ projectDir,
1485
+ correctionAuthor
1486
+ );
1487
+ return {
1488
+ success: true,
1489
+ correctedEntries: entriesToCorrect.length,
1490
+ ...correctionBlock && { correctionBlock }
1491
+ };
1492
+ } catch (error) {
1493
+ return {
1494
+ success: false,
1495
+ correctedEntries: 0,
1496
+ error: `Failed to correct entries: ${error instanceof Error ? error.message : "Unknown error"}`
1497
+ };
1259
1498
  }
1260
- await saveLedger(blocks, projectDir);
1261
- const correctionBlock = await appendIssuesToLedger(
1262
- correctionEntries.map((entry) => ({
1263
- id: entry.id,
1264
- hash: entry.hash,
1265
- severity: entry.severity,
1266
- issue: entry.correction || "",
1267
- fix: "",
1268
- file: entry.file,
1269
- line: 0,
1270
- agent: entry.agent,
1271
- category: "correction",
1272
- timestamp: entry.timestamp,
1273
- project: "",
1274
- resolved: false,
1275
- resolvedAt: void 0
1276
- })),
1277
- projectDir,
1278
- correctionAuthor
1279
- );
1280
- return {
1281
- success: true,
1282
- correctedEntries: entriesToCorrect.length,
1283
- ...correctionBlock && { correctionBlock }
1284
- };
1285
- } catch (error) {
1286
- return {
1287
- success: false,
1288
- correctedEntries: 0,
1289
- error: `Failed to correct entries: ${error instanceof Error ? error.message : "Unknown error"}`
1290
- };
1499
+ }, { timeout: 15e3 });
1500
+ }
1501
+ async function appendCorrectionEntries(correctionEntries, projectDir, author) {
1502
+ const blocks = await loadLedger(projectDir);
1503
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1504
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1505
+ const previousBlock = blocks[blocks.length - 1];
1506
+ const block = previousBlock && previousBlock.date === today ? previousBlock : createSyncableBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH, author, void 0, blocks.length);
1507
+ if (block !== previousBlock) {
1508
+ blocks.push(block);
1291
1509
  }
1510
+ block.entries = [...block.entries, ...correctionEntries];
1511
+ block.merkleRoot = computeMerkleRoot(block.entries.map((entry) => entry.hash));
1512
+ block.blockHash = computeBlockHash(block.previousHash, block.merkleRoot, block.date, block.version);
1513
+ block.updatedAt = now;
1514
+ await saveLedgerInternal(blocks, projectDir);
1515
+ return block;
1292
1516
  }
1293
1517
  async function getLedgerEntries(workDir, includeStatus) {
1294
1518
  const projectDir = workDir || getWorkingDirectory(void 0, true);
@@ -1355,6 +1579,7 @@ async function getCorrectionStats(workDir) {
1355
1579
  }
1356
1580
 
1357
1581
  export {
1582
+ withFileLock,
1358
1583
  formatAuditLog,
1359
1584
  getAuditStatistics,
1360
1585
  getRecentAuditLogs,
@@ -1367,6 +1592,12 @@ export {
1367
1592
  getWorkingTreeDiff,
1368
1593
  isGitRepo,
1369
1594
  getChangedFilesSinceTimestamp,
1595
+ generateKeyPair,
1596
+ saveKeyPair,
1597
+ loadKeyPair,
1598
+ getPublicKey,
1599
+ hasSigningKey,
1600
+ ConcurrentModificationError,
1370
1601
  signLedgerEntry,
1371
1602
  verifyLedgerEntry,
1372
1603
  verifyBlockSignatures,
@@ -1374,6 +1605,8 @@ export {
1374
1605
  verifyLedger,
1375
1606
  computeMerkleRoot,
1376
1607
  getLedgerBlocks,
1608
+ getLedgerBlocksWithHash,
1609
+ saveLedgerOptimistic,
1377
1610
  initializeSharedLedger,
1378
1611
  syncLedgerFromShared,
1379
1612
  pushLedgerToShared,
@@ -1389,4 +1622,4 @@ export {
1389
1622
  getEntryCorrectionHistory,
1390
1623
  getCorrectionStats
1391
1624
  };
1392
- //# sourceMappingURL=chunk-Y4B3VEL7.js.map
1625
+ //# sourceMappingURL=chunk-YAL3SUBG.js.map