oh-my-second-brain 0.2.0 → 0.6.1

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 (494) hide show
  1. package/.claude-plugin/marketplace.json +41 -0
  2. package/{adapters/claude-code/.claude-plugin → .claude-plugin}/plugin.json +7 -8
  3. package/{adapters/codex/.codex-plugin → .codex-plugin}/plugin.json +4 -4
  4. package/ACKNOWLEDGMENTS.md +162 -0
  5. package/CHANGELOG-assets.md +23 -0
  6. package/CHANGELOG-cli.md +24 -0
  7. package/CHANGELOG-kernel.md +48 -0
  8. package/CHANGELOG-mcp.md +36 -0
  9. package/CHANGELOG-vendors.md +26 -0
  10. package/CHANGELOG.md +51 -7
  11. package/README.ko.md +2 -2
  12. package/README.md +16 -16
  13. package/{adapters/claude-code → assets/claude}/CLAUDE.md +4 -4
  14. package/{adapters → assets}/codex/AGENTS.md +3 -3
  15. package/{adapters → assets}/codex/rules/oms.md +5 -5
  16. package/{adapters → assets}/hermes/README.md +1 -1
  17. package/{adapters → assets}/hermes/SOUL.md +3 -3
  18. package/{adapters/hermes/manifest.json → assets/hermes-manifest.json} +3 -4
  19. package/assets/skills/distill/SKILL.md +20 -0
  20. package/assets/skills/doctor/SKILL.md +23 -0
  21. package/assets/skills/link/SKILL.md +24 -0
  22. package/assets/skills/search/SKILL.md +25 -0
  23. package/assets/skills/status/SKILL.md +22 -0
  24. package/assets/skills/write/SKILL.md +30 -0
  25. package/core/ontology/schemas/README.md +20 -14
  26. package/dist/assets/shared-skills.d.ts +4 -0
  27. package/dist/assets/shared-skills.js +8 -0
  28. package/dist/assets/shared-skills.js.map +1 -0
  29. package/dist/cli/args.d.ts +3 -1
  30. package/dist/cli/args.js +14 -1
  31. package/dist/cli/args.js.map +1 -1
  32. package/dist/cli/audit.js +3 -3
  33. package/dist/cli/audit.js.map +1 -1
  34. package/dist/cli/claude-install-plan.js +2 -2
  35. package/dist/cli/claude-install-plan.js.map +1 -1
  36. package/dist/cli/doctor-lint.js +8 -8
  37. package/dist/cli/doctor-lint.js.map +1 -1
  38. package/dist/cli/global-writeback.js +1 -1
  39. package/dist/cli/global-writeback.js.map +1 -1
  40. package/dist/cli/host-commands.d.ts +1 -1
  41. package/dist/cli/host-commands.js +24 -5
  42. package/dist/cli/host-commands.js.map +1 -1
  43. package/dist/cli/link-command.d.ts +1 -1
  44. package/dist/cli/link-command.js +2 -2
  45. package/dist/cli/link-command.js.map +1 -1
  46. package/dist/cli/linkify.js +16 -71
  47. package/dist/cli/linkify.js.map +1 -1
  48. package/dist/cli/oms.d.ts +1 -1
  49. package/dist/cli/oms.js +45 -11
  50. package/dist/cli/oms.js.map +1 -1
  51. package/dist/cli/semantic-args.d.ts +1 -1
  52. package/dist/cli/semantic-args.js +102 -3
  53. package/dist/cli/semantic-args.js.map +1 -1
  54. package/dist/cli/semantic-http.js +3 -3
  55. package/dist/cli/semantic-http.js.map +1 -1
  56. package/dist/cli/semantic-usage.js +1 -1
  57. package/dist/cli/semantic-usage.js.map +1 -1
  58. package/dist/cli/semantic.js +31 -12
  59. package/dist/cli/semantic.js.map +1 -1
  60. package/dist/cli/setup-command.d.ts +17 -0
  61. package/dist/cli/setup-command.js +89 -145
  62. package/dist/cli/setup-command.js.map +1 -1
  63. package/dist/cli/update-notice.d.ts +1 -1
  64. package/dist/cli/update-notice.js +2 -2
  65. package/dist/cli/update-notice.js.map +1 -1
  66. package/dist/cli/usage.d.ts +1 -1
  67. package/dist/cli/usage.js +2 -2
  68. package/dist/cli/usage.js.map +1 -1
  69. package/dist/{capture → kernel/capture}/safe.d.ts +11 -1
  70. package/dist/{capture → kernel/capture}/safe.js +3 -3
  71. package/dist/kernel/capture/safe.js.map +1 -0
  72. package/dist/kernel/contracts/index.d.ts +144 -0
  73. package/dist/kernel/contracts/index.js +401 -0
  74. package/dist/kernel/contracts/index.js.map +1 -0
  75. package/dist/kernel/conventions/frontmatter.js.map +1 -0
  76. package/dist/kernel/conventions/lint.js.map +1 -0
  77. package/dist/kernel/conventions/report.js.map +1 -0
  78. package/dist/{conventions → kernel/conventions}/validate.d.ts +1 -1
  79. package/dist/kernel/conventions/validate.js.map +1 -0
  80. package/dist/kernel/conventions/vault-walk.js.map +1 -0
  81. package/dist/{conventions → kernel/conventions}/write-contract.d.ts +1 -1
  82. package/dist/kernel/conventions/write-contract.js.map +1 -0
  83. package/dist/kernel/conventions/write-protocol.js.map +1 -0
  84. package/dist/kernel/doctor/service.d.ts +71 -0
  85. package/dist/kernel/doctor/service.js +70 -0
  86. package/dist/kernel/doctor/service.js.map +1 -0
  87. package/dist/{engine → kernel/engine}/assemble.d.ts +46 -1
  88. package/dist/kernel/engine/assemble.js +483 -0
  89. package/dist/kernel/engine/assemble.js.map +1 -0
  90. package/dist/kernel/engine/axes/store.d.ts +90 -0
  91. package/dist/kernel/engine/axes/store.js +400 -0
  92. package/dist/kernel/engine/axes/store.js.map +1 -0
  93. package/dist/{engine → kernel/engine}/conventions/vault-lint.d.ts +1 -1
  94. package/dist/{engine → kernel/engine}/conventions/vault-lint.js +1 -1
  95. package/dist/kernel/engine/conventions/vault-lint.js.map +1 -0
  96. package/dist/kernel/engine/embed/chunker.js.map +1 -0
  97. package/dist/kernel/engine/embed/deferred.js.map +1 -0
  98. package/dist/{engine → kernel/engine}/embed/hash-stub.test-helper.d.ts +1 -1
  99. package/dist/{engine → kernel/engine}/embed/hash-stub.test-helper.js +1 -1
  100. package/dist/kernel/engine/embed/hash-stub.test-helper.js.map +1 -0
  101. package/dist/kernel/engine/embed/identity.d.ts +21 -0
  102. package/dist/kernel/engine/embed/identity.js +47 -0
  103. package/dist/kernel/engine/embed/identity.js.map +1 -0
  104. package/dist/kernel/engine/embed/model.d.ts +134 -0
  105. package/dist/kernel/engine/embed/model.js +302 -0
  106. package/dist/kernel/engine/embed/model.js.map +1 -0
  107. package/dist/{engine → kernel/engine}/embed/provider.d.ts +36 -5
  108. package/dist/kernel/engine/embed/provider.js +403 -0
  109. package/dist/kernel/engine/embed/provider.js.map +1 -0
  110. package/dist/{engine → kernel/engine}/embed/store.d.ts +13 -1
  111. package/dist/kernel/engine/embed/store.js +730 -0
  112. package/dist/kernel/engine/embed/store.js.map +1 -0
  113. package/dist/kernel/engine/embed/sync.d.ts +100 -0
  114. package/dist/kernel/engine/embed/sync.js +753 -0
  115. package/dist/kernel/engine/embed/sync.js.map +1 -0
  116. package/dist/{engine → kernel/engine}/graph/builder.d.ts +9 -5
  117. package/dist/{engine → kernel/engine}/graph/builder.js +213 -79
  118. package/dist/kernel/engine/graph/builder.js.map +1 -0
  119. package/dist/kernel/engine/graph/explore.js.map +1 -0
  120. package/dist/{engine → kernel/engine}/graph/node.d.ts +49 -1
  121. package/dist/kernel/engine/graph/node.js +315 -0
  122. package/dist/kernel/engine/graph/node.js.map +1 -0
  123. package/dist/kernel/engine/graph/resolver.js.map +1 -0
  124. package/dist/kernel/engine/graph/traverse.js.map +1 -0
  125. package/dist/kernel/engine/linkify/apply.js.map +1 -0
  126. package/dist/kernel/engine/linkify/josa.js.map +1 -0
  127. package/dist/kernel/engine/linkify/mask.js.map +1 -0
  128. package/dist/kernel/engine/linkify/suggest.js.map +1 -0
  129. package/dist/kernel/engine/linkify/types.js.map +1 -0
  130. package/dist/{engine → kernel/engine}/mcp/facade.d.ts +27 -1
  131. package/dist/kernel/engine/mcp/facade.js +1144 -0
  132. package/dist/kernel/engine/mcp/facade.js.map +1 -0
  133. package/dist/kernel/engine/mcp/op-mappers.js.map +1 -0
  134. package/dist/{engine → kernel/engine}/mcp/query-mapper.d.ts +27 -2
  135. package/dist/kernel/engine/mcp/query-mapper.js +247 -0
  136. package/dist/kernel/engine/mcp/query-mapper.js.map +1 -0
  137. package/dist/{engine → kernel/engine}/mcp/types.d.ts +69 -2
  138. package/dist/kernel/engine/mcp/types.js.map +1 -0
  139. package/dist/{engine → kernel/engine}/retrieval/dispatcher.d.ts +23 -1
  140. package/dist/{engine → kernel/engine}/retrieval/dispatcher.js +92 -14
  141. package/dist/kernel/engine/retrieval/dispatcher.js.map +1 -0
  142. package/dist/{engine → kernel/engine}/retrieval/index.d.ts +4 -1
  143. package/dist/{engine → kernel/engine}/retrieval/index.js +6 -3
  144. package/dist/kernel/engine/retrieval/index.js.map +1 -0
  145. package/dist/kernel/engine/retrieval/reranker.d.ts +124 -0
  146. package/dist/kernel/engine/retrieval/reranker.js +204 -0
  147. package/dist/kernel/engine/retrieval/reranker.js.map +1 -0
  148. package/dist/{engine → kernel/engine}/retrieval/rrf.d.ts +10 -2
  149. package/dist/kernel/engine/retrieval/rrf.js +77 -0
  150. package/dist/kernel/engine/retrieval/rrf.js.map +1 -0
  151. package/dist/{engine → kernel/engine}/tracer.d.ts +13 -0
  152. package/dist/{engine → kernel/engine}/tracer.js +63 -6
  153. package/dist/kernel/engine/tracer.js.map +1 -0
  154. package/dist/{engine → kernel/engine}/types.d.ts +4 -4
  155. package/dist/kernel/engine/types.js.map +1 -0
  156. package/dist/{graph → kernel/graph}/cache.d.ts +1 -1
  157. package/dist/{graph → kernel/graph}/cache.js +165 -21
  158. package/dist/kernel/graph/cache.js.map +1 -0
  159. package/dist/kernel/graph/explore.js.map +1 -0
  160. package/dist/{harness → kernel/harness}/surface-registry.d.ts +0 -1
  161. package/dist/kernel/harness/surface-registry.js +170 -0
  162. package/dist/kernel/harness/surface-registry.js.map +1 -0
  163. package/dist/{harness → kernel/harness}/validation.js +67 -4
  164. package/dist/kernel/harness/validation.js.map +1 -0
  165. package/dist/kernel/index.d.ts +13 -0
  166. package/dist/kernel/index.js +14 -0
  167. package/dist/kernel/index.js.map +1 -0
  168. package/dist/{install → kernel/install}/adapter-source.d.ts +10 -1
  169. package/dist/kernel/install/adapter-source.js +76 -0
  170. package/dist/kernel/install/adapter-source.js.map +1 -0
  171. package/dist/kernel/install/common.js.map +1 -0
  172. package/dist/{install → kernel/install}/hosts.d.ts +3 -3
  173. package/dist/{install → kernel/install}/hosts.js +3 -22
  174. package/dist/kernel/install/hosts.js.map +1 -0
  175. package/dist/{core/ontology → kernel/install}/types.js.map +1 -1
  176. package/dist/{link → kernel/link}/convention-note.js +2 -2
  177. package/dist/kernel/link/convention-note.js.map +1 -0
  178. package/dist/kernel/link/global-config.js.map +1 -0
  179. package/dist/kernel/link/link.js.map +1 -0
  180. package/dist/kernel/link/workflow.d.ts +55 -0
  181. package/dist/kernel/link/workflow.js +107 -0
  182. package/dist/kernel/link/workflow.js.map +1 -0
  183. package/dist/kernel/measurement/no-default-contract.d.ts +17 -0
  184. package/dist/kernel/measurement/no-default-contract.js +84 -0
  185. package/dist/kernel/measurement/no-default-contract.js.map +1 -0
  186. package/dist/{ontology → kernel/ontology}/active.d.ts +1 -1
  187. package/dist/{ontology → kernel/ontology}/active.js +2 -2
  188. package/dist/kernel/ontology/active.js.map +1 -0
  189. package/dist/kernel/ontology/loader.js.map +1 -0
  190. package/dist/kernel/ontology/resolver.js.map +1 -0
  191. package/dist/{install → kernel/ontology}/types.js.map +1 -1
  192. package/dist/kernel/plugin/index.d.ts +1 -0
  193. package/dist/kernel/plugin/index.js +2 -0
  194. package/dist/kernel/plugin/index.js.map +1 -0
  195. package/dist/{core → kernel}/runtime/assets.d.ts +2 -4
  196. package/dist/{core → kernel}/runtime/assets.js +1 -3
  197. package/dist/kernel/runtime/assets.js.map +1 -0
  198. package/dist/kernel/search/morning-test-fixtures.js.map +1 -0
  199. package/dist/{retrieve → kernel/search}/morning.d.ts +0 -1
  200. package/dist/kernel/search/morning.js.map +1 -0
  201. package/dist/kernel/search/semantic-contract.js.map +1 -0
  202. package/dist/kernel/searchbackend/engine-search-backend.d.ts +28 -0
  203. package/dist/kernel/searchbackend/engine-search-backend.js +153 -0
  204. package/dist/kernel/searchbackend/engine-search-backend.js.map +1 -0
  205. package/dist/kernel/searchbackend/index.d.ts +2 -0
  206. package/dist/kernel/searchbackend/index.js +2 -0
  207. package/dist/kernel/searchbackend/index.js.map +1 -0
  208. package/dist/kernel/searchbackend/search-backend.d.ts +57 -0
  209. package/dist/kernel/searchbackend/search-backend.js +110 -0
  210. package/dist/kernel/searchbackend/search-backend.js.map +1 -0
  211. package/dist/{mcp → kernel/semantic}/semantic-engine.d.ts +3 -2
  212. package/dist/kernel/semantic/semantic-engine.js +78 -0
  213. package/dist/kernel/semantic/semantic-engine.js.map +1 -0
  214. package/dist/{mcp → kernel/semantic}/semantic-retrieve-args.d.ts +20 -3
  215. package/dist/{mcp → kernel/semantic}/semantic-retrieve-args.js +81 -15
  216. package/dist/kernel/semantic/semantic-retrieve-args.js.map +1 -0
  217. package/dist/{mcp → kernel/semantic}/semantic-retrieve-schema.d.ts +0 -24
  218. package/dist/{mcp → kernel/semantic}/semantic-retrieve-schema.js +0 -8
  219. package/dist/kernel/semantic/semantic-retrieve-schema.js.map +1 -0
  220. package/dist/{mcp → kernel/semantic}/semantic-retrieve.js +5 -9
  221. package/dist/kernel/semantic/semantic-retrieve.js.map +1 -0
  222. package/dist/kernel/semantic/semantic-schemas.js.map +1 -0
  223. package/dist/{mcp → kernel/semantic}/semantic-tool-schemas.js +0 -28
  224. package/dist/kernel/semantic/semantic-tool-schemas.js.map +1 -0
  225. package/dist/{setup → kernel/setup}/axis.d.ts +1 -1
  226. package/dist/{setup → kernel/setup}/axis.js +1 -1
  227. package/dist/kernel/setup/axis.js.map +1 -0
  228. package/dist/{cli/setup-documents.d.ts → kernel/setup/documents.d.ts} +1 -1
  229. package/dist/{cli/setup-documents.js → kernel/setup/documents.js} +15 -49
  230. package/dist/kernel/setup/documents.js.map +1 -0
  231. package/dist/kernel/setup/service.d.ts +44 -0
  232. package/dist/kernel/setup/service.js +97 -0
  233. package/dist/kernel/setup/service.js.map +1 -0
  234. package/dist/{update → kernel/update}/update.d.ts +7 -0
  235. package/dist/{update → kernel/update}/update.js +106 -8
  236. package/dist/kernel/update/update.js.map +1 -0
  237. package/dist/mcp/engine-morning-backend.d.ts +4 -4
  238. package/dist/mcp/engine-morning-backend.js +4 -18
  239. package/dist/mcp/engine-morning-backend.js.map +1 -1
  240. package/dist/mcp/link-tools.d.ts +9 -56
  241. package/dist/mcp/link-tools.js +5 -129
  242. package/dist/mcp/link-tools.js.map +1 -1
  243. package/dist/mcp/server.d.ts +9 -2
  244. package/dist/mcp/server.js +373 -324
  245. package/dist/mcp/server.js.map +1 -1
  246. package/dist/mcp/update-notice.d.ts +1 -1
  247. package/dist/mcp/update-notice.js +1 -1
  248. package/dist/mcp/update-notice.js.map +1 -1
  249. package/dist/{install → vendors/claude}/claude-hooks.d.ts +1 -1
  250. package/dist/{install → vendors/claude}/claude-hooks.js +1 -1
  251. package/dist/vendors/claude/claude-hooks.js.map +1 -0
  252. package/dist/{install → vendors/claude}/claude-marketplace.d.ts +3 -3
  253. package/dist/{install → vendors/claude}/claude-marketplace.js +6 -9
  254. package/dist/vendors/claude/claude-marketplace.js.map +1 -0
  255. package/dist/{install → vendors/claude}/claude.d.ts +2 -2
  256. package/dist/{install → vendors/claude}/claude.js +2 -2
  257. package/dist/vendors/claude/claude.js.map +1 -0
  258. package/dist/{hook → vendors/claude/hook}/post-tool-use.js +5 -5
  259. package/dist/vendors/claude/hook/post-tool-use.js.map +1 -0
  260. package/dist/vendors/claude/hook/pre-tool-use.js.map +1 -0
  261. package/dist/vendors/claude/hook/stdin.js.map +1 -0
  262. package/dist/vendors/codex/codex.d.ts +10 -0
  263. package/dist/{install → vendors/codex}/codex.js +19 -37
  264. package/dist/vendors/codex/codex.js.map +1 -0
  265. package/dist/{install → vendors/hermes}/hermes.d.ts +2 -2
  266. package/dist/{install → vendors/hermes}/hermes.js +15 -7
  267. package/dist/vendors/hermes/hermes.js.map +1 -0
  268. package/docs/adapters.md +15 -0
  269. package/docs/install.md +10 -11
  270. package/package.json +23 -10
  271. package/adapters/README.md +0 -99
  272. package/adapters/claude-code/skills/compile/SKILL.md +0 -27
  273. package/adapters/claude-code/skills/define/SKILL.md +0 -51
  274. package/adapters/claude-code/skills/distill/SKILL.md +0 -28
  275. package/adapters/claude-code/skills/doctor/SKILL.md +0 -58
  276. package/adapters/claude-code/skills/link/SKILL.md +0 -87
  277. package/adapters/claude-code/skills/retrieve/SKILL.md +0 -99
  278. package/adapters/claude-code/skills/setup/SKILL.md +0 -78
  279. package/adapters/claude-code/skills/uninstall/SKILL.md +0 -34
  280. package/adapters/claude-code/skills/update/SKILL.md +0 -45
  281. package/adapters/claude-code/skills/vault-decision-record/SKILL.md +0 -52
  282. package/adapters/claude-code/skills/vault-lint/SKILL.md +0 -47
  283. package/adapters/claude-code/skills/vault-scaffold/SKILL.md +0 -47
  284. package/adapters/claude-code/skills/wiki/SKILL.md +0 -82
  285. package/adapters/claude-code/skills/write/SKILL.md +0 -16
  286. package/adapters/codex/skills/oms-compile/SKILL.md +0 -16
  287. package/adapters/codex/skills/oms-distill/SKILL.md +0 -14
  288. package/adapters/codex/skills/oms-doctor/SKILL.md +0 -14
  289. package/adapters/codex/skills/oms-install/SKILL.md +0 -19
  290. package/adapters/codex/skills/oms-link/SKILL.md +0 -35
  291. package/adapters/codex/skills/oms-retrieve/SKILL.md +0 -32
  292. package/adapters/codex/skills/oms-setup/SKILL.md +0 -34
  293. package/adapters/codex/skills/oms-uninstall/SKILL.md +0 -20
  294. package/adapters/codex/skills/oms-update/SKILL.md +0 -22
  295. package/adapters/codex/skills/oms-vault-lint/SKILL.md +0 -19
  296. package/adapters/codex/skills/oms-wiki/SKILL.md +0 -39
  297. package/adapters/codex/skills/oms-write/SKILL.md +0 -10
  298. package/adapters/hermes/skills/compile/SKILL.md +0 -13
  299. package/adapters/hermes/skills/distill/SKILL.md +0 -10
  300. package/adapters/hermes/skills/doctor/SKILL.md +0 -14
  301. package/adapters/hermes/skills/install/SKILL.md +0 -19
  302. package/adapters/hermes/skills/link/SKILL.md +0 -18
  303. package/adapters/hermes/skills/retrieve/SKILL.md +0 -32
  304. package/adapters/hermes/skills/setup/SKILL.md +0 -37
  305. package/adapters/hermes/skills/uninstall/SKILL.md +0 -20
  306. package/adapters/hermes/skills/update/SKILL.md +0 -22
  307. package/adapters/hermes/skills/wiki/SKILL.md +0 -14
  308. package/adapters/hermes/skills/write/SKILL.md +0 -10
  309. package/core/agents/librarian.md +0 -44
  310. package/core/agents/retriever.md +0 -62
  311. package/core/skills/compile/CHANGELOG.md +0 -24
  312. package/core/skills/compile/SKILL.md +0 -57
  313. package/core/skills/define/SKILL.md +0 -59
  314. package/core/skills/distill/CHANGELOG.md +0 -39
  315. package/core/skills/distill/SKILL.md +0 -62
  316. package/core/skills/doctor/SKILL.md +0 -49
  317. package/core/skills/link/SKILL.md +0 -130
  318. package/core/skills/retrieve/SKILL.md +0 -78
  319. package/core/skills/setup/CHANGELOG.md +0 -49
  320. package/core/skills/setup/SKILL.md +0 -246
  321. package/core/skills/uninstall/SKILL.md +0 -34
  322. package/core/skills/vault-decision-record/CHANGELOG.md +0 -24
  323. package/core/skills/vault-decision-record/SKILL.md +0 -93
  324. package/core/skills/vault-lint/CHANGELOG.md +0 -35
  325. package/core/skills/vault-lint/SKILL.md +0 -58
  326. package/core/skills/vault-scaffold/CHANGELOG.md +0 -21
  327. package/core/skills/vault-scaffold/SKILL.md +0 -72
  328. package/core/skills/wiki/CHANGELOG.md +0 -23
  329. package/core/skills/wiki/SKILL.md +0 -159
  330. package/core/skills/write/SKILL.md +0 -15
  331. package/dist/capture/safe.js.map +0 -1
  332. package/dist/cli/setup-documents.js.map +0 -1
  333. package/dist/conventions/frontmatter.js.map +0 -1
  334. package/dist/conventions/lint.js.map +0 -1
  335. package/dist/conventions/report.js.map +0 -1
  336. package/dist/conventions/validate.js.map +0 -1
  337. package/dist/conventions/vault-walk.js.map +0 -1
  338. package/dist/conventions/write-contract.js.map +0 -1
  339. package/dist/conventions/write-protocol.js.map +0 -1
  340. package/dist/core/ontology/loader.js.map +0 -1
  341. package/dist/core/ontology/resolver.js.map +0 -1
  342. package/dist/core/runtime/assets.js.map +0 -1
  343. package/dist/engine/assemble.js +0 -162
  344. package/dist/engine/assemble.js.map +0 -1
  345. package/dist/engine/conventions/vault-lint.js.map +0 -1
  346. package/dist/engine/embed/chunker.js.map +0 -1
  347. package/dist/engine/embed/deferred.js.map +0 -1
  348. package/dist/engine/embed/hash-stub.test-helper.js.map +0 -1
  349. package/dist/engine/embed/identity.d.ts +0 -11
  350. package/dist/engine/embed/identity.js +0 -15
  351. package/dist/engine/embed/identity.js.map +0 -1
  352. package/dist/engine/embed/provider.js +0 -266
  353. package/dist/engine/embed/provider.js.map +0 -1
  354. package/dist/engine/embed/store.js +0 -416
  355. package/dist/engine/embed/store.js.map +0 -1
  356. package/dist/engine/embed/sync.d.ts +0 -45
  357. package/dist/engine/embed/sync.js +0 -321
  358. package/dist/engine/embed/sync.js.map +0 -1
  359. package/dist/engine/graph/builder.js.map +0 -1
  360. package/dist/engine/graph/explore.js.map +0 -1
  361. package/dist/engine/graph/node.js +0 -110
  362. package/dist/engine/graph/node.js.map +0 -1
  363. package/dist/engine/graph/resolver.js.map +0 -1
  364. package/dist/engine/graph/traverse.js.map +0 -1
  365. package/dist/engine/linkify/apply.js.map +0 -1
  366. package/dist/engine/linkify/josa.js.map +0 -1
  367. package/dist/engine/linkify/mask.js.map +0 -1
  368. package/dist/engine/linkify/suggest.js.map +0 -1
  369. package/dist/engine/linkify/types.js.map +0 -1
  370. package/dist/engine/mcp/facade.js +0 -628
  371. package/dist/engine/mcp/facade.js.map +0 -1
  372. package/dist/engine/mcp/op-mappers.js.map +0 -1
  373. package/dist/engine/mcp/query-mapper.js +0 -102
  374. package/dist/engine/mcp/query-mapper.js.map +0 -1
  375. package/dist/engine/mcp/types.js.map +0 -1
  376. package/dist/engine/retrieval/dispatcher.js.map +0 -1
  377. package/dist/engine/retrieval/index.js.map +0 -1
  378. package/dist/engine/retrieval/reranker.d.ts +0 -46
  379. package/dist/engine/retrieval/reranker.js +0 -29
  380. package/dist/engine/retrieval/reranker.js.map +0 -1
  381. package/dist/engine/retrieval/rrf.js +0 -54
  382. package/dist/engine/retrieval/rrf.js.map +0 -1
  383. package/dist/engine/tracer.js.map +0 -1
  384. package/dist/engine/types.js.map +0 -1
  385. package/dist/graph/cache.js.map +0 -1
  386. package/dist/graph/explore.js.map +0 -1
  387. package/dist/harness/surface-registry.js +0 -397
  388. package/dist/harness/surface-registry.js.map +0 -1
  389. package/dist/harness/validation.js.map +0 -1
  390. package/dist/hook/post-tool-use.js.map +0 -1
  391. package/dist/hook/pre-tool-use.js.map +0 -1
  392. package/dist/hook/stdin.js.map +0 -1
  393. package/dist/index.d.ts +0 -12
  394. package/dist/index.js +0 -13
  395. package/dist/index.js.map +0 -1
  396. package/dist/install/adapter-source.js +0 -45
  397. package/dist/install/adapter-source.js.map +0 -1
  398. package/dist/install/claude-hooks.js.map +0 -1
  399. package/dist/install/claude-marketplace.js.map +0 -1
  400. package/dist/install/claude.js.map +0 -1
  401. package/dist/install/codex.d.ts +0 -24
  402. package/dist/install/codex.js.map +0 -1
  403. package/dist/install/common.js.map +0 -1
  404. package/dist/install/hermes.js.map +0 -1
  405. package/dist/install/hosts.js.map +0 -1
  406. package/dist/link/convention-note.js.map +0 -1
  407. package/dist/link/global-config.js.map +0 -1
  408. package/dist/link/link.js.map +0 -1
  409. package/dist/mcp/semantic-engine.js +0 -52
  410. package/dist/mcp/semantic-engine.js.map +0 -1
  411. package/dist/mcp/semantic-retrieve-args.js.map +0 -1
  412. package/dist/mcp/semantic-retrieve-schema.js.map +0 -1
  413. package/dist/mcp/semantic-retrieve.js.map +0 -1
  414. package/dist/mcp/semantic-schemas.js.map +0 -1
  415. package/dist/mcp/semantic-tool-schemas.js.map +0 -1
  416. package/dist/ontology/active.js.map +0 -1
  417. package/dist/retrieve/morning-test-fixtures.js.map +0 -1
  418. package/dist/retrieve/morning.js.map +0 -1
  419. package/dist/retrieve/semantic-contract.js.map +0 -1
  420. package/dist/setup/axis.js.map +0 -1
  421. package/dist/update/update.js.map +0 -1
  422. package/docs/release.md +0 -188
  423. /package/{adapters/codex/.mcp.json → .mcp.codex.json} +0 -0
  424. /package/{adapters/claude-code/.mcp.json → .mcp.json} +0 -0
  425. /package/{adapters/claude-code → assets/claude}/hooks/oms-guard.mjs +0 -0
  426. /package/{adapters/claude-code → assets/claude}/hooks/oms-post-guard.mjs +0 -0
  427. /package/dist/{conventions → kernel/conventions}/frontmatter.d.ts +0 -0
  428. /package/dist/{conventions → kernel/conventions}/frontmatter.js +0 -0
  429. /package/dist/{conventions → kernel/conventions}/lint.d.ts +0 -0
  430. /package/dist/{conventions → kernel/conventions}/lint.js +0 -0
  431. /package/dist/{conventions → kernel/conventions}/report.d.ts +0 -0
  432. /package/dist/{conventions → kernel/conventions}/report.js +0 -0
  433. /package/dist/{conventions → kernel/conventions}/validate.js +0 -0
  434. /package/dist/{conventions → kernel/conventions}/vault-walk.d.ts +0 -0
  435. /package/dist/{conventions → kernel/conventions}/vault-walk.js +0 -0
  436. /package/dist/{conventions → kernel/conventions}/write-contract.js +0 -0
  437. /package/dist/{conventions → kernel/conventions}/write-protocol.d.ts +0 -0
  438. /package/dist/{conventions → kernel/conventions}/write-protocol.js +0 -0
  439. /package/dist/{engine → kernel/engine}/embed/chunker.d.ts +0 -0
  440. /package/dist/{engine → kernel/engine}/embed/chunker.js +0 -0
  441. /package/dist/{engine → kernel/engine}/embed/deferred.d.ts +0 -0
  442. /package/dist/{engine → kernel/engine}/embed/deferred.js +0 -0
  443. /package/dist/{engine → kernel/engine}/graph/explore.d.ts +0 -0
  444. /package/dist/{engine → kernel/engine}/graph/explore.js +0 -0
  445. /package/dist/{engine → kernel/engine}/graph/resolver.d.ts +0 -0
  446. /package/dist/{engine → kernel/engine}/graph/resolver.js +0 -0
  447. /package/dist/{engine → kernel/engine}/graph/traverse.d.ts +0 -0
  448. /package/dist/{engine → kernel/engine}/graph/traverse.js +0 -0
  449. /package/dist/{engine → kernel/engine}/linkify/apply.d.ts +0 -0
  450. /package/dist/{engine → kernel/engine}/linkify/apply.js +0 -0
  451. /package/dist/{engine → kernel/engine}/linkify/josa.d.ts +0 -0
  452. /package/dist/{engine → kernel/engine}/linkify/josa.js +0 -0
  453. /package/dist/{engine → kernel/engine}/linkify/mask.d.ts +0 -0
  454. /package/dist/{engine → kernel/engine}/linkify/mask.js +0 -0
  455. /package/dist/{engine → kernel/engine}/linkify/suggest.d.ts +0 -0
  456. /package/dist/{engine → kernel/engine}/linkify/suggest.js +0 -0
  457. /package/dist/{engine → kernel/engine}/linkify/types.d.ts +0 -0
  458. /package/dist/{engine → kernel/engine}/linkify/types.js +0 -0
  459. /package/dist/{engine → kernel/engine}/mcp/op-mappers.d.ts +0 -0
  460. /package/dist/{engine → kernel/engine}/mcp/op-mappers.js +0 -0
  461. /package/dist/{engine → kernel/engine}/mcp/types.js +0 -0
  462. /package/dist/{engine → kernel/engine}/types.js +0 -0
  463. /package/dist/{graph → kernel/graph}/explore.d.ts +0 -0
  464. /package/dist/{graph → kernel/graph}/explore.js +0 -0
  465. /package/dist/{harness → kernel/harness}/validation.d.ts +0 -0
  466. /package/dist/{install → kernel/install}/common.d.ts +0 -0
  467. /package/dist/{install → kernel/install}/common.js +0 -0
  468. /package/dist/{install → kernel/install}/types.d.ts +0 -0
  469. /package/dist/{core/ontology → kernel/install}/types.js +0 -0
  470. /package/dist/{link → kernel/link}/convention-note.d.ts +0 -0
  471. /package/dist/{link → kernel/link}/global-config.d.ts +0 -0
  472. /package/dist/{link → kernel/link}/global-config.js +0 -0
  473. /package/dist/{link → kernel/link}/link.d.ts +0 -0
  474. /package/dist/{link → kernel/link}/link.js +0 -0
  475. /package/dist/{core → kernel}/ontology/loader.d.ts +0 -0
  476. /package/dist/{core → kernel}/ontology/loader.js +0 -0
  477. /package/dist/{core → kernel}/ontology/resolver.d.ts +0 -0
  478. /package/dist/{core → kernel}/ontology/resolver.js +0 -0
  479. /package/dist/{core → kernel}/ontology/types.d.ts +0 -0
  480. /package/dist/{install → kernel/ontology}/types.js +0 -0
  481. /package/dist/{retrieve → kernel/search}/morning-test-fixtures.d.ts +0 -0
  482. /package/dist/{retrieve → kernel/search}/morning-test-fixtures.js +0 -0
  483. /package/dist/{retrieve → kernel/search}/morning.js +0 -0
  484. /package/dist/{retrieve → kernel/search}/semantic-contract.d.ts +0 -0
  485. /package/dist/{retrieve → kernel/search}/semantic-contract.js +0 -0
  486. /package/dist/{mcp → kernel/semantic}/semantic-retrieve.d.ts +0 -0
  487. /package/dist/{mcp → kernel/semantic}/semantic-schemas.d.ts +0 -0
  488. /package/dist/{mcp → kernel/semantic}/semantic-schemas.js +0 -0
  489. /package/dist/{mcp → kernel/semantic}/semantic-tool-schemas.d.ts +0 -0
  490. /package/dist/{hook → vendors/claude/hook}/post-tool-use.d.ts +0 -0
  491. /package/dist/{hook → vendors/claude/hook}/pre-tool-use.d.ts +0 -0
  492. /package/dist/{hook → vendors/claude/hook}/pre-tool-use.js +0 -0
  493. /package/dist/{hook → vendors/claude/hook}/stdin.d.ts +0 -0
  494. /package/dist/{hook → vendors/claude/hook}/stdin.js +0 -0
