@remnic/core 9.3.663 → 9.3.665

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 (149) hide show
  1. package/dist/access-cli.js +25 -23
  2. package/dist/access-cli.js.map +1 -1
  3. package/dist/access-http.js +20 -18
  4. package/dist/access-mcp.js +19 -17
  5. package/dist/access-schema.d.ts +36 -36
  6. package/dist/access-schema.js +4 -3
  7. package/dist/access-service.js +17 -15
  8. package/dist/briefing.js +5 -4
  9. package/dist/{capsule-merge-T2JRE46P.js → capsule-merge-GK5E647P.js} +3 -2
  10. package/dist/{capsule-merge-T2JRE46P.js.map → capsule-merge-GK5E647P.js.map} +1 -1
  11. package/dist/causal-consolidation.js +6 -5
  12. package/dist/causal-consolidation.js.map +1 -1
  13. package/dist/{chunk-2KDQI363.js → chunk-2HEZXPYU.js} +4 -4
  14. package/dist/{chunk-HSCJYHYV.js → chunk-2OPARZ4B.js} +49 -19
  15. package/dist/chunk-2OPARZ4B.js.map +1 -0
  16. package/dist/chunk-5GPPACXK.js +16 -0
  17. package/dist/chunk-5GPPACXK.js.map +1 -0
  18. package/dist/{chunk-F6O7IOS3.js → chunk-6JBKHTQD.js} +2 -2
  19. package/dist/{chunk-YYQRVNSV.js → chunk-7C4MPEPE.js} +6 -6
  20. package/dist/{chunk-AL4RAJL5.js → chunk-7XH7VJN4.js} +6 -4
  21. package/dist/chunk-7XH7VJN4.js.map +1 -0
  22. package/dist/{chunk-Q4CAQGKQ.js → chunk-AER6MT24.js} +12 -21
  23. package/dist/chunk-AER6MT24.js.map +1 -0
  24. package/dist/{chunk-DHGSZ3UD.js → chunk-ARV3AUOM.js} +2 -2
  25. package/dist/{chunk-PXVFMQLD.js → chunk-BZG2CWOQ.js} +3 -3
  26. package/dist/{chunk-ANJOULTP.js → chunk-C7AF236A.js} +2 -2
  27. package/dist/{chunk-TBLGI2LT.js → chunk-D7IXTY5E.js} +31 -4
  28. package/dist/chunk-D7IXTY5E.js.map +1 -0
  29. package/dist/{chunk-FZC2WSDB.js → chunk-DOCTITOP.js} +2 -2
  30. package/dist/{chunk-WOQIHC67.js → chunk-DQY7NJ5L.js} +2 -2
  31. package/dist/{chunk-NMPEJV5M.js → chunk-DSLUOQDY.js} +2 -2
  32. package/dist/{chunk-A7EF2XRO.js → chunk-EXXBA5OM.js} +30 -8
  33. package/dist/chunk-EXXBA5OM.js.map +1 -0
  34. package/dist/{chunk-QXHBWFR3.js → chunk-IHG6CC7T.js} +2 -2
  35. package/dist/{chunk-4KDLCMLK.js → chunk-IROWLAWG.js} +5 -5
  36. package/dist/{chunk-ILXTATKK.js → chunk-J2HSAU72.js} +5 -5
  37. package/dist/chunk-J2HSAU72.js.map +1 -0
  38. package/dist/{chunk-DFAXGZKI.js → chunk-JIX3ZL2J.js} +8 -8
  39. package/dist/{chunk-GY3V3SUI.js → chunk-KHGE6PMF.js} +2 -2
  40. package/dist/{chunk-TWAJICBN.js → chunk-OHJFJ4HI.js} +2 -2
  41. package/dist/{chunk-WSQG37DV.js → chunk-OUWAQVDJ.js} +2 -2
  42. package/dist/{chunk-ZLDUQWT2.js → chunk-PWWWLD7D.js} +2 -2
  43. package/dist/{chunk-ZJH723NM.js → chunk-Q5ZU3RNY.js} +2 -2
  44. package/dist/{chunk-35HP3TGR.js → chunk-ROHLEUTH.js} +4 -4
  45. package/dist/{chunk-5RIRL3XL.js → chunk-RS25QOKZ.js} +2 -2
  46. package/dist/{chunk-RQGR3ETH.js → chunk-T2AN3BSP.js} +2 -2
  47. package/dist/{chunk-UAU5U5ML.js → chunk-UDJLF3BO.js} +2 -2
  48. package/dist/{chunk-ALEPI75L.js → chunk-VF4XKTX3.js} +6 -4
  49. package/dist/{chunk-ALEPI75L.js.map → chunk-VF4XKTX3.js.map} +1 -1
  50. package/dist/{chunk-AX5O25EF.js → chunk-VH6EIKVS.js} +152 -190
  51. package/dist/chunk-VH6EIKVS.js.map +1 -0
  52. package/dist/chunk-VS2IYZRU.js +43 -0
  53. package/dist/chunk-VS2IYZRU.js.map +1 -0
  54. package/dist/{chunk-TGOOJCGA.js → chunk-WH4SKYPX.js} +76 -54
  55. package/dist/chunk-WH4SKYPX.js.map +1 -0
  56. package/dist/{chunk-5AYAZN45.js → chunk-XRSIGVTS.js} +5 -5
  57. package/dist/{chunk-D2EFNQMY.js → chunk-XW3W4PV4.js} +2 -2
  58. package/dist/{chunk-TYIXG4VR.js → chunk-YW52BQSU.js} +2 -2
  59. package/dist/{cli-C6twwe84.d.ts → cli-BQRqR9N-.d.ts} +12 -1
  60. package/dist/cli.d.ts +1 -1
  61. package/dist/cli.js +32 -28
  62. package/dist/compounding/engine.js +5 -4
  63. package/dist/connectors/codex-materialize-runner.js +5 -4
  64. package/dist/connectors/index.js +5 -4
  65. package/dist/consolidation-provenance-check.js +3 -2
  66. package/dist/consolidation-undo.js +2 -1
  67. package/dist/consolidation-undo.js.map +1 -1
  68. package/dist/entity-retrieval.js +5 -4
  69. package/dist/index.d.ts +1 -1
  70. package/dist/index.js +39 -36
  71. package/dist/index.js.map +1 -1
  72. package/dist/maintenance/memory-governance.js +6 -4
  73. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -4
  74. package/dist/maintenance/rebuild-memory-projection.js +7 -5
  75. package/dist/namespaces/migrate.js +13 -11
  76. package/dist/namespaces/search.js +8 -6
  77. package/dist/namespaces/storage.d.ts +13 -0
  78. package/dist/namespaces/storage.js +5 -4
  79. package/dist/offline-sync.js +3 -2
  80. package/dist/operator-toolkit.js +16 -14
  81. package/dist/orchestrator.js +21 -19
  82. package/dist/page-versioning.js +2 -1
  83. package/dist/schemas.d.ts +64 -64
  84. package/dist/search/document-scanner.d.ts +11 -7
  85. package/dist/search/document-scanner.js +3 -1
  86. package/dist/search/factory.js +7 -5
  87. package/dist/search/index.js +7 -5
  88. package/dist/search/lancedb-backend.js +4 -2
  89. package/dist/search/meilisearch-backend.js +4 -2
  90. package/dist/search/orama-backend.js +4 -2
  91. package/dist/secure-store/index.js +3 -2
  92. package/dist/semantic-consolidation.js +6 -5
  93. package/dist/semantic-rule-promotion.js +5 -4
  94. package/dist/semantic-rule-verifier.js +5 -4
  95. package/dist/shared-context/manager.d.ts +2 -2
  96. package/dist/storage.d.ts +17 -3
  97. package/dist/storage.js +4 -3
  98. package/dist/transfer/capsule-import.js +3 -2
  99. package/dist/transfer/types.d.ts +12 -12
  100. package/dist/verified-recall.js +5 -4
  101. package/package.json +1 -1
  102. package/src/cli.ts +62 -23
  103. package/src/consolidation-provenance-check.ts +7 -6
  104. package/src/maintenance/memory-governance.ts +47 -7
  105. package/src/namespaces/catalog.test.ts +12 -12
  106. package/src/namespaces/storage.ts +28 -1
  107. package/src/orchestrator.ts +84 -58
  108. package/src/page-versioning.ts +7 -4
  109. package/src/search/document-scanner.test.ts +29 -0
  110. package/src/search/document-scanner.ts +17 -29
  111. package/src/secure-store/secure-fs.ts +19 -5
  112. package/src/secure-store/secure-store.test.ts +28 -0
  113. package/src/storage.ts +42 -43
  114. package/src/training-export/converter.test.ts +19 -0
  115. package/src/training-export/converter.ts +8 -5
  116. package/src/utils/category-dir.ts +10 -4
  117. package/src/utils/path-containment.ts +40 -0
  118. package/dist/chunk-A7EF2XRO.js.map +0 -1
  119. package/dist/chunk-AL4RAJL5.js.map +0 -1
  120. package/dist/chunk-AX5O25EF.js.map +0 -1
  121. package/dist/chunk-HSCJYHYV.js.map +0 -1
  122. package/dist/chunk-ILXTATKK.js.map +0 -1
  123. package/dist/chunk-Q4CAQGKQ.js.map +0 -1
  124. package/dist/chunk-TBLGI2LT.js.map +0 -1
  125. package/dist/chunk-TGOOJCGA.js.map +0 -1
  126. /package/dist/{chunk-2KDQI363.js.map → chunk-2HEZXPYU.js.map} +0 -0
  127. /package/dist/{chunk-F6O7IOS3.js.map → chunk-6JBKHTQD.js.map} +0 -0
  128. /package/dist/{chunk-YYQRVNSV.js.map → chunk-7C4MPEPE.js.map} +0 -0
  129. /package/dist/{chunk-DHGSZ3UD.js.map → chunk-ARV3AUOM.js.map} +0 -0
  130. /package/dist/{chunk-PXVFMQLD.js.map → chunk-BZG2CWOQ.js.map} +0 -0
  131. /package/dist/{chunk-ANJOULTP.js.map → chunk-C7AF236A.js.map} +0 -0
  132. /package/dist/{chunk-FZC2WSDB.js.map → chunk-DOCTITOP.js.map} +0 -0
  133. /package/dist/{chunk-WOQIHC67.js.map → chunk-DQY7NJ5L.js.map} +0 -0
  134. /package/dist/{chunk-NMPEJV5M.js.map → chunk-DSLUOQDY.js.map} +0 -0
  135. /package/dist/{chunk-QXHBWFR3.js.map → chunk-IHG6CC7T.js.map} +0 -0
  136. /package/dist/{chunk-4KDLCMLK.js.map → chunk-IROWLAWG.js.map} +0 -0
  137. /package/dist/{chunk-DFAXGZKI.js.map → chunk-JIX3ZL2J.js.map} +0 -0
  138. /package/dist/{chunk-GY3V3SUI.js.map → chunk-KHGE6PMF.js.map} +0 -0
  139. /package/dist/{chunk-TWAJICBN.js.map → chunk-OHJFJ4HI.js.map} +0 -0
  140. /package/dist/{chunk-WSQG37DV.js.map → chunk-OUWAQVDJ.js.map} +0 -0
  141. /package/dist/{chunk-ZLDUQWT2.js.map → chunk-PWWWLD7D.js.map} +0 -0
  142. /package/dist/{chunk-ZJH723NM.js.map → chunk-Q5ZU3RNY.js.map} +0 -0
  143. /package/dist/{chunk-35HP3TGR.js.map → chunk-ROHLEUTH.js.map} +0 -0
  144. /package/dist/{chunk-5RIRL3XL.js.map → chunk-RS25QOKZ.js.map} +0 -0
  145. /package/dist/{chunk-RQGR3ETH.js.map → chunk-T2AN3BSP.js.map} +0 -0
  146. /package/dist/{chunk-UAU5U5ML.js.map → chunk-UDJLF3BO.js.map} +0 -0
  147. /package/dist/{chunk-5AYAZN45.js.map → chunk-XRSIGVTS.js.map} +0 -0
  148. /package/dist/{chunk-D2EFNQMY.js.map → chunk-XW3W4PV4.js.map} +0 -0
  149. /package/dist/{chunk-TYIXG4VR.js.map → chunk-YW52BQSU.js.map} +0 -0
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  listNamespaces
3
- } from "./chunk-YYQRVNSV.js";
3
+ } from "./chunk-7C4MPEPE.js";
4
4
  import {
5
5
  runConsolidationProvenanceCheck
6
- } from "./chunk-AL4RAJL5.js";
6
+ } from "./chunk-7XH7VJN4.js";
7
7
  import {
8
8
  reportBufferSurpriseDistribution
9
9
  } from "./chunk-YBPYIAA5.js";
@@ -36,13 +36,13 @@ import {
36
36
  import {
37
37
  listMemoryGovernanceRuns,
38
38
  readMemoryGovernanceRunArtifact
39
- } from "./chunk-A7EF2XRO.js";
39
+ } from "./chunk-EXXBA5OM.js";
40
40
  import {
41
41
  analyzeGraphHealth
42
42
  } from "./chunk-Y56J7CXW.js";
