@iworkforces/tracelattice 2.1.2 → 2.2.0

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 (125) hide show
  1. package/README.md +19 -3
  2. package/dist/contracts/PersistenceBackend.d.ts +10 -1
  3. package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
  4. package/dist/contracts/calibrator.d.ts +9 -6
  5. package/dist/contracts/calibrator.d.ts.map +1 -1
  6. package/dist/contracts/interfaces.d.ts +6 -0
  7. package/dist/contracts/interfaces.d.ts.map +1 -1
  8. package/dist/contracts/persistence-work.d.ts +13 -1
  9. package/dist/contracts/persistence-work.d.ts.map +1 -1
  10. package/dist/contracts/strategy.d.ts +14 -9
  11. package/dist/contracts/strategy.d.ts.map +1 -1
  12. package/dist/core/DurableThoughtIdentityIndex.d.ts +35 -0
  13. package/dist/core/DurableThoughtIdentityIndex.d.ts.map +1 -0
  14. package/dist/core/DurableThoughtIdentityIndex.js +94 -0
  15. package/dist/core/DurableThoughtIdentityIndex.js.map +1 -0
  16. package/dist/core/HistoryManager.d.ts +5 -0
  17. package/dist/core/HistoryManager.d.ts.map +1 -1
  18. package/dist/core/HistoryManager.js +37 -4
  19. package/dist/core/HistoryManager.js.map +1 -1
  20. package/dist/core/IHistoryManager.d.ts +2 -0
  21. package/dist/core/IHistoryManager.d.ts.map +1 -1
  22. package/dist/core/PersistenceBuffer.d.ts +7 -1
  23. package/dist/core/PersistenceBuffer.d.ts.map +1 -1
  24. package/dist/core/PersistenceBuffer.js +13 -1
  25. package/dist/core/PersistenceBuffer.js.map +1 -1
  26. package/dist/core/PersistenceRestore.d.ts.map +1 -1
  27. package/dist/core/PersistenceRestore.js +11 -3
  28. package/dist/core/PersistenceRestore.js.map +1 -1
  29. package/dist/core/PersistenceWorkQueue.d.ts +13 -1
  30. package/dist/core/PersistenceWorkQueue.d.ts.map +1 -1
  31. package/dist/core/PersistenceWorkQueue.js +86 -11
  32. package/dist/core/PersistenceWorkQueue.js.map +1 -1
  33. package/dist/core/PersistenceWriter.d.ts.map +1 -1
  34. package/dist/core/PersistenceWriter.js +3 -0
  35. package/dist/core/PersistenceWriter.js.map +1 -1
  36. package/dist/core/ThoughtEvaluator.d.ts +7 -4
  37. package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
  38. package/dist/core/ThoughtEvaluator.js +15 -7
  39. package/dist/core/ThoughtEvaluator.js.map +1 -1
  40. package/dist/core/ThoughtProcessor.d.ts.map +1 -1
  41. package/dist/core/ThoughtProcessor.js +19 -7
  42. package/dist/core/ThoughtProcessor.js.map +1 -1
  43. package/dist/core/ThoughtReferenceIndex.d.ts +4 -0
  44. package/dist/core/ThoughtReferenceIndex.d.ts.map +1 -1
  45. package/dist/core/ThoughtReferenceIndex.js +28 -1
  46. package/dist/core/ThoughtReferenceIndex.js.map +1 -1
  47. package/dist/core/VerificationOutcomeAdmission.d.ts +8 -1
  48. package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
  49. package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
  50. package/dist/core/VerificationTargetRestore.d.ts +5 -0
  51. package/dist/core/VerificationTargetRestore.d.ts.map +1 -0
  52. package/dist/core/VerificationTargetRestore.js +61 -0
  53. package/dist/core/VerificationTargetRestore.js.map +1 -0
  54. package/dist/core/evaluator/Aggregator.d.ts +2 -1
  55. package/dist/core/evaluator/Aggregator.d.ts.map +1 -1
  56. package/dist/core/evaluator/Aggregator.js +4 -12
  57. package/dist/core/evaluator/Aggregator.js.map +1 -1
  58. package/dist/core/evaluator/Calibrator.d.ts +13 -9
  59. package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
  60. package/dist/core/evaluator/Calibrator.js +25 -11
  61. package/dist/core/evaluator/Calibrator.js.map +1 -1
  62. package/dist/core/evaluator/PatternDetector.d.ts +2 -1
  63. package/dist/core/evaluator/PatternDetector.d.ts.map +1 -1
  64. package/dist/core/evaluator/PatternDetector.js +13 -12
  65. package/dist/core/evaluator/PatternDetector.js.map +1 -1
  66. package/dist/core/evaluator/SignalComputer.d.ts +3 -2
  67. package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
  68. package/dist/core/evaluator/SignalComputer.js +4 -9
  69. package/dist/core/evaluator/SignalComputer.js.map +1 -1
  70. package/dist/core/evaluator/VerificationLinks.d.ts +19 -0
  71. package/dist/core/evaluator/VerificationLinks.d.ts.map +1 -0
  72. package/dist/core/evaluator/VerificationLinks.js +113 -0
  73. package/dist/core/evaluator/VerificationLinks.js.map +1 -0
  74. package/dist/core/evaluator/calibration-math.d.ts +12 -2
  75. package/dist/core/evaluator/calibration-math.d.ts.map +1 -1
  76. package/dist/core/evaluator/calibration-math.js +11 -2
  77. package/dist/core/evaluator/calibration-math.js.map +1 -1
  78. package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
  79. package/dist/core/graph/EdgeEmitter.js +2 -1
  80. package/dist/core/graph/EdgeEmitter.js.map +1 -1
  81. package/dist/core/graph/GraphView.d.ts +5 -5
  82. package/dist/core/graph/GraphView.d.ts.map +1 -1
  83. package/dist/core/graph/GraphView.js +11 -11
  84. package/dist/core/graph/GraphView.js.map +1 -1
  85. package/dist/core/reasoning/ActiveEvidenceProjection.d.ts +20 -0
  86. package/dist/core/reasoning/ActiveEvidenceProjection.d.ts.map +1 -0
  87. package/dist/core/reasoning/ActiveEvidenceProjection.js +100 -0
  88. package/dist/core/reasoning/ActiveEvidenceProjection.js.map +1 -0
  89. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts +5 -4
  90. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
  91. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +24 -14
  92. package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
  93. package/dist/lib.d.ts.map +1 -1
  94. package/dist/lib.js +3 -1
  95. package/dist/lib.js.map +1 -1
  96. package/dist/persistence/BacktrackPersistence.d.ts +13 -0
  97. package/dist/persistence/BacktrackPersistence.d.ts.map +1 -0
  98. package/dist/persistence/BacktrackPersistence.js +90 -0
  99. package/dist/persistence/BacktrackPersistence.js.map +1 -0
  100. package/dist/persistence/FilePersistence.d.ts +2 -1
  101. package/dist/persistence/FilePersistence.d.ts.map +1 -1
  102. package/dist/persistence/FilePersistence.js +28 -0
  103. package/dist/persistence/FilePersistence.js.map +1 -1
  104. package/dist/persistence/FileSnapshotV2.d.ts +2 -0
  105. package/dist/persistence/FileSnapshotV2.d.ts.map +1 -1
  106. package/dist/persistence/FileSnapshotV2.js +6 -2
  107. package/dist/persistence/FileSnapshotV2.js.map +1 -1
  108. package/dist/persistence/MemoryPersistence.d.ts +2 -1
  109. package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
  110. package/dist/persistence/MemoryPersistence.js +21 -1
  111. package/dist/persistence/MemoryPersistence.js.map +1 -1
  112. package/dist/persistence/PersistenceCodec.d.ts.map +1 -1
  113. package/dist/persistence/PersistenceCodec.js +5 -0
  114. package/dist/persistence/PersistenceCodec.js.map +1 -1
  115. package/dist/persistence/PersistenceErrors.d.ts +1 -1
  116. package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
  117. package/dist/persistence/PersistenceErrors.js.map +1 -1
  118. package/dist/persistence/PersistenceScope.d.ts +1 -1
  119. package/dist/persistence/PersistenceScope.d.ts.map +1 -1
  120. package/dist/persistence/PersistenceScope.js.map +1 -1
  121. package/dist/persistence/SqlitePersistence.d.ts +2 -1
  122. package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
  123. package/dist/persistence/SqlitePersistence.js +18 -0
  124. package/dist/persistence/SqlitePersistence.js.map +1 -1
  125. package/package.json +4 -3
@@ -6,7 +6,7 @@ export type PersistenceScope = {
6
6
  readonly branchId?: BranchId;
7
7
  };
8
8
  /** Operations whose payload ownership is validated before mutation. */
9
- export type PersistenceWriteOperation = 'saveThought' | 'saveThoughtForSession' | 'saveBranch' | 'saveBranchForSession' | 'saveEdges' | 'saveSummaries';
9
+ export type PersistenceWriteOperation = 'saveThought' | 'saveThoughtForSession' | 'saveBacktrackForSession' | 'saveBranch' | 'saveBranchForSession' | 'saveEdges' | 'saveSummaries';
10
10
  /** Error raised before a write whose payload belongs to another namespace. */
