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
@@ -2,24 +2,27 @@ import { readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
- import { CallToolRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
6
- import { parseNote } from "../conventions/frontmatter.js";
7
- import { validateFrontmatter } from "../conventions/validate.js";
8
- import { lintVault } from "../engine/conventions/vault-lint.js";
9
- import { safeVaultNotePath, writeNote, } from "../capture/safe.js";
10
- import { buildGraphCache, graphCacheStatus, graphCachePath, lazyLoadNoteBody, } from "../graph/cache.js";
11
- import { readBundledPackageVersion } from "../core/runtime/assets.js";
12
- import { resolveActiveOntology } from "../ontology/active.js";
13
- import { resolveConcept } from "../core/ontology/resolver.js";
14
- import { retrieveMorningContext } from "../retrieve/morning.js";
5
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
6
+ import { parseNote } from "../kernel/conventions/frontmatter.js";
7
+ import { validateFrontmatter } from "../kernel/conventions/validate.js";
8
+ import { lintVault } from "../kernel/engine/conventions/vault-lint.js";
9
+ import { safeVaultNotePath, writeNote, } from "../kernel/capture/safe.js";
10
+ import { graphCacheStatus, lazyLoadNoteBody, } from "../kernel/graph/cache.js";
11
+ import { readBundledPackageVersion } from "../kernel/runtime/assets.js";
12
+ import { resolveActiveOntology } from "../kernel/ontology/active.js";
13
+ import { resolveConcept } from "../kernel/ontology/resolver.js";
14
+ import { retrieveMorningContext } from "../kernel/search/morning.js";
15
+ import { repairDoctor } from "../kernel/doctor/service.js";
15
16
  import { makeEngineMorningBackend } from "./engine-morning-backend.js";
16
- import { handleSemanticTool, isEngineSemanticOp, isEngineDocumentOp, isModelOptionalSemanticQueryOp, semanticMcpTools, semanticOptionsFromArgs, retrieveContextSemanticInputProperties, } from "./semantic-retrieve.js";
17
- import { assembleCoreSemanticEngine, assembleGraphOnlyEngine } from "../engine/assemble.js";
18
- import { assembleFullSemanticEngine, embeddingConfigPresent } from "./semantic-engine.js";
17
+ import { handleSemanticTool, isEngineSemanticOp, isEngineDocumentOp, isModelOptionalSemanticQueryOp, semanticOptionsFromArgs, } from "../kernel/semantic/semantic-retrieve.js";
18
+ import { semanticQueryOptionsFromArgs } from "../kernel/semantic/semantic-retrieve-args.js";
19
+ import { assembleEphemeralCoreSemanticEngine, assembleCoreSemanticEngineReadOnly, assembleCoreSemanticEngine, assembleEngineReadOnly, assembleGraphOnlyEngine, } from "../kernel/engine/assemble.js";
20
+ import { assembleFullSemanticEngine, embeddingConfigPresent, } from "../kernel/semantic/semantic-engine.js";
19
21
  import { applyLinksForNote, linkApplyPayload, suggestLinksForNote } from "./link-tools.js";
22
+ import { EngineSearchBackend, requiresEmbeddings } from "../kernel/searchbackend/engine-search-backend.js";
20
23
  import { buildServerInstructions, cachedUpdateNotice, scheduleUpdateNoticeRefresh, } from "./update-notice.js";
21
24
  const SERVER_VERSION = readBundledPackageVersion();
22
- export const BASE_SERVER_INSTRUCTIONS = "Oh My Second Brain exposes ontology/status/cache/retrieval tools and the write tool. write is gated by a verified vault target (a vault inferred from the current directory is refused), vault confinement, and contract validation.";
25
+ export const BASE_SERVER_INSTRUCTIONS = "Oh My Second Brain exposes write, search, link, status, and doctor tools. oms_write and doctor repair operations are gated by a verified vault target (a vault inferred from the current directory is refused); oms_write also enforces vault confinement and contract validation.";
23
26
  function jsonText(value) {
24
27
  return {
25
28
  content: [
@@ -41,6 +44,11 @@ function errorText(message) {
41
44
  ],
42
45
  };
43
46
  }
47
+ class SemanticIndexUnavailableError extends Error {
48
+ constructor() {
49
+ super("The semantic index has not been built yet. Run `oms semantic sync` to build it.");
50
+ }
51
+ }
44
52
  function isRecord(value) {
45
53
  return typeof value === "object" && value !== null && !Array.isArray(value);
46
54
  }
@@ -66,246 +74,89 @@ function conceptSummary(concept) {
66
74
  })),
67
75
  };
68
76
  }