43
43
  import {
44
44
  StorageManager
45
- } from "./chunk-AX5O25EF.js";
45
+ } from "./chunk-VH6EIKVS.js";
46
46
  import {
47
47
  lintWorkspaceFiles
48
48
  } from "./chunk-DM2T26WE.js";
@@ -1336,4 +1336,4 @@ export {
1336
1336
  runBenchmarkRecall,
1337
1337
  runOperatorRepair
1338
1338
  };
1339
- //# sourceMappingURL=chunk-5AYAZN45.js.map
1339
+ //# sourceMappingURL=chunk-XRSIGVTS.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runPostConsolidationMaterialize
3
- } from "./chunk-ANJOULTP.js";
3
+ } from "./chunk-C7AF236A.js";
4
4
  import {
5
5
  discoverMemoryExtensions,
6
6
  renderExtensionsBlock,
@@ -217,4 +217,4 @@ export {
217
217
  buildExtensionsBlockForConsolidation,
218
218
  materializeAfterSemanticConsolidation
219
219
  };
220
- //# sourceMappingURL=chunk-D2EFNQMY.js.map
220
+ //# sourceMappingURL=chunk-XW3W4PV4.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-HQ6NIBL6.js";
4
4
  import {
5
5
  StorageManager
6
- } from "./chunk-AX5O25EF.js";
6
+ } from "./chunk-VH6EIKVS.js";
7
7
  import {
8
8
  getCachedEpisodeMap,
9
9
  setCachedEpisodeMap
@@ -107,4 +107,4 @@ export {
107
107
  compareVerifiedEpisodeResults,
108
108
  searchVerifiedEpisodes
109
109
  };
110
- //# sourceMappingURL=chunk-TYIXG4VR.js.map
110
+ //# sourceMappingURL=chunk-YW52BQSU.js.map
@@ -1112,6 +1112,17 @@ declare function runBulkImportCliCommand(opts: BulkImportCliCommandOptions): Pro
1112
1112
  declare function resolveMemoryDirForNamespace(orchestrator: Orchestrator, namespace?: string, options?: {
1113
1113
  rejectUnsupportedOverride?: boolean;
1114
1114
  }): Promise<string>;
1115
+ /**
1116
+ * List absolute paths of every `*.md` file under each recall category directory
1117
+ * of `memoryDir` (facts/, corrections/, decisions/, ...; see
1118
+ * `walkMemoryMarkdownFiles`). Used by the bulk-import CLI to derive a per-batch
1119
+ * `memoriesCreated` count via set-subtraction of "paths after extraction"
1120
+ * against "paths before extraction". Caveat: the extraction queue is shared
1121
+ * across sessions, so concurrent organic extractions between the two snapshots
1122
+ * can still inflate the count; the set diff at least ignores pre-existing and
1123
+ * deleted files. Exported for category-dir coverage tests (#1546).
1124
+ */
1125
+ declare function listMemoryMarkdownFilePaths(memoryDir: string): Promise<string[]>;
1115
1126
  declare function registerCli(api: CliApi, orchestrator: Orchestrator, registerOptions?: RegisterCliOptions): void;
1116
1127
 
1117
- export { registerCli as $, type AccessHttpServeCliCommandOptions as A, type BulkImportCliCommandOptions as B, type CompatCliCommandOptions as C, type DashboardStartCliCommandOptions as D, type ExactDedupePlan as E, type SessionRepairCliCommandOptions as F, type GraphHealthCliCommandOptions as G, type TailscaleSyncCliCommandOptions as H, type TierMigrationCliOrchestrator as I, type TrainingExportCliCommandOptions as J, type WorkProjectCliCommandOptions as K, type WorkTaskCliCommandOptions as L, type MemoryActionAuditCliCommandOptions as M, emitConnectorsRunCliResult as N, filterNormalMemorySearchResults as O, type PolicyDiffCliReport as P, hasDestructivePurgeFailures as Q, type RebuildMemoryLifecycleLedgerCliCommandOptions as R, type SessionIntegrityCliCommandOptions as S, type TailscaleStatusCliCommandOptions as T, isNormalRetrievalVisibleMemory as U, type VerifyMemoryProjectionCliCommandOptions as V, type WebDavServeCliCommandOptions as W, parseDurationToMs as X, parseStrictCliDate as Y, planAggressiveDuplicateDeletions as Z, planExactDuplicateDeletions as _, type ArchiveObservationsCliCommandOptions as a, runTrainingExportCliCommand as a$, resolveAccessPrincipalOverride as a0, resolveMemoryDirForNamespace as a1, runAbstractionNodeStatusCliCommand as a2, runAccessHttpServeCliCommand as a3, runAccessHttpStatusCliCommand as a4, runAccessHttpStopCliCommand as a5, runAccessMcpServeCliCommand as a6, runArchiveObservationsCliCommand as a7, runBenchmarkBaselineReportCliCommand as a8, runBenchmarkBaselineSnapshotCliCommand as a9, runMemoryTimelineCliCommand as aA, runMigrateNormalizeFrontmatterCliCommand as aB, runMigrateObservationsCliCommand as aC, runMigrateRechunkCliCommand as aD, runMigrateReextractCliCommand as aE, runMigrateRescoreImportanceCliCommand as aF, runObjectiveStateStatusCliCommand as aG, runPolicyDiffCliCommand as aH, runPolicyRollbackCliCommand as aI, runPolicyStatusCliCommand as aJ, runRebuildMemoryLifecycleLedgerCliCommand as aK, runRebuildMemoryProjectionCliCommand as aL, runRebuildObservationsCliCommand as aM, runRepairMemoryProjectionCliCommand as aN, runReplayCliCommand as aO, runResumeBundleBuildCliCommand as aP, runResumeBundleRecordCliCommand as aQ, runResumeBundleStatusCliCommand as aR, runRouteCliCommand as aS, runSemanticRulePromoteCliCommand as aT, runSemanticRuleVerifyCliCommand as aU, runSessionCheckCliCommand as aV, runSessionRepairCliCommand as aW, runTailscaleStatusCliCommand as aX, runTailscaleSyncCliCommand as aY, runTierMigrateCliCommand as aZ, runTierStatusCliCommand as a_, runBenchmarkCiGateCliCommand as aa, runBenchmarkImportCliCommand as ab, runBenchmarkStatusCliCommand as ac, runBenchmarkStoredBaselineCiGateCliCommand as ad, runBenchmarkValidateCliCommand as ae, runCausalTrajectoryStatusCliCommand as af, runCommitmentLifecycleCliCommand as ag, runCommitmentRecordCliCommand as ah, runCommitmentSetStateCliCommand as ai, runCommitmentStatusCliCommand as aj, runCompatCliCommand as ak, runCompoundingPromoteCliCommand as al, runConversationIndexHealthCliCommand as am, runConversationIndexInspectCliCommand as an, runConversationIndexRebuildCliCommand as ao, runCueAnchorStatusCliCommand as ap, runDashboardStartCliCommand as aq, runDashboardStatusCliCommand as ar, runDashboardStopCliCommand as as, runGraphHealthCliCommand as at, runHarmonicSearchCliCommand as au, runMemoryActionAuditCliCommand as av, runMemoryGovernanceCliCommand as aw, runMemoryGovernanceReportCliCommand as ax, runMemoryGovernanceRestoreCliCommand as ay, runMemoryReviewDispositionCliCommand as az, type ConnectorsRunCliOutputOptions as b, runTrustZoneDemoSeedCliCommand as b0, runTrustZonePromoteCliCommand as b1, runTrustZoneStatusCliCommand as b2, runUtilityLearningCliCommand as b3, runUtilityLearningStatusCliCommand as b4, runUtilityTelemetryRecordCliCommand as b5, runUtilityTelemetryStatusCliCommand as b6, runVerifiedRecallSearchCliCommand as b7, runVerifyMemoryProjectionCliCommand as b8, runWebDavServeCliCommand as b9, runWebDavStopCliCommand as ba, runWorkProductRecallSearchCliCommand as bb, runWorkProductRecordCliCommand as bc, runWorkProductStatusCliCommand as bd, runWorkProjectCliCommand as be, runWorkTaskCliCommand as bf, type ConversationIndexHealthCliOrchestrator as c, type DedupeCandidate as d, type MemoryActionAuditCliNamespaceSummary as e, type MemoryActionAuditCliReport as f, type MemoryGovernanceCliCommandOptions as g, type MemoryGovernanceReportCliCommandOptions as h, type MemoryGovernanceRestoreCliCommandOptions as i, type MemoryReviewDispositionCliCommandOptions as j, type MemoryTimelineCliCommandOptions as k, type MigrateCliOrchestrator as l, type MigrateCliReport as m, type MigrateObservationsCliCommandOptions as n, type PolicyDiffEntry as o, parseStrictCliDate$1 as p, type PolicyRollbackCliReport as q, runBulkImportCliCommand as r, type PolicyStatusCliReport as s, type PolicyTuningCliOrchestrator as t, type RebuildMemoryProjectionCliCommandOptions as u, type RebuildObservationsCliCommandOptions as v, type RepairMemoryProjectionCliCommandOptions as w, type ReplayCliCommandOptions as x, type ReplayCliOrchestrator as y, type RouteCliCommandOptions as z };
1128
+ export { planExactDuplicateDeletions as $, type AccessHttpServeCliCommandOptions as A, type BulkImportCliCommandOptions as B, type CompatCliCommandOptions as C, type DashboardStartCliCommandOptions as D, type ExactDedupePlan as E, type SessionRepairCliCommandOptions as F, type GraphHealthCliCommandOptions as G, type TailscaleSyncCliCommandOptions as H, type TierMigrationCliOrchestrator as I, type TrainingExportCliCommandOptions as J, type WorkProjectCliCommandOptions as K, type WorkTaskCliCommandOptions as L, type MemoryActionAuditCliCommandOptions as M, emitConnectorsRunCliResult as N, filterNormalMemorySearchResults as O, type PolicyDiffCliReport as P, hasDestructivePurgeFailures as Q, type RebuildMemoryLifecycleLedgerCliCommandOptions as R, type SessionIntegrityCliCommandOptions as S, type TailscaleStatusCliCommandOptions as T, isNormalRetrievalVisibleMemory as U, type VerifyMemoryProjectionCliCommandOptions as V, type WebDavServeCliCommandOptions as W, listMemoryMarkdownFilePaths as X, parseDurationToMs as Y, parseStrictCliDate as Z, planAggressiveDuplicateDeletions as _, type ArchiveObservationsCliCommandOptions as a, runTierStatusCliCommand as a$, registerCli as a0, resolveAccessPrincipalOverride as a1, resolveMemoryDirForNamespace as a2, runAbstractionNodeStatusCliCommand as a3, runAccessHttpServeCliCommand as a4, runAccessHttpStatusCliCommand as a5, runAccessHttpStopCliCommand as a6, runAccessMcpServeCliCommand as a7, runArchiveObservationsCliCommand as a8, runBenchmarkBaselineReportCliCommand as a9, runMemoryReviewDispositionCliCommand as aA, runMemoryTimelineCliCommand as aB, runMigrateNormalizeFrontmatterCliCommand as aC, runMigrateObservationsCliCommand as aD, runMigrateRechunkCliCommand as aE, runMigrateReextractCliCommand as aF, runMigrateRescoreImportanceCliCommand as aG, runObjectiveStateStatusCliCommand as aH, runPolicyDiffCliCommand as aI, runPolicyRollbackCliCommand as aJ, runPolicyStatusCliCommand as aK, runRebuildMemoryLifecycleLedgerCliCommand as aL, runRebuildMemoryProjectionCliCommand as aM, runRebuildObservationsCliCommand as aN, runRepairMemoryProjectionCliCommand as aO, runReplayCliCommand as aP, runResumeBundleBuildCliCommand as aQ, runResumeBundleRecordCliCommand as aR, runResumeBundleStatusCliCommand as aS, runRouteCliCommand as aT, runSemanticRulePromoteCliCommand as aU, runSemanticRuleVerifyCliCommand as aV, runSessionCheckCliCommand as aW, runSessionRepairCliCommand as aX, runTailscaleStatusCliCommand as aY, runTailscaleSyncCliCommand as aZ, runTierMigrateCliCommand as a_, runBenchmarkBaselineSnapshotCliCommand as aa, runBenchmarkCiGateCliCommand as ab, runBenchmarkImportCliCommand as ac, runBenchmarkStatusCliCommand as ad, runBenchmarkStoredBaselineCiGateCliCommand as ae, runBenchmarkValidateCliCommand as af, runCausalTrajectoryStatusCliCommand as ag, runCommitmentLifecycleCliCommand as ah, runCommitmentRecordCliCommand as ai, runCommitmentSetStateCliCommand as aj, runCommitmentStatusCliCommand as ak, runCompatCliCommand as al, runCompoundingPromoteCliCommand as am, runConversationIndexHealthCliCommand as an, runConversationIndexInspectCliCommand as ao, runConversationIndexRebuildCliCommand as ap, runCueAnchorStatusCliCommand as aq, runDashboardStartCliCommand as ar, runDashboardStatusCliCommand as as, runDashboardStopCliCommand as at, runGraphHealthCliCommand as au, runHarmonicSearchCliCommand as av, runMemoryActionAuditCliCommand as aw, runMemoryGovernanceCliCommand as ax, runMemoryGovernanceReportCliCommand as ay, runMemoryGovernanceRestoreCliCommand as az, type ConnectorsRunCliOutputOptions as b, runTrainingExportCliCommand as b0, runTrustZoneDemoSeedCliCommand as b1, runTrustZonePromoteCliCommand as b2, runTrustZoneStatusCliCommand as b3, runUtilityLearningCliCommand as b4, runUtilityLearningStatusCliCommand as b5, runUtilityTelemetryRecordCliCommand as b6, runUtilityTelemetryStatusCliCommand as b7, runVerifiedRecallSearchCliCommand as b8, runVerifyMemoryProjectionCliCommand as b9, runWebDavServeCliCommand as ba, runWebDavStopCliCommand as bb, runWorkProductRecallSearchCliCommand as bc, runWorkProductRecordCliCommand as bd, runWorkProductStatusCliCommand as be, runWorkProjectCliCommand as bf, runWorkTaskCliCommand as bg, type ConversationIndexHealthCliOrchestrator as c, type DedupeCandidate as d, type MemoryActionAuditCliNamespaceSummary as e, type MemoryActionAuditCliReport as f, type MemoryGovernanceCliCommandOptions as g, type MemoryGovernanceReportCliCommandOptions as h, type MemoryGovernanceRestoreCliCommandOptions as i, type MemoryReviewDispositionCliCommandOptions as j, type MemoryTimelineCliCommandOptions as k, type MigrateCliOrchestrator as l, type MigrateCliReport as m, type MigrateObservationsCliCommandOptions as n, type PolicyDiffEntry as o, parseStrictCliDate$1 as p, type PolicyRollbackCliReport as q, runBulkImportCliCommand as r, type PolicyStatusCliReport as s, type PolicyTuningCliOrchestrator as t, type RebuildMemoryProjectionCliCommandOptions as u, type RebuildObservationsCliCommandOptions as v, type RepairMemoryProjectionCliCommandOptions as w, type ReplayCliCommandOptions as x, type ReplayCliOrchestrator as y, type RouteCliCommandOptions as z };
package/dist/cli.d.ts CHANGED
@@ -38,7 +38,7 @@ import './trust-zones.js';
38
38
  import './session-integrity.js';
39
39
  import './recall-state.js';
40
40
  import './policy-runtime.js';
41
- export { A as AccessHttpServeCliCommandOptions, a as ArchiveObservationsCliCommandOptions, B as BulkImportCliCommandOptions, C as CompatCliCommandOptions, b as ConnectorsRunCliOutputOptions, c as ConversationIndexHealthCliOrchestrator, D as DashboardStartCliCommandOptions, d as DedupeCandidate, E as ExactDedupePlan, G as GraphHealthCliCommandOptions, M as MemoryActionAuditCliCommandOptions, e as MemoryActionAuditCliNamespaceSummary, f as MemoryActionAuditCliReport, g as MemoryGovernanceCliCommandOptions, h as MemoryGovernanceReportCliCommandOptions, i as MemoryGovernanceRestoreCliCommandOptions, j as MemoryReviewDispositionCliCommandOptions, k as MemoryTimelineCliCommandOptions, l as MigrateCliOrchestrator, m as MigrateCliReport, n as MigrateObservationsCliCommandOptions, P as PolicyDiffCliReport, o as PolicyDiffEntry, q as PolicyRollbackCliReport, s as PolicyStatusCliReport, t as PolicyTuningCliOrchestrator, R as RebuildMemoryLifecycleLedgerCliCommandOptions, u as RebuildMemoryProjectionCliCommandOptions, v as RebuildObservationsCliCommandOptions, w as RepairMemoryProjectionCliCommandOptions, x as ReplayCliCommandOptions, y as ReplayCliOrchestrator, z as RouteCliCommandOptions, S as SessionIntegrityCliCommandOptions, F as SessionRepairCliCommandOptions, T as TailscaleStatusCliCommandOptions, H as TailscaleSyncCliCommandOptions, I as TierMigrationCliOrchestrator, J as TrainingExportCliCommandOptions, V as VerifyMemoryProjectionCliCommandOptions, W as WebDavServeCliCommandOptions, K as WorkProjectCliCommandOptions, L as WorkTaskCliCommandOptions, N as emitConnectorsRunCliResult, O as filterNormalMemorySearchResults, Q as hasDestructivePurgeFailures, U as isNormalRetrievalVisibleMemory, X as parseDurationToMs, Y as parseStrictCliDate, Z as planAggressiveDuplicateDeletions, _ as planExactDuplicateDeletions, $ as registerCli, a0 as resolveAccessPrincipalOverride, a1 as resolveMemoryDirForNamespace, a2 as runAbstractionNodeStatusCliCommand, a3 as runAccessHttpServeCliCommand, a4 as runAccessHttpStatusCliCommand, a5 as runAccessHttpStopCliCommand, a6 as runAccessMcpServeCliCommand, a7 as runArchiveObservationsCliCommand, a8 as runBenchmarkBaselineReportCliCommand, a9 as runBenchmarkBaselineSnapshotCliCommand, aa as runBenchmarkCiGateCliCommand, ab as runBenchmarkImportCliCommand, ac as runBenchmarkStatusCliCommand, ad as runBenchmarkStoredBaselineCiGateCliCommand, ae as runBenchmarkValidateCliCommand, r as runBulkImportCliCommand, af as runCausalTrajectoryStatusCliCommand, ag as runCommitmentLifecycleCliCommand, ah as runCommitmentRecordCliCommand, ai as runCommitmentSetStateCliCommand, aj as runCommitmentStatusCliCommand, ak as runCompatCliCommand, al as runCompoundingPromoteCliCommand, am as runConversationIndexHealthCliCommand, an as runConversationIndexInspectCliCommand, ao as runConversationIndexRebuildCliCommand, ap as runCueAnchorStatusCliCommand, aq as runDashboardStartCliCommand, ar as runDashboardStatusCliCommand, as as runDashboardStopCliCommand, at as runGraphHealthCliCommand, au as runHarmonicSearchCliCommand, av as runMemoryActionAuditCliCommand, aw as runMemoryGovernanceCliCommand, ax as runMemoryGovernanceReportCliCommand, ay as runMemoryGovernanceRestoreCliCommand, az as runMemoryReviewDispositionCliCommand, aA as runMemoryTimelineCliCommand, aB as runMigrateNormalizeFrontmatterCliCommand, aC as runMigrateObservationsCliCommand, aD as runMigrateRechunkCliCommand, aE as runMigrateReextractCliCommand, aF as runMigrateRescoreImportanceCliCommand, aG as runObjectiveStateStatusCliCommand, aH as runPolicyDiffCliCommand, aI as runPolicyRollbackCliCommand, aJ as runPolicyStatusCliCommand, aK as runRebuildMemoryLifecycleLedgerCliCommand, aL as runRebuildMemoryProjectionCliCommand, aM as runRebuildObservationsCliCommand, aN as runRepairMemoryProjectionCliCommand, aO as runReplayCliCommand, aP as runResumeBundleBuildCliCommand, aQ as runResumeBundleRecordCliCommand, aR as runResumeBundleStatusCliCommand, aS as runRouteCliCommand, aT as runSemanticRulePromoteCliCommand, aU as runSemanticRuleVerifyCliCommand, aV as runSessionCheckCliCommand, aW as runSessionRepairCliCommand, aX as runTailscaleStatusCliCommand, aY as runTailscaleSyncCliCommand, aZ as runTierMigrateCliCommand, a_ as runTierStatusCliCommand, a$ as runTrainingExportCliCommand, b0 as runTrustZoneDemoSeedCliCommand, b1 as runTrustZonePromoteCliCommand, b2 as runTrustZoneStatusCliCommand, b3 as runUtilityLearningCliCommand, b4 as runUtilityLearningStatusCliCommand, b5 as runUtilityTelemetryRecordCliCommand, b6 as runUtilityTelemetryStatusCliCommand, b7 as runVerifiedRecallSearchCliCommand, b8 as runVerifyMemoryProjectionCliCommand, b9 as runWebDavServeCliCommand, ba as runWebDavStopCliCommand, bb as runWorkProductRecallSearchCliCommand, bc as runWorkProductRecordCliCommand, bd as runWorkProductStatusCliCommand, be as runWorkProjectCliCommand, bf as runWorkTaskCliCommand } from './cli-C6twwe84.js';
41
+ export { A as AccessHttpServeCliCommandOptions, a as ArchiveObservationsCliCommandOptions, B as BulkImportCliCommandOptions, C as CompatCliCommandOptions, b as ConnectorsRunCliOutputOptions, c as ConversationIndexHealthCliOrchestrator, D as DashboardStartCliCommandOptions, d as DedupeCandidate, E as ExactDedupePlan, G as GraphHealthCliCommandOptions, M as MemoryActionAuditCliCommandOptions, e as MemoryActionAuditCliNamespaceSummary, f as MemoryActionAuditCliReport, g as MemoryGovernanceCliCommandOptions, h as MemoryGovernanceReportCliCommandOptions, i as MemoryGovernanceRestoreCliCommandOptions, j as MemoryReviewDispositionCliCommandOptions, k as MemoryTimelineCliCommandOptions, l as MigrateCliOrchestrator, m as MigrateCliReport, n as MigrateObservationsCliCommandOptions, P as PolicyDiffCliReport, o as PolicyDiffEntry, q as PolicyRollbackCliReport, s as PolicyStatusCliReport, t as PolicyTuningCliOrchestrator, R as RebuildMemoryLifecycleLedgerCliCommandOptions, u as RebuildMemoryProjectionCliCommandOptions, v as RebuildObservationsCliCommandOptions, w as RepairMemoryProjectionCliCommandOptions, x as ReplayCliCommandOptions, y as ReplayCliOrchestrator, z as RouteCliCommandOptions, S as SessionIntegrityCliCommandOptions, F as SessionRepairCliCommandOptions, T as TailscaleStatusCliCommandOptions, H as TailscaleSyncCliCommandOptions, I as TierMigrationCliOrchestrator, J as TrainingExportCliCommandOptions, V as VerifyMemoryProjectionCliCommandOptions, W as WebDavServeCliCommandOptions, K as WorkProjectCliCommandOptions, L as WorkTaskCliCommandOptions, N as emitConnectorsRunCliResult, O as filterNormalMemorySearchResults, Q as hasDestructivePurgeFailures, U as isNormalRetrievalVisibleMemory, X as listMemoryMarkdownFilePaths, Y as parseDurationToMs, Z as parseStrictCliDate, _ as planAggressiveDuplicateDeletions, $ as planExactDuplicateDeletions, a0 as registerCli, a1 as resolveAccessPrincipalOverride, a2 as resolveMemoryDirForNamespace, a3 as runAbstractionNodeStatusCliCommand, a4 as runAccessHttpServeCliCommand, a5 as runAccessHttpStatusCliCommand, a6 as runAccessHttpStopCliCommand, a7 as runAccessMcpServeCliCommand, a8 as runArchiveObservationsCliCommand, a9 as runBenchmarkBaselineReportCliCommand, aa as runBenchmarkBaselineSnapshotCliCommand, ab as runBenchmarkCiGateCliCommand, ac as runBenchmarkImportCliCommand, ad as runBenchmarkStatusCliCommand, ae as runBenchmarkStoredBaselineCiGateCliCommand, af as runBenchmarkValidateCliCommand, r as runBulkImportCliCommand, ag as runCausalTrajectoryStatusCliCommand, ah as runCommitmentLifecycleCliCommand, ai as runCommitmentRecordCliCommand, aj as runCommitmentSetStateCliCommand, ak as runCommitmentStatusCliCommand, al as runCompatCliCommand, am as runCompoundingPromoteCliCommand, an as runConversationIndexHealthCliCommand, ao as runConversationIndexInspectCliCommand, ap as runConversationIndexRebuildCliCommand, aq as runCueAnchorStatusCliCommand, ar as runDashboardStartCliCommand, as as runDashboardStatusCliCommand, at as runDashboardStopCliCommand, au as runGraphHealthCliCommand, av as runHarmonicSearchCliCommand, aw as runMemoryActionAuditCliCommand, ax as runMemoryGovernanceCliCommand, ay as runMemoryGovernanceReportCliCommand, az as runMemoryGovernanceRestoreCliCommand, aA as runMemoryReviewDispositionCliCommand, aB as runMemoryTimelineCliCommand, aC as runMigrateNormalizeFrontmatterCliCommand, aD as runMigrateObservationsCliCommand, aE as runMigrateRechunkCliCommand, aF as runMigrateReextractCliCommand, aG as runMigrateRescoreImportanceCliCommand, aH as runObjectiveStateStatusCliCommand, aI as runPolicyDiffCliCommand, aJ as runPolicyRollbackCliCommand, aK as runPolicyStatusCliCommand, aL as runRebuildMemoryLifecycleLedgerCliCommand, aM as runRebuildMemoryProjectionCliCommand, aN as runRebuildObservationsCliCommand, aO as runRepairMemoryProjectionCliCommand, aP as runReplayCliCommand, aQ as runResumeBundleBuildCliCommand, aR as runResumeBundleRecordCliCommand, aS as runResumeBundleStatusCliCommand, aT as runRouteCliCommand, aU as runSemanticRulePromoteCliCommand, aV as runSemanticRuleVerifyCliCommand, aW as runSessionCheckCliCommand, aX as runSessionRepairCliCommand, aY as runTailscaleStatusCliCommand, aZ as runTailscaleSyncCliCommand, a_ as runTierMigrateCliCommand, a$ as runTierStatusCliCommand, b0 as runTrainingExportCliCommand, b1 as runTrustZoneDemoSeedCliCommand, b2 as runTrustZonePromoteCliCommand, b3 as runTrustZoneStatusCliCommand, b4 as runUtilityLearningCliCommand, b5 as runUtilityLearningStatusCliCommand, b6 as runUtilityTelemetryRecordCliCommand, b7 as runUtilityTelemetryStatusCliCommand, b8 as runVerifiedRecallSearchCliCommand, b9 as runVerifyMemoryProjectionCliCommand, ba as runWebDavServeCliCommand, bb as runWebDavStopCliCommand, bc as runWorkProductRecallSearchCliCommand, bd as runWorkProductRecordCliCommand, be as runWorkProductStatusCliCommand, bf as runWorkProjectCliCommand, bg as runWorkTaskCliCommand } from './cli-BQRqR9N-.js';
42
42
  import './connectors-cli-2iaQ5tX2.js';
43
43
  import './storage.js';
44
44
  import './page-versioning.js';
package/dist/cli.js CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  filterNormalMemorySearchResults,
4
4
  hasDestructivePurgeFailures,
5
5
  isNormalRetrievalVisibleMemory,
6
+ listMemoryMarkdownFilePaths,
6
7
  parseDurationToMs,
7
8
  parseStrictCliDate,
8
9
  planAggressiveDuplicateDeletions,
@@ -89,7 +90,7 @@ import {
89
90
  runWorkProductStatusCliCommand,
90
91
  runWorkProjectCliCommand,
91
92
  runWorkTaskCliCommand
92
- } from "./chunk-HSCJYHYV.js";
93
+ } from "./chunk-2OPARZ4B.js";
93
94
  import "./chunk-MC4FJXPA.js";