11
11
  export declare class PersistenceScopeMismatchError extends SequentialThinkingError {
12
12
  readonly operation: PersistenceWriteOperation;
@@ -1 +1 @@
1
- {"version":3,"file":"PersistenceErrors.d.ts","sourceRoot":"","sources":["../../src/persistence/PersistenceErrors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAe,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEpE,6DAA6D;AAC7D,MAAM,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC7B,CAAC;AAEF,uEAAuE;AACvE,MAAM,MAAM,yBAAyB,GAClC,aAAa,GACb,uBAAuB,GACvB,YAAY,GACZ,sBAAsB,GACtB,WAAW,GACX,eAAe,CAAC;AAEnB,8EAA8E;AAC9E,qBAAa,6BAA8B,SAAQ,uBAAuB;IACzE,SAAgB,SAAS,EAAE,yBAAyB,CAAC;IACrD,SAAgB,aAAa,EAAE,gBAAgB,CAAC;IAChD,SAAgB,YAAY,EAAE,SAAS,gBAAgB,EAAE,CAAC;gBAGzD,SAAS,EAAE,yBAAyB,EACpC,aAAa,EAAE,gBAAgB,EAC/B,YAAY,EAAE,SAAS,gBAAgB,EAAE;CAW1C"}
1
+ {"version":3,"file":"PersistenceErrors.d.ts","sourceRoot":"","sources":["../../src/persistence/PersistenceErrors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAe,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAEpE,6DAA6D;AAC7D,MAAM,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC7B,CAAC;AAEF,uEAAuE;AACvE,MAAM,MAAM,yBAAyB,GAClC,aAAa,GACb,uBAAuB,GACvB,yBAAyB,GACzB,YAAY,GACZ,sBAAsB,GACtB,WAAW,GACX,eAAe,CAAC;AAEnB,8EAA8E;AAC9E,qBAAa,6BAA8B,SAAQ,uBAAuB;IACzE,SAAgB,SAAS,EAAE,yBAAyB,CAAC;IACrD,SAAgB,aAAa,EAAE,gBAAgB,CAAC;IAChD,SAAgB,YAAY,EAAE,SAAS,gBAAgB,EAAE,CAAC;gBAGzD,SAAS,EAAE,yBAAyB,EACpC,aAAa,EAAE,gBAAgB,EAC/B,YAAY,EAAE,SAAS,gBAAgB,EAAE;CAW1C"}
@@ -1 +1 @@
1
- {"version":3,"file":"persistence/PersistenceErrors.js","sources":["../../src/persistence/PersistenceErrors.ts"],"sourcesContent":["import type { BranchId, SessionId } from '../contracts/ids.js';\nimport { ERROR_CODES, SequentialThinkingError } from '../errors.js';\n\n/** Durable namespace associated with a persistence write. */\nexport type PersistenceScope = {\n\treadonly sessionId: SessionId;\n\treadonly branchId?: BranchId;\n};\n\n/** Operations whose payload ownership is validated before mutation. */\nexport type PersistenceWriteOperation =\n\t| 'saveThought'\n\t| 'saveThoughtForSession'\n\t| 'saveBranch'\n\t| 'saveBranchForSession'\n\t| 'saveEdges'\n\t| 'saveSummaries';\n\n/** Error raised before a write whose payload belongs to another namespace. */\nexport class PersistenceScopeMismatchError extends SequentialThinkingError {\n\tpublic readonly operation: PersistenceWriteOperation;\n\tpublic readonly expectedScope: PersistenceScope;\n\tpublic readonly actualScopes: readonly PersistenceScope[];\n\n\tconstructor(\n\t\toperation: PersistenceWriteOperation,\n\t\texpectedScope: PersistenceScope,\n\t\tactualScopes: readonly PersistenceScope[]\n\t) {\n\t\tsuper(\n\t\t\t`Persistence payload scope does not match '${expectedScope.sessionId}' for ${operation}`,\n\t\t\tERROR_CODES.PERSISTENCE_SCOPE_MISMATCH\n\t\t);\n\t\tthis.name = 'PersistenceScopeMismatchError';\n\t\tthis.operation = operation;\n\t\tthis.expectedScope = expectedScope;\n\t\tthis.actualScopes = [...actualScopes];\n\t}\n}\n"],"names":["PersistenceScopeMismatchError","SequentialThinkingError","operation","expectedScope","actualScopes","ERROR_CODES"],"mappings":";AAmBO,MAAMA,sCAAsCC;IAClC,UAAqC;IACrC,cAAgC;IAChC,aAA0C;IAE1D,YACCC,SAAoC,EACpCC,aAA+B,EAC/BC,YAAyC,CACxC;QACD,KAAK,CACJ,CAAC,0CAA0C,EAAED,cAAc,SAAS,CAAC,MAAM,EAAED,WAAW,EACxFG,YAAY,0BAA0B;QAEvC,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,SAAS,GAAGH;QACjB,IAAI,CAAC,aAAa,GAAGC;QACrB,IAAI,CAAC,YAAY,GAAG;eAAIC;SAAa;IACtC;AACD"}
1
+ {"version":3,"file":"persistence/PersistenceErrors.js","sources":["../../src/persistence/PersistenceErrors.ts"],"sourcesContent":["import type { BranchId, SessionId } from '../contracts/ids.js';\nimport { ERROR_CODES, SequentialThinkingError } from '../errors.js';\n\n/** Durable namespace associated with a persistence write. */\nexport type PersistenceScope = {\n\treadonly sessionId: SessionId;\n\treadonly branchId?: BranchId;\n};\n\n/** Operations whose payload ownership is validated before mutation. */\nexport type PersistenceWriteOperation =\n\t| 'saveThought'\n\t| 'saveThoughtForSession'\n\t| 'saveBacktrackForSession'\n\t| 'saveBranch'\n\t| 'saveBranchForSession'\n\t| 'saveEdges'\n\t| 'saveSummaries';\n\n/** Error raised before a write whose payload belongs to another namespace. */\nexport class PersistenceScopeMismatchError extends SequentialThinkingError {\n\tpublic readonly operation: PersistenceWriteOperation;\n\tpublic readonly expectedScope: PersistenceScope;\n\tpublic readonly actualScopes: readonly PersistenceScope[];\n\n\tconstructor(\n\t\toperation: PersistenceWriteOperation,\n\t\texpectedScope: PersistenceScope,\n\t\tactualScopes: readonly PersistenceScope[]\n\t) {\n\t\tsuper(\n\t\t\t`Persistence payload scope does not match '${expectedScope.sessionId}' for ${operation}`,\n\t\t\tERROR_CODES.PERSISTENCE_SCOPE_MISMATCH\n\t\t);\n\t\tthis.name = 'PersistenceScopeMismatchError';\n\t\tthis.operation = operation;\n\t\tthis.expectedScope = expectedScope;\n\t\tthis.actualScopes = [...actualScopes];\n\t}\n}\n"],"names":["PersistenceScopeMismatchError","SequentialThinkingError","operation","expectedScope","actualScopes","ERROR_CODES"],"mappings":";AAoBO,MAAMA,sCAAsCC;IAClC,UAAqC;IACrC,cAAgC;IAChC,aAA0C;IAE1D,YACCC,SAAoC,EACpCC,aAA+B,EAC/BC,YAAyC,CACxC;QACD,KAAK,CACJ,CAAC,0CAA0C,EAAED,cAAc,SAAS,CAAC,MAAM,EAAED,WAAW,EACxFG,YAAY,0BAA0B;QAEvC,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,SAAS,GAAGH;QACjB,IAAI,CAAC,aAAa,GAAGC;QACrB,IAAI,CAAC,YAAY,GAAG;eAAIC;SAAa;IACtC;AACD"}
@@ -23,7 +23,7 @@ export declare function assertPersistableThoughts(thoughts: readonly ThoughtData
23
23
  * @returns Nothing when all collection identities are compatible.
24
24
  */
25
25
  export declare function assertPersistableThoughtCollections(collections: readonly PersistedThoughtCollection[], sourcePath: string): void;
26
- export declare function assertThoughtScope(operation: Extract<PersistenceWriteOperation, 'saveThought' | 'saveThoughtForSession'>, sessionId: SessionId, thought: ThoughtData): void;
26
+ export declare function assertThoughtScope(operation: Extract<PersistenceWriteOperation, 'saveThought' | 'saveThoughtForSession' | 'saveBacktrackForSession'>, sessionId: SessionId, thought: ThoughtData): void;
27
27
  export declare function assertBranchScope(operation: Extract<PersistenceWriteOperation, 'saveBranch' | 'saveBranchForSession'>, sessionId: SessionId, branchId: BranchId, thoughts: readonly ThoughtData[]): void;
28
28
  export declare function assertEdgeScopes(sessionId: SessionId, edges: readonly Edge[]): void;
29
29
  export declare function assertSummaryScopes(sessionId: SessionId, summaries: readonly Summary[]): void;
@@ -1 +1 @@
1
- {"version":3,"file":"PersistenceScope.d.ts","sourceRoot":"","sources":["../../src/persistence/PersistenceScope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAA2B,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE7F,OAAO,EAGN,KAAK,yBAAyB,EAC9B,MAAM,wBAAwB,CAAC;AAIhC,KAAK,oBAAoB,GAAG,WAAW,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,QAAQ,CAKpF;AAED,wBAAgB,yBAAyB,CACxC,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,IAAI,SAAS,oBAAoB,EAAE,CAWrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,mCAAmC,CAClD,WAAW,EAAE,SAAS,0BAA0B,EAAE,EAClD,UAAU,EAAE,MAAM,GAChB,IAAI,CAqBN;AASD,wBAAgB,kBAAkB,CACjC,SAAS,EAAE,OAAO,CAAC,yBAAyB,EAAE,aAAa,GAAG,uBAAuB,CAAC,EACtF,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,WAAW,GAClB,IAAI,CAKN;AAED,wBAAgB,iBAAiB,CAChC,SAAS,EAAE,OAAO,CAAC,yBAAyB,EAAE,YAAY,GAAG,sBAAsB,CAAC,EACpF,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC9B,IAAI,CAYN;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,IAAI,CAOnF;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CAU7F;AAED,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,SAAS;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EAC3C,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC5B,IAAI,CAWN;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,oBAAoB,CACnC,IAAI,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACzD,KAAK,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACxD,MAAM,CAER"}
1
+ {"version":3,"file":"PersistenceScope.d.ts","sourceRoot":"","sources":["../../src/persistence/PersistenceScope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAA2B,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE7F,OAAO,EAGN,KAAK,yBAAyB,EAC9B,MAAM,wBAAwB,CAAC;AAIhC,KAAK,oBAAoB,GAAG,WAAW,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,QAAQ,CAKpF;AAED,wBAAgB,yBAAyB,CACxC,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,IAAI,SAAS,oBAAoB,EAAE,CAWrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,mCAAmC,CAClD,WAAW,EAAE,SAAS,0BAA0B,EAAE,EAClD,UAAU,EAAE,MAAM,GAChB,IAAI,CAqBN;AASD,wBAAgB,kBAAkB,CACjC,SAAS,EAAE,OAAO,CACjB,yBAAyB,EACzB,aAAa,GAAG,uBAAuB,GAAG,yBAAyB,CACnE,EACD,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,WAAW,GAClB,IAAI,CAKN;AAED,wBAAgB,iBAAiB,CAChC,SAAS,EAAE,OAAO,CAAC,yBAAyB,EAAE,YAAY,GAAG,sBAAsB,CAAC,EACpF,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC9B,IAAI,CAYN;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,IAAI,CAOnF;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CAU7F;AAED,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,SAAS;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EAC3C,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC5B,IAAI,CAWN;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,oBAAoB,CACnC,IAAI,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EACzD,KAAK,EAAE;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACxD,MAAM,CAER"}
@@ -1 +1 @@
1
- {"version":3,"file":"persistence/PersistenceScope.js","sources":["../../src/persistence/PersistenceScope.ts"],"sourcesContent":["import { isDeepStrictEqual } from 'node:util';\nimport type { ThoughtData } from '../core/thought.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport { asBranchId, asSessionId, type BranchId, type SessionId } from '../contracts/ids.js';\nimport { PersistenceCompatibilityError } from '../errors.js';\nimport {\n\tPersistenceScopeMismatchError,\n\ttype PersistenceScope,\n\ttype PersistenceWriteOperation,\n} from './PersistenceErrors.js';\n\nconst BRANCH_ID_PATTERN = /^[A-Za-z0-9_-]{1,50}$/;\n\ntype PersistedThoughtData = ThoughtData & { readonly id: string };\n\nexport interface PersistedThoughtCollection {\n\treadonly sessionId: SessionId;\n\treadonly thoughts: readonly ThoughtData[];\n}\n\nexport function parsePersistenceBranchId(value: string, sourcePath: string): BranchId {\n\tif (!BRANCH_ID_PATTERN.test(value)) {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, `invalid branch id '${value}'`);\n\t}\n\treturn asBranchId(value);\n}\n\nexport function assertPersistableThoughts(\n\tthoughts: readonly ThoughtData[],\n\tsourcePath: string\n): asserts thoughts is readonly PersistedThoughtData[] {\n\tconst identifiers = new Set<string>();\n\tfor (const thought of thoughts) {\n\t\tif (thought.id === undefined || thought.id.length === 0) {\n\t\t\tthrow new PersistenceCompatibilityError(sourcePath, 'persisted thoughts require an id');\n\t\t}\n\t\tif (identifiers.has(thought.id)) {\n\t\t\tthrow new PersistenceCompatibilityError(sourcePath, `duplicate thought id '${thought.id}'`);\n\t\t}\n\t\tidentifiers.add(thought.id);\n\t}\n}\n\n/**\n * Enforces thought identity across session-tagged persisted arrays.\n *\n * Each array must contain unique IDs. Reuse between arrays is valid only for deeply equal\n * payloads in the same session; equal identifiers in different sessions are independent.\n *\n * @param collections - History and branch arrays tagged with their owning session.\n * @param sourcePath - Persistence location included in compatibility errors.\n * @returns Nothing when all collection identities are compatible.\n */\nexport function assertPersistableThoughtCollections(\n\tcollections: readonly PersistedThoughtCollection[],\n\tsourcePath: string\n): void {\n\tconst payloadsBySession = new Map<SessionId, Map<string, ThoughtData>>();\n\tfor (const collection of collections) {\n\t\tassertPersistableThoughts(collection.thoughts, sourcePath);\n\t\tlet sessionPayloads = payloadsBySession.get(collection.sessionId);\n\t\tif (sessionPayloads === undefined) {\n\t\t\tsessionPayloads = new Map<string, ThoughtData>();\n\t\t\tpayloadsBySession.set(collection.sessionId, sessionPayloads);\n\t\t}\n\t\tfor (const thought of collection.thoughts) {\n\t\t\tconst identifier = thought.id;\n\t\t\tconst existing = sessionPayloads.get(identifier);\n\t\t\tif (existing !== undefined && !isDeepStrictEqual(existing, thought)) {\n\t\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\t\tsourcePath,\n\t\t\t\t\t`conflicting thought id '${identifier}'`\n\t\t\t\t);\n\t\t\t}\n\t\t\tsessionPayloads.set(identifier, thought);\n\t\t}\n\t}\n}\n\nfunction thoughtScope(thought: ThoughtData): PersistenceScope {\n\treturn {\n\t\tsessionId: asSessionId(thought.session_id),\n\t\t...(thought.branch_id === undefined ? {} : { branchId: thought.branch_id }),\n\t};\n}\n\nexport function assertThoughtScope(\n\toperation: Extract<PersistenceWriteOperation, 'saveThought' | 'saveThoughtForSession'>,\n\tsessionId: SessionId,\n\tthought: ThoughtData\n): void {\n\tconst actualScope = thoughtScope(thought);\n\tif (actualScope.sessionId !== sessionId) {\n\t\tthrow new PersistenceScopeMismatchError(operation, { sessionId }, [actualScope]);\n\t}\n}\n\nexport function assertBranchScope(\n\toperation: Extract<PersistenceWriteOperation, 'saveBranch' | 'saveBranchForSession'>,\n\tsessionId: SessionId,\n\tbranchId: BranchId,\n\tthoughts: readonly ThoughtData[]\n): void {\n\tconst expectedScope = { sessionId, branchId } satisfies PersistenceScope;\n\tconst mismatches = thoughts\n\t\t.map(thoughtScope)\n\t\t.filter(\n\t\t\t(scope) =>\n\t\t\t\tscope.sessionId !== expectedScope.sessionId ||\n\t\t\t\t(scope.branchId !== undefined && scope.branchId !== expectedScope.branchId)\n\t\t);\n\tif (mismatches.length > 0) {\n\t\tthrow new PersistenceScopeMismatchError(operation, expectedScope, mismatches);\n\t}\n}\n\nexport function assertEdgeScopes(sessionId: SessionId, edges: readonly Edge[]): void {\n\tconst actualScopes = edges\n\t\t.filter((edge) => edge.sessionId !== sessionId)\n\t\t.map((edge) => ({ sessionId: edge.sessionId }));\n\tif (actualScopes.length > 0) {\n\t\tthrow new PersistenceScopeMismatchError('saveEdges', { sessionId }, actualScopes);\n\t}\n}\n\nexport function assertSummaryScopes(sessionId: SessionId, summaries: readonly Summary[]): void {\n\tconst actualScopes = summaries\n\t\t.filter((summary) => summary.sessionId !== sessionId)\n\t\t.map((summary) => ({\n\t\t\tsessionId: summary.sessionId,\n\t\t\t...(summary.branchId === undefined ? {} : { branchId: summary.branchId }),\n\t\t}));\n\tif (actualScopes.length > 0) {\n\t\tthrow new PersistenceScopeMismatchError('saveSummaries', { sessionId }, actualScopes);\n\t}\n}\n\nexport function assertUniqueRecordIds(\n\trecords: readonly { readonly id: string }[],\n\tsourcePath: string,\n\trecordKind: 'edge' | 'summary'\n): void {\n\tconst identifiers = new Set<string>();\n\tfor (const record of records) {\n\t\tif (identifiers.has(record.id)) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tsourcePath,\n\t\t\t\t`duplicate ${recordKind} id '${record.id}'`\n\t\t\t);\n\t\t}\n\t\tidentifiers.add(record.id);\n\t}\n}\n\nexport function compareCodePoint(left: string, right: string): number {\n\treturn left < right ? -1 : left > right ? 1 : 0;\n}\n\nexport function compareCreatedThenId(\n\tleft: { readonly createdAt: number; readonly id: string },\n\tright: { readonly createdAt: number; readonly id: string }\n): number {\n\treturn left.createdAt - right.createdAt || compareCodePoint(left.id, right.id);\n}\n"],"names":["BRANCH_ID_PATTERN","parsePersistenceBranchId","value","sourcePath","PersistenceCompatibilityError","asBranchId","assertPersistableThoughts","thoughts","identifiers","Set","thought","undefined","assertPersistableThoughtCollections","collections","payloadsBySession","Map","collection","sessionPayloads","identifier","existing","isDeepStrictEqual","thoughtScope","asSessionId","assertThoughtScope","operation","sessionId","actualScope","PersistenceScopeMismatchError","assertBranchScope","branchId","expectedScope","mismatches","scope","assertEdgeScopes","edges","actualScopes","edge","assertSummaryScopes","summaries","summary","assertUniqueRecordIds","records","recordKind","record","compareCodePoint","left","right","compareCreatedThenId"],"mappings":"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"}
1
+ {"version":3,"file":"persistence/PersistenceScope.js","sources":["../../src/persistence/PersistenceScope.ts"],"sourcesContent":["import { isDeepStrictEqual } from 'node:util';\nimport type { ThoughtData } from '../core/thought.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport { asBranchId, asSessionId, type BranchId, type SessionId } from '../contracts/ids.js';\nimport { PersistenceCompatibilityError } from '../errors.js';\nimport {\n\tPersistenceScopeMismatchError,\n\ttype PersistenceScope,\n\ttype PersistenceWriteOperation,\n} from './PersistenceErrors.js';\n\nconst BRANCH_ID_PATTERN = /^[A-Za-z0-9_-]{1,50}$/;\n\ntype PersistedThoughtData = ThoughtData & { readonly id: string };\n\nexport interface PersistedThoughtCollection {\n\treadonly sessionId: SessionId;\n\treadonly thoughts: readonly ThoughtData[];\n}\n\nexport function parsePersistenceBranchId(value: string, sourcePath: string): BranchId {\n\tif (!BRANCH_ID_PATTERN.test(value)) {\n\t\tthrow new PersistenceCompatibilityError(sourcePath, `invalid branch id '${value}'`);\n\t}\n\treturn asBranchId(value);\n}\n\nexport function assertPersistableThoughts(\n\tthoughts: readonly ThoughtData[],\n\tsourcePath: string\n): asserts thoughts is readonly PersistedThoughtData[] {\n\tconst identifiers = new Set<string>();\n\tfor (const thought of thoughts) {\n\t\tif (thought.id === undefined || thought.id.length === 0) {\n\t\t\tthrow new PersistenceCompatibilityError(sourcePath, 'persisted thoughts require an id');\n\t\t}\n\t\tif (identifiers.has(thought.id)) {\n\t\t\tthrow new PersistenceCompatibilityError(sourcePath, `duplicate thought id '${thought.id}'`);\n\t\t}\n\t\tidentifiers.add(thought.id);\n\t}\n}\n\n/**\n * Enforces thought identity across session-tagged persisted arrays.\n *\n * Each array must contain unique IDs. Reuse between arrays is valid only for deeply equal\n * payloads in the same session; equal identifiers in different sessions are independent.\n *\n * @param collections - History and branch arrays tagged with their owning session.\n * @param sourcePath - Persistence location included in compatibility errors.\n * @returns Nothing when all collection identities are compatible.\n */\nexport function assertPersistableThoughtCollections(\n\tcollections: readonly PersistedThoughtCollection[],\n\tsourcePath: string\n): void {\n\tconst payloadsBySession = new Map<SessionId, Map<string, ThoughtData>>();\n\tfor (const collection of collections) {\n\t\tassertPersistableThoughts(collection.thoughts, sourcePath);\n\t\tlet sessionPayloads = payloadsBySession.get(collection.sessionId);\n\t\tif (sessionPayloads === undefined) {\n\t\t\tsessionPayloads = new Map<string, ThoughtData>();\n\t\t\tpayloadsBySession.set(collection.sessionId, sessionPayloads);\n\t\t}\n\t\tfor (const thought of collection.thoughts) {\n\t\t\tconst identifier = thought.id;\n\t\t\tconst existing = sessionPayloads.get(identifier);\n\t\t\tif (existing !== undefined && !isDeepStrictEqual(existing, thought)) {\n\t\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\t\tsourcePath,\n\t\t\t\t\t`conflicting thought id '${identifier}'`\n\t\t\t\t);\n\t\t\t}\n\t\t\tsessionPayloads.set(identifier, thought);\n\t\t}\n\t}\n}\n\nfunction thoughtScope(thought: ThoughtData): PersistenceScope {\n\treturn {\n\t\tsessionId: asSessionId(thought.session_id),\n\t\t...(thought.branch_id === undefined ? {} : { branchId: thought.branch_id }),\n\t};\n}\n\nexport function assertThoughtScope(\n\toperation: Extract<\n\t\tPersistenceWriteOperation,\n\t\t'saveThought' | 'saveThoughtForSession' | 'saveBacktrackForSession'\n\t>,\n\tsessionId: SessionId,\n\tthought: ThoughtData\n): void {\n\tconst actualScope = thoughtScope(thought);\n\tif (actualScope.sessionId !== sessionId) {\n\t\tthrow new PersistenceScopeMismatchError(operation, { sessionId }, [actualScope]);\n\t}\n}\n\nexport function assertBranchScope(\n\toperation: Extract<PersistenceWriteOperation, 'saveBranch' | 'saveBranchForSession'>,\n\tsessionId: SessionId,\n\tbranchId: BranchId,\n\tthoughts: readonly ThoughtData[]\n): void {\n\tconst expectedScope = { sessionId, branchId } satisfies PersistenceScope;\n\tconst mismatches = thoughts\n\t\t.map(thoughtScope)\n\t\t.filter(\n\t\t\t(scope) =>\n\t\t\t\tscope.sessionId !== expectedScope.sessionId ||\n\t\t\t\t(scope.branchId !== undefined && scope.branchId !== expectedScope.branchId)\n\t\t);\n\tif (mismatches.length > 0) {\n\t\tthrow new PersistenceScopeMismatchError(operation, expectedScope, mismatches);\n\t}\n}\n\nexport function assertEdgeScopes(sessionId: SessionId, edges: readonly Edge[]): void {\n\tconst actualScopes = edges\n\t\t.filter((edge) => edge.sessionId !== sessionId)\n\t\t.map((edge) => ({ sessionId: edge.sessionId }));\n\tif (actualScopes.length > 0) {\n\t\tthrow new PersistenceScopeMismatchError('saveEdges', { sessionId }, actualScopes);\n\t}\n}\n\nexport function assertSummaryScopes(sessionId: SessionId, summaries: readonly Summary[]): void {\n\tconst actualScopes = summaries\n\t\t.filter((summary) => summary.sessionId !== sessionId)\n\t\t.map((summary) => ({\n\t\t\tsessionId: summary.sessionId,\n\t\t\t...(summary.branchId === undefined ? {} : { branchId: summary.branchId }),\n\t\t}));\n\tif (actualScopes.length > 0) {\n\t\tthrow new PersistenceScopeMismatchError('saveSummaries', { sessionId }, actualScopes);\n\t}\n}\n\nexport function assertUniqueRecordIds(\n\trecords: readonly { readonly id: string }[],\n\tsourcePath: string,\n\trecordKind: 'edge' | 'summary'\n): void {\n\tconst identifiers = new Set<string>();\n\tfor (const record of records) {\n\t\tif (identifiers.has(record.id)) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tsourcePath,\n\t\t\t\t`duplicate ${recordKind} id '${record.id}'`\n\t\t\t);\n\t\t}\n\t\tidentifiers.add(record.id);\n\t}\n}\n\nexport function compareCodePoint(left: string, right: string): number {\n\treturn left < right ? -1 : left > right ? 1 : 0;\n}\n\nexport function compareCreatedThenId(\n\tleft: { readonly createdAt: number; readonly id: string },\n\tright: { readonly createdAt: number; readonly id: string }\n): number {\n\treturn left.createdAt - right.createdAt || compareCodePoint(left.id, right.id);\n}\n"],"names":["BRANCH_ID_PATTERN","parsePersistenceBranchId","value","sourcePath","PersistenceCompatibilityError","asBranchId","assertPersistableThoughts","thoughts","identifiers","Set","thought","undefined","assertPersistableThoughtCollections","collections","payloadsBySession","Map","collection","sessionPayloads","identifier","existing","isDeepStrictEqual","thoughtScope","asSessionId","assertThoughtScope","operation","sessionId","actualScope","PersistenceScopeMismatchError","assertBranchScope","branchId","expectedScope","mismatches","scope","assertEdgeScopes","edges","actualScopes","edge","assertSummaryScopes","summaries","summary","assertUniqueRecordIds","records","recordKind","record","compareCodePoint","left","right","compareCreatedThenId"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { PersistenceConfig, PersistenceBackend } from '../contracts/PersistenceBackend.js';
2
- import { type BranchId, type SessionId } from '../contracts/ids.js';
2
+ import { type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';
3
3
  import type { Summary } from '../core/compression/Summary.js';
4
4
  import type { Edge } from '../core/graph/Edge.js';
5
5
  import type { ThoughtData } from '../core/thought.js';
@@ -14,6 +14,7 @@ export declare class SqlitePersistence implements PersistenceBackend {
14
14
  static createWithDatabase(database: SqliteDatabase, options?: SqliteOptions, sourcePath?: string): SqlitePersistence;
15
15
  static create(options?: SqliteOptions): Promise<SqlitePersistence>;
16
16
  saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void>;
17
+ saveBacktrackForSession(sessionId: SessionId, thought: ThoughtData, targetThoughtId: ThoughtId): Promise<void>;
17
18
  private _saveThought;
18
19
  loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]>;
19
20
  saveBranchForSession(sessionId: SessionId, branchId: BranchId, thoughts: readonly ThoughtData[]): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"SqlitePersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/SqlitePersistence.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAe,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAA6B,MAAM,mBAAmB,CAAC;AAsBnF,KAAK,aAAa,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAOlD,qBAAa,iBAAkB,YAAW,kBAAkB;IAE1D,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAJlC,OAAO;WAOO,kBAAkB,CAC/B,QAAQ,EAAE,cAAc,EACxB,OAAO,GAAE,aAAkB,EAC3B,UAAU,SAAwB,GAChC,iBAAiB;WAUA,MAAM,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAgClE,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7F,OAAO,CAAC,YAAY;IAwBP,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAQnE,oBAAoB,CAChC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC;IAOhB,OAAO,CAAC,WAAW;IAoBN,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/E,oBAAoB,CAChC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC;IASxB,sBAAsB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAUjE,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAUpC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOzB,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IASjD,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBtE,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAUhD,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBjF,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAUvD,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAU3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,QAAQ,IAAI;QAClB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACxB;IAcD,OAAO,CAAC,0BAA0B;IAoDlC,OAAO,CAAC,eAAe;CAMvB"}
1
+ {"version":3,"file":"SqlitePersistence.d.ts","sourceRoot":"","sources":["../../src/persistence/SqlitePersistence.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ import { runSqliteReadTransaction, runSqliteTransaction } from "./SqliteDriver.j
7
7
  import { decodeEdgeRow, decodeSummaryRow, decodeThoughtRow, numberField, stringField } from "./SqlitePayload.js";
8
8
  import { assertBranchScope, assertEdgeScopes, assertPersistableThoughtCollections, assertPersistableThoughts, assertSummaryScopes, assertThoughtScope, compareCodePoint, parsePersistenceBranchId } from "./PersistenceScope.js";
9
9
  import { initializeOrValidateSqliteV2 } from "./SqliteSchemaV2.js";
10
+ import { stageBacktrackPersistence } from "./BacktrackPersistence.js";
10
11
  class SqlitePersistence {
11
12
  _db;
12
13
  _sourcePath;
@@ -52,6 +53,23 @@ class SqlitePersistence {
52
53
  assertThoughtScope('saveThoughtForSession', validatedSessionId, thought);
53
54
  this._saveThought(validatedSessionId, thought);
54
55
  }
56
+ async saveBacktrackForSession(sessionId, thought, targetThoughtId) {
57
+ const validatedSessionId = asSessionId(sessionId);
58
+ runSqliteTransaction(this._db, ()=>{
59
+ const current = this._loadValidatedThoughtState(validatedSessionId);
60
+ const staged = stageBacktrackPersistence(validatedSessionId, current.history, [
61
+ ...current.branches
62
+ ].map(([branchId, thoughts])=>({
63
+ branchId,
64
+ thoughts
65
+ })), thought, targetThoughtId, this._maxHistorySize);
66
+ this._db.prepare('DELETE FROM thoughts WHERE session_id = ?').run(validatedSessionId);
67
+ const insertThought = this._db.prepare('INSERT INTO thoughts (session_id, data) VALUES (?, ?)');
68
+ for (const retained of staged.history)insertThought.run(validatedSessionId, JSON.stringify(retained));
69
+ const replaceBranch = this._db.prepare('INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)');
70
+ for (const branch of staged.branches)replaceBranch.run(validatedSessionId, branch.branchId, JSON.stringify(branch.thoughts));
71
+ });
72
+ }
55
73
  _saveThought(sessionId, thought) {
56
74
  runSqliteTransaction(this._db, ()=>{
57
75
  this._loadValidatedThoughtState(sessionId, [
@@ -1 +1 @@
1
- {"version":3,"file":"persistence/SqlitePersistence.js","sources":["../../src/persistence/SqlitePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type {\n\tPersistenceConfig,\n\tPersistenceBackend,\n} from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId } from '../contracts/ids.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError, PersistenceCorruptionError } from '../errors.js';\nimport type { SqliteDatabase, SqliteDatabaseConstructor } from './SqliteDriver.js';\nimport { runSqliteReadTransaction, runSqliteTransaction } from './SqliteDriver.js';\nimport {\n\tdecodeEdgeRow,\n\tdecodeSummaryRow,\n\tdecodeThoughtRow,\n\tnumberField,\n\tstringField,\n} from './SqlitePayload.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n\ttype PersistedThoughtCollection,\n} from './PersistenceScope.js';\nimport { initializeOrValidateSqliteV2 } from './SqliteSchemaV2.js';\n\ntype SqliteOptions = PersistenceConfig['options'];\n\ntype ValidatedThoughtState = {\n\treadonly history: ThoughtData[];\n\treadonly branches: ReadonlyMap<BranchId, ThoughtData[]>;\n};\n\nexport class SqlitePersistence implements PersistenceBackend {\n\tprivate constructor(\n\t\tprivate readonly _db: SqliteDatabase,\n\t\tprivate readonly _sourcePath: string,\n\t\tprivate readonly _maxHistorySize: number,\n\t\tprivate readonly _persistBranches: boolean\n\t) {}\n\n\tpublic static createWithDatabase(\n\t\tdatabase: SqliteDatabase,\n\t\toptions: SqliteOptions = {},\n\t\tsourcePath = '<structural-sqlite>'\n\t): SqlitePersistence {\n\t\tinitializeOrValidateSqliteV2(database, sourcePath);\n\t\treturn new SqlitePersistence(\n\t\t\tdatabase,\n\t\t\tsourcePath,\n\t\t\toptions?.maxHistorySize ?? 10000,\n\t\t\toptions?.persistBranches ?? true\n\t\t);\n\t}\n\n\tpublic static async create(options?: SqliteOptions): Promise<SqlitePersistence> {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tconst dbPath = options?.dbPath ?? join(defaultDataDir, 'history.db');\n\t\tlet Database: SqliteDatabaseConstructor;\n\t\ttry {\n\t\t\tconst module = await import('better-sqlite3');\n\t\t\tDatabase = module.default;\n\t\t} catch (error) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tdbPath,\n\t\t\t\t\"SQLite persistence requires the optional 'better-sqlite3' package\",\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t\tconst database = new Database(dbPath);\n\t\ttry {\n\t\t\tconst persistence = SqlitePersistence.createWithDatabase(database, options, dbPath);\n\t\t\tif (options?.enableWAL !== false) database.pragma('journal_mode = WAL');\n\t\t\tdatabase.pragma('synchronous = NORMAL');\n\t\t\tdatabase.pragma('foreign_keys = ON');\n\t\t\tdatabase.pragma('busy_timeout = 5000');\n\t\t\tdatabase.pragma('cache_size = -64000');\n\t\t\tdatabase.pragma('temp_store = MEMORY');\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tdatabase.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tthis._saveThought(validatedSessionId, thought);\n\t}\n\n\tprivate _saveThought(sessionId: SessionId, thought: ThoughtData): void {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, [thought]);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT INTO thoughts (session_id, data) VALUES (?, ?)')\n\t\t\t\t.run(sessionId, JSON.stringify(thought));\n\t\t\tif (this._maxHistorySize > 0) {\n\t\t\t\tconst countRow = this._db\n\t\t\t\t\t.prepare('SELECT COUNT(*) AS count FROM thoughts WHERE session_id = ?')\n\t\t\t\t\t.get(sessionId);\n\t\t\t\tconst excess =\n\t\t\t\t\tnumberField(countRow, 'count', `${this._sourcePath}:thought-count`) -\n\t\t\t\t\tthis._maxHistorySize;\n\t\t\t\tif (excess > 0) {\n\t\t\t\t\tthis._db\n\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t'DELETE FROM thoughts WHERE id IN (SELECT id FROM thoughts WHERE session_id = ? ORDER BY id ASC LIMIT ?)'\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.run(sessionId, excess);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn runSqliteReadTransaction(\n\t\t\tthis._db,\n\t\t\t() => this._loadValidatedThoughtState(validatedSessionId).history\n\t\t);\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tthis._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): void {\n\t\tassertPersistableThoughts(thoughts, `${this._sourcePath}:branch:${branchId}`);\n\t\tif (!this._persistBranches) {\n\t\t\trunSqliteReadTransaction(this._db, () =>\n\t\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId)\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)')\n\t\t\t\t.run(sessionId, branchId, JSON.stringify(thoughts));\n\t\t});\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db\n\t\t\t\t.prepare('DELETE FROM branches WHERE session_id = ? AND branch_id = ?')\n\t\t\t\t.run(validatedSessionId, validatedBranchId);\n\t\t});\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\treturn runSqliteReadTransaction(this._db, () =>\n\t\t\tthis._loadValidatedThoughtState(validatedSessionId).branches.get(validatedBranchId)\n\t\t);\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\treturn this._db\n\t\t\t.prepare('SELECT branch_id FROM branches WHERE session_id = ? ORDER BY branch_id ASC')\n\t\t\t.all(asSessionId(sessionId))\n\t\t\t.map((row) =>\n\t\t\t\tparsePersistenceBranchId(stringField(row, 'branch_id', this._sourcePath), this._sourcePath)\n\t\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT session_id FROM thoughts UNION SELECT session_id FROM branches UNION SELECT session_id FROM edges UNION SELECT session_id FROM summaries'\n\t\t\t)\n\t\t\t.all()\n\t\t\t.map((row) => asSessionId(stringField(row, 'session_id', this._sourcePath)))\n\t\t\t.sort(compareCodePoint);\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries'])\n\t\t\t\tthis._db.exec(`DELETE FROM ${table}`);\n\t\t});\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries']) {\n\t\t\t\tthis._db.prepare(`DELETE FROM ${table} WHERE session_id = ?`).run(validatedSessionId);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM edges WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO edges (id, session_id, from_id, to_id, kind, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const edge of edges)\n\t\t\t\tinsert.run(\n\t\t\t\t\tedge.id,\n\t\t\t\t\tedge.sessionId,\n\t\t\t\t\tedge.from,\n\t\t\t\t\tedge.to,\n\t\t\t\t\tedge.kind,\n\t\t\t\t\tedge.createdAt,\n\t\t\t\t\tedge.metadata === undefined ? null : JSON.stringify(edge.metadata)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeEdgeRow(row, `${this._sourcePath}:edges:${index}`));\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM summaries WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO summaries (id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const summary of summaries)\n\t\t\t\tinsert.run(\n\t\t\t\t\tsummary.id,\n\t\t\t\t\tsummary.sessionId,\n\t\t\t\t\tsummary.branchId ?? null,\n\t\t\t\t\tsummary.rootThoughtId,\n\t\t\t\t\tJSON.stringify(summary.coveredIds),\n\t\t\t\t\tsummary.coveredRange[0],\n\t\t\t\t\tsummary.coveredRange[1],\n\t\t\t\t\tJSON.stringify(summary.topics),\n\t\t\t\t\tsummary.aggregateConfidence,\n\t\t\t\t\tsummary.createdAt,\n\t\t\t\t\tsummary.meta === undefined ? null : JSON.stringify(summary.meta)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta FROM summaries WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeSummaryRow(row, `${this._sourcePath}:summaries:${index}`));\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tthis._db.prepare('SELECT 1').get();\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) return false;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis._db.close();\n\t}\n\n\tpublic getStats(): {\n\t\treadonly thoughtCount: number;\n\t\treadonly branchCount: number;\n\t\treadonly dbSize: number;\n\t} {\n\t\tconst thoughtCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM thoughts').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\tconst branchCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM branches').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\treturn { thoughtCount, branchCount: this._persistBranches ? branchCount : 0, dbSize: 0 };\n\t}\n\n\tprivate _loadValidatedThoughtState(\n\t\tsessionId: SessionId,\n\t\tcandidates: readonly ThoughtData[] = [],\n\t\treplacingBranch?: BranchId\n\t): ValidatedThoughtState {\n\t\tconst history = this.loadHistoryRows(sessionId);\n\t\tfor (const thought of history) {\n\t\t\tassertThoughtScope('saveThoughtForSession', sessionId, thought);\n\t\t}\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{\n\t\t\t\tsessionId,\n\t\t\t\tthoughts: replacingBranch === undefined ? [...history, ...candidates] : history,\n\t\t\t},\n\t\t];\n\t\tconst branches = new Map<BranchId, ThoughtData[]>();\n\t\tfor (const row of this._db\n\t\t\t.prepare('SELECT branch_id, data FROM branches WHERE session_id = ?')\n\t\t\t.all(sessionId)) {\n\t\t\tconst branchId = parsePersistenceBranchId(\n\t\t\t\tstringField(row, 'branch_id', this._sourcePath),\n\t\t\t\tthis._sourcePath\n\t\t\t);\n\t\t\tconst data = stringField(row, 'data', this._sourcePath);\n\t\t\tlet values: unknown;\n\t\t\ttry {\n\t\t\t\tvalues = JSON.parse(data);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new PersistenceCorruptionError(this._sourcePath, error);\n\t\t\t}\n\t\t\tif (!Array.isArray(values))\n\t\t\t\tthrow new PersistenceCorruptionError(\n\t\t\t\t\tthis._sourcePath,\n\t\t\t\t\tnew TypeError('branch data is not an array')\n\t\t\t\t);\n\t\t\tconst thoughts = values.map((value, index) =>\n\t\t\t\tdecodeThoughtRow(\n\t\t\t\t\t{ data: JSON.stringify(value) },\n\t\t\t\t\t`${this._sourcePath}:branch:${sessionId}:${branchId}:${index}`\n\t\t\t\t)\n\t\t\t);\n\t\t\tassertBranchScope('saveBranchForSession', sessionId, branchId, thoughts);\n\t\t\tbranches.set(branchId, thoughts);\n\t\t\tif (branchId !== replacingBranch) collections.push({ sessionId, thoughts });\n\t\t}\n\t\tif (replacingBranch !== undefined) {\n\t\t\tcollections.push({ sessionId, thoughts: candidates });\n\t\t}\n\t\tassertPersistableThoughtCollections(collections, this._sourcePath);\n\t\treturn { history, branches };\n\t}\n\n\tprivate loadHistoryRows(sessionId: SessionId): ThoughtData[] {\n\t\treturn this._db\n\t\t\t.prepare('SELECT data FROM thoughts WHERE session_id = ? ORDER BY id ASC')\n\t\t\t.all(sessionId)\n\t\t\t.map((row) => decodeThoughtRow(row, this._sourcePath));\n\t}\n}\n"],"names":["SqlitePersistence","_db","_sourcePath","_maxHistorySize","_persistBranches","database","options","sourcePath","initializeOrValidateSqliteV2","defaultDataDir","existsSync","join","homedir","dbPath","Database","module","error","PersistenceCompatibilityError","persistence","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","runSqliteTransaction","JSON","countRow","excess","numberField","runSqliteReadTransaction","branchId","thoughts","validatedBranchId","parsePersistenceBranchId","assertBranchScope","assertPersistableThoughts","row","stringField","compareCodePoint","table","edges","assertEdgeScopes","insert","edge","undefined","index","decodeEdgeRow","summaries","assertSummaryScopes","summary","decodeSummaryRow","Error","thoughtCount","branchCount","candidates","replacingBranch","history","collections","branches","Map","data","values","PersistenceCorruptionError","Array","TypeError","value","decodeThoughtRow","assertPersistableThoughtCollections"],"mappings":"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"}
1
+ {"version":3,"file":"persistence/SqlitePersistence.js","sources":["../../src/persistence/SqlitePersistence.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { PersistenceConfig, PersistenceBackend } from '../contracts/PersistenceBackend.js';\nimport { asSessionId, type BranchId, type SessionId, type ThoughtId } from '../contracts/ids.js';\nimport type { Summary } from '../core/compression/Summary.js';\nimport type { Edge } from '../core/graph/Edge.js';\nimport type { ThoughtData } from '../core/thought.js';\nimport { PersistenceCompatibilityError, PersistenceCorruptionError } from '../errors.js';\nimport type { SqliteDatabase, SqliteDatabaseConstructor } from './SqliteDriver.js';\nimport { runSqliteReadTransaction, runSqliteTransaction } from './SqliteDriver.js';\nimport {\n\tdecodeEdgeRow,\n\tdecodeSummaryRow,\n\tdecodeThoughtRow,\n\tnumberField,\n\tstringField,\n} from './SqlitePayload.js';\nimport {\n\tassertBranchScope,\n\tassertEdgeScopes,\n\tassertPersistableThoughtCollections,\n\tassertPersistableThoughts,\n\tassertSummaryScopes,\n\tassertThoughtScope,\n\tcompareCodePoint,\n\tparsePersistenceBranchId,\n\ttype PersistedThoughtCollection,\n} from './PersistenceScope.js';\nimport { initializeOrValidateSqliteV2 } from './SqliteSchemaV2.js';\nimport { stageBacktrackPersistence } from './BacktrackPersistence.js';\n\ntype SqliteOptions = PersistenceConfig['options'];\n\ntype ValidatedThoughtState = {\n\treadonly history: ThoughtData[];\n\treadonly branches: ReadonlyMap<BranchId, ThoughtData[]>;\n};\n\nexport class SqlitePersistence implements PersistenceBackend {\n\tprivate constructor(\n\t\tprivate readonly _db: SqliteDatabase,\n\t\tprivate readonly _sourcePath: string,\n\t\tprivate readonly _maxHistorySize: number,\n\t\tprivate readonly _persistBranches: boolean\n\t) {}\n\n\tpublic static createWithDatabase(\n\t\tdatabase: SqliteDatabase,\n\t\toptions: SqliteOptions = {},\n\t\tsourcePath = '<structural-sqlite>'\n\t): SqlitePersistence {\n\t\tinitializeOrValidateSqliteV2(database, sourcePath);\n\t\treturn new SqlitePersistence(\n\t\t\tdatabase,\n\t\t\tsourcePath,\n\t\t\toptions?.maxHistorySize ?? 10000,\n\t\t\toptions?.persistBranches ?? true\n\t\t);\n\t}\n\n\tpublic static async create(options?: SqliteOptions): Promise<SqlitePersistence> {\n\t\tconst defaultDataDir = existsSync('.claude/data')\n\t\t\t? '.claude/data'\n\t\t\t: join(homedir(), '.claude/data');\n\t\tconst dbPath = options?.dbPath ?? join(defaultDataDir, 'history.db');\n\t\tlet Database: SqliteDatabaseConstructor;\n\t\ttry {\n\t\t\tconst module = await import('better-sqlite3');\n\t\t\tDatabase = module.default;\n\t\t} catch (error) {\n\t\t\tthrow new PersistenceCompatibilityError(\n\t\t\t\tdbPath,\n\t\t\t\t\"SQLite persistence requires the optional 'better-sqlite3' package\",\n\t\t\t\terror\n\t\t\t);\n\t\t}\n\t\tconst database = new Database(dbPath);\n\t\ttry {\n\t\t\tconst persistence = SqlitePersistence.createWithDatabase(database, options, dbPath);\n\t\t\tif (options?.enableWAL !== false) database.pragma('journal_mode = WAL');\n\t\t\tdatabase.pragma('synchronous = NORMAL');\n\t\t\tdatabase.pragma('foreign_keys = ON');\n\t\t\tdatabase.pragma('busy_timeout = 5000');\n\t\t\tdatabase.pragma('cache_size = -64000');\n\t\t\tdatabase.pragma('temp_store = MEMORY');\n\t\t\treturn persistence;\n\t\t} catch (error) {\n\t\t\tdatabase.close();\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertThoughtScope('saveThoughtForSession', validatedSessionId, thought);\n\t\tthis._saveThought(validatedSessionId, thought);\n\t}\n\n\tpublic async saveBacktrackForSession(\n\t\tsessionId: SessionId,\n\t\tthought: ThoughtData,\n\t\ttargetThoughtId: ThoughtId\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tconst current = this._loadValidatedThoughtState(validatedSessionId);\n\t\t\tconst staged = stageBacktrackPersistence(\n\t\t\t\tvalidatedSessionId,\n\t\t\t\tcurrent.history,\n\t\t\t\t[...current.branches].map(([branchId, thoughts]) => ({ branchId, thoughts })),\n\t\t\t\tthought,\n\t\t\t\ttargetThoughtId,\n\t\t\t\tthis._maxHistorySize\n\t\t\t);\n\t\t\tthis._db.prepare('DELETE FROM thoughts WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insertThought = this._db.prepare(\n\t\t\t\t'INSERT INTO thoughts (session_id, data) VALUES (?, ?)'\n\t\t\t);\n\t\t\tfor (const retained of staged.history) {\n\t\t\t\tinsertThought.run(validatedSessionId, JSON.stringify(retained));\n\t\t\t}\n\t\t\tconst replaceBranch = this._db.prepare(\n\t\t\t\t'INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const branch of staged.branches) {\n\t\t\t\treplaceBranch.run(validatedSessionId, branch.branchId, JSON.stringify(branch.thoughts));\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate _saveThought(sessionId: SessionId, thought: ThoughtData): void {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, [thought]);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT INTO thoughts (session_id, data) VALUES (?, ?)')\n\t\t\t\t.run(sessionId, JSON.stringify(thought));\n\t\t\tif (this._maxHistorySize > 0) {\n\t\t\t\tconst countRow = this._db\n\t\t\t\t\t.prepare('SELECT COUNT(*) AS count FROM thoughts WHERE session_id = ?')\n\t\t\t\t\t.get(sessionId);\n\t\t\t\tconst excess =\n\t\t\t\t\tnumberField(countRow, 'count', `${this._sourcePath}:thought-count`) -\n\t\t\t\t\tthis._maxHistorySize;\n\t\t\t\tif (excess > 0) {\n\t\t\t\t\tthis._db\n\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t'DELETE FROM thoughts WHERE id IN (SELECT id FROM thoughts WHERE session_id = ? ORDER BY id ASC LIMIT ?)'\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.run(sessionId, excess);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn runSqliteReadTransaction(\n\t\t\tthis._db,\n\t\t\t() => this._loadValidatedThoughtState(validatedSessionId).history\n\t\t);\n\t}\n\n\tpublic async saveBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\tassertBranchScope('saveBranchForSession', validatedSessionId, validatedBranchId, thoughts);\n\t\tthis._saveBranch(validatedSessionId, validatedBranchId, thoughts);\n\t}\n\n\tprivate _saveBranch(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\tthoughts: readonly ThoughtData[]\n\t): void {\n\t\tassertPersistableThoughts(thoughts, `${this._sourcePath}:branch:${branchId}`);\n\t\tif (!this._persistBranches) {\n\t\t\trunSqliteReadTransaction(this._db, () =>\n\t\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId)\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._loadValidatedThoughtState(sessionId, thoughts, branchId);\n\t\t\tthis._db\n\t\t\t\t.prepare('INSERT OR REPLACE INTO branches (session_id, branch_id, data) VALUES (?, ?, ?)')\n\t\t\t\t.run(sessionId, branchId, JSON.stringify(thoughts));\n\t\t});\n\t}\n\n\tpublic async deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void> {\n\t\tif (!this._persistBranches) return;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db\n\t\t\t\t.prepare('DELETE FROM branches WHERE session_id = ? AND branch_id = ?')\n\t\t\t\t.run(validatedSessionId, validatedBranchId);\n\t\t});\n\t}\n\n\tpublic async loadBranchForSession(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId\n\t): Promise<ThoughtData[] | undefined> {\n\t\tif (!this._persistBranches) return undefined;\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tconst validatedBranchId = parsePersistenceBranchId(branchId, `${this._sourcePath}:branches`);\n\t\treturn runSqliteReadTransaction(this._db, () =>\n\t\t\tthis._loadValidatedThoughtState(validatedSessionId).branches.get(validatedBranchId)\n\t\t);\n\t}\n\n\tpublic async listBranchesForSession(sessionId: SessionId): Promise<BranchId[]> {\n\t\tif (!this._persistBranches) return [];\n\t\treturn this._db\n\t\t\t.prepare('SELECT branch_id FROM branches WHERE session_id = ? ORDER BY branch_id ASC')\n\t\t\t.all(asSessionId(sessionId))\n\t\t\t.map((row) =>\n\t\t\t\tparsePersistenceBranchId(stringField(row, 'branch_id', this._sourcePath), this._sourcePath)\n\t\t\t);\n\t}\n\n\tpublic async listSessions(): Promise<SessionId[]> {\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT session_id FROM thoughts UNION SELECT session_id FROM branches UNION SELECT session_id FROM edges UNION SELECT session_id FROM summaries'\n\t\t\t)\n\t\t\t.all()\n\t\t\t.map((row) => asSessionId(stringField(row, 'session_id', this._sourcePath)))\n\t\t\t.sort(compareCodePoint);\n\t}\n\n\tpublic async clearAll(): Promise<void> {\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries'])\n\t\t\t\tthis._db.exec(`DELETE FROM ${table}`);\n\t\t});\n\t}\n\n\tpublic async clearSession(sessionId: SessionId): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tfor (const table of ['thoughts', 'branches', 'edges', 'summaries']) {\n\t\t\t\tthis._db.prepare(`DELETE FROM ${table} WHERE session_id = ?`).run(validatedSessionId);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic async saveEdges(sessionId: SessionId, edges: readonly Edge[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertEdgeScopes(validatedSessionId, edges);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM edges WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO edges (id, session_id, from_id, to_id, kind, created_at, metadata) VALUES (?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const edge of edges)\n\t\t\t\tinsert.run(\n\t\t\t\t\tedge.id,\n\t\t\t\t\tedge.sessionId,\n\t\t\t\t\tedge.from,\n\t\t\t\t\tedge.to,\n\t\t\t\t\tedge.kind,\n\t\t\t\t\tedge.createdAt,\n\t\t\t\t\tedge.metadata === undefined ? null : JSON.stringify(edge.metadata)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadEdges(sessionId: SessionId): Promise<Edge[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, from_id, to_id, kind, created_at, metadata FROM edges WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeEdgeRow(row, `${this._sourcePath}:edges:${index}`));\n\t}\n\n\tpublic async saveSummaries(sessionId: SessionId, summaries: readonly Summary[]): Promise<void> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\tassertSummaryScopes(validatedSessionId, summaries);\n\t\trunSqliteTransaction(this._db, () => {\n\t\t\tthis._db.prepare('DELETE FROM summaries WHERE session_id = ?').run(validatedSessionId);\n\t\t\tconst insert = this._db.prepare(\n\t\t\t\t'INSERT INTO summaries (id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'\n\t\t\t);\n\t\t\tfor (const summary of summaries)\n\t\t\t\tinsert.run(\n\t\t\t\t\tsummary.id,\n\t\t\t\t\tsummary.sessionId,\n\t\t\t\t\tsummary.branchId ?? null,\n\t\t\t\t\tsummary.rootThoughtId,\n\t\t\t\t\tJSON.stringify(summary.coveredIds),\n\t\t\t\t\tsummary.coveredRange[0],\n\t\t\t\t\tsummary.coveredRange[1],\n\t\t\t\t\tJSON.stringify(summary.topics),\n\t\t\t\t\tsummary.aggregateConfidence,\n\t\t\t\t\tsummary.createdAt,\n\t\t\t\t\tsummary.meta === undefined ? null : JSON.stringify(summary.meta)\n\t\t\t\t);\n\t\t});\n\t}\n\n\tpublic async loadSummaries(sessionId: SessionId): Promise<Summary[]> {\n\t\tconst validatedSessionId = asSessionId(sessionId);\n\t\treturn this._db\n\t\t\t.prepare(\n\t\t\t\t'SELECT id, session_id, branch_id, root_thought_id, covered_ids, covered_range_start, covered_range_end, topics, aggregate_confidence, created_at, meta FROM summaries WHERE session_id = ? ORDER BY created_at ASC, id ASC'\n\t\t\t)\n\t\t\t.all(validatedSessionId)\n\t\t\t.map((row, index) => decodeSummaryRow(row, `${this._sourcePath}:summaries:${index}`));\n\t}\n\n\tpublic async healthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tthis._db.prepare('SELECT 1').get();\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error) return false;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis._db.close();\n\t}\n\n\tpublic getStats(): {\n\t\treadonly thoughtCount: number;\n\t\treadonly branchCount: number;\n\t\treadonly dbSize: number;\n\t} {\n\t\tconst thoughtCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM thoughts').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\tconst branchCount = numberField(\n\t\t\tthis._db.prepare('SELECT COUNT(*) AS count FROM branches').get(),\n\t\t\t'count',\n\t\t\tthis._sourcePath\n\t\t);\n\t\treturn { thoughtCount, branchCount: this._persistBranches ? branchCount : 0, dbSize: 0 };\n\t}\n\n\tprivate _loadValidatedThoughtState(\n\t\tsessionId: SessionId,\n\t\tcandidates: readonly ThoughtData[] = [],\n\t\treplacingBranch?: BranchId\n\t): ValidatedThoughtState {\n\t\tconst history = this.loadHistoryRows(sessionId);\n\t\tfor (const thought of history) {\n\t\t\tassertThoughtScope('saveThoughtForSession', sessionId, thought);\n\t\t}\n\t\tconst collections: PersistedThoughtCollection[] = [\n\t\t\t{\n\t\t\t\tsessionId,\n\t\t\t\tthoughts: replacingBranch === undefined ? [...history, ...candidates] : history,\n\t\t\t},\n\t\t];\n\t\tconst branches = new Map<BranchId, ThoughtData[]>();\n\t\tfor (const row of this._db\n\t\t\t.prepare('SELECT branch_id, data FROM branches WHERE session_id = ?')\n\t\t\t.all(sessionId)) {\n\t\t\tconst branchId = parsePersistenceBranchId(\n\t\t\t\tstringField(row, 'branch_id', this._sourcePath),\n\t\t\t\tthis._sourcePath\n\t\t\t);\n\t\t\tconst data = stringField(row, 'data', this._sourcePath);\n\t\t\tlet values: unknown;\n\t\t\ttry {\n\t\t\t\tvalues = JSON.parse(data);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new PersistenceCorruptionError(this._sourcePath, error);\n\t\t\t}\n\t\t\tif (!Array.isArray(values))\n\t\t\t\tthrow new PersistenceCorruptionError(\n\t\t\t\t\tthis._sourcePath,\n\t\t\t\t\tnew TypeError('branch data is not an array')\n\t\t\t\t);\n\t\t\tconst thoughts = values.map((value, index) =>\n\t\t\t\tdecodeThoughtRow(\n\t\t\t\t\t{ data: JSON.stringify(value) },\n\t\t\t\t\t`${this._sourcePath}:branch:${sessionId}:${branchId}:${index}`\n\t\t\t\t)\n\t\t\t);\n\t\t\tassertBranchScope('saveBranchForSession', sessionId, branchId, thoughts);\n\t\t\tbranches.set(branchId, thoughts);\n\t\t\tif (branchId !== replacingBranch) collections.push({ sessionId, thoughts });\n\t\t}\n\t\tif (replacingBranch !== undefined) {\n\t\t\tcollections.push({ sessionId, thoughts: candidates });\n\t\t}\n\t\tassertPersistableThoughtCollections(collections, this._sourcePath);\n\t\treturn { history, branches };\n\t}\n\n\tprivate loadHistoryRows(sessionId: SessionId): ThoughtData[] {\n\t\treturn this._db\n\t\t\t.prepare('SELECT data FROM thoughts WHERE session_id = ? ORDER BY id ASC')\n\t\t\t.all(sessionId)\n\t\t\t.map((row) => decodeThoughtRow(row, this._sourcePath));\n\t}\n}\n"],"names":["SqlitePersistence","_db","_sourcePath","_maxHistorySize","_persistBranches","database","options","sourcePath","initializeOrValidateSqliteV2","defaultDataDir","existsSync","join","homedir","dbPath","Database","module","error","PersistenceCompatibilityError","persistence","sessionId","thought","validatedSessionId","asSessionId","assertThoughtScope","targetThoughtId","runSqliteTransaction","current","staged","stageBacktrackPersistence","branchId","thoughts","insertThought","retained","JSON","replaceBranch","branch","countRow","excess","numberField","runSqliteReadTransaction","validatedBranchId","parsePersistenceBranchId","assertBranchScope","assertPersistableThoughts","row","stringField","compareCodePoint","table","edges","assertEdgeScopes","insert","edge","undefined","index","decodeEdgeRow","summaries","assertSummaryScopes","summary","decodeSummaryRow","Error","thoughtCount","branchCount","candidates","replacingBranch","history","collections","branches","Map","data","values","PersistenceCorruptionError","Array","TypeError","value","decodeThoughtRow","assertPersistableThoughtCollections"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iworkforces/tracelattice",
3
- "version": "2.1.2",
3
+ "version": "2.2.0",
4
4
  "description": "Semantic Sequential Thinking Layer For AI Agents.",
5
5
  "type": "module",
6
6
  "main": "dist/lib.js",
@@ -78,6 +78,7 @@
78
78
  "@valibot/to-json-schema": "^1.8.0",
79
79
  "chalk": "^6.0.0",
80
80
  "chokidar": "^5.0.0",
81
+ "or": "^0.2.0",
81
82
  "tmcp": "^1.20.0",
82
83
  "valibot": "^1.5.0",
83
84
  "yaml": "^2.9.1"
@@ -88,8 +89,8 @@
88
89
  "@rsbuild/core": "^2.2.8",
89
90
  "@rslib/core": "^1.0.1",
90
91
  "@types/node": "^26.6.2",
91
- "@typescript-eslint/eslint-plugin": "^8.70.0",
92
- "@typescript-eslint/parser": "^8.70.0",
92
+ "@typescript-eslint/eslint-plugin": "^8.70.1",
93
+ "@typescript-eslint/parser": "^8.70.1",
93
94
  "@vitest/coverage-v8": "^5.0.1",
94
95
  "better-sqlite3": "13.0.3",
95
96
  "eslint": "^10.11.0",