@remnic/core 9.3.621 → 9.3.623

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 (164) hide show
  1. package/dist/access-cli.js +28 -28
  2. package/dist/access-http.js +11 -11
  3. package/dist/access-mcp.js +10 -10
  4. package/dist/access-service.js +9 -9
  5. package/dist/briefing.js +6 -6
  6. package/dist/buffer-surprise.js +3 -3
  7. package/dist/calibration.js +2 -2
  8. package/dist/causal-consolidation.js +10 -10
  9. package/dist/{chunk-GLPBYIXN.js → chunk-2L54V4ZO.js} +3 -3
  10. package/dist/{chunk-PP2JH3GP.js → chunk-2UFQYU5F.js} +2 -2
  11. package/dist/{chunk-XAZOWLW4.js → chunk-3VONWEQB.js} +3 -3
  12. package/dist/{chunk-BF7ZRHH2.js → chunk-66SLUXKM.js} +2 -2
  13. package/dist/{chunk-3HPAPHUK.js → chunk-6KYMPV2O.js} +12 -11
  14. package/dist/chunk-6KYMPV2O.js.map +1 -0
  15. package/dist/{chunk-S53OYO3F.js → chunk-7VFZTJ7K.js} +2 -2
  16. package/dist/{chunk-4RR6ROTB.js → chunk-AGNBY3VG.js} +2 -2
  17. package/dist/{chunk-YEEAADCI.js → chunk-AYHXQR53.js} +2 -2
  18. package/dist/{chunk-IEUU7O4F.js → chunk-BNW5NJJH.js} +2 -2
  19. package/dist/{chunk-6GMPIJAZ.js → chunk-C3IW2F5Z.js} +2 -2
  20. package/dist/{chunk-4EWRLK3C.js → chunk-C4PZTWTG.js} +16 -16
  21. package/dist/{chunk-QVO4YOB7.js → chunk-D2B22JDF.js} +2 -2
  22. package/dist/{chunk-HA5SI4GK.js → chunk-FMGWXIES.js} +4 -4
  23. package/dist/{chunk-B6SU7YSE.js → chunk-GLWW3EJQ.js} +5 -5
  24. package/dist/{chunk-5BTCT236.js → chunk-GYTVOLNX.js} +2 -2
  25. package/dist/{chunk-IMA6GU4Y.js → chunk-H3PHZLMF.js} +3 -3
  26. package/dist/chunk-H3PHZLMF.js.map +1 -0
  27. package/dist/{chunk-TIPYPLLQ.js → chunk-I6UCUHLK.js} +4 -4
  28. package/dist/{chunk-2I2MDQIB.js → chunk-I74SUMNI.js} +2 -2
  29. package/dist/chunk-I74SUMNI.js.map +1 -0
  30. package/dist/{chunk-4H5ZJHEN.js → chunk-J6A3CX5N.js} +8 -3
  31. package/dist/{chunk-4H5ZJHEN.js.map → chunk-J6A3CX5N.js.map} +1 -1
  32. package/dist/{chunk-DEVUWMME.js → chunk-KGIGRNR6.js} +2 -2
  33. package/dist/{chunk-F4QTFIB4.js → chunk-KQFQ3IS5.js} +6 -6
  34. package/dist/{chunk-QSVPYQPG.js → chunk-LDXUBPMO.js} +2 -2
  35. package/dist/chunk-LDXUBPMO.js.map +1 -0
  36. package/dist/{chunk-JFEKNTX7.js → chunk-LN4YGHTM.js} +6 -2
  37. package/dist/chunk-LN4YGHTM.js.map +1 -0
  38. package/dist/{chunk-7XYTQGCC.js → chunk-MAV46GWQ.js} +2 -2
  39. package/dist/{chunk-KILOTVIF.js → chunk-MB5RSUW6.js} +2 -2
  40. package/dist/{chunk-WB3LYXC5.js → chunk-MON3LMO7.js} +3 -3
  41. package/dist/{chunk-APRRL26Q.js → chunk-O4UNM6OR.js} +2 -2
  42. package/dist/{chunk-AZDOWD2L.js → chunk-OZXVGYGZ.js} +2 -2
  43. package/dist/{chunk-WCYKT2DE.js → chunk-P4BC54KI.js} +23 -14
  44. package/dist/chunk-P4BC54KI.js.map +1 -0
  45. package/dist/{chunk-7MLB4NCL.js → chunk-PJGB7XRR.js} +6 -6
  46. package/dist/chunk-PJGB7XRR.js.map +1 -0
  47. package/dist/{chunk-DEPRLVLK.js → chunk-QFQQFX2H.js} +3 -3
  48. package/dist/{chunk-DEPRLVLK.js.map → chunk-QFQQFX2H.js.map} +1 -1
  49. package/dist/{chunk-QPD426WT.js → chunk-R3OQGYOU.js} +2 -2
  50. package/dist/{chunk-UZB5KHKX.js → chunk-RGMVMVMF.js} +2 -2
  51. package/dist/chunk-RGMVMVMF.js.map +1 -0
  52. package/dist/{chunk-O3U5BPUP.js → chunk-RKW6QR7W.js} +23 -19
  53. package/dist/chunk-RKW6QR7W.js.map +1 -0
  54. package/dist/{chunk-C6C7XVKG.js → chunk-UGEBPVNI.js} +3 -3
  55. package/dist/{chunk-4WMCPJWX.js → chunk-UQ7RN5HK.js} +22 -13
  56. package/dist/chunk-UQ7RN5HK.js.map +1 -0
  57. package/dist/{chunk-XQNPGNKK.js → chunk-W3BKVM64.js} +2 -2
  58. package/dist/{chunk-K5O2QY6T.js → chunk-YTWNKQ2G.js} +2 -2
  59. package/dist/chunk-YTWNKQ2G.js.map +1 -0
  60. package/dist/{chunk-2SGJY2UY.js → chunk-Z3CCEP6F.js} +3 -3
  61. package/dist/{chunk-THTIZJZA.js → chunk-ZJSZNTEI.js} +4 -4
  62. package/dist/{chunk-CIOMS6DI.js → chunk-ZZPIJPPD.js} +2 -2
  63. package/dist/chunking.js +1 -1
  64. package/dist/cli.js +23 -23
  65. package/dist/compounding/engine.js +6 -6
  66. package/dist/connectors/codex-materialize-runner.js +7 -7
  67. package/dist/connectors/codex-materialize.js +1 -1
  68. package/dist/connectors/index.js +7 -7
  69. package/dist/contradiction/index.js +2 -2
  70. package/dist/{contradiction-scan-GD7KUFWS.js → contradiction-scan-AZTGFMPY.js} +3 -3
  71. package/dist/entity-retrieval.js +6 -6
  72. package/dist/explicit-capture.js +1 -1
  73. package/dist/extraction-judge.js +3 -3
  74. package/dist/extraction.js +3 -3
  75. package/dist/fallback-llm.js +2 -2
  76. package/dist/identity-continuity.js +1 -1
  77. package/dist/index.js +45 -42
  78. package/dist/index.js.map +1 -1
  79. package/dist/json-extract.js +1 -1
  80. package/dist/lcm/engine.js +3 -3
  81. package/dist/lcm/index.js +3 -3
  82. package/dist/lcm/schema.js +2 -2
  83. package/dist/maintenance/memory-governance.js +6 -6
  84. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +6 -6
  85. package/dist/maintenance/rebuild-memory-projection.js +7 -7
  86. package/dist/memory-projection-store.js +2 -2
  87. package/dist/namespaces/migrate.js +7 -7
  88. package/dist/namespaces/storage.js +6 -6
  89. package/dist/operator-toolkit.js +9 -9
  90. package/dist/orchestrator.js +25 -25
  91. package/dist/peers/index.js +1 -1
  92. package/dist/recall-planner-llm.js +2 -2
  93. package/dist/runtime/better-sqlite.d.ts +2 -1
  94. package/dist/runtime/better-sqlite.js +3 -1
  95. package/dist/schemas.d.ts +22 -22
  96. package/dist/semantic-chunking.js +2 -2
  97. package/dist/semantic-consolidation.js +8 -8
  98. package/dist/semantic-rule-promotion.js +6 -6
  99. package/dist/semantic-rule-verifier.js +6 -6
  100. package/dist/source-attribution.js +1 -1
  101. package/dist/storage.js +5 -5
  102. package/dist/summarizer.js +3 -3
  103. package/dist/temporal-supersession.js +1 -1
  104. package/dist/transfer/export-sqlite.js +2 -2
  105. package/dist/transfer/import-sqlite.js +2 -2
  106. package/dist/transfer/types.d.ts +12 -12
  107. package/dist/verified-recall.js +6 -6
  108. package/package.json +1 -1
  109. package/src/chunking.ts +38 -23
  110. package/src/coding/review-context.ts +7 -1
  111. package/src/connectors/codex-materialize.ts +6 -1
  112. package/src/explicit-capture.ts +7 -2
  113. package/src/identity-continuity.ts +7 -1
  114. package/src/json-extract.ts +4 -1
  115. package/src/orchestrator.ts +5 -1
  116. package/src/peers/profile-reasoner.ts +4 -1
  117. package/src/runtime/better-sqlite.test.ts +29 -0
  118. package/src/runtime/better-sqlite.ts +30 -8
  119. package/src/semantic-chunking.ts +32 -16
  120. package/src/semantic-consolidation.ts +4 -1
  121. package/src/source-attribution.test.ts +21 -0
  122. package/src/source-attribution.ts +17 -2
  123. package/src/storage.ts +11 -2
  124. package/src/temporal-supersession.ts +4 -1
  125. package/dist/chunk-2I2MDQIB.js.map +0 -1
  126. package/dist/chunk-3HPAPHUK.js.map +0 -1
  127. package/dist/chunk-4WMCPJWX.js.map +0 -1
  128. package/dist/chunk-7MLB4NCL.js.map +0 -1
  129. package/dist/chunk-IMA6GU4Y.js.map +0 -1
  130. package/dist/chunk-JFEKNTX7.js.map +0 -1
  131. package/dist/chunk-K5O2QY6T.js.map +0 -1
  132. package/dist/chunk-O3U5BPUP.js.map +0 -1
  133. package/dist/chunk-QSVPYQPG.js.map +0 -1
  134. package/dist/chunk-UZB5KHKX.js.map +0 -1
  135. package/dist/chunk-WCYKT2DE.js.map +0 -1
  136. /package/dist/{chunk-GLPBYIXN.js.map → chunk-2L54V4ZO.js.map} +0 -0
  137. /package/dist/{chunk-PP2JH3GP.js.map → chunk-2UFQYU5F.js.map} +0 -0
  138. /package/dist/{chunk-XAZOWLW4.js.map → chunk-3VONWEQB.js.map} +0 -0
  139. /package/dist/{chunk-BF7ZRHH2.js.map → chunk-66SLUXKM.js.map} +0 -0
  140. /package/dist/{chunk-S53OYO3F.js.map → chunk-7VFZTJ7K.js.map} +0 -0
  141. /package/dist/{chunk-4RR6ROTB.js.map → chunk-AGNBY3VG.js.map} +0 -0
  142. /package/dist/{chunk-YEEAADCI.js.map → chunk-AYHXQR53.js.map} +0 -0
  143. /package/dist/{chunk-IEUU7O4F.js.map → chunk-BNW5NJJH.js.map} +0 -0
  144. /package/dist/{chunk-6GMPIJAZ.js.map → chunk-C3IW2F5Z.js.map} +0 -0
  145. /package/dist/{chunk-4EWRLK3C.js.map → chunk-C4PZTWTG.js.map} +0 -0
  146. /package/dist/{chunk-QVO4YOB7.js.map → chunk-D2B22JDF.js.map} +0 -0
  147. /package/dist/{chunk-HA5SI4GK.js.map → chunk-FMGWXIES.js.map} +0 -0
  148. /package/dist/{chunk-B6SU7YSE.js.map → chunk-GLWW3EJQ.js.map} +0 -0
  149. /package/dist/{chunk-5BTCT236.js.map → chunk-GYTVOLNX.js.map} +0 -0
  150. /package/dist/{chunk-TIPYPLLQ.js.map → chunk-I6UCUHLK.js.map} +0 -0
  151. /package/dist/{chunk-DEVUWMME.js.map → chunk-KGIGRNR6.js.map} +0 -0
  152. /package/dist/{chunk-F4QTFIB4.js.map → chunk-KQFQ3IS5.js.map} +0 -0
  153. /package/dist/{chunk-7XYTQGCC.js.map → chunk-MAV46GWQ.js.map} +0 -0
  154. /package/dist/{chunk-KILOTVIF.js.map → chunk-MB5RSUW6.js.map} +0 -0
  155. /package/dist/{chunk-WB3LYXC5.js.map → chunk-MON3LMO7.js.map} +0 -0
  156. /package/dist/{chunk-APRRL26Q.js.map → chunk-O4UNM6OR.js.map} +0 -0
  157. /package/dist/{chunk-AZDOWD2L.js.map → chunk-OZXVGYGZ.js.map} +0 -0
  158. /package/dist/{chunk-QPD426WT.js.map → chunk-R3OQGYOU.js.map} +0 -0
  159. /package/dist/{chunk-C6C7XVKG.js.map → chunk-UGEBPVNI.js.map} +0 -0
  160. /package/dist/{chunk-XQNPGNKK.js.map → chunk-W3BKVM64.js.map} +0 -0
  161. /package/dist/{chunk-2SGJY2UY.js.map → chunk-Z3CCEP6F.js.map} +0 -0
  162. /package/dist/{chunk-THTIZJZA.js.map → chunk-ZJSZNTEI.js.map} +0 -0
  163. /package/dist/{chunk-CIOMS6DI.js.map → chunk-ZZPIJPPD.js.map} +0 -0
  164. /package/dist/{contradiction-scan-GD7KUFWS.js.map → contradiction-scan-AZTGFMPY.js.map} +0 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/coding/review-context.ts","../src/binary-lifecycle/types.ts","../src/binary-lifecycle/backend.ts","../src/binary-lifecycle/scanner.ts","../src/binary-lifecycle/manifest.ts","../src/binary-lifecycle/pipeline.ts","../src/projection/index.ts","../src/onboarding/index.ts","../src/curation/index.ts","../src/dedup/index.ts","../src/review/index.ts","../src/sync/index.ts","../src/spaces/index.ts","../src/memory-extension/shared-instructions.ts","../src/memory-extension/codex-publisher.ts","../src/memory-extension/claude-code-publisher.ts","../src/memory-extension/hermes-publisher.ts","../src/memory-extension/index.ts","../src/transfer/capsule-fork.ts"],"sourcesContent":["/**\n * Diff-aware review-context packer (issue #569 PR 4).\n *\n * When an agent is asked \"review this PR\" / \"what changed in this diff\" /\n * \"look at this diff\", the prompt that reaches recall is short and generic\n * — the real signal is the diff itself. This module:\n *\n * 1. Detects review-intent prompts via `isReviewPrompt`.\n * 2. Extracts the touched file list from a unified diff via\n * `parseTouchedFiles`.\n * 3. Re-ranks a set of candidate memories so that memories whose\n * `entityRefs` mention a touched path float to the top. The boost is\n * additive and bounded so it doesn't obliterate the original ranking —\n * it's a bias, not a filter.\n *\n * Pure — no orchestrator, no storage. Callers inject the candidate memories\n * they already have from their normal recall pipeline. This keeps the\n * module easy to test and integrates cleanly with the existing tiered-recall\n * code in `orchestrator.ts` (the tier itself can be wired later; the pure\n * surface is what PRs 5/6/7 will call).\n */\n\n// ──────────────────────────────────────────────────────────────────────────\n// Public types\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * A memory candidate as fed into review-context ranking. The shape is a\n * deliberate subset of the core `MemorySummary` / recall result — only the\n * fields we actually need — so this module stays decoupled from the rest of\n * the codebase and can be reused by CLI tools, bench fixtures, etc.\n */\nexport interface ReviewCandidate {\n /** Opaque identifier. Echoed unchanged in the output. */\n id: string;\n /**\n * Pre-review relevance score from the upstream recall pipeline. Higher is\n * better. `0` is treated as \"no prior signal\" and gets the full review\n * boost when a path match is found.\n */\n score: number;\n /**\n * References the memory mentions (file paths, entity names, etc.). Used\n * to decide whether any touched file appears in the memory's scope.\n *\n * Accepts `undefined`/missing so callers can pass sparse records from\n * legacy storage without pre-filling.\n */\n entityRefs?: string[];\n}\n\nexport interface ReviewContext {\n /**\n * Normalized file paths touched by the diff. Each entry is forward-slashed\n * and relative to the repo root when possible.\n */\n touchedFiles: string[];\n /**\n * Candidates re-sorted so memories whose `entityRefs` mention a touched\n * path are boosted. Shape matches the input `ReviewCandidate[]` — the\n * boost is recorded on each entry as `boost` for observability.\n */\n rankedRecall: Array<ReviewCandidate & { boost: number }>;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Review-prompt heuristic\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Keyword list from the #569 design doc, plus obvious paraphrases. All\n * matching is case-insensitive and whole-word (so `reviewer` doesn't trigger\n * on `review` alone).\n */\nconst REVIEW_KEYWORD_PATTERNS: RegExp[] = [\n /\\breview\\b/i,\n /\\bdiff\\b/i,\n /\\bwhat changed\\b/i,\n /\\blook at this pr\\b/i,\n /\\bwhat('?s|\\s+is)\\s+in\\s+this\\s+(pr|patch|diff|change)\\b/i,\n /\\bcode review\\b/i,\n];\n\n/**\n * `true` when the prompt looks like a review / diff-explanation request.\n *\n * Empty / non-string input → `false` (the caller shouldn't branch on an\n * invalid prompt).\n */\nexport function isReviewPrompt(prompt: string | null | undefined): boolean {\n if (typeof prompt !== \"string\") return false;\n const trimmed = prompt.trim();\n if (!trimmed) return false;\n return REVIEW_KEYWORD_PATTERNS.some((re) => re.test(trimmed));\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Unified-diff parser — extract touched files\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Parse a unified diff and return the set of files touched. Accepts both the\n * `diff --git` form (`diff --git a/foo b/bar`) and the `--- / +++` form\n * (`--- a/foo\\n+++ b/bar`). Returns deduplicated, repo-root-relative paths\n * (with the conventional `a/` / `b/` prefixes stripped).\n *\n * Path entries of `/dev/null` (used in adds/deletes) are excluded.\n */\nexport function parseTouchedFiles(diff: string | null | undefined): string[] {\n if (typeof diff !== \"string\" || !diff.trim()) return [];\n const touched = new Set<string>();\n const lines = diff.split(/\\r?\\n/);\n\n for (const line of lines) {\n // `diff --git a/foo/bar.ts b/foo/bar.ts`\n //\n // Paths may be quoted by git when they contain spaces or non-ASCII\n // characters, e.g. `diff --git \"a/src/my file.ts\" \"b/src/my file.ts\"`.\n // The two paths are always separated by whitespace at the top level, but\n // whitespace INSIDE quoted paths must NOT split the tokens. Parse the\n // two paths with an explicit tokenizer instead of a `\\S+`-based regex\n // (which would shatter `\"a/my file.ts\"` into `\"a/my` / `file.ts\"`).\n const gitPrefix = line.match(/^diff --git\\s+/);\n if (gitPrefix) {\n const rest = line.slice(gitPrefix[0].length);\n const paths = splitDiffGitPaths(rest);\n if (paths) {\n for (const raw of paths) {\n const stripped = stripDiffPathPrefix(raw);\n if (stripped && stripped !== \"/dev/null\") touched.add(stripped);\n }\n }\n continue;\n }\n // `--- a/foo/bar.ts` or `+++ b/foo/bar.ts` — or quoted:\n // `--- \"a/foo bar.ts\"` / `+++ \"b/foo bar.ts\"` when git emits C-quoted\n // paths for whitespace or non-ASCII filenames.\n //\n // Matched with an anchored prefix and an explicit tokenizer for the\n // tail so quoted paths containing whitespace are not split on the\n // first internal space. The previous `\\S+` form silently dropped\n // everything after the first whitespace in a quoted path.\n const headerPrefix = line.match(/^(?:---|\\+\\+\\+)[ \\t]+/);\n if (headerPrefix) {\n const tail = line.slice(headerPrefix[0].length).replace(/[ \\t]+$/, \"\");\n const raw = extractSingleDiffPathToken(tail);\n if (raw) {\n const stripped = stripDiffPathPrefix(raw);\n if (stripped && stripped !== \"/dev/null\") touched.add(stripped);\n }\n }\n }\n\n return Array.from(touched).sort();\n}\n\n/**\n * Extract the single path token from the tail of a `---` / `+++` header\n * line. Returns `null` when the tail is empty or malformed (e.g. an\n * unterminated quoted path). The whole tail is consumed — trailing\n * timestamps from non-git diff frontends (`--- a/foo\t2023-01-01`) fall\n * into a leading-token extraction like the quoted-form case.\n */\nfunction extractSingleDiffPathToken(tail: string): string | null {\n if (tail.length === 0) return null;\n if (tail[0] === '\"') {\n let j = 1;\n while (j < tail.length) {\n if (tail[j] === \"\\\\\" && j + 1 < tail.length) {\n j += 2;\n continue;\n }\n if (tail[j] === '\"') break;\n j += 1;\n }\n if (j >= tail.length) return null; // unterminated quoted path\n return tail.slice(0, j + 1);\n }\n // Unquoted: consume up to the first tab or whitespace-run, so standard\n // `--- a/foo\t<timestamp>` lines surface just `a/foo`. For ordinary\n // git-style output the tail has no whitespace at all.\n let j = 0;\n while (j < tail.length && tail[j] !== \" \" && tail[j] !== \"\\t\") j += 1;\n return tail.slice(0, j);\n}\n\n/**\n * Split the `a-path b-path` portion of a `diff --git` line into exactly two\n * path tokens, respecting git's quoting convention. Returns `null` when the\n * input cannot be parsed into exactly two tokens.\n */\nfunction splitDiffGitPaths(rest: string): [string, string] | null {\n const tokens: string[] = [];\n let i = 0;\n while (i < rest.length && tokens.length < 2) {\n // Skip leading whitespace between tokens.\n while (i < rest.length && (rest[i] === \" \" || rest[i] === \"\\t\")) i += 1;\n if (i >= rest.length) break;\n if (rest[i] === '\"') {\n // Quoted path: consume up to the matching unescaped `\"`. Git escapes\n // inner quotes as `\\\"`, so we respect backslash escaping.\n let j = i + 1;\n while (j < rest.length) {\n if (rest[j] === \"\\\\\" && j + 1 < rest.length) {\n j += 2;\n continue;\n }\n if (rest[j] === '\"') break;\n j += 1;\n }\n if (j >= rest.length) return null; // unterminated quoted path\n tokens.push(rest.slice(i, j + 1));\n i = j + 1;\n } else {\n // Unquoted path: run of non-whitespace.\n let j = i;\n while (j < rest.length && rest[j] !== \" \" && rest[j] !== \"\\t\") j += 1;\n tokens.push(rest.slice(i, j));\n i = j;\n }\n }\n if (tokens.length !== 2) return null;\n return [tokens[0]!, tokens[1]!];\n}\n\nfunction stripDiffPathPrefix(raw: string): string {\n // Git conventionally prefixes paths with `a/` or `b/` in diffs, and\n // quotes the whole path (including the prefix) when it contains spaces or\n // non-ASCII bytes. Quote-stripping must therefore happen BEFORE the\n // prefix check — otherwise `\"a/path with spaces.ts\"` still starts with\n // `\"a` and the prefix is never recognized.\n let s = raw;\n if (s.length >= 2 && s[0] === '\"' && s[s.length - 1] === '\"') {\n const decoded = decodeGitCQuotedPath(s.slice(1, -1));\n if (decoded === null) {\n return raw;\n }\n s = decoded;\n }\n // Normalize Windows-style backslashes. Must happen AFTER quote stripping\n // so that C-quote escape pairs are decoded before path separators are\n // normalized.\n s = s.replace(/\\\\/g, \"/\");\n if (s.startsWith(\"a/\") || s.startsWith(\"b/\")) s = s.slice(2);\n return s;\n}\n\nfunction decodeGitCQuotedPath(value: string): string | null {\n const bytes: number[] = [];\n const encoder = new TextEncoder();\n const appendText = (text: string) => {\n bytes.push(...encoder.encode(text));\n };\n\n for (let index = 0; index < value.length; index += 1) {\n const char = value[index]!;\n if (char !== \"\\\\\") {\n appendText(char);\n continue;\n }\n\n if (index + 1 >= value.length) {\n appendText(\"\\\\\");\n continue;\n }\n\n const next = value[index + 1]!;\n if (next >= \"0\" && next <= \"7\") {\n let octal = next;\n let cursor = index + 2;\n while (cursor < value.length && octal.length < 3) {\n const digit = value[cursor]!;\n if (digit < \"0\" || digit > \"7\") break;\n octal += digit;\n cursor += 1;\n }\n bytes.push(Number.parseInt(octal, 8));\n index = cursor - 1;\n continue;\n }\n\n const escaped = cEscapeValue(next);\n if (escaped !== null) {\n appendText(escaped);\n index += 1;\n continue;\n }\n\n appendText(`\\\\${next}`);\n index += 1;\n }\n\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(Uint8Array.from(bytes));\n } catch {\n return null;\n }\n}\n\nfunction cEscapeValue(value: string): string | null {\n switch (value) {\n case \"n\":\n return \"\\n\";\n case \"t\":\n return \"\\t\";\n case \"r\":\n return \"\\r\";\n case \"b\":\n return \"\\b\";\n case \"f\":\n return \"\\f\";\n case \"\\\\\":\n case '\"':\n return value;\n default:\n return null;\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Ranking\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Additive boost per matching touched-file. Tuned so that a single exact\n * match is enough to float a `score=0` candidate above a `score=0.4`\n * unmatched peer, but not so large it buries multi-signal results. `0.5`\n * per match, capped at `1.0` so three matches don't eclipse strong recall.\n */\nconst BOOST_PER_MATCH = 0.5;\nconst MAX_BOOST = 1.0;\n\n/**\n * Count how many touched files appear in a memory's entityRefs. Matches are\n * literal substring matches on either direction — either the ref contains\n * the path, or the path contains the ref — so both\n * - `\"src/foo.ts\"` refs matching a touched `\"src/foo.ts\"`, and\n * - `\"foo.ts\"` refs matching a touched `\"src/foo.ts\"`\n * succeed.\n */\nfunction countPathHits(entityRefs: string[] | undefined, touchedFiles: string[]): number {\n if (!entityRefs || entityRefs.length === 0) return 0;\n if (touchedFiles.length === 0) return 0;\n let hits = 0;\n for (const ref of entityRefs) {\n if (typeof ref !== \"string\" || !ref) continue;\n const lowered = ref.toLowerCase();\n for (const file of touchedFiles) {\n const flower = file.toLowerCase();\n if (lowered === flower) {\n hits += 1;\n break;\n }\n if (lowered.includes(flower) || flower.includes(lowered)) {\n hits += 1;\n break;\n }\n }\n }\n return hits;\n}\n\n/**\n * Build a review-context ranking for a set of candidate memories.\n *\n * Contract:\n * - `touchedFiles` is the parsed diff file list.\n * - `candidates` is passed through unchanged when no boost applies.\n * - When a boost applies, the result is sorted by `(score + boost)` desc,\n * with a stable secondary sort on the original `id` for determinism\n * (CLAUDE.md #19 — comparators must return 0 for equal items).\n */\nexport function rankReviewCandidates(\n candidates: ReviewCandidate[],\n touchedFiles: string[],\n): Array<ReviewCandidate & { boost: number }> {\n const annotated: Array<ReviewCandidate & { boost: number }> = candidates.map((c) => {\n const hits = countPathHits(c.entityRefs, touchedFiles);\n const boost = Math.min(MAX_BOOST, hits * BOOST_PER_MATCH);\n return { ...c, boost };\n });\n\n annotated.sort((a, b) => {\n const adjA = a.score + a.boost;\n const adjB = b.score + b.boost;\n if (adjA !== adjB) return adjB - adjA;\n // Stable secondary sort for deterministic ordering on ties.\n if (a.id < b.id) return -1;\n if (a.id > b.id) return 1;\n return 0;\n });\n\n return annotated;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Packer entry point\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface PackReviewContextInput {\n /** Unified diff, as produced by `git diff`. */\n diff: string | null | undefined;\n /** Candidate memories from the upstream recall pipeline. */\n candidates: ReviewCandidate[];\n}\n\n/**\n * Top-level entry point used by the orchestrator (and CLI / bench) when a\n * review-intent prompt is detected.\n *\n * Parses the diff, re-ranks the candidates, and returns both artefacts so\n * the caller can surface `touchedFiles` as context and `rankedRecall` as\n * the recall result.\n */\nexport function packReviewContext(input: PackReviewContextInput): ReviewContext {\n const touchedFiles = parseTouchedFiles(input.diff);\n const rankedRecall = rankReviewCandidates(input.candidates, touchedFiles);\n return { touchedFiles, rankedRecall };\n}\n","/**\n * Binary file lifecycle management types.\n *\n * Defines the configuration, manifest, and record structures for the\n * three-stage binary lifecycle pipeline: mirror, redirect, clean.\n */\n\nexport interface BinaryLifecycleConfig {\n /** Master toggle. Default: false. */\n enabled: boolean;\n /** Days after mirror before local copy is eligible for cleanup. Default: 7. */\n gracePeriodDays: number;\n /** Files larger than this are skipped during scan. Default: 50 MB. */\n maxBinarySizeBytes: number;\n /** Glob patterns for binary file types to manage. */\n scanPatterns: string[];\n /** Backend configuration for binary storage. */\n backend: BinaryStorageBackendConfig;\n}\n\nexport interface BinaryStorageBackendConfig {\n /** Backend type. \"filesystem\" copies to a local directory. \"none\" is a no-op (dry-run/testing). */\n type: \"filesystem\" | \"s3\" | \"none\";\n /** Destination directory for the filesystem backend. */\n basePath?: string;\n /** S3 bucket name (future). */\n s3Bucket?: string;\n /** S3 region (future). */\n s3Region?: string;\n /** S3 key prefix (future). */\n s3Prefix?: string;\n}\n\nexport type BinaryAssetStatus =\n | \"pending\"\n | \"mirrored\"\n | \"redirected\"\n | \"cleaned\"\n | \"error\";\n\nexport interface BinaryAssetRecord {\n /** Relative path from memoryDir to the original file. */\n originalPath: string;\n /** Path (or URL) in the backend storage. */\n mirroredPath: string;\n /** Optional user-resolvable target to write into markdown links. */\n redirectPath?: string;\n /** SHA-256 hex digest of file content. */\n contentHash: string;\n /** File size in bytes. */\n sizeBytes: number;\n /** MIME type (e.g. \"image/png\"). */\n mimeType: string;\n /** ISO 8601 timestamp when the file was mirrored. */\n mirroredAt: string;\n /** ISO 8601 timestamp when markdown references were rewritten. */\n redirectedAt?: string;\n /** ISO 8601 timestamp when the local copy was deleted. */\n cleanedAt?: string;\n /** Current lifecycle status. */\n status: BinaryAssetStatus;\n}\n\nexport interface BinaryLifecycleManifest {\n version: 1;\n assets: BinaryAssetRecord[];\n lastScanAt?: string;\n}\n\nexport interface PipelineResult {\n scanned: number;\n mirrored: number;\n redirected: number;\n cleaned: number;\n errors: string[];\n dryRun: boolean;\n}\n\nexport const DEFAULT_SCAN_PATTERNS = [\n \"*.png\",\n \"*.jpg\",\n \"*.jpeg\",\n \"*.gif\",\n \"*.pdf\",\n \"*.mp3\",\n \"*.mp4\",\n \"*.wav\",\n];\n\nexport const DEFAULT_MAX_BINARY_SIZE_BYTES = 50 * 1024 * 1024; // 50 MB\nexport const DEFAULT_GRACE_PERIOD_DAYS = 7;\n","/**\n * Binary storage backend interface and implementations.\n *\n * Backends handle the actual persistence of binary files to an external\n * location. The pipeline calls upload/exists/delete through this interface\n * so swapping storage providers requires no pipeline changes.\n */\n\nimport type { Stats } from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { BinaryStorageBackendConfig } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Interface\n// ---------------------------------------------------------------------------\n\nexport interface BinaryStorageBackend {\n /** Discriminator for the backend type. */\n readonly type: string;\n /**\n * Upload a local file to the backend.\n * @returns The backend path or URL where the file was stored.\n */\n upload(localPath: string, remotePath: string): Promise<string>;\n /** Check whether a remote path already exists in the backend. */\n exists(remotePath: string): Promise<boolean>;\n /** Delete a file from the backend. */\n delete(remotePath: string): Promise<void>;\n /** Return the user-resolvable markdown target for a stored backend path. */\n getRedirectTarget?(remotePath: string): string;\n}\n\n// ---------------------------------------------------------------------------\n// Filesystem backend\n// ---------------------------------------------------------------------------\n\nexport class FilesystemBackend implements BinaryStorageBackend {\n readonly type = \"filesystem\";\n private readonly basePath: string;\n\n constructor(basePath: string) {\n if (!basePath || basePath.trim().length === 0) {\n throw new Error(\"FilesystemBackend requires a non-empty basePath\");\n }\n this.basePath = path.resolve(basePath);\n }\n\n private resolveRemotePath(remotePath: string): string {\n const resolved = path.isAbsolute(remotePath)\n ? path.resolve(remotePath)\n : path.resolve(this.basePath, remotePath);\n const relative = path.relative(this.basePath, resolved);\n if (relative === \"..\" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {\n throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);\n }\n return resolved;\n }\n\n private isInsideBase(candidate: string, realBase: string): boolean {\n const relative = path.relative(realBase, candidate);\n return relative === \"\" || (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));\n }\n\n private async realBasePathIfExists(): Promise<string | null> {\n try {\n const stat = await fsp.lstat(this.basePath);\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend basePath must not be a symlink: ${this.basePath}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`FilesystemBackend basePath must be a directory: ${this.basePath}`);\n }\n return await fsp.realpath(this.basePath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw err;\n }\n }\n\n private async ensureBaseDirectory(): Promise<string> {\n await fsp.mkdir(this.basePath, { recursive: true });\n const realBase = await this.realBasePathIfExists();\n if (realBase === null) {\n throw new Error(`FilesystemBackend failed to create basePath: ${this.basePath}`);\n }\n return realBase;\n }\n\n private async ensureSafeParentDirectory(dest: string): Promise<string> {\n const realBase = await this.ensureBaseDirectory();\n const destDir = path.dirname(dest);\n const relativeDir = path.relative(this.basePath, destDir);\n const segments = relativeDir === \"\" ? [] : relativeDir.split(path.sep);\n let current = this.basePath;\n\n for (const segment of segments) {\n if (segment === \".\" || segment === \"\") continue;\n current = path.join(current, segment);\n try {\n const stat = await fsp.lstat(current);\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend remotePath traverses symlink: ${current}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`FilesystemBackend remotePath parent is not a directory: ${current}`);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n await fsp.mkdir(current);\n }\n }\n\n const realParent = await fsp.realpath(destDir);\n if (!this.isInsideBase(realParent, realBase)) {\n throw new Error(`FilesystemBackend remotePath parent escapes basePath: ${dest}`);\n }\n return realBase;\n }\n\n private async resolveExistingRemotePath(remotePath: string): Promise<string | null> {\n const dest = this.resolveRemotePath(remotePath);\n const realBase = await this.realBasePathIfExists();\n if (realBase === null) {\n return null;\n }\n\n const destDir = path.dirname(dest);\n const relativeDir = path.relative(this.basePath, destDir);\n const segments = relativeDir === \"\" ? [] : relativeDir.split(path.sep);\n let current = this.basePath;\n for (const segment of segments) {\n if (segment === \".\" || segment === \"\") continue;\n current = path.join(current, segment);\n let stat: Stats;\n try {\n stat = await fsp.lstat(current);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw err;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend remotePath traverses symlink: ${current}`);\n }\n if (!stat.isDirectory()) {\n return null;\n }\n }\n\n const realParent = await fsp.realpath(destDir).catch((err: NodeJS.ErrnoException) => {\n if (err.code === \"ENOENT\") return null;\n throw err;\n });\n if (realParent === null) {\n return null;\n }\n if (!this.isInsideBase(realParent, realBase)) {\n throw new Error(`FilesystemBackend remotePath parent escapes basePath: ${JSON.stringify(remotePath)}`);\n }\n\n try {\n const stat = await fsp.lstat(dest);\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);\n }\n if (!stat.isFile()) {\n return null;\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw err;\n }\n\n const realDest = await fsp.realpath(dest);\n if (!this.isInsideBase(realDest, realBase)) {\n throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);\n }\n return dest;\n }\n\n async upload(localPath: string, remotePath: string): Promise<string> {\n if (path.isAbsolute(remotePath)) {\n throw new Error(`FilesystemBackend upload remotePath must be relative: ${JSON.stringify(remotePath)}`);\n }\n const dest = this.resolveRemotePath(remotePath);\n const realBase = await this.ensureSafeParentDirectory(dest);\n try {\n const stat = await fsp.lstat(dest);\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n }\n await fsp.copyFile(localPath, dest);\n const realDest = await fsp.realpath(dest);\n if (!this.isInsideBase(realDest, realBase)) {\n throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);\n }\n return remotePath;\n }\n\n async exists(remotePath: string): Promise<boolean> {\n const dest = await this.resolveExistingRemotePath(remotePath);\n return dest !== null;\n }\n\n async delete(remotePath: string): Promise<void> {\n const dest = await this.resolveExistingRemotePath(remotePath);\n if (dest === null) {\n return;\n }\n try {\n await fsp.unlink(dest);\n } catch (err: unknown) {\n // Ignore ENOENT (already deleted); rethrow everything else.\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n }\n\n getRedirectTarget(remotePath: string): string {\n return this.resolveRemotePath(remotePath);\n }\n}\n\n// ---------------------------------------------------------------------------\n// None backend (no-op, for dry-run / testing)\n// ---------------------------------------------------------------------------\n\nexport class NoneBackend implements BinaryStorageBackend {\n readonly type = \"none\";\n\n async upload(_localPath: string, remotePath: string): Promise<string> {\n return remotePath;\n }\n\n async exists(_remotePath: string): Promise<boolean> {\n return false;\n }\n\n async delete(_remotePath: string): Promise<void> {\n // intentional no-op\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createBackend(cfg: BinaryStorageBackendConfig): BinaryStorageBackend {\n switch (cfg.type) {\n case \"filesystem\": {\n if (!cfg.basePath) {\n throw new Error(\n \"BinaryStorageBackendConfig.basePath is required when type is \\\"filesystem\\\"\",\n );\n }\n return new FilesystemBackend(cfg.basePath);\n }\n case \"s3\":\n throw new Error(\"S3 binary storage backend is not yet implemented\");\n case \"none\":\n return new NoneBackend();\n default:\n throw new Error(`Unknown binary storage backend type: ${String((cfg as { type: string }).type)}`);\n }\n}\n","/**\n * Binary file scanner.\n *\n * Recursively walks the memory directory, matches files against configured\n * glob patterns, skips files already tracked in the manifest, and respects\n * the max-size limit.\n */\n\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport type { BinaryLifecycleConfig, BinaryLifecycleManifest } from \"./types.js\";\n\n/**\n * Test whether a filename matches any of the provided glob patterns.\n * Supports simple `*.ext` patterns (the default scan patterns).\n * For more complex globs a proper library should be used; this covers\n * the 95% case without adding a dependency.\n */\nexport function matchesPatterns(filename: string, patterns: string[]): boolean {\n const lower = filename.toLowerCase();\n for (const pattern of patterns) {\n // Simple *.ext matching\n if (pattern.startsWith(\"*.\")) {\n const ext = pattern.slice(1).toLowerCase(); // e.g. \".png\"\n if (lower.endsWith(ext)) return true;\n } else if (lower === pattern.toLowerCase()) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Scan memoryDir recursively for binary files matching the configured patterns.\n * Returns relative paths (relative to memoryDir) for files not yet tracked.\n */\nexport async function scanForBinaries(\n memoryDir: string,\n config: BinaryLifecycleConfig,\n manifest: BinaryLifecycleManifest,\n): Promise<string[]> {\n const tracked = new Map(manifest.assets.map((a) => [a.originalPath, a]));\n const results: string[] = [];\n\n async function walk(dir: string): Promise<void> {\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fsp.readdir(dir, { withFileTypes: true });\n } catch {\n return; // skip unreadable directories\n }\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n // Normalize to POSIX separators so redirect matching works on Windows\n // (markdown links always use forward slashes).\n const relativePath = path.relative(memoryDir, fullPath).split(path.sep).join(\"/\");\n\n if (entry.isDirectory()) {\n // Skip the manifest directory itself and hidden dirs starting with .\n if (entry.name === \".binary-lifecycle\") continue;\n await walk(fullPath);\n continue;\n }\n\n if (!entry.isFile()) continue;\n\n // Check pattern match\n if (!matchesPatterns(entry.name, config.scanPatterns)) continue;\n\n // Check file size\n try {\n const stat = await fsp.stat(fullPath);\n if (stat.size > config.maxBinarySizeBytes) continue;\n if (stat.size === 0) continue; // skip empty files\n const existing = tracked.get(relativePath);\n if (existing) {\n if (existing.sizeBytes !== stat.size) {\n results.push(relativePath);\n continue;\n }\n const contentHash = await hashFile(fullPath);\n if (existing.contentHash !== contentHash) {\n results.push(relativePath);\n }\n continue;\n }\n } catch {\n continue; // stat failure, skip\n }\n\n results.push(relativePath);\n }\n }\n\n await walk(memoryDir);\n return results;\n}\n\nasync function hashFile(filePath: string): Promise<string> {\n const content = await fsp.readFile(filePath);\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n","/**\n * Binary lifecycle manifest — read/write operations.\n *\n * The manifest lives at `${memoryDir}/.binary-lifecycle/manifest.json`.\n * Writes use the atomic temp-then-rename pattern (CLAUDE.md #54).\n */\n\nimport fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport type { BinaryLifecycleManifest } from \"./types.js\";\n\nconst MANIFEST_DIR = \".binary-lifecycle\";\nconst MANIFEST_FILE = \"manifest.json\";\n\nexport function manifestDir(memoryDir: string): string {\n return path.join(memoryDir, MANIFEST_DIR);\n}\n\nexport function manifestPath(memoryDir: string): string {\n return path.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);\n}\n\n/**\n * Read the manifest from disk. Returns a fresh empty manifest if the file\n * does not exist. Existing invalid manifests fail closed so the pipeline does\n * not overwrite state needed for safe cleanup.\n */\nexport async function readManifest(memoryDir: string): Promise<BinaryLifecycleManifest> {\n const filePath = manifestPath(memoryDir);\n let raw: string;\n try {\n raw = await fsp.readFile(filePath, \"utf-8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return emptyManifest();\n }\n throw new Error(`Failed to read binary lifecycle manifest at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(`Invalid binary lifecycle manifest JSON at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // CLAUDE.md #18: validate the parsed result is a non-null object.\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Invalid binary lifecycle manifest shape at ${filePath}: expected object`);\n }\n const obj = parsed as Record<string, unknown>;\n if (obj.version !== 1 || !Array.isArray(obj.assets)) {\n throw new Error(`Invalid binary lifecycle manifest shape at ${filePath}: expected version 1 with assets array`);\n }\n return parsed as BinaryLifecycleManifest;\n}\n\n/**\n * Write the manifest atomically: write to a temp file, then rename.\n * CLAUDE.md #54: never delete before write. Write temp first, rename atomically.\n */\nexport async function writeManifest(\n memoryDir: string,\n manifest: BinaryLifecycleManifest,\n): Promise<void> {\n const dir = manifestDir(memoryDir);\n await fsp.mkdir(dir, { recursive: true });\n const dest = manifestPath(memoryDir);\n const tmpSuffix = crypto.randomBytes(8).toString(\"hex\");\n const tmpPath = `${dest}.${tmpSuffix}.tmp`;\n // Sort keys for deterministic output (CLAUDE.md #38).\n const content = JSON.stringify(manifest, null, 2) + \"\\n\";\n await fsp.writeFile(tmpPath, content, \"utf-8\");\n try {\n await fsp.rename(tmpPath, dest);\n } catch (renameErr) {\n // Clean up temp on rename failure (cross-device edge case).\n try {\n await fsp.unlink(tmpPath);\n } catch {\n // ignore cleanup failure\n }\n throw renameErr;\n }\n}\n\nexport function emptyManifest(): BinaryLifecycleManifest {\n return { version: 1, assets: [] };\n}\n","/**\n * Binary lifecycle pipeline — mirror, redirect, clean.\n *\n * Three-stage pipeline:\n * 1. Mirror: upload binary to backend, record in manifest\n * 2. Redirect: scan markdown for inline refs, replace with redirect path\n * 3. Clean: after grace period, delete local copy\n */\n\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport type {\n BinaryAssetRecord,\n BinaryLifecycleConfig,\n PipelineResult,\n} from \"./types.js\";\nimport type { BinaryStorageBackend } from \"./backend.js\";\nimport { readManifest, writeManifest } from \"./manifest.js\";\nimport { scanForBinaries } from \"./scanner.js\";\n\n/** Minimal logger interface so we don't depend on the full logger module. */\ninterface PipelineLogger {\n info(msg: string): void;\n warn(msg: string): void;\n error(msg: string): void;\n}\n\ntype ReadMarkdownFile = (filePath: string) => Promise<string>;\ntype WriteMarkdownFile = (filePath: string, content: string) => Promise<void>;\n\ninterface PipelineOptions {\n dryRun?: boolean;\n /** Force-clean all files past grace period, ignoring redirect status. */\n forceClean?: boolean;\n /** Test hook for deterministic markdown read failures. */\n readMarkdownFile?: ReadMarkdownFile;\n /** Test hook for deterministic markdown write failures. */\n writeMarkdownFile?: WriteMarkdownFile;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nasync function hashFile(filePath: string): Promise<string> {\n const content = await fsp.readFile(filePath);\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nfunction guessMimeType(ext: string): string {\n const map: Record<string, string> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".pdf\": \"application/pdf\",\n \".mp3\": \"audio/mpeg\",\n \".mp4\": \"video/mp4\",\n \".wav\": \"audio/wav\",\n };\n return map[ext.toLowerCase()] ?? \"application/octet-stream\";\n}\n\n/**\n * Escape special regex characters in a string.\n * CLAUDE.md #46: always escapeRegex on user-derived parts.\n */\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction resolveManifestAssetPath(memoryDir: string, originalPath: string): string | null {\n if (\n originalPath.length === 0 ||\n originalPath.includes(\"\\0\") ||\n originalPath.includes(\"\\\\\") ||\n path.isAbsolute(originalPath) ||\n path.win32.isAbsolute(originalPath)\n ) {\n return null;\n }\n\n const memoryRoot = path.resolve(memoryDir);\n const fullPath = path.resolve(memoryRoot, originalPath);\n const relative = path.relative(memoryRoot, fullPath);\n if (relative === \"\" || relative === \"..\" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {\n return null;\n }\n\n return fullPath;\n}\n\nfunction validateBinaryLifecycleConfig(config: BinaryLifecycleConfig): void {\n if (\n typeof config.gracePeriodDays !== \"number\" ||\n !Number.isFinite(config.gracePeriodDays) ||\n !Number.isInteger(config.gracePeriodDays) ||\n config.gracePeriodDays < 0\n ) {\n throw new Error(\"binary lifecycle gracePeriodDays must be a finite non-negative integer\");\n }\n}\n\nfunction remotePathForAsset(backend: BinaryStorageBackend, relPath: string): string {\n const normalized = relPath.split(path.sep).join(\"/\");\n if (backend.type === \"filesystem\") {\n return `.binary-lifecycle/mirrors/${normalized}`;\n }\n return normalized;\n}\n\nfunction markdownTargetForAsset(asset: BinaryAssetRecord): string {\n return asset.redirectPath ?? asset.mirroredPath;\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline stages\n// ---------------------------------------------------------------------------\n\nasync function stageMirror(\n memoryDir: string,\n newPaths: string[],\n backend: BinaryStorageBackend,\n assets: BinaryAssetRecord[],\n log: PipelineLogger,\n dryRun: boolean,\n): Promise<{ mirrored: number; errors: string[] }> {\n let mirrored = 0;\n const errors: string[] = [];\n\n for (const relPath of newPaths) {\n const fullPath = path.join(memoryDir, relPath);\n try {\n const stat = await fsp.stat(fullPath);\n const contentHash = await hashFile(fullPath);\n const ext = path.extname(relPath);\n const mimeType = guessMimeType(ext);\n const remotePath = remotePathForAsset(backend, relPath);\n\n let backendLocation = remotePath;\n if (!dryRun) {\n backendLocation = await backend.upload(fullPath, remotePath);\n }\n const redirectPath = backend.getRedirectTarget?.(backendLocation);\n\n const record: BinaryAssetRecord = {\n originalPath: relPath,\n mirroredPath: backendLocation,\n ...(redirectPath ? { redirectPath } : {}),\n contentHash,\n sizeBytes: stat.size,\n mimeType,\n mirroredAt: new Date().toISOString(),\n status: \"mirrored\",\n };\n\n if (!dryRun) {\n const existingIndex = assets.findIndex((asset) => asset.originalPath === relPath);\n if (existingIndex >= 0) {\n assets.splice(existingIndex, 1);\n }\n assets.push(record);\n }\n mirrored++;\n log.info(`[binary-lifecycle] mirrored: ${relPath} (${stat.size} bytes)${dryRun ? \" [dry-run]\" : \"\"}`);\n } catch (err) {\n const msg = `mirror failed for ${relPath}: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n }\n\n return { mirrored, errors };\n}\n\nasync function stageRedirect(\n memoryDir: string,\n assets: BinaryAssetRecord[],\n log: PipelineLogger,\n dryRun: boolean,\n readMarkdownFile: ReadMarkdownFile,\n writeMarkdownFile: WriteMarkdownFile,\n): Promise<{ redirected: number; errors: string[] }> {\n let redirected = 0;\n const errors: string[] = [];\n\n // Redirect mirrored assets and retry prior redirect errors. Clean-stage errors\n // remain safe because the redirect path validation below will keep rejecting\n // invalid manifest records.\n const candidates = assets.filter((a) => a.status === \"mirrored\" || a.status === \"error\");\n if (candidates.length === 0) return { redirected, errors };\n\n // Find all markdown files in memoryDir (recursive).\n const mdFiles = await findMarkdownFiles(memoryDir);\n\n for (const asset of candidates) {\n const assetAbsolute = resolveManifestAssetPath(memoryDir, asset.originalPath);\n if (assetAbsolute === null) {\n const msg = `redirect blocked for ${asset.originalPath}: manifest path is outside memoryDir`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n if (!dryRun) {\n asset.status = \"error\";\n }\n continue;\n }\n\n const updates: Array<{ mdPath: string; content: string }> = [];\n let scanFailCount = 0;\n for (const mdPath of mdFiles) {\n try {\n const content = await readMarkdownFile(mdPath);\n\n const pattern = markdownReferencePattern(asset, assetAbsolute, mdPath);\n\n if (!pattern.test(content)) continue;\n\n // Reset lastIndex after test().\n pattern.lastIndex = 0;\n const updated = content.replace(pattern, (_match, open, _target, close) => {\n return `${open as string}${markdownTargetForAsset(asset)}${close as string}`;\n });\n updates.push({ mdPath, content: updated });\n } catch (err) {\n scanFailCount++;\n const msg = `redirect scan failed for ${mdPath}: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n }\n\n if (scanFailCount > 0) {\n if (!dryRun) {\n asset.status = \"error\";\n }\n log.warn(\n `[binary-lifecycle] redirect blocked for ${asset.originalPath}: ` +\n `${scanFailCount} markdown scan failure(s)` +\n `${dryRun ? \"\" : \" — status set to error\"}`,\n );\n continue;\n }\n\n if (updates.length === 0) {\n if (asset.status === \"error\") {\n const verifyResult = await countRemainingLocalReferences(\n memoryDir,\n asset,\n assetAbsolute,\n mdFiles,\n readMarkdownFile,\n );\n if (verifyResult.errors.length > 0 || verifyResult.remaining > 0) {\n if (!dryRun) {\n asset.status = \"error\";\n }\n for (const msg of verifyResult.errors) {\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n if (verifyResult.remaining > 0) {\n const msg = `redirect verification failed for ${asset.originalPath}: ${verifyResult.remaining} local reference(s) remain`;\n log.warn(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n continue;\n }\n\n if (asset.redirectedAt === undefined) {\n if (!dryRun) {\n asset.status = \"mirrored\";\n }\n log.info(`[binary-lifecycle] preserved mirrored asset without redirected marker: ${asset.originalPath}${dryRun ? \" [dry-run]\" : \"\"}`);\n continue;\n }\n\n if (!Number.isFinite(new Date(asset.mirroredAt).getTime())) {\n const msg = `redirect blocked for ${asset.originalPath}: manifest mirroredAt is invalid`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n if (!dryRun) {\n asset.status = \"error\";\n }\n continue;\n }\n\n if (!dryRun) {\n asset.status = \"redirected\";\n asset.redirectedAt = new Date().toISOString();\n }\n redirected++;\n log.info(`[binary-lifecycle] redirected: ${asset.originalPath}${dryRun ? \" [dry-run]\" : \"\"}`);\n }\n continue;\n }\n\n if (dryRun) {\n redirected++;\n log.info(`[binary-lifecycle] redirected: ${asset.originalPath} [dry-run]`);\n continue;\n }\n\n let writeFailCount = 0;\n for (const update of updates) {\n try {\n await writeMarkdownFile(update.mdPath, update.content);\n } catch (err) {\n writeFailCount++;\n const msg = `redirect write failed for ${update.mdPath}: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n }\n\n if (writeFailCount > 0) {\n if (!dryRun) {\n asset.status = \"error\";\n }\n log.warn(\n `[binary-lifecycle] redirect write failure for ${asset.originalPath}: ` +\n `${writeFailCount} write failure(s) — status set to error`,\n );\n continue;\n }\n\n const redirectedAt = new Date().toISOString();\n asset.redirectedAt = redirectedAt;\n\n const verifyResult = await countRemainingLocalReferences(\n memoryDir,\n asset,\n assetAbsolute,\n mdFiles,\n readMarkdownFile,\n );\n if (verifyResult.errors.length > 0 || verifyResult.remaining > 0) {\n asset.status = \"error\";\n for (const msg of verifyResult.errors) {\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n if (verifyResult.remaining > 0) {\n const msg = `redirect verification failed for ${asset.originalPath}: ${verifyResult.remaining} local reference(s) remain`;\n log.warn(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n continue;\n }\n asset.status = \"redirected\";\n asset.redirectedAt = redirectedAt;\n redirected++;\n log.info(`[binary-lifecycle] redirected: ${asset.originalPath}`);\n }\n\n return { redirected, errors };\n}\n\nasync function countRemainingLocalReferences(\n memoryDir: string,\n asset: BinaryAssetRecord,\n assetAbsolute: string,\n mdFiles: string[],\n readMarkdownFile: ReadMarkdownFile,\n): Promise<{ remaining: number; errors: string[] }> {\n let remaining = 0;\n const errors: string[] = [];\n\n for (const mdPath of mdFiles) {\n try {\n const content = await readMarkdownFile(mdPath);\n const pattern = markdownReferencePattern(asset, assetAbsolute, mdPath);\n if (pattern.test(content)) {\n remaining++;\n }\n } catch (err) {\n errors.push(`redirect verification failed for ${mdPath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return { remaining, errors };\n}\n\nfunction markdownReferencePattern(\n asset: BinaryAssetRecord,\n assetAbsolute: string,\n mdPath: string,\n): RegExp {\n const mdDir = path.dirname(mdPath);\n const candidates = new Set<string>();\n const addCandidate = (candidate: string): void => {\n const normalized = candidate.split(path.sep).join(\"/\");\n if (normalized.length === 0) return;\n candidates.add(normalized);\n const isParentTraversal = normalized === \"..\" || normalized.startsWith(\"../\");\n if (!normalized.startsWith(\"./\") && !normalized.startsWith(\"/\") && !isParentTraversal) {\n candidates.add(`./${normalized}`);\n }\n };\n\n // Markdown links may be file-relative to the note or memory-root-relative in\n // Remnic notes. Match both forms so verification cannot miss a live local ref.\n addCandidate(path.relative(mdDir, assetAbsolute));\n const originalPath = asset.originalPath.split(path.sep).join(\"/\");\n const originalAsFileRelative = path.resolve(mdDir, ...originalPath.split(\"/\"));\n if (path.resolve(originalAsFileRelative) === path.resolve(assetAbsolute)) {\n addCandidate(originalPath);\n }\n addCandidate(`/${originalPath}`);\n\n const alternatives = [...candidates]\n .sort((a, b) => b.length - a.length)\n .map(escapeRegex)\n .join(\"|\");\n\n return new RegExp(`(!?\\\\[[^\\\\]]*\\\\]\\\\()(${alternatives})(\\\\))`, \"g\");\n}\n\nasync function stageClean(\n memoryDir: string,\n assets: BinaryAssetRecord[],\n backend: BinaryStorageBackend,\n gracePeriodDays: number,\n log: PipelineLogger,\n dryRun: boolean,\n forceClean: boolean,\n): Promise<{ cleaned: number; errors: string[] }> {\n let cleaned = 0;\n const errors: string[] = [];\n const now = Date.now();\n const graceMs = gracePeriodDays * 24 * 60 * 60 * 1000;\n\n // Clean only assets that have been redirected (markdown refs already rewritten).\n // Mirrored-only assets must NOT be cleaned — their markdown refs still point\n // to the local file, so deletion would break links.\n const candidates = assets.filter(\n (a) => a.status === \"redirected\",\n );\n\n for (const asset of candidates) {\n const mirroredMs = new Date(asset.mirroredAt).getTime();\n if (!Number.isFinite(mirroredMs)) {\n const msg = `clean blocked for ${asset.originalPath}: manifest mirroredAt is invalid`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n if (!dryRun) {\n asset.status = \"error\";\n }\n continue;\n }\n const ageMs = now - mirroredMs;\n\n if (!forceClean && ageMs < graceMs) {\n // Not yet past grace period.\n continue;\n }\n\n const fullPath = resolveManifestAssetPath(memoryDir, asset.originalPath);\n if (fullPath === null) {\n const msg = `clean blocked for ${asset.originalPath}: manifest path is outside memoryDir`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n if (!dryRun) {\n asset.status = \"error\";\n }\n continue;\n }\n\n let remoteExists: boolean;\n try {\n remoteExists = await backend.exists(asset.mirroredPath);\n } catch (err) {\n const msg = `clean blocked for ${asset.originalPath}: failed to verify mirrored copy: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n continue;\n }\n\n if (!remoteExists) {\n const msg = `clean blocked for ${asset.originalPath}: mirrored copy is missing`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n continue;\n }\n\n try {\n const currentHash = await hashFile(fullPath);\n if (currentHash !== asset.contentHash) {\n const msg = `clean blocked for ${asset.originalPath}: local content hash does not match manifest`;\n log.warn(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n continue;\n }\n if (!dryRun) {\n await fsp.unlink(fullPath);\n asset.status = \"cleaned\";\n asset.cleanedAt = new Date().toISOString();\n }\n cleaned++;\n log.info(`[binary-lifecycle] cleaned: ${asset.originalPath}${dryRun ? \" [dry-run]\" : \"\"}`);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n // Already gone — mark as cleaned.\n if (!dryRun) {\n asset.status = \"cleaned\";\n asset.cleanedAt = new Date().toISOString();\n cleaned++;\n }\n } else {\n const msg = `clean failed for ${asset.originalPath}: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n }\n }\n\n return { cleaned, errors };\n}\n\n// ---------------------------------------------------------------------------\n// Markdown file discovery\n// ---------------------------------------------------------------------------\n\nasync function findMarkdownFiles(dir: string): Promise<string[]> {\n const results: string[] = [];\n\n async function walk(current: string): Promise<void> {\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fsp.readdir(current, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = path.join(current, entry.name);\n if (entry.isDirectory()) {\n if (entry.name === \".binary-lifecycle\") continue;\n await walk(full);\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n results.push(full);\n }\n }\n }\n\n await walk(dir);\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Main pipeline entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Run the binary lifecycle pipeline: scan, mirror, redirect, clean.\n */\nexport async function runBinaryLifecyclePipeline(\n memoryDir: string,\n config: BinaryLifecycleConfig,\n backend: BinaryStorageBackend,\n log: PipelineLogger,\n opts?: PipelineOptions,\n): Promise<PipelineResult> {\n validateBinaryLifecycleConfig(config);\n\n const dryRun = opts?.dryRun ?? false;\n const forceClean = opts?.forceClean ?? false;\n\n if (config.enabled === false) {\n return {\n scanned: 0,\n mirrored: 0,\n redirected: 0,\n cleaned: 0,\n errors: [],\n dryRun,\n };\n }\n\n const manifest = await readManifest(memoryDir);\n\n // Stage 0: Scan\n const newPaths = await scanForBinaries(memoryDir, config, manifest);\n const scanned = newPaths.length;\n\n // Stage 1: Mirror\n const mirrorResult = await stageMirror(\n memoryDir,\n newPaths,\n backend,\n manifest.assets,\n log,\n dryRun,\n );\n\n // Stage 2: Redirect\n const redirectResult = await stageRedirect(\n memoryDir,\n manifest.assets,\n log,\n dryRun,\n opts?.readMarkdownFile ?? ((filePath: string) => fsp.readFile(filePath, \"utf-8\")),\n opts?.writeMarkdownFile ?? ((filePath: string, content: string) => fsp.writeFile(filePath, content, \"utf-8\")),\n );\n\n // Stage 3: Clean\n const cleanResult = await stageClean(\n memoryDir,\n manifest.assets,\n backend,\n config.gracePeriodDays,\n log,\n dryRun,\n forceClean,\n );\n\n // Persist manifest (unless dry-run).\n manifest.lastScanAt = new Date().toISOString();\n if (!dryRun) {\n await writeManifest(memoryDir, manifest);\n }\n\n const allErrors = [\n ...mirrorResult.errors,\n ...redirectResult.errors,\n ...cleanResult.errors,\n ];\n\n return {\n scanned,\n mirrored: mirrorResult.mirrored,\n redirected: redirectResult.redirected,\n cleaned: cleanResult.cleaned,\n errors: allErrors,\n dryRun,\n };\n}\n","/**\n * @remnic/core — Workspace Tree Projection\n *\n * Generates a human-readable `.engram/context-tree/` from canonical memory.\n * Each node is a `.md` file with rich metadata, * (provenance, trust, confidence, source anchors).\n * Manual edits are preserved in fenced blocks.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { getCategoryDir, ALL_CATEGORY_KEYS } from \"../utils/category-dir.js\";\n\nconst VALID_PROJECTION_CATEGORIES = new Set(ALL_CATEGORY_KEYS);\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface TreeNode {\n /** Relative path from context-tree root, e.g. \"entities/claude.md\" */\n path: string;\n /** Category from canonical memory */\n category: string;\n /** Human-readable title */\n title: string;\n /** File content (rendered markdown) */\n content: string;\n /** Source memory IDs that contributed to this node */\n sourceAnchors: string[];\n /** Confidence (0-1) */\n confidence: number;\n /** Trust zone classification */\n confidenceTier: string;\n /** When this node was generated */\n generatedAt: string;\n /** Provenance chain */\n provenance: ProvenanceEntry[];\n}\n\nexport interface ProvenanceEntry {\n memoryId: string;\n source: string;\n extracted: string;\n}\n\nexport interface GenerateOptions {\n /** Memory root directory (e.g. ~/.openclaw/workspace/memory/local) */\n memoryDir: string;\n /** Output directory (e.g. .engram/context-tree) */\n outputDir: string;\n /** Categories to include (default: all) */\n categories?: string[];\n /** Whether to include entity graph */\n includeEntities?: boolean;\n /** Whether to include orphaned questions */\n includeQuestions?: boolean;\n /** Max nodes per category (default: unlimited) */\n maxPerCategory?: number;\n /** Whether to watch for changes and regenerate incrementally */\n watch?: boolean;\n}\n\nexport interface GenerateResult {\n nodesGenerated: number;\n nodesSkipped: number;\n categories: Record<string, number>;\n durationMs: number;\n outputDir: string;\n}\n\n// ── Generation ──────────────────────────────────────────────────────────────\n\n/**\n * Generate a context tree from canonical memory.\n *\n * Reads memory `.md` files from the source directory, * and projects them into a clean, * human-readable tree structure at `outputDir`.\n */\nexport async function generateContextTree(options: GenerateOptions): Promise<GenerateResult> {\n const startTime = Date.now();\n const {\n memoryDir,\n outputDir,\n categories: filterCategories,\n includeEntities = true,\n includeQuestions = true,\n maxPerCategory = Infinity,\n } = options;\n\n let nodesGenerated = 0;\n let nodesSkipped = 0;\n const categoryCounts: Record<string, number> = {};\n const resolvedMemoryDir = path.resolve(memoryDir);\n const resolvedOutputDir = path.resolve(outputDir);\n const requestedCategories = validateProjectionCategories(filterCategories);\n const realMemoryDir = assertSafeMemoryRoot(resolvedMemoryDir);\n\n // Ensure output directory exists\n assertNotSymlink(resolvedOutputDir, \"context tree outputDir\");\n fs.mkdirSync(resolvedOutputDir, { recursive: true });\n const realOutputDir = fs.realpathSync(resolvedOutputDir);\n\n // Process each category (exclude 'question' — handled by separate includeQuestions pass)\n const allCategories = (requestedCategories ?? ALL_CATEGORY_KEYS)\n .filter((c) => c !== \"question\");\n\n for (const category of allCategories) {\n const categoryDir = getCategoryDir(memoryDir, category);\n if (!fs.existsSync(categoryDir)) continue;\n assertSafeInputRoot(realMemoryDir, categoryDir, `${category} memory category`);\n\n categoryCounts[category] = 0;\n const files = walkR(categoryDir, realMemoryDir);\n let count = 0;\n\n for (const filePath of files) {\n if (count >= maxPerCategory) {\n nodesSkipped++;\n continue;\n }\n\n const content = fs.readFileSync(filePath, \"utf8\");\n const fm = parseFrontmatter(content);\n if (!fm) {\n nodesSkipped++;\n continue;\n }\n\n const node = projectNode(filePath, category, fm, content);\n if (!node) {\n nodesSkipped++;\n continue;\n }\n\n // Write node to output\n const outputPath = resolveContainedOutputPath(realOutputDir, node.path);\n writeProjectedContent(realOutputDir, outputPath, node.content);\n\n nodesGenerated++;\n categoryCounts[category] = (categoryCounts[category] ?? 0) + 1;\n count++;\n }\n }\n\n // Process entities\n if (includeEntities) {\n const entitiesDir = path.join(memoryDir, \"entities\");\n if (fs.existsSync(entitiesDir)) {\n assertSafeInputRoot(realMemoryDir, entitiesDir, \"entities root\");\n categoryCounts[\"entity\"] = 0;\n const entityFiles = walkR(entitiesDir, realMemoryDir);\n let count = 0;\n\n for (const filePath of entityFiles) {\n if (count >= maxPerCategory) {\n nodesSkipped++;\n continue;\n }\n\n const content = fs.readFileSync(filePath, \"utf8\");\n const fileName = path.basename(filePath, \".md\");\n const node = projectEntityNode(fileName, content);\n\n const outputPath = resolveContainedOutputPath(realOutputDir, \"entities\", `${fileName}.md`);\n writeProjectedContent(realOutputDir, outputPath, node.content);\n\n nodesGenerated++;\n categoryCounts[\"entity\"] = (categoryCounts[\"entity\"] ?? 0) + 1;\n count++;\n }\n }\n }\n\n // Process questions\n const shouldIncludeQuestions =\n includeQuestions &&\n (requestedCategories === undefined || requestedCategories.includes(\"question\"));\n if (shouldIncludeQuestions) {\n const questionsDir = path.join(memoryDir, \"questions\");\n if (fs.existsSync(questionsDir)) {\n assertSafeInputRoot(realMemoryDir, questionsDir, \"questions root\");\n categoryCounts[\"question\"] = 0;\n const qFiles = walkR(questionsDir, realMemoryDir);\n let count = 0;\n\n for (const filePath of qFiles) {\n if (count >= maxPerCategory) {\n nodesSkipped++;\n continue;\n }\n\n const content = fs.readFileSync(filePath, \"utf8\");\n const fm = parseFrontmatter(content);\n if (!fm) {\n nodesSkipped++;\n continue;\n }\n\n const node = projectNode(filePath, \"question\", fm, content);\n if (!node) {\n nodesSkipped++;\n continue;\n }\n\n const outputPath = resolveContainedOutputPath(realOutputDir, node.path);\n writeProjectedContent(realOutputDir, outputPath, node.content);\n\n nodesGenerated++;\n categoryCounts[\"question\"] = (categoryCounts[\"question\"] ?? 0) + 1;\n count++;\n }\n }\n }\n\n // Write index\n const index = generateIndex(categoryCounts, resolvedOutputDir);\n writeProjectedContent(realOutputDir, resolveContainedOutputPath(realOutputDir, \"INDEX.md\"), index);\n\n return {\n nodesGenerated,\n nodesSkipped,\n categories: categoryCounts,\n durationMs: Date.now() - startTime,\n outputDir,\n };\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction isPathInside(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nfunction assertNotSymlink(targetPath: string, label: string): void {\n try {\n if (fs.lstatSync(targetPath).isSymbolicLink()) {\n throw new Error(`${label} must not be a symlink: ${targetPath}`);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw err;\n }\n}\n\nfunction assertSafeMemoryRoot(targetPath: string): string {\n const stat = fs.lstatSync(targetPath);\n if (stat.isSymbolicLink()) {\n throw new Error(`memoryDir must not be a symlink: ${targetPath}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`memoryDir must be a directory: ${targetPath}`);\n }\n return fs.realpathSync(targetPath);\n}\n\nfunction assertSafeInputRoot(realMemoryDir: string, targetPath: string, label: string): void {\n const stat = fs.lstatSync(targetPath);\n if (stat.isSymbolicLink()) {\n throw new Error(`${label} must not be a symlink: ${targetPath}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`${label} must be a directory: ${targetPath}`);\n }\n const realTarget = fs.realpathSync(targetPath);\n if (!isPathInside(realMemoryDir, realTarget)) {\n throw new Error(`${label} escapes memoryDir: ${targetPath}`);\n }\n}\n\nfunction assertSafeOutputTarget(realOutputDir: string, outputPath: string): void {\n let current = realOutputDir;\n const relative = path.relative(realOutputDir, outputPath);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(`context tree output path escapes outputDir: ${outputPath}`);\n }\n for (const segment of relative.split(path.sep).filter(Boolean)) {\n current = path.join(current, segment);\n try {\n const stat = fs.lstatSync(current);\n if (stat.isSymbolicLink()) {\n throw new Error(`context tree output path contains symlink: ${current}`);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n break;\n }\n throw err;\n }\n }\n}\n\nfunction validateProjectionCategories(categories: string[] | undefined): string[] | undefined {\n if (categories === undefined) {\n return undefined;\n }\n const validated: string[] = [];\n for (const category of categories) {\n if (typeof category !== \"string\" || !VALID_PROJECTION_CATEGORIES.has(category)) {\n throw new Error(`invalid context tree category: ${String(category)}`);\n }\n if (!validated.includes(category)) {\n validated.push(category);\n }\n }\n return validated;\n}\n\nfunction resolveContainedOutputPath(outputRoot: string, ...segments: string[]): string {\n const resolved = path.resolve(outputRoot, ...segments);\n const relative = path.relative(outputRoot, resolved);\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) {\n return resolved;\n }\n throw new Error(`context tree output path escapes outputDir: ${segments.join(\"/\")}`);\n}\n\nfunction writeProjectedContent(realOutputDir: string, outputPath: string, generatedContent: string): void {\n assertSafeOutputTarget(realOutputDir, outputPath);\n fs.mkdirSync(path.dirname(outputPath), { recursive: true });\n const realParent = fs.realpathSync(path.dirname(outputPath));\n if (!isPathInside(realOutputDir, realParent)) {\n throw new Error(`context tree output path escapes outputDir: ${outputPath}`);\n }\n const existingContent = fs.existsSync(outputPath)\n ? fs.readFileSync(outputPath, \"utf8\")\n : \"\";\n fs.writeFileSync(\n outputPath,\n preserveManualFencedBlocks(generatedContent, existingContent),\n );\n}\n\nfunction preserveManualFencedBlocks(\n generatedContent: string,\n existingContent: string,\n): string {\n const manualBlocks = extractManualFencedBlocks(existingContent)\n .filter((block) => !generatedContent.includes(block));\n if (manualBlocks.length === 0) {\n return generatedContent;\n }\n return `${generatedContent.trimEnd()}\\n\\n## Manual Edits\\n\\n${manualBlocks.join(\"\\n\\n\")}\\n`;\n}\n\nfunction extractManualFencedBlocks(content: string): string[] {\n const blocks: string[] = [];\n const seen = new Set<string>();\n const fencePattern = /(?:^|\\n)([`~]{3,})[^\\n]*\\bmanual\\b[^\\n]*\\n[\\s\\S]*?\\n\\1[ \\t]*(?=\\n|$)/gi;\n for (const match of content.matchAll(fencePattern)) {\n const block = match[0].trim();\n if (!seen.has(block)) {\n seen.add(block);\n blocks.push(block);\n }\n }\n return blocks;\n}\n\nfunction walkR(dir: string, realMemoryDir: string): string[] {\n const results: string[] = [];\n function walk(directory: string): void {\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const fullPath = path.join(directory, entry.name);\n if (entry.isSymbolicLink()) {\n throw new Error(`context tree input path contains symlink: ${fullPath}`);\n }\n if (entry.isDirectory()) {\n const realDir = fs.realpathSync(fullPath);\n if (!isPathInside(realMemoryDir, realDir)) {\n throw new Error(`context tree input path escapes memoryDir: ${fullPath}`);\n }\n walk(fullPath);\n } else if (entry.name.endsWith(\".md\")) {\n const realFile = fs.realpathSync(fullPath);\n if (!isPathInside(realMemoryDir, realFile)) {\n throw new Error(`context tree input path escapes memoryDir: ${fullPath}`);\n }\n results.push(fullPath);\n }\n }\n }\n walk(dir);\n return results;\n}\n\ninterface Frontmatter {\n id: string;\n category: string;\n created: string;\n updated: string;\n confidence: number;\n confidenceTier: string;\n tags: string[];\n source: string;\n entityRef?: string;\n lifecycleState?: string;\n}\n\nfunction parseFrontmatter(content: string): Frontmatter | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fmText = match[1];\n const fm: Record<string, unknown> = {};\n for (const line of fmText.split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n if (key === \"tags\") {\n try {\n fm[key] = JSON.parse(value) as string[];\n } catch {\n fm[key] = [] as string[];\n }\n } else if (key === \"confidence\") {\n const parsed = parseFloat(value);\n fm[key] = Number.isFinite(parsed) ? parsed : 0;\n } else {\n fm[key] = value;\n }\n }\n return fm as unknown as Frontmatter;\n}\n\nfunction extractBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n([\\s\\S]*)/);\n return match ? match[1].trim() : content.trim();\n}\n\nfunction projectNode(\n filePath: string,\n category: string,\n fm: Frontmatter,\n rawContent: string,\n): TreeNode | null {\n const body = extractBody(rawContent);\n const fileName = path.basename(filePath, \".md\");\n const dateDir = path.basename(path.dirname(filePath));\n\n // Build relative path: category/date/file or just category/file\n let relPath: string;\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(dateDir)) {\n relPath = path.join(category, dateDir, `${fileName}.md`);\n } else {\n relPath = path.join(category, `${fileName}.md`);\n }\n\n const generatedAt = new Date().toISOString();\n\n const md = `# ${fm.id}\n\n> **Category:** ${fm.category}\n> **Created:** ${fm.created}\n> **Updated:** ${fm.updated ?? fm.created}\n> **Confidence:** ${fm.confidence} (${fm.confidenceTier}${fm.lifecycleState ? `, ${fm.lifecycleState}` : \"\"})\n${fm.tags?.length ? `\\n> **Tags:** ${fm.tags.join(\", \")}` : \"\"}\n${fm.entityRef ? `\\n> **Entity:** ${fm.entityRef}` : \"\"}\n> **Source:** ${fm.source ?? \"unknown\"}\n> **Projected:** ${generatedAt}\n\n---\n\n${body}\n`;\n\n return {\n path: relPath,\n category,\n title: fm.id,\n content: md,\n sourceAnchors: [fm.id],\n confidence: fm.confidence ?? 0,\n confidenceTier: fm.confidenceTier ?? \"unknown\",\n generatedAt,\n provenance: [{\n memoryId: fm.id,\n source: fm.source ?? \"unknown\",\n extracted: fm.created,\n }],\n };\n}\n\nfunction projectEntityNode(fileName: string, content: string): TreeNode {\n const generatedAt = new Date().toISOString();\n\n const md = `> **Projected:** ${generatedAt}\n> **Source:** canonical\n\n---\n\n${content}\n`;\n\n return {\n path: path.join(\"entities\", `${fileName}.md`),\n category: \"entity\",\n title: fileName,\n content: md,\n sourceAnchors: [fileName],\n confidence: 1,\n confidenceTier: \"explicit\",\n generatedAt,\n provenance: [{\n memoryId: fileName,\n source: \"canonical\",\n extracted: generatedAt,\n }],\n };\n}\n\nfunction generateIndex(\n categoryCounts: Record<string, number>,\n outputDir: string,\n): string {\n const lines = [\n \"# Context Tree Index\",\n \"\",\n `Generated: ${new Date().toISOString()}`,\n \"\",\n \"## Summary\",\n \"\",\n `| Category | Count |`,\n `|----------|-------|`,\n ];\n\n let total = 0;\n for (const [cat, count] of Object.entries(categoryCounts).sort()) {\n lines.push(`| ${cat} | ${count} |`);\n total += count;\n }\n\n lines.push(\"\");\n lines.push(`**Total:** ${total} nodes`);\n lines.push(\"\");\n lines.push(\"## Structure\");\n lines.push(\"\");\n lines.push(\"```\");\n lines.push(\"context-tree/\");\n lines.push(\"├── entities/ # Entity knowledge graph\");\n lines.push(\"├── fact/ # Factual memories (date-partitioned)\");\n lines.push(\"├── correction/ # Correction memories\");\n lines.push(\"├── decision/ # Decisions\");\n lines.push(\"├── moment/ # Notable moments\");\n lines.push(\"├── preference/ # Preferences\");\n lines.push(\"├── principle/ # Principles\");\n lines.push(\"├── question/ # Open questions\");\n lines.push(\"└── INDEX.md # This file\");\n lines.push(\"```\");\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n","/**\n * @remnic/core — Onboarding\n *\n * Detects project language, shape, and documentation to produce\n * an onboarding plan for memory ingestion.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface OnboardOptions {\n /** Directory to scan (defaults to cwd) */\n directory?: string;\n /** Max depth to walk (default: 6) */\n maxDepth?: number;\n /** Directories to skip */\n excludeDirs?: string[];\n}\n\nexport interface LanguageInfo {\n /** Language name (e.g. \"TypeScript\", \"Python\") */\n language: string;\n /** Confidence in detection (0-1) */\n confidence: number;\n /** Evidence (e.g. [\"package.json\", \"tsconfig.json\", \"*.ts files\"]) */\n evidence: string[];\n}\n\nexport interface DocFile {\n /** Absolute path */\n path: string;\n /** Relative path from project root */\n relativePath: string;\n /** Estimated type */\n kind: \"readme\" | \"changelog\" | \"contributing\" | \"license\" | \"config\" | \"docs\" | \"other\";\n /** File size in bytes */\n size: number;\n}\n\nexport type ProjectShape = \"app\" | \"library\" | \"monorepo\" | \"workspace\" | \"script\" | \"unknown\";\n\nexport interface OnboardResult {\n /** Project root */\n directory: string;\n /** Detected languages (sorted by confidence) */\n languages: LanguageInfo[];\n /** Detected project shape */\n shape: ProjectShape;\n /** Shape evidence */\n shapeEvidence: string[];\n /** Discovered documentation files */\n docs: DocFile[];\n /** Total files scanned */\n totalFiles: number;\n /** Duration in ms */\n durationMs: number;\n /** Suggested ingestion plan */\n plan: IngestionPlan;\n}\n\nexport interface IngestionPlan {\n /** Priority files to ingest first */\n priorityFiles: DocFile[];\n /** Estimated total files to ingest */\n estimatedFiles: number;\n /** Recommended categories */\n categories: string[];\n /** Suggested memory namespace */\n suggestedNamespace: string;\n}\n\n// ── Language detection rules ─────────────────────────────────────────────────\n\ninterface LanguageRule {\n language: string;\n extensions: string[];\n manifests: string[];\n configFiles: string[];\n}\n\nconst LANGUAGE_RULES: LanguageRule[] = [\n {\n language: \"TypeScript\",\n extensions: [\".ts\", \".tsx\"],\n manifests: [],\n configFiles: [\"tsconfig.json\", \"tsup.config.ts\"],\n },\n {\n language: \"JavaScript\",\n extensions: [\".js\", \".jsx\", \".mjs\", \".cjs\"],\n manifests: [],\n configFiles: [\".eslintrc\", \".prettierrc\"],\n },\n {\n language: \"Python\",\n extensions: [\".py\", \".pyi\"],\n manifests: [\"pyproject.toml\", \"setup.py\", \"setup.cfg\", \"requirements.txt\"],\n configFiles: [\"mypy.ini\", \".flake8\", \"tox.ini\"],\n },\n {\n language: \"Go\",\n extensions: [\".go\"],\n manifests: [\"go.mod\", \"go.sum\"],\n configFiles: [],\n },\n {\n language: \"Rust\",\n extensions: [\".rs\"],\n manifests: [\"Cargo.toml\"],\n configFiles: [],\n },\n {\n language: \"Ruby\",\n extensions: [\".rb\"],\n manifests: [\"Gemfile\", \"*.gemspec\"],\n configFiles: [\".rubocop.yml\"],\n },\n {\n language: \"PHP\",\n extensions: [\".php\"],\n manifests: [\"composer.json\"],\n configFiles: [\"phpcs.xml\"],\n },\n {\n language: \"Java\",\n extensions: [\".java\", \".kt\"],\n manifests: [\"pom.xml\", \"build.gradle\", \"build.gradle.kts\"],\n configFiles: [],\n },\n {\n language: \"Swift\",\n extensions: [\".swift\"],\n manifests: [\"Package.swift\", \"Podfile\"],\n configFiles: [],\n },\n {\n language: \"C#\",\n extensions: [\".cs\"],\n manifests: [\"*.csproj\", \"*.sln\"],\n configFiles: [],\n },\n {\n language: \"Shell\",\n extensions: [\".sh\", \".bash\", \".zsh\"],\n manifests: [],\n configFiles: [],\n },\n {\n language: \"Dart\",\n extensions: [\".dart\"],\n manifests: [\"pubspec.yaml\"],\n configFiles: [],\n },\n {\n language: \"Elixir\",\n extensions: [\".ex\", \".exs\"],\n manifests: [\"mix.exs\"],\n configFiles: [],\n },\n];\n\nconst DEFAULT_EXCLUDE = new Set([\n \"node_modules\",\n \".git\",\n \"vendor\",\n \"__pycache__\",\n \".venv\",\n \"venv\",\n \"dist\",\n \"build\",\n \".next\",\n \".nuxt\",\n \"target\",\n \"coverage\",\n \".engram\",\n]);\n\n// ── Main function ────────────────────────────────────────────────────────────\n\nexport function onboard(options: OnboardOptions): OnboardResult {\n const startTime = Date.now();\n const {\n maxDepth = 6,\n excludeDirs = [],\n } = options;\n const directory = path.resolve(options.directory ?? process.cwd());\n let rootStat: fs.Stats;\n try {\n rootStat = fs.statSync(directory);\n } catch (err) {\n throw new Error(`Cannot scan onboarding directory ${directory}: ${err instanceof Error ? err.message : String(err)}`);\n }\n if (!rootStat.isDirectory()) {\n throw new Error(`Cannot scan onboarding directory ${directory}: not a directory`);\n }\n\n const exclude = new Set([...DEFAULT_EXCLUDE, ...excludeDirs]);\n\n // Collect all files\n const files = walkDir(directory, exclude, maxDepth);\n\n // Detect languages\n const languages = detectLanguages(files, directory);\n\n // Detect shape\n const { shape, evidence: shapeEvidence } = detectShape(files, directory);\n\n // Discover docs\n const docs = discoverDocs(files, directory);\n\n // Build plan\n const plan = buildPlan(languages, shape, docs, directory);\n\n return {\n directory,\n languages,\n shape,\n shapeEvidence,\n docs,\n totalFiles: files.length,\n durationMs: Date.now() - startTime,\n plan,\n };\n}\n\n// ── Walk directory ───────────────────────────────────────────────────────────\n\nfunction walkDir(\n root: string,\n exclude: Set<string>,\n maxDepth: number,\n): string[] {\n const results: string[] = [];\n\n function walk(dir: string, depth: number): void {\n if (depth > maxDepth) return;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch (err) {\n if (depth === 0) {\n throw new Error(`Cannot scan onboarding directory ${root}: ${err instanceof Error ? err.message : String(err)}`);\n }\n return;\n }\n\n for (const entry of entries) {\n if (exclude.has(entry.name)) continue;\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walk(fullPath, depth + 1);\n } else if (entry.isFile()) {\n results.push(fullPath);\n }\n }\n }\n\n walk(root, 0);\n return results;\n}\n\n// ── Language detection ───────────────────────────────────────────────────────\n\nfunction detectLanguages(files: string[], root: string): LanguageInfo[] {\n const results: LanguageInfo[] = [];\n\n // Count extensions\n const extCounts = new Map<string, number>();\n for (const f of files) {\n const ext = path.extname(f).toLowerCase();\n if (ext) extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);\n }\n\n // Check manifests at root level\n const rootFiles = new Set(\n files\n .filter((f) => path.dirname(f) === root)\n .map((f) => path.basename(f)),\n );\n\n for (const rule of LANGUAGE_RULES) {\n const evidence: string[] = [];\n let score = 0;\n\n // Extension matches\n let extMatch = 0;\n for (const ext of rule.extensions) {\n const count = extCounts.get(ext) ?? 0;\n if (count > 0) {\n extMatch += count;\n evidence.push(`${ext} files (${count})`);\n }\n }\n score += Math.min(extMatch * 0.05, 0.5);\n\n // Manifest matches\n for (const manifest of rule.manifests) {\n if (manifest.includes(\"*\")) {\n // Glob pattern — e.g. \"*.gemspec\" matches files ending with \".gemspec\"\n const suffix = manifest.replaceAll(/\\*/g, \"\");\n if ([...rootFiles].some((f) => f.endsWith(suffix))) {\n score += 0.2;\n evidence.push(manifest);\n }\n } else if (rootFiles.has(manifest)) {\n score += 0.2;\n evidence.push(manifest);\n }\n }\n\n // Config matches\n for (const cfg of rule.configFiles) {\n if (rootFiles.has(cfg)) {\n score += 0.1;\n evidence.push(cfg);\n }\n }\n\n if (score > 0) {\n results.push({\n language: rule.language,\n confidence: Math.min(score, 1),\n evidence,\n });\n }\n }\n\n return results.sort((a, b) => b.confidence - a.confidence);\n}\n\n// ── Shape detection ──────────────────────────────────────────────────────────\n\nfunction detectShape(\n files: string[],\n root: string,\n): { shape: ProjectShape; evidence: string[] } {\n const rootFiles = new Set(\n files\n .filter((f) => path.dirname(f) === root)\n .map((f) => path.basename(f)),\n );\n\n const rootDirs = new Set<string>();\n try {\n for (const entry of fs.readdirSync(root, { withFileTypes: true })) {\n if (entry.isDirectory()) rootDirs.add(entry.name);\n }\n } catch {\n // ignore\n }\n\n const evidence: string[] = [];\n\n // Monorepo: workspace packages/ or libs/ dirs + root package.json with workspaces\n if (rootFiles.has(\"package.json\")) {\n const pkg = readJsonSafe(path.join(root, \"package.json\"));\n if (pkg?.workspaces) {\n evidence.push(\"package.json has workspaces\");\n return { shape: \"monorepo\", evidence };\n }\n }\n\n if (rootDirs.has(\"packages\") || rootDirs.has(\"libs\")) {\n evidence.push(\"has packages/ or libs/ directory\");\n return { shape: \"monorepo\", evidence };\n }\n\n // Workspace: pnpm-workspace.yaml, Cargo workspace, go.work\n if (rootFiles.has(\"pnpm-workspace.yaml\") || rootFiles.has(\"go.work\")) {\n evidence.push(\"workspace manifest found\");\n return { shape: \"workspace\", evidence };\n }\n\n const cargoToml = readTomlWorkspace(path.join(root, \"Cargo.toml\"));\n if (cargoToml) {\n evidence.push(\"Cargo.toml has workspace\");\n return { shape: \"workspace\", evidence };\n }\n\n // Library: has lib/ or src/index.*, exports in package.json\n if (rootFiles.has(\"package.json\")) {\n const pkg = readJsonSafe(path.join(root, \"package.json\"));\n if (pkg?.exports || pkg?.main) {\n // If it also has \"bin\", it's more of an app\n if (pkg?.bin) {\n evidence.push(\"package.json has bin\");\n return { shape: \"app\", evidence };\n }\n evidence.push(\"package.json has exports/main\");\n return { shape: \"library\", evidence };\n }\n }\n\n // Check for app indicators\n if (\n rootFiles.has(\"Dockerfile\") ||\n rootFiles.has(\"docker-compose.yml\") ||\n rootFiles.has(\"docker-compose.yaml\") ||\n rootDirs.has(\"app\") ||\n rootDirs.has(\"src\") && rootDirs.has(\"public\")\n ) {\n evidence.push(\"app-like structure detected\");\n return { shape: \"app\", evidence };\n }\n\n // Script: few files, no package manifest\n if (files.length <= 5 && !rootFiles.has(\"package.json\") && !rootFiles.has(\"pyproject.toml\")) {\n evidence.push(\"few files, no manifest\");\n return { shape: \"script\", evidence };\n }\n\n return { shape: \"unknown\", evidence: [\"no strong shape signal\"] };\n}\n\n// ── Doc discovery ────────────────────────────────────────────────────────────\n\nfunction discoverDocs(files: string[], root: string): DocFile[] {\n const docs: DocFile[] = [];\n const docPatterns: Array<{ pattern: RegExp; kind: DocFile[\"kind\"] }> = [\n { pattern: /^readme(\\.\\w+)?$/i, kind: \"readme\" },\n { pattern: /^changelog(\\.\\w+)?$/i, kind: \"changelog\" },\n { pattern: /^changes(\\.\\w+)?$/i, kind: \"changelog\" },\n { pattern: /^contributing(\\.\\w+)?$/i, kind: \"contributing\" },\n { pattern: /^code[_-]of[_-]conduct(\\.\\w+)?$/i, kind: \"contributing\" },\n { pattern: /^license(\\.\\w+)?$/i, kind: \"license\" },\n { pattern: /^copying(\\.\\w+)?$/i, kind: \"license\" },\n { pattern: /^\\.env\\.example$/i, kind: \"config\" },\n { pattern: /^\\.editorconfig$/i, kind: \"config\" },\n ];\n\n for (const filePath of files) {\n const basename = path.basename(filePath).toLowerCase();\n const relPath = path.relative(root, filePath);\n let kind: DocFile[\"kind\"] | undefined;\n\n // Check against patterns\n for (const { pattern, kind: k } of docPatterns) {\n if (pattern.test(basename)) {\n kind = k;\n break;\n }\n }\n\n // Check docs/ directories\n if (!kind && isUnderDocsDir(relPath)) {\n kind = \"docs\";\n }\n\n // Check markdown files at root or in docs/\n if (!kind && (basename.endsWith(\".md\") || basename.endsWith(\".mdx\"))) {\n if (path.dirname(relPath) === \".\" || isUnderDocsDir(relPath)) {\n kind = \"docs\";\n }\n }\n\n if (kind) {\n let size = 0;\n try {\n size = fs.statSync(filePath).size;\n } catch {\n // ignore\n }\n docs.push({\n path: filePath,\n relativePath: relPath,\n kind,\n size,\n });\n }\n }\n\n return docs;\n}\n\nfunction isUnderDocsDir(relPath: string): boolean {\n const parts = relPath.split(path.sep);\n return parts[0] === \"docs\" || parts[0] === \"doc\" || parts[0] === \"documentation\";\n}\n\n// ── Plan generation ──────────────────────────────────────────────────────────\n\nfunction buildPlan(\n languages: LanguageInfo[],\n shape: ProjectShape,\n docs: DocFile[],\n _root: string,\n): IngestionPlan {\n // Priority: README, CONTRIBUTING, then other docs\n const priorityOrder: Record<DocFile[\"kind\"], number> = {\n readme: 0,\n contributing: 1,\n changelog: 2,\n license: 3,\n docs: 4,\n config: 5,\n other: 6,\n };\n\n const priorityFiles = [...docs]\n .filter((d) => d.size > 0)\n .sort((a, b) => priorityOrder[a.kind] - priorityOrder[b.kind]);\n\n // Recommended categories based on project shape\n const categories: string[] = [\"fact\", \"preference\", \"decision\", \"principle\"];\n if (shape === \"monorepo\" || shape === \"workspace\") {\n categories.push(\"entity\");\n }\n\n // Namespace suggestion from primary language\n const suggestedNamespace = languages.length > 0\n ? languages[0].language.toLowerCase()\n : \"project\";\n\n return {\n priorityFiles,\n estimatedFiles: docs.filter((d) => d.size > 0).length,\n categories,\n suggestedNamespace,\n };\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction readJsonSafe(filePath: string): Record<string, unknown> | null {\n try {\n return JSON.parse(fs.readFileSync(filePath, \"utf8\"));\n } catch {\n return null;\n }\n}\n\nfunction readTomlWorkspace(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, \"utf8\");\n return content.includes(\"[workspace]\");\n } catch {\n return false;\n }\n}\n","/**\n * @remnic/core — Curation\n *\n * Deliberate ingestion of files into memory with provenance tracking.\n * Supports statement-level extraction, dedup, and contradiction checks.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { getCategoryDir, ALL_CATEGORY_DIRS } from \"../utils/category-dir.js\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface CurateOptions {\n /** File or directory path to curate */\n targetPath: string;\n /** Memory root directory for writing */\n memoryDir: string;\n /** Source label (e.g. \"manual\", \"docs\", \"onboarding\") */\n source?: string;\n /** Category override (default: auto-detect) */\n category?: string;\n /** Confidence to assign (default: 0.9 for curated items) */\n confidence?: number;\n /** Entity reference to attach */\n entityRef?: string;\n /** Tags to add */\n tags?: string[];\n /** Whether to perform dedup check against existing memories */\n checkDuplicates?: boolean;\n /** Whether to detect contradictions */\n checkContradictions?: boolean;\n /** Whether to write files (default: true). False = dry run */\n write?: boolean;\n}\n\nexport interface CuratedStatement {\n /** Unique ID for this statement */\n id: string;\n /** The extracted statement text */\n content: string;\n /** Category */\n category: string;\n /** Confidence */\n confidence: number;\n /** Provenance info */\n provenance: StatementProvenance;\n /** Hash of content for dedup */\n contentHash: string;\n /** Tags */\n tags: string[];\n /** Entity reference */\n entityRef?: string;\n}\n\nexport interface StatementProvenance {\n /** Source file path */\n sourcePath: string;\n /** Relative path from project root */\n relativePath: string;\n /** Source label */\n source: string;\n /** Line number if extractable (0 = unknown) */\n lineNumber: number;\n /** Timestamp of ingestion */\n ingestedAt: string;\n /** Hash of the source file for diff tracking */\n sourceFileHash: string;\n}\n\nexport interface CurateResult {\n /** Statements extracted */\n statements: CuratedStatement[];\n /** Files processed */\n filesProcessed: number;\n /** Files skipped (empty, binary, etc.) */\n filesSkipped: number;\n /** Duplicate statements found (if checkDuplicates) */\n duplicates: DuplicateResult[];\n /** Contradictions found (if checkContradictions) */\n contradictions: ContradictionResult[];\n /** Memory files written */\n written: string[];\n /** Duration in ms */\n durationMs: number;\n}\n\nexport interface DuplicateResult {\n /** New statement */\n newStatement: CuratedStatement;\n /** Existing memory ID that matches */\n existingId: string;\n /** Similarity score (0-1) */\n similarity: number;\n /** Recommended action */\n action: \"skip\" | \"merge\" | \"keep\";\n}\n\nexport interface ContradictionResult {\n /** New statement */\n newStatement: CuratedStatement;\n /** Conflicting memory ID */\n conflictingId: string;\n /** The conflicting content */\n conflictingContent: string;\n /** Severity */\n severity: \"high\" | \"medium\" | \"low\";\n}\n\n// ── Main function ────────────────────────────────────────────────────────────\n\nexport async function curate(options: CurateOptions): Promise<CurateResult> {\n const startTime = Date.now();\n const {\n targetPath,\n memoryDir,\n source = \"curation\",\n category: categoryOverride,\n confidence = 0.9,\n entityRef,\n tags = [],\n checkDuplicates = true,\n checkContradictions = false,\n write = true,\n } = options;\n\n const statements: CuratedStatement[] = [];\n const written: string[] = [];\n const duplicates: DuplicateResult[] = [];\n const contradictions: ContradictionResult[] = [];\n let filesProcessed = 0;\n let filesSkipped = 0;\n\n // Determine targets\n const targets = resolveTargets(targetPath);\n const provenanceRoot = resolveProvenanceRoot(targetPath);\n\n // Load existing memories for dedup/contradiction checks\n const existingMemories = checkDuplicates || checkContradictions\n ? loadExistingMemories(memoryDir)\n : new Map();\n\n // Process each file\n for (const filePath of targets) {\n const content = readFileSafe(filePath);\n if (!content) {\n filesSkipped++;\n continue;\n }\n\n if (isBinary(content)) {\n filesSkipped++;\n continue;\n }\n\n filesProcessed++;\n\n const sourceFileHash = hashContent(content);\n const fileStatements = extractStatements(\n content,\n filePath,\n provenanceRoot,\n source,\n sourceFileHash,\n categoryOverride,\n confidence,\n entityRef,\n tags,\n );\n\n for (const stmt of fileStatements) {\n // Dedup check\n if (checkDuplicates) {\n const dup = findDuplicate(stmt, existingMemories);\n if (dup) {\n duplicates.push(dup);\n if (dup.action === \"skip\") continue;\n }\n }\n\n // Contradiction check\n if (checkContradictions) {\n const contra = findContradiction(stmt, existingMemories);\n if (contra) {\n contradictions.push(contra);\n }\n }\n\n statements.push(stmt);\n\n // Write to memory\n if (write) {\n const writtenPath = writeStatement(stmt, memoryDir);\n written.push(writtenPath);\n existingMemories.set(stmt.contentHash, {\n id: stmt.id,\n content: stmt.content,\n category: stmt.category,\n });\n }\n }\n }\n\n return {\n statements,\n filesProcessed,\n filesSkipped,\n duplicates,\n contradictions,\n written,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Target resolution ────────────────────────────────────────────────────────\n\nfunction resolveTargets(targetPath: string): string[] {\n const stat = fs.statSync(targetPath);\n if (stat.isFile()) return [targetPath];\n\n // Directory — walk for .md, .txt, .mdx\n const results: string[] = [];\n const extensions = new Set([\".md\", \".txt\", \".mdx\", \".rst\"]);\n\n function walk(dir: string): void {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (entry.name !== \"node_modules\" && entry.name !== \".git\") {\n walk(fullPath);\n }\n } else if (extensions.has(path.extname(entry.name).toLowerCase())) {\n results.push(fullPath);\n }\n }\n }\n\n walk(targetPath);\n return results;\n}\n\nfunction resolveProvenanceRoot(targetPath: string): string {\n const resolvedTarget = path.resolve(targetPath);\n const stat = fs.statSync(resolvedTarget);\n return stat.isFile() ? path.dirname(resolvedTarget) : resolvedTarget;\n}\n\n// ── Statement extraction ─────────────────────────────────────────────────────\n\nfunction extractStatements(\n content: string,\n filePath: string,\n projectRoot: string,\n source: string,\n sourceFileHash: string,\n categoryOverride: string | undefined,\n confidence: number,\n entityRef: string | undefined,\n tags: string[],\n): CuratedStatement[] {\n const relativePath = path.relative(projectRoot, path.resolve(filePath)) || path.basename(filePath);\n const statements: CuratedStatement[] = [];\n const now = new Date().toISOString();\n\n // Split content into paragraphs/lines and extract meaningful statements\n const paragraphs = content\n .split(/\\n{2,}/)\n .map((p) => p.trim())\n .filter((p) => p.length > 20 && p.length < 2000);\n\n // Also extract list items\n const listItems = content\n .split(\"\\n\")\n .filter((l) => /^\\s*[-*]\\s+/.test(l))\n .map((l) => l.replace(/^\\s*[-*]\\s+/, \"\").trim())\n .filter((l) => l.length > 10 && l.length < 500);\n\n const allItems = [...paragraphs, ...listItems];\n\n // Deduplicate within file\n const seen = new Set<string>();\n for (const item of allItems) {\n const hash = hashContent(item.toLowerCase());\n if (seen.has(hash)) continue;\n seen.add(hash);\n\n const id = generateId();\n const category = categoryOverride ?? detectCategory(item);\n\n statements.push({\n id,\n content: item,\n category,\n confidence,\n provenance: {\n sourcePath: filePath,\n relativePath,\n source,\n lineNumber: 0,\n ingestedAt: now,\n sourceFileHash,\n },\n contentHash: hash,\n tags: [...tags],\n entityRef,\n });\n }\n\n return statements;\n}\n\n// ── Category detection ───────────────────────────────────────────────────────\n\nfunction detectCategory(text: string): string {\n const lower = text.toLowerCase();\n\n if (/^(always|never|must|should|don't|avoid|ensure)/.test(lower)) return \"principle\";\n if (/^(we|team|project)\\s+(decided|chose|will|use)/.test(lower)) return \"decision\";\n if (/^(i|we)\\s+(prefer|like|want|hate|dislike)/.test(lower)) return \"preference\";\n if (/fix|bug|issue|broken|error/i.test(lower)) return \"correction\";\n if (/\\?.+$/.test(lower.trim())) return \"question\";\n\n return \"fact\";\n}\n\n// ── Dedup ────────────────────────────────────────────────────────────────────\n\ninterface ExistingMemory {\n id: string;\n content: string;\n category: string;\n}\n\nfunction findDuplicate(\n stmt: CuratedStatement,\n existing: Map<string, ExistingMemory>,\n): DuplicateResult | null {\n const stmtLower = stmt.content.toLowerCase();\n\n // Exact hash match\n const exactMatch = existing.get(stmt.contentHash);\n if (exactMatch) {\n return {\n newStatement: stmt,\n existingId: exactMatch.id,\n similarity: 1,\n action: \"skip\",\n };\n }\n\n // Fuzzy match — check substring containment\n for (const [_, mem] of existing) {\n const memLower = mem.content.toLowerCase();\n if (memLower.length > 50 && stmtLower.length > 50) {\n // Check if one contains the other\n if (memLower.includes(stmtLower.slice(0, 40)) || stmtLower.includes(memLower.slice(0, 40))) {\n return {\n newStatement: stmt,\n existingId: mem.id,\n similarity: 0.85,\n action: \"skip\",\n };\n }\n }\n }\n\n return null;\n}\n\n// ── Contradiction detection ──────────────────────────────────────────────────\n\nfunction findContradiction(\n stmt: CuratedStatement,\n existing: Map<string, ExistingMemory>,\n): ContradictionResult | null {\n const negationPatterns = [\n /\\b(not|don't|doesn't|isn't|aren't|won't|can't|never|no)\\b/i,\n ];\n\n const hasNegation = negationPatterns.some((p) => p.test(stmt.content));\n if (!hasNegation) return null;\n\n // Strip negation and look for positive version\n const stripped = stmt.content\n .toLowerCase()\n .replace(/\\b(not|don't|doesn't|isn't|aren't|won't|can't|never|no)\\b/gi, \"\")\n .trim();\n\n if (stripped.length < 20) return null;\n\n for (const [_, mem] of existing) {\n const memLower = mem.content.toLowerCase();\n // If an existing memory affirms what this statement negates\n if (memLower.includes(stripped.slice(0, Math.min(30, stripped.length)))) {\n return {\n newStatement: stmt,\n conflictingId: mem.id,\n conflictingContent: mem.content,\n severity: \"high\",\n };\n }\n }\n\n return null;\n}\n\n// ── Memory loading ───────────────────────────────────────────────────────────\n\nfunction loadExistingMemories(memoryDir: string): Map<string, ExistingMemory> {\n const result = new Map<string, ExistingMemory>();\n if (!fs.existsSync(memoryDir)) return result;\n\n // Walk all known category dirs for existing memories\n const dirs = ALL_CATEGORY_DIRS;\n for (const dir of dirs) {\n const fullDir = path.join(memoryDir, dir);\n if (!fs.existsSync(fullDir)) continue;\n\n walkFiles(fullDir, (filePath) => {\n const content = readFileSafe(filePath);\n if (!content) return;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id || !body) return;\n\n const hash = hashContent(body.toLowerCase());\n result.set(hash, {\n id: fm.id,\n content: body,\n category: fm.category ?? dir.slice(0, -1),\n });\n });\n }\n\n return result;\n}\n\n// ── Writing ──────────────────────────────────────────────────────────────────\n\nfunction writeStatement(stmt: CuratedStatement, memoryDir: string): string {\n const now = new Date();\n const dateDir = now.toISOString().split(\"T\")[0];\n const categoryDir = getCategoryDir(memoryDir, stmt.category);\n\n const dir = path.join(categoryDir, dateDir);\n fs.mkdirSync(dir, { recursive: true });\n\n const fileName = `${stmt.category}-${Date.now()}-${stmt.id.slice(0, 8)}.md`;\n const filePath = path.join(dir, fileName);\n\n const frontmatter = [\n \"---\",\n `id: ${stmt.id}`,\n `category: ${stmt.category}`,\n `created: ${stmt.provenance.ingestedAt}`,\n `updated: ${stmt.provenance.ingestedAt}`,\n `confidence: ${stmt.confidence}`,\n `confidenceTier: ${tierFromConfidence(stmt.confidence)}`,\n `source: ${stmt.provenance.source}`,\n `tags: ${JSON.stringify(stmt.tags)}`,\n stmt.entityRef ? `entityRef: ${stmt.entityRef}` : null,\n `provenanceFile: ${stmt.provenance.relativePath}`,\n `provenanceHash: ${stmt.provenance.sourceFileHash}`,\n \"---\",\n ]\n .filter(Boolean)\n .join(\"\\n\");\n\n const body = `${frontmatter}\\n\\n${stmt.content}\\n`;\n\n fs.writeFileSync(filePath, body);\n return filePath;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction generateId(): string {\n return crypto.randomUUID();\n}\n\nfunction hashContent(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\nfunction tierFromConfidence(confidence: number): string {\n if (confidence >= 0.95) return \"explicit\";\n if (confidence >= 0.8) return \"high\";\n if (confidence >= 0.5) return \"medium\";\n return \"low\";\n}\n\nfunction readFileSafe(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction isBinary(content: string): boolean {\n // Simple heuristic: if content has null bytes, it's binary\n for (let i = 0; i < Math.min(content.length, 8000); i++) {\n if (content.charCodeAt(i) === 0) return true;\n }\n return false;\n}\n\ninterface SimpleFrontmatter {\n id?: string;\n category?: string;\n [key: string]: unknown;\n}\n\nfunction parseFrontmatter(content: string): SimpleFrontmatter | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fm: SimpleFrontmatter = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n (fm as Record<string, unknown>)[key] = value;\n }\n return fm;\n}\n\nfunction extractBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n([\\s\\S]*)/);\n return match ? match[1].trim() : content.trim();\n}\n\nfunction walkFiles(dir: string, callback: (filePath: string) => void): void {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walkFiles(fullPath, callback);\n } else if (entry.name.endsWith(\".md\")) {\n callback(fullPath);\n }\n }\n}\n","/**\n * @remnic/core — Dedup & Contradiction Detection\n *\n * Statement-level deduplication and contradiction detection\n * against existing memories. Can be used standalone or via curation.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { ALL_CATEGORY_DIRS } from \"../utils/category-dir.js\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface MemoryEntry {\n /** Memory ID */\n id: string;\n /** Content text */\n content: string;\n /** Category */\n category: string;\n /** File path (if known) */\n filePath?: string;\n}\n\nexport interface DedupOptions {\n /** Memory root directory */\n memoryDir: string;\n /** Categories to scan (default: all) */\n categories?: string[];\n /** Similarity threshold for fuzzy matching (0-1, default: 0.85) */\n threshold?: number;\n /** Max memories to load (default: 10000) */\n maxLoad?: number;\n}\n\nexport interface DedupResult {\n /** Total memories scanned */\n scanned: number;\n /** Duplicate pairs found */\n duplicates: DuplicatePair[];\n /** Duration in ms */\n durationMs: number;\n}\n\nexport interface DuplicatePair {\n /** First memory */\n left: MemoryEntry;\n /** Second memory */\n right: MemoryEntry;\n /** Similarity score */\n similarity: number;\n /** Recommended action */\n action: \"merge\" | \"keep_left\" | \"keep_right\";\n}\n\nexport interface ContradictionOptions {\n /** Memory root directory */\n memoryDir: string;\n /** Categories to scan (default: all) */\n categories?: string[];\n /** Max memories to load (default: 10000) */\n maxLoad?: number;\n}\n\nexport interface ContradictionResult {\n /** Total memories scanned */\n scanned: number;\n /** Contradictions found */\n contradictions: ContradictionPair[];\n /** Duration in ms */\n durationMs: number;\n}\n\nexport interface ContradictionPair {\n /** First statement */\n left: MemoryEntry;\n /** Contradicting statement */\n right: MemoryEntry;\n /** Severity */\n severity: \"high\" | \"medium\" | \"low\";\n /** Reason */\n reason: string;\n}\n\n// ── Main functions ───────────────────────────────────────────────────────────\n\nconst DEFAULT_DEDUP_THRESHOLD = 0.85;\nconst DEFAULT_MAX_LOAD = 10000;\n\nfunction normalizeThreshold(value: number | undefined, defaultValue: number): number {\n return typeof value === \"number\" &&\n Number.isFinite(value) &&\n value >= 0 &&\n value <= 1\n ? value\n : defaultValue;\n}\n\nfunction normalizeMaxLoad(value: number | undefined, defaultValue: number): number {\n return typeof value === \"number\" &&\n Number.isInteger(value) &&\n value >= 0\n ? value\n : defaultValue;\n}\n\nexport function findDuplicates(options: DedupOptions): DedupResult {\n const startTime = Date.now();\n const { memoryDir } = options;\n const threshold = normalizeThreshold(options.threshold, DEFAULT_DEDUP_THRESHOLD);\n const maxLoad = normalizeMaxLoad(options.maxLoad, DEFAULT_MAX_LOAD);\n\n const memories = loadMemories(memoryDir, options.categories, maxLoad);\n const duplicates: DuplicatePair[] = [];\n\n // Compare all pairs (O(n^2) but bounded by maxLoad)\n for (let i = 0; i < memories.length; i++) {\n for (let j = i + 1; j < memories.length; j++) {\n const sim = computeSimilarity(memories[i].content, memories[j].content);\n if (sim >= threshold) {\n duplicates.push({\n left: memories[i],\n right: memories[j],\n similarity: sim,\n action: sim >= 0.98 ? \"merge\" : sim >= 0.9 ? \"keep_right\" : \"keep_left\",\n });\n }\n }\n }\n\n return {\n scanned: memories.length,\n duplicates,\n durationMs: Date.now() - startTime,\n };\n}\n\nexport function findContradictions(options: ContradictionOptions): ContradictionResult {\n const startTime = Date.now();\n const { memoryDir } = options;\n const maxLoad = normalizeMaxLoad(options.maxLoad, DEFAULT_MAX_LOAD);\n\n const memories = loadMemories(memoryDir, options.categories, maxLoad);\n const contradictions: ContradictionPair[] = [];\n\n for (let i = 0; i < memories.length; i++) {\n for (let j = i + 1; j < memories.length; j++) {\n const contra = detectContradiction(memories[i], memories[j]);\n if (contra) {\n contradictions.push(contra);\n }\n }\n }\n\n return {\n scanned: memories.length,\n contradictions,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Similarity computation ───────────────────────────────────────────────────\n\nfunction computeSimilarity(a: string, b: string): number {\n // Normalize\n const normA = normalize(a);\n const normB = normalize(b);\n\n // Exact match\n if (normA === normB) return 1;\n\n // Hash-based exact match\n if (hashContent(normA) === hashContent(normB)) return 0.99;\n\n // Substring containment\n if (normA.length > 50 && normB.length > 50) {\n if (normA.includes(normB.slice(0, 40)) || normB.includes(normA.slice(0, 40))) {\n return 0.9;\n }\n }\n\n // Word overlap (Jaccard)\n const wordsA = new Set(normA.split(/\\s+/));\n const wordsB = new Set(normB.split(/\\s+/));\n const intersection = new Set([...wordsA].filter((w) => wordsB.has(w)));\n const union = new Set([...wordsA, ...wordsB]);\n\n if (union.size === 0) return 0;\n return intersection.size / union.size;\n}\n\nfunction normalize(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^\\w\\s']/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n// ── Contradiction detection ──────────────────────────────────────────────────\n\nconst NEGATION_WORDS = new Set([\n \"not\", \"don't\", \"doesn't\", \"isn't\", \"aren't\", \"won't\", \"can't\", \"cannot\",\n \"never\", \"no\", \"none\", \"neither\", \"nor\", \"nothing\", \"nowhere\",\n]);\n\nfunction detectContradiction(\n a: MemoryEntry,\n b: MemoryEntry,\n): ContradictionPair | null {\n const normA = normalize(a.content);\n const normB = normalize(b.content);\n\n // Check if one has negation and the other doesn't\n const aHasNegation = containsNegation(normA);\n const bHasNegation = containsNegation(normB);\n\n if (aHasNegation === bHasNegation) return null;\n\n // Strip negation and compare core content\n const strippedA = stripNegation(normA);\n const strippedB = stripNegation(normB);\n\n const sim = computeSimilarity(strippedA, strippedB);\n if (sim < 0.7) return null;\n\n // Check for opposite quantifiers\n const oppQuantifiers = [\n [\"always\", \"never\"],\n [\"all\", \"none\"],\n [\"every\", \"no\"],\n [\"must\", \"must not\"],\n [\"should\", \"should not\"],\n [\"can\", \"cannot\"],\n ];\n\n for (const [pos, neg] of oppQuantifiers) {\n if (\n (a.content.toLowerCase().includes(pos) && b.content.toLowerCase().includes(neg)) ||\n (a.content.toLowerCase().includes(neg) && b.content.toLowerCase().includes(pos))\n ) {\n return {\n left: a,\n right: b,\n severity: \"high\",\n reason: `Opposite quantifiers: \"${pos}\" vs \"${neg}\"`,\n };\n }\n }\n\n return {\n left: a,\n right: b,\n severity: sim >= 0.85 ? \"high\" : \"medium\",\n reason: \"Negated version of similar content\",\n };\n}\n\nfunction containsNegation(text: string): boolean {\n const words = text.split(/\\s+/);\n return words.some((w) => NEGATION_WORDS.has(w));\n}\n\nfunction stripNegation(text: string): string {\n return text\n .replace(/\\b(not|don't|doesn't|isn't|aren't|won't|can't|cannot|never|no|none|neither|nor|nothing|nowhere)\\b/gi, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n// ── Memory loading ───────────────────────────────────────────────────────────\n\nfunction loadMemories(\n memoryDir: string,\n categories?: string[],\n maxLoad = 10000,\n): MemoryEntry[] {\n const result: MemoryEntry[] = [];\n const allCategories = categories ?? ALL_CATEGORY_DIRS;\n if (!fs.existsSync(memoryDir)) return result;\n const memoryRootReal = fs.realpathSync(memoryDir);\n\n for (const category of allCategories) {\n if (result.length >= maxLoad) break;\n\n const dir = path.join(memoryDir, category);\n if (!fs.existsSync(dir)) continue;\n const categoryStat = fs.lstatSync(dir);\n if (categoryStat.isSymbolicLink()) {\n throw new Error(`Refusing to scan symlinked memory category directory: ${dir}`);\n }\n if (!categoryStat.isDirectory()) continue;\n const categoryRootReal = fs.realpathSync(dir);\n assertPathInsideRoot(memoryRootReal, categoryRootReal, dir);\n\n walkMdFiles(dir, memoryRootReal, categoryRootReal, (filePath) => {\n if (result.length >= maxLoad) return;\n\n const content = readFileSafe(filePath, memoryRootReal, categoryRootReal);\n if (!content) return;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id || !body) return;\n\n result.push({\n id: fm.id as string,\n content: body,\n category: (fm.category as string) ?? category.slice(0, -1),\n filePath,\n });\n });\n }\n\n return result;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction hashContent(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\nfunction readFileSafe(\n filePath: string,\n memoryRootReal: string,\n categoryRootReal: string,\n): string | null {\n try {\n const fileStat = fs.lstatSync(filePath);\n if (fileStat.isSymbolicLink()) {\n throw new Error(`Refusing to read symlinked memory file: ${filePath}`);\n }\n const fileReal = fs.realpathSync(filePath);\n assertPathInsideRoot(memoryRootReal, fileReal, filePath);\n assertPathInsideRoot(categoryRootReal, fileReal, filePath);\n return fs.readFileSync(filePath, \"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction parseFrontmatter(content: string): Record<string, unknown> | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fm: Record<string, unknown> = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n fm[key] = value;\n }\n return fm;\n}\n\nfunction extractBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n([\\s\\S]*)/);\n return match ? match[1].trim() : content.trim();\n}\n\nfunction assertPathInsideRoot(rootReal: string, targetReal: string, sourcePath: string): void {\n const rel = path.relative(rootReal, targetReal);\n if (rel === \"\" || (!rel.startsWith(\"..\") && !path.isAbsolute(rel))) {\n return;\n }\n throw new Error(`Refusing to scan memory path outside root: ${sourcePath}`);\n}\n\nfunction walkMdFiles(\n dir: string,\n memoryRootReal: string,\n categoryRootReal: string,\n callback: (filePath: string) => void,\n): void {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n const entryStat = fs.lstatSync(fullPath);\n if (entryStat.isSymbolicLink()) {\n throw new Error(`Refusing to scan symlinked memory path: ${fullPath}`);\n }\n const entryReal = fs.realpathSync(fullPath);\n assertPathInsideRoot(memoryRootReal, entryReal, fullPath);\n assertPathInsideRoot(categoryRootReal, entryReal, fullPath);\n if (entryStat.isDirectory()) {\n walkMdFiles(fullPath, memoryRootReal, categoryRootReal, callback);\n } else if (entry.name.endsWith(\".md\")) {\n callback(fullPath);\n }\n }\n}\n","/**\n * @remnic/core — Review Inbox\n *\n * Manages low-confidence memories and suggestions pending review.\n * Integrates with the existing review-queue system.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { getCategoryDir, ALL_CATEGORY_DIRS } from \"../utils/category-dir.js\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface ReviewItem {\n /** Memory ID */\n id: string;\n /** Content text */\n content: string;\n /** Category */\n category: string;\n /** Confidence score (0-1) */\n confidence: number;\n /** Confidence tier */\n confidenceTier: string;\n /** Source */\n source: string;\n /** File path if available */\n filePath?: string;\n /** Created date */\n created: string;\n /** Reason it's in review */\n reviewReason: \"low_confidence\" | \"suggestion\" | \"contradiction\" | \"duplicate\";\n /** Additional context */\n context?: string;\n}\n\nexport type ReviewAction = \"approve\" | \"dismiss\" | \"flag\";\n\nexport interface ReviewResult {\n /** Item acted upon */\n itemId: string;\n /** Action taken */\n action: ReviewAction;\n /** Updated file path (if modified) */\n updatedPath?: string;\n /** Status message */\n message: string;\n}\n\nexport interface ReviewListResult {\n /** Items pending review */\n items: ReviewItem[];\n /** Total count */\n total: number;\n /** Duration in ms */\n durationMs: number;\n}\n\nexport interface ReviewOptions {\n /** Memory root directory */\n memoryDir: string;\n /** Filter by reason */\n reason?: ReviewItem[\"reviewReason\"];\n /** Max items to return (default: 50) */\n limit?: number;\n /** Include items with confidence below this threshold (default: 0.7) */\n confidenceThreshold?: number;\n}\n\nexport interface ReviewActionOptions {\n /** Match the threshold used when listing review items (default: 0.7) */\n confidenceThreshold?: number;\n}\n\ninterface ReviewFileMatch {\n filePath: string;\n location: \"queue\" | \"category\";\n}\n\nconst DEFAULT_CONFIDENCE_THRESHOLD = 0.7;\n\nfunction realMemoryRoot(memoryDir: string): string | null {\n try {\n const stat = fs.lstatSync(memoryDir);\n if (!stat.isDirectory() || stat.isSymbolicLink()) return null;\n return fs.realpathSync(memoryDir);\n } catch {\n return null;\n }\n}\n\nfunction isPathInside(rootReal: string, candidateReal: string): boolean {\n const relative = path.relative(rootReal, candidateReal);\n return relative === \"\" || (!!relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nfunction isSafeDirectory(rootReal: string, dir: string): boolean {\n try {\n const stat = fs.lstatSync(dir);\n if (!stat.isDirectory() || stat.isSymbolicLink()) return false;\n return isPathInside(rootReal, fs.realpathSync(dir));\n } catch {\n return false;\n }\n}\n\nfunction ensureSafeDirectory(rootReal: string, dir: string): void {\n if (fs.existsSync(dir)) {\n if (!isSafeDirectory(rootReal, dir)) {\n throw new Error(`Refusing to write through unsafe review path: ${dir}`);\n }\n return;\n }\n fs.mkdirSync(dir, { recursive: true });\n if (!isSafeDirectory(rootReal, dir)) {\n throw new Error(`Refusing to write through unsafe review path: ${dir}`);\n }\n}\n\n// ── Main functions ───────────────────────────────────────────────────────────\n\n/**\n * List items pending review.\n */\nexport function listReviewItems(options: ReviewOptions): ReviewListResult {\n const startTime = Date.now();\n const {\n memoryDir,\n reason: filterReason,\n limit = 50,\n confidenceThreshold = DEFAULT_CONFIDENCE_THRESHOLD,\n } = options;\n const maxItems = Math.max(0, limit);\n const rootReal = realMemoryRoot(memoryDir);\n if (!rootReal || maxItems === 0) {\n return { items: [], total: 0, durationMs: Date.now() - startTime };\n }\n\n const items: ReviewItem[] = [];\n const isLimitReached = (): boolean => items.length >= maxItems;\n const addItem = (item: ReviewItem): void => {\n if (isLimitReached()) return;\n if (filterReason && item.reviewReason !== filterReason) return;\n items.push(item);\n };\n\n // Check suggestions directory\n const suggestionsDir = path.join(memoryDir, \"suggestions\");\n if (!isLimitReached() && fs.existsSync(suggestionsDir) && isSafeDirectory(rootReal, suggestionsDir)) {\n walkMd(rootReal, suggestionsDir, (filePath, content) => {\n if (isLimitReached()) return true;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id) return false;\n\n addItem({\n id: fm.id as string,\n content: body,\n category: (fm.category as string) ?? \"suggestion\",\n confidence: parseConfidence(fm.confidence, 0.5),\n confidenceTier: (fm.confidenceTier as string) ?? \"low\",\n source: (fm.source as string) ?? \"unknown\",\n filePath,\n created: (fm.created as string) ?? new Date().toISOString(),\n reviewReason: \"suggestion\",\n });\n return isLimitReached();\n });\n }\n\n // Check review directory\n const reviewDir = path.join(memoryDir, \"review\");\n if (!isLimitReached() && fs.existsSync(reviewDir) && isSafeDirectory(rootReal, reviewDir)) {\n walkMd(rootReal, reviewDir, (filePath, content) => {\n if (isLimitReached()) return true;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id) return false;\n\n addItem({\n id: fm.id as string,\n content: body,\n category: (fm.category as string) ?? \"review\",\n confidence: parseConfidence(fm.confidence, 0.5),\n confidenceTier: (fm.confidenceTier as string) ?? \"low\",\n source: (fm.source as string) ?? \"unknown\",\n filePath,\n created: (fm.created as string) ?? new Date().toISOString(),\n reviewReason: (fm.reviewReason as ReviewItem[\"reviewReason\"]) ?? \"low_confidence\",\n context: fm.context as string | undefined,\n });\n return isLimitReached();\n });\n }\n\n // Scan all categories for low-confidence items\n const categories = ALL_CATEGORY_DIRS;\n for (const category of categories) {\n if (isLimitReached()) break;\n\n const dir = path.join(memoryDir, category);\n if (!fs.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;\n\n walkMd(rootReal, dir, (filePath, content) => {\n if (isLimitReached()) return true;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id) return false;\n\n const confidence = parseConfidence(fm.confidence, 1);\n if (confidence >= confidenceThreshold) return false;\n if (parseBoolean(fm.reviewDismissed)) return false;\n\n // Skip if already in items\n if (items.some((i) => i.id === fm.id)) return false;\n\n addItem({\n id: fm.id as string,\n content: body,\n category: (fm.category as string) ?? category.slice(0, -1),\n confidence,\n confidenceTier: (fm.confidenceTier as string) ?? \"low\",\n source: (fm.source as string) ?? \"unknown\",\n filePath,\n created: (fm.created as string) ?? new Date().toISOString(),\n reviewReason: \"low_confidence\",\n });\n return isLimitReached();\n });\n }\n\n return {\n items,\n total: items.length,\n durationMs: Date.now() - startTime,\n };\n}\n\n/**\n * Perform a review action on an item.\n */\nexport function performReview(\n memoryDir: string,\n itemId: string,\n action: ReviewAction,\n options: ReviewActionOptions = {},\n): ReviewResult {\n switch (action) {\n case \"approve\":\n return approveItem(memoryDir, itemId, options);\n case \"dismiss\":\n return dismissItem(memoryDir, itemId, options);\n case \"flag\":\n return flagItem(memoryDir, itemId, options);\n }\n}\n\n// ── Actions ──────────────────────────────────────────────────────────────────\n\nfunction approveItem(\n memoryDir: string,\n itemId: string,\n options: ReviewActionOptions,\n): ReviewResult {\n const rootReal = realMemoryRoot(memoryDir);\n if (!rootReal) return { itemId, action: \"approve\", message: \"Item not found\" };\n const found = findReviewFileById(memoryDir, itemId, options);\n if (!found) {\n return { itemId, action: \"approve\", message: \"Item not found\" };\n }\n\n const content = fs.readFileSync(found.filePath, \"utf8\");\n const fm = parseFrontmatter(content);\n if (!fm) return { itemId, action: \"approve\", message: \"Could not parse frontmatter\" };\n\n const updatedContent = updateFrontmatterFields(content, {\n confidence: \"0.9\",\n confidenceTier: \"high\",\n reviewDismissed: null,\n });\n\n if (found.location === \"category\") {\n fs.writeFileSync(found.filePath, updatedContent, \"utf8\");\n return {\n itemId,\n action: \"approve\",\n updatedPath: found.filePath,\n message: \"Approved low-confidence memory in place with confidence 0.9\",\n };\n }\n\n // Promote queued suggestions/review items to their category directory.\n const category = (fm.category as string) ?? \"fact\";\n const targetDir = getCategoryDir(memoryDir, category);\n const dateDir = new Date().toISOString().split(\"T\")[0];\n ensureSafeDirectory(rootReal, targetDir);\n const outputPath = path.join(targetDir, dateDir, path.basename(found.filePath));\n\n ensureSafeDirectory(rootReal, path.dirname(outputPath));\n const promotedPath = writeFileWithoutClobber(outputPath, updatedContent, itemId);\n\n // Remove from review\n fs.unlinkSync(found.filePath);\n\n return {\n itemId,\n action: \"approve\",\n updatedPath: promotedPath,\n message: `Promoted to ${category} with confidence 0.9`,\n };\n}\n\nfunction dismissItem(\n memoryDir: string,\n itemId: string,\n options: ReviewActionOptions,\n): ReviewResult {\n const found = findReviewFileById(memoryDir, itemId, options);\n if (!found) {\n return { itemId, action: \"dismiss\", message: \"Item not found\" };\n }\n\n if (found.location === \"queue\") {\n fs.unlinkSync(found.filePath);\n return { itemId, action: \"dismiss\", message: \"Dismissed and removed\" };\n }\n\n const content = fs.readFileSync(found.filePath, \"utf8\");\n fs.writeFileSync(\n found.filePath,\n updateFrontmatterFields(content, {\n reviewDismissed: \"true\",\n reviewDismissedAt: new Date().toISOString(),\n }),\n \"utf8\",\n );\n return {\n itemId,\n action: \"dismiss\",\n updatedPath: found.filePath,\n message: \"Dismissed low-confidence memory in place\",\n };\n}\n\nfunction flagItem(\n memoryDir: string,\n itemId: string,\n options: ReviewActionOptions,\n): ReviewResult {\n const found = findReviewFileById(memoryDir, itemId, options);\n if (!found) {\n return { itemId, action: \"flag\", message: \"Item not found\" };\n }\n\n const content = fs.readFileSync(found.filePath, \"utf8\");\n const fixed = updateFrontmatterFields(content, {\n flagged: \"true\",\n flaggedAt: new Date().toISOString(),\n });\n fs.writeFileSync(found.filePath, fixed);\n return {\n itemId,\n action: \"flag\",\n updatedPath: found.filePath,\n message: \"Flagged for further review\",\n };\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction findReviewFileById(\n memoryDir: string,\n id: string,\n options: ReviewActionOptions = {},\n): ReviewFileMatch | null {\n const rootReal = realMemoryRoot(memoryDir);\n if (!rootReal) return null;\n for (const loc of [\"suggestions\", \"review\"]) {\n const dir = path.join(memoryDir, loc);\n if (!fs.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;\n\n const found = findFileById(rootReal, dir, id);\n if (found) return { filePath: found, location: \"queue\" };\n }\n\n for (const category of ALL_CATEGORY_DIRS) {\n const dir = path.join(memoryDir, category);\n if (!fs.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;\n\n const found = findFileById(rootReal, dir, id, (fm) => isLowConfidenceReviewCandidate(fm, options));\n if (found) return { filePath: found, location: \"category\" };\n }\n\n return null;\n}\n\nfunction findFileById(\n rootReal: string,\n dir: string,\n id: string,\n include?: (frontmatter: Record<string, unknown>) => boolean,\n): string | null {\n const files = walkMdPaths(rootReal, dir);\n for (const filePath of files) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n const fm = parseFrontmatter(content);\n if (fm?.id === id && (!include || include(fm))) return filePath;\n }\n return null;\n}\n\nfunction isLowConfidenceReviewCandidate(\n fm: Record<string, unknown>,\n options: ReviewActionOptions,\n): boolean {\n const threshold = options.confidenceThreshold ?? DEFAULT_CONFIDENCE_THRESHOLD;\n return (\n parseConfidence(fm.confidence, 1) < threshold &&\n !parseBoolean(fm.reviewDismissed)\n );\n}\n\nfunction parseBoolean(value: unknown): boolean {\n if (typeof value === \"boolean\") return value;\n if (typeof value !== \"string\") return false;\n const normalized = value.trim().toLowerCase();\n return normalized === \"true\" || normalized === \"1\" || normalized === \"yes\";\n}\n\nfunction parseConfidence(value: unknown, fallback: number): number {\n if (typeof value === \"number\") return Number.isFinite(value) ? value : fallback;\n if (typeof value === \"string\") {\n const n = parseFloat(value);\n return Number.isFinite(n) ? n : fallback;\n }\n return fallback;\n}\n\nfunction updateFrontmatterFields(\n content: string,\n fields: Record<string, string | null>,\n): string {\n const match = content.match(/^(---\\n)([\\s\\S]*?)(\\n---(?:\\n|$))/);\n if (!match) return content;\n\n const seen = new Set<string>();\n const lines = match[2].split(\"\\n\");\n const nextLines: string[] = [];\n for (const line of lines) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) {\n nextLines.push(line);\n continue;\n }\n const key = line.slice(0, colonIdx).trim();\n if (!Object.prototype.hasOwnProperty.call(fields, key)) {\n nextLines.push(line);\n continue;\n }\n seen.add(key);\n const value = fields[key];\n if (value !== null) {\n nextLines.push(`${key}: ${value}`);\n }\n }\n\n for (const [key, value] of Object.entries(fields)) {\n if (value !== null && !seen.has(key)) {\n nextLines.push(`${key}: ${value}`);\n }\n }\n\n return `${match[1]}${nextLines.join(\"\\n\")}${match[3]}${content.slice(match[0].length)}`;\n}\n\nfunction readFileSafe(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction writeFileWithoutClobber(basePath: string, content: string, discriminator: string): string {\n const parsed = path.parse(basePath);\n const safeDiscriminator = sanitizeFilePart(discriminator);\n\n for (let attempt = 0; attempt < 1000; attempt++) {\n const candidate = attempt === 0\n ? basePath\n : path.join(\n parsed.dir,\n `${parsed.name}-${safeDiscriminator}${attempt === 1 ? \"\" : `-${attempt}`}${parsed.ext || \".md\"}`,\n );\n\n try {\n fs.writeFileSync(candidate, content, { encoding: \"utf8\", flag: \"wx\" });\n return candidate;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") continue;\n throw error;\n }\n }\n\n throw new Error(`Could not find a free review promotion path for ${basePath}`);\n}\n\nfunction sanitizeFilePart(value: string): string {\n const chars: string[] = [];\n let previousWasDash = false;\n\n for (const char of value) {\n const next = isSafeFilePartChar(char) ? char : \"-\";\n if (next === \"-\" && previousWasDash) continue;\n chars.push(next);\n previousWasDash = next === \"-\";\n if (chars.length >= 64) break;\n }\n\n let start = 0;\n let end = chars.length;\n while (start < end && chars[start] === \"-\") start++;\n while (end > start && chars[end - 1] === \"-\") end--;\n\n const sanitized = chars.slice(start, end).join(\"\");\n return sanitized || \"review-item\";\n}\n\nfunction isSafeFilePartChar(value: string): boolean {\n if (value.length !== 1) return false;\n const code = value.charCodeAt(0);\n return (\n (code >= 48 && code <= 57) ||\n (code >= 65 && code <= 90) ||\n (code >= 97 && code <= 122) ||\n value === \".\" ||\n value === \"_\" ||\n value === \"-\"\n );\n}\n\nfunction parseFrontmatter(content: string): Record<string, unknown> | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fm: Record<string, unknown> = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n fm[key] = value;\n }\n return fm;\n}\n\nfunction extractBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n([\\s\\S]*)/);\n return match ? match[1].trim() : content.trim();\n}\n\nfunction walkMd(rootReal: string, dir: string, callback: (filePath: string, content: string) => boolean | void): boolean {\n if (!isSafeDirectory(rootReal, dir)) return false;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n if (walkMd(rootReal, fullPath, callback)) return true;\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n const content = readFileSafe(fullPath);\n if (content && callback(fullPath, content) === true) return true;\n }\n }\n return false;\n}\n\nfunction walkMdPaths(rootReal: string, dir: string): string[] {\n const results: string[] = [];\n if (!isSafeDirectory(rootReal, dir)) return results;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n results.push(...walkMdPaths(rootReal, fullPath));\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n results.push(fullPath);\n }\n }\n return results;\n}\n","/**\n * @remnic/core — Diff-Aware Sync\n *\n * Watches source files for changes and triggers re-ingestion\n * only for changed content. Uses file hashing to detect changes.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface SyncOptions {\n /** Source directory to watch */\n sourceDir: string;\n /** Memory root directory */\n memoryDir: string;\n /** State file path (stores hashes). Default: memoryDir/.sync-state.json */\n stateFile?: string;\n /** File extensions to watch (default: .md, .txt, .mdx) */\n extensions?: string[];\n /** Directories to exclude */\n excludeDirs?: string[];\n /** Poll interval for watchForChanges. Default: 5000ms */\n pollIntervalMs?: number;\n /** Whether to actually write changes (default: true) */\n dryRun?: boolean;\n}\n\nexport interface SyncResult {\n /** Files scanned */\n scanned: number;\n /** Files changed since last sync */\n changed: FileChange[];\n /** Files unchanged */\n unchanged: number;\n /** Files deleted since last sync */\n deleted: string[];\n /** Files newly added */\n added: string[];\n /** Duration in ms */\n durationMs: number;\n /** State file path */\n stateFile: string;\n}\n\nexport interface FileChange {\n /** Absolute file path */\n filePath: string;\n /** Relative path from source root */\n relativePath: string;\n /** Change type */\n type: \"added\" | \"modified\" | \"deleted\";\n /** Current content hash */\n currentHash: string;\n /** Previous content hash (if modified) */\n previousHash?: string;\n /** File size in bytes */\n size: number;\n}\n\nexport interface SyncState {\n /** Map of relative path → content hash */\n fileHashes: Record<string, string>;\n /** Last sync timestamp */\n lastSyncAt: string;\n /** Version of state format */\n version: number;\n}\n\n// ── Constants ────────────────────────────────────────────────────────────────\n\nconst DEFAULT_EXTENSIONS = new Set([\".md\", \".txt\", \".mdx\", \".rst\"]);\nconst DEFAULT_EXCLUDE = new Set([\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".engram\",\n \"coverage\",\n]);\n\n// ── Main function ────────────────────────────────────────────────────────────\n\nexport function syncChanges(options: SyncOptions): SyncResult {\n const startTime = Date.now();\n const {\n sourceDir,\n memoryDir,\n extensions = [...DEFAULT_EXTENSIONS],\n excludeDirs = [],\n dryRun = false,\n } = options;\n\n const extSet = new Set(extensions);\n const excludeSet = new Set([...DEFAULT_EXCLUDE, ...excludeDirs]);\n const stateFilePath = options.stateFile ?? path.join(memoryDir, \".sync-state.json\");\n\n // Load previous state\n const prevState = loadState(stateFilePath);\n\n // Scan current files\n const currentFiles = scanFiles(sourceDir, extSet, excludeSet);\n\n // Compute diffs\n const changes = computeDiff(currentFiles, prevState.fileHashes, sourceDir);\n\n const added = changes.filter((c) => c.type === \"added\").map((c) => c.relativePath);\n const modified = changes.filter((c) => c.type === \"modified\");\n const deleted = changes\n .filter((c) => c.type === \"deleted\")\n .map((c) => c.relativePath);\n\n // Update state (even in dry run, we want to show what would change)\n if (!dryRun) {\n const newState: SyncState = {\n fileHashes: {},\n lastSyncAt: new Date().toISOString(),\n version: 1,\n };\n\n // Build new state from current files\n for (const [relPath, hash] of Object.entries(currentFiles)) {\n newState.fileHashes[relPath] = hash;\n }\n\n // Write state\n fs.mkdirSync(path.dirname(stateFilePath), { recursive: true });\n fs.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));\n }\n\n return {\n scanned: Object.keys(currentFiles).length,\n changed: changes,\n unchanged:\n Object.keys(currentFiles).length - changes.filter((c) => c.type !== \"deleted\").length,\n deleted,\n added,\n durationMs: Date.now() - startTime,\n stateFile: stateFilePath,\n };\n}\n\n/**\n * Watch for changes and call callback on file changes.\n * Returns a stop function.\n */\nexport function watchForChanges(\n options: SyncOptions,\n onChange: (changes: FileChange[]) => void | Promise<void>,\n): { stop: () => void } {\n const { sourceDir, extensions, excludeDirs } = options;\n const extSet = new Set(extensions ?? DEFAULT_EXTENSIONS);\n const excludeSet = new Set([...DEFAULT_EXCLUDE, ...(excludeDirs ?? [])]);\n const pollIntervalMs =\n typeof options.pollIntervalMs === \"number\" &&\n Number.isFinite(options.pollIntervalMs) &&\n options.pollIntervalMs > 0\n ? options.pollIntervalMs\n : 5000;\n\n let lastHashes: Record<string, string> = {};\n let pollInFlight = false;\n\n // Initial scan\n const currentFiles = scanFiles(sourceDir, extSet, excludeSet);\n lastHashes = { ...currentFiles };\n\n // Poll interval (FSWatcher doesn't reliably work for all platforms)\n const poll = async (): Promise<void> => {\n if (pollInFlight) return;\n pollInFlight = true;\n try {\n const nowFiles = scanFiles(sourceDir, extSet, excludeSet);\n const changes = computeDiff(nowFiles, lastHashes, sourceDir);\n\n if (changes.length > 0) {\n await onChange(changes);\n // Update hashes\n for (const change of changes) {\n if (change.type === \"deleted\") {\n delete lastHashes[change.relativePath];\n } else {\n lastHashes[change.relativePath] = change.currentHash;\n }\n }\n }\n } catch {\n // Leave lastHashes unchanged so the next poll retries the same diff.\n } finally {\n pollInFlight = false;\n }\n };\n const interval = setInterval(() => {\n void poll();\n }, pollIntervalMs);\n\n return {\n stop: () => clearInterval(interval),\n };\n}\n\n// ── File scanning ────────────────────────────────────────────────────────────\n\nfunction scanFiles(\n root: string,\n extensions: Set<string>,\n exclude: Set<string>,\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n function walk(dir: string, isRoot = false): void {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch (err) {\n if (isRoot) {\n throw new Error(\n `sync scan failed for ${dir}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n return;\n }\n\n for (const entry of entries) {\n if (exclude.has(entry.name)) continue;\n\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walk(fullPath);\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name).toLowerCase();\n if (!extensions.has(ext)) continue;\n\n const relPath = path.relative(root, fullPath);\n try {\n const content = fs.readFileSync(fullPath, \"utf8\");\n result[relPath] = hashContent(content);\n } catch {\n // Can't read — skip\n }\n }\n }\n }\n\n walk(root, true);\n return result;\n}\n\n// ── Diff computation ─────────────────────────────────────────────────────────\n\nfunction computeDiff(\n current: Record<string, string>,\n previous: Record<string, string>,\n sourceDir: string,\n): FileChange[] {\n const changes: FileChange[] = [];\n\n // Find added and modified\n for (const [relPath, hash] of Object.entries(current)) {\n const fullPath = path.join(sourceDir, relPath);\n\n if (!(relPath in previous)) {\n // Added\n let size = 0;\n try {\n size = fs.statSync(fullPath).size;\n } catch {\n // ignore\n }\n changes.push({\n filePath: fullPath,\n relativePath: relPath,\n type: \"added\",\n currentHash: hash,\n size,\n });\n } else if (previous[relPath] !== hash) {\n // Modified\n let size = 0;\n try {\n size = fs.statSync(fullPath).size;\n } catch {\n // ignore\n }\n changes.push({\n filePath: fullPath,\n relativePath: relPath,\n type: \"modified\",\n currentHash: hash,\n previousHash: previous[relPath],\n size,\n });\n }\n }\n\n // Find deleted\n for (const relPath of Object.keys(previous)) {\n if (!(relPath in current)) {\n changes.push({\n filePath: path.join(sourceDir, relPath),\n relativePath: relPath,\n type: \"deleted\",\n currentHash: \"\",\n size: 0,\n });\n }\n }\n\n return changes;\n}\n\n// ── State management ─────────────────────────────────────────────────────────\n\nfunction loadState(stateFilePath: string): SyncState {\n try {\n const raw = fs.readFileSync(stateFilePath, \"utf8\");\n return JSON.parse(raw);\n } catch {\n return {\n fileHashes: {},\n lastSyncAt: new Date(0).toISOString(),\n version: 1,\n };\n }\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction hashContent(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n","/**\n * @remnic/core — Spaces + Collaboration\n *\n * First-class memory spaces (personal, project, team) with merge/conflict\n * flows, promotion workflow, and audit trail.\n *\n * Each space is an isolated memory directory. Spaces can share memories\n * through push/pull and promotion workflows.\n */\n\nimport { spawnSync } from \"node:child_process\";\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { readEnvVar, resolveHomeDir } from \"../runtime/env.js\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport type SpaceKind = \"personal\" | \"project\" | \"team\";\n\nexport interface Space {\n /** Unique space ID */\n id: string;\n /** Human-readable name */\n name: string;\n /** Space type */\n kind: SpaceKind;\n /** Description */\n description?: string;\n /** Memory directory path (absolute) */\n memoryDir: string;\n /** Created at */\n createdAt: string;\n /** Updated at */\n updatedAt: string;\n /** Owner */\n owner?: string;\n /** Members (for team spaces) */\n members?: string[];\n /** Parent space (for promotion) */\n parentSpaceId?: string;\n}\n\nexport interface SpaceManifest {\n /** Current active space ID */\n activeSpaceId: string;\n /** All spaces */\n spaces: Space[];\n /** Manifest version */\n version: number;\n /** Last updated */\n updatedAt?: string;\n}\n\nexport interface SpaceSwitchResult {\n previousSpaceId: string;\n currentSpaceId: string;\n message: string;\n}\n\nexport interface SpacePushResult {\n sourceSpaceId: string;\n targetSpaceId: string;\n memoriesPushed: number;\n conflicts: ConflictEntry[];\n durationMs: number;\n}\n\nexport interface SpacePullResult {\n sourceSpaceId: string;\n targetSpaceId: string;\n memoriesPulled: number;\n conflicts: ConflictEntry[];\n durationMs: number;\n}\n\nexport interface SpaceShareResult {\n spaceId: string;\n sharedWith: string[];\n message: string;\n}\n\nexport interface SpacePromoteResult {\n sourceSpaceId: string;\n targetSpaceId: string;\n memoriesPromoted: number;\n conflicts: ConflictEntry[];\n durationMs: number;\n}\n\nexport interface ConflictEntry {\n /** Memory ID */\n memoryId: string;\n /** Source file path */\n sourcePath: string;\n /** Target file path */\n targetPath: string;\n /** Conflict type */\n conflictType: \"content_mismatch\" | \"metadata_mismatch\" | \"both\";\n /** Source content hash */\n sourceHash: string;\n /** Target content hash */\n targetHash: string;\n}\n\nexport interface MergeResult {\n merged: number;\n conflicts: ConflictEntry[];\n skipped: number;\n durationMs: number;\n}\n\nexport interface AuditEntry {\n id: string;\n timestamp: string;\n action: string;\n sourceSpaceId: string;\n targetSpaceId?: string;\n actor?: string;\n details: string;\n memoryIds?: string[];\n}\n\n// ── Manifest management ─────────────────────────────────────────────────────\n\nconst MANIFEST_VERSION = 1;\nconst MANIFEST_LOCK_STALE_MS = 30_000;\nconst MANIFEST_LOCK_TIMEOUT_MS = MANIFEST_LOCK_STALE_MS + 10_000;\nconst MANIFEST_LOCK_SLEEP_MS = 20;\n\nfunction normalizeSpaceMemoryDir(memoryDir: string): string {\n return path.resolve(memoryDir);\n}\n\nexport function getSpacesDir(baseDir?: string): string {\n const homeDir = baseDir ?? resolveHomeDir();\n return path.join(homeDir, \".config\", \"engram\", \"spaces\");\n}\n\nexport function getManifestPath(baseDir?: string): string {\n return path.join(getSpacesDir(baseDir), \"manifest.json\");\n}\n\nexport function loadManifest(baseDir?: string, memoryDirOverride?: string): SpaceManifest {\n if (fs.existsSync(getManifestPath(baseDir))) {\n try {\n return readManifestUnlocked(baseDir, memoryDirOverride, { bootstrapIfMissing: false });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n }\n\n return updateManifest(baseDir, (manifest) => manifest, memoryDirOverride);\n}\n\nexport function saveManifest(manifest: SpaceManifest, baseDir?: string): void {\n withManifestLock(baseDir, () => {\n saveManifestUnlocked(manifest, baseDir);\n });\n}\n\nexport function updateManifest<T>(\n baseDir: string | undefined,\n updater: (manifest: SpaceManifest) => T,\n memoryDirOverride?: string\n): T {\n return withManifestLock(baseDir, () => {\n const manifest = readManifestUnlocked(baseDir, memoryDirOverride);\n const result = updater(manifest);\n saveManifestUnlocked(manifest, baseDir);\n return result;\n });\n}\n\nfunction readManifestUnlocked(\n baseDir?: string,\n memoryDirOverride?: string,\n options: { bootstrapIfMissing?: boolean } = {}\n): SpaceManifest {\n const manifestPath = getManifestPath(baseDir);\n\n if (!fs.existsSync(manifestPath)) {\n if (options.bootstrapIfMissing === false) {\n const error = new Error(`Spaces manifest not found: ${manifestPath}`) as NodeJS.ErrnoException;\n error.code = \"ENOENT\";\n throw error;\n }\n const personalSpace = createPersonalSpace(baseDir, memoryDirOverride);\n return {\n activeSpaceId: personalSpace.id,\n spaces: [personalSpace],\n version: MANIFEST_VERSION,\n };\n }\n\n const raw = JSON.parse(fs.readFileSync(manifestPath, \"utf8\"));\n return raw as SpaceManifest;\n}\n\nfunction saveManifestUnlocked(manifest: SpaceManifest, baseDir?: string): void {\n const manifestPath = getManifestPath(baseDir);\n const manifestDir = path.dirname(manifestPath);\n fs.mkdirSync(manifestDir, { recursive: true });\n const tempPath = path.join(manifestDir, `.manifest.${process.pid}.${Date.now()}.${crypto.randomUUID()}.tmp`);\n try {\n fs.writeFileSync(tempPath, `${JSON.stringify(manifest, null, 2)}\\n`, { flag: \"wx\" });\n fs.renameSync(tempPath, manifestPath);\n } catch (error) {\n try {\n fs.rmSync(tempPath, { force: true });\n } catch {\n // Ignore cleanup failures; surface the original write/rename error.\n }\n throw error;\n }\n}\n\nfunction withManifestLock<T>(baseDir: string | undefined, operation: () => T): T {\n const lockDir = `${getManifestPath(baseDir)}.lock`;\n fs.mkdirSync(path.dirname(lockDir), { recursive: true });\n const lockOwner = acquireManifestLock(lockDir);\n try {\n return operation();\n } finally {\n releaseManifestLock(lockDir, lockOwner);\n }\n}\n\nfunction acquireManifestLock(lockDir: string): string {\n const deadline = Date.now() + MANIFEST_LOCK_TIMEOUT_MS;\n const owner = createManifestLockOwner();\n const reclaimDir = getManifestLockReclaimDir(lockDir);\n while (true) {\n if (fs.existsSync(reclaimDir)) {\n removeStaleManifestReclaimLock(reclaimDir);\n }\n if (fs.existsSync(reclaimDir)) {\n if (Date.now() >= deadline) {\n throw new Error(`Timed out waiting for spaces manifest reclaim lock: ${reclaimDir}`);\n }\n sleepSync(MANIFEST_LOCK_SLEEP_MS);\n continue;\n }\n\n try {\n fs.mkdirSync(lockDir, { recursive: false });\n try {\n fs.writeFileSync(path.join(lockDir, \"owner\"), `${owner}\\n`, { flag: \"wx\" });\n } catch (error) {\n fs.rmSync(lockDir, { recursive: true, force: true });\n throw error;\n }\n if (fs.existsSync(reclaimDir)) {\n releaseManifestLock(lockDir, owner);\n if (Date.now() >= deadline) {\n throw new Error(`Timed out waiting for spaces manifest reclaim lock: ${reclaimDir}`);\n }\n sleepSync(MANIFEST_LOCK_SLEEP_MS);\n continue;\n }\n return owner;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") {\n throw error;\n }\n\n removeStaleManifestLock(lockDir);\n if (Date.now() >= deadline) {\n throw new Error(`Timed out waiting for spaces manifest lock: ${lockDir}`);\n }\n sleepSync(MANIFEST_LOCK_SLEEP_MS);\n }\n }\n}\n\nfunction releaseManifestLock(lockDir: string, owner: string): void {\n try {\n const ownerPath = path.join(lockDir, \"owner\");\n if (fs.readFileSync(ownerPath, \"utf8\").trim() === owner) {\n fs.rmSync(lockDir, { recursive: true, force: true });\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n}\n\nfunction removeStaleManifestLock(lockDir: string): void {\n const reclaimDir = getManifestLockReclaimDir(lockDir);\n const reclaimOwner = createManifestLockOwner();\n try {\n fs.mkdirSync(reclaimDir, { recursive: false });\n try {\n fs.writeFileSync(path.join(reclaimDir, \"owner\"), `${reclaimOwner}\\n`, { flag: \"wx\" });\n } catch (error) {\n fs.rmSync(reclaimDir, { recursive: true, force: true });\n throw error;\n }\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EEXIST\") {\n return;\n }\n throw error;\n }\n\n try {\n const snapshot = readManifestLockSnapshot(lockDir);\n if (!snapshot || Date.now() - snapshot.mtimeMs <= MANIFEST_LOCK_STALE_MS) {\n return;\n }\n\n if (isManifestLockOwnerActive(snapshot.owner)) {\n return;\n }\n\n const tombstoneDir = `${lockDir}.stale.${process.pid}.${crypto.randomUUID()}`;\n try {\n fs.renameSync(lockDir, tombstoneDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n return;\n }\n fs.rmSync(tombstoneDir, { recursive: true, force: true });\n } finally {\n fs.rmSync(reclaimDir, { recursive: true, force: true });\n }\n}\n\nfunction getManifestLockReclaimDir(lockDir: string): string {\n return `${lockDir}.reclaim`;\n}\n\nfunction createManifestLockOwner(): string {\n return JSON.stringify({\n pid: process.pid,\n startKey: readProcessStartKey(process.pid),\n token: crypto.randomUUID(),\n });\n}\n\nfunction removeStaleManifestReclaimLock(reclaimDir: string): void {\n const snapshot = readManifestLockSnapshot(reclaimDir);\n if (!snapshot || Date.now() - snapshot.mtimeMs <= MANIFEST_LOCK_STALE_MS) {\n return;\n }\n\n if (isManifestLockOwnerActive(snapshot.owner)) {\n return;\n }\n\n const tombstoneDir = `${reclaimDir}.stale.${process.pid}.${crypto.randomUUID()}`;\n try {\n fs.renameSync(reclaimDir, tombstoneDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n return;\n }\n fs.rmSync(tombstoneDir, { recursive: true, force: true });\n}\n\nfunction readManifestLockSnapshot(lockDir: string): { mtimeMs: number; owner?: string } | undefined {\n let stat: fs.Stats;\n try {\n stat = fs.statSync(lockDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw error;\n }\n\n try {\n const owner = fs.readFileSync(path.join(lockDir, \"owner\"), \"utf8\").trim();\n return { mtimeMs: stat.mtimeMs, owner };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return { mtimeMs: stat.mtimeMs };\n }\n throw error;\n }\n}\n\nfunction isManifestLockOwnerActive(owner: string | undefined): boolean {\n if (!owner) {\n return false;\n }\n\n const parsed = parseManifestLockOwner(owner);\n if (!parsed) {\n return false;\n }\n\n const currentStartKey = readProcessStartKey(parsed.pid);\n if (currentStartKey && parsed.startKey) {\n return currentStartKey === parsed.startKey;\n }\n\n return isProcessAlive(parsed.pid);\n}\n\nfunction parseManifestLockOwner(owner: string): { pid: number; startKey?: string } | undefined {\n try {\n const parsed = JSON.parse(owner) as { pid?: unknown; startKey?: unknown };\n const pid = typeof parsed.pid === \"number\" ? parsed.pid : Number.NaN;\n if (Number.isInteger(pid) && pid > 0) {\n return {\n pid,\n startKey: typeof parsed.startKey === \"string\" && parsed.startKey.length > 0 ? parsed.startKey : undefined,\n };\n }\n } catch {\n // Fall through to legacy owner format.\n }\n\n const legacyPid = Number(owner.split(\":\", 1)[0]);\n return Number.isInteger(legacyPid) && legacyPid > 0 ? { pid: legacyPid } : undefined;\n}\n\nfunction readProcessStartKey(pid: number): string | undefined {\n if (!Number.isInteger(pid) || pid <= 0) {\n return undefined;\n }\n\n const result = spawnSync(\"ps\", [\"-p\", String(pid), \"-o\", \"lstart=\"], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n if (result.error || result.status !== 0 || typeof result.stdout !== \"string\") {\n return undefined;\n }\n const startKey = result.stdout.trim().replace(/\\s+/g, \" \");\n return startKey.length > 0 ? startKey : undefined;\n}\n\nfunction isProcessAlive(pid: number): boolean {\n if (pid === process.pid) {\n return true;\n }\n\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"ESRCH\") {\n return false;\n }\n return true;\n }\n}\n\nfunction sleepSync(ms: number): void {\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n}\n\nfunction createPersonalSpace(baseDir?: string, memoryDirOverride?: string): Space {\n const homeDir = baseDir ?? resolveHomeDir();\n // Priority: override > REMNIC_MEMORY_DIR > ENGRAM_MEMORY_DIR > existing standalone dir > existing OpenClaw dir > new standalone dir\n const standalonePath = path.join(homeDir, \".engram\", \"memory\");\n const openclawPath = path.join(homeDir, \".openclaw\", \"workspace\", \"memory\", \"local\");\n const memoryDir =\n memoryDirOverride ??\n readEnvVar(\"REMNIC_MEMORY_DIR\") ??\n readEnvVar(\"ENGRAM_MEMORY_DIR\") ??\n (fs.existsSync(standalonePath) ? standalonePath : fs.existsSync(openclawPath) ? openclawPath : standalonePath);\n const normalizedMemoryDir = normalizeSpaceMemoryDir(memoryDir);\n const now = new Date().toISOString();\n\n return {\n id: \"personal\",\n name: \"Personal\",\n kind: \"personal\",\n description: \"Default personal memory space\",\n memoryDir: normalizedMemoryDir,\n createdAt: now,\n updatedAt: now,\n owner: readEnvVar(\"USER\"),\n };\n}\n\n// ── Space CRUD ──────────────────────────────────────────────────────────────\n\nexport function listSpaces(baseDir?: string): Space[] {\n const manifest = loadManifest(baseDir);\n return manifest.spaces;\n}\n\nexport function getActiveSpace(baseDir?: string): Space {\n const manifest = loadManifest(baseDir);\n const space = manifest.spaces.find((s) => s.id === manifest.activeSpaceId);\n if (!space) throw new Error(`Active space ${manifest.activeSpaceId} not found`);\n return space;\n}\n\nexport function createSpace(options: {\n name: string;\n kind: SpaceKind;\n description?: string;\n memoryDir?: string;\n parentSpaceId?: string;\n baseDir?: string;\n}): Space {\n const id = options.name\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\")\n .replace(/-+/g, \"-\");\n const now = new Date().toISOString();\n const memoryDir = normalizeSpaceMemoryDir(\n options.memoryDir ?? path.join(getSpacesDir(options.baseDir), id, \"memory\")\n );\n\n const space = updateManifest(options.baseDir, (manifest) => {\n if (manifest.spaces.some((s) => s.id === id)) {\n throw new Error(`Space \"${id}\" already exists`);\n }\n\n // Validate parent space exists\n if (options.parentSpaceId && !manifest.spaces.some((s) => s.id === options.parentSpaceId)) {\n throw new Error(`Parent space \"${options.parentSpaceId}\" not found`);\n }\n\n const created: Space = {\n id,\n name: options.name,\n kind: options.kind,\n description: options.description,\n memoryDir,\n createdAt: now,\n updatedAt: now,\n owner: readEnvVar(\"USER\"),\n parentSpaceId: options.parentSpaceId,\n };\n\n // Ensure memory directory exists before publishing the manifest entry.\n fs.mkdirSync(memoryDir, { recursive: true });\n\n manifest.spaces.push(created);\n manifest.updatedAt = now;\n return created;\n });\n\n // Audit\n appendAudit(\n {\n action: \"space.create\",\n sourceSpaceId: id,\n details: `Created ${options.kind} space \"${options.name}\"`,\n },\n options.baseDir\n );\n\n return space;\n}\n\nexport function deleteSpace(spaceId: string, baseDir?: string): void {\n if (spaceId === \"personal\") {\n throw new Error(\"Cannot delete the personal space\");\n }\n\n updateManifest(baseDir, (manifest) => {\n const idx = manifest.spaces.findIndex((s) => s.id === spaceId);\n if (idx === -1) throw new Error(`Space \"${spaceId}\" not found`);\n\n // If deleting active space, switch to personal\n if (manifest.activeSpaceId === spaceId) {\n manifest.activeSpaceId = \"personal\";\n }\n\n // Clear parentSpaceId references from children\n for (const space of manifest.spaces) {\n if (space.parentSpaceId === spaceId) {\n space.parentSpaceId = undefined;\n }\n }\n\n manifest.spaces.splice(idx, 1);\n });\n\n appendAudit(\n {\n action: \"space.delete\",\n sourceSpaceId: spaceId,\n details: `Deleted space \"${spaceId}\"`,\n },\n baseDir\n );\n}\n\n// ── Switch ───────────────────────────────────────────────────────────────────\n\nexport function switchSpace(spaceId: string, baseDir?: string): SpaceSwitchResult {\n const { previousId, spaceName } = updateManifest(baseDir, (manifest) => {\n const space = manifest.spaces.find((s) => s.id === spaceId);\n if (!space) throw new Error(`Space \"${spaceId}\" not found`);\n const previousId = manifest.activeSpaceId;\n manifest.activeSpaceId = spaceId;\n return { previousId, spaceName: space.name };\n });\n\n appendAudit(\n {\n action: \"space.switch\",\n sourceSpaceId: previousId,\n targetSpaceId: spaceId,\n details: `Switched from \"${previousId}\" to \"${spaceId}\"`,\n },\n baseDir\n );\n\n return {\n previousSpaceId: previousId,\n currentSpaceId: spaceId,\n message: `Switched to \"${spaceName}\"`,\n };\n}\n\n// ── Push / Pull ─────────────────────────────────────────────────────────────\n\nexport function pushToSpace(\n sourceSpaceId: string,\n targetSpaceId: string,\n options?: { memoryIds?: string[]; force?: boolean; baseDir?: string }\n): SpacePushResult {\n const startTime = Date.now();\n const manifest = loadManifest(options?.baseDir);\n\n const source = manifest.spaces.find((s) => s.id === sourceSpaceId);\n const target = manifest.spaces.find((s) => s.id === targetSpaceId);\n\n if (!source) throw new Error(`Source space \"${sourceSpaceId}\" not found`);\n if (!target) throw new Error(`Target space \"${targetSpaceId}\" not found`);\n\n const result = copyMemories(source.memoryDir, target.memoryDir, {\n filterIds: options?.memoryIds,\n force: options?.force,\n });\n\n appendAudit(\n {\n action: \"space.push\",\n sourceSpaceId,\n targetSpaceId,\n details: `Pushed ${result.merged} memories, ${result.conflicts.length} conflicts`,\n },\n options?.baseDir\n );\n\n return {\n sourceSpaceId,\n targetSpaceId,\n memoriesPushed: result.merged,\n conflicts: result.conflicts,\n durationMs: Date.now() - startTime,\n };\n}\n\nexport function pullFromSpace(\n sourceSpaceId: string,\n targetSpaceId: string,\n options?: { memoryIds?: string[]; force?: boolean; baseDir?: string }\n): SpacePullResult {\n const startTime = Date.now();\n const manifest = loadManifest(options?.baseDir);\n\n const source = manifest.spaces.find((s) => s.id === sourceSpaceId);\n const target = manifest.spaces.find((s) => s.id === targetSpaceId);\n\n if (!source) throw new Error(`Source space \"${sourceSpaceId}\" not found`);\n if (!target) throw new Error(`Target space \"${targetSpaceId}\" not found`);\n\n const result = copyMemories(source.memoryDir, target.memoryDir, {\n filterIds: options?.memoryIds,\n force: options?.force,\n });\n\n appendAudit(\n {\n action: \"space.pull\",\n sourceSpaceId,\n targetSpaceId,\n details: `Pulled ${result.merged} memories, ${result.conflicts.length} conflicts`,\n },\n options?.baseDir\n );\n\n return {\n sourceSpaceId,\n targetSpaceId,\n memoriesPulled: result.merged,\n conflicts: result.conflicts,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Share ────────────────────────────────────────────────────────────────────\n\nexport function shareSpace(spaceId: string, members: string[], baseDir?: string): SpaceShareResult {\n const spaceName = updateManifest(baseDir, (manifest) => {\n const space = manifest.spaces.find((s) => s.id === spaceId);\n if (!space) throw new Error(`Space \"${spaceId}\" not found`);\n if (space.kind === \"personal\") throw new Error(\"Cannot share personal space\");\n\n space.members = [...new Set([...(space.members ?? []), ...members])];\n space.updatedAt = new Date().toISOString();\n return space.name;\n });\n\n appendAudit(\n {\n action: \"space.share\",\n sourceSpaceId: spaceId,\n details: `Shared with: ${members.join(\", \")}`,\n },\n baseDir\n );\n\n return {\n spaceId,\n sharedWith: members,\n message: `Shared \"${spaceName}\" with ${members.length} member(s)`,\n };\n}\n\n// ── Promote ──────────────────────────────────────────────────────────────────\n\nexport function promoteSpace(\n sourceSpaceId: string,\n targetSpaceId: string,\n options?: { memoryIds?: string[]; force?: boolean; forceOverwrite?: boolean; baseDir?: string }\n): SpacePromoteResult {\n const startTime = Date.now();\n const manifest = loadManifest(options?.baseDir);\n\n const source = manifest.spaces.find((s) => s.id === sourceSpaceId);\n const target = manifest.spaces.find((s) => s.id === targetSpaceId);\n\n if (!source) throw new Error(`Source space \"${sourceSpaceId}\" not found`);\n if (!target) throw new Error(`Target space \"${targetSpaceId}\" not found`);\n\n // Promotion requires parent-child relationship or explicit force\n if (source.parentSpaceId !== targetSpaceId && target.parentSpaceId !== sourceSpaceId) {\n if (!options?.force) {\n throw new Error(\"Spaces must have a parent-child relationship for promotion. Use --force to override.\");\n }\n }\n\n const result = copyMemories(source.memoryDir, target.memoryDir, {\n filterIds: options?.memoryIds,\n force: options?.forceOverwrite !== undefined ? options.forceOverwrite : (options?.force ?? false),\n });\n\n appendAudit(\n {\n action: \"space.promote\",\n sourceSpaceId,\n targetSpaceId,\n details: `Promoted ${result.merged} memories from \"${source.name}\" to \"${target.name}\"`,\n },\n options?.baseDir\n );\n\n return {\n sourceSpaceId,\n targetSpaceId,\n memoriesPromoted: result.merged,\n conflicts: result.conflicts,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Merge ────────────────────────────────────────────────────────────────────\n\nexport function mergeSpaces(\n sourceSpaceId: string,\n targetSpaceId: string,\n options?: { force?: boolean; baseDir?: string }\n): MergeResult {\n const startTime = Date.now();\n const manifest = loadManifest(options?.baseDir);\n\n const source = manifest.spaces.find((s) => s.id === sourceSpaceId);\n const target = manifest.spaces.find((s) => s.id === targetSpaceId);\n\n if (!source) throw new Error(`Source space \"${sourceSpaceId}\" not found`);\n if (!target) throw new Error(`Target space \"${targetSpaceId}\" not found`);\n\n const result = copyMemories(source.memoryDir, target.memoryDir, {\n force: options?.force,\n });\n\n appendAudit(\n {\n action: \"space.merge\",\n sourceSpaceId,\n targetSpaceId,\n details: `Merged: ${result.merged} merged, ${result.conflicts.length} conflicts, ${result.skipped} skipped`,\n },\n options?.baseDir\n );\n\n return {\n ...result,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Audit trail ─────────────────────────────────────────────────────────────\n\nexport function getAuditLog(baseDir?: string): AuditEntry[] {\n const auditPath = path.join(getSpacesDir(baseDir), \"audit.jsonl\");\n if (!fs.existsSync(auditPath)) return [];\n\n const lines = fs.readFileSync(auditPath, \"utf8\").trim().split(\"\\n\");\n return lines.filter((l) => l.trim()).map((l) => JSON.parse(l) as AuditEntry);\n}\n\nfunction appendAudit(entry: Omit<AuditEntry, \"id\" | \"timestamp\">, baseDir?: string): void {\n const auditPath = path.join(getSpacesDir(baseDir), \"audit.jsonl\");\n fs.mkdirSync(path.dirname(auditPath), { recursive: true });\n\n const full: AuditEntry = {\n id: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n ...entry,\n };\n\n fs.appendFileSync(auditPath, `${JSON.stringify(full)}\\n`);\n}\n\n// ── Internal helpers ─────────────────────────────────────────────────────────\n\ninterface CopyOptions {\n filterIds?: string[];\n force?: boolean;\n}\n\nfunction copyMemories(\n sourceDir: string,\n targetDir: string,\n options?: CopyOptions\n): { merged: number; conflicts: ConflictEntry[]; skipped: number } {\n let merged = 0;\n const conflicts: ConflictEntry[] = [];\n let skipped = 0;\n\n if (!fs.existsSync(sourceDir)) {\n return { merged: 0, conflicts: [], skipped: 0 };\n }\n\n const sourceRoot = fs.realpathSync(sourceDir);\n fs.mkdirSync(targetDir, { recursive: true });\n const targetRoot = fs.realpathSync(targetDir);\n\n const sourceFiles = walkMd(sourceRoot);\n for (const sourcePath of sourceFiles) {\n const sourceRealPath = safeRealpath(sourcePath);\n if (!sourceRealPath || !isPathInsideRoot(sourceRealPath, sourceRoot)) {\n skipped++;\n continue;\n }\n const sourceStat = safeLstat(sourcePath);\n if (!sourceStat?.isFile()) {\n skipped++;\n continue;\n }\n const content = fs.readFileSync(sourcePath, \"utf8\");\n const relativePath = path.relative(sourceRoot, sourceRealPath);\n const targetPath = path.resolve(targetRoot, relativePath);\n if (!isPathInsideRoot(targetPath, targetRoot)) {\n skipped++;\n continue;\n }\n\n const sourceHash = hashContent(content);\n\n // Filter by IDs if specified\n if (options?.filterIds?.length) {\n const fm = parseSimpleFrontmatter(content);\n if (!fm?.id || !options.filterIds.includes(fm.id)) {\n skipped++;\n continue;\n }\n }\n\n // Check for conflict\n if (fs.existsSync(targetPath)) {\n const targetStat = safeLstat(targetPath);\n if (!targetStat?.isFile() || targetStat.isSymbolicLink()) {\n skipped++;\n continue;\n }\n const targetRealPath = safeRealpath(targetPath);\n if (!targetRealPath || !isPathInsideRoot(targetRealPath, targetRoot)) {\n skipped++;\n continue;\n }\n }\n\n if (fs.existsSync(targetPath) && !options?.force) {\n const targetContent = fs.readFileSync(targetPath, \"utf8\");\n const targetHash = hashContent(targetContent);\n\n if (sourceHash !== targetHash) {\n conflicts.push({\n memoryId: parseSimpleFrontmatter(content)?.id ?? relativePath,\n sourcePath,\n targetPath,\n conflictType: \"content_mismatch\",\n sourceHash,\n targetHash,\n });\n continue;\n }\n\n // Same content — skip\n skipped++;\n continue;\n }\n\n // Copy file\n fs.mkdirSync(path.dirname(targetPath), { recursive: true });\n const targetParentRealPath = safeRealpath(path.dirname(targetPath));\n if (!targetParentRealPath || !isPathInsideRoot(targetParentRealPath, targetRoot)) {\n skipped++;\n continue;\n }\n fs.writeFileSync(targetPath, content);\n merged++;\n }\n\n return { merged, conflicts, skipped };\n}\n\nfunction hashContent(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\nfunction walkMd(dir: string): string[] {\n const results: string[] = [];\n\n function walk(d: string): void {\n for (const entry of fs.readdirSync(d, { withFileTypes: true })) {\n const fullPath = path.join(d, entry.name);\n if (entry.isSymbolicLink()) {\n continue;\n }\n if (entry.isDirectory()) {\n walk(fullPath);\n } else if (entry.name.endsWith(\".md\")) {\n results.push(fullPath);\n }\n }\n }\n\n walk(dir);\n return results;\n}\n\nfunction safeLstat(filePath: string): fs.Stats | null {\n try {\n return fs.lstatSync(filePath);\n } catch {\n return null;\n }\n}\n\nfunction safeRealpath(filePath: string): string | null {\n try {\n return fs.realpathSync(filePath);\n } catch {\n return null;\n }\n}\n\nfunction isPathInsideRoot(candidatePath: string, rootPath: string): boolean {\n const relative = path.relative(rootPath, candidatePath);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\ninterface SimpleFrontmatter {\n id?: string;\n [key: string]: string | undefined;\n}\n\nfunction parseSimpleFrontmatter(content: string): SimpleFrontmatter | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fm: SimpleFrontmatter = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n fm[key] = value;\n }\n return fm;\n}\n","/**\n * @remnic/core — Shared Instruction Blocks\n *\n * Reusable markdown fragments that every host-specific publisher can\n * compose into its instructions.md file. Keeping them here avoids\n * per-host copy-paste drift.\n */\n\n/**\n * Describes the Remnic memory types a host agent may encounter.\n */\nexport const REMNIC_SEMANTIC_OVERVIEW = `\\\n## Remnic Memory Types\n\nRemnic stores memories as plain Markdown files with YAML front-matter.\nEach memory has a **type** that describes its semantic role:\n\n| Type | Description |\n|------|-------------|\n| \\`fact\\` | An objective piece of knowledge the user confirmed or that was extracted from a session. |\n| \\`preference\\` | A stated or inferred user preference (e.g. coding style, tool choice). |\n| \\`decision\\` | An explicit decision or trade-off the user made. |\n| \\`entity\\` | A named thing the user cares about (project, service, person, API). |\n| \\`skill\\` | A reusable workflow or procedure documented for future sessions. |\n| \\`correction\\` | A fix or amendment to a previously stored memory. |\n| \\`question\\` | An open question or uncertainty flagged for future resolution. |\n| \\`observation\\` | A pattern noticed across sessions (e.g. \"user always runs tests before commits\"). |\n| \\`summary\\` | A condensed roll-up of recent sessions or a topic area. |\n\nWhen reading Remnic content, the front-matter \\`type\\` field tells you what\nkind of knowledge you are looking at and how much weight to give it.\n`;\n\n/**\n * Explains the oai-mem-citation block format hosts should use when\n * referencing Remnic-sourced content.\n */\nexport const REMNIC_CITATION_FORMAT = `\\\n## Citing Remnic Memories\n\nWhen a piece of your output draws on a Remnic file, cite it using the\nmemory citation block format so the user can trace the source:\n\n\\`\\`\\`\n<oai-mem-citation path=\"<path-relative-to-remnic-memory-base>\" />\n\\`\\`\\`\n\nThe path must be **relative to the Remnic memory base** (the directory\nnamed \\`memories/\\` under \\`<remnic-home>\\`), not absolute. Examples:\n\n- \\`<oai-mem-citation path=\"default/MEMORY.md\" />\\`\n- \\`<oai-mem-citation path=\"my-project/skills/deploy/SKILL.md\" />\\`\n- \\`<oai-mem-citation path=\"shared/memory_summary.md\" />\\`\n\nCite each distinct source once near the fact it supports. Do not invent\ncitations for files you have not actually read.\n`;\n\n/**\n * Table of MCP tools the Remnic daemon exposes. Hosts that can reach\n * the MCP server should prefer these over raw file reads.\n *\n * Tool names use the canonical `remnic.*` prefix. Legacy `engram.*`\n * aliases are also accepted by the server for backward compatibility.\n */\nexport const REMNIC_MCP_TOOL_INVENTORY = `\\\n## Remnic MCP Tools\n\nWhen the Remnic MCP server is reachable, the following tools are\navailable. Prefer MCP tools over direct file reads when the host\nsupports MCP connections.\n\n| Tool | Purpose |\n|------|---------|\n| \\`remnic.recall\\` | Retrieve contextually relevant memories for the current session. |\n| \\`remnic.recall_explain\\` | Like recall, but includes an explanation of why each memory was selected. |\n| \\`remnic.memory_store\\` | Persist a new memory (fact, preference, decision, etc.). |\n| \\`remnic.memory_get\\` | Fetch a specific memory by ID. |\n| \\`remnic.memory_search\\` | Full-text + semantic search across all memories. |\n| \\`remnic.memory_timeline\\` | Retrieve memories in chronological order within a time range. |\n| \\`remnic.observe\\` | Record an observation from the current conversation turn. |\n| \\`remnic.entity_get\\` | Look up a named entity and its relationships. |\n| \\`remnic.memory_entities_list\\` | List all known entities. |\n| \\`remnic.memory_profile\\` | Retrieve the user profile summary. |\n| \\`remnic.day_summary\\` | Generate a summary of memories from a specific day. |\n| \\`remnic.briefing\\` | Generate a structured briefing for an upcoming session. |\n| \\`remnic.memory_feedback\\` | Submit feedback on a recalled memory (useful, outdated, wrong). |\n| \\`remnic.memory_promote\\` | Promote a memory to a higher confidence tier. |\n| \\`remnic.context_checkpoint\\` | Save a conversation checkpoint for continuity. |\n| \\`remnic.suggestion_submit\\` | Submit a suggestion for a new memory to the review queue. |\n| \\`remnic.review_queue_list\\` | List pending suggestions in the review queue. |\n| \\`remnic.work_task\\` | Create or update a work task. |\n| \\`remnic.work_project\\` | Create or update a work project. |\n| \\`remnic.work_board\\` | View the work board. |\n\nLegacy \\`engram.*\\` prefixed names are accepted as aliases for all tools.\n`;\n\n/**\n * Decision rules for when a host agent should use MCP recall vs\n * reading Remnic files directly from disk.\n */\nexport const REMNIC_RECALL_DECISION_RULES = `\\\n## When to Use Recall vs Direct Read\n\n### Use \\`remnic.recall\\` (MCP) when:\n\n- The Remnic MCP server is reachable (the host has an active MCP\n connection to the Remnic daemon).\n- You want contextually relevant memories ranked by the recall planner\n (semantic search + reranking + importance scoring).\n- You need memories across multiple namespaces or topics.\n- The conversation benefits from Remnic's intent detection and\n adaptive recall depth.\n\n### Use direct file reads when:\n\n- You are in a sandboxed environment with no network or MCP access\n (e.g. Codex phase-2 consolidation).\n- You need a specific file you already know the path to.\n- The MCP server is unavailable or unhealthy.\n- You are operating on the raw memory files for maintenance or\n migration purposes.\n\n### General guidance:\n\n- Prefer MCP tools when available — they provide ranked, deduplicated,\n and context-aware results.\n- Fall back to file reads gracefully — never block on a failed MCP call\n when the data is also on disk.\n- Never write directly to the Remnic memory directory unless you are an\n authorized extraction or consolidation process.\n`;\n","/**\n * @remnic/core — Codex Memory Extension Publisher\n *\n * Writes Remnic instructions into ~/.codex/memories_extensions/remnic/\n * so the Codex agent can discover and use Remnic memories during its\n * consolidation phase.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nimport type {\n MemoryExtensionPublisher,\n PublishContext,\n PublishResult,\n PublisherCapabilities,\n} from \"./types.js\";\n\nimport {\n REMNIC_SEMANTIC_OVERVIEW,\n REMNIC_CITATION_FORMAT,\n REMNIC_MCP_TOOL_INVENTORY,\n REMNIC_RECALL_DECISION_RULES,\n} from \"./shared-instructions.js\";\nimport { readEnvVar, resolveHomeDir } from \"../runtime/env.js\";\n\n/** Folder name Remnic installs its extension under inside memories_extensions/. */\nconst REMNIC_EXTENSION_DIR_NAME = \"remnic\";\n\nfunction resolveEnvHome(env?: NodeJS.ProcessEnv): string {\n if (env === undefined) return resolveHomeDir();\n return env.HOME?.trim() || env.USERPROFILE?.trim() || os.homedir();\n}\n\nfunction expandTildeWithHome(input: string, homeDir: string): string {\n if (input === \"~\") return homeDir;\n if (input.startsWith(\"~/\") || input.startsWith(\"~\\\\\")) {\n return path.join(homeDir, input.slice(2));\n }\n return input;\n}\n\nfunction normalizeHostRoot(input: string, homeDir: string): string {\n return path.resolve(expandTildeWithHome(input.trim(), homeDir));\n}\n\n/**\n * Codex-specific publisher that knows the Codex extension layout:\n * ~/.codex/memories_extensions/remnic/instructions.md\n */\nexport class CodexMemoryExtensionPublisher implements MemoryExtensionPublisher {\n readonly hostId = \"codex\";\n\n static readonly capabilities: PublisherCapabilities = {\n instructionsMd: true,\n skillsFolder: false,\n citationFormat: true,\n readPathTemplate: true,\n };\n\n async resolveExtensionRoot(\n env?: NodeJS.ProcessEnv,\n ): Promise<string> {\n const homeDir = resolveEnvHome(env);\n const codexHomeInput = env === undefined\n ? readEnvVar(\"CODEX_HOME\")?.trim()\n : env.CODEX_HOME?.trim();\n const codexHome = codexHomeInput\n ? normalizeHostRoot(codexHomeInput, homeDir)\n : path.resolve(homeDir, \".codex\");\n return path.join(codexHome, \"memories_extensions\", REMNIC_EXTENSION_DIR_NAME);\n }\n\n async isHostAvailable(): Promise<boolean> {\n try {\n const home = readEnvVar(\"CODEX_HOME\")?.trim() ||\n path.join(resolveHomeDir(), \".codex\");\n return fs.existsSync(home);\n } catch {\n return false;\n }\n }\n\n async renderInstructions(ctx: PublishContext): Promise<string> {\n const memDir = ctx.config.memoryDir;\n const ns = ctx.config.namespace ?? \"default\";\n\n const sections: string[] = [\n `# Remnic Memory Extension for Codex\\n`,\n `This document tells you how to use Remnic as an authoritative local ` +\n `memory source. Remnic is a local-first, file-backed memory system. ` +\n `All Remnic content lives on disk as plain Markdown.\\n`,\n REMNIC_SEMANTIC_OVERVIEW,\n `## Where Remnic Content Lives\\n\\n` +\n `Memory base directory: \\`${memDir}\\`\\n\\n` +\n `Namespace: \\`${ns}\\`\\n\\n` +\n `Under the base directory, memories are organized by namespace:\\n\\n` +\n \"```\\n\" +\n `${memDir}/<namespace>/\\n` +\n ` MEMORY.md # compact top-of-mind memory\\n` +\n ` memory_summary.md # optional longer summary\\n` +\n ` skills/\\n` +\n ` <skill-name>/SKILL.md # reusable workflows\\n` +\n ` rollout_summaries/\\n` +\n ` *.md # per-session rollup notes\\n` +\n \"```\\n\",\n REMNIC_CITATION_FORMAT,\n REMNIC_MCP_TOOL_INVENTORY,\n REMNIC_RECALL_DECISION_RULES,\n `## Sandboxing Rules (Codex Phase-2)\\n\\n` +\n `When running inside the Codex phase-2 consolidation sandbox:\\n\\n` +\n `- **No network.** Do not attempt HTTP calls or MCP connections.\\n` +\n `- **No CLI invocation.** Do not shell out to \\`remnic\\` or \\`engram\\`.\\n` +\n `- **No MCP tool calls.** Use filesystem reads only.\\n` +\n `- **Local writes** are allowed only where Codex's sandbox policy permits.\\n` +\n `- **Respect missing files.** If a file does not exist, move on silently.\\n`,\n ];\n\n return sections.join(\"\\n\");\n }\n\n async publish(ctx: PublishContext): Promise<PublishResult> {\n const extensionRoot = await this.resolveExtensionRoot();\n const instructionsPath = path.join(extensionRoot, \"instructions.md\");\n const filesWritten: string[] = [];\n const skipped: string[] = [];\n\n ctx.log.info(`Publishing Codex memory extension to ${extensionRoot}`);\n\n // Ensure the extension root exists.\n fs.mkdirSync(extensionRoot, { recursive: true });\n\n // Render and write instructions.md using atomic write (temp + rename).\n // Per CLAUDE.md #54: never delete before write in file replace operations.\n const content = await this.renderInstructions(ctx);\n const tmpPath = `${instructionsPath}.tmp-${process.pid}-${Date.now()}`;\n\n try {\n fs.writeFileSync(tmpPath, content, \"utf-8\");\n fs.renameSync(tmpPath, instructionsPath);\n filesWritten.push(instructionsPath);\n ctx.log.info(`Wrote ${instructionsPath}`);\n } catch (err) {\n // Clean up temp file on failure.\n try {\n if (fs.existsSync(tmpPath)) {\n fs.unlinkSync(tmpPath);\n }\n } catch {\n // swallow cleanup error\n }\n throw err;\n }\n\n return {\n hostId: this.hostId,\n extensionRoot,\n filesWritten,\n skipped,\n };\n }\n\n async unpublish(): Promise<void> {\n const extensionRoot = await this.resolveExtensionRoot();\n if (fs.existsSync(extensionRoot)) {\n fs.rmSync(extensionRoot, { recursive: true, force: true });\n }\n }\n}\n","/**\n * @remnic/core — Claude Code Memory Extension Publisher (stub)\n *\n * Placeholder publisher for Claude Code. Claude Code does not yet\n * support a file-based memory extension directory, so all methods are\n * no-ops that return safe defaults.\n */\n\nimport type {\n MemoryExtensionPublisher,\n PublishContext,\n PublishResult,\n PublisherCapabilities,\n} from \"./types.js\";\n\nexport class ClaudeCodeMemoryExtensionPublisher implements MemoryExtensionPublisher {\n readonly hostId = \"claude-code\";\n\n static readonly capabilities: PublisherCapabilities = {\n instructionsMd: false,\n skillsFolder: false,\n citationFormat: false,\n readPathTemplate: false,\n };\n\n async resolveExtensionRoot(): Promise<string> {\n // Claude Code does not have an extension directory yet.\n return \"\";\n }\n\n async isHostAvailable(): Promise<boolean> {\n return false;\n }\n\n async renderInstructions(_ctx: PublishContext): Promise<string> {\n return \"\";\n }\n\n async publish(_ctx: PublishContext): Promise<PublishResult> {\n return {\n hostId: this.hostId,\n extensionRoot: \"\",\n filesWritten: [],\n skipped: [],\n };\n }\n\n async unpublish(): Promise<void> {\n // no-op\n }\n}\n","/**\n * @remnic/core — Hermes Memory Extension Publisher (stub)\n *\n * Placeholder publisher for Hermes. Hermes uses a daemon-based\n * transport and does not currently consume file-based memory\n * extensions, so all methods are no-ops.\n */\n\nimport type {\n MemoryExtensionPublisher,\n PublishContext,\n PublishResult,\n PublisherCapabilities,\n} from \"./types.js\";\n\nexport class HermesMemoryExtensionPublisher implements MemoryExtensionPublisher {\n readonly hostId = \"hermes\";\n\n static readonly capabilities: PublisherCapabilities = {\n instructionsMd: false,\n skillsFolder: false,\n citationFormat: false,\n readPathTemplate: false,\n };\n\n async resolveExtensionRoot(): Promise<string> {\n // Hermes does not have an extension directory.\n return \"\";\n }\n\n async isHostAvailable(): Promise<boolean> {\n return false;\n }\n\n async renderInstructions(_ctx: PublishContext): Promise<string> {\n return \"\";\n }\n\n async publish(_ctx: PublishContext): Promise<PublishResult> {\n return {\n hostId: this.hostId,\n extensionRoot: \"\",\n filesWritten: [],\n skipped: [],\n };\n }\n\n async unpublish(): Promise<void> {\n // no-op\n }\n}\n","/**\n * @remnic/core — Memory Extension Publisher Registry\n *\n * Generic registry that host adapters populate at startup via\n * `registerPublisher()`. The publisher *classes* live in core so\n * adapters can import them, but the wiring of host-specific\n * implementations into the registry happens in the host adapter\n * layer (e.g. @remnic/cli), not here. This keeps core free of\n * host-specific knowledge (CLAUDE.md gotcha #31).\n *\n * Usage (from a host adapter):\n * import { registerPublisher, CodexMemoryExtensionPublisher } from \"@remnic/core\";\n * registerPublisher(\"codex\", () => new CodexMemoryExtensionPublisher());\n */\n\nexport type {\n MemoryExtensionPublisher,\n PublishContext,\n PublishResult,\n PublisherCapabilities,\n} from \"./types.js\";\n\nexport {\n REMNIC_SEMANTIC_OVERVIEW,\n REMNIC_CITATION_FORMAT,\n REMNIC_MCP_TOOL_INVENTORY,\n REMNIC_RECALL_DECISION_RULES,\n} from \"./shared-instructions.js\";\n\nexport { CodexMemoryExtensionPublisher } from \"./codex-publisher.js\";\nexport { ClaudeCodeMemoryExtensionPublisher } from \"./claude-code-publisher.js\";\nexport { HermesMemoryExtensionPublisher } from \"./hermes-publisher.js\";\n\nimport type { MemoryExtensionPublisher } from \"./types.js\";\n\n/**\n * Factory registry keyed by host ID. Each value is a zero-argument\n * factory that returns a fresh publisher instance.\n *\n * Starts empty — host adapters populate it via registerPublisher().\n */\nexport const PUBLISHERS: Record<string, () => MemoryExtensionPublisher> = {};\n\n/**\n * Register a publisher factory for a given host ID.\n *\n * Host adapters call this at startup to wire their host-specific\n * publisher implementations into the registry. Calling with an\n * existing hostId replaces the previous factory.\n */\nexport function registerPublisher(\n hostId: string,\n factory: () => MemoryExtensionPublisher,\n): void {\n PUBLISHERS[hostId] = factory;\n}\n\n/**\n * Maps connector IDs to publisher host IDs.\n *\n * Most connector IDs match their publisher host ID exactly (e.g.\n * \"claude-code\" -> \"claude-code\", \"hermes\" -> \"hermes\").\n * This map only needs entries for connector IDs that differ from\n * their publisher host ID. Connectors without a publisher (e.g.\n * \"cursor\", \"cline\") are intentionally absent.\n */\nconst CONNECTOR_TO_HOST: Record<string, string> = {\n \"codex-cli\": \"codex\",\n};\n\n/**\n * Resolve a connector ID to its publisher host ID.\n *\n * Returns the explicit mapping if one exists, otherwise returns\n * the connector ID itself (identity mapping covers the common case\n * where connector ID === host ID).\n */\nexport function hostIdForConnector(connectorId: string): string {\n return CONNECTOR_TO_HOST[connectorId] ?? connectorId;\n}\n\n/**\n * Look up a publisher by host ID.\n * Returns undefined for unknown host IDs rather than throwing.\n */\nexport function publisherFor(hostId: string): MemoryExtensionPublisher | undefined {\n const factory = PUBLISHERS[hostId];\n return factory ? factory() : undefined;\n}\n\n/**\n * Look up a publisher by connector ID.\n *\n * Resolves the connector ID to its host ID first (e.g. \"codex-cli\" -> \"codex\"),\n * then looks up the publisher. Returns undefined if no publisher exists for\n * the resolved host ID.\n */\nexport function publisherForConnector(connectorId: string): MemoryExtensionPublisher | undefined {\n return publisherFor(hostIdForConnector(connectorId));\n}\n","/**\n * Capsule fork semantics — issue #676 PR 4/6.\n *\n * A fork takes an existing capsule archive, imports it into a target memory\n * root under the `fork` conflict-resolution mode (which rebases all records\n * under `forks/<capsule-id>/`), and then writes a lineage breadcrumb at\n * `<targetRoot>/forks/<forkId>/lineage.json` recording the parent capsule's\n * identity. Subsequent forks of the same parent or of a fork produce a\n * queryable chain.\n *\n * The lineage breadcrumb is a pure JSON file — no gzip, no bundle format —\n * so downstream tooling can read it with a single `readFile` + `JSON.parse`\n * without pulling in the transfer pipeline.\n */\n\nimport { lstat, mkdir, readFile, realpath, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { importCapsule, type ImportCapsuleResult } from \"./capsule-import.js\";\nimport { assertIsDirectoryNotSymlink, assertRealpathInsideRoot } from \"./fs-utils.js\";\nimport type { CapsuleParent, ExportManifestV2 } from \"./types.js\";\nimport { CAPSULE_ID_PATTERN } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Options accepted by {@link forkCapsule}.\n *\n * `sourceArchive` — absolute or cwd-relative path to a `.capsule.json.gz`\n * archive produced by `exportCapsule`.\n *\n * `targetRoot` — absolute or cwd-relative path to the memory directory that\n * will receive the forked records. Must be an existing directory.\n *\n * `forkId` — user-chosen id for the fork. Validated against\n * {@link CAPSULE_ID_PATTERN}; must be unique under `<targetRoot>/forks/` (a\n * pre-existing `forks/<forkId>/` directory is rejected before any write).\n *\n * `versioning` — optional page-versioning config forwarded to\n * {@link importCapsule}. Only relevant when the target root already has files\n * that would be overwritten (fork mode is skip-on-exist by design, so this is\n * a no-op unless mode is changed in a future subclass).\n *\n * `now` — optional clock override (ms epoch) forwarded to `importCapsule` for\n * deterministic fork-id rewriting in tests.\n */\nexport interface ForkCapsuleOptions {\n sourceArchive: string;\n targetRoot: string;\n forkId: string;\n now?: number;\n}\n\n/**\n * The lineage breadcrumb written to `forks/<forkId>/lineage.json`.\n *\n * Fields are intentionally flat so the file is human-readable at a glance\n * and trivially diffable by `git diff`.\n *\n * `forkId` — the id supplied to `forkCapsule`.\n * `forkedAt` — ISO-8601 creation timestamp (UTC).\n * `parent` — structured linkage to the source capsule.\n * `importedRecords` — number of records written by the fork import.\n * `skippedRecords` — number of records skipped (target already existed).\n */\nexport interface ForkLineage {\n forkId: string;\n forkedAt: string;\n parent: CapsuleParent;\n importedRecords: number;\n skippedRecords: number;\n}\n\nexport interface ForkCapsuleResult {\n /** Absolute path to the source archive (unchanged, for chaining). */\n archivePath: string;\n /** The V2 manifest decoded from the source archive. */\n manifest: ExportManifestV2;\n /** Result of the underlying `importCapsule` call. */\n importResult: ImportCapsuleResult;\n /** The lineage breadcrumb that was written. */\n lineage: ForkLineage;\n /** Absolute path to the lineage breadcrumb file. */\n lineagePath: string;\n}\n\n// ---------------------------------------------------------------------------\n// Main function\n// ---------------------------------------------------------------------------\n\n/**\n * Fork a capsule archive into a target memory root.\n *\n * Sequence:\n * 1. Validate `forkId` against {@link CAPSULE_ID_PATTERN}.\n * 2. Resolve `targetRoot` and verify it is an existing directory (not a\n * symlink — mirrors {@link importCapsule}'s root validation).\n * 3. Reject if `forks/<forkId>/` already exists in the target root\n * (gotcha #49: deduplicate batch inputs; gotcha #25: don't destroy\n * old state).\n * 4. Import the archive in `\"fork\"` mode via {@link importCapsule}.\n * 5. Write the lineage breadcrumb at `forks/<forkId>/lineage.json`.\n * The breadcrumb dir is created by step 4 (importCapsule writes records\n * under `forks/<sourceId>/`); if `forkId !== sourceId` we may need to\n * create the fork dir ourselves. We always `mkdir -p` defensively.\n *\n * Error semantics:\n * - All validation errors throw before any filesystem write (fail-closed,\n * gotcha #25).\n * - If `importCapsule` throws after writing some records, the lineage\n * breadcrumb is NOT written (partial state is better than a false\n * \"fork complete\" marker — gotcha #12: write rollback data before\n * success markers).\n */\nexport async function forkCapsule(opts: ForkCapsuleOptions): Promise<ForkCapsuleResult> {\n // --- 1. Validate forkId ---\n validateForkId(opts.forkId);\n\n // --- 2. Validate targetRoot ---\n // Use the shared assertIsDirectoryNotSymlink helper from fs-utils.ts so\n // capsule-fork and capsule-import share the same symlink-safe validation\n // logic (Cursor medium #751 round 2: the fork's doc comment claims it\n // \"mirrors importCapsule's root validation\"; now it literally does).\n const rootAbs = path.resolve(opts.targetRoot);\n await assertIsDirectoryNotSymlink(rootAbs, \"forkCapsule\", \"targetRoot\");\n\n // --- 3. Reject duplicate forkId ---\n // Treat ANY existing filesystem entry at `forks/<forkId>` as occupied:\n // directory, regular file, or symlink. A previous version of this check\n // only rejected directories, so a stray file at the path would slip past\n // and `importCapsule` would still write under `forks/<sourceCapsule>/...`.\n // The later `mkdir`/`writeFile` for the breadcrumb would then fail,\n // leaving a partial fork import after reporting an error — violating the\n // documented \"reject before any write\" contract (Codex P2 #751 round 2).\n // `lstat` (not `stat`) is intentional so a symlink at the path is detected\n // even if its target is missing or otherwise unreadable.\n const forkDirAbs = path.join(rootAbs, \"forks\", opts.forkId);\n const forkEntryExists = await pathEntryExists(forkDirAbs);\n if (forkEntryExists) {\n throw new Error(\n `forkCapsule: fork path already exists — forkId \"${opts.forkId}\" is already in use at: ${forkDirAbs}`,\n );\n }\n\n // --- 4. Import in fork mode ---\n const archiveAbs = path.resolve(opts.sourceArchive);\n const importResult = await importCapsule({\n archivePath: archiveAbs,\n root: rootAbs,\n mode: \"fork\",\n now: opts.now,\n });\n\n const manifest = importResult.manifest;\n const sourceCapsule = manifest.capsule;\n\n // --- 5. Build lineage and write breadcrumb ---\n // The breadcrumb lives under the FORK's own directory, not the source\n // capsule's fork subtree. `forkId` may differ from `sourceCapsule.id`\n // (e.g. `forkCapsule({ forkId: \"my-fork\" })` with source `base-caps`\n // imports records under `forks/base-caps/` but the lineage breadcrumb\n // is written to `forks/my-fork/lineage.json` so a subsequent fork of\n // this fork can locate the breadcrumb by its own id).\n const forkedAt = new Date(opts.now ?? Date.now()).toISOString();\n\n const parent: CapsuleParent = {\n capsuleId: sourceCapsule.id,\n version: sourceCapsule.version,\n forkRoot: `forks/${sourceCapsule.id}`,\n };\n\n const lineage: ForkLineage = {\n forkId: opts.forkId,\n forkedAt,\n parent,\n importedRecords: importResult.imported.length,\n skippedRecords: importResult.skipped.length,\n };\n\n // Ensure the fork breadcrumb directory exists (it may not exist if forkId\n // differs from the source capsule's id, or if all records were skipped).\n const lineagePath = path.join(forkDirAbs, \"lineage.json\");\n\n // Guard lineage write against a symlinked `forks/` directory (or any\n // intermediate path component) pointing outside the memory root. If\n // `targetRoot/forks` is a symlink to `/tmp/evil`, a zero-record capsule\n // passes `importCapsule` without triggering per-record path checks and this\n // write would silently escape the root sandbox. We resolve the nearest\n // existing ancestor of `lineagePath` via `realpath` (same technique used by\n // `capsule-import` and `capsule-merge`) and verify the canonical path is\n // still inside `rootReal` before creating any directories or writing.\n //\n // Note: `rootReal` is computed from `rootAbs` here rather than reusing\n // `forkDirAbs` for the lexical check, because on macOS /tmp is a symlink\n // to /private/tmp and `path.relative(rootReal, forkDirAbs)` would produce\n // an absolute path if forkDirAbs was not also resolved. We skip the lexical\n // pre-check and rely solely on `assertRealpathInsideRoot` which handles\n // both the realpath walk and the containment check atomically.\n const rootReal = await realpath(rootAbs);\n // Symlink-safe containment check: walks the nearest existing ancestor and\n // confirms the canonical path is still inside rootReal.\n await assertRealpathInsideRoot(rootReal, lineagePath, `forks/${opts.forkId}/lineage.json`, \"forkCapsule\");\n\n await mkdir(path.dirname(lineagePath), { recursive: true });\n\n // Write breadcrumb AFTER import completes successfully — consistent with\n // gotcha #25 (don't destroy old state before new state is confirmed) and\n // gotcha #54 (write temp before rename / write before marker).\n await writeFile(lineagePath, JSON.stringify(lineage, null, 2) + \"\\n\", \"utf-8\");\n\n return {\n archivePath: archiveAbs,\n manifest,\n importResult,\n lineage,\n lineagePath,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Lineage query helper\n// ---------------------------------------------------------------------------\n\n/**\n * Read the lineage breadcrumb for a given fork in a memory root.\n *\n * Returns `null` when no breadcrumb exists (the directory is not a fork, or\n * was created before PR 4/6). Never throws for a missing file — callers\n * that need to distinguish \"not a fork\" from \"corrupt breadcrumb\" should\n * handle the JSON parse error themselves.\n *\n * `forkId` is validated against {@link CAPSULE_ID_PATTERN} before being\n * joined into the breadcrumb path so a malicious value like\n * `../../../../tmp` cannot escape the `forks/` namespace and resolve to\n * unrelated files outside the configured memory root (Codex P2 #751).\n * Invalid ids return `null` (same shape as \"no breadcrumb\"); callers that\n * need to distinguish \"invalid id\" from \"absent breadcrumb\" should validate\n * upstream.\n */\nexport async function readForkLineage(\n targetRoot: string,\n forkId: string,\n): Promise<ForkLineage | null> {\n // Reject any forkId that does not satisfy the capsule-id pattern. We use\n // the same constraints as `forkCapsule` so a path traversal payload like\n // `../../etc` is rejected before any filesystem access. Returning null\n // (rather than throwing) keeps the contract symmetric with the\n // \"breadcrumb not present\" case for the common get-or-default usage.\n if (\n typeof forkId !== \"string\" ||\n forkId.length === 0 ||\n forkId.length > 64 ||\n !CAPSULE_ID_PATTERN.test(forkId)\n ) {\n return null;\n }\n const rootAbs = path.resolve(targetRoot);\n // Resolve the root via realpath up-front so the symlink-safe containment\n // check below compares against the canonical path. If realpath fails\n // (root does not exist or is unreadable) we fall back to the lexical\n // root; the read will then return null for a missing breadcrumb anyway.\n const rootReal = await realpath(rootAbs).catch(() => rootAbs);\n\n const lineagePath = path.join(rootReal, \"forks\", forkId, \"lineage.json\");\n // Defensive lexical containment check: even though CAPSULE_ID_PATTERN\n // forbids `/` and `..`, an attacker who somehow bypasses the regex would\n // still be caught here. `path.relative` returns a `..`-prefixed string\n // when the target escapes the root.\n const rel = path.relative(rootReal, lineagePath);\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) {\n return null;\n }\n\n // Symlink-safe containment check (Codex P2 #751 round 2).\n // The lexical check above cannot detect a symlinked `forks/<forkId>`\n // directory whose target is outside the memory root. We resolve the\n // nearest existing ancestor of the breadcrumb path via realpath (which\n // follows symlinks), re-append the non-existent suffix, and verify the\n // result still lives under the real root. Mirrors the\n // `assertRealpathInsideRoot` pattern used by capsule-import.ts.\n if (!(await isLineagePathContained(rootReal, lineagePath))) {\n return null;\n }\n const raw = await readFile(lineagePath, \"utf-8\").catch(() => null);\n if (raw === null) return null;\n try {\n const parsed = JSON.parse(raw);\n // Basic shape check — we do not run full zod validation here so that\n // slightly malformed breadcrumbs (e.g. missing new fields added in later\n // PRs) can still be returned rather than silently dropped.\n if (typeof parsed !== \"object\" || parsed === null || typeof parsed.forkId !== \"string\") {\n return null;\n }\n return parsed as ForkLineage;\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nfunction validateForkId(forkId: unknown): void {\n if (typeof forkId !== \"string\") {\n throw new Error(\"forkCapsule: forkId must be a string\");\n }\n if (forkId.length === 0) {\n throw new Error(\"forkCapsule: forkId must not be empty\");\n }\n if (forkId.length > 64) {\n throw new Error(\"forkCapsule: forkId must be 64 characters or fewer\");\n }\n if (!CAPSULE_ID_PATTERN.test(forkId)) {\n throw new Error(\n `forkCapsule: invalid forkId \"${forkId}\". Expected alphanumeric with single dashes (no leading/trailing dashes, no consecutive dashes).`,\n );\n }\n}\n\n/**\n * Return true when ANY filesystem entry exists at {@link absPath} —\n * directory, regular file, symlink (even broken), or other special file.\n * Uses `lstat` so a symlink at the path is detected regardless of whether\n * its target resolves. Used by the duplicate-forkId check so a stray file\n * cannot bypass the \"reject before any write\" guarantee (Codex P2 #751).\n */\nasync function pathEntryExists(absPath: string): Promise<boolean> {\n const st = await lstat(absPath).catch(() => null);\n return st !== null;\n}\n\n/**\n * Symlink-safe containment check for {@link readForkLineage}.\n *\n * Walks from {@link lineagePath} toward {@link rootReal} until it finds a\n * path component that exists on disk, resolves that prefix via `realpath`\n * (which follows symlinks), then re-appends the non-existent suffix and\n * verifies the resulting canonical path is still inside {@link rootReal}.\n *\n * This catches the case where any subdirectory in the path is a symlink\n * pointing outside the intended root. Returns `true` when the path is\n * safely contained, `false` otherwise.\n *\n * Mirrors the `assertRealpathInsideRoot` helper in `capsule-import.ts`.\n * Returning a boolean (rather than throwing) keeps the contract aligned\n * with `readForkLineage`'s \"return null on any safety failure\" pattern.\n */\nasync function isLineagePathContained(\n rootReal: string,\n lineagePath: string,\n): Promise<boolean> {\n let existing = lineagePath;\n const suffix: string[] = [];\n while (existing !== path.dirname(existing)) {\n const st = await lstat(existing).catch(() => null);\n if (st !== null) break;\n suffix.unshift(path.basename(existing));\n existing = path.dirname(existing);\n }\n\n // If we walked all the way to the filesystem root without finding\n // anything that exists, the path is harmless (no symlinks to follow).\n // The subsequent readFile will simply fail and return null.\n const existingReal = await realpath(existing).catch(() => existing);\n const targetReal = suffix.length > 0 ? path.join(existingReal, ...suffix) : existingReal;\n\n const rel = path.relative(rootReal, targetReal);\n if (rel === \"\") return true;\n if (rel === \"..\") return false;\n if (rel.startsWith(`..${path.sep}`)) return false;\n if (path.isAbsolute(rel)) return false;\n return true;\n}\n"],"mappings":"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","names":["j","fsp","path","fsp","path","crypto","fsp","path","crypto","hashFile","fsp","crypto","path","log","verifyResult","path","path","fs","path","fs","path","crypto","fs","path","parseFrontmatter","extractBody","crypto","fs","path","crypto","hashContent","fs","path","readFileSafe","parseFrontmatter","extractBody","crypto","fs","path","fs","isPathInside","path","parseFrontmatter","extractBody","readFileSafe","fs","path","crypto","DEFAULT_EXCLUDE","hashContent","crypto","fs","path","path","fs","manifestPath","manifestDir","crypto","previousId","walkMd","hashContent","fs","path","path","fs","path","path"]}
1
+ {"version":3,"sources":["../src/coding/review-context.ts","../src/binary-lifecycle/types.ts","../src/binary-lifecycle/backend.ts","../src/binary-lifecycle/scanner.ts","../src/binary-lifecycle/manifest.ts","../src/binary-lifecycle/pipeline.ts","../src/projection/index.ts","../src/onboarding/index.ts","../src/curation/index.ts","../src/dedup/index.ts","../src/review/index.ts","../src/sync/index.ts","../src/spaces/index.ts","../src/memory-extension/shared-instructions.ts","../src/memory-extension/codex-publisher.ts","../src/memory-extension/claude-code-publisher.ts","../src/memory-extension/hermes-publisher.ts","../src/memory-extension/index.ts","../src/transfer/capsule-fork.ts"],"sourcesContent":["/**\n * Diff-aware review-context packer (issue #569 PR 4).\n *\n * When an agent is asked \"review this PR\" / \"what changed in this diff\" /\n * \"look at this diff\", the prompt that reaches recall is short and generic\n * — the real signal is the diff itself. This module:\n *\n * 1. Detects review-intent prompts via `isReviewPrompt`.\n * 2. Extracts the touched file list from a unified diff via\n * `parseTouchedFiles`.\n * 3. Re-ranks a set of candidate memories so that memories whose\n * `entityRefs` mention a touched path float to the top. The boost is\n * additive and bounded so it doesn't obliterate the original ranking —\n * it's a bias, not a filter.\n *\n * Pure — no orchestrator, no storage. Callers inject the candidate memories\n * they already have from their normal recall pipeline. This keeps the\n * module easy to test and integrates cleanly with the existing tiered-recall\n * code in `orchestrator.ts` (the tier itself can be wired later; the pure\n * surface is what PRs 5/6/7 will call).\n */\n\n// ──────────────────────────────────────────────────────────────────────────\n// Public types\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * A memory candidate as fed into review-context ranking. The shape is a\n * deliberate subset of the core `MemorySummary` / recall result — only the\n * fields we actually need — so this module stays decoupled from the rest of\n * the codebase and can be reused by CLI tools, bench fixtures, etc.\n */\nexport interface ReviewCandidate {\n /** Opaque identifier. Echoed unchanged in the output. */\n id: string;\n /**\n * Pre-review relevance score from the upstream recall pipeline. Higher is\n * better. `0` is treated as \"no prior signal\" and gets the full review\n * boost when a path match is found.\n */\n score: number;\n /**\n * References the memory mentions (file paths, entity names, etc.). Used\n * to decide whether any touched file appears in the memory's scope.\n *\n * Accepts `undefined`/missing so callers can pass sparse records from\n * legacy storage without pre-filling.\n */\n entityRefs?: string[];\n}\n\nexport interface ReviewContext {\n /**\n * Normalized file paths touched by the diff. Each entry is forward-slashed\n * and relative to the repo root when possible.\n */\n touchedFiles: string[];\n /**\n * Candidates re-sorted so memories whose `entityRefs` mention a touched\n * path are boosted. Shape matches the input `ReviewCandidate[]` — the\n * boost is recorded on each entry as `boost` for observability.\n */\n rankedRecall: Array<ReviewCandidate & { boost: number }>;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Review-prompt heuristic\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Keyword list from the #569 design doc, plus obvious paraphrases. All\n * matching is case-insensitive and whole-word (so `reviewer` doesn't trigger\n * on `review` alone).\n */\nconst REVIEW_KEYWORD_PATTERNS: RegExp[] = [\n /\\breview\\b/i,\n /\\bdiff\\b/i,\n /\\bwhat changed\\b/i,\n /\\blook at this pr\\b/i,\n /\\bwhat('?s|\\s+is)\\s+in\\s+this\\s+(pr|patch|diff|change)\\b/i,\n /\\bcode review\\b/i,\n];\n\n/**\n * `true` when the prompt looks like a review / diff-explanation request.\n *\n * Empty / non-string input → `false` (the caller shouldn't branch on an\n * invalid prompt).\n */\nexport function isReviewPrompt(prompt: string | null | undefined): boolean {\n if (typeof prompt !== \"string\") return false;\n const trimmed = prompt.trim();\n if (!trimmed) return false;\n return REVIEW_KEYWORD_PATTERNS.some((re) => re.test(trimmed));\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Unified-diff parser — extract touched files\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Parse a unified diff and return the set of files touched. Accepts both the\n * `diff --git` form (`diff --git a/foo b/bar`) and the `--- / +++` form\n * (`--- a/foo\\n+++ b/bar`). Returns deduplicated, repo-root-relative paths\n * (with the conventional `a/` / `b/` prefixes stripped).\n *\n * Path entries of `/dev/null` (used in adds/deletes) are excluded.\n */\nexport function parseTouchedFiles(diff: string | null | undefined): string[] {\n if (typeof diff !== \"string\" || !diff.trim()) return [];\n const touched = new Set<string>();\n const lines = diff.split(/\\r?\\n/);\n\n for (const line of lines) {\n // `diff --git a/foo/bar.ts b/foo/bar.ts`\n //\n // Paths may be quoted by git when they contain spaces or non-ASCII\n // characters, e.g. `diff --git \"a/src/my file.ts\" \"b/src/my file.ts\"`.\n // The two paths are always separated by whitespace at the top level, but\n // whitespace INSIDE quoted paths must NOT split the tokens. Parse the\n // two paths with an explicit tokenizer instead of a `\\S+`-based regex\n // (which would shatter `\"a/my file.ts\"` into `\"a/my` / `file.ts\"`).\n const gitPrefix = line.match(/^diff --git\\s+/);\n if (gitPrefix) {\n const rest = line.slice(gitPrefix[0].length);\n const paths = splitDiffGitPaths(rest);\n if (paths) {\n for (const raw of paths) {\n const stripped = stripDiffPathPrefix(raw);\n if (stripped && stripped !== \"/dev/null\") touched.add(stripped);\n }\n }\n continue;\n }\n // `--- a/foo/bar.ts` or `+++ b/foo/bar.ts` — or quoted:\n // `--- \"a/foo bar.ts\"` / `+++ \"b/foo bar.ts\"` when git emits C-quoted\n // paths for whitespace or non-ASCII filenames.\n //\n // Matched with an anchored prefix and an explicit tokenizer for the\n // tail so quoted paths containing whitespace are not split on the\n // first internal space. The previous `\\S+` form silently dropped\n // everything after the first whitespace in a quoted path.\n const headerPrefix = line.match(/^(?:---|\\+\\+\\+)[ \\t]+/);\n if (headerPrefix) {\n // Linear trailing space/tab trim instead of /[ \\t]+$/, whose anchored\n // quantifier backtracks polynomially on a long diff line (CodeQL\n // js/polynomial-redos).\n const sliced = line.slice(headerPrefix[0].length);\n let tailEnd = sliced.length;\n while (tailEnd > 0 && (sliced[tailEnd - 1] === \" \" || sliced[tailEnd - 1] === \"\\t\")) tailEnd--;\n const tail = sliced.slice(0, tailEnd);\n const raw = extractSingleDiffPathToken(tail);\n if (raw) {\n const stripped = stripDiffPathPrefix(raw);\n if (stripped && stripped !== \"/dev/null\") touched.add(stripped);\n }\n }\n }\n\n return Array.from(touched).sort();\n}\n\n/**\n * Extract the single path token from the tail of a `---` / `+++` header\n * line. Returns `null` when the tail is empty or malformed (e.g. an\n * unterminated quoted path). The whole tail is consumed — trailing\n * timestamps from non-git diff frontends (`--- a/foo\t2023-01-01`) fall\n * into a leading-token extraction like the quoted-form case.\n */\nfunction extractSingleDiffPathToken(tail: string): string | null {\n if (tail.length === 0) return null;\n if (tail[0] === '\"') {\n let j = 1;\n while (j < tail.length) {\n if (tail[j] === \"\\\\\" && j + 1 < tail.length) {\n j += 2;\n continue;\n }\n if (tail[j] === '\"') break;\n j += 1;\n }\n if (j >= tail.length) return null; // unterminated quoted path\n return tail.slice(0, j + 1);\n }\n // Unquoted: consume up to the first tab or whitespace-run, so standard\n // `--- a/foo\t<timestamp>` lines surface just `a/foo`. For ordinary\n // git-style output the tail has no whitespace at all.\n let j = 0;\n while (j < tail.length && tail[j] !== \" \" && tail[j] !== \"\\t\") j += 1;\n return tail.slice(0, j);\n}\n\n/**\n * Split the `a-path b-path` portion of a `diff --git` line into exactly two\n * path tokens, respecting git's quoting convention. Returns `null` when the\n * input cannot be parsed into exactly two tokens.\n */\nfunction splitDiffGitPaths(rest: string): [string, string] | null {\n const tokens: string[] = [];\n let i = 0;\n while (i < rest.length && tokens.length < 2) {\n // Skip leading whitespace between tokens.\n while (i < rest.length && (rest[i] === \" \" || rest[i] === \"\\t\")) i += 1;\n if (i >= rest.length) break;\n if (rest[i] === '\"') {\n // Quoted path: consume up to the matching unescaped `\"`. Git escapes\n // inner quotes as `\\\"`, so we respect backslash escaping.\n let j = i + 1;\n while (j < rest.length) {\n if (rest[j] === \"\\\\\" && j + 1 < rest.length) {\n j += 2;\n continue;\n }\n if (rest[j] === '\"') break;\n j += 1;\n }\n if (j >= rest.length) return null; // unterminated quoted path\n tokens.push(rest.slice(i, j + 1));\n i = j + 1;\n } else {\n // Unquoted path: run of non-whitespace.\n let j = i;\n while (j < rest.length && rest[j] !== \" \" && rest[j] !== \"\\t\") j += 1;\n tokens.push(rest.slice(i, j));\n i = j;\n }\n }\n if (tokens.length !== 2) return null;\n return [tokens[0]!, tokens[1]!];\n}\n\nfunction stripDiffPathPrefix(raw: string): string {\n // Git conventionally prefixes paths with `a/` or `b/` in diffs, and\n // quotes the whole path (including the prefix) when it contains spaces or\n // non-ASCII bytes. Quote-stripping must therefore happen BEFORE the\n // prefix check — otherwise `\"a/path with spaces.ts\"` still starts with\n // `\"a` and the prefix is never recognized.\n let s = raw;\n if (s.length >= 2 && s[0] === '\"' && s[s.length - 1] === '\"') {\n const decoded = decodeGitCQuotedPath(s.slice(1, -1));\n if (decoded === null) {\n return raw;\n }\n s = decoded;\n }\n // Normalize Windows-style backslashes. Must happen AFTER quote stripping\n // so that C-quote escape pairs are decoded before path separators are\n // normalized.\n s = s.replace(/\\\\/g, \"/\");\n if (s.startsWith(\"a/\") || s.startsWith(\"b/\")) s = s.slice(2);\n return s;\n}\n\nfunction decodeGitCQuotedPath(value: string): string | null {\n const bytes: number[] = [];\n const encoder = new TextEncoder();\n const appendText = (text: string) => {\n bytes.push(...encoder.encode(text));\n };\n\n for (let index = 0; index < value.length; index += 1) {\n const char = value[index]!;\n if (char !== \"\\\\\") {\n appendText(char);\n continue;\n }\n\n if (index + 1 >= value.length) {\n appendText(\"\\\\\");\n continue;\n }\n\n const next = value[index + 1]!;\n if (next >= \"0\" && next <= \"7\") {\n let octal = next;\n let cursor = index + 2;\n while (cursor < value.length && octal.length < 3) {\n const digit = value[cursor]!;\n if (digit < \"0\" || digit > \"7\") break;\n octal += digit;\n cursor += 1;\n }\n bytes.push(Number.parseInt(octal, 8));\n index = cursor - 1;\n continue;\n }\n\n const escaped = cEscapeValue(next);\n if (escaped !== null) {\n appendText(escaped);\n index += 1;\n continue;\n }\n\n appendText(`\\\\${next}`);\n index += 1;\n }\n\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(Uint8Array.from(bytes));\n } catch {\n return null;\n }\n}\n\nfunction cEscapeValue(value: string): string | null {\n switch (value) {\n case \"n\":\n return \"\\n\";\n case \"t\":\n return \"\\t\";\n case \"r\":\n return \"\\r\";\n case \"b\":\n return \"\\b\";\n case \"f\":\n return \"\\f\";\n case \"\\\\\":\n case '\"':\n return value;\n default:\n return null;\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Ranking\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Additive boost per matching touched-file. Tuned so that a single exact\n * match is enough to float a `score=0` candidate above a `score=0.4`\n * unmatched peer, but not so large it buries multi-signal results. `0.5`\n * per match, capped at `1.0` so three matches don't eclipse strong recall.\n */\nconst BOOST_PER_MATCH = 0.5;\nconst MAX_BOOST = 1.0;\n\n/**\n * Count how many touched files appear in a memory's entityRefs. Matches are\n * literal substring matches on either direction — either the ref contains\n * the path, or the path contains the ref — so both\n * - `\"src/foo.ts\"` refs matching a touched `\"src/foo.ts\"`, and\n * - `\"foo.ts\"` refs matching a touched `\"src/foo.ts\"`\n * succeed.\n */\nfunction countPathHits(entityRefs: string[] | undefined, touchedFiles: string[]): number {\n if (!entityRefs || entityRefs.length === 0) return 0;\n if (touchedFiles.length === 0) return 0;\n let hits = 0;\n for (const ref of entityRefs) {\n if (typeof ref !== \"string\" || !ref) continue;\n const lowered = ref.toLowerCase();\n for (const file of touchedFiles) {\n const flower = file.toLowerCase();\n if (lowered === flower) {\n hits += 1;\n break;\n }\n if (lowered.includes(flower) || flower.includes(lowered)) {\n hits += 1;\n break;\n }\n }\n }\n return hits;\n}\n\n/**\n * Build a review-context ranking for a set of candidate memories.\n *\n * Contract:\n * - `touchedFiles` is the parsed diff file list.\n * - `candidates` is passed through unchanged when no boost applies.\n * - When a boost applies, the result is sorted by `(score + boost)` desc,\n * with a stable secondary sort on the original `id` for determinism\n * (CLAUDE.md #19 — comparators must return 0 for equal items).\n */\nexport function rankReviewCandidates(\n candidates: ReviewCandidate[],\n touchedFiles: string[],\n): Array<ReviewCandidate & { boost: number }> {\n const annotated: Array<ReviewCandidate & { boost: number }> = candidates.map((c) => {\n const hits = countPathHits(c.entityRefs, touchedFiles);\n const boost = Math.min(MAX_BOOST, hits * BOOST_PER_MATCH);\n return { ...c, boost };\n });\n\n annotated.sort((a, b) => {\n const adjA = a.score + a.boost;\n const adjB = b.score + b.boost;\n if (adjA !== adjB) return adjB - adjA;\n // Stable secondary sort for deterministic ordering on ties.\n if (a.id < b.id) return -1;\n if (a.id > b.id) return 1;\n return 0;\n });\n\n return annotated;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Packer entry point\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface PackReviewContextInput {\n /** Unified diff, as produced by `git diff`. */\n diff: string | null | undefined;\n /** Candidate memories from the upstream recall pipeline. */\n candidates: ReviewCandidate[];\n}\n\n/**\n * Top-level entry point used by the orchestrator (and CLI / bench) when a\n * review-intent prompt is detected.\n *\n * Parses the diff, re-ranks the candidates, and returns both artefacts so\n * the caller can surface `touchedFiles` as context and `rankedRecall` as\n * the recall result.\n */\nexport function packReviewContext(input: PackReviewContextInput): ReviewContext {\n const touchedFiles = parseTouchedFiles(input.diff);\n const rankedRecall = rankReviewCandidates(input.candidates, touchedFiles);\n return { touchedFiles, rankedRecall };\n}\n","/**\n * Binary file lifecycle management types.\n *\n * Defines the configuration, manifest, and record structures for the\n * three-stage binary lifecycle pipeline: mirror, redirect, clean.\n */\n\nexport interface BinaryLifecycleConfig {\n /** Master toggle. Default: false. */\n enabled: boolean;\n /** Days after mirror before local copy is eligible for cleanup. Default: 7. */\n gracePeriodDays: number;\n /** Files larger than this are skipped during scan. Default: 50 MB. */\n maxBinarySizeBytes: number;\n /** Glob patterns for binary file types to manage. */\n scanPatterns: string[];\n /** Backend configuration for binary storage. */\n backend: BinaryStorageBackendConfig;\n}\n\nexport interface BinaryStorageBackendConfig {\n /** Backend type. \"filesystem\" copies to a local directory. \"none\" is a no-op (dry-run/testing). */\n type: \"filesystem\" | \"s3\" | \"none\";\n /** Destination directory for the filesystem backend. */\n basePath?: string;\n /** S3 bucket name (future). */\n s3Bucket?: string;\n /** S3 region (future). */\n s3Region?: string;\n /** S3 key prefix (future). */\n s3Prefix?: string;\n}\n\nexport type BinaryAssetStatus =\n | \"pending\"\n | \"mirrored\"\n | \"redirected\"\n | \"cleaned\"\n | \"error\";\n\nexport interface BinaryAssetRecord {\n /** Relative path from memoryDir to the original file. */\n originalPath: string;\n /** Path (or URL) in the backend storage. */\n mirroredPath: string;\n /** Optional user-resolvable target to write into markdown links. */\n redirectPath?: string;\n /** SHA-256 hex digest of file content. */\n contentHash: string;\n /** File size in bytes. */\n sizeBytes: number;\n /** MIME type (e.g. \"image/png\"). */\n mimeType: string;\n /** ISO 8601 timestamp when the file was mirrored. */\n mirroredAt: string;\n /** ISO 8601 timestamp when markdown references were rewritten. */\n redirectedAt?: string;\n /** ISO 8601 timestamp when the local copy was deleted. */\n cleanedAt?: string;\n /** Current lifecycle status. */\n status: BinaryAssetStatus;\n}\n\nexport interface BinaryLifecycleManifest {\n version: 1;\n assets: BinaryAssetRecord[];\n lastScanAt?: string;\n}\n\nexport interface PipelineResult {\n scanned: number;\n mirrored: number;\n redirected: number;\n cleaned: number;\n errors: string[];\n dryRun: boolean;\n}\n\nexport const DEFAULT_SCAN_PATTERNS = [\n \"*.png\",\n \"*.jpg\",\n \"*.jpeg\",\n \"*.gif\",\n \"*.pdf\",\n \"*.mp3\",\n \"*.mp4\",\n \"*.wav\",\n];\n\nexport const DEFAULT_MAX_BINARY_SIZE_BYTES = 50 * 1024 * 1024; // 50 MB\nexport const DEFAULT_GRACE_PERIOD_DAYS = 7;\n","/**\n * Binary storage backend interface and implementations.\n *\n * Backends handle the actual persistence of binary files to an external\n * location. The pipeline calls upload/exists/delete through this interface\n * so swapping storage providers requires no pipeline changes.\n */\n\nimport type { Stats } from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { BinaryStorageBackendConfig } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Interface\n// ---------------------------------------------------------------------------\n\nexport interface BinaryStorageBackend {\n /** Discriminator for the backend type. */\n readonly type: string;\n /**\n * Upload a local file to the backend.\n * @returns The backend path or URL where the file was stored.\n */\n upload(localPath: string, remotePath: string): Promise<string>;\n /** Check whether a remote path already exists in the backend. */\n exists(remotePath: string): Promise<boolean>;\n /** Delete a file from the backend. */\n delete(remotePath: string): Promise<void>;\n /** Return the user-resolvable markdown target for a stored backend path. */\n getRedirectTarget?(remotePath: string): string;\n}\n\n// ---------------------------------------------------------------------------\n// Filesystem backend\n// ---------------------------------------------------------------------------\n\nexport class FilesystemBackend implements BinaryStorageBackend {\n readonly type = \"filesystem\";\n private readonly basePath: string;\n\n constructor(basePath: string) {\n if (!basePath || basePath.trim().length === 0) {\n throw new Error(\"FilesystemBackend requires a non-empty basePath\");\n }\n this.basePath = path.resolve(basePath);\n }\n\n private resolveRemotePath(remotePath: string): string {\n const resolved = path.isAbsolute(remotePath)\n ? path.resolve(remotePath)\n : path.resolve(this.basePath, remotePath);\n const relative = path.relative(this.basePath, resolved);\n if (relative === \"..\" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {\n throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);\n }\n return resolved;\n }\n\n private isInsideBase(candidate: string, realBase: string): boolean {\n const relative = path.relative(realBase, candidate);\n return relative === \"\" || (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));\n }\n\n private async realBasePathIfExists(): Promise<string | null> {\n try {\n const stat = await fsp.lstat(this.basePath);\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend basePath must not be a symlink: ${this.basePath}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`FilesystemBackend basePath must be a directory: ${this.basePath}`);\n }\n return await fsp.realpath(this.basePath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw err;\n }\n }\n\n private async ensureBaseDirectory(): Promise<string> {\n await fsp.mkdir(this.basePath, { recursive: true });\n const realBase = await this.realBasePathIfExists();\n if (realBase === null) {\n throw new Error(`FilesystemBackend failed to create basePath: ${this.basePath}`);\n }\n return realBase;\n }\n\n private async ensureSafeParentDirectory(dest: string): Promise<string> {\n const realBase = await this.ensureBaseDirectory();\n const destDir = path.dirname(dest);\n const relativeDir = path.relative(this.basePath, destDir);\n const segments = relativeDir === \"\" ? [] : relativeDir.split(path.sep);\n let current = this.basePath;\n\n for (const segment of segments) {\n if (segment === \".\" || segment === \"\") continue;\n current = path.join(current, segment);\n try {\n const stat = await fsp.lstat(current);\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend remotePath traverses symlink: ${current}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`FilesystemBackend remotePath parent is not a directory: ${current}`);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n await fsp.mkdir(current);\n }\n }\n\n const realParent = await fsp.realpath(destDir);\n if (!this.isInsideBase(realParent, realBase)) {\n throw new Error(`FilesystemBackend remotePath parent escapes basePath: ${dest}`);\n }\n return realBase;\n }\n\n private async resolveExistingRemotePath(remotePath: string): Promise<string | null> {\n const dest = this.resolveRemotePath(remotePath);\n const realBase = await this.realBasePathIfExists();\n if (realBase === null) {\n return null;\n }\n\n const destDir = path.dirname(dest);\n const relativeDir = path.relative(this.basePath, destDir);\n const segments = relativeDir === \"\" ? [] : relativeDir.split(path.sep);\n let current = this.basePath;\n for (const segment of segments) {\n if (segment === \".\" || segment === \"\") continue;\n current = path.join(current, segment);\n let stat: Stats;\n try {\n stat = await fsp.lstat(current);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw err;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend remotePath traverses symlink: ${current}`);\n }\n if (!stat.isDirectory()) {\n return null;\n }\n }\n\n const realParent = await fsp.realpath(destDir).catch((err: NodeJS.ErrnoException) => {\n if (err.code === \"ENOENT\") return null;\n throw err;\n });\n if (realParent === null) {\n return null;\n }\n if (!this.isInsideBase(realParent, realBase)) {\n throw new Error(`FilesystemBackend remotePath parent escapes basePath: ${JSON.stringify(remotePath)}`);\n }\n\n try {\n const stat = await fsp.lstat(dest);\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);\n }\n if (!stat.isFile()) {\n return null;\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw err;\n }\n\n const realDest = await fsp.realpath(dest);\n if (!this.isInsideBase(realDest, realBase)) {\n throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);\n }\n return dest;\n }\n\n async upload(localPath: string, remotePath: string): Promise<string> {\n if (path.isAbsolute(remotePath)) {\n throw new Error(`FilesystemBackend upload remotePath must be relative: ${JSON.stringify(remotePath)}`);\n }\n const dest = this.resolveRemotePath(remotePath);\n const realBase = await this.ensureSafeParentDirectory(dest);\n try {\n const stat = await fsp.lstat(dest);\n if (stat.isSymbolicLink()) {\n throw new Error(`FilesystemBackend remotePath points to symlink: ${dest}`);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n }\n await fsp.copyFile(localPath, dest);\n const realDest = await fsp.realpath(dest);\n if (!this.isInsideBase(realDest, realBase)) {\n throw new Error(`FilesystemBackend remotePath escapes basePath: ${JSON.stringify(remotePath)}`);\n }\n return remotePath;\n }\n\n async exists(remotePath: string): Promise<boolean> {\n const dest = await this.resolveExistingRemotePath(remotePath);\n return dest !== null;\n }\n\n async delete(remotePath: string): Promise<void> {\n const dest = await this.resolveExistingRemotePath(remotePath);\n if (dest === null) {\n return;\n }\n try {\n await fsp.unlink(dest);\n } catch (err: unknown) {\n // Ignore ENOENT (already deleted); rethrow everything else.\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n }\n }\n\n getRedirectTarget(remotePath: string): string {\n return this.resolveRemotePath(remotePath);\n }\n}\n\n// ---------------------------------------------------------------------------\n// None backend (no-op, for dry-run / testing)\n// ---------------------------------------------------------------------------\n\nexport class NoneBackend implements BinaryStorageBackend {\n readonly type = \"none\";\n\n async upload(_localPath: string, remotePath: string): Promise<string> {\n return remotePath;\n }\n\n async exists(_remotePath: string): Promise<boolean> {\n return false;\n }\n\n async delete(_remotePath: string): Promise<void> {\n // intentional no-op\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createBackend(cfg: BinaryStorageBackendConfig): BinaryStorageBackend {\n switch (cfg.type) {\n case \"filesystem\": {\n if (!cfg.basePath) {\n throw new Error(\n \"BinaryStorageBackendConfig.basePath is required when type is \\\"filesystem\\\"\",\n );\n }\n return new FilesystemBackend(cfg.basePath);\n }\n case \"s3\":\n throw new Error(\"S3 binary storage backend is not yet implemented\");\n case \"none\":\n return new NoneBackend();\n default:\n throw new Error(`Unknown binary storage backend type: ${String((cfg as { type: string }).type)}`);\n }\n}\n","/**\n * Binary file scanner.\n *\n * Recursively walks the memory directory, matches files against configured\n * glob patterns, skips files already tracked in the manifest, and respects\n * the max-size limit.\n */\n\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport type { BinaryLifecycleConfig, BinaryLifecycleManifest } from \"./types.js\";\n\n/**\n * Test whether a filename matches any of the provided glob patterns.\n * Supports simple `*.ext` patterns (the default scan patterns).\n * For more complex globs a proper library should be used; this covers\n * the 95% case without adding a dependency.\n */\nexport function matchesPatterns(filename: string, patterns: string[]): boolean {\n const lower = filename.toLowerCase();\n for (const pattern of patterns) {\n // Simple *.ext matching\n if (pattern.startsWith(\"*.\")) {\n const ext = pattern.slice(1).toLowerCase(); // e.g. \".png\"\n if (lower.endsWith(ext)) return true;\n } else if (lower === pattern.toLowerCase()) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Scan memoryDir recursively for binary files matching the configured patterns.\n * Returns relative paths (relative to memoryDir) for files not yet tracked.\n */\nexport async function scanForBinaries(\n memoryDir: string,\n config: BinaryLifecycleConfig,\n manifest: BinaryLifecycleManifest,\n): Promise<string[]> {\n const tracked = new Map(manifest.assets.map((a) => [a.originalPath, a]));\n const results: string[] = [];\n\n async function walk(dir: string): Promise<void> {\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fsp.readdir(dir, { withFileTypes: true });\n } catch {\n return; // skip unreadable directories\n }\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n // Normalize to POSIX separators so redirect matching works on Windows\n // (markdown links always use forward slashes).\n const relativePath = path.relative(memoryDir, fullPath).split(path.sep).join(\"/\");\n\n if (entry.isDirectory()) {\n // Skip the manifest directory itself and hidden dirs starting with .\n if (entry.name === \".binary-lifecycle\") continue;\n await walk(fullPath);\n continue;\n }\n\n if (!entry.isFile()) continue;\n\n // Check pattern match\n if (!matchesPatterns(entry.name, config.scanPatterns)) continue;\n\n // Check file size\n try {\n const stat = await fsp.stat(fullPath);\n if (stat.size > config.maxBinarySizeBytes) continue;\n if (stat.size === 0) continue; // skip empty files\n const existing = tracked.get(relativePath);\n if (existing) {\n if (existing.sizeBytes !== stat.size) {\n results.push(relativePath);\n continue;\n }\n const contentHash = await hashFile(fullPath);\n if (existing.contentHash !== contentHash) {\n results.push(relativePath);\n }\n continue;\n }\n } catch {\n continue; // stat failure, skip\n }\n\n results.push(relativePath);\n }\n }\n\n await walk(memoryDir);\n return results;\n}\n\nasync function hashFile(filePath: string): Promise<string> {\n const content = await fsp.readFile(filePath);\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n","/**\n * Binary lifecycle manifest — read/write operations.\n *\n * The manifest lives at `${memoryDir}/.binary-lifecycle/manifest.json`.\n * Writes use the atomic temp-then-rename pattern (CLAUDE.md #54).\n */\n\nimport fs from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport type { BinaryLifecycleManifest } from \"./types.js\";\n\nconst MANIFEST_DIR = \".binary-lifecycle\";\nconst MANIFEST_FILE = \"manifest.json\";\n\nexport function manifestDir(memoryDir: string): string {\n return path.join(memoryDir, MANIFEST_DIR);\n}\n\nexport function manifestPath(memoryDir: string): string {\n return path.join(memoryDir, MANIFEST_DIR, MANIFEST_FILE);\n}\n\n/**\n * Read the manifest from disk. Returns a fresh empty manifest if the file\n * does not exist. Existing invalid manifests fail closed so the pipeline does\n * not overwrite state needed for safe cleanup.\n */\nexport async function readManifest(memoryDir: string): Promise<BinaryLifecycleManifest> {\n const filePath = manifestPath(memoryDir);\n let raw: string;\n try {\n raw = await fsp.readFile(filePath, \"utf-8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return emptyManifest();\n }\n throw new Error(`Failed to read binary lifecycle manifest at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(`Invalid binary lifecycle manifest JSON at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n // CLAUDE.md #18: validate the parsed result is a non-null object.\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Invalid binary lifecycle manifest shape at ${filePath}: expected object`);\n }\n const obj = parsed as Record<string, unknown>;\n if (obj.version !== 1 || !Array.isArray(obj.assets)) {\n throw new Error(`Invalid binary lifecycle manifest shape at ${filePath}: expected version 1 with assets array`);\n }\n return parsed as BinaryLifecycleManifest;\n}\n\n/**\n * Write the manifest atomically: write to a temp file, then rename.\n * CLAUDE.md #54: never delete before write. Write temp first, rename atomically.\n */\nexport async function writeManifest(\n memoryDir: string,\n manifest: BinaryLifecycleManifest,\n): Promise<void> {\n const dir = manifestDir(memoryDir);\n await fsp.mkdir(dir, { recursive: true });\n const dest = manifestPath(memoryDir);\n const tmpSuffix = crypto.randomBytes(8).toString(\"hex\");\n const tmpPath = `${dest}.${tmpSuffix}.tmp`;\n // Sort keys for deterministic output (CLAUDE.md #38).\n const content = JSON.stringify(manifest, null, 2) + \"\\n\";\n await fsp.writeFile(tmpPath, content, \"utf-8\");\n try {\n await fsp.rename(tmpPath, dest);\n } catch (renameErr) {\n // Clean up temp on rename failure (cross-device edge case).\n try {\n await fsp.unlink(tmpPath);\n } catch {\n // ignore cleanup failure\n }\n throw renameErr;\n }\n}\n\nexport function emptyManifest(): BinaryLifecycleManifest {\n return { version: 1, assets: [] };\n}\n","/**\n * Binary lifecycle pipeline — mirror, redirect, clean.\n *\n * Three-stage pipeline:\n * 1. Mirror: upload binary to backend, record in manifest\n * 2. Redirect: scan markdown for inline refs, replace with redirect path\n * 3. Clean: after grace period, delete local copy\n */\n\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport type {\n BinaryAssetRecord,\n BinaryLifecycleConfig,\n PipelineResult,\n} from \"./types.js\";\nimport type { BinaryStorageBackend } from \"./backend.js\";\nimport { readManifest, writeManifest } from \"./manifest.js\";\nimport { scanForBinaries } from \"./scanner.js\";\n\n/** Minimal logger interface so we don't depend on the full logger module. */\ninterface PipelineLogger {\n info(msg: string): void;\n warn(msg: string): void;\n error(msg: string): void;\n}\n\ntype ReadMarkdownFile = (filePath: string) => Promise<string>;\ntype WriteMarkdownFile = (filePath: string, content: string) => Promise<void>;\n\ninterface PipelineOptions {\n dryRun?: boolean;\n /** Force-clean all files past grace period, ignoring redirect status. */\n forceClean?: boolean;\n /** Test hook for deterministic markdown read failures. */\n readMarkdownFile?: ReadMarkdownFile;\n /** Test hook for deterministic markdown write failures. */\n writeMarkdownFile?: WriteMarkdownFile;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nasync function hashFile(filePath: string): Promise<string> {\n const content = await fsp.readFile(filePath);\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nfunction guessMimeType(ext: string): string {\n const map: Record<string, string> = {\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".pdf\": \"application/pdf\",\n \".mp3\": \"audio/mpeg\",\n \".mp4\": \"video/mp4\",\n \".wav\": \"audio/wav\",\n };\n return map[ext.toLowerCase()] ?? \"application/octet-stream\";\n}\n\n/**\n * Escape special regex characters in a string.\n * CLAUDE.md #46: always escapeRegex on user-derived parts.\n */\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction resolveManifestAssetPath(memoryDir: string, originalPath: string): string | null {\n if (\n originalPath.length === 0 ||\n originalPath.includes(\"\\0\") ||\n originalPath.includes(\"\\\\\") ||\n path.isAbsolute(originalPath) ||\n path.win32.isAbsolute(originalPath)\n ) {\n return null;\n }\n\n const memoryRoot = path.resolve(memoryDir);\n const fullPath = path.resolve(memoryRoot, originalPath);\n const relative = path.relative(memoryRoot, fullPath);\n if (relative === \"\" || relative === \"..\" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {\n return null;\n }\n\n return fullPath;\n}\n\nfunction validateBinaryLifecycleConfig(config: BinaryLifecycleConfig): void {\n if (\n typeof config.gracePeriodDays !== \"number\" ||\n !Number.isFinite(config.gracePeriodDays) ||\n !Number.isInteger(config.gracePeriodDays) ||\n config.gracePeriodDays < 0\n ) {\n throw new Error(\"binary lifecycle gracePeriodDays must be a finite non-negative integer\");\n }\n}\n\nfunction remotePathForAsset(backend: BinaryStorageBackend, relPath: string): string {\n const normalized = relPath.split(path.sep).join(\"/\");\n if (backend.type === \"filesystem\") {\n return `.binary-lifecycle/mirrors/${normalized}`;\n }\n return normalized;\n}\n\nfunction markdownTargetForAsset(asset: BinaryAssetRecord): string {\n return asset.redirectPath ?? asset.mirroredPath;\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline stages\n// ---------------------------------------------------------------------------\n\nasync function stageMirror(\n memoryDir: string,\n newPaths: string[],\n backend: BinaryStorageBackend,\n assets: BinaryAssetRecord[],\n log: PipelineLogger,\n dryRun: boolean,\n): Promise<{ mirrored: number; errors: string[] }> {\n let mirrored = 0;\n const errors: string[] = [];\n\n for (const relPath of newPaths) {\n const fullPath = path.join(memoryDir, relPath);\n try {\n const stat = await fsp.stat(fullPath);\n const contentHash = await hashFile(fullPath);\n const ext = path.extname(relPath);\n const mimeType = guessMimeType(ext);\n const remotePath = remotePathForAsset(backend, relPath);\n\n let backendLocation = remotePath;\n if (!dryRun) {\n backendLocation = await backend.upload(fullPath, remotePath);\n }\n const redirectPath = backend.getRedirectTarget?.(backendLocation);\n\n const record: BinaryAssetRecord = {\n originalPath: relPath,\n mirroredPath: backendLocation,\n ...(redirectPath ? { redirectPath } : {}),\n contentHash,\n sizeBytes: stat.size,\n mimeType,\n mirroredAt: new Date().toISOString(),\n status: \"mirrored\",\n };\n\n if (!dryRun) {\n const existingIndex = assets.findIndex((asset) => asset.originalPath === relPath);\n if (existingIndex >= 0) {\n assets.splice(existingIndex, 1);\n }\n assets.push(record);\n }\n mirrored++;\n log.info(`[binary-lifecycle] mirrored: ${relPath} (${stat.size} bytes)${dryRun ? \" [dry-run]\" : \"\"}`);\n } catch (err) {\n const msg = `mirror failed for ${relPath}: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n }\n\n return { mirrored, errors };\n}\n\nasync function stageRedirect(\n memoryDir: string,\n assets: BinaryAssetRecord[],\n log: PipelineLogger,\n dryRun: boolean,\n readMarkdownFile: ReadMarkdownFile,\n writeMarkdownFile: WriteMarkdownFile,\n): Promise<{ redirected: number; errors: string[] }> {\n let redirected = 0;\n const errors: string[] = [];\n\n // Redirect mirrored assets and retry prior redirect errors. Clean-stage errors\n // remain safe because the redirect path validation below will keep rejecting\n // invalid manifest records.\n const candidates = assets.filter((a) => a.status === \"mirrored\" || a.status === \"error\");\n if (candidates.length === 0) return { redirected, errors };\n\n // Find all markdown files in memoryDir (recursive).\n const mdFiles = await findMarkdownFiles(memoryDir);\n\n for (const asset of candidates) {\n const assetAbsolute = resolveManifestAssetPath(memoryDir, asset.originalPath);\n if (assetAbsolute === null) {\n const msg = `redirect blocked for ${asset.originalPath}: manifest path is outside memoryDir`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n if (!dryRun) {\n asset.status = \"error\";\n }\n continue;\n }\n\n const updates: Array<{ mdPath: string; content: string }> = [];\n let scanFailCount = 0;\n for (const mdPath of mdFiles) {\n try {\n const content = await readMarkdownFile(mdPath);\n\n const pattern = markdownReferencePattern(asset, assetAbsolute, mdPath);\n\n if (!pattern.test(content)) continue;\n\n // Reset lastIndex after test().\n pattern.lastIndex = 0;\n const updated = content.replace(pattern, (_match, open, _target, close) => {\n return `${open as string}${markdownTargetForAsset(asset)}${close as string}`;\n });\n updates.push({ mdPath, content: updated });\n } catch (err) {\n scanFailCount++;\n const msg = `redirect scan failed for ${mdPath}: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n }\n\n if (scanFailCount > 0) {\n if (!dryRun) {\n asset.status = \"error\";\n }\n log.warn(\n `[binary-lifecycle] redirect blocked for ${asset.originalPath}: ` +\n `${scanFailCount} markdown scan failure(s)` +\n `${dryRun ? \"\" : \" — status set to error\"}`,\n );\n continue;\n }\n\n if (updates.length === 0) {\n if (asset.status === \"error\") {\n const verifyResult = await countRemainingLocalReferences(\n memoryDir,\n asset,\n assetAbsolute,\n mdFiles,\n readMarkdownFile,\n );\n if (verifyResult.errors.length > 0 || verifyResult.remaining > 0) {\n if (!dryRun) {\n asset.status = \"error\";\n }\n for (const msg of verifyResult.errors) {\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n if (verifyResult.remaining > 0) {\n const msg = `redirect verification failed for ${asset.originalPath}: ${verifyResult.remaining} local reference(s) remain`;\n log.warn(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n continue;\n }\n\n if (asset.redirectedAt === undefined) {\n if (!dryRun) {\n asset.status = \"mirrored\";\n }\n log.info(`[binary-lifecycle] preserved mirrored asset without redirected marker: ${asset.originalPath}${dryRun ? \" [dry-run]\" : \"\"}`);\n continue;\n }\n\n if (!Number.isFinite(new Date(asset.mirroredAt).getTime())) {\n const msg = `redirect blocked for ${asset.originalPath}: manifest mirroredAt is invalid`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n if (!dryRun) {\n asset.status = \"error\";\n }\n continue;\n }\n\n if (!dryRun) {\n asset.status = \"redirected\";\n asset.redirectedAt = new Date().toISOString();\n }\n redirected++;\n log.info(`[binary-lifecycle] redirected: ${asset.originalPath}${dryRun ? \" [dry-run]\" : \"\"}`);\n }\n continue;\n }\n\n if (dryRun) {\n redirected++;\n log.info(`[binary-lifecycle] redirected: ${asset.originalPath} [dry-run]`);\n continue;\n }\n\n let writeFailCount = 0;\n for (const update of updates) {\n try {\n await writeMarkdownFile(update.mdPath, update.content);\n } catch (err) {\n writeFailCount++;\n const msg = `redirect write failed for ${update.mdPath}: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n }\n\n if (writeFailCount > 0) {\n if (!dryRun) {\n asset.status = \"error\";\n }\n log.warn(\n `[binary-lifecycle] redirect write failure for ${asset.originalPath}: ` +\n `${writeFailCount} write failure(s) — status set to error`,\n );\n continue;\n }\n\n const redirectedAt = new Date().toISOString();\n asset.redirectedAt = redirectedAt;\n\n const verifyResult = await countRemainingLocalReferences(\n memoryDir,\n asset,\n assetAbsolute,\n mdFiles,\n readMarkdownFile,\n );\n if (verifyResult.errors.length > 0 || verifyResult.remaining > 0) {\n asset.status = \"error\";\n for (const msg of verifyResult.errors) {\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n if (verifyResult.remaining > 0) {\n const msg = `redirect verification failed for ${asset.originalPath}: ${verifyResult.remaining} local reference(s) remain`;\n log.warn(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n continue;\n }\n asset.status = \"redirected\";\n asset.redirectedAt = redirectedAt;\n redirected++;\n log.info(`[binary-lifecycle] redirected: ${asset.originalPath}`);\n }\n\n return { redirected, errors };\n}\n\nasync function countRemainingLocalReferences(\n memoryDir: string,\n asset: BinaryAssetRecord,\n assetAbsolute: string,\n mdFiles: string[],\n readMarkdownFile: ReadMarkdownFile,\n): Promise<{ remaining: number; errors: string[] }> {\n let remaining = 0;\n const errors: string[] = [];\n\n for (const mdPath of mdFiles) {\n try {\n const content = await readMarkdownFile(mdPath);\n const pattern = markdownReferencePattern(asset, assetAbsolute, mdPath);\n if (pattern.test(content)) {\n remaining++;\n }\n } catch (err) {\n errors.push(`redirect verification failed for ${mdPath}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return { remaining, errors };\n}\n\nfunction markdownReferencePattern(\n asset: BinaryAssetRecord,\n assetAbsolute: string,\n mdPath: string,\n): RegExp {\n const mdDir = path.dirname(mdPath);\n const candidates = new Set<string>();\n const addCandidate = (candidate: string): void => {\n const normalized = candidate.split(path.sep).join(\"/\");\n if (normalized.length === 0) return;\n candidates.add(normalized);\n const isParentTraversal = normalized === \"..\" || normalized.startsWith(\"../\");\n if (!normalized.startsWith(\"./\") && !normalized.startsWith(\"/\") && !isParentTraversal) {\n candidates.add(`./${normalized}`);\n }\n };\n\n // Markdown links may be file-relative to the note or memory-root-relative in\n // Remnic notes. Match both forms so verification cannot miss a live local ref.\n addCandidate(path.relative(mdDir, assetAbsolute));\n const originalPath = asset.originalPath.split(path.sep).join(\"/\");\n const originalAsFileRelative = path.resolve(mdDir, ...originalPath.split(\"/\"));\n if (path.resolve(originalAsFileRelative) === path.resolve(assetAbsolute)) {\n addCandidate(originalPath);\n }\n addCandidate(`/${originalPath}`);\n\n const alternatives = [...candidates]\n .sort((a, b) => b.length - a.length)\n .map(escapeRegex)\n .join(\"|\");\n\n return new RegExp(`(!?\\\\[[^\\\\]]*\\\\]\\\\()(${alternatives})(\\\\))`, \"g\");\n}\n\nasync function stageClean(\n memoryDir: string,\n assets: BinaryAssetRecord[],\n backend: BinaryStorageBackend,\n gracePeriodDays: number,\n log: PipelineLogger,\n dryRun: boolean,\n forceClean: boolean,\n): Promise<{ cleaned: number; errors: string[] }> {\n let cleaned = 0;\n const errors: string[] = [];\n const now = Date.now();\n const graceMs = gracePeriodDays * 24 * 60 * 60 * 1000;\n\n // Clean only assets that have been redirected (markdown refs already rewritten).\n // Mirrored-only assets must NOT be cleaned — their markdown refs still point\n // to the local file, so deletion would break links.\n const candidates = assets.filter(\n (a) => a.status === \"redirected\",\n );\n\n for (const asset of candidates) {\n const mirroredMs = new Date(asset.mirroredAt).getTime();\n if (!Number.isFinite(mirroredMs)) {\n const msg = `clean blocked for ${asset.originalPath}: manifest mirroredAt is invalid`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n if (!dryRun) {\n asset.status = \"error\";\n }\n continue;\n }\n const ageMs = now - mirroredMs;\n\n if (!forceClean && ageMs < graceMs) {\n // Not yet past grace period.\n continue;\n }\n\n const fullPath = resolveManifestAssetPath(memoryDir, asset.originalPath);\n if (fullPath === null) {\n const msg = `clean blocked for ${asset.originalPath}: manifest path is outside memoryDir`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n if (!dryRun) {\n asset.status = \"error\";\n }\n continue;\n }\n\n let remoteExists: boolean;\n try {\n remoteExists = await backend.exists(asset.mirroredPath);\n } catch (err) {\n const msg = `clean blocked for ${asset.originalPath}: failed to verify mirrored copy: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n continue;\n }\n\n if (!remoteExists) {\n const msg = `clean blocked for ${asset.originalPath}: mirrored copy is missing`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n continue;\n }\n\n try {\n const currentHash = await hashFile(fullPath);\n if (currentHash !== asset.contentHash) {\n const msg = `clean blocked for ${asset.originalPath}: local content hash does not match manifest`;\n log.warn(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n continue;\n }\n if (!dryRun) {\n await fsp.unlink(fullPath);\n asset.status = \"cleaned\";\n asset.cleanedAt = new Date().toISOString();\n }\n cleaned++;\n log.info(`[binary-lifecycle] cleaned: ${asset.originalPath}${dryRun ? \" [dry-run]\" : \"\"}`);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n // Already gone — mark as cleaned.\n if (!dryRun) {\n asset.status = \"cleaned\";\n asset.cleanedAt = new Date().toISOString();\n cleaned++;\n }\n } else {\n const msg = `clean failed for ${asset.originalPath}: ${err instanceof Error ? err.message : String(err)}`;\n log.error(`[binary-lifecycle] ${msg}`);\n errors.push(msg);\n }\n }\n }\n\n return { cleaned, errors };\n}\n\n// ---------------------------------------------------------------------------\n// Markdown file discovery\n// ---------------------------------------------------------------------------\n\nasync function findMarkdownFiles(dir: string): Promise<string[]> {\n const results: string[] = [];\n\n async function walk(current: string): Promise<void> {\n let entries: import(\"node:fs\").Dirent[];\n try {\n entries = await fsp.readdir(current, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = path.join(current, entry.name);\n if (entry.isDirectory()) {\n if (entry.name === \".binary-lifecycle\") continue;\n await walk(full);\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n results.push(full);\n }\n }\n }\n\n await walk(dir);\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Main pipeline entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Run the binary lifecycle pipeline: scan, mirror, redirect, clean.\n */\nexport async function runBinaryLifecyclePipeline(\n memoryDir: string,\n config: BinaryLifecycleConfig,\n backend: BinaryStorageBackend,\n log: PipelineLogger,\n opts?: PipelineOptions,\n): Promise<PipelineResult> {\n validateBinaryLifecycleConfig(config);\n\n const dryRun = opts?.dryRun ?? false;\n const forceClean = opts?.forceClean ?? false;\n\n if (config.enabled === false) {\n return {\n scanned: 0,\n mirrored: 0,\n redirected: 0,\n cleaned: 0,\n errors: [],\n dryRun,\n };\n }\n\n const manifest = await readManifest(memoryDir);\n\n // Stage 0: Scan\n const newPaths = await scanForBinaries(memoryDir, config, manifest);\n const scanned = newPaths.length;\n\n // Stage 1: Mirror\n const mirrorResult = await stageMirror(\n memoryDir,\n newPaths,\n backend,\n manifest.assets,\n log,\n dryRun,\n );\n\n // Stage 2: Redirect\n const redirectResult = await stageRedirect(\n memoryDir,\n manifest.assets,\n log,\n dryRun,\n opts?.readMarkdownFile ?? ((filePath: string) => fsp.readFile(filePath, \"utf-8\")),\n opts?.writeMarkdownFile ?? ((filePath: string, content: string) => fsp.writeFile(filePath, content, \"utf-8\")),\n );\n\n // Stage 3: Clean\n const cleanResult = await stageClean(\n memoryDir,\n manifest.assets,\n backend,\n config.gracePeriodDays,\n log,\n dryRun,\n forceClean,\n );\n\n // Persist manifest (unless dry-run).\n manifest.lastScanAt = new Date().toISOString();\n if (!dryRun) {\n await writeManifest(memoryDir, manifest);\n }\n\n const allErrors = [\n ...mirrorResult.errors,\n ...redirectResult.errors,\n ...cleanResult.errors,\n ];\n\n return {\n scanned,\n mirrored: mirrorResult.mirrored,\n redirected: redirectResult.redirected,\n cleaned: cleanResult.cleaned,\n errors: allErrors,\n dryRun,\n };\n}\n","/**\n * @remnic/core — Workspace Tree Projection\n *\n * Generates a human-readable `.engram/context-tree/` from canonical memory.\n * Each node is a `.md` file with rich metadata, * (provenance, trust, confidence, source anchors).\n * Manual edits are preserved in fenced blocks.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { getCategoryDir, ALL_CATEGORY_KEYS } from \"../utils/category-dir.js\";\n\nconst VALID_PROJECTION_CATEGORIES = new Set(ALL_CATEGORY_KEYS);\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface TreeNode {\n /** Relative path from context-tree root, e.g. \"entities/claude.md\" */\n path: string;\n /** Category from canonical memory */\n category: string;\n /** Human-readable title */\n title: string;\n /** File content (rendered markdown) */\n content: string;\n /** Source memory IDs that contributed to this node */\n sourceAnchors: string[];\n /** Confidence (0-1) */\n confidence: number;\n /** Trust zone classification */\n confidenceTier: string;\n /** When this node was generated */\n generatedAt: string;\n /** Provenance chain */\n provenance: ProvenanceEntry[];\n}\n\nexport interface ProvenanceEntry {\n memoryId: string;\n source: string;\n extracted: string;\n}\n\nexport interface GenerateOptions {\n /** Memory root directory (e.g. ~/.openclaw/workspace/memory/local) */\n memoryDir: string;\n /** Output directory (e.g. .engram/context-tree) */\n outputDir: string;\n /** Categories to include (default: all) */\n categories?: string[];\n /** Whether to include entity graph */\n includeEntities?: boolean;\n /** Whether to include orphaned questions */\n includeQuestions?: boolean;\n /** Max nodes per category (default: unlimited) */\n maxPerCategory?: number;\n /** Whether to watch for changes and regenerate incrementally */\n watch?: boolean;\n}\n\nexport interface GenerateResult {\n nodesGenerated: number;\n nodesSkipped: number;\n categories: Record<string, number>;\n durationMs: number;\n outputDir: string;\n}\n\n// ── Generation ──────────────────────────────────────────────────────────────\n\n/**\n * Generate a context tree from canonical memory.\n *\n * Reads memory `.md` files from the source directory, * and projects them into a clean, * human-readable tree structure at `outputDir`.\n */\nexport async function generateContextTree(options: GenerateOptions): Promise<GenerateResult> {\n const startTime = Date.now();\n const {\n memoryDir,\n outputDir,\n categories: filterCategories,\n includeEntities = true,\n includeQuestions = true,\n maxPerCategory = Infinity,\n } = options;\n\n let nodesGenerated = 0;\n let nodesSkipped = 0;\n const categoryCounts: Record<string, number> = {};\n const resolvedMemoryDir = path.resolve(memoryDir);\n const resolvedOutputDir = path.resolve(outputDir);\n const requestedCategories = validateProjectionCategories(filterCategories);\n const realMemoryDir = assertSafeMemoryRoot(resolvedMemoryDir);\n\n // Ensure output directory exists\n assertNotSymlink(resolvedOutputDir, \"context tree outputDir\");\n fs.mkdirSync(resolvedOutputDir, { recursive: true });\n const realOutputDir = fs.realpathSync(resolvedOutputDir);\n\n // Process each category (exclude 'question' — handled by separate includeQuestions pass)\n const allCategories = (requestedCategories ?? ALL_CATEGORY_KEYS)\n .filter((c) => c !== \"question\");\n\n for (const category of allCategories) {\n const categoryDir = getCategoryDir(memoryDir, category);\n if (!fs.existsSync(categoryDir)) continue;\n assertSafeInputRoot(realMemoryDir, categoryDir, `${category} memory category`);\n\n categoryCounts[category] = 0;\n const files = walkR(categoryDir, realMemoryDir);\n let count = 0;\n\n for (const filePath of files) {\n if (count >= maxPerCategory) {\n nodesSkipped++;\n continue;\n }\n\n const content = fs.readFileSync(filePath, \"utf8\");\n const fm = parseFrontmatter(content);\n if (!fm) {\n nodesSkipped++;\n continue;\n }\n\n const node = projectNode(filePath, category, fm, content);\n if (!node) {\n nodesSkipped++;\n continue;\n }\n\n // Write node to output\n const outputPath = resolveContainedOutputPath(realOutputDir, node.path);\n writeProjectedContent(realOutputDir, outputPath, node.content);\n\n nodesGenerated++;\n categoryCounts[category] = (categoryCounts[category] ?? 0) + 1;\n count++;\n }\n }\n\n // Process entities\n if (includeEntities) {\n const entitiesDir = path.join(memoryDir, \"entities\");\n if (fs.existsSync(entitiesDir)) {\n assertSafeInputRoot(realMemoryDir, entitiesDir, \"entities root\");\n categoryCounts[\"entity\"] = 0;\n const entityFiles = walkR(entitiesDir, realMemoryDir);\n let count = 0;\n\n for (const filePath of entityFiles) {\n if (count >= maxPerCategory) {\n nodesSkipped++;\n continue;\n }\n\n const content = fs.readFileSync(filePath, \"utf8\");\n const fileName = path.basename(filePath, \".md\");\n const node = projectEntityNode(fileName, content);\n\n const outputPath = resolveContainedOutputPath(realOutputDir, \"entities\", `${fileName}.md`);\n writeProjectedContent(realOutputDir, outputPath, node.content);\n\n nodesGenerated++;\n categoryCounts[\"entity\"] = (categoryCounts[\"entity\"] ?? 0) + 1;\n count++;\n }\n }\n }\n\n // Process questions\n const shouldIncludeQuestions =\n includeQuestions &&\n (requestedCategories === undefined || requestedCategories.includes(\"question\"));\n if (shouldIncludeQuestions) {\n const questionsDir = path.join(memoryDir, \"questions\");\n if (fs.existsSync(questionsDir)) {\n assertSafeInputRoot(realMemoryDir, questionsDir, \"questions root\");\n categoryCounts[\"question\"] = 0;\n const qFiles = walkR(questionsDir, realMemoryDir);\n let count = 0;\n\n for (const filePath of qFiles) {\n if (count >= maxPerCategory) {\n nodesSkipped++;\n continue;\n }\n\n const content = fs.readFileSync(filePath, \"utf8\");\n const fm = parseFrontmatter(content);\n if (!fm) {\n nodesSkipped++;\n continue;\n }\n\n const node = projectNode(filePath, \"question\", fm, content);\n if (!node) {\n nodesSkipped++;\n continue;\n }\n\n const outputPath = resolveContainedOutputPath(realOutputDir, node.path);\n writeProjectedContent(realOutputDir, outputPath, node.content);\n\n nodesGenerated++;\n categoryCounts[\"question\"] = (categoryCounts[\"question\"] ?? 0) + 1;\n count++;\n }\n }\n }\n\n // Write index\n const index = generateIndex(categoryCounts, resolvedOutputDir);\n writeProjectedContent(realOutputDir, resolveContainedOutputPath(realOutputDir, \"INDEX.md\"), index);\n\n return {\n nodesGenerated,\n nodesSkipped,\n categories: categoryCounts,\n durationMs: Date.now() - startTime,\n outputDir,\n };\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction isPathInside(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nfunction assertNotSymlink(targetPath: string, label: string): void {\n try {\n if (fs.lstatSync(targetPath).isSymbolicLink()) {\n throw new Error(`${label} must not be a symlink: ${targetPath}`);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw err;\n }\n}\n\nfunction assertSafeMemoryRoot(targetPath: string): string {\n const stat = fs.lstatSync(targetPath);\n if (stat.isSymbolicLink()) {\n throw new Error(`memoryDir must not be a symlink: ${targetPath}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`memoryDir must be a directory: ${targetPath}`);\n }\n return fs.realpathSync(targetPath);\n}\n\nfunction assertSafeInputRoot(realMemoryDir: string, targetPath: string, label: string): void {\n const stat = fs.lstatSync(targetPath);\n if (stat.isSymbolicLink()) {\n throw new Error(`${label} must not be a symlink: ${targetPath}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`${label} must be a directory: ${targetPath}`);\n }\n const realTarget = fs.realpathSync(targetPath);\n if (!isPathInside(realMemoryDir, realTarget)) {\n throw new Error(`${label} escapes memoryDir: ${targetPath}`);\n }\n}\n\nfunction assertSafeOutputTarget(realOutputDir: string, outputPath: string): void {\n let current = realOutputDir;\n const relative = path.relative(realOutputDir, outputPath);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(`context tree output path escapes outputDir: ${outputPath}`);\n }\n for (const segment of relative.split(path.sep).filter(Boolean)) {\n current = path.join(current, segment);\n try {\n const stat = fs.lstatSync(current);\n if (stat.isSymbolicLink()) {\n throw new Error(`context tree output path contains symlink: ${current}`);\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n break;\n }\n throw err;\n }\n }\n}\n\nfunction validateProjectionCategories(categories: string[] | undefined): string[] | undefined {\n if (categories === undefined) {\n return undefined;\n }\n const validated: string[] = [];\n for (const category of categories) {\n if (typeof category !== \"string\" || !VALID_PROJECTION_CATEGORIES.has(category)) {\n throw new Error(`invalid context tree category: ${String(category)}`);\n }\n if (!validated.includes(category)) {\n validated.push(category);\n }\n }\n return validated;\n}\n\nfunction resolveContainedOutputPath(outputRoot: string, ...segments: string[]): string {\n const resolved = path.resolve(outputRoot, ...segments);\n const relative = path.relative(outputRoot, resolved);\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) {\n return resolved;\n }\n throw new Error(`context tree output path escapes outputDir: ${segments.join(\"/\")}`);\n}\n\nfunction writeProjectedContent(realOutputDir: string, outputPath: string, generatedContent: string): void {\n assertSafeOutputTarget(realOutputDir, outputPath);\n fs.mkdirSync(path.dirname(outputPath), { recursive: true });\n const realParent = fs.realpathSync(path.dirname(outputPath));\n if (!isPathInside(realOutputDir, realParent)) {\n throw new Error(`context tree output path escapes outputDir: ${outputPath}`);\n }\n const existingContent = fs.existsSync(outputPath)\n ? fs.readFileSync(outputPath, \"utf8\")\n : \"\";\n fs.writeFileSync(\n outputPath,\n preserveManualFencedBlocks(generatedContent, existingContent),\n );\n}\n\nfunction preserveManualFencedBlocks(\n generatedContent: string,\n existingContent: string,\n): string {\n const manualBlocks = extractManualFencedBlocks(existingContent)\n .filter((block) => !generatedContent.includes(block));\n if (manualBlocks.length === 0) {\n return generatedContent;\n }\n return `${generatedContent.trimEnd()}\\n\\n## Manual Edits\\n\\n${manualBlocks.join(\"\\n\\n\")}\\n`;\n}\n\nfunction extractManualFencedBlocks(content: string): string[] {\n const blocks: string[] = [];\n const seen = new Set<string>();\n const fencePattern = /(?:^|\\n)([`~]{3,})[^\\n]*\\bmanual\\b[^\\n]*\\n[\\s\\S]*?\\n\\1[ \\t]*(?=\\n|$)/gi;\n for (const match of content.matchAll(fencePattern)) {\n const block = match[0].trim();\n if (!seen.has(block)) {\n seen.add(block);\n blocks.push(block);\n }\n }\n return blocks;\n}\n\nfunction walkR(dir: string, realMemoryDir: string): string[] {\n const results: string[] = [];\n function walk(directory: string): void {\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\n const fullPath = path.join(directory, entry.name);\n if (entry.isSymbolicLink()) {\n throw new Error(`context tree input path contains symlink: ${fullPath}`);\n }\n if (entry.isDirectory()) {\n const realDir = fs.realpathSync(fullPath);\n if (!isPathInside(realMemoryDir, realDir)) {\n throw new Error(`context tree input path escapes memoryDir: ${fullPath}`);\n }\n walk(fullPath);\n } else if (entry.name.endsWith(\".md\")) {\n const realFile = fs.realpathSync(fullPath);\n if (!isPathInside(realMemoryDir, realFile)) {\n throw new Error(`context tree input path escapes memoryDir: ${fullPath}`);\n }\n results.push(fullPath);\n }\n }\n }\n walk(dir);\n return results;\n}\n\ninterface Frontmatter {\n id: string;\n category: string;\n created: string;\n updated: string;\n confidence: number;\n confidenceTier: string;\n tags: string[];\n source: string;\n entityRef?: string;\n lifecycleState?: string;\n}\n\nfunction parseFrontmatter(content: string): Frontmatter | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fmText = match[1];\n const fm: Record<string, unknown> = {};\n for (const line of fmText.split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n if (key === \"tags\") {\n try {\n fm[key] = JSON.parse(value) as string[];\n } catch {\n fm[key] = [] as string[];\n }\n } else if (key === \"confidence\") {\n const parsed = parseFloat(value);\n fm[key] = Number.isFinite(parsed) ? parsed : 0;\n } else {\n fm[key] = value;\n }\n }\n return fm as unknown as Frontmatter;\n}\n\nfunction extractBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n([\\s\\S]*)/);\n return match ? match[1].trim() : content.trim();\n}\n\nfunction projectNode(\n filePath: string,\n category: string,\n fm: Frontmatter,\n rawContent: string,\n): TreeNode | null {\n const body = extractBody(rawContent);\n const fileName = path.basename(filePath, \".md\");\n const dateDir = path.basename(path.dirname(filePath));\n\n // Build relative path: category/date/file or just category/file\n let relPath: string;\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(dateDir)) {\n relPath = path.join(category, dateDir, `${fileName}.md`);\n } else {\n relPath = path.join(category, `${fileName}.md`);\n }\n\n const generatedAt = new Date().toISOString();\n\n const md = `# ${fm.id}\n\n> **Category:** ${fm.category}\n> **Created:** ${fm.created}\n> **Updated:** ${fm.updated ?? fm.created}\n> **Confidence:** ${fm.confidence} (${fm.confidenceTier}${fm.lifecycleState ? `, ${fm.lifecycleState}` : \"\"})\n${fm.tags?.length ? `\\n> **Tags:** ${fm.tags.join(\", \")}` : \"\"}\n${fm.entityRef ? `\\n> **Entity:** ${fm.entityRef}` : \"\"}\n> **Source:** ${fm.source ?? \"unknown\"}\n> **Projected:** ${generatedAt}\n\n---\n\n${body}\n`;\n\n return {\n path: relPath,\n category,\n title: fm.id,\n content: md,\n sourceAnchors: [fm.id],\n confidence: fm.confidence ?? 0,\n confidenceTier: fm.confidenceTier ?? \"unknown\",\n generatedAt,\n provenance: [{\n memoryId: fm.id,\n source: fm.source ?? \"unknown\",\n extracted: fm.created,\n }],\n };\n}\n\nfunction projectEntityNode(fileName: string, content: string): TreeNode {\n const generatedAt = new Date().toISOString();\n\n const md = `> **Projected:** ${generatedAt}\n> **Source:** canonical\n\n---\n\n${content}\n`;\n\n return {\n path: path.join(\"entities\", `${fileName}.md`),\n category: \"entity\",\n title: fileName,\n content: md,\n sourceAnchors: [fileName],\n confidence: 1,\n confidenceTier: \"explicit\",\n generatedAt,\n provenance: [{\n memoryId: fileName,\n source: \"canonical\",\n extracted: generatedAt,\n }],\n };\n}\n\nfunction generateIndex(\n categoryCounts: Record<string, number>,\n outputDir: string,\n): string {\n const lines = [\n \"# Context Tree Index\",\n \"\",\n `Generated: ${new Date().toISOString()}`,\n \"\",\n \"## Summary\",\n \"\",\n `| Category | Count |`,\n `|----------|-------|`,\n ];\n\n let total = 0;\n for (const [cat, count] of Object.entries(categoryCounts).sort()) {\n lines.push(`| ${cat} | ${count} |`);\n total += count;\n }\n\n lines.push(\"\");\n lines.push(`**Total:** ${total} nodes`);\n lines.push(\"\");\n lines.push(\"## Structure\");\n lines.push(\"\");\n lines.push(\"```\");\n lines.push(\"context-tree/\");\n lines.push(\"├── entities/ # Entity knowledge graph\");\n lines.push(\"├── fact/ # Factual memories (date-partitioned)\");\n lines.push(\"├── correction/ # Correction memories\");\n lines.push(\"├── decision/ # Decisions\");\n lines.push(\"├── moment/ # Notable moments\");\n lines.push(\"├── preference/ # Preferences\");\n lines.push(\"├── principle/ # Principles\");\n lines.push(\"├── question/ # Open questions\");\n lines.push(\"└── INDEX.md # This file\");\n lines.push(\"```\");\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n","/**\n * @remnic/core — Onboarding\n *\n * Detects project language, shape, and documentation to produce\n * an onboarding plan for memory ingestion.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface OnboardOptions {\n /** Directory to scan (defaults to cwd) */\n directory?: string;\n /** Max depth to walk (default: 6) */\n maxDepth?: number;\n /** Directories to skip */\n excludeDirs?: string[];\n}\n\nexport interface LanguageInfo {\n /** Language name (e.g. \"TypeScript\", \"Python\") */\n language: string;\n /** Confidence in detection (0-1) */\n confidence: number;\n /** Evidence (e.g. [\"package.json\", \"tsconfig.json\", \"*.ts files\"]) */\n evidence: string[];\n}\n\nexport interface DocFile {\n /** Absolute path */\n path: string;\n /** Relative path from project root */\n relativePath: string;\n /** Estimated type */\n kind: \"readme\" | \"changelog\" | \"contributing\" | \"license\" | \"config\" | \"docs\" | \"other\";\n /** File size in bytes */\n size: number;\n}\n\nexport type ProjectShape = \"app\" | \"library\" | \"monorepo\" | \"workspace\" | \"script\" | \"unknown\";\n\nexport interface OnboardResult {\n /** Project root */\n directory: string;\n /** Detected languages (sorted by confidence) */\n languages: LanguageInfo[];\n /** Detected project shape */\n shape: ProjectShape;\n /** Shape evidence */\n shapeEvidence: string[];\n /** Discovered documentation files */\n docs: DocFile[];\n /** Total files scanned */\n totalFiles: number;\n /** Duration in ms */\n durationMs: number;\n /** Suggested ingestion plan */\n plan: IngestionPlan;\n}\n\nexport interface IngestionPlan {\n /** Priority files to ingest first */\n priorityFiles: DocFile[];\n /** Estimated total files to ingest */\n estimatedFiles: number;\n /** Recommended categories */\n categories: string[];\n /** Suggested memory namespace */\n suggestedNamespace: string;\n}\n\n// ── Language detection rules ─────────────────────────────────────────────────\n\ninterface LanguageRule {\n language: string;\n extensions: string[];\n manifests: string[];\n configFiles: string[];\n}\n\nconst LANGUAGE_RULES: LanguageRule[] = [\n {\n language: \"TypeScript\",\n extensions: [\".ts\", \".tsx\"],\n manifests: [],\n configFiles: [\"tsconfig.json\", \"tsup.config.ts\"],\n },\n {\n language: \"JavaScript\",\n extensions: [\".js\", \".jsx\", \".mjs\", \".cjs\"],\n manifests: [],\n configFiles: [\".eslintrc\", \".prettierrc\"],\n },\n {\n language: \"Python\",\n extensions: [\".py\", \".pyi\"],\n manifests: [\"pyproject.toml\", \"setup.py\", \"setup.cfg\", \"requirements.txt\"],\n configFiles: [\"mypy.ini\", \".flake8\", \"tox.ini\"],\n },\n {\n language: \"Go\",\n extensions: [\".go\"],\n manifests: [\"go.mod\", \"go.sum\"],\n configFiles: [],\n },\n {\n language: \"Rust\",\n extensions: [\".rs\"],\n manifests: [\"Cargo.toml\"],\n configFiles: [],\n },\n {\n language: \"Ruby\",\n extensions: [\".rb\"],\n manifests: [\"Gemfile\", \"*.gemspec\"],\n configFiles: [\".rubocop.yml\"],\n },\n {\n language: \"PHP\",\n extensions: [\".php\"],\n manifests: [\"composer.json\"],\n configFiles: [\"phpcs.xml\"],\n },\n {\n language: \"Java\",\n extensions: [\".java\", \".kt\"],\n manifests: [\"pom.xml\", \"build.gradle\", \"build.gradle.kts\"],\n configFiles: [],\n },\n {\n language: \"Swift\",\n extensions: [\".swift\"],\n manifests: [\"Package.swift\", \"Podfile\"],\n configFiles: [],\n },\n {\n language: \"C#\",\n extensions: [\".cs\"],\n manifests: [\"*.csproj\", \"*.sln\"],\n configFiles: [],\n },\n {\n language: \"Shell\",\n extensions: [\".sh\", \".bash\", \".zsh\"],\n manifests: [],\n configFiles: [],\n },\n {\n language: \"Dart\",\n extensions: [\".dart\"],\n manifests: [\"pubspec.yaml\"],\n configFiles: [],\n },\n {\n language: \"Elixir\",\n extensions: [\".ex\", \".exs\"],\n manifests: [\"mix.exs\"],\n configFiles: [],\n },\n];\n\nconst DEFAULT_EXCLUDE = new Set([\n \"node_modules\",\n \".git\",\n \"vendor\",\n \"__pycache__\",\n \".venv\",\n \"venv\",\n \"dist\",\n \"build\",\n \".next\",\n \".nuxt\",\n \"target\",\n \"coverage\",\n \".engram\",\n]);\n\n// ── Main function ────────────────────────────────────────────────────────────\n\nexport function onboard(options: OnboardOptions): OnboardResult {\n const startTime = Date.now();\n const {\n maxDepth = 6,\n excludeDirs = [],\n } = options;\n const directory = path.resolve(options.directory ?? process.cwd());\n let rootStat: fs.Stats;\n try {\n rootStat = fs.statSync(directory);\n } catch (err) {\n throw new Error(`Cannot scan onboarding directory ${directory}: ${err instanceof Error ? err.message : String(err)}`);\n }\n if (!rootStat.isDirectory()) {\n throw new Error(`Cannot scan onboarding directory ${directory}: not a directory`);\n }\n\n const exclude = new Set([...DEFAULT_EXCLUDE, ...excludeDirs]);\n\n // Collect all files\n const files = walkDir(directory, exclude, maxDepth);\n\n // Detect languages\n const languages = detectLanguages(files, directory);\n\n // Detect shape\n const { shape, evidence: shapeEvidence } = detectShape(files, directory);\n\n // Discover docs\n const docs = discoverDocs(files, directory);\n\n // Build plan\n const plan = buildPlan(languages, shape, docs, directory);\n\n return {\n directory,\n languages,\n shape,\n shapeEvidence,\n docs,\n totalFiles: files.length,\n durationMs: Date.now() - startTime,\n plan,\n };\n}\n\n// ── Walk directory ───────────────────────────────────────────────────────────\n\nfunction walkDir(\n root: string,\n exclude: Set<string>,\n maxDepth: number,\n): string[] {\n const results: string[] = [];\n\n function walk(dir: string, depth: number): void {\n if (depth > maxDepth) return;\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch (err) {\n if (depth === 0) {\n throw new Error(`Cannot scan onboarding directory ${root}: ${err instanceof Error ? err.message : String(err)}`);\n }\n return;\n }\n\n for (const entry of entries) {\n if (exclude.has(entry.name)) continue;\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walk(fullPath, depth + 1);\n } else if (entry.isFile()) {\n results.push(fullPath);\n }\n }\n }\n\n walk(root, 0);\n return results;\n}\n\n// ── Language detection ───────────────────────────────────────────────────────\n\nfunction detectLanguages(files: string[], root: string): LanguageInfo[] {\n const results: LanguageInfo[] = [];\n\n // Count extensions\n const extCounts = new Map<string, number>();\n for (const f of files) {\n const ext = path.extname(f).toLowerCase();\n if (ext) extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);\n }\n\n // Check manifests at root level\n const rootFiles = new Set(\n files\n .filter((f) => path.dirname(f) === root)\n .map((f) => path.basename(f)),\n );\n\n for (const rule of LANGUAGE_RULES) {\n const evidence: string[] = [];\n let score = 0;\n\n // Extension matches\n let extMatch = 0;\n for (const ext of rule.extensions) {\n const count = extCounts.get(ext) ?? 0;\n if (count > 0) {\n extMatch += count;\n evidence.push(`${ext} files (${count})`);\n }\n }\n score += Math.min(extMatch * 0.05, 0.5);\n\n // Manifest matches\n for (const manifest of rule.manifests) {\n if (manifest.includes(\"*\")) {\n // Glob pattern — e.g. \"*.gemspec\" matches files ending with \".gemspec\"\n const suffix = manifest.replaceAll(/\\*/g, \"\");\n if ([...rootFiles].some((f) => f.endsWith(suffix))) {\n score += 0.2;\n evidence.push(manifest);\n }\n } else if (rootFiles.has(manifest)) {\n score += 0.2;\n evidence.push(manifest);\n }\n }\n\n // Config matches\n for (const cfg of rule.configFiles) {\n if (rootFiles.has(cfg)) {\n score += 0.1;\n evidence.push(cfg);\n }\n }\n\n if (score > 0) {\n results.push({\n language: rule.language,\n confidence: Math.min(score, 1),\n evidence,\n });\n }\n }\n\n return results.sort((a, b) => b.confidence - a.confidence);\n}\n\n// ── Shape detection ──────────────────────────────────────────────────────────\n\nfunction detectShape(\n files: string[],\n root: string,\n): { shape: ProjectShape; evidence: string[] } {\n const rootFiles = new Set(\n files\n .filter((f) => path.dirname(f) === root)\n .map((f) => path.basename(f)),\n );\n\n const rootDirs = new Set<string>();\n try {\n for (const entry of fs.readdirSync(root, { withFileTypes: true })) {\n if (entry.isDirectory()) rootDirs.add(entry.name);\n }\n } catch {\n // ignore\n }\n\n const evidence: string[] = [];\n\n // Monorepo: workspace packages/ or libs/ dirs + root package.json with workspaces\n if (rootFiles.has(\"package.json\")) {\n const pkg = readJsonSafe(path.join(root, \"package.json\"));\n if (pkg?.workspaces) {\n evidence.push(\"package.json has workspaces\");\n return { shape: \"monorepo\", evidence };\n }\n }\n\n if (rootDirs.has(\"packages\") || rootDirs.has(\"libs\")) {\n evidence.push(\"has packages/ or libs/ directory\");\n return { shape: \"monorepo\", evidence };\n }\n\n // Workspace: pnpm-workspace.yaml, Cargo workspace, go.work\n if (rootFiles.has(\"pnpm-workspace.yaml\") || rootFiles.has(\"go.work\")) {\n evidence.push(\"workspace manifest found\");\n return { shape: \"workspace\", evidence };\n }\n\n const cargoToml = readTomlWorkspace(path.join(root, \"Cargo.toml\"));\n if (cargoToml) {\n evidence.push(\"Cargo.toml has workspace\");\n return { shape: \"workspace\", evidence };\n }\n\n // Library: has lib/ or src/index.*, exports in package.json\n if (rootFiles.has(\"package.json\")) {\n const pkg = readJsonSafe(path.join(root, \"package.json\"));\n if (pkg?.exports || pkg?.main) {\n // If it also has \"bin\", it's more of an app\n if (pkg?.bin) {\n evidence.push(\"package.json has bin\");\n return { shape: \"app\", evidence };\n }\n evidence.push(\"package.json has exports/main\");\n return { shape: \"library\", evidence };\n }\n }\n\n // Check for app indicators\n if (\n rootFiles.has(\"Dockerfile\") ||\n rootFiles.has(\"docker-compose.yml\") ||\n rootFiles.has(\"docker-compose.yaml\") ||\n rootDirs.has(\"app\") ||\n rootDirs.has(\"src\") && rootDirs.has(\"public\")\n ) {\n evidence.push(\"app-like structure detected\");\n return { shape: \"app\", evidence };\n }\n\n // Script: few files, no package manifest\n if (files.length <= 5 && !rootFiles.has(\"package.json\") && !rootFiles.has(\"pyproject.toml\")) {\n evidence.push(\"few files, no manifest\");\n return { shape: \"script\", evidence };\n }\n\n return { shape: \"unknown\", evidence: [\"no strong shape signal\"] };\n}\n\n// ── Doc discovery ────────────────────────────────────────────────────────────\n\nfunction discoverDocs(files: string[], root: string): DocFile[] {\n const docs: DocFile[] = [];\n const docPatterns: Array<{ pattern: RegExp; kind: DocFile[\"kind\"] }> = [\n { pattern: /^readme(\\.\\w+)?$/i, kind: \"readme\" },\n { pattern: /^changelog(\\.\\w+)?$/i, kind: \"changelog\" },\n { pattern: /^changes(\\.\\w+)?$/i, kind: \"changelog\" },\n { pattern: /^contributing(\\.\\w+)?$/i, kind: \"contributing\" },\n { pattern: /^code[_-]of[_-]conduct(\\.\\w+)?$/i, kind: \"contributing\" },\n { pattern: /^license(\\.\\w+)?$/i, kind: \"license\" },\n { pattern: /^copying(\\.\\w+)?$/i, kind: \"license\" },\n { pattern: /^\\.env\\.example$/i, kind: \"config\" },\n { pattern: /^\\.editorconfig$/i, kind: \"config\" },\n ];\n\n for (const filePath of files) {\n const basename = path.basename(filePath).toLowerCase();\n const relPath = path.relative(root, filePath);\n let kind: DocFile[\"kind\"] | undefined;\n\n // Check against patterns\n for (const { pattern, kind: k } of docPatterns) {\n if (pattern.test(basename)) {\n kind = k;\n break;\n }\n }\n\n // Check docs/ directories\n if (!kind && isUnderDocsDir(relPath)) {\n kind = \"docs\";\n }\n\n // Check markdown files at root or in docs/\n if (!kind && (basename.endsWith(\".md\") || basename.endsWith(\".mdx\"))) {\n if (path.dirname(relPath) === \".\" || isUnderDocsDir(relPath)) {\n kind = \"docs\";\n }\n }\n\n if (kind) {\n let size = 0;\n try {\n size = fs.statSync(filePath).size;\n } catch {\n // ignore\n }\n docs.push({\n path: filePath,\n relativePath: relPath,\n kind,\n size,\n });\n }\n }\n\n return docs;\n}\n\nfunction isUnderDocsDir(relPath: string): boolean {\n const parts = relPath.split(path.sep);\n return parts[0] === \"docs\" || parts[0] === \"doc\" || parts[0] === \"documentation\";\n}\n\n// ── Plan generation ──────────────────────────────────────────────────────────\n\nfunction buildPlan(\n languages: LanguageInfo[],\n shape: ProjectShape,\n docs: DocFile[],\n _root: string,\n): IngestionPlan {\n // Priority: README, CONTRIBUTING, then other docs\n const priorityOrder: Record<DocFile[\"kind\"], number> = {\n readme: 0,\n contributing: 1,\n changelog: 2,\n license: 3,\n docs: 4,\n config: 5,\n other: 6,\n };\n\n const priorityFiles = [...docs]\n .filter((d) => d.size > 0)\n .sort((a, b) => priorityOrder[a.kind] - priorityOrder[b.kind]);\n\n // Recommended categories based on project shape\n const categories: string[] = [\"fact\", \"preference\", \"decision\", \"principle\"];\n if (shape === \"monorepo\" || shape === \"workspace\") {\n categories.push(\"entity\");\n }\n\n // Namespace suggestion from primary language\n const suggestedNamespace = languages.length > 0\n ? languages[0].language.toLowerCase()\n : \"project\";\n\n return {\n priorityFiles,\n estimatedFiles: docs.filter((d) => d.size > 0).length,\n categories,\n suggestedNamespace,\n };\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction readJsonSafe(filePath: string): Record<string, unknown> | null {\n try {\n return JSON.parse(fs.readFileSync(filePath, \"utf8\"));\n } catch {\n return null;\n }\n}\n\nfunction readTomlWorkspace(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, \"utf8\");\n return content.includes(\"[workspace]\");\n } catch {\n return false;\n }\n}\n","/**\n * @remnic/core — Curation\n *\n * Deliberate ingestion of files into memory with provenance tracking.\n * Supports statement-level extraction, dedup, and contradiction checks.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { getCategoryDir, ALL_CATEGORY_DIRS } from \"../utils/category-dir.js\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface CurateOptions {\n /** File or directory path to curate */\n targetPath: string;\n /** Memory root directory for writing */\n memoryDir: string;\n /** Source label (e.g. \"manual\", \"docs\", \"onboarding\") */\n source?: string;\n /** Category override (default: auto-detect) */\n category?: string;\n /** Confidence to assign (default: 0.9 for curated items) */\n confidence?: number;\n /** Entity reference to attach */\n entityRef?: string;\n /** Tags to add */\n tags?: string[];\n /** Whether to perform dedup check against existing memories */\n checkDuplicates?: boolean;\n /** Whether to detect contradictions */\n checkContradictions?: boolean;\n /** Whether to write files (default: true). False = dry run */\n write?: boolean;\n}\n\nexport interface CuratedStatement {\n /** Unique ID for this statement */\n id: string;\n /** The extracted statement text */\n content: string;\n /** Category */\n category: string;\n /** Confidence */\n confidence: number;\n /** Provenance info */\n provenance: StatementProvenance;\n /** Hash of content for dedup */\n contentHash: string;\n /** Tags */\n tags: string[];\n /** Entity reference */\n entityRef?: string;\n}\n\nexport interface StatementProvenance {\n /** Source file path */\n sourcePath: string;\n /** Relative path from project root */\n relativePath: string;\n /** Source label */\n source: string;\n /** Line number if extractable (0 = unknown) */\n lineNumber: number;\n /** Timestamp of ingestion */\n ingestedAt: string;\n /** Hash of the source file for diff tracking */\n sourceFileHash: string;\n}\n\nexport interface CurateResult {\n /** Statements extracted */\n statements: CuratedStatement[];\n /** Files processed */\n filesProcessed: number;\n /** Files skipped (empty, binary, etc.) */\n filesSkipped: number;\n /** Duplicate statements found (if checkDuplicates) */\n duplicates: DuplicateResult[];\n /** Contradictions found (if checkContradictions) */\n contradictions: ContradictionResult[];\n /** Memory files written */\n written: string[];\n /** Duration in ms */\n durationMs: number;\n}\n\nexport interface DuplicateResult {\n /** New statement */\n newStatement: CuratedStatement;\n /** Existing memory ID that matches */\n existingId: string;\n /** Similarity score (0-1) */\n similarity: number;\n /** Recommended action */\n action: \"skip\" | \"merge\" | \"keep\";\n}\n\nexport interface ContradictionResult {\n /** New statement */\n newStatement: CuratedStatement;\n /** Conflicting memory ID */\n conflictingId: string;\n /** The conflicting content */\n conflictingContent: string;\n /** Severity */\n severity: \"high\" | \"medium\" | \"low\";\n}\n\n// ── Main function ────────────────────────────────────────────────────────────\n\nexport async function curate(options: CurateOptions): Promise<CurateResult> {\n const startTime = Date.now();\n const {\n targetPath,\n memoryDir,\n source = \"curation\",\n category: categoryOverride,\n confidence = 0.9,\n entityRef,\n tags = [],\n checkDuplicates = true,\n checkContradictions = false,\n write = true,\n } = options;\n\n const statements: CuratedStatement[] = [];\n const written: string[] = [];\n const duplicates: DuplicateResult[] = [];\n const contradictions: ContradictionResult[] = [];\n let filesProcessed = 0;\n let filesSkipped = 0;\n\n // Determine targets\n const targets = resolveTargets(targetPath);\n const provenanceRoot = resolveProvenanceRoot(targetPath);\n\n // Load existing memories for dedup/contradiction checks\n const existingMemories = checkDuplicates || checkContradictions\n ? loadExistingMemories(memoryDir)\n : new Map();\n\n // Process each file\n for (const filePath of targets) {\n const content = readFileSafe(filePath);\n if (!content) {\n filesSkipped++;\n continue;\n }\n\n if (isBinary(content)) {\n filesSkipped++;\n continue;\n }\n\n filesProcessed++;\n\n const sourceFileHash = hashContent(content);\n const fileStatements = extractStatements(\n content,\n filePath,\n provenanceRoot,\n source,\n sourceFileHash,\n categoryOverride,\n confidence,\n entityRef,\n tags,\n );\n\n for (const stmt of fileStatements) {\n // Dedup check\n if (checkDuplicates) {\n const dup = findDuplicate(stmt, existingMemories);\n if (dup) {\n duplicates.push(dup);\n if (dup.action === \"skip\") continue;\n }\n }\n\n // Contradiction check\n if (checkContradictions) {\n const contra = findContradiction(stmt, existingMemories);\n if (contra) {\n contradictions.push(contra);\n }\n }\n\n statements.push(stmt);\n\n // Write to memory\n if (write) {\n const writtenPath = writeStatement(stmt, memoryDir);\n written.push(writtenPath);\n existingMemories.set(stmt.contentHash, {\n id: stmt.id,\n content: stmt.content,\n category: stmt.category,\n });\n }\n }\n }\n\n return {\n statements,\n filesProcessed,\n filesSkipped,\n duplicates,\n contradictions,\n written,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Target resolution ────────────────────────────────────────────────────────\n\nfunction resolveTargets(targetPath: string): string[] {\n const stat = fs.statSync(targetPath);\n if (stat.isFile()) return [targetPath];\n\n // Directory — walk for .md, .txt, .mdx\n const results: string[] = [];\n const extensions = new Set([\".md\", \".txt\", \".mdx\", \".rst\"]);\n\n function walk(dir: string): void {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n if (entry.name !== \"node_modules\" && entry.name !== \".git\") {\n walk(fullPath);\n }\n } else if (extensions.has(path.extname(entry.name).toLowerCase())) {\n results.push(fullPath);\n }\n }\n }\n\n walk(targetPath);\n return results;\n}\n\nfunction resolveProvenanceRoot(targetPath: string): string {\n const resolvedTarget = path.resolve(targetPath);\n const stat = fs.statSync(resolvedTarget);\n return stat.isFile() ? path.dirname(resolvedTarget) : resolvedTarget;\n}\n\n// ── Statement extraction ─────────────────────────────────────────────────────\n\nfunction extractStatements(\n content: string,\n filePath: string,\n projectRoot: string,\n source: string,\n sourceFileHash: string,\n categoryOverride: string | undefined,\n confidence: number,\n entityRef: string | undefined,\n tags: string[],\n): CuratedStatement[] {\n const relativePath = path.relative(projectRoot, path.resolve(filePath)) || path.basename(filePath);\n const statements: CuratedStatement[] = [];\n const now = new Date().toISOString();\n\n // Split content into paragraphs/lines and extract meaningful statements\n const paragraphs = content\n .split(/\\n{2,}/)\n .map((p) => p.trim())\n .filter((p) => p.length > 20 && p.length < 2000);\n\n // Also extract list items\n const listItems = content\n .split(\"\\n\")\n .filter((l) => /^\\s*[-*]\\s+/.test(l))\n .map((l) => l.replace(/^\\s*[-*]\\s+/, \"\").trim())\n .filter((l) => l.length > 10 && l.length < 500);\n\n const allItems = [...paragraphs, ...listItems];\n\n // Deduplicate within file\n const seen = new Set<string>();\n for (const item of allItems) {\n const hash = hashContent(item.toLowerCase());\n if (seen.has(hash)) continue;\n seen.add(hash);\n\n const id = generateId();\n const category = categoryOverride ?? detectCategory(item);\n\n statements.push({\n id,\n content: item,\n category,\n confidence,\n provenance: {\n sourcePath: filePath,\n relativePath,\n source,\n lineNumber: 0,\n ingestedAt: now,\n sourceFileHash,\n },\n contentHash: hash,\n tags: [...tags],\n entityRef,\n });\n }\n\n return statements;\n}\n\n// ── Category detection ───────────────────────────────────────────────────────\n\nfunction detectCategory(text: string): string {\n const lower = text.toLowerCase();\n\n if (/^(always|never|must|should|don't|avoid|ensure)/.test(lower)) return \"principle\";\n if (/^(we|team|project)\\s+(decided|chose|will|use)/.test(lower)) return \"decision\";\n if (/^(i|we)\\s+(prefer|like|want|hate|dislike)/.test(lower)) return \"preference\";\n if (/fix|bug|issue|broken|error/i.test(lower)) return \"correction\";\n if (/\\?.+$/.test(lower.trim())) return \"question\";\n\n return \"fact\";\n}\n\n// ── Dedup ────────────────────────────────────────────────────────────────────\n\ninterface ExistingMemory {\n id: string;\n content: string;\n category: string;\n}\n\nfunction findDuplicate(\n stmt: CuratedStatement,\n existing: Map<string, ExistingMemory>,\n): DuplicateResult | null {\n const stmtLower = stmt.content.toLowerCase();\n\n // Exact hash match\n const exactMatch = existing.get(stmt.contentHash);\n if (exactMatch) {\n return {\n newStatement: stmt,\n existingId: exactMatch.id,\n similarity: 1,\n action: \"skip\",\n };\n }\n\n // Fuzzy match — check substring containment\n for (const [_, mem] of existing) {\n const memLower = mem.content.toLowerCase();\n if (memLower.length > 50 && stmtLower.length > 50) {\n // Check if one contains the other\n if (memLower.includes(stmtLower.slice(0, 40)) || stmtLower.includes(memLower.slice(0, 40))) {\n return {\n newStatement: stmt,\n existingId: mem.id,\n similarity: 0.85,\n action: \"skip\",\n };\n }\n }\n }\n\n return null;\n}\n\n// ── Contradiction detection ──────────────────────────────────────────────────\n\nfunction findContradiction(\n stmt: CuratedStatement,\n existing: Map<string, ExistingMemory>,\n): ContradictionResult | null {\n const negationPatterns = [\n /\\b(not|don't|doesn't|isn't|aren't|won't|can't|never|no)\\b/i,\n ];\n\n const hasNegation = negationPatterns.some((p) => p.test(stmt.content));\n if (!hasNegation) return null;\n\n // Strip negation and look for positive version\n const stripped = stmt.content\n .toLowerCase()\n .replace(/\\b(not|don't|doesn't|isn't|aren't|won't|can't|never|no)\\b/gi, \"\")\n .trim();\n\n if (stripped.length < 20) return null;\n\n for (const [_, mem] of existing) {\n const memLower = mem.content.toLowerCase();\n // If an existing memory affirms what this statement negates\n if (memLower.includes(stripped.slice(0, Math.min(30, stripped.length)))) {\n return {\n newStatement: stmt,\n conflictingId: mem.id,\n conflictingContent: mem.content,\n severity: \"high\",\n };\n }\n }\n\n return null;\n}\n\n// ── Memory loading ───────────────────────────────────────────────────────────\n\nfunction loadExistingMemories(memoryDir: string): Map<string, ExistingMemory> {\n const result = new Map<string, ExistingMemory>();\n if (!fs.existsSync(memoryDir)) return result;\n\n // Walk all known category dirs for existing memories\n const dirs = ALL_CATEGORY_DIRS;\n for (const dir of dirs) {\n const fullDir = path.join(memoryDir, dir);\n if (!fs.existsSync(fullDir)) continue;\n\n walkFiles(fullDir, (filePath) => {\n const content = readFileSafe(filePath);\n if (!content) return;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id || !body) return;\n\n const hash = hashContent(body.toLowerCase());\n result.set(hash, {\n id: fm.id,\n content: body,\n category: fm.category ?? dir.slice(0, -1),\n });\n });\n }\n\n return result;\n}\n\n// ── Writing ──────────────────────────────────────────────────────────────────\n\nfunction writeStatement(stmt: CuratedStatement, memoryDir: string): string {\n const now = new Date();\n const dateDir = now.toISOString().split(\"T\")[0];\n const categoryDir = getCategoryDir(memoryDir, stmt.category);\n\n const dir = path.join(categoryDir, dateDir);\n fs.mkdirSync(dir, { recursive: true });\n\n const fileName = `${stmt.category}-${Date.now()}-${stmt.id.slice(0, 8)}.md`;\n const filePath = path.join(dir, fileName);\n\n const frontmatter = [\n \"---\",\n `id: ${stmt.id}`,\n `category: ${stmt.category}`,\n `created: ${stmt.provenance.ingestedAt}`,\n `updated: ${stmt.provenance.ingestedAt}`,\n `confidence: ${stmt.confidence}`,\n `confidenceTier: ${tierFromConfidence(stmt.confidence)}`,\n `source: ${stmt.provenance.source}`,\n `tags: ${JSON.stringify(stmt.tags)}`,\n stmt.entityRef ? `entityRef: ${stmt.entityRef}` : null,\n `provenanceFile: ${stmt.provenance.relativePath}`,\n `provenanceHash: ${stmt.provenance.sourceFileHash}`,\n \"---\",\n ]\n .filter(Boolean)\n .join(\"\\n\");\n\n const body = `${frontmatter}\\n\\n${stmt.content}\\n`;\n\n fs.writeFileSync(filePath, body);\n return filePath;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction generateId(): string {\n return crypto.randomUUID();\n}\n\nfunction hashContent(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\nfunction tierFromConfidence(confidence: number): string {\n if (confidence >= 0.95) return \"explicit\";\n if (confidence >= 0.8) return \"high\";\n if (confidence >= 0.5) return \"medium\";\n return \"low\";\n}\n\nfunction readFileSafe(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction isBinary(content: string): boolean {\n // Simple heuristic: if content has null bytes, it's binary\n for (let i = 0; i < Math.min(content.length, 8000); i++) {\n if (content.charCodeAt(i) === 0) return true;\n }\n return false;\n}\n\ninterface SimpleFrontmatter {\n id?: string;\n category?: string;\n [key: string]: unknown;\n}\n\nfunction parseFrontmatter(content: string): SimpleFrontmatter | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fm: SimpleFrontmatter = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n (fm as Record<string, unknown>)[key] = value;\n }\n return fm;\n}\n\nfunction extractBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n([\\s\\S]*)/);\n return match ? match[1].trim() : content.trim();\n}\n\nfunction walkFiles(dir: string, callback: (filePath: string) => void): void {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walkFiles(fullPath, callback);\n } else if (entry.name.endsWith(\".md\")) {\n callback(fullPath);\n }\n }\n}\n","/**\n * @remnic/core — Dedup & Contradiction Detection\n *\n * Statement-level deduplication and contradiction detection\n * against existing memories. Can be used standalone or via curation.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\nimport { ALL_CATEGORY_DIRS } from \"../utils/category-dir.js\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface MemoryEntry {\n /** Memory ID */\n id: string;\n /** Content text */\n content: string;\n /** Category */\n category: string;\n /** File path (if known) */\n filePath?: string;\n}\n\nexport interface DedupOptions {\n /** Memory root directory */\n memoryDir: string;\n /** Categories to scan (default: all) */\n categories?: string[];\n /** Similarity threshold for fuzzy matching (0-1, default: 0.85) */\n threshold?: number;\n /** Max memories to load (default: 10000) */\n maxLoad?: number;\n}\n\nexport interface DedupResult {\n /** Total memories scanned */\n scanned: number;\n /** Duplicate pairs found */\n duplicates: DuplicatePair[];\n /** Duration in ms */\n durationMs: number;\n}\n\nexport interface DuplicatePair {\n /** First memory */\n left: MemoryEntry;\n /** Second memory */\n right: MemoryEntry;\n /** Similarity score */\n similarity: number;\n /** Recommended action */\n action: \"merge\" | \"keep_left\" | \"keep_right\";\n}\n\nexport interface ContradictionOptions {\n /** Memory root directory */\n memoryDir: string;\n /** Categories to scan (default: all) */\n categories?: string[];\n /** Max memories to load (default: 10000) */\n maxLoad?: number;\n}\n\nexport interface ContradictionResult {\n /** Total memories scanned */\n scanned: number;\n /** Contradictions found */\n contradictions: ContradictionPair[];\n /** Duration in ms */\n durationMs: number;\n}\n\nexport interface ContradictionPair {\n /** First statement */\n left: MemoryEntry;\n /** Contradicting statement */\n right: MemoryEntry;\n /** Severity */\n severity: \"high\" | \"medium\" | \"low\";\n /** Reason */\n reason: string;\n}\n\n// ── Main functions ───────────────────────────────────────────────────────────\n\nconst DEFAULT_DEDUP_THRESHOLD = 0.85;\nconst DEFAULT_MAX_LOAD = 10000;\n\nfunction normalizeThreshold(value: number | undefined, defaultValue: number): number {\n return typeof value === \"number\" &&\n Number.isFinite(value) &&\n value >= 0 &&\n value <= 1\n ? value\n : defaultValue;\n}\n\nfunction normalizeMaxLoad(value: number | undefined, defaultValue: number): number {\n return typeof value === \"number\" &&\n Number.isInteger(value) &&\n value >= 0\n ? value\n : defaultValue;\n}\n\nexport function findDuplicates(options: DedupOptions): DedupResult {\n const startTime = Date.now();\n const { memoryDir } = options;\n const threshold = normalizeThreshold(options.threshold, DEFAULT_DEDUP_THRESHOLD);\n const maxLoad = normalizeMaxLoad(options.maxLoad, DEFAULT_MAX_LOAD);\n\n const memories = loadMemories(memoryDir, options.categories, maxLoad);\n const duplicates: DuplicatePair[] = [];\n\n // Compare all pairs (O(n^2) but bounded by maxLoad)\n for (let i = 0; i < memories.length; i++) {\n for (let j = i + 1; j < memories.length; j++) {\n const sim = computeSimilarity(memories[i].content, memories[j].content);\n if (sim >= threshold) {\n duplicates.push({\n left: memories[i],\n right: memories[j],\n similarity: sim,\n action: sim >= 0.98 ? \"merge\" : sim >= 0.9 ? \"keep_right\" : \"keep_left\",\n });\n }\n }\n }\n\n return {\n scanned: memories.length,\n duplicates,\n durationMs: Date.now() - startTime,\n };\n}\n\nexport function findContradictions(options: ContradictionOptions): ContradictionResult {\n const startTime = Date.now();\n const { memoryDir } = options;\n const maxLoad = normalizeMaxLoad(options.maxLoad, DEFAULT_MAX_LOAD);\n\n const memories = loadMemories(memoryDir, options.categories, maxLoad);\n const contradictions: ContradictionPair[] = [];\n\n for (let i = 0; i < memories.length; i++) {\n for (let j = i + 1; j < memories.length; j++) {\n const contra = detectContradiction(memories[i], memories[j]);\n if (contra) {\n contradictions.push(contra);\n }\n }\n }\n\n return {\n scanned: memories.length,\n contradictions,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Similarity computation ───────────────────────────────────────────────────\n\nfunction computeSimilarity(a: string, b: string): number {\n // Normalize\n const normA = normalize(a);\n const normB = normalize(b);\n\n // Exact match\n if (normA === normB) return 1;\n\n // Hash-based exact match\n if (hashContent(normA) === hashContent(normB)) return 0.99;\n\n // Substring containment\n if (normA.length > 50 && normB.length > 50) {\n if (normA.includes(normB.slice(0, 40)) || normB.includes(normA.slice(0, 40))) {\n return 0.9;\n }\n }\n\n // Word overlap (Jaccard)\n const wordsA = new Set(normA.split(/\\s+/));\n const wordsB = new Set(normB.split(/\\s+/));\n const intersection = new Set([...wordsA].filter((w) => wordsB.has(w)));\n const union = new Set([...wordsA, ...wordsB]);\n\n if (union.size === 0) return 0;\n return intersection.size / union.size;\n}\n\nfunction normalize(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^\\w\\s']/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n// ── Contradiction detection ──────────────────────────────────────────────────\n\nconst NEGATION_WORDS = new Set([\n \"not\", \"don't\", \"doesn't\", \"isn't\", \"aren't\", \"won't\", \"can't\", \"cannot\",\n \"never\", \"no\", \"none\", \"neither\", \"nor\", \"nothing\", \"nowhere\",\n]);\n\nfunction detectContradiction(\n a: MemoryEntry,\n b: MemoryEntry,\n): ContradictionPair | null {\n const normA = normalize(a.content);\n const normB = normalize(b.content);\n\n // Check if one has negation and the other doesn't\n const aHasNegation = containsNegation(normA);\n const bHasNegation = containsNegation(normB);\n\n if (aHasNegation === bHasNegation) return null;\n\n // Strip negation and compare core content\n const strippedA = stripNegation(normA);\n const strippedB = stripNegation(normB);\n\n const sim = computeSimilarity(strippedA, strippedB);\n if (sim < 0.7) return null;\n\n // Check for opposite quantifiers\n const oppQuantifiers = [\n [\"always\", \"never\"],\n [\"all\", \"none\"],\n [\"every\", \"no\"],\n [\"must\", \"must not\"],\n [\"should\", \"should not\"],\n [\"can\", \"cannot\"],\n ];\n\n for (const [pos, neg] of oppQuantifiers) {\n if (\n (a.content.toLowerCase().includes(pos) && b.content.toLowerCase().includes(neg)) ||\n (a.content.toLowerCase().includes(neg) && b.content.toLowerCase().includes(pos))\n ) {\n return {\n left: a,\n right: b,\n severity: \"high\",\n reason: `Opposite quantifiers: \"${pos}\" vs \"${neg}\"`,\n };\n }\n }\n\n return {\n left: a,\n right: b,\n severity: sim >= 0.85 ? \"high\" : \"medium\",\n reason: \"Negated version of similar content\",\n };\n}\n\nfunction containsNegation(text: string): boolean {\n const words = text.split(/\\s+/);\n return words.some((w) => NEGATION_WORDS.has(w));\n}\n\nfunction stripNegation(text: string): string {\n return text\n .replace(/\\b(not|don't|doesn't|isn't|aren't|won't|can't|cannot|never|no|none|neither|nor|nothing|nowhere)\\b/gi, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n// ── Memory loading ───────────────────────────────────────────────────────────\n\nfunction loadMemories(\n memoryDir: string,\n categories?: string[],\n maxLoad = 10000,\n): MemoryEntry[] {\n const result: MemoryEntry[] = [];\n const allCategories = categories ?? ALL_CATEGORY_DIRS;\n if (!fs.existsSync(memoryDir)) return result;\n const memoryRootReal = fs.realpathSync(memoryDir);\n\n for (const category of allCategories) {\n if (result.length >= maxLoad) break;\n\n const dir = path.join(memoryDir, category);\n if (!fs.existsSync(dir)) continue;\n const categoryStat = fs.lstatSync(dir);\n if (categoryStat.isSymbolicLink()) {\n throw new Error(`Refusing to scan symlinked memory category directory: ${dir}`);\n }\n if (!categoryStat.isDirectory()) continue;\n const categoryRootReal = fs.realpathSync(dir);\n assertPathInsideRoot(memoryRootReal, categoryRootReal, dir);\n\n walkMdFiles(dir, memoryRootReal, categoryRootReal, (filePath) => {\n if (result.length >= maxLoad) return;\n\n const content = readFileSafe(filePath, memoryRootReal, categoryRootReal);\n if (!content) return;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id || !body) return;\n\n result.push({\n id: fm.id as string,\n content: body,\n category: (fm.category as string) ?? category.slice(0, -1),\n filePath,\n });\n });\n }\n\n return result;\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction hashContent(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\nfunction readFileSafe(\n filePath: string,\n memoryRootReal: string,\n categoryRootReal: string,\n): string | null {\n try {\n const fileStat = fs.lstatSync(filePath);\n if (fileStat.isSymbolicLink()) {\n throw new Error(`Refusing to read symlinked memory file: ${filePath}`);\n }\n const fileReal = fs.realpathSync(filePath);\n assertPathInsideRoot(memoryRootReal, fileReal, filePath);\n assertPathInsideRoot(categoryRootReal, fileReal, filePath);\n return fs.readFileSync(filePath, \"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction parseFrontmatter(content: string): Record<string, unknown> | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fm: Record<string, unknown> = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n fm[key] = value;\n }\n return fm;\n}\n\nfunction extractBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n([\\s\\S]*)/);\n return match ? match[1].trim() : content.trim();\n}\n\nfunction assertPathInsideRoot(rootReal: string, targetReal: string, sourcePath: string): void {\n const rel = path.relative(rootReal, targetReal);\n if (rel === \"\" || (!rel.startsWith(\"..\") && !path.isAbsolute(rel))) {\n return;\n }\n throw new Error(`Refusing to scan memory path outside root: ${sourcePath}`);\n}\n\nfunction walkMdFiles(\n dir: string,\n memoryRootReal: string,\n categoryRootReal: string,\n callback: (filePath: string) => void,\n): void {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n const entryStat = fs.lstatSync(fullPath);\n if (entryStat.isSymbolicLink()) {\n throw new Error(`Refusing to scan symlinked memory path: ${fullPath}`);\n }\n const entryReal = fs.realpathSync(fullPath);\n assertPathInsideRoot(memoryRootReal, entryReal, fullPath);\n assertPathInsideRoot(categoryRootReal, entryReal, fullPath);\n if (entryStat.isDirectory()) {\n walkMdFiles(fullPath, memoryRootReal, categoryRootReal, callback);\n } else if (entry.name.endsWith(\".md\")) {\n callback(fullPath);\n }\n }\n}\n","/**\n * @remnic/core — Review Inbox\n *\n * Manages low-confidence memories and suggestions pending review.\n * Integrates with the existing review-queue system.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { getCategoryDir, ALL_CATEGORY_DIRS } from \"../utils/category-dir.js\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface ReviewItem {\n /** Memory ID */\n id: string;\n /** Content text */\n content: string;\n /** Category */\n category: string;\n /** Confidence score (0-1) */\n confidence: number;\n /** Confidence tier */\n confidenceTier: string;\n /** Source */\n source: string;\n /** File path if available */\n filePath?: string;\n /** Created date */\n created: string;\n /** Reason it's in review */\n reviewReason: \"low_confidence\" | \"suggestion\" | \"contradiction\" | \"duplicate\";\n /** Additional context */\n context?: string;\n}\n\nexport type ReviewAction = \"approve\" | \"dismiss\" | \"flag\";\n\nexport interface ReviewResult {\n /** Item acted upon */\n itemId: string;\n /** Action taken */\n action: ReviewAction;\n /** Updated file path (if modified) */\n updatedPath?: string;\n /** Status message */\n message: string;\n}\n\nexport interface ReviewListResult {\n /** Items pending review */\n items: ReviewItem[];\n /** Total count */\n total: number;\n /** Duration in ms */\n durationMs: number;\n}\n\nexport interface ReviewOptions {\n /** Memory root directory */\n memoryDir: string;\n /** Filter by reason */\n reason?: ReviewItem[\"reviewReason\"];\n /** Max items to return (default: 50) */\n limit?: number;\n /** Include items with confidence below this threshold (default: 0.7) */\n confidenceThreshold?: number;\n}\n\nexport interface ReviewActionOptions {\n /** Match the threshold used when listing review items (default: 0.7) */\n confidenceThreshold?: number;\n}\n\ninterface ReviewFileMatch {\n filePath: string;\n location: \"queue\" | \"category\";\n}\n\nconst DEFAULT_CONFIDENCE_THRESHOLD = 0.7;\n\nfunction realMemoryRoot(memoryDir: string): string | null {\n try {\n const stat = fs.lstatSync(memoryDir);\n if (!stat.isDirectory() || stat.isSymbolicLink()) return null;\n return fs.realpathSync(memoryDir);\n } catch {\n return null;\n }\n}\n\nfunction isPathInside(rootReal: string, candidateReal: string): boolean {\n const relative = path.relative(rootReal, candidateReal);\n return relative === \"\" || (!!relative && !relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nfunction isSafeDirectory(rootReal: string, dir: string): boolean {\n try {\n const stat = fs.lstatSync(dir);\n if (!stat.isDirectory() || stat.isSymbolicLink()) return false;\n return isPathInside(rootReal, fs.realpathSync(dir));\n } catch {\n return false;\n }\n}\n\nfunction ensureSafeDirectory(rootReal: string, dir: string): void {\n if (fs.existsSync(dir)) {\n if (!isSafeDirectory(rootReal, dir)) {\n throw new Error(`Refusing to write through unsafe review path: ${dir}`);\n }\n return;\n }\n fs.mkdirSync(dir, { recursive: true });\n if (!isSafeDirectory(rootReal, dir)) {\n throw new Error(`Refusing to write through unsafe review path: ${dir}`);\n }\n}\n\n// ── Main functions ───────────────────────────────────────────────────────────\n\n/**\n * List items pending review.\n */\nexport function listReviewItems(options: ReviewOptions): ReviewListResult {\n const startTime = Date.now();\n const {\n memoryDir,\n reason: filterReason,\n limit = 50,\n confidenceThreshold = DEFAULT_CONFIDENCE_THRESHOLD,\n } = options;\n const maxItems = Math.max(0, limit);\n const rootReal = realMemoryRoot(memoryDir);\n if (!rootReal || maxItems === 0) {\n return { items: [], total: 0, durationMs: Date.now() - startTime };\n }\n\n const items: ReviewItem[] = [];\n const isLimitReached = (): boolean => items.length >= maxItems;\n const addItem = (item: ReviewItem): void => {\n if (isLimitReached()) return;\n if (filterReason && item.reviewReason !== filterReason) return;\n items.push(item);\n };\n\n // Check suggestions directory\n const suggestionsDir = path.join(memoryDir, \"suggestions\");\n if (!isLimitReached() && fs.existsSync(suggestionsDir) && isSafeDirectory(rootReal, suggestionsDir)) {\n walkMd(rootReal, suggestionsDir, (filePath, content) => {\n if (isLimitReached()) return true;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id) return false;\n\n addItem({\n id: fm.id as string,\n content: body,\n category: (fm.category as string) ?? \"suggestion\",\n confidence: parseConfidence(fm.confidence, 0.5),\n confidenceTier: (fm.confidenceTier as string) ?? \"low\",\n source: (fm.source as string) ?? \"unknown\",\n filePath,\n created: (fm.created as string) ?? new Date().toISOString(),\n reviewReason: \"suggestion\",\n });\n return isLimitReached();\n });\n }\n\n // Check review directory\n const reviewDir = path.join(memoryDir, \"review\");\n if (!isLimitReached() && fs.existsSync(reviewDir) && isSafeDirectory(rootReal, reviewDir)) {\n walkMd(rootReal, reviewDir, (filePath, content) => {\n if (isLimitReached()) return true;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id) return false;\n\n addItem({\n id: fm.id as string,\n content: body,\n category: (fm.category as string) ?? \"review\",\n confidence: parseConfidence(fm.confidence, 0.5),\n confidenceTier: (fm.confidenceTier as string) ?? \"low\",\n source: (fm.source as string) ?? \"unknown\",\n filePath,\n created: (fm.created as string) ?? new Date().toISOString(),\n reviewReason: (fm.reviewReason as ReviewItem[\"reviewReason\"]) ?? \"low_confidence\",\n context: fm.context as string | undefined,\n });\n return isLimitReached();\n });\n }\n\n // Scan all categories for low-confidence items\n const categories = ALL_CATEGORY_DIRS;\n for (const category of categories) {\n if (isLimitReached()) break;\n\n const dir = path.join(memoryDir, category);\n if (!fs.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;\n\n walkMd(rootReal, dir, (filePath, content) => {\n if (isLimitReached()) return true;\n\n const fm = parseFrontmatter(content);\n const body = extractBody(content);\n if (!fm?.id) return false;\n\n const confidence = parseConfidence(fm.confidence, 1);\n if (confidence >= confidenceThreshold) return false;\n if (parseBoolean(fm.reviewDismissed)) return false;\n\n // Skip if already in items\n if (items.some((i) => i.id === fm.id)) return false;\n\n addItem({\n id: fm.id as string,\n content: body,\n category: (fm.category as string) ?? category.slice(0, -1),\n confidence,\n confidenceTier: (fm.confidenceTier as string) ?? \"low\",\n source: (fm.source as string) ?? \"unknown\",\n filePath,\n created: (fm.created as string) ?? new Date().toISOString(),\n reviewReason: \"low_confidence\",\n });\n return isLimitReached();\n });\n }\n\n return {\n items,\n total: items.length,\n durationMs: Date.now() - startTime,\n };\n}\n\n/**\n * Perform a review action on an item.\n */\nexport function performReview(\n memoryDir: string,\n itemId: string,\n action: ReviewAction,\n options: ReviewActionOptions = {},\n): ReviewResult {\n switch (action) {\n case \"approve\":\n return approveItem(memoryDir, itemId, options);\n case \"dismiss\":\n return dismissItem(memoryDir, itemId, options);\n case \"flag\":\n return flagItem(memoryDir, itemId, options);\n }\n}\n\n// ── Actions ──────────────────────────────────────────────────────────────────\n\nfunction approveItem(\n memoryDir: string,\n itemId: string,\n options: ReviewActionOptions,\n): ReviewResult {\n const rootReal = realMemoryRoot(memoryDir);\n if (!rootReal) return { itemId, action: \"approve\", message: \"Item not found\" };\n const found = findReviewFileById(memoryDir, itemId, options);\n if (!found) {\n return { itemId, action: \"approve\", message: \"Item not found\" };\n }\n\n const content = fs.readFileSync(found.filePath, \"utf8\");\n const fm = parseFrontmatter(content);\n if (!fm) return { itemId, action: \"approve\", message: \"Could not parse frontmatter\" };\n\n const updatedContent = updateFrontmatterFields(content, {\n confidence: \"0.9\",\n confidenceTier: \"high\",\n reviewDismissed: null,\n });\n\n if (found.location === \"category\") {\n fs.writeFileSync(found.filePath, updatedContent, \"utf8\");\n return {\n itemId,\n action: \"approve\",\n updatedPath: found.filePath,\n message: \"Approved low-confidence memory in place with confidence 0.9\",\n };\n }\n\n // Promote queued suggestions/review items to their category directory.\n const category = (fm.category as string) ?? \"fact\";\n const targetDir = getCategoryDir(memoryDir, category);\n const dateDir = new Date().toISOString().split(\"T\")[0];\n ensureSafeDirectory(rootReal, targetDir);\n const outputPath = path.join(targetDir, dateDir, path.basename(found.filePath));\n\n ensureSafeDirectory(rootReal, path.dirname(outputPath));\n const promotedPath = writeFileWithoutClobber(outputPath, updatedContent, itemId);\n\n // Remove from review\n fs.unlinkSync(found.filePath);\n\n return {\n itemId,\n action: \"approve\",\n updatedPath: promotedPath,\n message: `Promoted to ${category} with confidence 0.9`,\n };\n}\n\nfunction dismissItem(\n memoryDir: string,\n itemId: string,\n options: ReviewActionOptions,\n): ReviewResult {\n const found = findReviewFileById(memoryDir, itemId, options);\n if (!found) {\n return { itemId, action: \"dismiss\", message: \"Item not found\" };\n }\n\n if (found.location === \"queue\") {\n fs.unlinkSync(found.filePath);\n return { itemId, action: \"dismiss\", message: \"Dismissed and removed\" };\n }\n\n const content = fs.readFileSync(found.filePath, \"utf8\");\n fs.writeFileSync(\n found.filePath,\n updateFrontmatterFields(content, {\n reviewDismissed: \"true\",\n reviewDismissedAt: new Date().toISOString(),\n }),\n \"utf8\",\n );\n return {\n itemId,\n action: \"dismiss\",\n updatedPath: found.filePath,\n message: \"Dismissed low-confidence memory in place\",\n };\n}\n\nfunction flagItem(\n memoryDir: string,\n itemId: string,\n options: ReviewActionOptions,\n): ReviewResult {\n const found = findReviewFileById(memoryDir, itemId, options);\n if (!found) {\n return { itemId, action: \"flag\", message: \"Item not found\" };\n }\n\n const content = fs.readFileSync(found.filePath, \"utf8\");\n const fixed = updateFrontmatterFields(content, {\n flagged: \"true\",\n flaggedAt: new Date().toISOString(),\n });\n fs.writeFileSync(found.filePath, fixed);\n return {\n itemId,\n action: \"flag\",\n updatedPath: found.filePath,\n message: \"Flagged for further review\",\n };\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction findReviewFileById(\n memoryDir: string,\n id: string,\n options: ReviewActionOptions = {},\n): ReviewFileMatch | null {\n const rootReal = realMemoryRoot(memoryDir);\n if (!rootReal) return null;\n for (const loc of [\"suggestions\", \"review\"]) {\n const dir = path.join(memoryDir, loc);\n if (!fs.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;\n\n const found = findFileById(rootReal, dir, id);\n if (found) return { filePath: found, location: \"queue\" };\n }\n\n for (const category of ALL_CATEGORY_DIRS) {\n const dir = path.join(memoryDir, category);\n if (!fs.existsSync(dir) || !isSafeDirectory(rootReal, dir)) continue;\n\n const found = findFileById(rootReal, dir, id, (fm) => isLowConfidenceReviewCandidate(fm, options));\n if (found) return { filePath: found, location: \"category\" };\n }\n\n return null;\n}\n\nfunction findFileById(\n rootReal: string,\n dir: string,\n id: string,\n include?: (frontmatter: Record<string, unknown>) => boolean,\n): string | null {\n const files = walkMdPaths(rootReal, dir);\n for (const filePath of files) {\n const content = readFileSafe(filePath);\n if (!content) continue;\n const fm = parseFrontmatter(content);\n if (fm?.id === id && (!include || include(fm))) return filePath;\n }\n return null;\n}\n\nfunction isLowConfidenceReviewCandidate(\n fm: Record<string, unknown>,\n options: ReviewActionOptions,\n): boolean {\n const threshold = options.confidenceThreshold ?? DEFAULT_CONFIDENCE_THRESHOLD;\n return (\n parseConfidence(fm.confidence, 1) < threshold &&\n !parseBoolean(fm.reviewDismissed)\n );\n}\n\nfunction parseBoolean(value: unknown): boolean {\n if (typeof value === \"boolean\") return value;\n if (typeof value !== \"string\") return false;\n const normalized = value.trim().toLowerCase();\n return normalized === \"true\" || normalized === \"1\" || normalized === \"yes\";\n}\n\nfunction parseConfidence(value: unknown, fallback: number): number {\n if (typeof value === \"number\") return Number.isFinite(value) ? value : fallback;\n if (typeof value === \"string\") {\n const n = parseFloat(value);\n return Number.isFinite(n) ? n : fallback;\n }\n return fallback;\n}\n\nfunction updateFrontmatterFields(\n content: string,\n fields: Record<string, string | null>,\n): string {\n const match = content.match(/^(---\\n)([\\s\\S]*?)(\\n---(?:\\n|$))/);\n if (!match) return content;\n\n const seen = new Set<string>();\n const lines = match[2].split(\"\\n\");\n const nextLines: string[] = [];\n for (const line of lines) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) {\n nextLines.push(line);\n continue;\n }\n const key = line.slice(0, colonIdx).trim();\n if (!Object.prototype.hasOwnProperty.call(fields, key)) {\n nextLines.push(line);\n continue;\n }\n seen.add(key);\n const value = fields[key];\n if (value !== null) {\n nextLines.push(`${key}: ${value}`);\n }\n }\n\n for (const [key, value] of Object.entries(fields)) {\n if (value !== null && !seen.has(key)) {\n nextLines.push(`${key}: ${value}`);\n }\n }\n\n return `${match[1]}${nextLines.join(\"\\n\")}${match[3]}${content.slice(match[0].length)}`;\n}\n\nfunction readFileSafe(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, \"utf8\");\n } catch {\n return null;\n }\n}\n\nfunction writeFileWithoutClobber(basePath: string, content: string, discriminator: string): string {\n const parsed = path.parse(basePath);\n const safeDiscriminator = sanitizeFilePart(discriminator);\n\n for (let attempt = 0; attempt < 1000; attempt++) {\n const candidate = attempt === 0\n ? basePath\n : path.join(\n parsed.dir,\n `${parsed.name}-${safeDiscriminator}${attempt === 1 ? \"\" : `-${attempt}`}${parsed.ext || \".md\"}`,\n );\n\n try {\n fs.writeFileSync(candidate, content, { encoding: \"utf8\", flag: \"wx\" });\n return candidate;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") continue;\n throw error;\n }\n }\n\n throw new Error(`Could not find a free review promotion path for ${basePath}`);\n}\n\nfunction sanitizeFilePart(value: string): string {\n const chars: string[] = [];\n let previousWasDash = false;\n\n for (const char of value) {\n const next = isSafeFilePartChar(char) ? char : \"-\";\n if (next === \"-\" && previousWasDash) continue;\n chars.push(next);\n previousWasDash = next === \"-\";\n if (chars.length >= 64) break;\n }\n\n let start = 0;\n let end = chars.length;\n while (start < end && chars[start] === \"-\") start++;\n while (end > start && chars[end - 1] === \"-\") end--;\n\n const sanitized = chars.slice(start, end).join(\"\");\n return sanitized || \"review-item\";\n}\n\nfunction isSafeFilePartChar(value: string): boolean {\n if (value.length !== 1) return false;\n const code = value.charCodeAt(0);\n return (\n (code >= 48 && code <= 57) ||\n (code >= 65 && code <= 90) ||\n (code >= 97 && code <= 122) ||\n value === \".\" ||\n value === \"_\" ||\n value === \"-\"\n );\n}\n\nfunction parseFrontmatter(content: string): Record<string, unknown> | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fm: Record<string, unknown> = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n fm[key] = value;\n }\n return fm;\n}\n\nfunction extractBody(content: string): string {\n const match = content.match(/^---\\n[\\s\\S]*?\\n---\\n([\\s\\S]*)/);\n return match ? match[1].trim() : content.trim();\n}\n\nfunction walkMd(rootReal: string, dir: string, callback: (filePath: string, content: string) => boolean | void): boolean {\n if (!isSafeDirectory(rootReal, dir)) return false;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n if (walkMd(rootReal, fullPath, callback)) return true;\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n const content = readFileSafe(fullPath);\n if (content && callback(fullPath, content) === true) return true;\n }\n }\n return false;\n}\n\nfunction walkMdPaths(rootReal: string, dir: string): string[] {\n const results: string[] = [];\n if (!isSafeDirectory(rootReal, dir)) return results;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n results.push(...walkMdPaths(rootReal, fullPath));\n } else if (entry.isFile() && entry.name.endsWith(\".md\")) {\n results.push(fullPath);\n }\n }\n return results;\n}\n","/**\n * @remnic/core — Diff-Aware Sync\n *\n * Watches source files for changes and triggers re-ingestion\n * only for changed content. Uses file hashing to detect changes.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport interface SyncOptions {\n /** Source directory to watch */\n sourceDir: string;\n /** Memory root directory */\n memoryDir: string;\n /** State file path (stores hashes). Default: memoryDir/.sync-state.json */\n stateFile?: string;\n /** File extensions to watch (default: .md, .txt, .mdx) */\n extensions?: string[];\n /** Directories to exclude */\n excludeDirs?: string[];\n /** Poll interval for watchForChanges. Default: 5000ms */\n pollIntervalMs?: number;\n /** Whether to actually write changes (default: true) */\n dryRun?: boolean;\n}\n\nexport interface SyncResult {\n /** Files scanned */\n scanned: number;\n /** Files changed since last sync */\n changed: FileChange[];\n /** Files unchanged */\n unchanged: number;\n /** Files deleted since last sync */\n deleted: string[];\n /** Files newly added */\n added: string[];\n /** Duration in ms */\n durationMs: number;\n /** State file path */\n stateFile: string;\n}\n\nexport interface FileChange {\n /** Absolute file path */\n filePath: string;\n /** Relative path from source root */\n relativePath: string;\n /** Change type */\n type: \"added\" | \"modified\" | \"deleted\";\n /** Current content hash */\n currentHash: string;\n /** Previous content hash (if modified) */\n previousHash?: string;\n /** File size in bytes */\n size: number;\n}\n\nexport interface SyncState {\n /** Map of relative path → content hash */\n fileHashes: Record<string, string>;\n /** Last sync timestamp */\n lastSyncAt: string;\n /** Version of state format */\n version: number;\n}\n\n// ── Constants ────────────────────────────────────────────────────────────────\n\nconst DEFAULT_EXTENSIONS = new Set([\".md\", \".txt\", \".mdx\", \".rst\"]);\nconst DEFAULT_EXCLUDE = new Set([\n \"node_modules\",\n \".git\",\n \"dist\",\n \"build\",\n \".engram\",\n \"coverage\",\n]);\n\n// ── Main function ────────────────────────────────────────────────────────────\n\nexport function syncChanges(options: SyncOptions): SyncResult {\n const startTime = Date.now();\n const {\n sourceDir,\n memoryDir,\n extensions = [...DEFAULT_EXTENSIONS],\n excludeDirs = [],\n dryRun = false,\n } = options;\n\n const extSet = new Set(extensions);\n const excludeSet = new Set([...DEFAULT_EXCLUDE, ...excludeDirs]);\n const stateFilePath = options.stateFile ?? path.join(memoryDir, \".sync-state.json\");\n\n // Load previous state\n const prevState = loadState(stateFilePath);\n\n // Scan current files\n const currentFiles = scanFiles(sourceDir, extSet, excludeSet);\n\n // Compute diffs\n const changes = computeDiff(currentFiles, prevState.fileHashes, sourceDir);\n\n const added = changes.filter((c) => c.type === \"added\").map((c) => c.relativePath);\n const modified = changes.filter((c) => c.type === \"modified\");\n const deleted = changes\n .filter((c) => c.type === \"deleted\")\n .map((c) => c.relativePath);\n\n // Update state (even in dry run, we want to show what would change)\n if (!dryRun) {\n const newState: SyncState = {\n fileHashes: {},\n lastSyncAt: new Date().toISOString(),\n version: 1,\n };\n\n // Build new state from current files\n for (const [relPath, hash] of Object.entries(currentFiles)) {\n newState.fileHashes[relPath] = hash;\n }\n\n // Write state\n fs.mkdirSync(path.dirname(stateFilePath), { recursive: true });\n fs.writeFileSync(stateFilePath, JSON.stringify(newState, null, 2));\n }\n\n return {\n scanned: Object.keys(currentFiles).length,\n changed: changes,\n unchanged:\n Object.keys(currentFiles).length - changes.filter((c) => c.type !== \"deleted\").length,\n deleted,\n added,\n durationMs: Date.now() - startTime,\n stateFile: stateFilePath,\n };\n}\n\n/**\n * Watch for changes and call callback on file changes.\n * Returns a stop function.\n */\nexport function watchForChanges(\n options: SyncOptions,\n onChange: (changes: FileChange[]) => void | Promise<void>,\n): { stop: () => void } {\n const { sourceDir, extensions, excludeDirs } = options;\n const extSet = new Set(extensions ?? DEFAULT_EXTENSIONS);\n const excludeSet = new Set([...DEFAULT_EXCLUDE, ...(excludeDirs ?? [])]);\n const pollIntervalMs =\n typeof options.pollIntervalMs === \"number\" &&\n Number.isFinite(options.pollIntervalMs) &&\n options.pollIntervalMs > 0\n ? options.pollIntervalMs\n : 5000;\n\n let lastHashes: Record<string, string> = {};\n let pollInFlight = false;\n\n // Initial scan\n const currentFiles = scanFiles(sourceDir, extSet, excludeSet);\n lastHashes = { ...currentFiles };\n\n // Poll interval (FSWatcher doesn't reliably work for all platforms)\n const poll = async (): Promise<void> => {\n if (pollInFlight) return;\n pollInFlight = true;\n try {\n const nowFiles = scanFiles(sourceDir, extSet, excludeSet);\n const changes = computeDiff(nowFiles, lastHashes, sourceDir);\n\n if (changes.length > 0) {\n await onChange(changes);\n // Update hashes\n for (const change of changes) {\n if (change.type === \"deleted\") {\n delete lastHashes[change.relativePath];\n } else {\n lastHashes[change.relativePath] = change.currentHash;\n }\n }\n }\n } catch {\n // Leave lastHashes unchanged so the next poll retries the same diff.\n } finally {\n pollInFlight = false;\n }\n };\n const interval = setInterval(() => {\n void poll();\n }, pollIntervalMs);\n\n return {\n stop: () => clearInterval(interval),\n };\n}\n\n// ── File scanning ────────────────────────────────────────────────────────────\n\nfunction scanFiles(\n root: string,\n extensions: Set<string>,\n exclude: Set<string>,\n): Record<string, string> {\n const result: Record<string, string> = {};\n\n function walk(dir: string, isRoot = false): void {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch (err) {\n if (isRoot) {\n throw new Error(\n `sync scan failed for ${dir}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n return;\n }\n\n for (const entry of entries) {\n if (exclude.has(entry.name)) continue;\n\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walk(fullPath);\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name).toLowerCase();\n if (!extensions.has(ext)) continue;\n\n const relPath = path.relative(root, fullPath);\n try {\n const content = fs.readFileSync(fullPath, \"utf8\");\n result[relPath] = hashContent(content);\n } catch {\n // Can't read — skip\n }\n }\n }\n }\n\n walk(root, true);\n return result;\n}\n\n// ── Diff computation ─────────────────────────────────────────────────────────\n\nfunction computeDiff(\n current: Record<string, string>,\n previous: Record<string, string>,\n sourceDir: string,\n): FileChange[] {\n const changes: FileChange[] = [];\n\n // Find added and modified\n for (const [relPath, hash] of Object.entries(current)) {\n const fullPath = path.join(sourceDir, relPath);\n\n if (!(relPath in previous)) {\n // Added\n let size = 0;\n try {\n size = fs.statSync(fullPath).size;\n } catch {\n // ignore\n }\n changes.push({\n filePath: fullPath,\n relativePath: relPath,\n type: \"added\",\n currentHash: hash,\n size,\n });\n } else if (previous[relPath] !== hash) {\n // Modified\n let size = 0;\n try {\n size = fs.statSync(fullPath).size;\n } catch {\n // ignore\n }\n changes.push({\n filePath: fullPath,\n relativePath: relPath,\n type: \"modified\",\n currentHash: hash,\n previousHash: previous[relPath],\n size,\n });\n }\n }\n\n // Find deleted\n for (const relPath of Object.keys(previous)) {\n if (!(relPath in current)) {\n changes.push({\n filePath: path.join(sourceDir, relPath),\n relativePath: relPath,\n type: \"deleted\",\n currentHash: \"\",\n size: 0,\n });\n }\n }\n\n return changes;\n}\n\n// ── State management ─────────────────────────────────────────────────────────\n\nfunction loadState(stateFilePath: string): SyncState {\n try {\n const raw = fs.readFileSync(stateFilePath, \"utf8\");\n return JSON.parse(raw);\n } catch {\n return {\n fileHashes: {},\n lastSyncAt: new Date(0).toISOString(),\n version: 1,\n };\n }\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nfunction hashContent(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n","/**\n * @remnic/core — Spaces + Collaboration\n *\n * First-class memory spaces (personal, project, team) with merge/conflict\n * flows, promotion workflow, and audit trail.\n *\n * Each space is an isolated memory directory. Spaces can share memories\n * through push/pull and promotion workflows.\n */\n\nimport { spawnSync } from \"node:child_process\";\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { readEnvVar, resolveHomeDir } from \"../runtime/env.js\";\n\n// ── Types ────────────────────────────────────────────────────────────────────\n\nexport type SpaceKind = \"personal\" | \"project\" | \"team\";\n\nexport interface Space {\n /** Unique space ID */\n id: string;\n /** Human-readable name */\n name: string;\n /** Space type */\n kind: SpaceKind;\n /** Description */\n description?: string;\n /** Memory directory path (absolute) */\n memoryDir: string;\n /** Created at */\n createdAt: string;\n /** Updated at */\n updatedAt: string;\n /** Owner */\n owner?: string;\n /** Members (for team spaces) */\n members?: string[];\n /** Parent space (for promotion) */\n parentSpaceId?: string;\n}\n\nexport interface SpaceManifest {\n /** Current active space ID */\n activeSpaceId: string;\n /** All spaces */\n spaces: Space[];\n /** Manifest version */\n version: number;\n /** Last updated */\n updatedAt?: string;\n}\n\nexport interface SpaceSwitchResult {\n previousSpaceId: string;\n currentSpaceId: string;\n message: string;\n}\n\nexport interface SpacePushResult {\n sourceSpaceId: string;\n targetSpaceId: string;\n memoriesPushed: number;\n conflicts: ConflictEntry[];\n durationMs: number;\n}\n\nexport interface SpacePullResult {\n sourceSpaceId: string;\n targetSpaceId: string;\n memoriesPulled: number;\n conflicts: ConflictEntry[];\n durationMs: number;\n}\n\nexport interface SpaceShareResult {\n spaceId: string;\n sharedWith: string[];\n message: string;\n}\n\nexport interface SpacePromoteResult {\n sourceSpaceId: string;\n targetSpaceId: string;\n memoriesPromoted: number;\n conflicts: ConflictEntry[];\n durationMs: number;\n}\n\nexport interface ConflictEntry {\n /** Memory ID */\n memoryId: string;\n /** Source file path */\n sourcePath: string;\n /** Target file path */\n targetPath: string;\n /** Conflict type */\n conflictType: \"content_mismatch\" | \"metadata_mismatch\" | \"both\";\n /** Source content hash */\n sourceHash: string;\n /** Target content hash */\n targetHash: string;\n}\n\nexport interface MergeResult {\n merged: number;\n conflicts: ConflictEntry[];\n skipped: number;\n durationMs: number;\n}\n\nexport interface AuditEntry {\n id: string;\n timestamp: string;\n action: string;\n sourceSpaceId: string;\n targetSpaceId?: string;\n actor?: string;\n details: string;\n memoryIds?: string[];\n}\n\n// ── Manifest management ─────────────────────────────────────────────────────\n\nconst MANIFEST_VERSION = 1;\nconst MANIFEST_LOCK_STALE_MS = 30_000;\nconst MANIFEST_LOCK_TIMEOUT_MS = MANIFEST_LOCK_STALE_MS + 10_000;\nconst MANIFEST_LOCK_SLEEP_MS = 20;\n\nfunction normalizeSpaceMemoryDir(memoryDir: string): string {\n return path.resolve(memoryDir);\n}\n\nexport function getSpacesDir(baseDir?: string): string {\n const homeDir = baseDir ?? resolveHomeDir();\n return path.join(homeDir, \".config\", \"engram\", \"spaces\");\n}\n\nexport function getManifestPath(baseDir?: string): string {\n return path.join(getSpacesDir(baseDir), \"manifest.json\");\n}\n\nexport function loadManifest(baseDir?: string, memoryDirOverride?: string): SpaceManifest {\n if (fs.existsSync(getManifestPath(baseDir))) {\n try {\n return readManifestUnlocked(baseDir, memoryDirOverride, { bootstrapIfMissing: false });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n }\n\n return updateManifest(baseDir, (manifest) => manifest, memoryDirOverride);\n}\n\nexport function saveManifest(manifest: SpaceManifest, baseDir?: string): void {\n withManifestLock(baseDir, () => {\n saveManifestUnlocked(manifest, baseDir);\n });\n}\n\nexport function updateManifest<T>(\n baseDir: string | undefined,\n updater: (manifest: SpaceManifest) => T,\n memoryDirOverride?: string\n): T {\n return withManifestLock(baseDir, () => {\n const manifest = readManifestUnlocked(baseDir, memoryDirOverride);\n const result = updater(manifest);\n saveManifestUnlocked(manifest, baseDir);\n return result;\n });\n}\n\nfunction readManifestUnlocked(\n baseDir?: string,\n memoryDirOverride?: string,\n options: { bootstrapIfMissing?: boolean } = {}\n): SpaceManifest {\n const manifestPath = getManifestPath(baseDir);\n\n if (!fs.existsSync(manifestPath)) {\n if (options.bootstrapIfMissing === false) {\n const error = new Error(`Spaces manifest not found: ${manifestPath}`) as NodeJS.ErrnoException;\n error.code = \"ENOENT\";\n throw error;\n }\n const personalSpace = createPersonalSpace(baseDir, memoryDirOverride);\n return {\n activeSpaceId: personalSpace.id,\n spaces: [personalSpace],\n version: MANIFEST_VERSION,\n };\n }\n\n const raw = JSON.parse(fs.readFileSync(manifestPath, \"utf8\"));\n return raw as SpaceManifest;\n}\n\nfunction saveManifestUnlocked(manifest: SpaceManifest, baseDir?: string): void {\n const manifestPath = getManifestPath(baseDir);\n const manifestDir = path.dirname(manifestPath);\n fs.mkdirSync(manifestDir, { recursive: true });\n const tempPath = path.join(manifestDir, `.manifest.${process.pid}.${Date.now()}.${crypto.randomUUID()}.tmp`);\n try {\n fs.writeFileSync(tempPath, `${JSON.stringify(manifest, null, 2)}\\n`, { flag: \"wx\" });\n fs.renameSync(tempPath, manifestPath);\n } catch (error) {\n try {\n fs.rmSync(tempPath, { force: true });\n } catch {\n // Ignore cleanup failures; surface the original write/rename error.\n }\n throw error;\n }\n}\n\nfunction withManifestLock<T>(baseDir: string | undefined, operation: () => T): T {\n const lockDir = `${getManifestPath(baseDir)}.lock`;\n fs.mkdirSync(path.dirname(lockDir), { recursive: true });\n const lockOwner = acquireManifestLock(lockDir);\n try {\n return operation();\n } finally {\n releaseManifestLock(lockDir, lockOwner);\n }\n}\n\nfunction acquireManifestLock(lockDir: string): string {\n const deadline = Date.now() + MANIFEST_LOCK_TIMEOUT_MS;\n const owner = createManifestLockOwner();\n const reclaimDir = getManifestLockReclaimDir(lockDir);\n while (true) {\n if (fs.existsSync(reclaimDir)) {\n removeStaleManifestReclaimLock(reclaimDir);\n }\n if (fs.existsSync(reclaimDir)) {\n if (Date.now() >= deadline) {\n throw new Error(`Timed out waiting for spaces manifest reclaim lock: ${reclaimDir}`);\n }\n sleepSync(MANIFEST_LOCK_SLEEP_MS);\n continue;\n }\n\n try {\n fs.mkdirSync(lockDir, { recursive: false });\n try {\n fs.writeFileSync(path.join(lockDir, \"owner\"), `${owner}\\n`, { flag: \"wx\" });\n } catch (error) {\n fs.rmSync(lockDir, { recursive: true, force: true });\n throw error;\n }\n if (fs.existsSync(reclaimDir)) {\n releaseManifestLock(lockDir, owner);\n if (Date.now() >= deadline) {\n throw new Error(`Timed out waiting for spaces manifest reclaim lock: ${reclaimDir}`);\n }\n sleepSync(MANIFEST_LOCK_SLEEP_MS);\n continue;\n }\n return owner;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") {\n throw error;\n }\n\n removeStaleManifestLock(lockDir);\n if (Date.now() >= deadline) {\n throw new Error(`Timed out waiting for spaces manifest lock: ${lockDir}`);\n }\n sleepSync(MANIFEST_LOCK_SLEEP_MS);\n }\n }\n}\n\nfunction releaseManifestLock(lockDir: string, owner: string): void {\n try {\n const ownerPath = path.join(lockDir, \"owner\");\n if (fs.readFileSync(ownerPath, \"utf8\").trim() === owner) {\n fs.rmSync(lockDir, { recursive: true, force: true });\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n}\n\nfunction removeStaleManifestLock(lockDir: string): void {\n const reclaimDir = getManifestLockReclaimDir(lockDir);\n const reclaimOwner = createManifestLockOwner();\n try {\n fs.mkdirSync(reclaimDir, { recursive: false });\n try {\n fs.writeFileSync(path.join(reclaimDir, \"owner\"), `${reclaimOwner}\\n`, { flag: \"wx\" });\n } catch (error) {\n fs.rmSync(reclaimDir, { recursive: true, force: true });\n throw error;\n }\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EEXIST\") {\n return;\n }\n throw error;\n }\n\n try {\n const snapshot = readManifestLockSnapshot(lockDir);\n if (!snapshot || Date.now() - snapshot.mtimeMs <= MANIFEST_LOCK_STALE_MS) {\n return;\n }\n\n if (isManifestLockOwnerActive(snapshot.owner)) {\n return;\n }\n\n const tombstoneDir = `${lockDir}.stale.${process.pid}.${crypto.randomUUID()}`;\n try {\n fs.renameSync(lockDir, tombstoneDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n return;\n }\n fs.rmSync(tombstoneDir, { recursive: true, force: true });\n } finally {\n fs.rmSync(reclaimDir, { recursive: true, force: true });\n }\n}\n\nfunction getManifestLockReclaimDir(lockDir: string): string {\n return `${lockDir}.reclaim`;\n}\n\nfunction createManifestLockOwner(): string {\n return JSON.stringify({\n pid: process.pid,\n startKey: readProcessStartKey(process.pid),\n token: crypto.randomUUID(),\n });\n}\n\nfunction removeStaleManifestReclaimLock(reclaimDir: string): void {\n const snapshot = readManifestLockSnapshot(reclaimDir);\n if (!snapshot || Date.now() - snapshot.mtimeMs <= MANIFEST_LOCK_STALE_MS) {\n return;\n }\n\n if (isManifestLockOwnerActive(snapshot.owner)) {\n return;\n }\n\n const tombstoneDir = `${reclaimDir}.stale.${process.pid}.${crypto.randomUUID()}`;\n try {\n fs.renameSync(reclaimDir, tombstoneDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n return;\n }\n fs.rmSync(tombstoneDir, { recursive: true, force: true });\n}\n\nfunction readManifestLockSnapshot(lockDir: string): { mtimeMs: number; owner?: string } | undefined {\n let stat: fs.Stats;\n try {\n stat = fs.statSync(lockDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n throw error;\n }\n\n try {\n const owner = fs.readFileSync(path.join(lockDir, \"owner\"), \"utf8\").trim();\n return { mtimeMs: stat.mtimeMs, owner };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return { mtimeMs: stat.mtimeMs };\n }\n throw error;\n }\n}\n\nfunction isManifestLockOwnerActive(owner: string | undefined): boolean {\n if (!owner) {\n return false;\n }\n\n const parsed = parseManifestLockOwner(owner);\n if (!parsed) {\n return false;\n }\n\n const currentStartKey = readProcessStartKey(parsed.pid);\n if (currentStartKey && parsed.startKey) {\n return currentStartKey === parsed.startKey;\n }\n\n return isProcessAlive(parsed.pid);\n}\n\nfunction parseManifestLockOwner(owner: string): { pid: number; startKey?: string } | undefined {\n try {\n const parsed = JSON.parse(owner) as { pid?: unknown; startKey?: unknown };\n const pid = typeof parsed.pid === \"number\" ? parsed.pid : Number.NaN;\n if (Number.isInteger(pid) && pid > 0) {\n return {\n pid,\n startKey: typeof parsed.startKey === \"string\" && parsed.startKey.length > 0 ? parsed.startKey : undefined,\n };\n }\n } catch {\n // Fall through to legacy owner format.\n }\n\n const legacyPid = Number(owner.split(\":\", 1)[0]);\n return Number.isInteger(legacyPid) && legacyPid > 0 ? { pid: legacyPid } : undefined;\n}\n\nfunction readProcessStartKey(pid: number): string | undefined {\n if (!Number.isInteger(pid) || pid <= 0) {\n return undefined;\n }\n\n const result = spawnSync(\"ps\", [\"-p\", String(pid), \"-o\", \"lstart=\"], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n if (result.error || result.status !== 0 || typeof result.stdout !== \"string\") {\n return undefined;\n }\n const startKey = result.stdout.trim().replace(/\\s+/g, \" \");\n return startKey.length > 0 ? startKey : undefined;\n}\n\nfunction isProcessAlive(pid: number): boolean {\n if (pid === process.pid) {\n return true;\n }\n\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"ESRCH\") {\n return false;\n }\n return true;\n }\n}\n\nfunction sleepSync(ms: number): void {\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n}\n\nfunction createPersonalSpace(baseDir?: string, memoryDirOverride?: string): Space {\n const homeDir = baseDir ?? resolveHomeDir();\n // Priority: override > REMNIC_MEMORY_DIR > ENGRAM_MEMORY_DIR > existing standalone dir > existing OpenClaw dir > new standalone dir\n const standalonePath = path.join(homeDir, \".engram\", \"memory\");\n const openclawPath = path.join(homeDir, \".openclaw\", \"workspace\", \"memory\", \"local\");\n const memoryDir =\n memoryDirOverride ??\n readEnvVar(\"REMNIC_MEMORY_DIR\") ??\n readEnvVar(\"ENGRAM_MEMORY_DIR\") ??\n (fs.existsSync(standalonePath) ? standalonePath : fs.existsSync(openclawPath) ? openclawPath : standalonePath);\n const normalizedMemoryDir = normalizeSpaceMemoryDir(memoryDir);\n const now = new Date().toISOString();\n\n return {\n id: \"personal\",\n name: \"Personal\",\n kind: \"personal\",\n description: \"Default personal memory space\",\n memoryDir: normalizedMemoryDir,\n createdAt: now,\n updatedAt: now,\n owner: readEnvVar(\"USER\"),\n };\n}\n\n// ── Space CRUD ──────────────────────────────────────────────────────────────\n\nexport function listSpaces(baseDir?: string): Space[] {\n const manifest = loadManifest(baseDir);\n return manifest.spaces;\n}\n\nexport function getActiveSpace(baseDir?: string): Space {\n const manifest = loadManifest(baseDir);\n const space = manifest.spaces.find((s) => s.id === manifest.activeSpaceId);\n if (!space) throw new Error(`Active space ${manifest.activeSpaceId} not found`);\n return space;\n}\n\nexport function createSpace(options: {\n name: string;\n kind: SpaceKind;\n description?: string;\n memoryDir?: string;\n parentSpaceId?: string;\n baseDir?: string;\n}): Space {\n const id = options.name\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\")\n .replace(/-+/g, \"-\");\n const now = new Date().toISOString();\n const memoryDir = normalizeSpaceMemoryDir(\n options.memoryDir ?? path.join(getSpacesDir(options.baseDir), id, \"memory\")\n );\n\n const space = updateManifest(options.baseDir, (manifest) => {\n if (manifest.spaces.some((s) => s.id === id)) {\n throw new Error(`Space \"${id}\" already exists`);\n }\n\n // Validate parent space exists\n if (options.parentSpaceId && !manifest.spaces.some((s) => s.id === options.parentSpaceId)) {\n throw new Error(`Parent space \"${options.parentSpaceId}\" not found`);\n }\n\n const created: Space = {\n id,\n name: options.name,\n kind: options.kind,\n description: options.description,\n memoryDir,\n createdAt: now,\n updatedAt: now,\n owner: readEnvVar(\"USER\"),\n parentSpaceId: options.parentSpaceId,\n };\n\n // Ensure memory directory exists before publishing the manifest entry.\n fs.mkdirSync(memoryDir, { recursive: true });\n\n manifest.spaces.push(created);\n manifest.updatedAt = now;\n return created;\n });\n\n // Audit\n appendAudit(\n {\n action: \"space.create\",\n sourceSpaceId: id,\n details: `Created ${options.kind} space \"${options.name}\"`,\n },\n options.baseDir\n );\n\n return space;\n}\n\nexport function deleteSpace(spaceId: string, baseDir?: string): void {\n if (spaceId === \"personal\") {\n throw new Error(\"Cannot delete the personal space\");\n }\n\n updateManifest(baseDir, (manifest) => {\n const idx = manifest.spaces.findIndex((s) => s.id === spaceId);\n if (idx === -1) throw new Error(`Space \"${spaceId}\" not found`);\n\n // If deleting active space, switch to personal\n if (manifest.activeSpaceId === spaceId) {\n manifest.activeSpaceId = \"personal\";\n }\n\n // Clear parentSpaceId references from children\n for (const space of manifest.spaces) {\n if (space.parentSpaceId === spaceId) {\n space.parentSpaceId = undefined;\n }\n }\n\n manifest.spaces.splice(idx, 1);\n });\n\n appendAudit(\n {\n action: \"space.delete\",\n sourceSpaceId: spaceId,\n details: `Deleted space \"${spaceId}\"`,\n },\n baseDir\n );\n}\n\n// ── Switch ───────────────────────────────────────────────────────────────────\n\nexport function switchSpace(spaceId: string, baseDir?: string): SpaceSwitchResult {\n const { previousId, spaceName } = updateManifest(baseDir, (manifest) => {\n const space = manifest.spaces.find((s) => s.id === spaceId);\n if (!space) throw new Error(`Space \"${spaceId}\" not found`);\n const previousId = manifest.activeSpaceId;\n manifest.activeSpaceId = spaceId;\n return { previousId, spaceName: space.name };\n });\n\n appendAudit(\n {\n action: \"space.switch\",\n sourceSpaceId: previousId,\n targetSpaceId: spaceId,\n details: `Switched from \"${previousId}\" to \"${spaceId}\"`,\n },\n baseDir\n );\n\n return {\n previousSpaceId: previousId,\n currentSpaceId: spaceId,\n message: `Switched to \"${spaceName}\"`,\n };\n}\n\n// ── Push / Pull ─────────────────────────────────────────────────────────────\n\nexport function pushToSpace(\n sourceSpaceId: string,\n targetSpaceId: string,\n options?: { memoryIds?: string[]; force?: boolean; baseDir?: string }\n): SpacePushResult {\n const startTime = Date.now();\n const manifest = loadManifest(options?.baseDir);\n\n const source = manifest.spaces.find((s) => s.id === sourceSpaceId);\n const target = manifest.spaces.find((s) => s.id === targetSpaceId);\n\n if (!source) throw new Error(`Source space \"${sourceSpaceId}\" not found`);\n if (!target) throw new Error(`Target space \"${targetSpaceId}\" not found`);\n\n const result = copyMemories(source.memoryDir, target.memoryDir, {\n filterIds: options?.memoryIds,\n force: options?.force,\n });\n\n appendAudit(\n {\n action: \"space.push\",\n sourceSpaceId,\n targetSpaceId,\n details: `Pushed ${result.merged} memories, ${result.conflicts.length} conflicts`,\n },\n options?.baseDir\n );\n\n return {\n sourceSpaceId,\n targetSpaceId,\n memoriesPushed: result.merged,\n conflicts: result.conflicts,\n durationMs: Date.now() - startTime,\n };\n}\n\nexport function pullFromSpace(\n sourceSpaceId: string,\n targetSpaceId: string,\n options?: { memoryIds?: string[]; force?: boolean; baseDir?: string }\n): SpacePullResult {\n const startTime = Date.now();\n const manifest = loadManifest(options?.baseDir);\n\n const source = manifest.spaces.find((s) => s.id === sourceSpaceId);\n const target = manifest.spaces.find((s) => s.id === targetSpaceId);\n\n if (!source) throw new Error(`Source space \"${sourceSpaceId}\" not found`);\n if (!target) throw new Error(`Target space \"${targetSpaceId}\" not found`);\n\n const result = copyMemories(source.memoryDir, target.memoryDir, {\n filterIds: options?.memoryIds,\n force: options?.force,\n });\n\n appendAudit(\n {\n action: \"space.pull\",\n sourceSpaceId,\n targetSpaceId,\n details: `Pulled ${result.merged} memories, ${result.conflicts.length} conflicts`,\n },\n options?.baseDir\n );\n\n return {\n sourceSpaceId,\n targetSpaceId,\n memoriesPulled: result.merged,\n conflicts: result.conflicts,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Share ────────────────────────────────────────────────────────────────────\n\nexport function shareSpace(spaceId: string, members: string[], baseDir?: string): SpaceShareResult {\n const spaceName = updateManifest(baseDir, (manifest) => {\n const space = manifest.spaces.find((s) => s.id === spaceId);\n if (!space) throw new Error(`Space \"${spaceId}\" not found`);\n if (space.kind === \"personal\") throw new Error(\"Cannot share personal space\");\n\n space.members = [...new Set([...(space.members ?? []), ...members])];\n space.updatedAt = new Date().toISOString();\n return space.name;\n });\n\n appendAudit(\n {\n action: \"space.share\",\n sourceSpaceId: spaceId,\n details: `Shared with: ${members.join(\", \")}`,\n },\n baseDir\n );\n\n return {\n spaceId,\n sharedWith: members,\n message: `Shared \"${spaceName}\" with ${members.length} member(s)`,\n };\n}\n\n// ── Promote ──────────────────────────────────────────────────────────────────\n\nexport function promoteSpace(\n sourceSpaceId: string,\n targetSpaceId: string,\n options?: { memoryIds?: string[]; force?: boolean; forceOverwrite?: boolean; baseDir?: string }\n): SpacePromoteResult {\n const startTime = Date.now();\n const manifest = loadManifest(options?.baseDir);\n\n const source = manifest.spaces.find((s) => s.id === sourceSpaceId);\n const target = manifest.spaces.find((s) => s.id === targetSpaceId);\n\n if (!source) throw new Error(`Source space \"${sourceSpaceId}\" not found`);\n if (!target) throw new Error(`Target space \"${targetSpaceId}\" not found`);\n\n // Promotion requires parent-child relationship or explicit force\n if (source.parentSpaceId !== targetSpaceId && target.parentSpaceId !== sourceSpaceId) {\n if (!options?.force) {\n throw new Error(\"Spaces must have a parent-child relationship for promotion. Use --force to override.\");\n }\n }\n\n const result = copyMemories(source.memoryDir, target.memoryDir, {\n filterIds: options?.memoryIds,\n force: options?.forceOverwrite !== undefined ? options.forceOverwrite : (options?.force ?? false),\n });\n\n appendAudit(\n {\n action: \"space.promote\",\n sourceSpaceId,\n targetSpaceId,\n details: `Promoted ${result.merged} memories from \"${source.name}\" to \"${target.name}\"`,\n },\n options?.baseDir\n );\n\n return {\n sourceSpaceId,\n targetSpaceId,\n memoriesPromoted: result.merged,\n conflicts: result.conflicts,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Merge ────────────────────────────────────────────────────────────────────\n\nexport function mergeSpaces(\n sourceSpaceId: string,\n targetSpaceId: string,\n options?: { force?: boolean; baseDir?: string }\n): MergeResult {\n const startTime = Date.now();\n const manifest = loadManifest(options?.baseDir);\n\n const source = manifest.spaces.find((s) => s.id === sourceSpaceId);\n const target = manifest.spaces.find((s) => s.id === targetSpaceId);\n\n if (!source) throw new Error(`Source space \"${sourceSpaceId}\" not found`);\n if (!target) throw new Error(`Target space \"${targetSpaceId}\" not found`);\n\n const result = copyMemories(source.memoryDir, target.memoryDir, {\n force: options?.force,\n });\n\n appendAudit(\n {\n action: \"space.merge\",\n sourceSpaceId,\n targetSpaceId,\n details: `Merged: ${result.merged} merged, ${result.conflicts.length} conflicts, ${result.skipped} skipped`,\n },\n options?.baseDir\n );\n\n return {\n ...result,\n durationMs: Date.now() - startTime,\n };\n}\n\n// ── Audit trail ─────────────────────────────────────────────────────────────\n\nexport function getAuditLog(baseDir?: string): AuditEntry[] {\n const auditPath = path.join(getSpacesDir(baseDir), \"audit.jsonl\");\n if (!fs.existsSync(auditPath)) return [];\n\n const lines = fs.readFileSync(auditPath, \"utf8\").trim().split(\"\\n\");\n return lines.filter((l) => l.trim()).map((l) => JSON.parse(l) as AuditEntry);\n}\n\nfunction appendAudit(entry: Omit<AuditEntry, \"id\" | \"timestamp\">, baseDir?: string): void {\n const auditPath = path.join(getSpacesDir(baseDir), \"audit.jsonl\");\n fs.mkdirSync(path.dirname(auditPath), { recursive: true });\n\n const full: AuditEntry = {\n id: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n ...entry,\n };\n\n fs.appendFileSync(auditPath, `${JSON.stringify(full)}\\n`);\n}\n\n// ── Internal helpers ─────────────────────────────────────────────────────────\n\ninterface CopyOptions {\n filterIds?: string[];\n force?: boolean;\n}\n\nfunction copyMemories(\n sourceDir: string,\n targetDir: string,\n options?: CopyOptions\n): { merged: number; conflicts: ConflictEntry[]; skipped: number } {\n let merged = 0;\n const conflicts: ConflictEntry[] = [];\n let skipped = 0;\n\n if (!fs.existsSync(sourceDir)) {\n return { merged: 0, conflicts: [], skipped: 0 };\n }\n\n const sourceRoot = fs.realpathSync(sourceDir);\n fs.mkdirSync(targetDir, { recursive: true });\n const targetRoot = fs.realpathSync(targetDir);\n\n const sourceFiles = walkMd(sourceRoot);\n for (const sourcePath of sourceFiles) {\n const sourceRealPath = safeRealpath(sourcePath);\n if (!sourceRealPath || !isPathInsideRoot(sourceRealPath, sourceRoot)) {\n skipped++;\n continue;\n }\n const sourceStat = safeLstat(sourcePath);\n if (!sourceStat?.isFile()) {\n skipped++;\n continue;\n }\n const content = fs.readFileSync(sourcePath, \"utf8\");\n const relativePath = path.relative(sourceRoot, sourceRealPath);\n const targetPath = path.resolve(targetRoot, relativePath);\n if (!isPathInsideRoot(targetPath, targetRoot)) {\n skipped++;\n continue;\n }\n\n const sourceHash = hashContent(content);\n\n // Filter by IDs if specified\n if (options?.filterIds?.length) {\n const fm = parseSimpleFrontmatter(content);\n if (!fm?.id || !options.filterIds.includes(fm.id)) {\n skipped++;\n continue;\n }\n }\n\n // Check for conflict\n if (fs.existsSync(targetPath)) {\n const targetStat = safeLstat(targetPath);\n if (!targetStat?.isFile() || targetStat.isSymbolicLink()) {\n skipped++;\n continue;\n }\n const targetRealPath = safeRealpath(targetPath);\n if (!targetRealPath || !isPathInsideRoot(targetRealPath, targetRoot)) {\n skipped++;\n continue;\n }\n }\n\n if (fs.existsSync(targetPath) && !options?.force) {\n const targetContent = fs.readFileSync(targetPath, \"utf8\");\n const targetHash = hashContent(targetContent);\n\n if (sourceHash !== targetHash) {\n conflicts.push({\n memoryId: parseSimpleFrontmatter(content)?.id ?? relativePath,\n sourcePath,\n targetPath,\n conflictType: \"content_mismatch\",\n sourceHash,\n targetHash,\n });\n continue;\n }\n\n // Same content — skip\n skipped++;\n continue;\n }\n\n // Copy file\n fs.mkdirSync(path.dirname(targetPath), { recursive: true });\n const targetParentRealPath = safeRealpath(path.dirname(targetPath));\n if (!targetParentRealPath || !isPathInsideRoot(targetParentRealPath, targetRoot)) {\n skipped++;\n continue;\n }\n fs.writeFileSync(targetPath, content);\n merged++;\n }\n\n return { merged, conflicts, skipped };\n}\n\nfunction hashContent(content: string): string {\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\nfunction walkMd(dir: string): string[] {\n const results: string[] = [];\n\n function walk(d: string): void {\n for (const entry of fs.readdirSync(d, { withFileTypes: true })) {\n const fullPath = path.join(d, entry.name);\n if (entry.isSymbolicLink()) {\n continue;\n }\n if (entry.isDirectory()) {\n walk(fullPath);\n } else if (entry.name.endsWith(\".md\")) {\n results.push(fullPath);\n }\n }\n }\n\n walk(dir);\n return results;\n}\n\nfunction safeLstat(filePath: string): fs.Stats | null {\n try {\n return fs.lstatSync(filePath);\n } catch {\n return null;\n }\n}\n\nfunction safeRealpath(filePath: string): string | null {\n try {\n return fs.realpathSync(filePath);\n } catch {\n return null;\n }\n}\n\nfunction isPathInsideRoot(candidatePath: string, rootPath: string): boolean {\n const relative = path.relative(rootPath, candidatePath);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\ninterface SimpleFrontmatter {\n id?: string;\n [key: string]: string | undefined;\n}\n\nfunction parseSimpleFrontmatter(content: string): SimpleFrontmatter | null {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!match) return null;\n\n const fm: SimpleFrontmatter = {};\n for (const line of match[1].split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n fm[key] = value;\n }\n return fm;\n}\n","/**\n * @remnic/core — Shared Instruction Blocks\n *\n * Reusable markdown fragments that every host-specific publisher can\n * compose into its instructions.md file. Keeping them here avoids\n * per-host copy-paste drift.\n */\n\n/**\n * Describes the Remnic memory types a host agent may encounter.\n */\nexport const REMNIC_SEMANTIC_OVERVIEW = `\\\n## Remnic Memory Types\n\nRemnic stores memories as plain Markdown files with YAML front-matter.\nEach memory has a **type** that describes its semantic role:\n\n| Type | Description |\n|------|-------------|\n| \\`fact\\` | An objective piece of knowledge the user confirmed or that was extracted from a session. |\n| \\`preference\\` | A stated or inferred user preference (e.g. coding style, tool choice). |\n| \\`decision\\` | An explicit decision or trade-off the user made. |\n| \\`entity\\` | A named thing the user cares about (project, service, person, API). |\n| \\`skill\\` | A reusable workflow or procedure documented for future sessions. |\n| \\`correction\\` | A fix or amendment to a previously stored memory. |\n| \\`question\\` | An open question or uncertainty flagged for future resolution. |\n| \\`observation\\` | A pattern noticed across sessions (e.g. \"user always runs tests before commits\"). |\n| \\`summary\\` | A condensed roll-up of recent sessions or a topic area. |\n\nWhen reading Remnic content, the front-matter \\`type\\` field tells you what\nkind of knowledge you are looking at and how much weight to give it.\n`;\n\n/**\n * Explains the oai-mem-citation block format hosts should use when\n * referencing Remnic-sourced content.\n */\nexport const REMNIC_CITATION_FORMAT = `\\\n## Citing Remnic Memories\n\nWhen a piece of your output draws on a Remnic file, cite it using the\nmemory citation block format so the user can trace the source:\n\n\\`\\`\\`\n<oai-mem-citation path=\"<path-relative-to-remnic-memory-base>\" />\n\\`\\`\\`\n\nThe path must be **relative to the Remnic memory base** (the directory\nnamed \\`memories/\\` under \\`<remnic-home>\\`), not absolute. Examples:\n\n- \\`<oai-mem-citation path=\"default/MEMORY.md\" />\\`\n- \\`<oai-mem-citation path=\"my-project/skills/deploy/SKILL.md\" />\\`\n- \\`<oai-mem-citation path=\"shared/memory_summary.md\" />\\`\n\nCite each distinct source once near the fact it supports. Do not invent\ncitations for files you have not actually read.\n`;\n\n/**\n * Table of MCP tools the Remnic daemon exposes. Hosts that can reach\n * the MCP server should prefer these over raw file reads.\n *\n * Tool names use the canonical `remnic.*` prefix. Legacy `engram.*`\n * aliases are also accepted by the server for backward compatibility.\n */\nexport const REMNIC_MCP_TOOL_INVENTORY = `\\\n## Remnic MCP Tools\n\nWhen the Remnic MCP server is reachable, the following tools are\navailable. Prefer MCP tools over direct file reads when the host\nsupports MCP connections.\n\n| Tool | Purpose |\n|------|---------|\n| \\`remnic.recall\\` | Retrieve contextually relevant memories for the current session. |\n| \\`remnic.recall_explain\\` | Like recall, but includes an explanation of why each memory was selected. |\n| \\`remnic.memory_store\\` | Persist a new memory (fact, preference, decision, etc.). |\n| \\`remnic.memory_get\\` | Fetch a specific memory by ID. |\n| \\`remnic.memory_search\\` | Full-text + semantic search across all memories. |\n| \\`remnic.memory_timeline\\` | Retrieve memories in chronological order within a time range. |\n| \\`remnic.observe\\` | Record an observation from the current conversation turn. |\n| \\`remnic.entity_get\\` | Look up a named entity and its relationships. |\n| \\`remnic.memory_entities_list\\` | List all known entities. |\n| \\`remnic.memory_profile\\` | Retrieve the user profile summary. |\n| \\`remnic.day_summary\\` | Generate a summary of memories from a specific day. |\n| \\`remnic.briefing\\` | Generate a structured briefing for an upcoming session. |\n| \\`remnic.memory_feedback\\` | Submit feedback on a recalled memory (useful, outdated, wrong). |\n| \\`remnic.memory_promote\\` | Promote a memory to a higher confidence tier. |\n| \\`remnic.context_checkpoint\\` | Save a conversation checkpoint for continuity. |\n| \\`remnic.suggestion_submit\\` | Submit a suggestion for a new memory to the review queue. |\n| \\`remnic.review_queue_list\\` | List pending suggestions in the review queue. |\n| \\`remnic.work_task\\` | Create or update a work task. |\n| \\`remnic.work_project\\` | Create or update a work project. |\n| \\`remnic.work_board\\` | View the work board. |\n\nLegacy \\`engram.*\\` prefixed names are accepted as aliases for all tools.\n`;\n\n/**\n * Decision rules for when a host agent should use MCP recall vs\n * reading Remnic files directly from disk.\n */\nexport const REMNIC_RECALL_DECISION_RULES = `\\\n## When to Use Recall vs Direct Read\n\n### Use \\`remnic.recall\\` (MCP) when:\n\n- The Remnic MCP server is reachable (the host has an active MCP\n connection to the Remnic daemon).\n- You want contextually relevant memories ranked by the recall planner\n (semantic search + reranking + importance scoring).\n- You need memories across multiple namespaces or topics.\n- The conversation benefits from Remnic's intent detection and\n adaptive recall depth.\n\n### Use direct file reads when:\n\n- You are in a sandboxed environment with no network or MCP access\n (e.g. Codex phase-2 consolidation).\n- You need a specific file you already know the path to.\n- The MCP server is unavailable or unhealthy.\n- You are operating on the raw memory files for maintenance or\n migration purposes.\n\n### General guidance:\n\n- Prefer MCP tools when available — they provide ranked, deduplicated,\n and context-aware results.\n- Fall back to file reads gracefully — never block on a failed MCP call\n when the data is also on disk.\n- Never write directly to the Remnic memory directory unless you are an\n authorized extraction or consolidation process.\n`;\n","/**\n * @remnic/core — Codex Memory Extension Publisher\n *\n * Writes Remnic instructions into ~/.codex/memories_extensions/remnic/\n * so the Codex agent can discover and use Remnic memories during its\n * consolidation phase.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nimport type {\n MemoryExtensionPublisher,\n PublishContext,\n PublishResult,\n PublisherCapabilities,\n} from \"./types.js\";\n\nimport {\n REMNIC_SEMANTIC_OVERVIEW,\n REMNIC_CITATION_FORMAT,\n REMNIC_MCP_TOOL_INVENTORY,\n REMNIC_RECALL_DECISION_RULES,\n} from \"./shared-instructions.js\";\nimport { readEnvVar, resolveHomeDir } from \"../runtime/env.js\";\n\n/** Folder name Remnic installs its extension under inside memories_extensions/. */\nconst REMNIC_EXTENSION_DIR_NAME = \"remnic\";\n\nfunction resolveEnvHome(env?: NodeJS.ProcessEnv): string {\n if (env === undefined) return resolveHomeDir();\n return env.HOME?.trim() || env.USERPROFILE?.trim() || os.homedir();\n}\n\nfunction expandTildeWithHome(input: string, homeDir: string): string {\n if (input === \"~\") return homeDir;\n if (input.startsWith(\"~/\") || input.startsWith(\"~\\\\\")) {\n return path.join(homeDir, input.slice(2));\n }\n return input;\n}\n\nfunction normalizeHostRoot(input: string, homeDir: string): string {\n return path.resolve(expandTildeWithHome(input.trim(), homeDir));\n}\n\n/**\n * Codex-specific publisher that knows the Codex extension layout:\n * ~/.codex/memories_extensions/remnic/instructions.md\n */\nexport class CodexMemoryExtensionPublisher implements MemoryExtensionPublisher {\n readonly hostId = \"codex\";\n\n static readonly capabilities: PublisherCapabilities = {\n instructionsMd: true,\n skillsFolder: false,\n citationFormat: true,\n readPathTemplate: true,\n };\n\n async resolveExtensionRoot(\n env?: NodeJS.ProcessEnv,\n ): Promise<string> {\n const homeDir = resolveEnvHome(env);\n const codexHomeInput = env === undefined\n ? readEnvVar(\"CODEX_HOME\")?.trim()\n : env.CODEX_HOME?.trim();\n const codexHome = codexHomeInput\n ? normalizeHostRoot(codexHomeInput, homeDir)\n : path.resolve(homeDir, \".codex\");\n return path.join(codexHome, \"memories_extensions\", REMNIC_EXTENSION_DIR_NAME);\n }\n\n async isHostAvailable(): Promise<boolean> {\n try {\n const home = readEnvVar(\"CODEX_HOME\")?.trim() ||\n path.join(resolveHomeDir(), \".codex\");\n return fs.existsSync(home);\n } catch {\n return false;\n }\n }\n\n async renderInstructions(ctx: PublishContext): Promise<string> {\n const memDir = ctx.config.memoryDir;\n const ns = ctx.config.namespace ?? \"default\";\n\n const sections: string[] = [\n `# Remnic Memory Extension for Codex\\n`,\n `This document tells you how to use Remnic as an authoritative local ` +\n `memory source. Remnic is a local-first, file-backed memory system. ` +\n `All Remnic content lives on disk as plain Markdown.\\n`,\n REMNIC_SEMANTIC_OVERVIEW,\n `## Where Remnic Content Lives\\n\\n` +\n `Memory base directory: \\`${memDir}\\`\\n\\n` +\n `Namespace: \\`${ns}\\`\\n\\n` +\n `Under the base directory, memories are organized by namespace:\\n\\n` +\n \"```\\n\" +\n `${memDir}/<namespace>/\\n` +\n ` MEMORY.md # compact top-of-mind memory\\n` +\n ` memory_summary.md # optional longer summary\\n` +\n ` skills/\\n` +\n ` <skill-name>/SKILL.md # reusable workflows\\n` +\n ` rollout_summaries/\\n` +\n ` *.md # per-session rollup notes\\n` +\n \"```\\n\",\n REMNIC_CITATION_FORMAT,\n REMNIC_MCP_TOOL_INVENTORY,\n REMNIC_RECALL_DECISION_RULES,\n `## Sandboxing Rules (Codex Phase-2)\\n\\n` +\n `When running inside the Codex phase-2 consolidation sandbox:\\n\\n` +\n `- **No network.** Do not attempt HTTP calls or MCP connections.\\n` +\n `- **No CLI invocation.** Do not shell out to \\`remnic\\` or \\`engram\\`.\\n` +\n `- **No MCP tool calls.** Use filesystem reads only.\\n` +\n `- **Local writes** are allowed only where Codex's sandbox policy permits.\\n` +\n `- **Respect missing files.** If a file does not exist, move on silently.\\n`,\n ];\n\n return sections.join(\"\\n\");\n }\n\n async publish(ctx: PublishContext): Promise<PublishResult> {\n const extensionRoot = await this.resolveExtensionRoot();\n const instructionsPath = path.join(extensionRoot, \"instructions.md\");\n const filesWritten: string[] = [];\n const skipped: string[] = [];\n\n ctx.log.info(`Publishing Codex memory extension to ${extensionRoot}`);\n\n // Ensure the extension root exists.\n fs.mkdirSync(extensionRoot, { recursive: true });\n\n // Render and write instructions.md using atomic write (temp + rename).\n // Per CLAUDE.md #54: never delete before write in file replace operations.\n const content = await this.renderInstructions(ctx);\n const tmpPath = `${instructionsPath}.tmp-${process.pid}-${Date.now()}`;\n\n try {\n fs.writeFileSync(tmpPath, content, \"utf-8\");\n fs.renameSync(tmpPath, instructionsPath);\n filesWritten.push(instructionsPath);\n ctx.log.info(`Wrote ${instructionsPath}`);\n } catch (err) {\n // Clean up temp file on failure.\n try {\n if (fs.existsSync(tmpPath)) {\n fs.unlinkSync(tmpPath);\n }\n } catch {\n // swallow cleanup error\n }\n throw err;\n }\n\n return {\n hostId: this.hostId,\n extensionRoot,\n filesWritten,\n skipped,\n };\n }\n\n async unpublish(): Promise<void> {\n const extensionRoot = await this.resolveExtensionRoot();\n if (fs.existsSync(extensionRoot)) {\n fs.rmSync(extensionRoot, { recursive: true, force: true });\n }\n }\n}\n","/**\n * @remnic/core — Claude Code Memory Extension Publisher (stub)\n *\n * Placeholder publisher for Claude Code. Claude Code does not yet\n * support a file-based memory extension directory, so all methods are\n * no-ops that return safe defaults.\n */\n\nimport type {\n MemoryExtensionPublisher,\n PublishContext,\n PublishResult,\n PublisherCapabilities,\n} from \"./types.js\";\n\nexport class ClaudeCodeMemoryExtensionPublisher implements MemoryExtensionPublisher {\n readonly hostId = \"claude-code\";\n\n static readonly capabilities: PublisherCapabilities = {\n instructionsMd: false,\n skillsFolder: false,\n citationFormat: false,\n readPathTemplate: false,\n };\n\n async resolveExtensionRoot(): Promise<string> {\n // Claude Code does not have an extension directory yet.\n return \"\";\n }\n\n async isHostAvailable(): Promise<boolean> {\n return false;\n }\n\n async renderInstructions(_ctx: PublishContext): Promise<string> {\n return \"\";\n }\n\n async publish(_ctx: PublishContext): Promise<PublishResult> {\n return {\n hostId: this.hostId,\n extensionRoot: \"\",\n filesWritten: [],\n skipped: [],\n };\n }\n\n async unpublish(): Promise<void> {\n // no-op\n }\n}\n","/**\n * @remnic/core — Hermes Memory Extension Publisher (stub)\n *\n * Placeholder publisher for Hermes. Hermes uses a daemon-based\n * transport and does not currently consume file-based memory\n * extensions, so all methods are no-ops.\n */\n\nimport type {\n MemoryExtensionPublisher,\n PublishContext,\n PublishResult,\n PublisherCapabilities,\n} from \"./types.js\";\n\nexport class HermesMemoryExtensionPublisher implements MemoryExtensionPublisher {\n readonly hostId = \"hermes\";\n\n static readonly capabilities: PublisherCapabilities = {\n instructionsMd: false,\n skillsFolder: false,\n citationFormat: false,\n readPathTemplate: false,\n };\n\n async resolveExtensionRoot(): Promise<string> {\n // Hermes does not have an extension directory.\n return \"\";\n }\n\n async isHostAvailable(): Promise<boolean> {\n return false;\n }\n\n async renderInstructions(_ctx: PublishContext): Promise<string> {\n return \"\";\n }\n\n async publish(_ctx: PublishContext): Promise<PublishResult> {\n return {\n hostId: this.hostId,\n extensionRoot: \"\",\n filesWritten: [],\n skipped: [],\n };\n }\n\n async unpublish(): Promise<void> {\n // no-op\n }\n}\n","/**\n * @remnic/core — Memory Extension Publisher Registry\n *\n * Generic registry that host adapters populate at startup via\n * `registerPublisher()`. The publisher *classes* live in core so\n * adapters can import them, but the wiring of host-specific\n * implementations into the registry happens in the host adapter\n * layer (e.g. @remnic/cli), not here. This keeps core free of\n * host-specific knowledge (CLAUDE.md gotcha #31).\n *\n * Usage (from a host adapter):\n * import { registerPublisher, CodexMemoryExtensionPublisher } from \"@remnic/core\";\n * registerPublisher(\"codex\", () => new CodexMemoryExtensionPublisher());\n */\n\nexport type {\n MemoryExtensionPublisher,\n PublishContext,\n PublishResult,\n PublisherCapabilities,\n} from \"./types.js\";\n\nexport {\n REMNIC_SEMANTIC_OVERVIEW,\n REMNIC_CITATION_FORMAT,\n REMNIC_MCP_TOOL_INVENTORY,\n REMNIC_RECALL_DECISION_RULES,\n} from \"./shared-instructions.js\";\n\nexport { CodexMemoryExtensionPublisher } from \"./codex-publisher.js\";\nexport { ClaudeCodeMemoryExtensionPublisher } from \"./claude-code-publisher.js\";\nexport { HermesMemoryExtensionPublisher } from \"./hermes-publisher.js\";\n\nimport type { MemoryExtensionPublisher } from \"./types.js\";\n\n/**\n * Factory registry keyed by host ID. Each value is a zero-argument\n * factory that returns a fresh publisher instance.\n *\n * Starts empty — host adapters populate it via registerPublisher().\n */\nexport const PUBLISHERS: Record<string, () => MemoryExtensionPublisher> = {};\n\n/**\n * Register a publisher factory for a given host ID.\n *\n * Host adapters call this at startup to wire their host-specific\n * publisher implementations into the registry. Calling with an\n * existing hostId replaces the previous factory.\n */\nexport function registerPublisher(\n hostId: string,\n factory: () => MemoryExtensionPublisher,\n): void {\n PUBLISHERS[hostId] = factory;\n}\n\n/**\n * Maps connector IDs to publisher host IDs.\n *\n * Most connector IDs match their publisher host ID exactly (e.g.\n * \"claude-code\" -> \"claude-code\", \"hermes\" -> \"hermes\").\n * This map only needs entries for connector IDs that differ from\n * their publisher host ID. Connectors without a publisher (e.g.\n * \"cursor\", \"cline\") are intentionally absent.\n */\nconst CONNECTOR_TO_HOST: Record<string, string> = {\n \"codex-cli\": \"codex\",\n};\n\n/**\n * Resolve a connector ID to its publisher host ID.\n *\n * Returns the explicit mapping if one exists, otherwise returns\n * the connector ID itself (identity mapping covers the common case\n * where connector ID === host ID).\n */\nexport function hostIdForConnector(connectorId: string): string {\n return CONNECTOR_TO_HOST[connectorId] ?? connectorId;\n}\n\n/**\n * Look up a publisher by host ID.\n * Returns undefined for unknown host IDs rather than throwing.\n */\nexport function publisherFor(hostId: string): MemoryExtensionPublisher | undefined {\n const factory = PUBLISHERS[hostId];\n return factory ? factory() : undefined;\n}\n\n/**\n * Look up a publisher by connector ID.\n *\n * Resolves the connector ID to its host ID first (e.g. \"codex-cli\" -> \"codex\"),\n * then looks up the publisher. Returns undefined if no publisher exists for\n * the resolved host ID.\n */\nexport function publisherForConnector(connectorId: string): MemoryExtensionPublisher | undefined {\n return publisherFor(hostIdForConnector(connectorId));\n}\n","/**\n * Capsule fork semantics — issue #676 PR 4/6.\n *\n * A fork takes an existing capsule archive, imports it into a target memory\n * root under the `fork` conflict-resolution mode (which rebases all records\n * under `forks/<capsule-id>/`), and then writes a lineage breadcrumb at\n * `<targetRoot>/forks/<forkId>/lineage.json` recording the parent capsule's\n * identity. Subsequent forks of the same parent or of a fork produce a\n * queryable chain.\n *\n * The lineage breadcrumb is a pure JSON file — no gzip, no bundle format —\n * so downstream tooling can read it with a single `readFile` + `JSON.parse`\n * without pulling in the transfer pipeline.\n */\n\nimport { lstat, mkdir, readFile, realpath, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { importCapsule, type ImportCapsuleResult } from \"./capsule-import.js\";\nimport { assertIsDirectoryNotSymlink, assertRealpathInsideRoot } from \"./fs-utils.js\";\nimport type { CapsuleParent, ExportManifestV2 } from \"./types.js\";\nimport { CAPSULE_ID_PATTERN } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Options accepted by {@link forkCapsule}.\n *\n * `sourceArchive` — absolute or cwd-relative path to a `.capsule.json.gz`\n * archive produced by `exportCapsule`.\n *\n * `targetRoot` — absolute or cwd-relative path to the memory directory that\n * will receive the forked records. Must be an existing directory.\n *\n * `forkId` — user-chosen id for the fork. Validated against\n * {@link CAPSULE_ID_PATTERN}; must be unique under `<targetRoot>/forks/` (a\n * pre-existing `forks/<forkId>/` directory is rejected before any write).\n *\n * `versioning` — optional page-versioning config forwarded to\n * {@link importCapsule}. Only relevant when the target root already has files\n * that would be overwritten (fork mode is skip-on-exist by design, so this is\n * a no-op unless mode is changed in a future subclass).\n *\n * `now` — optional clock override (ms epoch) forwarded to `importCapsule` for\n * deterministic fork-id rewriting in tests.\n */\nexport interface ForkCapsuleOptions {\n sourceArchive: string;\n targetRoot: string;\n forkId: string;\n now?: number;\n}\n\n/**\n * The lineage breadcrumb written to `forks/<forkId>/lineage.json`.\n *\n * Fields are intentionally flat so the file is human-readable at a glance\n * and trivially diffable by `git diff`.\n *\n * `forkId` — the id supplied to `forkCapsule`.\n * `forkedAt` — ISO-8601 creation timestamp (UTC).\n * `parent` — structured linkage to the source capsule.\n * `importedRecords` — number of records written by the fork import.\n * `skippedRecords` — number of records skipped (target already existed).\n */\nexport interface ForkLineage {\n forkId: string;\n forkedAt: string;\n parent: CapsuleParent;\n importedRecords: number;\n skippedRecords: number;\n}\n\nexport interface ForkCapsuleResult {\n /** Absolute path to the source archive (unchanged, for chaining). */\n archivePath: string;\n /** The V2 manifest decoded from the source archive. */\n manifest: ExportManifestV2;\n /** Result of the underlying `importCapsule` call. */\n importResult: ImportCapsuleResult;\n /** The lineage breadcrumb that was written. */\n lineage: ForkLineage;\n /** Absolute path to the lineage breadcrumb file. */\n lineagePath: string;\n}\n\n// ---------------------------------------------------------------------------\n// Main function\n// ---------------------------------------------------------------------------\n\n/**\n * Fork a capsule archive into a target memory root.\n *\n * Sequence:\n * 1. Validate `forkId` against {@link CAPSULE_ID_PATTERN}.\n * 2. Resolve `targetRoot` and verify it is an existing directory (not a\n * symlink — mirrors {@link importCapsule}'s root validation).\n * 3. Reject if `forks/<forkId>/` already exists in the target root\n * (gotcha #49: deduplicate batch inputs; gotcha #25: don't destroy\n * old state).\n * 4. Import the archive in `\"fork\"` mode via {@link importCapsule}.\n * 5. Write the lineage breadcrumb at `forks/<forkId>/lineage.json`.\n * The breadcrumb dir is created by step 4 (importCapsule writes records\n * under `forks/<sourceId>/`); if `forkId !== sourceId` we may need to\n * create the fork dir ourselves. We always `mkdir -p` defensively.\n *\n * Error semantics:\n * - All validation errors throw before any filesystem write (fail-closed,\n * gotcha #25).\n * - If `importCapsule` throws after writing some records, the lineage\n * breadcrumb is NOT written (partial state is better than a false\n * \"fork complete\" marker — gotcha #12: write rollback data before\n * success markers).\n */\nexport async function forkCapsule(opts: ForkCapsuleOptions): Promise<ForkCapsuleResult> {\n // --- 1. Validate forkId ---\n validateForkId(opts.forkId);\n\n // --- 2. Validate targetRoot ---\n // Use the shared assertIsDirectoryNotSymlink helper from fs-utils.ts so\n // capsule-fork and capsule-import share the same symlink-safe validation\n // logic (Cursor medium #751 round 2: the fork's doc comment claims it\n // \"mirrors importCapsule's root validation\"; now it literally does).\n const rootAbs = path.resolve(opts.targetRoot);\n await assertIsDirectoryNotSymlink(rootAbs, \"forkCapsule\", \"targetRoot\");\n\n // --- 3. Reject duplicate forkId ---\n // Treat ANY existing filesystem entry at `forks/<forkId>` as occupied:\n // directory, regular file, or symlink. A previous version of this check\n // only rejected directories, so a stray file at the path would slip past\n // and `importCapsule` would still write under `forks/<sourceCapsule>/...`.\n // The later `mkdir`/`writeFile` for the breadcrumb would then fail,\n // leaving a partial fork import after reporting an error — violating the\n // documented \"reject before any write\" contract (Codex P2 #751 round 2).\n // `lstat` (not `stat`) is intentional so a symlink at the path is detected\n // even if its target is missing or otherwise unreadable.\n const forkDirAbs = path.join(rootAbs, \"forks\", opts.forkId);\n const forkEntryExists = await pathEntryExists(forkDirAbs);\n if (forkEntryExists) {\n throw new Error(\n `forkCapsule: fork path already exists — forkId \"${opts.forkId}\" is already in use at: ${forkDirAbs}`,\n );\n }\n\n // --- 4. Import in fork mode ---\n const archiveAbs = path.resolve(opts.sourceArchive);\n const importResult = await importCapsule({\n archivePath: archiveAbs,\n root: rootAbs,\n mode: \"fork\",\n now: opts.now,\n });\n\n const manifest = importResult.manifest;\n const sourceCapsule = manifest.capsule;\n\n // --- 5. Build lineage and write breadcrumb ---\n // The breadcrumb lives under the FORK's own directory, not the source\n // capsule's fork subtree. `forkId` may differ from `sourceCapsule.id`\n // (e.g. `forkCapsule({ forkId: \"my-fork\" })` with source `base-caps`\n // imports records under `forks/base-caps/` but the lineage breadcrumb\n // is written to `forks/my-fork/lineage.json` so a subsequent fork of\n // this fork can locate the breadcrumb by its own id).\n const forkedAt = new Date(opts.now ?? Date.now()).toISOString();\n\n const parent: CapsuleParent = {\n capsuleId: sourceCapsule.id,\n version: sourceCapsule.version,\n forkRoot: `forks/${sourceCapsule.id}`,\n };\n\n const lineage: ForkLineage = {\n forkId: opts.forkId,\n forkedAt,\n parent,\n importedRecords: importResult.imported.length,\n skippedRecords: importResult.skipped.length,\n };\n\n // Ensure the fork breadcrumb directory exists (it may not exist if forkId\n // differs from the source capsule's id, or if all records were skipped).\n const lineagePath = path.join(forkDirAbs, \"lineage.json\");\n\n // Guard lineage write against a symlinked `forks/` directory (or any\n // intermediate path component) pointing outside the memory root. If\n // `targetRoot/forks` is a symlink to `/tmp/evil`, a zero-record capsule\n // passes `importCapsule` without triggering per-record path checks and this\n // write would silently escape the root sandbox. We resolve the nearest\n // existing ancestor of `lineagePath` via `realpath` (same technique used by\n // `capsule-import` and `capsule-merge`) and verify the canonical path is\n // still inside `rootReal` before creating any directories or writing.\n //\n // Note: `rootReal` is computed from `rootAbs` here rather than reusing\n // `forkDirAbs` for the lexical check, because on macOS /tmp is a symlink\n // to /private/tmp and `path.relative(rootReal, forkDirAbs)` would produce\n // an absolute path if forkDirAbs was not also resolved. We skip the lexical\n // pre-check and rely solely on `assertRealpathInsideRoot` which handles\n // both the realpath walk and the containment check atomically.\n const rootReal = await realpath(rootAbs);\n // Symlink-safe containment check: walks the nearest existing ancestor and\n // confirms the canonical path is still inside rootReal.\n await assertRealpathInsideRoot(rootReal, lineagePath, `forks/${opts.forkId}/lineage.json`, \"forkCapsule\");\n\n await mkdir(path.dirname(lineagePath), { recursive: true });\n\n // Write breadcrumb AFTER import completes successfully — consistent with\n // gotcha #25 (don't destroy old state before new state is confirmed) and\n // gotcha #54 (write temp before rename / write before marker).\n await writeFile(lineagePath, JSON.stringify(lineage, null, 2) + \"\\n\", \"utf-8\");\n\n return {\n archivePath: archiveAbs,\n manifest,\n importResult,\n lineage,\n lineagePath,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Lineage query helper\n// ---------------------------------------------------------------------------\n\n/**\n * Read the lineage breadcrumb for a given fork in a memory root.\n *\n * Returns `null` when no breadcrumb exists (the directory is not a fork, or\n * was created before PR 4/6). Never throws for a missing file — callers\n * that need to distinguish \"not a fork\" from \"corrupt breadcrumb\" should\n * handle the JSON parse error themselves.\n *\n * `forkId` is validated against {@link CAPSULE_ID_PATTERN} before being\n * joined into the breadcrumb path so a malicious value like\n * `../../../../tmp` cannot escape the `forks/` namespace and resolve to\n * unrelated files outside the configured memory root (Codex P2 #751).\n * Invalid ids return `null` (same shape as \"no breadcrumb\"); callers that\n * need to distinguish \"invalid id\" from \"absent breadcrumb\" should validate\n * upstream.\n */\nexport async function readForkLineage(\n targetRoot: string,\n forkId: string,\n): Promise<ForkLineage | null> {\n // Reject any forkId that does not satisfy the capsule-id pattern. We use\n // the same constraints as `forkCapsule` so a path traversal payload like\n // `../../etc` is rejected before any filesystem access. Returning null\n // (rather than throwing) keeps the contract symmetric with the\n // \"breadcrumb not present\" case for the common get-or-default usage.\n if (\n typeof forkId !== \"string\" ||\n forkId.length === 0 ||\n forkId.length > 64 ||\n !CAPSULE_ID_PATTERN.test(forkId)\n ) {\n return null;\n }\n const rootAbs = path.resolve(targetRoot);\n // Resolve the root via realpath up-front so the symlink-safe containment\n // check below compares against the canonical path. If realpath fails\n // (root does not exist or is unreadable) we fall back to the lexical\n // root; the read will then return null for a missing breadcrumb anyway.\n const rootReal = await realpath(rootAbs).catch(() => rootAbs);\n\n const lineagePath = path.join(rootReal, \"forks\", forkId, \"lineage.json\");\n // Defensive lexical containment check: even though CAPSULE_ID_PATTERN\n // forbids `/` and `..`, an attacker who somehow bypasses the regex would\n // still be caught here. `path.relative` returns a `..`-prefixed string\n // when the target escapes the root.\n const rel = path.relative(rootReal, lineagePath);\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) {\n return null;\n }\n\n // Symlink-safe containment check (Codex P2 #751 round 2).\n // The lexical check above cannot detect a symlinked `forks/<forkId>`\n // directory whose target is outside the memory root. We resolve the\n // nearest existing ancestor of the breadcrumb path via realpath (which\n // follows symlinks), re-append the non-existent suffix, and verify the\n // result still lives under the real root. Mirrors the\n // `assertRealpathInsideRoot` pattern used by capsule-import.ts.\n if (!(await isLineagePathContained(rootReal, lineagePath))) {\n return null;\n }\n const raw = await readFile(lineagePath, \"utf-8\").catch(() => null);\n if (raw === null) return null;\n try {\n const parsed = JSON.parse(raw);\n // Basic shape check — we do not run full zod validation here so that\n // slightly malformed breadcrumbs (e.g. missing new fields added in later\n // PRs) can still be returned rather than silently dropped.\n if (typeof parsed !== \"object\" || parsed === null || typeof parsed.forkId !== \"string\") {\n return null;\n }\n return parsed as ForkLineage;\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nfunction validateForkId(forkId: unknown): void {\n if (typeof forkId !== \"string\") {\n throw new Error(\"forkCapsule: forkId must be a string\");\n }\n if (forkId.length === 0) {\n throw new Error(\"forkCapsule: forkId must not be empty\");\n }\n if (forkId.length > 64) {\n throw new Error(\"forkCapsule: forkId must be 64 characters or fewer\");\n }\n if (!CAPSULE_ID_PATTERN.test(forkId)) {\n throw new Error(\n `forkCapsule: invalid forkId \"${forkId}\". Expected alphanumeric with single dashes (no leading/trailing dashes, no consecutive dashes).`,\n );\n }\n}\n\n/**\n * Return true when ANY filesystem entry exists at {@link absPath} —\n * directory, regular file, symlink (even broken), or other special file.\n * Uses `lstat` so a symlink at the path is detected regardless of whether\n * its target resolves. Used by the duplicate-forkId check so a stray file\n * cannot bypass the \"reject before any write\" guarantee (Codex P2 #751).\n */\nasync function pathEntryExists(absPath: string): Promise<boolean> {\n const st = await lstat(absPath).catch(() => null);\n return st !== null;\n}\n\n/**\n * Symlink-safe containment check for {@link readForkLineage}.\n *\n * Walks from {@link lineagePath} toward {@link rootReal} until it finds a\n * path component that exists on disk, resolves that prefix via `realpath`\n * (which follows symlinks), then re-appends the non-existent suffix and\n * verifies the resulting canonical path is still inside {@link rootReal}.\n *\n * This catches the case where any subdirectory in the path is a symlink\n * pointing outside the intended root. Returns `true` when the path is\n * safely contained, `false` otherwise.\n *\n * Mirrors the `assertRealpathInsideRoot` helper in `capsule-import.ts`.\n * Returning a boolean (rather than throwing) keeps the contract aligned\n * with `readForkLineage`'s \"return null on any safety failure\" pattern.\n */\nasync function isLineagePathContained(\n rootReal: string,\n lineagePath: string,\n): Promise<boolean> {\n let existing = lineagePath;\n const suffix: string[] = [];\n while (existing !== path.dirname(existing)) {\n const st = await lstat(existing).catch(() => null);\n if (st !== null) break;\n suffix.unshift(path.basename(existing));\n existing = path.dirname(existing);\n }\n\n // If we walked all the way to the filesystem root without finding\n // anything that exists, the path is harmless (no symlinks to follow).\n // The subsequent readFile will simply fail and return null.\n const existingReal = await realpath(existing).catch(() => existing);\n const targetReal = suffix.length > 0 ? path.join(existingReal, ...suffix) : existingReal;\n\n const rel = path.relative(rootReal, targetReal);\n if (rel === \"\") return true;\n if (rel === \"..\") return false;\n if (rel.startsWith(`..${path.sep}`)) return false;\n if (path.isAbsolute(rel)) return false;\n return true;\n}\n"],"mappings":"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","names":["j","fsp","path","fsp","path","crypto","fsp","path","crypto","hashFile","fsp","crypto","path","log","verifyResult","path","path","fs","path","fs","path","crypto","fs","path","parseFrontmatter","extractBody","crypto","fs","path","crypto","hashContent","fs","path","readFileSafe","parseFrontmatter","extractBody","crypto","fs","path","fs","isPathInside","path","parseFrontmatter","extractBody","readFileSafe","fs","path","crypto","DEFAULT_EXCLUDE","hashContent","crypto","fs","path","path","fs","manifestPath","manifestDir","crypto","previousId","walkMd","hashContent","fs","path","path","fs","path","path"]}