69
- export const omsMcpTools = [
70
- {
71
- name: "oms_graph_status",
72
- title: "Oh My Second Brain graph/status",
73
- description: "Read-only status for the active Oh My Second Brain ontology, graph/search cache phase, and gated write-tool posture.",
74
- inputSchema: {
75
- type: "object",
76
- properties: {},
77
- },
78
- annotations: {
79
- readOnlyHint: true,
80
- destructiveHint: false,
81
- idempotentHint: true,
82
- openWorldHint: false,
83
- },
84
- },
85
- {
86
- name: "oms_graph_build",
87
- title: "Oh My Second Brain graph build",
88
- description: "Build the derived graph/search cache from markdown, frontmatter, folders, and wikilinks.",
89
- inputSchema: {
90
- type: "object",
91
- properties: {},
92
- },
93
- annotations: {
94
- readOnlyHint: false,
95
- destructiveHint: false,
96
- idempotentHint: true,
97
- openWorldHint: false,
98
- },
99
- },
100
- {
101
- name: "oms_list_concepts",
102
- title: "Oh My Second Brain list concepts",
103
- description: "Read the active ontology concepts, frontmatter axes, folder bindings, and retrieval views.",
104
- inputSchema: {
105
- type: "object",
106
- properties: {},
107
- },
108
- annotations: {
109
- readOnlyHint: true,
110
- destructiveHint: false,
111
- idempotentHint: true,
112
- openWorldHint: false,
113
- },
114
- },
115
- {
116
- name: "oms_retrieve_by_axis",
117
- title: "Oh My Second Brain retrieve by axis",
118
- description: "Axis-first retrieval over the derived cache; optional lexical query only ranks inside the narrowed candidate set.",
119
- inputSchema: {
120
- type: "object",
121
- properties: {
122
- concept: { type: "string" },
123
- folder: { type: "string" },
124
- property: { type: "string" },
125
- value: { type: "string" },
126
- wikilink: { type: "string" },
127
- query: { type: "string" },
128
- limit: { type: "number" },
129
- },
130
- },
131
- annotations: {
132
- readOnlyHint: true,
133
- destructiveHint: false,
134
- idempotentHint: true,
135
- openWorldHint: false,
136
- },
137
- },
138
- {
139
- name: "oms_retrieve_context",
140
- title: "Oh My Second Brain retrieve context",
141
- description: "Live local graph retrieval with axis seeds, frontmatter/wikilink neighbors, optional OMS semantic candidates, and no warm-cache requirement.",
142
- inputSchema: {
143
- type: "object",
144
- properties: {
145
- concept: { type: "string" },
146
- folder: { type: "string" },
147
- property: { type: "string" },
148
- value: { type: "string" },
149
- wikilink: { type: "string" },
150
- query: { type: "string" },
151
- limit: { type: "number" },
152
- maxNeighbors: { type: "number" },
153
- useCache: { type: "boolean" },
154
- ...retrieveContextSemanticInputProperties,
155
- },
156
- },
157
- annotations: {
158
- readOnlyHint: false,
159
- destructiveHint: false,
160
- idempotentHint: true,
161
- openWorldHint: false,
162
- },
163
- },
164
- ...semanticMcpTools,
165
- {
166
- name: "oms_lazy_load_note",
167
- title: "Oh My Second Brain lazy-load note body",
168
- description: "Load a selected note body only after axis/search narrowing has selected the note.",
169
- inputSchema: {
170
- type: "object",
171
- properties: {
172
- notePath: {
173
- type: "string",
174
- description: "Vault-relative markdown note path.",
175
- },
176
- },
177
- required: ["notePath"],
178
- },
179
- annotations: {
180
- readOnlyHint: true,
181
- destructiveHint: false,
182
- idempotentHint: true,
183
- openWorldHint: false,
184
- },
185
- },
186
- {
187
- name: "oms_validate_contract",
188
- title: "Oh My Second Brain validate contract",
189
- description: "Read one vault note and validate its frontmatter against the active folder/concept contract.",
190
- inputSchema: {
191
- type: "object",
192
- properties: {
193
- notePath: {
194
- type: "string",
195
- description: "Vault-relative markdown note path, for example references/book.md.",
196
- },
197
- },
198
- required: ["notePath"],
199
- },
200
- annotations: {
201
- readOnlyHint: true,
202
- destructiveHint: false,
203
- idempotentHint: true,
204
- openWorldHint: false,
205
- },
206
- },
207
- {
208
- name: "oms_vault_audit",
209
- title: "Oh My Second Brain vault audit",
210
- description: "Scan vault notes against the active ontology and return a structured violation report. Read-only; the CLI counterpart is `oms audit`.",
211
- inputSchema: {
212
- type: "object",
213
- properties: {
214
- folder: {
215
- type: "string",
216
- description: "Restrict the scan to one top-level vault folder, for example \"references\".",
217
- },
218
- },
219
- },
220
- annotations: {
221
- readOnlyHint: true,
222
- destructiveHint: false,
223
- idempotentHint: true,
224
- openWorldHint: false,
225
- },
226
- },
227
- {
228
- name: "oms_link_suggest",
229
- title: "Oh My Second Brain link suggest",
230
- description: "Propose [[wikilink]] insertions for one note against the vault's term notes. Read-only: returns ranked candidates plus the baseContentHash oms_link_apply requires.",
231
- inputSchema: {
232
- type: "object",
233
- properties: {
234
- notePath: {
235
- type: "string",
236
- description: "Vault-relative markdown note path to linkify, for example notes/sage.md.",
237
- },
238
- folder: {
239
- type: "string",
240
- description: "Restrict the term-note candidate universe to one top-level vault folder.",
241
- },
242
- },
243
- required: ["notePath"],
244
- },
245
- annotations: {
246
- readOnlyHint: true,
247
- destructiveHint: false,
248
- idempotentHint: true,
249
- openWorldHint: false,
250
- },
77
+ const string = { type: "string" };
78
+ const number = { type: "number" };
79
+ const boolean = { type: "boolean" };
80
+ const stringArray = { type: "array", items: string };
81
+ const axisScalar = { anyOf: [string, number, boolean] };
82
+ const axisValue = { anyOf: [axisScalar, { type: "array", items: axisScalar }] };
83
+ const fieldPredicate = {
84
+ type: "object",
85
+ additionalProperties: false,
86
+ properties: {
87
+ contains: axisValue,
88
+ containsAll: { type: "array", items: axisScalar },
89
+ in: { type: "array", items: axisScalar },
90
+ between: { type: "array", items: axisScalar, minItems: 2, maxItems: 2 },
91
+ gte: axisScalar,
92
+ gt: axisScalar,
93
+ lte: axisScalar,
94
+ lt: axisScalar,
95
+ from: axisScalar,
96
+ to: axisScalar,
251
97
  },
252
- {
253
- name: "oms_link_apply",
254
- title: "Oh My Second Brain link apply",
255
- description: "Splice accepted oms_link_suggest candidates into a note and persist through the write kernel. Refuses without writing when baseContentHash no longer matches the note.",
256
- inputSchema: {
98
+ };
99
+ const queryAxes = {
100
+ type: "object",
101
+ additionalProperties: false,
102
+ properties: {
103
+ folder: axisValue,
104
+ field: {
257
105
  type: "object",
258
- properties: {
259
- notePath: {
260
- type: "string",
261
- description: "Vault-relative markdown note path returned by oms_link_suggest.",
262
- },
263
- baseContentHash: {
264
- type: "string",
265
- description: "The baseContentHash from the oms_link_suggest call the candidates came from.",
266
- },
267
- candidateIds: {
268
- type: "array",
269
- items: { type: "string" },
270
- description: "Ids of the accepted candidates from that same oms_link_suggest call.",
271
- },
272
- folder: {
273
- type: "string",
274
- description: "Same candidate-universe folder scope used for the suggest call.",
275
- },
276
- },
277
- required: ["notePath", "baseContentHash", "candidateIds"],
278
- },
279
- annotations: {
280
- readOnlyHint: false,
281
- destructiveHint: true,
282
- idempotentHint: false,
283
- openWorldHint: false,
284
- },
285
- },
286
- {
287
- name: "write",
288
- title: "Oh My Second Brain write",
289
- description: "Write a vault note through the kernel-owned .oms contract. Modes: create, append, update. Returns ask, inbox, written, or rejected.",
290
- inputSchema: {
291
- type: "object",
292
- properties: {
293
- mode: { type: "string", enum: ["create", "append", "update"] },
294
- notePath: { type: "string" },
295
- concept: { type: "string" },
296
- folder: { type: "string" },
297
- filename: { type: "string" },
298
- frontmatter: { type: "object" },
299
- body: { type: "string" },
300
- },
301
- },
302
- annotations: {
303
- readOnlyHint: false,
304
- destructiveHint: false,
305
- idempotentHint: false,
306
- openWorldHint: false,
106
+ additionalProperties: { anyOf: [axisValue, fieldPredicate] },
307
107
  },
108
+ link: axisValue,
308
109
  },
110
+ };
111
+ const searchProperties = {
112
+ query: string, searches: { type: "array", maxItems: 10, items: { type: "object", properties: { type: { ...string, enum: ["lex", "vec", "hyde"] }, query: string }, required: ["type", "query"] } },
113
+ collection: string, collections: stringArray, mode: { ...string, enum: ["query", "search", "vsearch"] }, limit: { ...number, minimum: 0, default: 10 }, candidateLimit: { ...number, minimum: 1 }, rerank: { ...boolean, default: false }, minScore: { ...number, default: 0 }, cursor: string, axes: queryAxes, intent: string, lex: string, vec: string, hyde: string, index: string,
114
+ target: string, targets: stringArray, fromLine: number, lineCount: number, lineLimit: number, maxBytes: number, lineNumbers: boolean, fullPath: boolean,
115
+ };
116
+ const contextProperties = { concept: string, folder: string, property: string, value: string, wikilink: string, query: string, limit: number, maxNeighbors: number, useCache: boolean,
117
+ semanticEnabled: boolean, semanticCollection: string, semanticLimit: number, semanticScope: { ...string, enum: ["global", "graph"] }, semanticMode: searchProperties.mode, semanticIntent: string, semanticSearches: searchProperties.searches, semanticLex: string, semanticVec: string, semanticHyde: string, semanticMinScore: number, semanticAll: boolean, semanticFormat: { ...string, enum: ["json", "files"] }, semanticFull: boolean, semanticLineNumbers: boolean, semanticFullPath: boolean, semanticIndex: string, semanticChunkStrategy: string, semanticCandidateLimit: number, semanticNoRerank: boolean, semanticHydrate: { ...string, enum: ["none", "top", "all", "targets"] }, semanticHydrateTargets: stringArray, semanticHydrateLineLimit: number, semanticHydrateMaxBytes: number, semanticHydrateFromLine: number, semanticHydrateLineCount: number };
118
+ // `folder` + `filename` is a supported addressing form that writeNote still
119
+ // accepts. With `additionalProperties: false` a strict schema is only as
120
+ // complete as its property list, so omitting them silently removed a real
121
+ // capability from every schema-driven client while raw SDK calls kept working.
122
+ const writeProperties = {
123
+ notePath: string,
124
+ folder: string,
125
+ filename: string,
126
+ concept: string,
127
+ frontmatter: { type: "object" },
128
+ body: string,
129
+ };
130
+ const operations = {
131
+ oms_write: [
132
+ { op: "create", name: "write", properties: writeProperties },
133
+ { op: "append", name: "write", properties: writeProperties },
134
+ { op: "update", name: "write", properties: writeProperties },
135
+ ],
136
+ oms_search: [{ op: "context", name: "oms_retrieve_context", properties: contextProperties }, { op: "lazy-load", name: "oms_lazy_load_note", properties: { notePath: string }, required: ["notePath"] }, { op: "concepts", name: "oms_list_concepts" }, { op: "query", name: "oms_semantic_query", properties: searchProperties }, { op: "collections", name: "oms_semantic_collections", properties: { index: string } }, { op: "contexts", name: "oms_semantic_contexts", properties: { index: string } }, { op: "status", name: "oms_semantic_status", properties: { index: string } }, { op: "get-document", name: "oms_get_document", properties: searchProperties, required: ["target"] }, { op: "multi-get-documents", name: "oms_multi_get_documents", properties: searchProperties }],
137
+ oms_link: [{ op: "suggest", name: "oms_link_suggest", properties: { notePath: string, folder: string }, required: ["notePath"] }, { op: "apply", name: "oms_link_apply", properties: { notePath: string, folder: string, baseContentHash: string, candidateIds: stringArray }, required: ["notePath", "baseContentHash", "candidateIds"] }],
138
+ oms_status: [{ name: "oms_graph_status", direct: true }],
139
+ oms_doctor: [{ op: "audit", name: "oms_vault_audit", properties: { folder: string } }, { op: "validate", name: "oms_validate_contract", properties: { notePath: string }, required: ["notePath"] }, { op: "build-graph", name: "oms_graph_build" }, { op: "cleanup", name: "oms_semantic_cleanup", properties: { collection: string, index: string } }, { op: "sync-embeddings", name: "oms_sync_embeddings", properties: { collection: string, ensureCollection: boolean, update: boolean, embed: boolean, force: boolean, pull: boolean, index: string, chunkStrategy: string, maxDocsPerBatch: number, maxBatchMb: number } }],
140
+ };
141
+ function operationSchema(tool) {
142
+ const toolOperations = operations[tool];
143
+ if (!toolOperations)
144
+ throw new Error(`Missing MCP operation definition for ${tool}.`);
145
+ if (toolOperations.length === 1 && toolOperations[0]?.direct) {
146
+ const { properties = {}, required = [] } = toolOperations[0];
147
+ return { type: "object", additionalProperties: false, properties, required: [...required] };
148
+ }
149
+ return { type: "object", oneOf: toolOperations.map(({ op, properties = {}, required = [] }) => ({ additionalProperties: false, properties: { op: { ...string, const: op }, ...properties }, required: ["op", ...required] })) };
150
+ }
151
+ function resolveOperation(tool, op) {
152
+ return operations[tool]?.find((operation) => operation.direct || operation.op === op)?.name;
153
+ }
154
+ export const omsMcpTools = [
155
+ { name: "oms_write", title: "Oh My Second Brain write", description: "Write a vault note through the kernel-owned .oms contract.", inputSchema: operationSchema("oms_write"), annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false } },
156
+ { name: "oms_search", title: "Oh My Second Brain search", description: "Retrieve vault context, semantic search, ontology, and selected documents. `op` selects the operation.", inputSchema: operationSchema("oms_search"), annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: false } },
157
+ { name: "oms_link", title: "Oh My Second Brain link", description: "Suggest or apply wikilinks; `op` selects the operation.", inputSchema: operationSchema("oms_link"), annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false } },
158
+ { name: "oms_status", title: "Oh My Second Brain status", description: "Read-only health and statistics for the active vault.", inputSchema: operationSchema("oms_status"), annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false } },
159
+ { name: "oms_doctor", title: "Oh My Second Brain doctor", description: "Diagnose or repair the vault; `op` selects the operation.", inputSchema: operationSchema("oms_doctor"), annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false } },
309
160
  ];
