oh-my-second-brain 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) 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 +154 -0
  5. package/CHANGELOG-assets.md +19 -0
  6. package/CHANGELOG-cli.md +15 -0
  7. package/CHANGELOG-kernel.md +25 -0
  8. package/CHANGELOG-mcp.md +26 -0
  9. package/CHANGELOG-vendors.md +22 -0
  10. package/CHANGELOG.md +24 -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 +1 -1
  30. package/dist/cli/args.js +1 -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 +22 -4
  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.js +20 -9
  49. package/dist/cli/oms.js.map +1 -1
  50. package/dist/cli/semantic-args.d.ts +1 -1
  51. package/dist/cli/semantic-http.js +3 -3
  52. package/dist/cli/semantic-http.js.map +1 -1
  53. package/dist/cli/semantic-usage.js +1 -1
  54. package/dist/cli/semantic-usage.js.map +1 -1
  55. package/dist/cli/semantic.js +1 -6
  56. package/dist/cli/semantic.js.map +1 -1
  57. package/dist/cli/setup-command.d.ts +1 -0
  58. package/dist/cli/setup-command.js +42 -147
  59. package/dist/cli/setup-command.js.map +1 -1
  60. package/dist/cli/update-notice.d.ts +1 -1
  61. package/dist/cli/update-notice.js +2 -2
  62. package/dist/cli/update-notice.js.map +1 -1
  63. package/dist/cli/usage.d.ts +1 -1
  64. package/dist/cli/usage.js +2 -2
  65. package/dist/cli/usage.js.map +1 -1
  66. package/dist/{capture → kernel/capture}/safe.d.ts +11 -1
  67. package/dist/{capture → kernel/capture}/safe.js +3 -3
  68. package/dist/kernel/capture/safe.js.map +1 -0
  69. package/dist/kernel/conventions/frontmatter.js.map +1 -0
  70. package/dist/kernel/conventions/lint.js.map +1 -0
  71. package/dist/kernel/conventions/report.js.map +1 -0
  72. package/dist/{conventions → kernel/conventions}/validate.d.ts +1 -1
  73. package/dist/kernel/conventions/validate.js.map +1 -0
  74. package/dist/kernel/conventions/vault-walk.js.map +1 -0
  75. package/dist/{conventions → kernel/conventions}/write-contract.d.ts +1 -1
  76. package/dist/kernel/conventions/write-contract.js.map +1 -0
  77. package/dist/kernel/conventions/write-protocol.js.map +1 -0
  78. package/dist/kernel/doctor/service.d.ts +71 -0
  79. package/dist/kernel/doctor/service.js +70 -0
  80. package/dist/kernel/doctor/service.js.map +1 -0
  81. package/dist/{engine → kernel/engine}/assemble.d.ts +24 -0
  82. package/dist/{engine → kernel/engine}/assemble.js +142 -4
  83. package/dist/kernel/engine/assemble.js.map +1 -0
  84. package/dist/{engine → kernel/engine}/conventions/vault-lint.d.ts +1 -1
  85. package/dist/{engine → kernel/engine}/conventions/vault-lint.js +1 -1
  86. package/dist/kernel/engine/conventions/vault-lint.js.map +1 -0
  87. package/dist/kernel/engine/embed/chunker.js.map +1 -0
  88. package/dist/kernel/engine/embed/deferred.js.map +1 -0
  89. package/dist/{engine → kernel/engine}/embed/hash-stub.test-helper.d.ts +1 -1
  90. package/dist/{engine → kernel/engine}/embed/hash-stub.test-helper.js +1 -1
  91. package/dist/kernel/engine/embed/hash-stub.test-helper.js.map +1 -0
  92. package/dist/kernel/engine/embed/identity.js.map +1 -0
  93. package/dist/kernel/engine/embed/provider.js.map +1 -0
  94. package/dist/{engine → kernel/engine}/embed/store.d.ts +8 -0
  95. package/dist/{engine → kernel/engine}/embed/store.js +212 -8
  96. package/dist/kernel/engine/embed/store.js.map +1 -0
  97. package/dist/{engine → kernel/engine}/embed/sync.d.ts +3 -1
  98. package/dist/{engine → kernel/engine}/embed/sync.js +5 -3
  99. package/dist/kernel/engine/embed/sync.js.map +1 -0
  100. package/dist/kernel/engine/graph/builder.js.map +1 -0
  101. package/dist/kernel/engine/graph/explore.js.map +1 -0
  102. package/dist/kernel/engine/graph/node.js.map +1 -0
  103. package/dist/kernel/engine/graph/resolver.js.map +1 -0
  104. package/dist/kernel/engine/graph/traverse.js.map +1 -0
  105. package/dist/kernel/engine/linkify/apply.js.map +1 -0
  106. package/dist/kernel/engine/linkify/josa.js.map +1 -0
  107. package/dist/kernel/engine/linkify/mask.js.map +1 -0
  108. package/dist/kernel/engine/linkify/suggest.js.map +1 -0
  109. package/dist/kernel/engine/linkify/types.js.map +1 -0
  110. package/dist/{engine → kernel/engine}/mcp/facade.d.ts +7 -1
  111. package/dist/{engine → kernel/engine}/mcp/facade.js +32 -11
  112. package/dist/kernel/engine/mcp/facade.js.map +1 -0
  113. package/dist/kernel/engine/mcp/op-mappers.js.map +1 -0
  114. package/dist/kernel/engine/mcp/query-mapper.js.map +1 -0
  115. package/dist/{engine → kernel/engine}/mcp/types.d.ts +5 -0
  116. package/dist/kernel/engine/mcp/types.js.map +1 -0
  117. package/dist/{engine → kernel/engine}/retrieval/dispatcher.d.ts +1 -1
  118. package/dist/{engine → kernel/engine}/retrieval/dispatcher.js +8 -6
  119. package/dist/kernel/engine/retrieval/dispatcher.js.map +1 -0
  120. package/dist/{engine → kernel/engine}/retrieval/index.d.ts +2 -0
  121. package/dist/{engine → kernel/engine}/retrieval/index.js +5 -2
  122. package/dist/kernel/engine/retrieval/index.js.map +1 -0
  123. package/dist/kernel/engine/retrieval/reranker.js.map +1 -0
  124. package/dist/kernel/engine/retrieval/rrf.js.map +1 -0
  125. package/dist/kernel/engine/tracer.js.map +1 -0
  126. package/dist/{engine → kernel/engine}/types.d.ts +4 -4
  127. package/dist/kernel/engine/types.js.map +1 -0
  128. package/dist/{graph → kernel/graph}/cache.d.ts +1 -1
  129. package/dist/{graph → kernel/graph}/cache.js +1 -1
  130. package/dist/kernel/graph/cache.js.map +1 -0
  131. package/dist/kernel/graph/explore.js.map +1 -0
  132. package/dist/{harness → kernel/harness}/surface-registry.d.ts +0 -1
  133. package/dist/kernel/harness/surface-registry.js +170 -0
  134. package/dist/kernel/harness/surface-registry.js.map +1 -0
  135. package/dist/{harness → kernel/harness}/validation.js +67 -4
  136. package/dist/kernel/harness/validation.js.map +1 -0
  137. package/dist/{index.d.ts → kernel/index.d.ts} +5 -6
  138. package/dist/kernel/index.js +12 -0
  139. package/dist/kernel/index.js.map +1 -0
  140. package/dist/{install → kernel/install}/adapter-source.d.ts +10 -1
  141. package/dist/kernel/install/adapter-source.js +76 -0
  142. package/dist/kernel/install/adapter-source.js.map +1 -0
  143. package/dist/kernel/install/common.js.map +1 -0
  144. package/dist/{install → kernel/install}/hosts.d.ts +3 -3
  145. package/dist/{install → kernel/install}/hosts.js +3 -22
  146. package/dist/kernel/install/hosts.js.map +1 -0
  147. package/dist/{core/ontology → kernel/install}/types.js.map +1 -1
  148. package/dist/{link → kernel/link}/convention-note.js +2 -2
  149. package/dist/kernel/link/convention-note.js.map +1 -0
  150. package/dist/kernel/link/global-config.js.map +1 -0
  151. package/dist/kernel/link/link.js.map +1 -0
  152. package/dist/kernel/link/workflow.d.ts +55 -0
  153. package/dist/kernel/link/workflow.js +107 -0
  154. package/dist/kernel/link/workflow.js.map +1 -0
  155. package/dist/{ontology → kernel/ontology}/active.d.ts +1 -1
  156. package/dist/{ontology → kernel/ontology}/active.js +2 -2
  157. package/dist/kernel/ontology/active.js.map +1 -0
  158. package/dist/kernel/ontology/loader.js.map +1 -0
  159. package/dist/kernel/ontology/resolver.js.map +1 -0
  160. package/dist/{install → kernel/ontology}/types.js.map +1 -1
  161. package/dist/kernel/plugin/index.d.ts +1 -0
  162. package/dist/kernel/plugin/index.js +2 -0
  163. package/dist/kernel/plugin/index.js.map +1 -0
  164. package/dist/{core → kernel}/runtime/assets.d.ts +2 -4
  165. package/dist/{core → kernel}/runtime/assets.js +1 -3
  166. package/dist/kernel/runtime/assets.js.map +1 -0
  167. package/dist/kernel/search/morning-test-fixtures.js.map +1 -0
  168. package/dist/{retrieve → kernel/search}/morning.d.ts +0 -1
  169. package/dist/kernel/search/morning.js.map +1 -0
  170. package/dist/kernel/search/semantic-contract.js.map +1 -0
  171. package/dist/kernel/searchbackend/engine-search-backend.d.ts +28 -0
  172. package/dist/kernel/searchbackend/engine-search-backend.js +67 -0
  173. package/dist/kernel/searchbackend/engine-search-backend.js.map +1 -0
  174. package/dist/kernel/searchbackend/index.d.ts +2 -0
  175. package/dist/kernel/searchbackend/index.js +2 -0
  176. package/dist/kernel/searchbackend/index.js.map +1 -0
  177. package/dist/kernel/searchbackend/search-backend.d.ts +47 -0
  178. package/dist/kernel/searchbackend/search-backend.js +49 -0
  179. package/dist/kernel/searchbackend/search-backend.js.map +1 -0
  180. package/dist/{mcp → kernel/semantic}/semantic-engine.d.ts +3 -2
  181. package/dist/{mcp → kernel/semantic}/semantic-engine.js +5 -5
  182. package/dist/kernel/semantic/semantic-engine.js.map +1 -0
  183. package/dist/{mcp → kernel/semantic}/semantic-retrieve-args.d.ts +2 -2
  184. package/dist/{mcp → kernel/semantic}/semantic-retrieve-args.js +0 -8
  185. package/dist/kernel/semantic/semantic-retrieve-args.js.map +1 -0
  186. package/dist/{mcp → kernel/semantic}/semantic-retrieve-schema.d.ts +0 -24
  187. package/dist/{mcp → kernel/semantic}/semantic-retrieve-schema.js +0 -8
  188. package/dist/kernel/semantic/semantic-retrieve-schema.js.map +1 -0
  189. package/dist/{mcp → kernel/semantic}/semantic-retrieve.js +5 -9
  190. package/dist/kernel/semantic/semantic-retrieve.js.map +1 -0
  191. package/dist/kernel/semantic/semantic-schemas.js.map +1 -0
  192. package/dist/{mcp → kernel/semantic}/semantic-tool-schemas.js +0 -28
  193. package/dist/kernel/semantic/semantic-tool-schemas.js.map +1 -0
  194. package/dist/{setup → kernel/setup}/axis.d.ts +1 -1
  195. package/dist/{setup → kernel/setup}/axis.js +1 -1
  196. package/dist/kernel/setup/axis.js.map +1 -0
  197. package/dist/{cli/setup-documents.d.ts → kernel/setup/documents.d.ts} +1 -1
  198. package/dist/{cli/setup-documents.js → kernel/setup/documents.js} +15 -49
  199. package/dist/kernel/setup/documents.js.map +1 -0
  200. package/dist/kernel/setup/service.d.ts +44 -0
  201. package/dist/kernel/setup/service.js +97 -0
  202. package/dist/kernel/setup/service.js.map +1 -0
  203. package/dist/kernel/update/update.js.map +1 -0
  204. package/dist/mcp/engine-morning-backend.d.ts +4 -4
  205. package/dist/mcp/engine-morning-backend.js +4 -18
  206. package/dist/mcp/engine-morning-backend.js.map +1 -1
  207. package/dist/mcp/link-tools.d.ts +9 -56
  208. package/dist/mcp/link-tools.js +5 -129
  209. package/dist/mcp/link-tools.js.map +1 -1
  210. package/dist/mcp/server.d.ts +9 -2
  211. package/dist/mcp/server.js +326 -327
  212. package/dist/mcp/server.js.map +1 -1
  213. package/dist/mcp/update-notice.d.ts +1 -1
  214. package/dist/mcp/update-notice.js +1 -1
  215. package/dist/mcp/update-notice.js.map +1 -1
  216. package/dist/{install → vendors/claude}/claude-hooks.d.ts +1 -1
  217. package/dist/{install → vendors/claude}/claude-hooks.js +1 -1
  218. package/dist/vendors/claude/claude-hooks.js.map +1 -0
  219. package/dist/{install → vendors/claude}/claude-marketplace.d.ts +3 -3
  220. package/dist/{install → vendors/claude}/claude-marketplace.js +6 -9
  221. package/dist/vendors/claude/claude-marketplace.js.map +1 -0
  222. package/dist/{install → vendors/claude}/claude.d.ts +2 -2
  223. package/dist/{install → vendors/claude}/claude.js +2 -2
  224. package/dist/vendors/claude/claude.js.map +1 -0
  225. package/dist/{hook → vendors/claude/hook}/post-tool-use.js +5 -5
  226. package/dist/vendors/claude/hook/post-tool-use.js.map +1 -0
  227. package/dist/vendors/claude/hook/pre-tool-use.js.map +1 -0
  228. package/dist/vendors/claude/hook/stdin.js.map +1 -0
  229. package/dist/vendors/codex/codex.d.ts +10 -0
  230. package/dist/{install → vendors/codex}/codex.js +19 -37
  231. package/dist/vendors/codex/codex.js.map +1 -0
  232. package/dist/{install → vendors/hermes}/hermes.d.ts +2 -2
  233. package/dist/{install → vendors/hermes}/hermes.js +15 -7
  234. package/dist/vendors/hermes/hermes.js.map +1 -0
  235. package/docs/adapters.md +15 -0
  236. package/docs/install.md +10 -11
  237. package/package.json +21 -9
  238. package/adapters/README.md +0 -99
  239. package/adapters/claude-code/skills/compile/SKILL.md +0 -27
  240. package/adapters/claude-code/skills/define/SKILL.md +0 -51
  241. package/adapters/claude-code/skills/distill/SKILL.md +0 -28
  242. package/adapters/claude-code/skills/doctor/SKILL.md +0 -58
  243. package/adapters/claude-code/skills/link/SKILL.md +0 -87
  244. package/adapters/claude-code/skills/retrieve/SKILL.md +0 -99
  245. package/adapters/claude-code/skills/setup/SKILL.md +0 -78
  246. package/adapters/claude-code/skills/uninstall/SKILL.md +0 -34
  247. package/adapters/claude-code/skills/update/SKILL.md +0 -45
  248. package/adapters/claude-code/skills/vault-decision-record/SKILL.md +0 -52
  249. package/adapters/claude-code/skills/vault-lint/SKILL.md +0 -47
  250. package/adapters/claude-code/skills/vault-scaffold/SKILL.md +0 -47
  251. package/adapters/claude-code/skills/wiki/SKILL.md +0 -82
  252. package/adapters/claude-code/skills/write/SKILL.md +0 -16
  253. package/adapters/codex/skills/oms-compile/SKILL.md +0 -16
  254. package/adapters/codex/skills/oms-distill/SKILL.md +0 -14
  255. package/adapters/codex/skills/oms-doctor/SKILL.md +0 -14
  256. package/adapters/codex/skills/oms-install/SKILL.md +0 -19
  257. package/adapters/codex/skills/oms-link/SKILL.md +0 -35
  258. package/adapters/codex/skills/oms-retrieve/SKILL.md +0 -32
  259. package/adapters/codex/skills/oms-setup/SKILL.md +0 -34
  260. package/adapters/codex/skills/oms-uninstall/SKILL.md +0 -20
  261. package/adapters/codex/skills/oms-update/SKILL.md +0 -22
  262. package/adapters/codex/skills/oms-vault-lint/SKILL.md +0 -19
  263. package/adapters/codex/skills/oms-wiki/SKILL.md +0 -39
  264. package/adapters/codex/skills/oms-write/SKILL.md +0 -10
  265. package/adapters/hermes/skills/compile/SKILL.md +0 -13
  266. package/adapters/hermes/skills/distill/SKILL.md +0 -10
  267. package/adapters/hermes/skills/doctor/SKILL.md +0 -14
  268. package/adapters/hermes/skills/install/SKILL.md +0 -19
  269. package/adapters/hermes/skills/link/SKILL.md +0 -18
  270. package/adapters/hermes/skills/retrieve/SKILL.md +0 -32
  271. package/adapters/hermes/skills/setup/SKILL.md +0 -37
  272. package/adapters/hermes/skills/uninstall/SKILL.md +0 -20
  273. package/adapters/hermes/skills/update/SKILL.md +0 -22
  274. package/adapters/hermes/skills/wiki/SKILL.md +0 -14
  275. package/adapters/hermes/skills/write/SKILL.md +0 -10
  276. package/core/agents/librarian.md +0 -44
  277. package/core/agents/retriever.md +0 -62
  278. package/core/skills/compile/CHANGELOG.md +0 -24
  279. package/core/skills/compile/SKILL.md +0 -57
  280. package/core/skills/define/SKILL.md +0 -59
  281. package/core/skills/distill/CHANGELOG.md +0 -39
  282. package/core/skills/distill/SKILL.md +0 -62
  283. package/core/skills/doctor/SKILL.md +0 -49
  284. package/core/skills/link/SKILL.md +0 -130
  285. package/core/skills/retrieve/SKILL.md +0 -78
  286. package/core/skills/setup/CHANGELOG.md +0 -49
  287. package/core/skills/setup/SKILL.md +0 -246
  288. package/core/skills/uninstall/SKILL.md +0 -34
  289. package/core/skills/vault-decision-record/CHANGELOG.md +0 -24
  290. package/core/skills/vault-decision-record/SKILL.md +0 -93
  291. package/core/skills/vault-lint/CHANGELOG.md +0 -35
  292. package/core/skills/vault-lint/SKILL.md +0 -58
  293. package/core/skills/vault-scaffold/CHANGELOG.md +0 -21
  294. package/core/skills/vault-scaffold/SKILL.md +0 -72
  295. package/core/skills/wiki/CHANGELOG.md +0 -23
  296. package/core/skills/wiki/SKILL.md +0 -159
  297. package/core/skills/write/SKILL.md +0 -15
  298. package/dist/capture/safe.js.map +0 -1
  299. package/dist/cli/setup-documents.js.map +0 -1
  300. package/dist/conventions/frontmatter.js.map +0 -1
  301. package/dist/conventions/lint.js.map +0 -1
  302. package/dist/conventions/report.js.map +0 -1
  303. package/dist/conventions/validate.js.map +0 -1
  304. package/dist/conventions/vault-walk.js.map +0 -1
  305. package/dist/conventions/write-contract.js.map +0 -1
  306. package/dist/conventions/write-protocol.js.map +0 -1
  307. package/dist/core/ontology/loader.js.map +0 -1
  308. package/dist/core/ontology/resolver.js.map +0 -1
  309. package/dist/core/runtime/assets.js.map +0 -1
  310. package/dist/engine/assemble.js.map +0 -1
  311. package/dist/engine/conventions/vault-lint.js.map +0 -1
  312. package/dist/engine/embed/chunker.js.map +0 -1
  313. package/dist/engine/embed/deferred.js.map +0 -1
  314. package/dist/engine/embed/hash-stub.test-helper.js.map +0 -1
  315. package/dist/engine/embed/identity.js.map +0 -1
  316. package/dist/engine/embed/provider.js.map +0 -1
  317. package/dist/engine/embed/store.js.map +0 -1
  318. package/dist/engine/embed/sync.js.map +0 -1
  319. package/dist/engine/graph/builder.js.map +0 -1
  320. package/dist/engine/graph/explore.js.map +0 -1
  321. package/dist/engine/graph/node.js.map +0 -1
  322. package/dist/engine/graph/resolver.js.map +0 -1
  323. package/dist/engine/graph/traverse.js.map +0 -1
  324. package/dist/engine/linkify/apply.js.map +0 -1
  325. package/dist/engine/linkify/josa.js.map +0 -1
  326. package/dist/engine/linkify/mask.js.map +0 -1
  327. package/dist/engine/linkify/suggest.js.map +0 -1
  328. package/dist/engine/linkify/types.js.map +0 -1
  329. package/dist/engine/mcp/facade.js.map +0 -1
  330. package/dist/engine/mcp/op-mappers.js.map +0 -1
  331. package/dist/engine/mcp/query-mapper.js.map +0 -1
  332. package/dist/engine/mcp/types.js.map +0 -1
  333. package/dist/engine/retrieval/dispatcher.js.map +0 -1
  334. package/dist/engine/retrieval/index.js.map +0 -1
  335. package/dist/engine/retrieval/reranker.js.map +0 -1
  336. package/dist/engine/retrieval/rrf.js.map +0 -1
  337. package/dist/engine/tracer.js.map +0 -1
  338. package/dist/engine/types.js.map +0 -1
  339. package/dist/graph/cache.js.map +0 -1
  340. package/dist/graph/explore.js.map +0 -1
  341. package/dist/harness/surface-registry.js +0 -397
  342. package/dist/harness/surface-registry.js.map +0 -1
  343. package/dist/harness/validation.js.map +0 -1
  344. package/dist/hook/post-tool-use.js.map +0 -1
  345. package/dist/hook/pre-tool-use.js.map +0 -1
  346. package/dist/hook/stdin.js.map +0 -1
  347. package/dist/index.js +0 -13
  348. package/dist/index.js.map +0 -1
  349. package/dist/install/adapter-source.js +0 -45
  350. package/dist/install/adapter-source.js.map +0 -1
  351. package/dist/install/claude-hooks.js.map +0 -1
  352. package/dist/install/claude-marketplace.js.map +0 -1
  353. package/dist/install/claude.js.map +0 -1
  354. package/dist/install/codex.d.ts +0 -24
  355. package/dist/install/codex.js.map +0 -1
  356. package/dist/install/common.js.map +0 -1
  357. package/dist/install/hermes.js.map +0 -1
  358. package/dist/install/hosts.js.map +0 -1
  359. package/dist/link/convention-note.js.map +0 -1
  360. package/dist/link/global-config.js.map +0 -1
  361. package/dist/link/link.js.map +0 -1
  362. package/dist/mcp/semantic-engine.js.map +0 -1
  363. package/dist/mcp/semantic-retrieve-args.js.map +0 -1
  364. package/dist/mcp/semantic-retrieve-schema.js.map +0 -1
  365. package/dist/mcp/semantic-retrieve.js.map +0 -1
  366. package/dist/mcp/semantic-schemas.js.map +0 -1
  367. package/dist/mcp/semantic-tool-schemas.js.map +0 -1
  368. package/dist/ontology/active.js.map +0 -1
  369. package/dist/retrieve/morning-test-fixtures.js.map +0 -1
  370. package/dist/retrieve/morning.js.map +0 -1
  371. package/dist/retrieve/semantic-contract.js.map +0 -1
  372. package/dist/setup/axis.js.map +0 -1
  373. package/dist/update/update.js.map +0 -1
  374. package/docs/release.md +0 -188
  375. /package/{adapters/codex/.mcp.json → .mcp.codex.json} +0 -0
  376. /package/{adapters/claude-code/.mcp.json → .mcp.json} +0 -0
  377. /package/{adapters/claude-code → assets/claude}/hooks/oms-guard.mjs +0 -0
  378. /package/{adapters/claude-code → assets/claude}/hooks/oms-post-guard.mjs +0 -0
  379. /package/dist/{conventions → kernel/conventions}/frontmatter.d.ts +0 -0
  380. /package/dist/{conventions → kernel/conventions}/frontmatter.js +0 -0
  381. /package/dist/{conventions → kernel/conventions}/lint.d.ts +0 -0
  382. /package/dist/{conventions → kernel/conventions}/lint.js +0 -0
  383. /package/dist/{conventions → kernel/conventions}/report.d.ts +0 -0
  384. /package/dist/{conventions → kernel/conventions}/report.js +0 -0
  385. /package/dist/{conventions → kernel/conventions}/validate.js +0 -0
  386. /package/dist/{conventions → kernel/conventions}/vault-walk.d.ts +0 -0
  387. /package/dist/{conventions → kernel/conventions}/vault-walk.js +0 -0
  388. /package/dist/{conventions → kernel/conventions}/write-contract.js +0 -0
  389. /package/dist/{conventions → kernel/conventions}/write-protocol.d.ts +0 -0
  390. /package/dist/{conventions → kernel/conventions}/write-protocol.js +0 -0
  391. /package/dist/{engine → kernel/engine}/embed/chunker.d.ts +0 -0
  392. /package/dist/{engine → kernel/engine}/embed/chunker.js +0 -0
  393. /package/dist/{engine → kernel/engine}/embed/deferred.d.ts +0 -0
  394. /package/dist/{engine → kernel/engine}/embed/deferred.js +0 -0
  395. /package/dist/{engine → kernel/engine}/embed/identity.d.ts +0 -0
  396. /package/dist/{engine → kernel/engine}/embed/identity.js +0 -0
  397. /package/dist/{engine → kernel/engine}/embed/provider.d.ts +0 -0
  398. /package/dist/{engine → kernel/engine}/embed/provider.js +0 -0
  399. /package/dist/{engine → kernel/engine}/graph/builder.d.ts +0 -0
  400. /package/dist/{engine → kernel/engine}/graph/builder.js +0 -0
  401. /package/dist/{engine → kernel/engine}/graph/explore.d.ts +0 -0
  402. /package/dist/{engine → kernel/engine}/graph/explore.js +0 -0
  403. /package/dist/{engine → kernel/engine}/graph/node.d.ts +0 -0
  404. /package/dist/{engine → kernel/engine}/graph/node.js +0 -0
  405. /package/dist/{engine → kernel/engine}/graph/resolver.d.ts +0 -0
  406. /package/dist/{engine → kernel/engine}/graph/resolver.js +0 -0
  407. /package/dist/{engine → kernel/engine}/graph/traverse.d.ts +0 -0
  408. /package/dist/{engine → kernel/engine}/graph/traverse.js +0 -0
  409. /package/dist/{engine → kernel/engine}/linkify/apply.d.ts +0 -0
  410. /package/dist/{engine → kernel/engine}/linkify/apply.js +0 -0
  411. /package/dist/{engine → kernel/engine}/linkify/josa.d.ts +0 -0
  412. /package/dist/{engine → kernel/engine}/linkify/josa.js +0 -0
  413. /package/dist/{engine → kernel/engine}/linkify/mask.d.ts +0 -0
  414. /package/dist/{engine → kernel/engine}/linkify/mask.js +0 -0
  415. /package/dist/{engine → kernel/engine}/linkify/suggest.d.ts +0 -0
  416. /package/dist/{engine → kernel/engine}/linkify/suggest.js +0 -0
  417. /package/dist/{engine → kernel/engine}/linkify/types.d.ts +0 -0
  418. /package/dist/{engine → kernel/engine}/linkify/types.js +0 -0
  419. /package/dist/{engine → kernel/engine}/mcp/op-mappers.d.ts +0 -0
  420. /package/dist/{engine → kernel/engine}/mcp/op-mappers.js +0 -0
  421. /package/dist/{engine → kernel/engine}/mcp/query-mapper.d.ts +0 -0
  422. /package/dist/{engine → kernel/engine}/mcp/query-mapper.js +0 -0
  423. /package/dist/{engine → kernel/engine}/mcp/types.js +0 -0
  424. /package/dist/{engine → kernel/engine}/retrieval/reranker.d.ts +0 -0
  425. /package/dist/{engine → kernel/engine}/retrieval/reranker.js +0 -0
  426. /package/dist/{engine → kernel/engine}/retrieval/rrf.d.ts +0 -0
  427. /package/dist/{engine → kernel/engine}/retrieval/rrf.js +0 -0
  428. /package/dist/{engine → kernel/engine}/tracer.d.ts +0 -0
  429. /package/dist/{engine → kernel/engine}/tracer.js +0 -0
  430. /package/dist/{engine → kernel/engine}/types.js +0 -0
  431. /package/dist/{graph → kernel/graph}/explore.d.ts +0 -0
  432. /package/dist/{graph → kernel/graph}/explore.js +0 -0
  433. /package/dist/{harness → kernel/harness}/validation.d.ts +0 -0
  434. /package/dist/{install → kernel/install}/common.d.ts +0 -0
  435. /package/dist/{install → kernel/install}/common.js +0 -0
  436. /package/dist/{install → kernel/install}/types.d.ts +0 -0
  437. /package/dist/{core/ontology → kernel/install}/types.js +0 -0
  438. /package/dist/{link → kernel/link}/convention-note.d.ts +0 -0
  439. /package/dist/{link → kernel/link}/global-config.d.ts +0 -0
  440. /package/dist/{link → kernel/link}/global-config.js +0 -0
  441. /package/dist/{link → kernel/link}/link.d.ts +0 -0
  442. /package/dist/{link → kernel/link}/link.js +0 -0
  443. /package/dist/{core → kernel}/ontology/loader.d.ts +0 -0
  444. /package/dist/{core → kernel}/ontology/loader.js +0 -0
  445. /package/dist/{core → kernel}/ontology/resolver.d.ts +0 -0
  446. /package/dist/{core → kernel}/ontology/resolver.js +0 -0
  447. /package/dist/{core → kernel}/ontology/types.d.ts +0 -0
  448. /package/dist/{install → kernel/ontology}/types.js +0 -0
  449. /package/dist/{retrieve → kernel/search}/morning-test-fixtures.d.ts +0 -0
  450. /package/dist/{retrieve → kernel/search}/morning-test-fixtures.js +0 -0
  451. /package/dist/{retrieve → kernel/search}/morning.js +0 -0
  452. /package/dist/{retrieve → kernel/search}/semantic-contract.d.ts +0 -0
  453. /package/dist/{retrieve → kernel/search}/semantic-contract.js +0 -0
  454. /package/dist/{mcp → kernel/semantic}/semantic-retrieve.d.ts +0 -0
  455. /package/dist/{mcp → kernel/semantic}/semantic-schemas.d.ts +0 -0
  456. /package/dist/{mcp → kernel/semantic}/semantic-schemas.js +0 -0
  457. /package/dist/{mcp → kernel/semantic}/semantic-tool-schemas.d.ts +0 -0
  458. /package/dist/{update → kernel/update}/update.d.ts +0 -0
  459. /package/dist/{update → kernel/update}/update.js +0 -0
  460. /package/dist/{hook → vendors/claude/hook}/post-tool-use.d.ts +0 -0
  461. /package/dist/{hook → vendors/claude/hook}/pre-tool-use.d.ts +0 -0
  462. /package/dist/{hook → vendors/claude/hook}/pre-tool-use.js +0 -0
  463. /package/dist/{hook → vendors/claude/hook}/stdin.d.ts +0 -0
  464. /package/dist/{hook → vendors/claude/hook}/stdin.js +0 -0