94
95
  import "./chunk-LQHDIS7L.js";
95
96
  import "./chunk-7F7Z6MOS.js";
@@ -107,8 +108,8 @@ import "./chunk-765K3SAT.js";
107
108
  import "./chunk-EEC4PCG5.js";
108
109
  import "./chunk-PYIFUBRK.js";
109
110
  import "./chunk-HOJZMQ4J.js";
110
- import "./chunk-F6O7IOS3.js";
111
- import "./chunk-PXVFMQLD.js";
111
+ import "./chunk-6JBKHTQD.js";
112
+ import "./chunk-BZG2CWOQ.js";
112
113
  import "./chunk-LZZNTPLR.js";
113
114
  import "./chunk-WMWVO45V.js";
114
115
  import "./chunk-KJTKLXTH.js";
@@ -118,33 +119,33 @@ import "./chunk-CKITWVWJ.js";
118
119
  import "./chunk-OUELRE5E.js";
119
120
  import "./chunk-GQL52GQ5.js";
120
121
  import "./chunk-EVWIEEKZ.js";
121
- import "./chunk-QXHBWFR3.js";
122
+ import "./chunk-IHG6CC7T.js";
122
123
  import "./chunk-TGQ2NTWH.js";
123
124
  import "./chunk-PEPHBH2W.js";