310
161
  export function createOMSMcpServer(opts) {
311
162
  const vault = path.resolve(opts.vault);
@@ -315,17 +166,12 @@ export function createOMSMcpServer(opts) {
315
166
  // graph cache status scan the vault off the filesystem and need no model.
316
167
  // No model load, no SQLite store, no watcher: side-effect-free per boot (R2).
317
168
  const engine = assembleGraphOnlyEngine({ vault });
318
- // Native engine — semantic layer (lazy): assembled on the FIRST semantic op,
319
- // not at boot, so boot stays stateless (R2). The vec-capable engine opens the
320
- // engine SQLite store on construction and loads the embedding model on first
321
- // embed(). Embedding selection is canonical and explicit: OMS_EMBEDDING_PROVIDER
322
- // (e.g. gguf | upstage) + OMS_EMBEDDING_MODEL (path or model id). Absent either,
323
- // assembleFullSemanticEngine throws a loud, actionable error (ADR-007: no
324
- // hash/fake fallback, no auto-detect) that surfaces via the dispatch catch.
169
+ // Creating semantic engines are shared by all non-search tools, including
170
+ // doctor repairs which must initialize a missing store.
325
171
  let semanticEngine = null;
326
172
  const getSemanticEngine = () => {
327
173
  if (semanticEngine === null) {
328
- semanticEngine = assembleFullSemanticEngine(vault);
174
+ semanticEngine = assembleFullSemanticEngine(vault, opts.reranker);
329
175
  }
330
176
  return semanticEngine;
331
177
  };
@@ -335,10 +181,47 @@ export function createOMSMcpServer(opts) {
335
181
  let coreSemanticEngine = null;
336
182
  const getCoreSemanticEngine = () => {
337
183
  if (coreSemanticEngine === null) {
338
- coreSemanticEngine = assembleCoreSemanticEngine({ vault });
184
+ coreSemanticEngine = assembleCoreSemanticEngine({ vault, reranker: opts.reranker });
339
185
  }
340
186
  return coreSemanticEngine;
341
187
  };
188
+ // Search owns independent read-only slots so it cannot poison doctor repair.
189
+ let readOnlySemanticEngine;
190
+ const getReadOnlySemanticEngine = () => {
191
+ if (readOnlySemanticEngine === undefined) {
192
+ readOnlySemanticEngine = assembleEngineReadOnly({
193
+ vault,
194
+ embeddingProvider: process.env["OMS_EMBEDDING_PROVIDER"],
195
+ embeddingModel: process.env["OMS_EMBEDDING_MODEL"],
196
+ reranker: opts.reranker,
197
+ });
198
+ }
199
+ return readOnlySemanticEngine;
200
+ };
201
+ let readOnlyCoreSemanticEngine;
202
+ const getReadOnlyCoreSemanticEngine = () => {
203
+ if (readOnlyCoreSemanticEngine === undefined) {
204
+ readOnlyCoreSemanticEngine = assembleCoreSemanticEngineReadOnly({ vault, reranker: opts.reranker });
205
+ }
206
+ return readOnlyCoreSemanticEngine;
207
+ };
208
+ let ephemeralCoreSemanticEngine = null;
209
+ let ephemeralCoreSemanticEnginePromise = null;
210
+ const getEphemeralCoreSemanticEngine = async () => {
211
+ if (ephemeralCoreSemanticEngine !== null)
212
+ return ephemeralCoreSemanticEngine;
213
+ if (ephemeralCoreSemanticEnginePromise === null) {
214
+ ephemeralCoreSemanticEnginePromise = (async () => {
215
+ const assembled = assembleEphemeralCoreSemanticEngine({ vault, reranker: opts.reranker });
216
+ ephemeralCoreSemanticEngine = assembled;
217
+ return assembled;
218
+ })().catch((error) => {
219
+ ephemeralCoreSemanticEnginePromise = null;
220
+ throw error;
221
+ });
222
+ }
223
+ return ephemeralCoreSemanticEnginePromise;
224
+ };
342
225
  // A real embedding provider is configured iff the canonical pair is set
343
226
  // (ADR-007). The engine's model-OPTIONAL surface (document reads,
344
227
  // retrieve_context's semantic leg, ReadResource) keys off this to decide
@@ -355,7 +238,51 @@ export function createOMSMcpServer(opts) {
355
238
  // missing auth, store-open failure) must surface its error loudly rather than
356
239
  // silently masquerade as a model-less host (ADR-007). The core fallback is
357
240
  // strictly for the absent-config case.
358
- const resolveDocumentAdapter = () => hasEmbeddingModel() ? getSemanticEngine().adapter : getCoreSemanticEngine().adapter;
241
+ const resolveCreatingDocumentAdapter = () => hasEmbeddingModel() ? getSemanticEngine().adapter : getCoreSemanticEngine().adapter;
242
+ const resolveReadOnlyDocumentAdapter = () => hasEmbeddingModel()
243
+ ? getReadOnlySemanticEngine()?.adapter ?? engine.adapter
244
+ : getReadOnlyCoreSemanticEngine()?.adapter ?? engine.adapter;
245
+ const resolveDocumentAdapter = (publicName) => {
246
+ if (publicName === "oms_search")
247
+ return resolveReadOnlyDocumentAdapter();
248
+ return resolveCreatingDocumentAdapter();
249
+ };
250
+ const resolveReadOnlyIndexAdapter = () => {
251
+ const adapter = hasEmbeddingModel()
252
+ ? getReadOnlySemanticEngine()?.adapter
253
+ : getReadOnlyCoreSemanticEngine()?.adapter;
254
+ if (adapter === undefined || adapter === null)
255
+ throw new SemanticIndexUnavailableError();
256
+ return adapter;
257
+ };
258
+ const resolveReadOnlyLexicalAdapter = async () => {
259
+ const adapter = hasEmbeddingModel()
260
+ ? getReadOnlySemanticEngine()?.adapter
261
+ : getReadOnlyCoreSemanticEngine()?.adapter;
262
+ return adapter ?? (await getEphemeralCoreSemanticEngine()).adapter;
263
+ };
264
+ const hasExplicitEmbeddingIntent = (args) => requiresEmbeddings({
265
+ mode: args?.["mode"] === "vsearch" ? "vsearch" : undefined,
266
+ vec: stringArg(args, "vec"),
267
+ hyde: stringArg(args, "hyde"),
268
+ searches: Array.isArray(args?.["searches"])
269
+ ? args["searches"].flatMap((search) => isRecord(search) &&
270
+ (search["type"] === "lex" || search["type"] === "vec" || search["type"] === "hyde") &&
271
+ typeof search["query"] === "string"
272
+ ? [{ type: search["type"], query: search["query"] }]
273
+ : [])
274
+ : undefined,
275
+ });
276
+ const searchBackend = new EngineSearchBackend((requiresEmbeddings) => requiresEmbeddings
277
+ ? (() => {
278
+ // Validate ADR-007 configuration before probing the read-only store:
279
+ // vector intent is actionable only after its required provider/model
280
+ // pair is present, regardless of whether an index exists yet.
281
+ if (!hasEmbeddingModel())
282
+ return getSemanticEngine().adapter;
283
+ return resolveReadOnlyIndexAdapter();
284
+ })()
285
+ : resolveReadOnlyIndexAdapter(), vault);
359
286
  const server = new Server({ name: "oms", version: SERVER_VERSION }, {
360
287
  capabilities: { tools: {}, resources: {} },
361
288
  // Cache read only: construction must never touch the network. The
@@ -370,43 +297,35 @@ export function createOMSMcpServer(opts) {
370
297
  if (coreSemanticEngine !== null) {
371
298
  void coreSemanticEngine.dispose().catch(() => undefined);
372
299
  }
300
+ if (readOnlySemanticEngine !== null && readOnlySemanticEngine !== undefined) {
301
+ void readOnlySemanticEngine.dispose().catch(() => undefined);
302
+ }
303
+ if (readOnlyCoreSemanticEngine !== null && readOnlyCoreSemanticEngine !== undefined) {
304
+ void readOnlyCoreSemanticEngine.dispose().catch(() => undefined);
305
+ }
306
+ if (ephemeralCoreSemanticEngine !== null) {
307
+ void ephemeralCoreSemanticEngine.dispose().catch(() => undefined);
308
+ }
373
309
  };
374
310
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
375
311
  tools: omsMcpTools,
376
312
  }));
377
- server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
378
- resourceTemplates: [
379
- {
380
- uriTemplate: "qmd://{path}",
381
- name: "QMD-compatible OMS semantic document",
382
- description: "Read a native OMS semantic-index document by qmd:// vault-relative path.",
383
- mimeType: "text/markdown",
384
- },
385
- ],
386
- }));
387
- server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
388
- const uri = request.params.uri;
389
- // Resource reads hydrate on the SAME backend the semantic ops use: the engine
390
- // (file-based, qmd:// / oms:// scheme aware), vec-capable when a model is
391
- // configured and core (lex + file reads) otherwise — so a retrieve_context
392
- // docid resolves through the URI surface regardless of which backend produced it.
393
- const result = await resolveDocumentAdapter().getDocument({ vault, target: uri });
394
- if (!result.available || !result.documents[0]) {
395
- throw new Error(!result.available && result.reason ? result.reason : "OMS semantic resource not found.");
396
- }
397
- return {
398
- contents: [
399
- {
400
- uri,
401
- mimeType: "text/markdown",
402
- text: result.documents[0].content,
403
- },
404
- ],
405
- };
406
- });
407
313
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
408
- const args = isRecord(request.params.arguments) ? request.params.arguments : undefined;
409
- if (request.params.name === "oms_graph_status") {
314
+ let args = isRecord(request.params.arguments) ? request.params.arguments : undefined;
315
+ const publicName = request.params.name;
316
+ const op = publicName === "oms_write" ? stringArg(args, "op") ?? "create" : stringArg(args, "op");
317
+ const name = resolveOperation(publicName, op);
318
+ if (!name)
319
+ return errorText(`Unknown operation "${op ?? "(missing)"}" for ${publicName}.`);
320
+ if (publicName === "oms_write")
321
+ args = { ...args, mode: op };
322
+ if (publicName === "oms_search" && op === "query") {
323
+ const searches = args?.["searches"];
324
+ if (typeof args?.["query"] === "string" && Array.isArray(searches)) {
325
+ return errorText('Provide exactly one of "query" or "searches" for query.');
326
+ }
327
+ }
328
+ if (name === "oms_graph_status") {
410
329
  // The src/graph derived-cache ledger (M3 5-state staleness) is the source
411
330
  // of truth for retrieve_context's optional warm cache and stays intact.
412
331
  // engineGraph is additive: it surfaces the native engine's axis cache that
@@ -429,8 +348,8 @@ export function createOMSMcpServer(opts) {
429
348
  derivedState: cacheStatus,
430
349
  engineGraph,
431
350
  writeTools: source === "cwd"
432
- ? "write-disabled-target-unverified"
433
- : "write-gated-by-verified-target-and-contract",
351
+ ? "oms_write-disabled-target-unverified"
352
+ : "oms_write-gated-by-verified-target-and-contract",
434
353
  readTools: omsMcpTools.map((tool) => tool.name),
435
354
  });
436
355
  }