@@ -2,24 +2,26 @@ 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 { assembleEphemeralCoreSemanticEngine, assembleCoreSemanticEngineReadOnly, assembleCoreSemanticEngine, assembleEngineReadOnly, assembleGraphOnlyEngine, } from "../kernel/engine/assemble.js";
19
+ import { assembleFullSemanticEngine, embeddingConfigPresent, } from "../kernel/semantic/semantic-engine.js";
19
20
  import { applyLinksForNote, linkApplyPayload, suggestLinksForNote } from "./link-tools.js";
21
+ import { EngineSearchBackend, requiresEmbeddings } from "../kernel/searchbackend/engine-search-backend.js";
20
22
  import { buildServerInstructions, cachedUpdateNotice, scheduleUpdateNoticeRefresh, } from "./update-notice.js";
21
23
  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.";
24
+ 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
25
  function jsonText(value) {
24
26
  return {
25
27
  content: [
@@ -41,6 +43,11 @@ function errorText(message) {
41
43
  ],
42
44
  };
43
45
  }
46
+ class SemanticIndexUnavailableError extends Error {
47
+ constructor() {
48
+ super("The semantic index has not been built yet. Run `oms semantic sync` to build it.");
49
+ }
50
+ }
44
51
  function isRecord(value) {
45
52
  return typeof value === "object" && value !== null && !Array.isArray(value);
46
53
  }
@@ -66,246 +73,59 @@ function conceptSummary(concept) {
66
73
  })),