124
125
  import "./chunk-SXYCVRLK.js";
125
- import "./chunk-5AYAZN45.js";
126
- import "./chunk-YYQRVNSV.js";
126
+ import "./chunk-XRSIGVTS.js";
127
+ import "./chunk-7C4MPEPE.js";
127
128
  import "./chunk-3T74IZB3.js";
128
129
  import "./chunk-HL4DB7TO.js";
129
130
  import "./chunk-YNDLCWXS.js";
130
131
  import "./chunk-AUDJPF4N.js";
131
132
  import "./chunk-44442YCH.js";
132
133
  import "./chunk-Y4Z4I6WK.js";
133
- import "./chunk-AL4RAJL5.js";
134
+ import "./chunk-7XH7VJN4.js";
134
135
  import "./chunk-YBPYIAA5.js";
135
136
  import "./chunk-2PRQG7PV.js";
136
137
  import "./chunk-X6IRLNOO.js";
137
138
  import "./chunk-2F6NP3NT.js";
138
139
  import "./chunk-TERNBNJB.js";
139
- import "./chunk-TYIXG4VR.js";
140
+ import "./chunk-YW52BQSU.js";
140
141
  import "./chunk-W4RVMTHR.js";
141
- import "./chunk-NMPEJV5M.js";
142
+ import "./chunk-DSLUOQDY.js";
142
143
  import "./chunk-ZRWB5D4H.js";
143
144
  import "./chunk-AGRPGAKR.js";
144
145
  import "./chunk-S4DDLTPX.js";
145
146
  import "./chunk-SFQ6QNL7.js";
146
147
  import "./chunk-33JBK2XP.js";
147
- import "./chunk-TBLGI2LT.js";
148
+ import "./chunk-D7IXTY5E.js";
148
149
  import "./chunk-KFY3SGN7.js";
149
150
  import "./chunk-CMTINOFS.js";
150
151
  import "./chunk-TQNRI55H.js";
@@ -166,7 +167,7 @@ import "./chunk-Z5LAYHGJ.js";
166
167
  import "./chunk-LBJBNWS2.js";
167
168
  import "./chunk-HQ6NIBL6.js";
168
169
  import "./chunk-OADWQ5CR.js";
169
- import "./chunk-4KDLCMLK.js";
170
+ import "./chunk-IROWLAWG.js";
170
171
  import "./chunk-SEDEKFYQ.js";
171
172
  import "./chunk-RKNJBZ55.js";
172
173
  import "./chunk-J64TK33U.js";
@@ -175,34 +176,35 @@ import "./chunk-42NQ7AVG.js";
175
176
  import "./chunk-TMSXWOBZ.js";
176
177
  import "./chunk-7RXCMVFQ.js";
177
178
  import "./chunk-7WV3F5DQ.js";
178
- import "./chunk-2KDQI363.js";
179
+ import "./chunk-2HEZXPYU.js";
179
180
  import "./chunk-T4WDJPEZ.js";
180
181
  import "./chunk-D24OXEPB.js";
181
- import "./chunk-DFAXGZKI.js";
182
+ import "./chunk-JIX3ZL2J.js";
182
183
  import "./chunk-GDASG7NC.js";
183
184
  import "./chunk-GDB4J2H3.js";
184
- import "./chunk-DHGSZ3UD.js";
185
+ import "./chunk-ARV3AUOM.js";
185
186
  import "./chunk-H7XKCNR6.js";
186
187
  import "./chunk-TIJYQXDI.js";
187
188
  import "./chunk-SOBJ6NEY.js";
188
189
  import "./chunk-BT7NVCML.js";
189
- import "./chunk-A7EF2XRO.js";
190
+ import "./chunk-EXXBA5OM.js";
190
191
  import "./chunk-GYSYLGNE.js";
191
- import "./chunk-5RIRL3XL.js";
192
+ import "./chunk-RS25QOKZ.js";
192
193
  import "./chunk-JGSKJHF7.js";
193
194
  import "./chunk-FF4KLI5W.js";
194
195
  import "./chunk-2MXEVL75.js";
195
- import "./chunk-WOQIHC67.js";
196
- import "./chunk-35HP3TGR.js";
197
- import "./chunk-FZC2WSDB.js";
196
+ import "./chunk-DQY7NJ5L.js";
197
+ import "./chunk-ROHLEUTH.js";
198
+ import "./chunk-DOCTITOP.js";
198
199
  import "./chunk-CYEPCZN5.js";
199
- import "./chunk-ZJH723NM.js";
200
+ import "./chunk-Q5ZU3RNY.js";
200
201
  import "./chunk-JOASJWQR.js";
201
202
  import "./chunk-RN7MUWON.js";
202
- import "./chunk-WSQG37DV.js";
203
- import "./chunk-Q4CAQGKQ.js";
203
+ import "./chunk-OUWAQVDJ.js";
204
+ import "./chunk-AER6MT24.js";
204
205
  import "./chunk-CINZGPSJ.js";
205
206
  import "./chunk-ZFXCQPNO.js";
207
+ import "./chunk-5GPPACXK.js";
206
208
  import "./chunk-7OGJQP7T.js";
207
209
  import "./chunk-E6ZDCOHM.js";
208
210
  import "./chunk-OIF36KGD.js";
@@ -224,8 +226,8 @@ import "./chunk-3ONXXHQO.js";
224
226
  import "./chunk-Y56J7CXW.js";
225
227
  import "./chunk-2LSZVONP.js";
226
228
  import "./chunk-DEUNUKTD.js";
227
- import "./chunk-GY3V3SUI.js";
228
- import "./chunk-AX5O25EF.js";
229
+ import "./chunk-KHGE6PMF.js";
230
+ import "./chunk-VH6EIKVS.js";
229
231
  import "./chunk-M7XQSUBB.js";
230
232
  import "./chunk-5UZXUTVO.js";
231
233
  import "./chunk-J6A3CX5N.js";
@@ -240,7 +242,7 @@ import "./chunk-DM2T26WE.js";
240
242
  import "./chunk-LDXUBPMO.js";
241
243
  import "./chunk-FVQJYWH7.js";
242
244
  import "./chunk-G7D6GZ5J.js";
243
- import "./chunk-ALEPI75L.js";
245
+ import "./chunk-VF4XKTX3.js";
244
246
  import "./chunk-RGMVMVMF.js";
245
247
  import "./chunk-ZY2MNJR6.js";
246
248
  import "./chunk-SSOMTUCA.js";
@@ -259,7 +261,7 @@ import "./chunk-TVVEYCNW.js";
259
261
  import "./chunk-RFYAYKTD.js";
260
262
  import "./chunk-LBLXEFWK.js";
261
263
  import "./chunk-VFUEZZBS.js";
262
- import "./chunk-UAU5U5ML.js";
264
+ import "./chunk-UDJLF3BO.js";
263
265
  import "./chunk-KQAFEZQX.js";
264
266
  import "./chunk-WEHSQBFR.js";
265
267
  import "./chunk-X7Y7WX73.js";
@@ -267,12 +269,13 @@ import "./chunk-J4EB7DNW.js";
267
269
  import "./chunk-BJMBJZ2Y.js";
268
270
  import "./chunk-UKJAGEXH.js";
269
271
  import "./chunk-FP2373TW.js";
270
- import "./chunk-ZLDUQWT2.js";
272
+ import "./chunk-PWWWLD7D.js";
271
273
  import "./chunk-UI3NYK34.js";
272
274
  import "./chunk-GCGJW34D.js";
273
- import "./chunk-ILXTATKK.js";
275
+ import "./chunk-J2HSAU72.js";
274
276
  import "./chunk-A6XUJE5D.js";
275
277
  import "./chunk-P7FMDTKL.js";
278
+ import "./chunk-VS2IYZRU.js";
276
279
  import "./chunk-AH2JUU6X.js";
277
280
  import "./chunk-AC5LO7IU.js";
278
281
  import "./chunk-SOAU2OE2.js";
@@ -282,6 +285,7 @@ export {
282
285
  filterNormalMemorySearchResults,
283
286
  hasDestructivePurgeFailures,
284
287
  isNormalRetrievalVisibleMemory,
288
+ listMemoryMarkdownFilePaths,
285
289
  parseDurationToMs,
286
290
  parseStrictCliDate,
287
291
  planAggressiveDuplicateDeletions,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  CompoundingEngine,
3
3
  defaultTierMigrationCycleBudget
4
- } from "../chunk-TWAJICBN.js";
4
+ } from "../chunk-OHJFJ4HI.js";
5
5
  import "../chunk-DRD2Q7HQ.js";
6
- import "../chunk-AX5O25EF.js";
6
+ import "../chunk-VH6EIKVS.js";
7
7
  import "../chunk-M7XQSUBB.js";
8
8
  import "../chunk-5UZXUTVO.js";
9
9
  import "../chunk-J6A3CX5N.js";
@@ -18,14 +18,15 @@ import "../chunk-DM2T26WE.js";
18
18
  import "../chunk-LDXUBPMO.js";
19
19
  import "../chunk-FVQJYWH7.js";
20
20
  import "../chunk-G7D6GZ5J.js";
21
- import "../chunk-ALEPI75L.js";
21
+ import "../chunk-VF4XKTX3.js";
22
22
  import "../chunk-4DJQYKMN.js";
23
23
  import "../chunk-EYIEWJNI.js";
24
24
  import "../chunk-JUC24CTX.js";
25
25
  import "../chunk-2ODBA7MQ.js";
26
- import "../chunk-ILXTATKK.js";
26
+ import "../chunk-J2HSAU72.js";
27
27
  import "../chunk-A6XUJE5D.js";
28
28
  import "../chunk-P7FMDTKL.js";
29
+ import "../chunk-VS2IYZRU.js";
29
30
  import "../chunk-PZ5AY32C.js";
30
31
  export {
31
32
  CompoundingEngine,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  runCodexMaterialize,
3
3
  runPostConsolidationMaterialize
4
- } from "../chunk-ANJOULTP.js";
4
+ } from "../chunk-C7AF236A.js";
5
5
  import "../chunk-LN4YGHTM.js";