@@ -453,27 +372,41 @@ export function createOMSMcpServer(opts) {
453
372
  },
454
373
  },
455
374
  engineGraph,
456
- writeTools: "disabled-invalid-ontology",
375
+ writeTools: "oms_write-disabled-invalid-ontology",
457
376
  readTools: ["oms_graph_status"],
458
377
  });
459
378
  }
460
379
  }
461
380
  try {
462
- if (request.params.name === "oms_graph_build") {
463
- const { ontology, source } = await resolveActiveOntology(vault);
464
- const cache = await buildGraphCache({ vault, ontology, write: true });
465
- return jsonText({
381
+ if (name === "oms_graph_build" || name === "oms_semantic_cleanup" || name === "oms_sync_embeddings") {
382
+ const operation = name === "oms_graph_build" ? "build-graph" : name === "oms_semantic_cleanup" ? "semantic-cleanup" : "sync-embeddings";
383
+ // A FACTORY, not a value. JavaScript evaluates an argument expression
384
+ // before entering the callee, so passing a constructed adapter here would
385
+ // open - and therefore create - `<vault>/.oms/engine-store.sqlite` before
386
+ // repairDoctor got the chance to run admission. On an invalid global
387
+ // target that means mutating a directory we are about to reject, which
388
+ // breaks the verified-target contract's requirement that admission
389
+ // precede ANY disk mutation. The kernel calls this only after admitting.
390
+ //
391
+ // Deliberately NOT re-checking admission here: two policy paths is how
392
+ // the check drifts. One authoritative decision, deferred dependency.
393
+ const resolveRepairAdapter = operation === "build-graph"
394
+ ? undefined
395
+ : () => publicName === "oms_search"
396
+ ? resolveReadOnlyDocumentAdapter()
397
+ : operation === "semantic-cleanup" || (operation === "sync-embeddings" && args?.["embed"] === false)
398
+ ? resolveCreatingDocumentAdapter()
399
+ : getSemanticEngine().adapter;
400
+ const repair = await repairDoctor({
401
+ operation,
466
402
  vault,
467
- ontologySource: source,
468
- cachePath: graphCachePath(vault),
469
- generatedAt: cache.generatedAt,
470
- notes: cache.notes.length,
471
- edges: cache.edges.length,
472
- searchDocuments: cache.search.length,
473
- sourceOfTruth: cache.sourceOfTruth,
403
+ source,
404
+ args,
405
+ resolveAdapter: resolveRepairAdapter,
474
406
  });
407
+ return repair.kind === "error" ? errorText(repair.message) : jsonText(repair.value);
475
408
  }
476
- if (request.params.name === "oms_list_concepts") {
409
+ if (name === "oms_list_concepts") {
477
410
  const { ontology, source } = await resolveActiveOntology(vault);
478
411
  return jsonText({
479
412
  vault,
@@ -482,7 +415,7 @@ export function createOMSMcpServer(opts) {
482
415
  concepts: Array.from(ontology.concepts.values()).map(conceptSummary),
483
416
  });
484
417
  }
485
- if (request.params.name === "oms_retrieve_by_axis") {
418
+ if (name === "oms_retrieve_by_axis") {
486
419
  // Engine-owned (graph-only swap): axis-first retrieval over the native
487
420
  // node index, built lazily off the filesystem — no embedding model needed.
488
421
  const limitValue = args?.["limit"];
@@ -504,13 +437,24 @@ export function createOMSMcpServer(opts) {
504
437
  ...result,
505
438
  });
506
439
  }
507
- if (request.params.name === "oms_retrieve_context") {
440
+ if (name === "oms_retrieve_context") {
508
441
  // Graph + semantic fusion. The graph leg stays on the src/graph warm cache;
509
442
  // the semantic leg routes to the native engine: vec-capable when a model is
510
443
  // configured (parity ranking, real-path docids) and core (lex; vec/HyDE fail
511
444
  // fast) otherwise. get/multi_get and ReadResource make the SAME choice, so a
512
445
  // docid emitted here always hydrates on the backend that produced it.
513
- const semanticBackend = makeEngineMorningBackend(resolveDocumentAdapter(), vault);
446
+ const semantic = semanticOptionsFromArgs(args);
447
+ let contextAdapter = engine.adapter;
448
+ if (semantic?.enabled !== false) {
449
+ try {
450
+ contextAdapter = resolveDocumentAdapter(publicName);
451
+ }
452
+ catch (error) {
453
+ if (!(error instanceof SemanticIndexUnavailableError))
454
+ throw error;
455
+ }
456
+ }
457
+ const semanticBackend = makeEngineMorningBackend(contextAdapter, vault);
514
458
  const { ontology, source } = await resolveActiveOntology(vault);
515
459
  const limitValue = args?.["limit"];
516
460
  const maxNeighborsValue = args?.["maxNeighbors"];
@@ -527,7 +471,7 @@ export function createOMSMcpServer(opts) {
527
471
  limit: typeof limitValue === "number" ? limitValue : undefined,
528
472
  maxNeighbors: typeof maxNeighborsValue === "number" ? maxNeighborsValue : undefined,
529
473
  useCache: typeof useCacheValue === "boolean" ? useCacheValue : undefined,
530
- semantic: semanticOptionsFromArgs(args),
474
+ semantic,
531
475
  }, semanticBackend);
532
476
  return jsonText({
533
477
  vault,
@@ -543,23 +487,112 @@ export function createOMSMcpServer(opts) {
543
487
  // engine when a model is configured, else the core engine. Lex is a real
544
488
  // model-free BM25/FTS feature, not an ADR-007 fake vector fallback.
545
489
  // Every other tool never touches the engine here.
546
- if (isEngineSemanticOp(request.params.name) || isEngineDocumentOp(request.params.name)) {
547
- const semanticAdapter = isEngineSemanticOp(request.params.name) && !isModelOptionalSemanticQueryOp(request.params.name, args, vault)
548
- ? getSemanticEngine().adapter
549
- : resolveDocumentAdapter();
550
- const semanticToolResult = await handleSemanticTool(request.params.name, args, vault, semanticAdapter);
490
+ if (isEngineSemanticOp(name) || isEngineDocumentOp(name)) {
491
+ if (name === "oms_semantic_query") {
492
+ const hasQueryAxes = isRecord(args?.["axes"]) ||
493
+ args?.["folder"] !== undefined ||
494
+ args?.["field"] !== undefined ||
495
+ args?.["link"] !== undefined;
496
+ if (hasQueryAxes) {
497
+ const axisAdapter = hasExplicitEmbeddingIntent(args)
498
+ ? resolveReadOnlyIndexAdapter()
499
+ : await resolveReadOnlyLexicalAdapter();
500
+ const axisOptions = semanticQueryOptionsFromArgs(vault, args);
501
+ const axisResult = await new EngineSearchBackend(axisAdapter, vault).search({
502
+ ...axisOptions,
503
+ query: axisOptions.lex !== undefined ||
504
+ axisOptions.vec !== undefined ||
505
+ axisOptions.hyde !== undefined
506
+ ? undefined
507
+ : axisOptions.query ?? "",
508
+ });
509
+ return jsonText(axisResult);
510
+ }
511
+ const query = stringArg(args, "query");
512
+ const vec = stringArg(args, "vec");
513
+ const hyde = stringArg(args, "hyde");
514
+ const queryOptions = semanticQueryOptionsFromArgs(vault, args);
515
+ const noPersistentReadOnlyIndex = hasEmbeddingModel()
516
+ ? getReadOnlySemanticEngine() === null
517
+ : getReadOnlyCoreSemanticEngine() === null;
518
+ const hasExplicitLexicalIntent = query !== undefined ||
519
+ stringArg(args, "lex") !== undefined ||
520
+ (queryOptions.searches ?? []).some((search) => search.type === "lex");
521
+ const isOverviewRequest = query === undefined &&
522
+ (queryOptions.searches ?? []).length === 0 &&
523
+ queryOptions.lex === undefined &&
524
+ queryOptions.vec === undefined &&
525
+ queryOptions.hyde === undefined &&
526
+ queryOptions.axes === undefined;
527
+ if (!hasExplicitEmbeddingIntent(args) && noPersistentReadOnlyIndex && (hasExplicitLexicalIntent || isOverviewRequest)) {
528
+ // Reuse the SearchBackend seam for model-free fallback as well. This
529
+ // keeps overview, cursor, axes, and collection aggregation semantics
530
+ // identical to the indexed path; its normalized default is lexical,
531
+ // so no vector intent is fabricated when the model is absent.
532
+ const fallbackBackend = new EngineSearchBackend(await resolveReadOnlyLexicalAdapter(), vault);
533
+ const result = await fallbackBackend.search({
534
+ ...queryOptions,
535
+ // `lex` is an explicit lexical representation. Do not send it
536
+ // alongside `query`, which would make the two equivalent forms
537
+ // look contradictory to the SearchBackend normalizer.
538
+ query: queryOptions.lex === undefined ? query ?? "" : undefined,
539
+ });
540
+ return jsonText(result);
541
+ }
542
+ const requestOptions = {
543
+ ...queryOptions,
544
+ collections: queryOptions.collections,
545
+ };
546
+ const result = await searchBackend.search({
547
+ ...requestOptions,
548
+ // `query` is the default lexical representation. An explicit vector
549
+ // or HyDE shorthand selects its own representation instead; only
550
+ // `query` plus typed `searches` is contradictory.
551
+ query: vec !== undefined || hyde !== undefined || queryOptions.lex !== undefined
552
+ ? undefined
553
+ : query ?? "",
554
+ searches: queryOptions.searches,
555
+ });
556
+ return jsonText(result);
557
+ }
558
+ const useEphemeralLexicalFallback = name === "oms_semantic_query" &&
559
+ publicName === "oms_search" &&
560
+ !hasExplicitEmbeddingIntent(args) &&
561
+ (hasEmbeddingModel()
562
+ ? getReadOnlySemanticEngine() === null
563
+ : getReadOnlyCoreSemanticEngine() === null);
564
+ const semanticAdapter = useEphemeralLexicalFallback
565
+ ? await resolveReadOnlyLexicalAdapter()
566
+ :
567
+ isEngineSemanticOp(name) &&
568
+ name !== "oms_semantic_cleanup" &&
569
+ !(name === "oms_sync_embeddings" && args?.["embed"] === false) &&
570
+ !isModelOptionalSemanticQueryOp(name, args, vault)
571
+ ? publicName === "oms_search"
572
+ ? resolveReadOnlyIndexAdapter()
573
+ : getSemanticEngine().adapter
574
+ : isEngineDocumentOp(name)
575
+ ? resolveDocumentAdapter(publicName)
576
+ : publicName === "oms_search"
577
+ ? resolveReadOnlyIndexAdapter()
578
+ : resolveDocumentAdapter(publicName);
579
+ const semanticToolResult = await handleSemanticTool(name, useEphemeralLexicalFallback
580
+ ? { ...args, lex: stringArg(args, "query") }
581
+ : args, vault, semanticAdapter);
551
582
  if (semanticToolResult) {
552
- return semanticToolResult.ok ? jsonText(semanticToolResult.value) : errorText(semanticToolResult.message);
583
+ if (!semanticToolResult.ok)
584
+ return errorText(semanticToolResult.message);
585
+ return jsonText(semanticToolResult.value);
553
586
  }
554
587
  }
555
- if (request.params.name === "oms_lazy_load_note") {
588
+ if (name === "oms_lazy_load_note") {
556
589
  const notePath = stringArg(args, "notePath");
557
590
  if (!notePath) {
558
591
  return errorText('Missing required string argument "notePath".');
559
592
  }
560
593
  return jsonText(await lazyLoadNoteBody(vault, notePath));
561
594
  }
562
- if (request.params.name === "oms_validate_contract") {
595
+ if (name === "oms_validate_contract") {
563
596
  const notePath = stringArg(args, "notePath");
564
597
  if (!notePath) {
565
598
  return errorText('Missing required string argument "notePath".');
@@ -603,7 +636,7 @@ export function createOMSMcpServer(opts) {
603
636
  violations: result.violations,
604
637
  });
605
638
  }
606
- if (request.params.name === "oms_vault_audit") {
639
+ if (name === "oms_vault_audit") {
607
640
  if (args !== undefined &&
608
641
  Object.prototype.hasOwnProperty.call(args, "folder") &&
609
642
  typeof args["folder"] !== "string") {
@@ -622,7 +655,7 @@ export function createOMSMcpServer(opts) {
622
655
  violations: report.violations,
623
656
  });
624
657
  }
625
- if (request.params.name === "oms_link_suggest") {
658
+ if (name === "oms_link_suggest") {
626
659
  const notePath = stringArg(args, "notePath");
627
660
  if (!notePath) {
628
661
  return errorText('Missing required string argument "notePath".');
@@ -631,7 +664,7 @@ export function createOMSMcpServer(opts) {
631
664
  const suggestion = await suggestLinksForNote({ vault, source, ontology, notePath }, { folder: stringArg(args, "folder") });
632
665
  return jsonText({ vault, ontologySource, ...suggestion });
633
666
  }
634
- if (request.params.name === "oms_link_apply") {
667
+ if (name === "oms_link_apply") {
635
668
  const notePath = stringArg(args, "notePath");
636
669
  if (!notePath) {
637
670
  return errorText('Missing required string argument "notePath".');
@@ -648,10 +681,20 @@ export function createOMSMcpServer(opts) {
648
681
  const outcome = await applyLinksForNote({ vault, source, ontology, notePath }, { baseContentHash, candidateIds: idsArg.filter((id) => typeof id === "string") }, { folder: stringArg(args, "folder") });
649
682
  return jsonText({ vault, ontologySource, ...linkApplyPayload(outcome) });
650
683
  }
651
- if (request.params.name === "write") {
684
+ if (name === "write") {
652
685
  const { ontology, source: ontologySource } = await resolveActiveOntology(vault);
653
686
  const modeArg = stringArg(args, "mode");
654
687
  const mode = isWriteMode(modeArg) ? modeArg : "create";
688
+ // `notePath` and `folder`/`filename` are two ways to address the same
689
+ // note. Supplying both is a contradiction the caller should hear about:
690
+ // silently preferring one produced a response that reported the concept
691
+ // implied by one form and the folder implied by the other, which reads as
692
+ // corruption rather than as the input error it is.
693
+ const hasNotePath = stringArg(args, "notePath") !== undefined;
694
+ const hasFolderForm = stringArg(args, "folder") !== undefined || stringArg(args, "filename") !== undefined;
695
+ if (hasNotePath && hasFolderForm) {
696
+ return errorText('Provide either "notePath" or "folder"/"filename" to address the note, not both.');
697
+ }
655
698
  const frontmatterArg = args?.["frontmatter"];
656
699
  const result = await writeNote({
657
700
  target: { vault, source },
@@ -673,9 +716,15 @@ export function createOMSMcpServer(opts) {
673
716
  resolutionSource: source,
674
717
  });
675
718
  }
676
- return errorText(`Unknown Oh My Second Brain tool: ${request.params.name}`);
719
+ return errorText(`Unknown Oh My Second Brain tool: ${publicName}`);
677
720
  }
678
721
  catch (error) {
722
+ if (error instanceof SemanticIndexUnavailableError) {
723
+ return jsonText({
724
+ available: false,
725
+ reason: error.message,
726
+ });
727
+ }
679
728
  return errorText(`Oh My Second Brain MCP error: ${error instanceof Error ? error.message : String(error)}`);
680
729
  }
681
730
  });