67
74
  };
68
75
  }
76
+ const string = { type: "string" };
77
+ const number = { type: "number" };
78
+ const boolean = { type: "boolean" };
79
+ const stringArray = { type: "array", items: string };
80
+ const searchProperties = {
81
+ query: string, searches: { type: "array", maxItems: 10, items: { type: "object", properties: { type: { ...string, enum: ["lex", "vec", "hyde"] }, query: string }, required: ["type", "query"] } },
82
+ collection: string, collections: stringArray, mode: { ...string, enum: ["query", "search", "vsearch"] }, limit: { ...number, default: 10 }, candidateLimit: number, rerank: { ...boolean, default: false }, minScore: { ...number, default: 0 }, intent: string, lex: string, vec: string, hyde: string, index: string,
83
+ target: string, targets: stringArray, fromLine: number, lineCount: number, lineLimit: number, maxBytes: number, lineNumbers: boolean, fullPath: boolean,
84
+ };
85
+ const contextProperties = { concept: string, folder: string, property: string, value: string, wikilink: string, query: string, limit: number, maxNeighbors: number, useCache: boolean,
86
+ 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 };
87
+ // `folder` + `filename` is a supported addressing form that writeNote still
88
+ // accepts. With `additionalProperties: false` a strict schema is only as
89
+ // complete as its property list, so omitting them silently removed a real
90
+ // capability from every schema-driven client while raw SDK calls kept working.
91
+ const writeProperties = {
92
+ notePath: string,
93
+ folder: string,
94
+ filename: string,
95
+ concept: string,
96
+ frontmatter: { type: "object" },
97
+ body: string,
98
+ };
99
+ const operations = {
100
+ oms_write: [
101
+ { op: "create", name: "write", properties: writeProperties },
102
+ { op: "append", name: "write", properties: writeProperties },
103
+ { op: "update", name: "write", properties: writeProperties },
104
+ ],
105
+ oms_search: [{ op: "axis", name: "oms_retrieve_by_axis", properties: contextProperties }, { 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: "semantic-query", name: "oms_semantic_query", properties: searchProperties }, { op: "semantic-collections", name: "oms_semantic_collections", properties: { index: string } }, { op: "semantic-contexts", name: "oms_semantic_contexts", properties: { index: string } }, { op: "semantic-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 }],
106
+ 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"] }],
107
+ oms_status: [{ name: "oms_graph_status", direct: true }],
108
+ 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: "semantic-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 } }],
109
+ };
110
+ function operationSchema(tool) {
111
+ const toolOperations = operations[tool];
112
+ if (!toolOperations)
113
+ throw new Error(`Missing MCP operation definition for ${tool}.`);
114
+ if (toolOperations.length === 1 && toolOperations[0]?.direct) {
115
+ const { properties = {}, required = [] } = toolOperations[0];
116
+ return { type: "object", additionalProperties: false, properties, required: [...required] };
117
+ }
118
+ return { type: "object", oneOf: toolOperations.map(({ op, properties = {}, required = [] }) => ({ additionalProperties: false, properties: { op: { ...string, const: op }, ...properties }, required: ["op", ...required] })) };
119
+ }
120
+ function resolveOperation(tool, op) {
121
+ return operations[tool]?.find((operation) => operation.direct || operation.op === op)?.name;
122
+ }
69
123
  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
- },
251
- },
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: {
257
- 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,
307
- },
308
- },
124
+ { 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 } },
125
+ { 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 } },
126
+ { 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 } },
127
+ { 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 } },
128
+ { 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
129
  ];