6
6
  import "../chunk-3UXOZBHV.js";
7
- import "../chunk-AX5O25EF.js";
7
+ import "../chunk-VH6EIKVS.js";
8
8
  import "../chunk-M7XQSUBB.js";
9
9
  import "../chunk-5UZXUTVO.js";
10
10
  import "../chunk-J6A3CX5N.js";
@@ -19,15 +19,16 @@ import "../chunk-DM2T26WE.js";
19
19
  import "../chunk-LDXUBPMO.js";
20
20
  import "../chunk-FVQJYWH7.js";
21
21
  import "../chunk-G7D6GZ5J.js";
22
- import "../chunk-ALEPI75L.js";
22
+ import "../chunk-VF4XKTX3.js";
23
23
  import "../chunk-U3PN77QT.js";
24
24
  import "../chunk-4DJQYKMN.js";
25
25
  import "../chunk-EYIEWJNI.js";
26
26
  import "../chunk-JUC24CTX.js";
27
27
  import "../chunk-2ODBA7MQ.js";
28
- import "../chunk-ILXTATKK.js";
28
+ import "../chunk-J2HSAU72.js";
29
29
  import "../chunk-A6XUJE5D.js";
30
30
  import "../chunk-P7FMDTKL.js";
31
+ import "../chunk-VS2IYZRU.js";
31
32
  import "../chunk-PZ5AY32C.js";
32
33
  export {
33
34
  runCodexMaterialize,
@@ -27,7 +27,7 @@ import {
27
27
  import "../chunk-G56P5RLD.js";
28
28
  import {
29
29
  runCodexMaterialize
30
- } from "../chunk-ANJOULTP.js";
30
+ } from "../chunk-C7AF236A.js";
31
31
  import {
32
32
  MATERIALIZE_VERSION,
33
33
  SENTINEL_FILE,
@@ -48,7 +48,7 @@ import {
48
48
  coerceInstallExtension
49
49
  } from "../chunk-PHK3HARR.js";
50
50
  import "../chunk-O75CRYGF.js";
51
- import "../chunk-AX5O25EF.js";
51
+ import "../chunk-VH6EIKVS.js";
52
52
  import "../chunk-M7XQSUBB.js";
53
53
  import "../chunk-5UZXUTVO.js";
54
54
  import "../chunk-J6A3CX5N.js";
@@ -63,15 +63,16 @@ import "../chunk-DM2T26WE.js";
63
63
  import "../chunk-LDXUBPMO.js";
64
64
  import "../chunk-FVQJYWH7.js";
65
65
  import "../chunk-G7D6GZ5J.js";
66
- import "../chunk-ALEPI75L.js";
66
+ import "../chunk-VF4XKTX3.js";
67
67
  import "../chunk-U3PN77QT.js";
68
68
  import "../chunk-4DJQYKMN.js";
69
69
  import "../chunk-EYIEWJNI.js";
70
70
  import "../chunk-JUC24CTX.js";
71
71
  import "../chunk-2ODBA7MQ.js";
72
- import "../chunk-ILXTATKK.js";
72
+ import "../chunk-J2HSAU72.js";
73
73
  import "../chunk-A6XUJE5D.js";
74
74
  import "../chunk-P7FMDTKL.js";
75
+ import "../chunk-VS2IYZRU.js";
75
76
  import "../chunk-PZ5AY32C.js";
76
77
  export {
77
78
  MARKETPLACE_MANIFEST_FILENAME,
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  runConsolidationProvenanceCheck
3
- } from "./chunk-AL4RAJL5.js";
3
+ } from "./chunk-7XH7VJN4.js";
4
4
  import "./chunk-G7D6GZ5J.js";
5
- import "./chunk-ALEPI75L.js";
5
+ import "./chunk-VF4XKTX3.js";
6
+ import "./chunk-VS2IYZRU.js";
6
7
  import "./chunk-PZ5AY32C.js";
7
8
  export {
8
9
  runConsolidationProvenanceCheck
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  getVersion
3
- } from "./chunk-ALEPI75L.js";
3
+ } from "./chunk-VF4XKTX3.js";
4
+ import "./chunk-VS2IYZRU.js";
4
5
  import "./chunk-PZ5AY32C.js";
5
6
 