@@ -0,0 +1,753 @@
1
+ /**
2
+ * Vault → engine store synchronisation.
3
+ *
4
+ * RALPLAN constraints (approved):
5
+ * - vec/HyDE require sqlite-vec + real embeddings; no fake/hash fallback.
6
+ * - embed=false is a lex-only sync: it MUST NOT fabricate vectors.
7
+ * - Fingerprint mismatch fails fast by default; destructive rebuild only with explicit force.
8
+ */
9
+ import { closeSync, existsSync, fsyncSync, linkSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeSync, } from "node:fs";
10
+ import { readdir, readFile } from "node:fs/promises";
11
+ import path from "node:path";
12
+ import { chunkDocument } from "./chunker.js";
13
+ import { requireRealEmbeddingProvider } from "./provider.js";
14
+ import { openEngineStore, openEngineStoreCore } from "./store.js";
15
+ import { makeEmbeddingIdentity } from "./identity.js";
16
+ // ---------------------------------------------------------------------------
17
+ // Internal vault walker
18
+ // ---------------------------------------------------------------------------
19
+ const SKIP_DIRS = new Set(["node_modules", ".git", ".oms"]);
20
+ function isEnoent(error) {
21
+ return typeof error === "object" && error !== null && "code" in error &&
22
+ error.code === "ENOENT";
23
+ }
24
+ export async function* walkMarkdown(dir, base) {
25
+ let entries;
26
+ try {
27
+ entries = await readdir(dir, { withFileTypes: true });
28
+ }
29
+ catch (error) {
30
+ if (isEnoent(error))
31
+ return;
32
+ throw new Error(`Unable to scan vault directory "${dir}": ${error instanceof Error ? error.message : String(error)}`, {
33
+ cause: error,
34
+ });
35
+ }
36
+ for (const entry of entries) {
37
+ if (SKIP_DIRS.has(entry.name))
38
+ continue;
39
+ const fullPath = path.join(dir, entry.name);
40
+ if (entry.isDirectory()) {
41
+ yield* walkMarkdown(fullPath, base);
42
+ }
43
+ else if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
44
+ yield path.relative(base, fullPath).replace(/\\/g, "/");
45
+ }
46
+ }
47
+ }
48
+ function explicitMarkdownFiles(vault, collectionRelative, files) {
49
+ const selected = new Set();
50
+ for (const value of files) {
51
+ if (typeof value !== "string" || value.trim().length === 0) {
52
+ throw new Error("Embedding sync files must contain non-empty vault-relative paths.");
53
+ }
54
+ const normalized = value.replace(/\\/g, "/");
55
+ if (path.isAbsolute(normalized)) {
56
+ throw new Error("Embedding sync files must stay inside the vault.");
57
+ }
58
+ const fullPath = path.resolve(vault, normalized);
59
+ const relPath = path.relative(vault, fullPath).replace(/\\/g, "/");
60
+ if (relPath === ".." || relPath.startsWith("../") || !relPath.toLowerCase().endsWith(".md")) {
61
+ throw new Error(`Embedding sync file must be a markdown path inside the vault: ${value}`);
62
+ }
63
+ if (relPath.split("/").some((segment) => SKIP_DIRS.has(segment))) {
64
+ throw new Error(`Embedding sync file is inside an ignored vault directory: ${value}`);
65
+ }
66
+ if (!isDocumentInCollection(relPath, collectionRelative))
67
+ continue;
68
+ selected.add(relPath);
69
+ }
70
+ return [...selected].sort((left, right) => left.localeCompare(right));
71
+ }
72
+ async function* selectedMarkdownFiles(vault, collectionRoot, collectionRelative, files) {
73
+ if (files === undefined) {
74
+ yield* walkMarkdown(collectionRoot, vault);
75
+ return;
76
+ }
77
+ for (const relPath of explicitMarkdownFiles(vault, collectionRelative, files)) {
78
+ yield relPath;
79
+ }
80
+ }
81
+ // ---------------------------------------------------------------------------
82
+ // Identity helpers
83
+ // ---------------------------------------------------------------------------
84
+ function storeHasAnyChunks(store) {
85
+ return store.listDocPaths().length > 0;
86
+ }
87
+ function identityEquivalent(a, b) {
88
+ const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
89
+ for (const key of keys) {
90
+ if (a[key] !== b[key]) {
91
+ return false;
92
+ }
93
+ }
94
+ return true;
95
+ }
96
+ function providerIdentityMetadata(provider) {
97
+ return provider;
98
+ }
99
+ /**
100
+ * Acquire the writer lock without a dependency on a native locking package.
101
+ *
102
+ * A complete owner payload is published through a temporary O_EXCL inode and
103
+ * atomically claimed with a hard link. The file records the owner PID so a
104
+ * process killed between claim and release does not strand every future sync.
105
+ * A live owner is always rejected (rather than silently waiting), which keeps
106
+ * concurrent writers loud and bounded.
107
+ */
108
+ export function acquireEngineStoreWriterLock(dbPath) {
109
+ const lockPath = `${dbPath}.lock`;
110
+ const lockDir = path.dirname(lockPath);
111
+ mkdirSync(lockDir, { recursive: true });
112
+ for (;;) {
113
+ // Publish the owner payload through a completed temporary inode, then
114
+ // claim the visible path with a hard link. Unlike open(..., "wx") followed
115
+ // by write(), this never exposes an empty/partial lock file for stale
116
+ // cleanup to mistake for a dead owner.
117
+ const tempPath = path.join(lockDir, `.${path.basename(lockPath)}.${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}.tmp`);
118
+ let tempFd;
119
+ const ownerText = `${process.pid}\n${Date.now()}-${Math.random().toString(16).slice(2)}\n`;
120
+ try {
121
+ tempFd = openSync(tempPath, "wx");
122
+ const owner = Buffer.from(ownerText, "utf8");
123
+ writeSync(tempFd, owner, 0, owner.length, 0);
124
+ fsyncSync(tempFd);
125
+ closeSync(tempFd);
126
+ tempFd = undefined;
127
+ linkSync(tempPath, lockPath);
128
+ unlinkSync(tempPath);
129
+ }
130
+ catch (err) {
131
+ const code = err.code;
132
+ if (tempFd !== undefined) {
133
+ try {
134
+ closeSync(tempFd);
135
+ }
136
+ catch {
137
+ // Preserve the original claim/write error.
138
+ }
139
+ }
140
+ try {
141
+ unlinkSync(tempPath);
142
+ }
143
+ catch (cleanupErr) {
144
+ if (cleanupErr.code !== "ENOENT")
145
+ throw cleanupErr;
146
+ }
147
+ if (code !== "EEXIST")
148
+ throw err;
149
+ let observedLockText;
150
+ let ownerPid;
151
+ try {
152
+ observedLockText = readFileSync(lockPath, "utf8");
153
+ const ownerText = observedLockText.trim().split(/\r?\n/, 1)[0] ?? "";
154
+ if (/^\d+$/.test(ownerText))
155
+ ownerPid = Number.parseInt(ownerText, 10);
156
+ }
157
+ catch {
158
+ // An unreadable lock is treated as stale.
159
+ }
160
+ if (ownerPid !== undefined && Number.isInteger(ownerPid) && ownerPid > 0) {
161
+ try {
162
+ process.kill(ownerPid, 0);
163
+ throw new Error(`Embedding sync is already in progress (lock: ${lockPath}).`);
164
+ }
165
+ catch (probeErr) {
166
+ if (probeErr.code !== "ESRCH")
167
+ throw probeErr;
168
+ }
169
+ }
170
+ // Remove exactly the stale inode that was inspected. Renaming it away
171
+ // first prevents a second stale cleaner from unlinking a newly claimed
172
+ // lock between its read and delete operations.
173
+ const stalePath = path.join(lockDir, `.${path.basename(lockPath)}.stale-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`);
174
+ try {
175
+ renameSync(lockPath, stalePath);
176
+ }
177
+ catch (renameErr) {
178
+ if (renameErr.code === "ENOENT")
179
+ continue;
180
+ throw renameErr;
181
+ }
182
+ // Another stale cleaner may have replaced the path between our read and
183
+ // rename. Compare the complete owner payload (which includes a nonce for
184
+ // locks created here) before deleting the moved inode.
185
+ let movedLockText;
186
+ try {
187
+ movedLockText = readFileSync(stalePath, "utf8");
188
+ }
189
+ catch {
190
+ // Treat an unreadable moved inode as a failed identity check.
191
+ }
192
+ if (observedLockText === undefined || movedLockText !== observedLockText) {
193
+ let restored = false;
194
+ try {
195
+ linkSync(stalePath, lockPath);
196
+ restored = true;
197
+ }
198
+ catch (restoreErr) {
199
+ const restoreCode = restoreErr.code;
200
+ if (restoreCode !== "EEXIST" && restoreCode !== "ENOENT")
201
+ throw restoreErr;
202
+ }
203
+ if (restored) {
204
+ try {
205
+ unlinkSync(stalePath);
206
+ }
207
+ catch (unlinkErr) {
208
+ if (unlinkErr.code !== "ENOENT")
209
+ throw unlinkErr;
210
+ }
211
+ }
212
+ continue;
213
+ }
214
+ try {
215
+ unlinkSync(stalePath);
216
+ }
217
+ catch (unlinkErr) {
218
+ if (unlinkErr.code !== "ENOENT") {
219
+ // Keep the stale inode visible when cleanup fails, unless another
220
+ // writer already claimed the path after the atomic rename.
221
+ try {
222
+ linkSync(stalePath, lockPath);
223
+ }
224
+ catch (restoreErr) {
225
+ const restoreCode = restoreErr.code;
226
+ if (restoreCode !== "EEXIST" && restoreCode !== "ENOENT")
227
+ throw restoreErr;
228
+ }
229
+ throw unlinkErr;
230
+ }
231
+ }
232
+ continue;
233
+ }
234
+ let released = false;
235
+ return () => {
236
+ if (released)
237
+ return;
238
+ released = true;
239
+ try {
240
+ if (readFileSync(lockPath, "utf8") !== ownerText)
241
+ return;
242
+ unlinkSync(lockPath);
243
+ }
244
+ catch (err) {
245
+ if (err.code !== "ENOENT")
246
+ throw err;
247
+ }
248
+ };
249
+ }
250
+ }
251
+ function crashAt(point, expected) {
252
+ if (point === expected) {
253
+ throw new Error(`Injected generation swap crash at ${expected}.`);
254
+ }
255
+ }
256
+ function formatMismatchReason(args) {
257
+ const stored = args.stored;
258
+ const cfg = args.configured;
259
+ const storedText = stored
260
+ ? `stored=${stored.provider}/${stored.model} dim=${stored.dimensions} fp=${stored.fingerprint.slice(0, 12)}`
261
+ : "stored=<none>";
262
+ const cfgText = cfg
263
+ ? `configured=${cfg.provider}/${cfg.model} dim=${cfg.dimensions} fp=${cfg.fingerprint.slice(0, 12)}`
264
+ : "configured=<none>";
265
+ return (`Embedding identity mismatch (${storedText}; ${cfgText}). ` +
266
+ `Rebuild vectors with ${args.forceFlagName}.`);
267
+ }
268
+ function isDocumentInCollection(docPath, collectionRoot) {
269
+ return collectionRoot === "" ||
270
+ docPath === collectionRoot ||
271
+ docPath.startsWith(`${collectionRoot}/`);
272
+ }
273
+ async function syncDocument(opts) {
274
+ let content;
275
+ try {
276
+ content = await readFile(path.join(opts.vault, opts.relPath), "utf-8");
277
+ }
278
+ catch {
279
+ return;
280
+ }
281
+ opts.counters.scanned++;
282
+ const chunks = chunkDocument(opts.relPath, content, opts.chunkerOpts);
283
+ const storedShas = opts.store.getShas(opts.relPath);
284
+ const chunkCountChanged = storedShas.size !== chunks.length;
285
+ const fullRewrite = opts.rebuildAllVectors || chunkCountChanged;
286
+ if (!opts.shouldEmbed) {
287
+ // Lex-only: update meta+FTS only.
288
+ // When the chunk-count changes we clear and reinsert to avoid orphaned extra chunks.
289
+ if (fullRewrite) {
290
+ opts.store.clearDocument(opts.relPath);
291
+ opts.store.upsertLex(chunks);
292
+ opts.counters.added += chunks.length;
293
+ return;
294
+ }
295
+ const toUpsert = [];
296
+ for (const chunk of chunks) {
297
+ const storedSha = storedShas.get(chunk.ordinal);
298
+ if (storedSha === chunk.sha) {
299
+ opts.counters.skipped++;
300
+ continue;
301
+ }
302
+ toUpsert.push(chunk);
303
+ if (storedSha === undefined)
304
+ opts.counters.added++;
305
+ else
306
+ opts.counters.updated++;
307
+ }
308
+ if (toUpsert.length > 0)
309
+ opts.store.upsertLex(toUpsert);
310
+ return;
311
+ }
312
+ if (!opts.provider) {
313
+ throw new Error("Internal error: shouldEmbed=true but provider is null.");
314
+ }
315
+ // Vector path
316
+ if (fullRewrite) {
317
+ opts.store.clearDocument(opts.relPath);
318
+ const toUpsert = [];
319
+ for (const chunk of chunks) {
320
+ const vector = await opts.provider.embed(chunk.text);
321
+ toUpsert.push({ ...chunk, vector });
322
+ opts.counters.added++;
323
+ }
324
+ if (toUpsert.length > 0)
325
+ opts.store.upsert(toUpsert);
326
+ return;
327
+ }
328
+ const toUpsert = [];
329
+ for (const chunk of chunks) {
330
+ const storedSha = storedShas.get(chunk.ordinal);
331
+ if (storedSha === chunk.sha) {
332
+ opts.counters.skipped++;
333
+ continue;
334
+ }
335
+ const vector = await opts.provider.embed(chunk.text);
336
+ toUpsert.push({ ...chunk, vector });
337
+ if (storedSha === undefined)
338
+ opts.counters.added++;
339
+ else
340
+ opts.counters.updated++;
341
+ }
342
+ if (toUpsert.length > 0)
343
+ opts.store.upsert(toUpsert);
344
+ }
345
+ async function rebuildGenerationAtomically(opts) {
346
+ if (opts.dbPath === ":memory:") {
347
+ throw new Error("Atomic generation swap requires a file-backed engine store.");
348
+ }
349
+ const directory = path.dirname(opts.dbPath);
350
+ const base = path.basename(opts.dbPath);
351
+ let shadowPath;
352
+ let shadow = null;
353
+ let swapped = false;
354
+ let swapPreparationStarted = false;
355
+ try {
356
+ // Keep the shadow in the same directory so rename(2) is one filesystem
357
+ // operation. The random suffix also prevents a previous crash from
358
+ // colliding with a future generation.
359
+ for (let attempt = 0; attempt < 10; attempt += 1) {
360
+ const candidate = path.join(directory, `.${base}.generation-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}.sqlite`);
361
+ if (!existsSync(candidate)) {
362
+ shadowPath = candidate;
363
+ break;
364
+ }
365
+ }
366
+ if (!shadowPath)
367
+ throw new Error("Could not allocate a shadow embedding generation path.");
368
+ shadow = openEngineStore(shadowPath, opts.provider.dimensions);
369
+ if (!shadow.capabilities().vecAvailable) {
370
+ throw new Error("Vector layer unavailable while building the shadow generation.");
371
+ }
372
+ const expectedDocs = new Set();
373
+ for await (const relPath of selectedMarkdownFiles(opts.vault, opts.collectionRoot, opts.collectionRelative, opts.files)) {
374
+ expectedDocs.add(relPath);
375
+ await syncDocument({
376
+ relPath,
377
+ vault: opts.vault,
378
+ store: shadow,
379
+ provider: opts.provider,
380
+ shouldEmbed: true,
381
+ chunkerOpts: opts.chunkerOpts,
382
+ counters: opts.counters,
383
+ rebuildAllVectors: true,
384
+ });
385
+ }
386
+ crashAt(opts.crashPoint, "after-build");
387
+ // Identity is written only to the inactive generation. The live
388
+ // generation remains byte-for-byte unchanged until the rename below.
389
+ shadow.writeEmbeddingIdentity(opts.configuredIdentity);
390
+ const writtenIdentity = shadow.readEmbeddingIdentity();
391
+ if (writtenIdentity === null || !identityEquivalent(writtenIdentity, opts.configuredIdentity)) {
392
+ throw new Error("Shadow embedding generation failed identity validation.");
393
+ }
394
+ const actualDocs = new Set(shadow.listDocPaths());
395
+ if (actualDocs.size !== expectedDocs.size || [...expectedDocs].some((doc) => !actualDocs.has(doc))) {
396
+ throw new Error("Shadow embedding generation failed document validation.");
397
+ }
398
+ crashAt(opts.crashPoint, "after-validation");
399
+ // Keep the active handle open while building and validating the shadow.
400
+ // Closing it only here ensures no active bytes or identity can change
401
+ // before validation has completed. Any long-lived reader owned by the
402
+ // caller must close at the same boundary so its WAL/SHM descriptors do
403
+ // not survive the rename.
404
+ swapPreparationStarted = true;
405
+ opts.onGenerationSwapPrepare?.();
406
+ opts.closeActive();
407
+ // close() checkpoints WAL and releases every shadow descriptor before
408
+ // rename. The active sidecars are removed only after every known active
409
+ // handle has closed; stale files from an interrupted run are harmless.
410
+ unlinkStaleSidecars(opts.dbPath);
411
+ shadow.close();
412
+ shadow = null;
413
+ crashAt(opts.crashPoint, "before-swap");
414
+ // rename is atomic on the same filesystem: readers observe either the
415
+ // complete old database or the complete new one, never a partial build.
416
+ // Future EAV/axis state deliberately lives in its own database and is not
417
+ // copied into this embedding generation.
418
+ unlinkStaleSidecars(shadowPath);
419
+ renameGeneration(shadowPath, opts.dbPath);
420
+ swapped = true;
421
+ opts.onSwap?.();
422
+ opts.onGenerationSwapComplete?.(true);
423
+ crashAt(opts.crashPoint, "after-swap");
424
+ }
425
+ finally {
426
+ try {
427
+ shadow?.close();
428
+ if (shadowPath && !swapped) {
429
+ unlinkStaleSidecars(shadowPath);
430
+ try {
431
+ unlinkSync(shadowPath);
432
+ }
433
+ catch (err) {
434
+ if (err.code !== "ENOENT")
435
+ throw err;
436
+ }
437
+ }
438
+ }
439
+ finally {
440
+ // A crash or validation failure after preparation still closed the
441
+ // caller's long-lived handle. Give it a chance to rebind to the intact
442
+ // old generation before releasing the cross-process writer lock.
443
+ if (swapPreparationStarted && !swapped) {
444
+ opts.onGenerationSwapComplete?.(false);
445
+ }
446
+ }
447
+ }
448
+ }
449
+ function unlinkStaleSidecars(dbPath) {
450
+ for (const suffix of ["-wal", "-shm"]) {
451
+ try {
452
+ unlinkSync(`${dbPath}${suffix}`);
453
+ }
454
+ catch (err) {
455
+ if (err.code !== "ENOENT")
456
+ throw err;
457
+ }
458
+ }
459
+ }
460
+ function renameGeneration(shadowPath, activePath) {
461
+ renameSync(shadowPath, activePath);
462
+ }
463
+ // ---------------------------------------------------------------------------
464
+ // Public entry point
465
+ // ---------------------------------------------------------------------------
466
+ export async function syncEngineStore(opts) {
467
+ const vault = path.resolve(opts.vault);
468
+ const collection = opts.collection ?? "vault";
469
+ const collectionRoot = opts.collectionPath ? path.resolve(vault, opts.collectionPath) : vault;
470
+ const collectionRelative = path.relative(vault, collectionRoot).replace(/\\/g, "/");
471
+ const invalidCollectionPath = path.isAbsolute(collectionRelative) ||
472
+ collectionRelative === ".." ||
473
+ collectionRelative.startsWith("../");
474
+ const dbPath = opts.dbPath ?? path.join(vault, ".oms", "engine-store.sqlite");
475
+ const shouldEmbed = opts.embed !== false;
476
+ const force = opts.force === true;
477
+ const persist = opts.persist !== false;
478
+ const warnings = [];
479
+ let provider = null;
480
+ let store = opts.store ?? null;
481
+ const ownsStore = opts.store === undefined;
482
+ let storedIdentity;
483
+ let configuredIdentity;
484
+ let generationSwapped = false;
485
+ let releaseLock = null;
486
+ try {
487
+ if (invalidCollectionPath) {
488
+ throw new Error("Embedding sync collectionPath must stay inside the vault.");
489
+ }
490
+ if (!shouldEmbed) {
491
+ // Lex-only path: no embedding provider required.
492
+ if (persist)
493
+ releaseLock = acquireEngineStoreWriterLock(dbPath);
494
+ store ??= openEngineStoreCore(dbPath);
495
+ warnings.push("embed=false: lexical index updated; no vectors generated");
496
+ const counters = { scanned: 0, added: 0, updated: 0, skipped: 0 };
497
+ for await (const relPath of selectedMarkdownFiles(vault, collectionRoot, collectionRelative, opts.files)) {
498
+ await syncDocument({
499
+ relPath,
500
+ vault,
501
+ store,
502
+ provider: null,
503
+ shouldEmbed: false,
504
+ chunkerOpts: opts.chunkerOpts,
505
+ counters,
506
+ rebuildAllVectors: false,
507
+ });
508
+ }
509
+ return {
510
+ available: true,
511
+ warnings,
512
+ collection,
513
+ dbPath,
514
+ scanned: counters.scanned,
515
+ added: counters.added,
516
+ updated: counters.updated,
517
+ skipped: counters.skipped,
518
+ };
519
+ }
520
+ const descriptor = opts.embeddingDescriptor;
521
+ const embeddingProvider = (opts.embeddingProvider ??
522
+ descriptor?.provider ??
523
+ "").trim();
524
+ const embeddingModel = (opts.embeddingModel ??
525
+ (descriptor?.path || descriptor?.modelPath) ??
526
+ descriptor?.model ??
527
+ "").trim();
528
+ const embeddingDimensions = opts.embeddingDimensions ?? descriptor?.dimensions;
529
+ const embeddingContext = opts.embeddingContext ?? descriptor?.context;
530
+ const embeddingContextLength = opts.embeddingContextLength ?? descriptor?.contextLength;
531
+ const embeddingContextTokens = opts.embeddingContextTokens ?? descriptor?.contextTokens;
532
+ const embeddingMrlDim = opts.embeddingMrlDim ?? descriptor?.mrlDim;
533
+ const embeddingNormalization = opts.embeddingNormalization ?? descriptor?.normalization;
534
+ const embeddingPrefixScheme = opts.embeddingPrefixScheme ?? descriptor?.prefixScheme;
535
+ if (descriptor !== undefined) {
536
+ const descriptorContext = embeddingContext ?? embeddingContextLength ?? embeddingContextTokens;
537
+ if (typeof embeddingDimensions !== "number" ||
538
+ typeof descriptorContext !== "number" ||
539
+ typeof embeddingMrlDim !== "number" ||
540
+ typeof embeddingNormalization !== "string" ||
541
+ !embeddingNormalization.trim() ||
542
+ typeof embeddingPrefixScheme !== "string" ||
543
+ !embeddingPrefixScheme.trim()) {
544
+ throw new Error("Embedding descriptor is incomplete. dimensions/context/mrlDim/normalization/prefixScheme are required.");
545
+ }
546
+ }
547
+ provider = requireRealEmbeddingProvider({
548
+ provider: embeddingProvider,
549
+ model: embeddingModel,
550
+ dimensions: embeddingDimensions,
551
+ context: embeddingContext,
552
+ contextLength: embeddingContextLength,
553
+ contextTokens: embeddingContextTokens,
554
+ mrlDim: embeddingMrlDim,
555
+ normalization: embeddingNormalization,
556
+ prefixScheme: embeddingPrefixScheme,
557
+ });
558
+ const metadata = providerIdentityMetadata(provider);
559
+ const contextLength = embeddingContext ??
560
+ embeddingContextLength ??
561
+ embeddingContextTokens ??
562
+ metadata.context ??
563
+ metadata.contextLength;
564
+ const mrlDim = embeddingMrlDim ?? metadata.mrlDim;
565
+ const normalization = embeddingNormalization ?? metadata.normalization;
566
+ const prefixScheme = embeddingPrefixScheme ?? metadata.prefixScheme;
567
+ if (contextLength === undefined || mrlDim === undefined || normalization === undefined || prefixScheme === undefined) {
568
+ throw new Error("Embedding descriptor is incomplete. dimensions/context/mrlDim/normalization/prefixScheme are required for vector sync.");
569
+ }
570
+ const identity = makeEmbeddingIdentity({
571
+ provider: embeddingProvider,
572
+ model: embeddingModel,
573
+ dimensions: provider.dimensions,
574
+ contextLength,
575
+ mrlDim,
576
+ normalization,
577
+ prefixScheme,
578
+ });
579
+ configuredIdentity = identity;
580
+ // Lock before opening the write handle so identity inspection and every
581
+ // subsequent write observe one writer generation.
582
+ if (persist)
583
+ releaseLock = acquireEngineStoreWriterLock(dbPath);
584
+ // A caller-owned handle is used as-is and is never closed by this
585
+ // function. Otherwise sync owns the handle it opens below.
586
+ store ??= openEngineStore(dbPath, provider.dimensions);
587
+ if (!store.capabilities().vecAvailable) {
588
+ warnings.push("Vector layer unavailable: sqlite-vec not loaded");
589
+ return {
590
+ available: false,
591
+ reason: "Vector layer unavailable: sqlite-vec not loaded.",
592
+ warnings,
593
+ collection,
594
+ dbPath,
595
+ scanned: 0,
596
+ added: 0,
597
+ updated: 0,
598
+ skipped: 0,
599
+ configuredIdentity,
600
+ };
601
+ }
602
+ try {
603
+ storedIdentity = store.readEmbeddingIdentity() ?? undefined;
604
+ }
605
+ catch (error) {
606
+ // A stale metadata version is intentionally not decoded as an identity.
607
+ // Force mode can still rebuild it through the atomic generation path;
608
+ // without force, preserve the loud rejection reason.
609
+ if (force && error instanceof Error && /metadata version/i.test(error.message)) {
610
+ storedIdentity = undefined;
611
+ }
612
+ else {
613
+ throw error;
614
+ }
615
+ }
616
+ // If there are indexed chunks on disk but no stored identity, treat as mismatch.
617
+ const hasStoredChunks = storeHasAnyChunks(store);
618
+ const missingStoredIdentity = storedIdentity === undefined;
619
+ const mismatch = (storedIdentity !== undefined &&
620
+ !identityEquivalent(storedIdentity, identity)) ||
621
+ (missingStoredIdentity && hasStoredChunks);
622
+ if (mismatch && !force) {
623
+ return {
624
+ available: false,
625
+ reason: formatMismatchReason({
626
+ stored: storedIdentity,
627
+ configured: configuredIdentity,
628
+ forceFlagName: "--force/force:true",
629
+ }),
630
+ warnings,
631
+ collection,
632
+ dbPath,
633
+ scanned: 0,
634
+ added: 0,
635
+ updated: 0,
636
+ skipped: 0,
637
+ storedIdentity,
638
+ configuredIdentity,
639
+ };
640
+ }
641
+ if (mismatch && force) {
642
+ if (!ownsStore) {
643
+ throw new Error("Force reindex requires an internally-owned store; close the caller-owned handle and retry without store.");
644
+ }
645
+ if (collectionRelative !== "") {
646
+ const outOfScope = store.listDocPaths().filter((docPath) => !isDocumentInCollection(docPath, collectionRelative));
647
+ if (outOfScope.length > 0) {
648
+ throw new Error(`Scoped force reindex refused: ${outOfScope.length} indexed document(s) fall outside "${collectionRelative}". ` +
649
+ "Run an unscoped force reindex to replace the complete generation.");
650
+ }
651
+ }
652
+ // Build a complete shadow generation before touching the active path.
653
+ // Caller-owned handles are rejected above rather than being closed or
654
+ // left pointing at a removed table.
655
+ const counters = { scanned: 0, added: 0, updated: 0, skipped: 0 };
656
+ await rebuildGenerationAtomically({
657
+ dbPath,
658
+ vault,
659
+ collectionRoot,
660
+ collectionRelative,
661
+ files: opts.files,
662
+ provider,
663
+ configuredIdentity: identity,
664
+ chunkerOpts: opts.chunkerOpts,
665
+ counters,
666
+ crashPoint: opts.crashPoint,
667
+ onGenerationSwapPrepare: opts.onGenerationSwapPrepare,
668
+ onGenerationSwapComplete: opts.onGenerationSwapComplete,
669
+ onSwap: () => {
670
+ generationSwapped = true;
671
+ },
672
+ closeActive: () => {
673
+ if (!store)
674
+ throw new Error("Internal error: active store is already closed.");
675
+ store.close();
676
+ store = null;
677
+ },
678
+ });
679
+ // The active handle was intentionally closed before the atomic rename.
680
+ // Reopen it so callers that inspect the owned handle after the swap do
681
+ // not retain prepared statements bound to the retired inode.
682
+ store = openEngineStore(dbPath, provider.dimensions);
683
+ return {
684
+ available: true,
685
+ warnings,
686
+ collection,
687
+ dbPath,
688
+ scanned: counters.scanned,
689
+ added: counters.added,
690
+ updated: counters.updated,
691
+ skipped: counters.skipped,
692
+ storedIdentity,
693
+ configuredIdentity,
694
+ generationSwapped,
695
+ };
696
+ }
697
+ if (!store)
698
+ throw new Error("Internal error: engine store is null after preparation.");
699
+ const counters = { scanned: 0, added: 0, updated: 0, skipped: 0 };
700
+ for await (const relPath of selectedMarkdownFiles(vault, collectionRoot, collectionRelative, opts.files)) {
701
+ await syncDocument({
702
+ relPath,
703
+ vault,
704
+ store,
705
+ provider,
706
+ shouldEmbed: true,
707
+ chunkerOpts: opts.chunkerOpts,
708
+ counters,
709
+ rebuildAllVectors: false,
710
+ });
711
+ }
712
+ // Persist configured embedding identity only after a successful embed=true
713
+ // incremental sync.
714
+ store.writeEmbeddingIdentity(identity);
715
+ return {
716
+ available: true,
717
+ warnings,
718
+ collection,
719
+ dbPath,
720
+ scanned: counters.scanned,
721
+ added: counters.added,
722
+ updated: counters.updated,
723
+ skipped: counters.skipped,
724
+ storedIdentity,
725
+ configuredIdentity,
726
+ generationSwapped,
727
+ };
728
+ }
729
+ catch (err) {
730
+ const reason = err instanceof Error ? err.message : String(err);
731
+ return {
732
+ available: false,
733
+ reason,
734
+ warnings,
735
+ collection,
736
+ dbPath,
737
+ scanned: 0,
738
+ added: 0,
739
+ updated: 0,
740
+ skipped: 0,
741
+ storedIdentity,
742
+ configuredIdentity,
743
+ generationSwapped,
744
+ };
745
+ }
746
+ finally {
747
+ await provider?.dispose().catch(() => undefined);
748
+ if (ownsStore)
749
+ store?.close();
750
+ releaseLock?.();
751
+ }
752
+ }
753
+ //# sourceMappingURL=sync.js.map