310
130
  export function createOMSMcpServer(opts) {
311
131
  const vault = path.resolve(opts.vault);
@@ -315,17 +135,12 @@ export function createOMSMcpServer(opts) {
315
135
  // graph cache status scan the vault off the filesystem and need no model.
316
136
  // No model load, no SQLite store, no watcher: side-effect-free per boot (R2).
317
137
  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.
138
+ // Creating semantic engines are shared by all non-search tools, including
139
+ // doctor repairs which must initialize a missing store.
325
140
  let semanticEngine = null;
326
141
  const getSemanticEngine = () => {
327
142
  if (semanticEngine === null) {
328
- semanticEngine = assembleFullSemanticEngine(vault);
143
+ semanticEngine = assembleFullSemanticEngine(vault, opts.reranker);
329
144
  }
330
145
  return semanticEngine;
331
146
  };
@@ -335,10 +150,47 @@ export function createOMSMcpServer(opts) {
335
150
  let coreSemanticEngine = null;
336
151
  const getCoreSemanticEngine = () => {
337
152
  if (coreSemanticEngine === null) {
338
- coreSemanticEngine = assembleCoreSemanticEngine({ vault });
153
+ coreSemanticEngine = assembleCoreSemanticEngine({ vault, reranker: opts.reranker });
339
154
  }
340
155
  return coreSemanticEngine;
341
156
  };
157
+ // Search owns independent read-only slots so it cannot poison doctor repair.
158
+ let readOnlySemanticEngine;
159
+ const getReadOnlySemanticEngine = () => {
160
+ if (readOnlySemanticEngine === undefined) {
161
+ readOnlySemanticEngine = assembleEngineReadOnly({
162
+ vault,
163
+ embeddingProvider: process.env["OMS_EMBEDDING_PROVIDER"],
164
+ embeddingModel: process.env["OMS_EMBEDDING_MODEL"],
165
+ reranker: opts.reranker,
166
+ });
167
+ }
168
+ return readOnlySemanticEngine;
169
+ };
170
+ let readOnlyCoreSemanticEngine;
171
+ const getReadOnlyCoreSemanticEngine = () => {
172
+ if (readOnlyCoreSemanticEngine === undefined) {
173
+ readOnlyCoreSemanticEngine = assembleCoreSemanticEngineReadOnly({ vault, reranker: opts.reranker });
174
+ }
175
+ return readOnlyCoreSemanticEngine;
176
+ };
177
+ let ephemeralCoreSemanticEngine = null;
178
+ let ephemeralCoreSemanticEnginePromise = null;
179
+ const getEphemeralCoreSemanticEngine = async () => {
180
+ if (ephemeralCoreSemanticEngine !== null)
181
+ return ephemeralCoreSemanticEngine;
182
+ if (ephemeralCoreSemanticEnginePromise === null) {
183
+ ephemeralCoreSemanticEnginePromise = (async () => {
184
+ const assembled = assembleEphemeralCoreSemanticEngine({ vault, reranker: opts.reranker });
185
+ ephemeralCoreSemanticEngine = assembled;
186
+ return assembled;
187
+ })().catch((error) => {
188
+ ephemeralCoreSemanticEnginePromise = null;
189
+ throw error;
190
+ });
191
+ }
192
+ return ephemeralCoreSemanticEnginePromise;
193
+ };
342
194
  // A real embedding provider is configured iff the canonical pair is set
343
195
  // (ADR-007). The engine's model-OPTIONAL surface (document reads,
344
196
  // retrieve_context's semantic leg, ReadResource) keys off this to decide
@@ -355,7 +207,51 @@ export function createOMSMcpServer(opts) {
355
207
  // missing auth, store-open failure) must surface its error loudly rather than
356
208
  // silently masquerade as a model-less host (ADR-007). The core fallback is
357
209
  // strictly for the absent-config case.
358
- const resolveDocumentAdapter = () => hasEmbeddingModel() ? getSemanticEngine().adapter : getCoreSemanticEngine().adapter;
210
+ const resolveCreatingDocumentAdapter = () => hasEmbeddingModel() ? getSemanticEngine().adapter : getCoreSemanticEngine().adapter;
211
+ const resolveReadOnlyDocumentAdapter = () => hasEmbeddingModel()
212
+ ? getReadOnlySemanticEngine()?.adapter ?? engine.adapter
213
+ : getReadOnlyCoreSemanticEngine()?.adapter ?? engine.adapter;
214
+ const resolveDocumentAdapter = (publicName) => {
215
+ if (publicName === "oms_search")
216
+ return resolveReadOnlyDocumentAdapter();
217
+ return resolveCreatingDocumentAdapter();
218
+ };
219
+ const resolveReadOnlyIndexAdapter = () => {
220
+ const adapter = hasEmbeddingModel()
221
+ ? getReadOnlySemanticEngine()?.adapter
222
+ : getReadOnlyCoreSemanticEngine()?.adapter;
223
+ if (adapter === undefined || adapter === null)
224
+ throw new SemanticIndexUnavailableError();
225
+ return adapter;
226
+ };
227
+ const resolveReadOnlyLexicalAdapter = async () => {
228
+ const adapter = hasEmbeddingModel()
229
+ ? getReadOnlySemanticEngine()?.adapter
230
+ : getReadOnlyCoreSemanticEngine()?.adapter;
231
+ return adapter ?? (await getEphemeralCoreSemanticEngine()).adapter;
232
+ };
233
+ const hasExplicitEmbeddingIntent = (args) => requiresEmbeddings({
234
+ mode: args?.["mode"] === "vsearch" ? "vsearch" : undefined,
235
+ vec: stringArg(args, "vec"),
236
+ hyde: stringArg(args, "hyde"),
237
+ searches: Array.isArray(args?.["searches"])
238
+ ? args["searches"].flatMap((search) => isRecord(search) &&
239
+ (search["type"] === "lex" || search["type"] === "vec" || search["type"] === "hyde") &&
240
+ typeof search["query"] === "string"
241
+ ? [{ type: search["type"], query: search["query"] }]
242
+ : [])
243
+ : undefined,
244
+ });
245
+ const searchBackend = new EngineSearchBackend((requiresEmbeddings) => requiresEmbeddings
246
+ ? (() => {
247
+ // Validate ADR-007 configuration before probing the read-only store:
248
+ // vector intent is actionable only after its required provider/model
249
+ // pair is present, regardless of whether an index exists yet.
250
+ if (!hasEmbeddingModel())
251
+ return getSemanticEngine().adapter;
252
+ return resolveReadOnlyIndexAdapter();
253
+ })()
254
+ : resolveReadOnlyIndexAdapter(), vault);
359
255
  const server = new Server({ name: "oms", version: SERVER_VERSION }, {
360
256
  capabilities: { tools: {}, resources: {} },
361
257
  // Cache read only: construction must never touch the network. The
@@ -370,43 +266,35 @@ export function createOMSMcpServer(opts) {
370
266
  if (coreSemanticEngine !== null) {
371
267
  void coreSemanticEngine.dispose().catch(() => undefined);
372
268
  }
269
+ if (readOnlySemanticEngine !== null && readOnlySemanticEngine !== undefined) {
270
+ void readOnlySemanticEngine.dispose().catch(() => undefined);
271
+ }
272
+ if (readOnlyCoreSemanticEngine !== null && readOnlyCoreSemanticEngine !== undefined) {
273
+ void readOnlyCoreSemanticEngine.dispose().catch(() => undefined);
274
+ }
275
+ if (ephemeralCoreSemanticEngine !== null) {
276
+ void ephemeralCoreSemanticEngine.dispose().catch(() => undefined);
277
+ }
373
278
  };
374
279
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
375
280
  tools: omsMcpTools,
376
281
  }));
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
282
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
408
- const args = isRecord(request.params.arguments) ? request.params.arguments : undefined;
409
- if (request.params.name === "oms_graph_status") {
283
+ let args = isRecord(request.params.arguments) ? request.params.arguments : undefined;
284
+ const publicName = request.params.name;
285
+ const op = publicName === "oms_write" ? stringArg(args, "op") ?? "create" : stringArg(args, "op");
286
+ const name = resolveOperation(publicName, op);
287
+ if (!name)
288
+ return errorText(`Unknown Oh My Second Brain tool: ${publicName}`);
289
+ if (publicName === "oms_write")
290
+ args = { ...args, mode: op };
291
+ if (publicName === "oms_search" && op === "semantic-query") {
292
+ const searches = args?.["searches"];
293
+ if (typeof args?.["query"] === "string" && Array.isArray(searches)) {
294
+ return errorText('Provide exactly one of "query" or "searches" for semantic-query.');
295
+ }
296
+ }
297
+ if (name === "oms_graph_status") {
410
298
  // The src/graph derived-cache ledger (M3 5-state staleness) is the source
411
299
  // of truth for retrieve_context's optional warm cache and stays intact.
412
300
  // engineGraph is additive: it surfaces the native engine's axis cache that
@@ -429,8 +317,8 @@ export function createOMSMcpServer(opts) {
429
317
  derivedState: cacheStatus,
430
318
  engineGraph,
431
319
  writeTools: source === "cwd"
432
- ? "write-disabled-target-unverified"
433
- : "write-gated-by-verified-target-and-contract",
320
+ ? "oms_write-disabled-target-unverified"
321
+ : "oms_write-gated-by-verified-target-and-contract",
434
322
  readTools: omsMcpTools.map((tool) => tool.name),
435
323
  });
436
324
  }
@@ -453,27 +341,41 @@ export function createOMSMcpServer(opts) {
453
341
  },
454
342
  },
455
343
  engineGraph,
456
- writeTools: "disabled-invalid-ontology",
344
+ writeTools: "oms_write-disabled-invalid-ontology",
457
345
  readTools: ["oms_graph_status"],
458
346
  });