6
7
  // src/consolidation-undo.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/consolidation-undo.ts"],"sourcesContent":["/**\n * Consolidation undo (issue #561 PR 5).\n *\n * Reverts a consolidated memory by restoring each source memory from its\n * `derived_from` snapshot and archiving the target.\n *\n * Contract:\n * - Load the target memory markdown file via its absolute path.\n * - For every `\"<rel>:<version>\"` entry in `derived_from`, fetch the\n * snapshot content via `page-versioning.getVersion` and restore it\n * to the original relative path. If the restore target file\n * already exists, we skip overwriting it (the source was never\n * archived, or was re-created since) and record the skip.\n * - Archive the target with reason code `\"consolidation-undo\"` so the\n * lifecycle ledger records the undo.\n * - Dry-run mode produces the same plan without touching disk.\n *\n * The helper is kept pure over `StorageManager` so the CLI can reuse it\n * without additional wiring, and tests can exercise the plan logic\n * directly.\n */\n\nimport path from \"node:path\";\nimport { mkdir, writeFile, access, realpath, lstat } from \"node:fs/promises\";\nimport { constants as fsConstants } from \"node:fs\";\nimport type { StorageManager } from \"./storage.js\";\nimport type { VersioningConfig } from \"./page-versioning.js\";\nimport { getVersion } from \"./page-versioning.js\";\n\n/**\n * Outcome of restoring a single `derived_from` source.\n */\nexport interface ConsolidationUndoRestore {\n /** The raw `\"<relpath>:<version>\"` entry from `derived_from`. */\n entry: string;\n /** Absolute path where the source would be / was restored. */\n sourcePath: string;\n /** What actually happened. */\n outcome:\n | \"restored\"\n | \"skipped_file_exists\"\n | \"skipped_non_regular_file\"\n | \"skipped_snapshot_missing\"\n | \"skipped_malformed_entry\"\n | \"skipped_outside_memory_dir\"\n | \"skipped_non_active_path\"\n | \"skipped_self_referential\"\n | \"skipped_write_failed\"\n | \"skipped_blocked_by_other_failures\"\n | \"skipped_dry_run\";\n /** Human-readable detail. */\n detail?: string;\n}\n\n/**\n * Plan + result of a `remnic consolidate undo` invocation.\n */\nexport interface ConsolidationUndoResult {\n /** Absolute path to the target memory. */\n targetPath: string;\n /** True when the target was archived successfully. */\n targetArchived: boolean;\n /** Per-source restore outcomes. */\n restores: ConsolidationUndoRestore[];\n /** Whether the run was a dry-run plan only. */\n dryRun: boolean;\n /** Fatal error, if any — the run bails early. */\n error?: string;\n}\n\nconst DERIVED_FROM_ENTRY_RE = /^(.+):(\\d+)$/;\n\nfunction parseEntry(entry: unknown): { pagePath: string; versionId: string } | null {\n // Non-string entries (PR #637 round-3 review, cursor Low) can arrive\n // from hostile on-disk frontmatter — guard against a .match() crash.\n if (typeof entry !== \"string\") return null;\n const match = entry.match(DERIVED_FROM_ENTRY_RE);\n if (!match) return null;\n return { pagePath: match[1], versionId: match[2] };\n}\n\n/**\n * Verify that `candidate` resolves inside `root` (defense against\n * path-traversal in `derived_from` entries and user-facing target\n * paths). Path-string normalization only; for symlink-aware checks\n * use `isInsideDirectoryRealpath`. Both paths are resolved to\n * absolute form before comparison so `..` segments, symlinks-as-\n * strings, and relative prefixes are normalized.\n */\nexport function isInsideDirectory(candidate: string, root: string): boolean {\n const normRoot = path.resolve(root);\n const normCandidate = path.resolve(candidate);\n const rel = path.relative(normRoot, normCandidate);\n if (rel.length === 0) return true;\n if (rel.startsWith(\"..\")) return false;\n if (path.isAbsolute(rel)) return false;\n return true;\n}\n\n/**\n * Symlink-aware containment check (PR #637 round-2 review, codex P1).\n *\n * `isInsideDirectory` only normalizes path strings — if a `derived_from`\n * entry resolves through a symlink inside `memoryDir` that points\n * outside, the string check passes but the subsequent `writeFile` would\n * land outside the memory tree. Use this guard for any path that is\n * about to be written.\n *\n * Walks every parent directory between `candidate` and `root`,\n * `realpath`-ing each segment that exists and rejecting when any\n * segment escapes `root`. Non-existent parents are resolved as the\n * canonicalized deepest-existing ancestor plus the trailing segments,\n * so a not-yet-created target file still gets the symlink check on its\n * existing parent directories.\n */\nexport async function isInsideDirectoryRealpath(\n candidate: string,\n root: string,\n): Promise<boolean> {\n if (!isInsideDirectory(candidate, root)) return false;\n // Reject raw `..` segments before canonicalization so that symlinks\n // cannot be hidden behind intermediate dot-dot components (PR #637\n // round-14 review, codex P1).\n const rawSegments = candidate.replace(/\\\\/g, \"/\").split(\"/\");\n if (rawSegments.some((s) => s === \"..\")) return false;\n let resolvedRoot: string;\n try {\n resolvedRoot = await realpath(path.resolve(root));\n } catch {\n return false;\n }\n const normCandidate = path.resolve(candidate);\n\n // Reject dangling symlinks (PR #637 round-3 review, codex P1).\n // If the candidate itself is a symlink (even if its target doesn't\n // exist), Node will follow it when we later call `writeFile`.\n // `lstat` inspects the link itself without dereferencing; if it\n // succeeds and reports a symlink, we treat the candidate as\n // unsafe. We must check every non-root ancestor too — a symlink\n // anywhere along the path lets an attacker redirect writes.\n const normRoot = path.resolve(root);\n const relFromRoot = path.relative(normRoot, normCandidate);\n const segments = relFromRoot.length > 0 ? relFromRoot.split(path.sep) : [];\n for (let i = 0; i <= segments.length; i++) {\n const probe = i === 0 ? normRoot : path.join(normRoot, ...segments.slice(0, i));\n try {\n const st = await lstat(probe);\n if (st.isSymbolicLink() && probe !== normRoot) {\n // A symlink on the path — resolve THIS segment and bail out\n // if the resolved target escapes `resolvedRoot`.\n let target: string;\n try {\n target = await realpath(probe);\n } catch {\n // Dangling symlink inside memoryDir — always unsafe.\n return false;\n }\n const rel = path.relative(resolvedRoot, target);\n if (rel.length === 0) continue;\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) return false;\n }\n } catch {\n // Segment doesn't exist yet — that's fine, fall through to the\n // textual containment verification below.\n }\n }\n\n // Walk up from the candidate until we hit a path that exists, then\n // realpath THAT and re-apply the trailing segments textually.\n const parts = normCandidate.split(path.sep);\n for (let i = parts.length; i > 0; i--) {\n const probe = parts.slice(0, i).join(path.sep) || path.sep;\n try {\n const resolved = await realpath(probe);\n // Re-join any trailing segments that didn't exist yet.\n const trailing = parts.slice(i).join(path.sep);\n const final = trailing.length > 0 ? path.join(resolved, trailing) : resolved;\n // Now apply the textual containment check against the canonical\n // `resolvedRoot`.\n const rel = path.relative(resolvedRoot, final);\n if (rel.length === 0) return true;\n if (rel.startsWith(\"..\")) return false;\n if (path.isAbsolute(rel)) return false;\n return true;\n } catch {\n continue;\n }\n }\n // Nothing along the path resolvable — treat as outside by default.\n return false;\n}\n\n/**\n * Directories under memoryDir that are NOT active memory locations.\n * A `derived_from` entry pointing into one of these should not be\n * counted as \"recovered_existing\" (PR #637 round-7 review, codex P2).\n * The versioning sidecar directory is included dynamically via the\n * `sidecarDir` parameter (PR #637 round-8 review, codex P2).\n */\nconst NON_ACTIVE_PREFIXES = [\"archive/\", \"state/\"];\n\n/**\n * Normalize a relative path by collapsing `.` and `..` segments so\n * that crafted entries like `\"facts/../archive/x.md\"` are reduced to\n * `\"archive/x.md\"` before the non-active-prefix check.\n */\nfunction normalizeRelativePath(p: string): string {\n // Normalize separators, split into segments, then resolve.\n const parts = p.replace(/\\\\/g, \"/\").split(\"/\");\n const resolved: string[] = [];\n for (const seg of parts) {\n if (seg === \"\" || seg === \".\") continue;\n if (seg === \"..\") {\n if (resolved.length > 0) resolved.pop();\n // If \"..\" pops past the root, we let the caller's containment\n // check catch it — don't silently drop.\n } else {\n resolved.push(seg);\n }\n }\n return resolved.join(\"/\");\n}\n\n/**\n * Check that a relative path (relative to memoryDir) points to an\n * active memory location rather than an internal/archive directory.\n * Returns `true` when the normalised `pagePath` does NOT start with\n * a known non-active prefix.\n *\n * @param pagePath Relative path from `derived_from` entry.\n * @param sidecarDir Optional versioning sidecar directory name\n * (e.g. `\".versions\"`). When provided, paths\n * under this directory are also rejected as\n * non-active.\n */\nexport function isActiveMemoryRelativePath(\n pagePath: string,\n sidecarDir?: string,\n): boolean {\n const normalized = normalizeRelativePath(pagePath);\n const prefixes = [...NON_ACTIVE_PREFIXES];\n if (sidecarDir) {\n const normSidecar = normalizeRelativePath(sidecarDir);\n prefixes.push(normSidecar + \"/\");\n }\n for (const prefix of prefixes) {\n if (normalized === prefix.slice(0, -1) || normalized.startsWith(prefix)) {\n return false;\n }\n }\n return true;\n}\n\nasync function isRegularFile(p: string): Promise<boolean> {\n try {\n const st = await lstat(p);\n return st.isFile();\n } catch {\n return false;\n }\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await access(p, fsConstants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Perform a consolidation-undo operation.\n *\n * @param options.storage Storage manager for the memory directory.\n * @param options.memoryDir Absolute memory directory root.\n * @param options.targetPath Absolute path to the consolidated memory.\n * @param options.versioning Page-versioning config (sidecarDir must\n * match the sidecar layout used when the\n * snapshots were created).\n * @param options.dryRun When true, compute the plan but do not\n * write or archive.\n */\nexport async function runConsolidationUndo(options: {\n storage: StorageManager;\n memoryDir: string;\n targetPath: string;\n versioning: VersioningConfig;\n dryRun?: boolean;\n}): Promise<ConsolidationUndoResult> {\n const { storage, memoryDir, targetPath, versioning } = options;\n const dryRun = options.dryRun === true;\n\n const result: ConsolidationUndoResult = {\n targetPath,\n targetArchived: false,\n restores: [],\n dryRun,\n };\n\n // Defense against path-traversal (PR #637 review, codex P1): refuse\n // to operate on a target outside the configured memory directory.\n // Archive moves and eventual unlink would otherwise let an operator\n // accidentally destroy an unrelated file with memory-like\n // frontmatter. Uses the realpath-aware check so a symlinked\n // directory inside `memoryDir` can't tunnel a target past the guard.\n if (!(await isInsideDirectoryRealpath(targetPath, memoryDir))) {\n result.error = `target path ${targetPath} is outside memory directory ${memoryDir}`;\n return result;\n }\n\n // Reject targets in non-active directories (archive/, state/,\n // versioning sidecar). A target inside `.versions/...` would be\n // a sidecar snapshot, not a real consolidated memory; archiving\n // it would silently delete version history (PR #637 round-8\n // review, codex P2).\n const targetRel = path.relative(memoryDir, targetPath);\n if (!isActiveMemoryRelativePath(targetRel, versioning.sidecarDir)) {\n result.error = `target path \"${targetRel}\" is inside a non-active directory — refusing to operate`;\n return result;\n }\n\n // Load the target memory. readMemoryByPath returns null when the file\n // is absent or unparseable — surface that as a fatal error because the\n // caller cannot continue without a derived_from list.\n const target = await storage.readMemoryByPath(targetPath);\n if (!target) {\n result.error = `could not load target memory at ${targetPath}`;\n return result;\n }\n\n const derivedFrom = target.frontmatter.derived_from;\n if (!Array.isArray(derivedFrom) || derivedFrom.length === 0) {\n result.error = \"target memory has no derived_from entries — nothing to undo\";\n return result;\n }\n\n // Two-pass plan + execute (PR #637 round-4 review, cursor Medium):\n // the undo is \"all-or-nothing\" both for the archive decision AND\n // for the per-source writes. First pass validates + loads every\n // snapshot into memory; second pass writes only if every source\n // would succeed. This prevents the previous eager-write behaviour\n // where a later-failing source would leave earlier sources already\n // written to disk alongside an unarchived consolidated target.\n type RestorePlan =\n | { kind: \"skip\"; restore: ConsolidationUndoRestore }\n | { kind: \"write\"; entry: string; sourcePath: string; content: string }\n | { kind: \"recovered_existing\"; entry: string; sourcePath: string };\n\n const plans: RestorePlan[] = [];\n for (const rawEntry of derivedFrom) {\n const entry = typeof rawEntry === \"string\" ? rawEntry : String(rawEntry);\n const parsed = parseEntry(rawEntry);\n if (!parsed) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath: \"\",\n outcome: \"skipped_malformed_entry\",\n detail: `expected \"<path>:<version>\" shape`,\n },\n });\n continue;\n }\n\n // Reject absolute paths in derived_from entries (PR #637 round-10\n // review, codex P1). An absolute pagePath would cause path.join to\n // ignore memoryDir, bypassing the active-directory guard downstream.\n if (path.isAbsolute(parsed.pagePath)) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath: parsed.pagePath,\n outcome: \"skipped_malformed_entry\",\n detail: `derived_from path must be relative, got absolute: \"${parsed.pagePath}\"`,\n },\n });\n continue;\n }\n\n const sourcePath = path.join(memoryDir, parsed.pagePath);\n\n if (!(await isInsideDirectoryRealpath(sourcePath, memoryDir))) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_outside_memory_dir\",\n detail: `resolved path escapes memory directory ${memoryDir}`,\n },\n });\n continue;\n }\n\n // Reject source paths inside non-active directories (archive/,\n // state/, versioning sidecar). A crafted or corrupted derived_from\n // entry like \"archive/2024-01-01/x.md:1\" would otherwise be counted\n // as \"recovered_existing\" even though no active memory was restored.\n // Also resolve symlinks before checking — a derived_from entry like\n // \"facts/link/stale.md:1\" where `facts/link` points to `archive/…`\n // must be caught (PR #637 round-8 review, cursor+codex).\n let resolvedRelative = parsed.pagePath;\n try {\n const realBase = await realpath(memoryDir);\n try {\n const realSource = await realpath(sourcePath);\n const rel = path.relative(realBase, realSource);\n if (!rel.startsWith(\"..\") && !path.isAbsolute(rel)) {\n resolvedRelative = rel.replace(/\\\\/g, \"/\");\n }\n } catch {\n // realpath on the leaf failed (file doesn't exist yet). Try\n // resolving the parent directory instead — if the parent is a\n // symlink into archive/state, the leaf would be written there\n // too (PR #637 round-12 review, codex P1).\n const parentDir = path.dirname(sourcePath);\n try {\n const realParent = await realpath(parentDir);\n const parentRel = path.relative(realBase, realParent);\n if (!parentRel.startsWith(\"..\") && !path.isAbsolute(parentRel)) {\n const leafName = path.basename(sourcePath);\n resolvedRelative = path.join(parentRel, leafName).replace(/\\\\/g, \"/\");\n }\n } catch {\n // Parent also doesn't exist — fall through to text path check\n }\n }\n } catch {\n // memoryDir realpath failed — use the text path\n }\n if (!isActiveMemoryRelativePath(parsed.pagePath, versioning.sidecarDir) ||\n !isActiveMemoryRelativePath(resolvedRelative, versioning.sidecarDir)) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_non_active_path\",\n detail: `source path \"${parsed.pagePath}\" is inside a non-active directory (archive/state/versions)`,\n },\n });\n continue;\n }\n\n // Reject self-referential derived_from entries (PR #637 round-9 review,\n // codex P1). If the source resolves to the same file as the target,\n // counting it as \"recovered\" would let undo archive the target without\n // restoring any independent source — leaving no active copy. This\n // guards against corrupted or manually-edited derived_from lists.\n if (path.resolve(sourcePath) === path.resolve(targetPath)) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_self_referential\",\n detail: `derived_from entry \"${entry}\" resolves to the same file as the target — refusing to count as recovered`,\n },\n });\n continue;\n }\n\n if (await isRegularFile(sourcePath)) {\n // Source is still active (regular file present) — nothing to\n // restore but this counts as \"recovered\" for the archive\n // decision. We require a regular file specifically (PR #637\n // round-5 review, codex P2): a directory, device node, or\n // symlink at the source path should not count as \"recovered\"\n // because a later read won't find the expected memory content.\n plans.push({ kind: \"recovered_existing\", entry, sourcePath });\n continue;\n }\n if (await fileExists(sourcePath)) {\n // Something other than a regular file is at the source path\n // (directory, device node, symlink). Refuse to overwrite AND\n // refuse to count as recovered (PR #637 round-5 review, codex\n // P2) — the operator needs to clean up manually. This is a\n // blocking skip: no source writes happen, target stays active.\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_non_regular_file\",\n detail: \"source path is occupied by a non-regular-file; refusing to proceed\",\n },\n });\n continue;\n }\n\n let snapshotContent: string;\n try {\n snapshotContent = await getVersion(\n sourcePath,\n parsed.versionId,\n versioning,\n memoryDir,\n );\n } catch {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_snapshot_missing\",\n detail: `no snapshot for version ${parsed.versionId}`,\n },\n });\n continue;\n }\n\n plans.push({ kind: \"write\", entry, sourcePath, content: snapshotContent });\n }\n\n // If any plan is a skip (anything other than \"write\" or\n // \"recovered_existing\"), the undo is over before it starts — no\n // writes happen. Reveal every per-source skip reason in the\n // result so operators can diagnose what went wrong.\n const skipped = plans.filter((p) => p.kind === \"skip\");\n if (skipped.length > 0) {\n for (const p of plans) {\n if (p.kind === \"skip\") {\n result.restores.push(p.restore);\n } else if (p.kind === \"write\") {\n // Announced-but-not-executed write — still record it so the\n // operator sees what would have been restored if the failed\n // sources had been recoverable.\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: dryRun ? \"skipped_dry_run\" : \"skipped_blocked_by_other_failures\",\n detail: dryRun\n ? \"would restore from snapshot (blocked by other failures)\"\n : \"snapshot available but undo aborted due to other failures\",\n });\n } else {\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_file_exists\",\n detail: \"source file already exists; no restore needed\",\n });\n }\n }\n const recovered = result.restores.filter(\n (r) => r.outcome === \"restored\" || r.outcome === \"skipped_file_exists\",\n ).length;\n if (recovered === 0) {\n result.error =\n \"no sources could be recovered (all snapshots missing or paths unsafe); target not archived to preserve data\";\n } else {\n result.error = `${skipped.length} of ${plans.length} sources could not be recovered; target not archived (undo is all-or-nothing)`;\n }\n return result;\n }\n\n // Deduplicate plans by sourcePath: duplicate derived_from entries for\n // the same source would cause the second wx-flagged write to fail with\n // EEXIST after the first succeeds. The first plan for each source wins;\n // subsequent duplicates are recorded as skipped. Applied before dry-run\n // so the preview accurately reflects what execution would do.\n const seenSourcePaths = new Set<string>();\n const dedupedPlans: RestorePlan[] = [];\n for (const p of plans) {\n if (p.kind === \"write\" || p.kind === \"recovered_existing\") {\n if (seenSourcePaths.has(p.sourcePath)) {\n dedupedPlans.push({\n kind: \"skip\",\n restore: {\n entry: p.kind === \"write\" ? p.entry : p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_file_exists\",\n detail: \"duplicate derived_from entry — source already processed\",\n },\n });\n continue;\n }\n seenSourcePaths.add(p.sourcePath);\n }\n dedupedPlans.push(p);\n }\n\n // Dry-run: report what each plan would do.\n if (dryRun) {\n for (const p of dedupedPlans) {\n if (p.kind === \"write\") {\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_dry_run\",\n detail: \"would restore from snapshot\",\n });\n } else if (p.kind === \"recovered_existing\") {\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_file_exists\",\n detail: \"source file already exists; no restore needed\",\n });\n } else if (p.kind === \"skip\" && p.restore) {\n result.restores.push(p.restore);\n }\n }\n return result;\n }\n\n // All validations passed — execute writes. A write failure here\n // is a filesystem problem rather than a provenance problem, but\n // any failure still aborts the archive.\n\n let writeFailed = false;\n for (const p of dedupedPlans) {\n if (p.kind === \"skip\") {\n // Dedup-generated skip entries and other pre-write skips.\n if (p.restore) result.restores.push(p.restore);\n continue;\n }\n if (p.kind === \"recovered_existing\") {\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_file_exists\",\n detail: \"source file already exists; no restore needed\",\n });\n continue;\n }\n if (p.kind === \"write\") {\n if (writeFailed) {\n // All-or-nothing: once a write fails, skip all remaining writes\n // so the target is not archived with partial source coverage.\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_blocked_by_other_failures\",\n detail: \"a prior source write failed; skipping remaining writes to honor all-or-nothing contract\",\n });\n continue;\n }\n try {\n await mkdir(path.dirname(p.sourcePath), { recursive: true });\n // Use exclusive create (wx / O_EXCL) so that if another process\n // recreates the source file between planning and execution, this\n // write fails with EEXIST instead of silently overwriting the new\n // file (PR #637 round-11 review, codex P1).\n await writeFile(p.sourcePath, p.content, { encoding: \"utf-8\", flag: \"wx\" });\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"restored\",\n });\n } catch (err) {\n writeFailed = true;\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_write_failed\",\n detail: `write failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n }\n\n if (writeFailed) {\n result.error =\n \"one or more source writes failed mid-restore; target not archived to preserve data\";\n return result;\n }\n\n // Archive the target memory. archiveMemory returns null on\n // failure — surface that as a fatal error (PR #637 round-5 review,\n // codex P2) so automation doesn't mistake a half-undo for a clean\n // run. The already-completed restores still roll forward; the\n // result.restores list records what was written.\n const archivedAt = await storage.archiveMemory(target, {\n actor: \"consolidate-undo\",\n reasonCode: \"consolidation-undo\",\n });\n result.targetArchived = archivedAt !== null;\n if (!result.targetArchived) {\n result.error =\n \"sources restored successfully but archiving the consolidated target failed; inspect storage for manual cleanup\";\n }\n return result;\n}\n\n/**\n * Render a consolidation-undo result as a human-readable multi-line\n * string for the CLI. Extracted so tests can snapshot the formatting\n * without parsing stdout.\n */\nexport function formatConsolidationUndoResult(result: ConsolidationUndoResult): string {\n const lines: string[] = [];\n lines.push(`consolidate undo ${result.dryRun ? \"(dry run) \" : \"\"}→ ${result.targetPath}`);\n // Emit per-restore details BEFORE the error (PR #637 review, cursor\n // Medium): the \"no sources could be recovered\" error is set after\n // the restore loop ran, so operators need the per-source skip\n // reasons to diagnose which snapshots were missing / outside\n // memoryDir / malformed. Early-bail errors (unloadable target,\n // target outside memoryDir, no derived_from) run before the loop,\n // so `result.restores` is empty in those cases and this block is a\n // no-op.\n for (const r of result.restores) {\n lines.push(` - ${r.entry} → ${r.outcome}${r.detail ? ` (${r.detail})` : \"\"}`);\n }\n if (result.error) {\n lines.push(` ERROR: ${result.error}`);\n return lines.join(\"\\n\");\n }\n lines.push(\n result.dryRun\n ? \" (dry run — no files were modified, target not archived)\"\n : ` target archived: ${result.targetArchived ? \"yes\" : \"no\"}`,\n );\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/consolidation-undo.ts"],"sourcesContent":["/**\n * Consolidation undo (issue #561 PR 5).\n *\n * Reverts a consolidated memory by restoring each source memory from its\n * `derived_from` snapshot and archiving the target.\n *\n * Contract:\n * - Load the target memory markdown file via its absolute path.\n * - For every `\"<rel>:<version>\"` entry in `derived_from`, fetch the\n * snapshot content via `page-versioning.getVersion` and restore it\n * to the original relative path. If the restore target file\n * already exists, we skip overwriting it (the source was never\n * archived, or was re-created since) and record the skip.\n * - Archive the target with reason code `\"consolidation-undo\"` so the\n * lifecycle ledger records the undo.\n * - Dry-run mode produces the same plan without touching disk.\n *\n * The helper is kept pure over `StorageManager` so the CLI can reuse it\n * without additional wiring, and tests can exercise the plan logic\n * directly.\n */\n\nimport path from \"node:path\";\nimport { mkdir, writeFile, access, realpath, lstat } from \"node:fs/promises\";\nimport { constants as fsConstants } from \"node:fs\";\nimport type { StorageManager } from \"./storage.js\";\nimport type { VersioningConfig } from \"./page-versioning.js\";\nimport { getVersion } from \"./page-versioning.js\";\n\n/**\n * Outcome of restoring a single `derived_from` source.\n */\nexport interface ConsolidationUndoRestore {\n /** The raw `\"<relpath>:<version>\"` entry from `derived_from`. */\n entry: string;\n /** Absolute path where the source would be / was restored. */\n sourcePath: string;\n /** What actually happened. */\n outcome:\n | \"restored\"\n | \"skipped_file_exists\"\n | \"skipped_non_regular_file\"\n | \"skipped_snapshot_missing\"\n | \"skipped_malformed_entry\"\n | \"skipped_outside_memory_dir\"\n | \"skipped_non_active_path\"\n | \"skipped_self_referential\"\n | \"skipped_write_failed\"\n | \"skipped_blocked_by_other_failures\"\n | \"skipped_dry_run\";\n /** Human-readable detail. */\n detail?: string;\n}\n\n/**\n * Plan + result of a `remnic consolidate undo` invocation.\n */\nexport interface ConsolidationUndoResult {\n /** Absolute path to the target memory. */\n targetPath: string;\n /** True when the target was archived successfully. */\n targetArchived: boolean;\n /** Per-source restore outcomes. */\n restores: ConsolidationUndoRestore[];\n /** Whether the run was a dry-run plan only. */\n dryRun: boolean;\n /** Fatal error, if any — the run bails early. */\n error?: string;\n}\n\nconst DERIVED_FROM_ENTRY_RE = /^(.+):(\\d+)$/;\n\nfunction parseEntry(entry: unknown): { pagePath: string; versionId: string } | null {\n // Non-string entries (PR #637 round-3 review, cursor Low) can arrive\n // from hostile on-disk frontmatter — guard against a .match() crash.\n if (typeof entry !== \"string\") return null;\n const match = entry.match(DERIVED_FROM_ENTRY_RE);\n if (!match) return null;\n return { pagePath: match[1], versionId: match[2] };\n}\n\n/**\n * Verify that `candidate` resolves inside `root` (defense against\n * path-traversal in `derived_from` entries and user-facing target\n * paths). Path-string normalization only; for symlink-aware checks\n * use `isInsideDirectoryRealpath`. Both paths are resolved to\n * absolute form before comparison so `..` segments, symlinks-as-\n * strings, and relative prefixes are normalized.\n */\nexport function isInsideDirectory(candidate: string, root: string): boolean {\n const normRoot = path.resolve(root);\n const normCandidate = path.resolve(candidate);\n const rel = path.relative(normRoot, normCandidate);\n if (rel.length === 0) return true;\n if (rel.startsWith(\"..\")) return false;\n if (path.isAbsolute(rel)) return false;\n return true;\n}\n\n/**\n * Symlink-aware containment check (PR #637 round-2 review, codex P1).\n *\n * `isInsideDirectory` only normalizes path strings — if a `derived_from`\n * entry resolves through a symlink inside `memoryDir` that points\n * outside, the string check passes but the subsequent `writeFile` would\n * land outside the memory tree. Use this guard for any path that is\n * about to be written.\n *\n * Walks every parent directory between `candidate` and `root`,\n * `realpath`-ing each segment that exists and rejecting when any\n * segment escapes `root`. Non-existent parents are resolved as the\n * canonicalized deepest-existing ancestor plus the trailing segments,\n * so a not-yet-created target file still gets the symlink check on its\n * existing parent directories.\n */\nexport async function isInsideDirectoryRealpath(\n candidate: string,\n root: string,\n): Promise<boolean> {\n if (!isInsideDirectory(candidate, root)) return false;\n // Reject raw `..` segments before canonicalization so that symlinks\n // cannot be hidden behind intermediate dot-dot components (PR #637\n // round-14 review, codex P1).\n const rawSegments = candidate.replace(/\\\\/g, \"/\").split(\"/\");\n if (rawSegments.some((s) => s === \"..\")) return false;\n let resolvedRoot: string;\n try {\n resolvedRoot = await realpath(path.resolve(root));\n } catch {\n return false;\n }\n const normCandidate = path.resolve(candidate);\n\n // Reject dangling symlinks (PR #637 round-3 review, codex P1).\n // If the candidate itself is a symlink (even if its target doesn't\n // exist), Node will follow it when we later call `writeFile`.\n // `lstat` inspects the link itself without dereferencing; if it\n // succeeds and reports a symlink, we treat the candidate as\n // unsafe. We must check every non-root ancestor too — a symlink\n // anywhere along the path lets an attacker redirect writes.\n const normRoot = path.resolve(root);\n const relFromRoot = path.relative(normRoot, normCandidate);\n const segments = relFromRoot.length > 0 ? relFromRoot.split(path.sep) : [];\n for (let i = 0; i <= segments.length; i++) {\n const probe = i === 0 ? normRoot : path.join(normRoot, ...segments.slice(0, i));\n try {\n const st = await lstat(probe);\n if (st.isSymbolicLink() && probe !== normRoot) {\n // A symlink on the path — resolve THIS segment and bail out\n // if the resolved target escapes `resolvedRoot`.\n let target: string;\n try {\n target = await realpath(probe);\n } catch {\n // Dangling symlink inside memoryDir — always unsafe.\n return false;\n }\n const rel = path.relative(resolvedRoot, target);\n if (rel.length === 0) continue;\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) return false;\n }\n } catch {\n // Segment doesn't exist yet — that's fine, fall through to the\n // textual containment verification below.\n }\n }\n\n // Walk up from the candidate until we hit a path that exists, then\n // realpath THAT and re-apply the trailing segments textually.\n const parts = normCandidate.split(path.sep);\n for (let i = parts.length; i > 0; i--) {\n const probe = parts.slice(0, i).join(path.sep) || path.sep;\n try {\n const resolved = await realpath(probe);\n // Re-join any trailing segments that didn't exist yet.\n const trailing = parts.slice(i).join(path.sep);\n const final = trailing.length > 0 ? path.join(resolved, trailing) : resolved;\n // Now apply the textual containment check against the canonical\n // `resolvedRoot`.\n const rel = path.relative(resolvedRoot, final);\n if (rel.length === 0) return true;\n if (rel.startsWith(\"..\")) return false;\n if (path.isAbsolute(rel)) return false;\n return true;\n } catch {\n continue;\n }\n }\n // Nothing along the path resolvable — treat as outside by default.\n return false;\n}\n\n/**\n * Directories under memoryDir that are NOT active memory locations.\n * A `derived_from` entry pointing into one of these should not be\n * counted as \"recovered_existing\" (PR #637 round-7 review, codex P2).\n * The versioning sidecar directory is included dynamically via the\n * `sidecarDir` parameter (PR #637 round-8 review, codex P2).\n */\nconst NON_ACTIVE_PREFIXES = [\"archive/\", \"state/\"];\n\n/**\n * Normalize a relative path by collapsing `.` and `..` segments so\n * that crafted entries like `\"facts/../archive/x.md\"` are reduced to\n * `\"archive/x.md\"` before the non-active-prefix check.\n */\nfunction normalizeRelativePath(p: string): string {\n // Normalize separators, split into segments, then resolve.\n const parts = p.replace(/\\\\/g, \"/\").split(\"/\");\n const resolved: string[] = [];\n for (const seg of parts) {\n if (seg === \"\" || seg === \".\") continue;\n if (seg === \"..\") {\n if (resolved.length > 0) resolved.pop();\n // If \"..\" pops past the root, we let the caller's containment\n // check catch it — don't silently drop.\n } else {\n resolved.push(seg);\n }\n }\n return resolved.join(\"/\");\n}\n\n/**\n * Check that a relative path (relative to memoryDir) points to an\n * active memory location rather than an internal/archive directory.\n * Returns `true` when the normalised `pagePath` does NOT start with\n * a known non-active prefix.\n *\n * @param pagePath Relative path from `derived_from` entry.\n * @param sidecarDir Optional versioning sidecar directory name\n * (e.g. `\".versions\"`). When provided, paths\n * under this directory are also rejected as\n * non-active.\n */\nexport function isActiveMemoryRelativePath(\n pagePath: string,\n sidecarDir?: string,\n): boolean {\n const normalized = normalizeRelativePath(pagePath);\n const prefixes = [...NON_ACTIVE_PREFIXES];\n if (sidecarDir) {\n const normSidecar = normalizeRelativePath(sidecarDir);\n prefixes.push(normSidecar + \"/\");\n }\n for (const prefix of prefixes) {\n if (normalized === prefix.slice(0, -1) || normalized.startsWith(prefix)) {\n return false;\n }\n }\n return true;\n}\n\nasync function isRegularFile(p: string): Promise<boolean> {\n try {\n const st = await lstat(p);\n return st.isFile();\n } catch {\n return false;\n }\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await access(p, fsConstants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Perform a consolidation-undo operation.\n *\n * @param options.storage Storage manager for the memory directory.\n * @param options.memoryDir Absolute memory directory root.\n * @param options.targetPath Absolute path to the consolidated memory.\n * @param options.versioning Page-versioning config (sidecarDir must\n * match the sidecar layout used when the\n * snapshots were created).\n * @param options.dryRun When true, compute the plan but do not\n * write or archive.\n */\nexport async function runConsolidationUndo(options: {\n storage: StorageManager;\n memoryDir: string;\n targetPath: string;\n versioning: VersioningConfig;\n dryRun?: boolean;\n}): Promise<ConsolidationUndoResult> {\n const { storage, memoryDir, targetPath, versioning } = options;\n const dryRun = options.dryRun === true;\n\n const result: ConsolidationUndoResult = {\n targetPath,\n targetArchived: false,\n restores: [],\n dryRun,\n };\n\n // Defense against path-traversal (PR #637 review, codex P1): refuse\n // to operate on a target outside the configured memory directory.\n // Archive moves and eventual unlink would otherwise let an operator\n // accidentally destroy an unrelated file with memory-like\n // frontmatter. Uses the realpath-aware check so a symlinked\n // directory inside `memoryDir` can't tunnel a target past the guard.\n if (!(await isInsideDirectoryRealpath(targetPath, memoryDir))) {\n result.error = `target path ${targetPath} is outside memory directory ${memoryDir}`;\n return result;\n }\n\n // Reject targets in non-active directories (archive/, state/,\n // versioning sidecar). A target inside `.versions/...` would be\n // a sidecar snapshot, not a real consolidated memory; archiving\n // it would silently delete version history (PR #637 round-8\n // review, codex P2).\n const targetRel = path.relative(memoryDir, targetPath);\n if (!isActiveMemoryRelativePath(targetRel, versioning.sidecarDir)) {\n result.error = `target path \"${targetRel}\" is inside a non-active directory — refusing to operate`;\n return result;\n }\n\n // Load the target memory. readMemoryByPath returns null when the file\n // is absent or unparseable — surface that as a fatal error because the\n // caller cannot continue without a derived_from list.\n const target = await storage.readMemoryByPath(targetPath);\n if (!target) {\n result.error = `could not load target memory at ${targetPath}`;\n return result;\n }\n\n const derivedFrom = target.frontmatter.derived_from;\n if (!Array.isArray(derivedFrom) || derivedFrom.length === 0) {\n result.error = \"target memory has no derived_from entries — nothing to undo\";\n return result;\n }\n\n // Two-pass plan + execute (PR #637 round-4 review, cursor Medium):\n // the undo is \"all-or-nothing\" both for the archive decision AND\n // for the per-source writes. First pass validates + loads every\n // snapshot into memory; second pass writes only if every source\n // would succeed. This prevents the previous eager-write behaviour\n // where a later-failing source would leave earlier sources already\n // written to disk alongside an unarchived consolidated target.\n type RestorePlan =\n | { kind: \"skip\"; restore: ConsolidationUndoRestore }\n | { kind: \"write\"; entry: string; sourcePath: string; content: string }\n | { kind: \"recovered_existing\"; entry: string; sourcePath: string };\n\n const plans: RestorePlan[] = [];\n for (const rawEntry of derivedFrom) {\n const entry = typeof rawEntry === \"string\" ? rawEntry : String(rawEntry);\n const parsed = parseEntry(rawEntry);\n if (!parsed) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath: \"\",\n outcome: \"skipped_malformed_entry\",\n detail: `expected \"<path>:<version>\" shape`,\n },\n });\n continue;\n }\n\n // Reject absolute paths in derived_from entries (PR #637 round-10\n // review, codex P1). An absolute pagePath would cause path.join to\n // ignore memoryDir, bypassing the active-directory guard downstream.\n if (path.isAbsolute(parsed.pagePath)) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath: parsed.pagePath,\n outcome: \"skipped_malformed_entry\",\n detail: `derived_from path must be relative, got absolute: \"${parsed.pagePath}\"`,\n },\n });\n continue;\n }\n\n const sourcePath = path.join(memoryDir, parsed.pagePath);\n\n if (!(await isInsideDirectoryRealpath(sourcePath, memoryDir))) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_outside_memory_dir\",\n detail: `resolved path escapes memory directory ${memoryDir}`,\n },\n });\n continue;\n }\n\n // Reject source paths inside non-active directories (archive/,\n // state/, versioning sidecar). A crafted or corrupted derived_from\n // entry like \"archive/2024-01-01/x.md:1\" would otherwise be counted\n // as \"recovered_existing\" even though no active memory was restored.\n // Also resolve symlinks before checking — a derived_from entry like\n // \"facts/link/stale.md:1\" where `facts/link` points to `archive/…`\n // must be caught (PR #637 round-8 review, cursor+codex).\n let resolvedRelative = parsed.pagePath;\n try {\n const realBase = await realpath(memoryDir);\n try {\n const realSource = await realpath(sourcePath);\n const rel = path.relative(realBase, realSource);\n if (!rel.startsWith(\"..\") && !path.isAbsolute(rel)) {\n resolvedRelative = rel.replace(/\\\\/g, \"/\");\n }\n } catch {\n // realpath on the leaf failed (file doesn't exist yet). Try\n // resolving the parent directory instead — if the parent is a\n // symlink into archive/state, the leaf would be written there\n // too (PR #637 round-12 review, codex P1).\n const parentDir = path.dirname(sourcePath);\n try {\n const realParent = await realpath(parentDir);\n const parentRel = path.relative(realBase, realParent);\n if (!parentRel.startsWith(\"..\") && !path.isAbsolute(parentRel)) {\n const leafName = path.basename(sourcePath);\n resolvedRelative = path.join(parentRel, leafName).replace(/\\\\/g, \"/\");\n }\n } catch {\n // Parent also doesn't exist — fall through to text path check\n }\n }\n } catch {\n // memoryDir realpath failed — use the text path\n }\n if (!isActiveMemoryRelativePath(parsed.pagePath, versioning.sidecarDir) ||\n !isActiveMemoryRelativePath(resolvedRelative, versioning.sidecarDir)) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_non_active_path\",\n detail: `source path \"${parsed.pagePath}\" is inside a non-active directory (archive/state/versions)`,\n },\n });\n continue;\n }\n\n // Reject self-referential derived_from entries (PR #637 round-9 review,\n // codex P1). If the source resolves to the same file as the target,\n // counting it as \"recovered\" would let undo archive the target without\n // restoring any independent source — leaving no active copy. This\n // guards against corrupted or manually-edited derived_from lists.\n if (path.resolve(sourcePath) === path.resolve(targetPath)) {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_self_referential\",\n detail: `derived_from entry \"${entry}\" resolves to the same file as the target — refusing to count as recovered`,\n },\n });\n continue;\n }\n\n if (await isRegularFile(sourcePath)) {\n // Source is still active (regular file present) — nothing to\n // restore but this counts as \"recovered\" for the archive\n // decision. We require a regular file specifically (PR #637\n // round-5 review, codex P2): a directory, device node, or\n // symlink at the source path should not count as \"recovered\"\n // because a later read won't find the expected memory content.\n plans.push({ kind: \"recovered_existing\", entry, sourcePath });\n continue;\n }\n if (await fileExists(sourcePath)) {\n // Something other than a regular file is at the source path\n // (directory, device node, symlink). Refuse to overwrite AND\n // refuse to count as recovered (PR #637 round-5 review, codex\n // P2) — the operator needs to clean up manually. This is a\n // blocking skip: no source writes happen, target stays active.\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_non_regular_file\",\n detail: \"source path is occupied by a non-regular-file; refusing to proceed\",\n },\n });\n continue;\n }\n\n let snapshotContent: string;\n try {\n snapshotContent = await getVersion(\n sourcePath,\n parsed.versionId,\n versioning,\n memoryDir,\n );\n } catch {\n plans.push({\n kind: \"skip\",\n restore: {\n entry,\n sourcePath,\n outcome: \"skipped_snapshot_missing\",\n detail: `no snapshot for version ${parsed.versionId}`,\n },\n });\n continue;\n }\n\n plans.push({ kind: \"write\", entry, sourcePath, content: snapshotContent });\n }\n\n // If any plan is a skip (anything other than \"write\" or\n // \"recovered_existing\"), the undo is over before it starts — no\n // writes happen. Reveal every per-source skip reason in the\n // result so operators can diagnose what went wrong.\n const skipped = plans.filter((p) => p.kind === \"skip\");\n if (skipped.length > 0) {\n for (const p of plans) {\n if (p.kind === \"skip\") {\n result.restores.push(p.restore);\n } else if (p.kind === \"write\") {\n // Announced-but-not-executed write — still record it so the\n // operator sees what would have been restored if the failed\n // sources had been recoverable.\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: dryRun ? \"skipped_dry_run\" : \"skipped_blocked_by_other_failures\",\n detail: dryRun\n ? \"would restore from snapshot (blocked by other failures)\"\n : \"snapshot available but undo aborted due to other failures\",\n });\n } else {\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_file_exists\",\n detail: \"source file already exists; no restore needed\",\n });\n }\n }\n const recovered = result.restores.filter(\n (r) => r.outcome === \"restored\" || r.outcome === \"skipped_file_exists\",\n ).length;\n if (recovered === 0) {\n result.error =\n \"no sources could be recovered (all snapshots missing or paths unsafe); target not archived to preserve data\";\n } else {\n result.error = `${skipped.length} of ${plans.length} sources could not be recovered; target not archived (undo is all-or-nothing)`;\n }\n return result;\n }\n\n // Deduplicate plans by sourcePath: duplicate derived_from entries for\n // the same source would cause the second wx-flagged write to fail with\n // EEXIST after the first succeeds. The first plan for each source wins;\n // subsequent duplicates are recorded as skipped. Applied before dry-run\n // so the preview accurately reflects what execution would do.\n const seenSourcePaths = new Set<string>();\n const dedupedPlans: RestorePlan[] = [];\n for (const p of plans) {\n if (p.kind === \"write\" || p.kind === \"recovered_existing\") {\n if (seenSourcePaths.has(p.sourcePath)) {\n dedupedPlans.push({\n kind: \"skip\",\n restore: {\n entry: p.kind === \"write\" ? p.entry : p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_file_exists\",\n detail: \"duplicate derived_from entry — source already processed\",\n },\n });\n continue;\n }\n seenSourcePaths.add(p.sourcePath);\n }\n dedupedPlans.push(p);\n }\n\n // Dry-run: report what each plan would do.\n if (dryRun) {\n for (const p of dedupedPlans) {\n if (p.kind === \"write\") {\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_dry_run\",\n detail: \"would restore from snapshot\",\n });\n } else if (p.kind === \"recovered_existing\") {\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_file_exists\",\n detail: \"source file already exists; no restore needed\",\n });\n } else if (p.kind === \"skip\" && p.restore) {\n result.restores.push(p.restore);\n }\n }\n return result;\n }\n\n // All validations passed — execute writes. A write failure here\n // is a filesystem problem rather than a provenance problem, but\n // any failure still aborts the archive.\n\n let writeFailed = false;\n for (const p of dedupedPlans) {\n if (p.kind === \"skip\") {\n // Dedup-generated skip entries and other pre-write skips.\n if (p.restore) result.restores.push(p.restore);\n continue;\n }\n if (p.kind === \"recovered_existing\") {\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_file_exists\",\n detail: \"source file already exists; no restore needed\",\n });\n continue;\n }\n if (p.kind === \"write\") {\n if (writeFailed) {\n // All-or-nothing: once a write fails, skip all remaining writes\n // so the target is not archived with partial source coverage.\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_blocked_by_other_failures\",\n detail: \"a prior source write failed; skipping remaining writes to honor all-or-nothing contract\",\n });\n continue;\n }\n try {\n await mkdir(path.dirname(p.sourcePath), { recursive: true });\n // Use exclusive create (wx / O_EXCL) so that if another process\n // recreates the source file between planning and execution, this\n // write fails with EEXIST instead of silently overwriting the new\n // file (PR #637 round-11 review, codex P1).\n await writeFile(p.sourcePath, p.content, { encoding: \"utf-8\", flag: \"wx\" });\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"restored\",\n });\n } catch (err) {\n writeFailed = true;\n result.restores.push({\n entry: p.entry,\n sourcePath: p.sourcePath,\n outcome: \"skipped_write_failed\",\n detail: `write failed: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n }\n\n if (writeFailed) {\n result.error =\n \"one or more source writes failed mid-restore; target not archived to preserve data\";\n return result;\n }\n\n // Archive the target memory. archiveMemory returns null on\n // failure — surface that as a fatal error (PR #637 round-5 review,\n // codex P2) so automation doesn't mistake a half-undo for a clean\n // run. The already-completed restores still roll forward; the\n // result.restores list records what was written.\n const archivedAt = await storage.archiveMemory(target, {\n actor: \"consolidate-undo\",\n reasonCode: \"consolidation-undo\",\n });\n result.targetArchived = archivedAt !== null;\n if (!result.targetArchived) {\n result.error =\n \"sources restored successfully but archiving the consolidated target failed; inspect storage for manual cleanup\";\n }\n return result;\n}\n\n/**\n * Render a consolidation-undo result as a human-readable multi-line\n * string for the CLI. Extracted so tests can snapshot the formatting\n * without parsing stdout.\n */\nexport function formatConsolidationUndoResult(result: ConsolidationUndoResult): string {\n const lines: string[] = [];\n lines.push(`consolidate undo ${result.dryRun ? \"(dry run) \" : \"\"}→ ${result.targetPath}`);\n // Emit per-restore details BEFORE the error (PR #637 review, cursor\n // Medium): the \"no sources could be recovered\" error is set after\n // the restore loop ran, so operators need the per-source skip\n // reasons to diagnose which snapshots were missing / outside\n // memoryDir / malformed. Early-bail errors (unloadable target,\n // target outside memoryDir, no derived_from) run before the loop,\n // so `result.restores` is empty in those cases and this block is a\n // no-op.\n for (const r of result.restores) {\n lines.push(` - ${r.entry} → ${r.outcome}${r.detail ? ` (${r.detail})` : \"\"}`);\n }\n if (result.error) {\n lines.push(` ERROR: ${result.error}`);\n return lines.join(\"\\n\");\n }\n lines.push(\n result.dryRun\n ? \" (dry run — no files were modified, target not archived)\"\n : ` target archived: ${result.targetArchived ? \"yes\" : \"no\"}`,\n );\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}