459
347
  }
460
348
  }
461
349
  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({
350
+ if (name === "oms_graph_build" || name === "oms_semantic_cleanup" || name === "oms_sync_embeddings") {
351
+ const operation = name === "oms_graph_build" ? "build-graph" : name === "oms_semantic_cleanup" ? "semantic-cleanup" : "sync-embeddings";
352
+ // A FACTORY, not a value. JavaScript evaluates an argument expression
353
+ // before entering the callee, so passing a constructed adapter here would
354
+ // open - and therefore create - `<vault>/.oms/engine-store.sqlite` before
355
+ // repairDoctor got the chance to run admission. On an invalid global
356
+ // target that means mutating a directory we are about to reject, which
357
+ // breaks the verified-target contract's requirement that admission
358
+ // precede ANY disk mutation. The kernel calls this only after admitting.
359
+ //
360
+ // Deliberately NOT re-checking admission here: two policy paths is how
361
+ // the check drifts. One authoritative decision, deferred dependency.
362
+ const resolveRepairAdapter = operation === "build-graph"
363
+ ? undefined
364
+ : () => publicName === "oms_search"
365
+ ? resolveReadOnlyDocumentAdapter()
366
+ : operation === "semantic-cleanup" || (operation === "sync-embeddings" && args?.["embed"] === false)
367
+ ? resolveCreatingDocumentAdapter()
368
+ : getSemanticEngine().adapter;
369
+ const repair = await repairDoctor({
370
+ operation,
466
371
  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,
372
+ source,
373
+ args,
374
+ resolveAdapter: resolveRepairAdapter,
474
375
  });
376
+ return repair.kind === "error" ? errorText(repair.message) : jsonText(repair.value);
475
377
  }
476
- if (request.params.name === "oms_list_concepts") {
378
+ if (name === "oms_list_concepts") {
477
379
  const { ontology, source } = await resolveActiveOntology(vault);
478
380
  return jsonText({
479
381
  vault,
@@ -482,7 +384,7 @@ export function createOMSMcpServer(opts) {
482
384
  concepts: Array.from(ontology.concepts.values()).map(conceptSummary),
483
385
  });
484
386
  }
485
- if (request.params.name === "oms_retrieve_by_axis") {
387
+ if (name === "oms_retrieve_by_axis") {
486
388
  // Engine-owned (graph-only swap): axis-first retrieval over the native
487
389
  // node index, built lazily off the filesystem — no embedding model needed.
488
390
  const limitValue = args?.["limit"];
@@ -504,13 +406,24 @@ export function createOMSMcpServer(opts) {
504
406
  ...result,
505
407
  });
506
408
  }
507
- if (request.params.name === "oms_retrieve_context") {
409
+ if (name === "oms_retrieve_context") {
508
410
  // Graph + semantic fusion. The graph leg stays on the src/graph warm cache;
509
411
  // the semantic leg routes to the native engine: vec-capable when a model is
510
412
  // configured (parity ranking, real-path docids) and core (lex; vec/HyDE fail
511
413
  // fast) otherwise. get/multi_get and ReadResource make the SAME choice, so a
512
414
  // docid emitted here always hydrates on the backend that produced it.
513
- const semanticBackend = makeEngineMorningBackend(resolveDocumentAdapter(), vault);
415
+ const semantic = semanticOptionsFromArgs(args);
416
+ let contextAdapter = engine.adapter;
417
+ if (semantic?.enabled !== false) {
418
+ try {
419
+ contextAdapter = resolveDocumentAdapter(publicName);
420
+ }
421
+ catch (error) {
422
+ if (!(error instanceof SemanticIndexUnavailableError))
423
+ throw error;
424
+ }
425
+ }
426
+ const semanticBackend = makeEngineMorningBackend(contextAdapter, vault);
514
427
  const { ontology, source } = await resolveActiveOntology(vault);
515
428
  const limitValue = args?.["limit"];
516
429
  const maxNeighborsValue = args?.["maxNeighbors"];
@@ -527,7 +440,7 @@ export function createOMSMcpServer(opts) {
527
440
  limit: typeof limitValue === "number" ? limitValue : undefined,
528
441
  maxNeighbors: typeof maxNeighborsValue === "number" ? maxNeighborsValue : undefined,
529
442
  useCache: typeof useCacheValue === "boolean" ? useCacheValue : undefined,
530
- semantic: semanticOptionsFromArgs(args),
443
+ semantic,
531
444
  }, semanticBackend);
532
445
  return jsonText({
533
446
  vault,
@@ -543,23 +456,93 @@ export function createOMSMcpServer(opts) {
543
456
  // engine when a model is configured, else the core engine. Lex is a real
544
457
  // model-free BM25/FTS feature, not an ADR-007 fake vector fallback.
545
458
  // 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);
459
+ if (isEngineSemanticOp(name) || isEngineDocumentOp(name)) {
460
+ if (name === "oms_semantic_query") {
461
+ const query = stringArg(args, "query");
462
+ const vec = stringArg(args, "vec");
463
+ const hyde = stringArg(args, "hyde");
464
+ const noPersistentReadOnlyIndex = hasEmbeddingModel()
465
+ ? getReadOnlySemanticEngine() === null
466
+ : getReadOnlyCoreSemanticEngine() === null;
467
+ if (query !== undefined && !hasExplicitEmbeddingIntent(args) && noPersistentReadOnlyIndex) {
468
+ const result = await (await getEphemeralCoreSemanticEngine()).adapter.semanticQuery({
469
+ vault,
470
+ query,
471
+ lex: stringArg(args, "lex") ?? query,
472
+ limit: typeof args?.["limit"] === "number" ? args["limit"] : undefined,
473
+ minScore: typeof args?.["minScore"] === "number" ? args["minScore"] : undefined,
474
+ intent: stringArg(args, "intent"),
475
+ collection: stringArg(args, "collection"),
476
+ index: stringArg(args, "index"),
477
+ });
478
+ return jsonText(result);
479
+ }
480
+ const requestOptions = {
481
+ limit: typeof args?.["limit"] === "number" ? args["limit"] : undefined,
482
+ candidateLimit: typeof args?.["candidateLimit"] === "number" ? args["candidateLimit"] : undefined,
483
+ rerank: typeof args?.["rerank"] === "boolean" ? args["rerank"] : undefined,
484
+ minScore: typeof args?.["minScore"] === "number" ? args["minScore"] : undefined,
485
+ intent: stringArg(args, "intent"),
486
+ collection: stringArg(args, "collection"),
487
+ collections: Array.isArray(args?.["collections"])
488
+ ? args["collections"].filter((collection) => typeof collection === "string")
489
+ : undefined,
490
+ mode: stringArg(args, "mode"),
491
+ lex: stringArg(args, "lex"),
492
+ vec,
493
+ hyde,
494
+ index: stringArg(args, "index"),
495
+ };
496
+ const result = await searchBackend.search({
497
+ ...requestOptions,
498
+ // `query` is the default lexical representation. An explicit vector
499
+ // or HyDE shorthand selects its own representation instead; only
500
+ // `query` plus typed `searches` is contradictory.
501
+ query: vec !== undefined || hyde !== undefined ? undefined : query,
502
+ searches: Array.isArray(args?.["searches"])
503
+ ? args["searches"]
504
+ : undefined,
505
+ });
506
+ return jsonText(result);
507
+ }
508
+ const useEphemeralLexicalFallback = name === "oms_semantic_query" &&
509
+ publicName === "oms_search" &&
510
+ !hasExplicitEmbeddingIntent(args) &&
511
+ (hasEmbeddingModel()
512
+ ? getReadOnlySemanticEngine() === null
513
+ : getReadOnlyCoreSemanticEngine() === null);
514
+ const semanticAdapter = useEphemeralLexicalFallback
515
+ ? await resolveReadOnlyLexicalAdapter()
516
+ :
517
+ isEngineSemanticOp(name) &&
518
+ name !== "oms_semantic_cleanup" &&
519
+ !(name === "oms_sync_embeddings" && args?.["embed"] === false) &&
520
+ !isModelOptionalSemanticQueryOp(name, args, vault)
521
+ ? publicName === "oms_search"
522
+ ? resolveReadOnlyIndexAdapter()
523
+ : getSemanticEngine().adapter
524
+ : isEngineDocumentOp(name)
525
+ ? resolveDocumentAdapter(publicName)
526
+ : publicName === "oms_search"
527
+ ? resolveReadOnlyIndexAdapter()
528
+ : resolveDocumentAdapter(publicName);
529
+ const semanticToolResult = await handleSemanticTool(name, useEphemeralLexicalFallback
530
+ ? { ...args, lex: stringArg(args, "query") }
531
+ : args, vault, semanticAdapter);
551
532
  if (semanticToolResult) {
552
- return semanticToolResult.ok ? jsonText(semanticToolResult.value) : errorText(semanticToolResult.message);
533
+ if (!semanticToolResult.ok)
534
+ return errorText(semanticToolResult.message);
535
+ return jsonText(semanticToolResult.value);
553
536
  }
554
537
  }
555
- if (request.params.name === "oms_lazy_load_note") {
538
+ if (name === "oms_lazy_load_note") {
556
539
  const notePath = stringArg(args, "notePath");
557
540
  if (!notePath) {
558
541
  return errorText('Missing required string argument "notePath".');
559
542
  }
560
543
  return jsonText(await lazyLoadNoteBody(vault, notePath));
561
544
  }
562
- if (request.params.name === "oms_validate_contract") {
545
+ if (name === "oms_validate_contract") {
563
546
  const notePath = stringArg(args, "notePath");
564
547
  if (!notePath) {
565
548
  return errorText('Missing required string argument "notePath".');
@@ -603,7 +586,7 @@ export function createOMSMcpServer(opts) {
603
586
  violations: result.violations,
604
587
  });
605
588
  }
606
- if (request.params.name === "oms_vault_audit") {
589
+ if (name === "oms_vault_audit") {
607
590
  if (args !== undefined &&
608
591
  Object.prototype.hasOwnProperty.call(args, "folder") &&
609
592
  typeof args["folder"] !== "string") {
@@ -622,7 +605,7 @@ export function createOMSMcpServer(opts) {
622
605
  violations: report.violations,
623
606
  });
624
607
  }
625
- if (request.params.name === "oms_link_suggest") {
608
+ if (name === "oms_link_suggest") {
626
609
  const notePath = stringArg(args, "notePath");
627
610
  if (!notePath) {
628
611
  return errorText('Missing required string argument "notePath".');
@@ -631,7 +614,7 @@ export function createOMSMcpServer(opts) {
631
614
  const suggestion = await suggestLinksForNote({ vault, source, ontology, notePath }, { folder: stringArg(args, "folder") });
632
615
  return jsonText({ vault, ontologySource, ...suggestion });
633
616
  }
634
- if (request.params.name === "oms_link_apply") {
617
+ if (name === "oms_link_apply") {
635
618
  const notePath = stringArg(args, "notePath");
636
619
  if (!notePath) {
637
620
  return errorText('Missing required string argument "notePath".');
@@ -648,10 +631,20 @@ export function createOMSMcpServer(opts) {
648
631
  const outcome = await applyLinksForNote({ vault, source, ontology, notePath }, { baseContentHash, candidateIds: idsArg.filter((id) => typeof id === "string") }, { folder: stringArg(args, "folder") });
649
632
  return jsonText({ vault, ontologySource, ...linkApplyPayload(outcome) });
650
633
  }
651
- if (request.params.name === "write") {
634
+ if (name === "write") {
652
635
  const { ontology, source: ontologySource } = await resolveActiveOntology(vault);
653
636
  const modeArg = stringArg(args, "mode");
654
637
  const mode = isWriteMode(modeArg) ? modeArg : "create";
638
+ // `notePath` and `folder`/`filename` are two ways to address the same
639
+ // note. Supplying both is a contradiction the caller should hear about:
640
+ // silently preferring one produced a response that reported the concept
641
+ // implied by one form and the folder implied by the other, which reads as
642
+ // corruption rather than as the input error it is.
643
+ const hasNotePath = stringArg(args, "notePath") !== undefined;
644
+ const hasFolderForm = stringArg(args, "folder") !== undefined || stringArg(args, "filename") !== undefined;
645
+ if (hasNotePath && hasFolderForm) {
646
+ return errorText('Provide either "notePath" or "folder"/"filename" to address the note, not both.');
647
+ }
655
648
  const frontmatterArg = args?.["frontmatter"];
656
649
  const result = await writeNote({
657
650
  target: { vault, source },
@@ -673,9 +666,15 @@ export function createOMSMcpServer(opts) {
673
666
  resolutionSource: source,
674
667
  });
675
668
  }
676
- return errorText(`Unknown Oh My Second Brain tool: ${request.params.name}`);
669
+ return errorText(`Unknown Oh My Second Brain tool: ${publicName}`);
677
670
  }
678
671
  catch (error) {
672
+ if (error instanceof SemanticIndexUnavailableError) {
673
+ return jsonText({
674
+ available: false,
675
+ reason: error.message,
676
+ });
677
+ }
679
678
  return errorText(`Oh My Second Brain MCP error: ${error instanceof Error ? error.message : String(error)}`);
680
679
  }
681
680
  });