neotoma 0.26.0 → 0.27.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 (280) hide show
  1. package/README.md +3 -3
  2. package/dist/actions.d.ts.map +1 -1
  3. package/dist/actions.js +165 -27
  4. package/dist/actions.js.map +1 -1
  5. package/dist/cli/index.d.ts.map +1 -1
  6. package/dist/cli/index.js +1 -1
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/docs/architecture/architecture.md +1 -1
  9. package/dist/docs/developer/cli_agent_instructions.md +3 -1
  10. package/dist/docs/developer/cli_reference.md +4 -2
  11. package/dist/docs/developer/mcp/instructions.md +8 -2
  12. package/dist/docs/developer/mcp_codex_remote_setup.md +61 -0
  13. package/dist/docs/developer/mcp_continue_setup.md +9 -17
  14. package/dist/docs/developer/mcp_letta_setup.md +5 -2
  15. package/dist/docs/developer/mcp_openclaw_setup.md +5 -3
  16. package/dist/docs/developer/mcp_overview.md +39 -19
  17. package/dist/docs/developer/mcp_vscode_setup.md +10 -23
  18. package/dist/docs/developer/mcp_windsurf_setup.md +9 -25
  19. package/dist/docs/developer/seo_analytics_verification.md +12 -10
  20. package/dist/docs/developer/site_launch_readiness.md +56 -0
  21. package/dist/docs/developer/tunnels.md +1 -1
  22. package/dist/docs/infrastructure/deployment.md +1 -1
  23. package/dist/docs/integrations/es/matrix.md +38 -0
  24. package/dist/docs/integrations/matrix.md +26 -71
  25. package/dist/docs/legal/site_privacy_notice.md +30 -8
  26. package/dist/docs/site/site_doc_manifest.yaml +7 -4
  27. package/dist/docs/specs/MCP_SPEC.md +7 -2
  28. package/dist/docs/subsystems/agent_capabilities.md +105 -4
  29. package/dist/docs/subsystems/auth.md +45 -0
  30. package/dist/docs/subsystems/conflict_resolution.md +18 -4
  31. package/dist/docs/subsystems/errors.md +1 -0
  32. package/dist/docs/subsystems/observation_architecture.md +2 -1
  33. package/dist/docs/subsystems/peer_sync.md +146 -24
  34. package/dist/docs/subsystems/reducer.md +130 -10
  35. package/dist/docs/testing/automated_test_catalog.md +84 -24
  36. package/dist/inspector/assets/{access_policies-CJOlV60d.js → access_policies-CxCjBA7D.js} +1 -1
  37. package/dist/inspector/assets/{agent_badge-BnBqn8kt.js → agent_badge-DC5_shpm.js} +1 -1
  38. package/dist/inspector/assets/{agent_detail-wP0ccjhX.js → agent_detail-BvbCiS93.js} +1 -1
  39. package/dist/inspector/assets/{agent_filter-Bp2xA131.js → agent_filter-B0yydBrx.js} +1 -1
  40. package/dist/inspector/assets/{agent_grant_detail-HIGr5dq_.js → agent_grant_detail-3kKIKzX6.js} +1 -1
  41. package/dist/inspector/assets/agent_grant_form-B6q5pZjP.js +1 -0
  42. package/dist/inspector/assets/{agent_grants-CTKkadE5.js → agent_grants-B6nfERyL.js} +1 -1
  43. package/dist/inspector/assets/{agents-CPwJLNJN.js → agents-ClGGY_ZM.js} +1 -1
  44. package/dist/inspector/assets/{api_not_configured_state-ivqIcs2c.js → api_not_configured_state-CJQ8_tf0.js} +1 -1
  45. package/dist/inspector/assets/{attribution_card-5ZAqRz6K.js → attribution_card-Bksgj8a3.js} +1 -1
  46. package/dist/inspector/assets/{attribution_summary-D_MHFv7e.js → attribution_summary-D4MXp_WI.js} +1 -1
  47. package/dist/inspector/assets/{bundles-QfMciBj9.js → bundles-ycjhJZOr.js} +1 -1
  48. package/dist/inspector/assets/{card-1rkzdi9W.js → card-4DFCisoq.js} +1 -1
  49. package/dist/inspector/assets/{checkbox-CO5dXSZf.js → checkbox-V-L1QbzC.js} +1 -1
  50. package/dist/inspector/assets/{compliance-OTGEtY7Y.js → compliance-DKt8M8nA.js} +1 -1
  51. package/dist/inspector/assets/{confirm-dialog-D0cZ5vck.js → confirm-dialog-DYa8Vbqn.js} +1 -1
  52. package/dist/inspector/assets/{conversation_common-cSILaHXq.js → conversation_common-BTYeAMA9.js} +1 -1
  53. package/dist/inspector/assets/{conversation_detail-DT-lGapN.js → conversation_detail-CW7GDcOq.js} +1 -1
  54. package/dist/inspector/assets/{copy_id_button-Dz0JDn4l.js → copy_id_button-ByAabH9A.js} +1 -1
  55. package/dist/inspector/assets/{copyable_code_block-B2f99g8Q.js → copyable_code_block-Bspyx1dk.js} +1 -1
  56. package/dist/inspector/assets/{corrections-KvxGvvLV.js → corrections-CTmXBVDZ.js} +1 -1
  57. package/dist/inspector/assets/{dashboard-BudvW21X.js → dashboard-C4yk5lEb.js} +1 -1
  58. package/dist/inspector/assets/{data-table-d9EMxowf.js → data-table-BWQDz2No.js} +1 -1
  59. package/dist/inspector/assets/{design-DyiQbEeP.js → design-DSwT0Hqn.js} +1 -1
  60. package/dist/inspector/assets/{dialog-BmW1Iw8o.js → dialog-D-_2M8D7.js} +1 -1
  61. package/dist/inspector/assets/{docs-CT3IYX0E.js → docs-BcccV5pq.js} +1 -1
  62. package/dist/inspector/assets/{docs_page_layout-CosNjUZa.js → docs_page_layout-D2iWK6hY.js} +1 -1
  63. package/dist/inspector/assets/{embed_graph-Dk1-zVnz.js → embed_graph-BjqqvjAi.js} +1 -1
  64. package/dist/inspector/assets/{empty_state-B8Ot2oGB.js → empty_state-DWHf3FCX.js} +1 -1
  65. package/dist/inspector/assets/{entities-Dt5Ts5UN.js → entities-DrG0hlC7.js} +1 -1
  66. package/dist/inspector/assets/{entity_correct-D2PHEpGY.js → entity_correct-Bpg1q7T4.js} +1 -1
  67. package/dist/inspector/assets/{entity_history-DHgNythA.js → entity_history-CJ62iQZu.js} +1 -1
  68. package/dist/inspector/assets/{entity_history_sections-Cnxblw-Z.js → entity_history_sections-BDd9Wiiu.js} +1 -1
  69. package/dist/inspector/assets/{entity_link-DWf1VD1n.js → entity_link-Bb0aaVN-.js} +1 -1
  70. package/dist/inspector/assets/{entity_relationships_by_type-B0-TLC5o.js → entity_relationships_by_type-CJyxm8EQ.js} +1 -1
  71. package/dist/inspector/assets/{entity_segment_page-CzZ0VhKm.js → entity_segment_page-q21vDqLO.js} +1 -1
  72. package/dist/inspector/assets/{entity_table_column_toggle-C73aErGE.js → entity_table_column_toggle-DN8xVqKP.js} +1 -1
  73. package/dist/inspector/assets/{entity_timeline-SAq5qvB5.js → entity_timeline-D8glraS3.js} +1 -1
  74. package/dist/inspector/assets/{entity_types-DEcDvyO0.js → entity_types-Cers3ITY.js} +1 -1
  75. package/dist/inspector/assets/{faq-DazWIFdv.js → faq-Bd-NrqaV.js} +1 -1
  76. package/dist/inspector/assets/{graph_auto_fit-CSzD7yNh.js → graph_auto_fit-BYwV350M.js} +1 -1
  77. package/dist/inspector/assets/{graph_explorer-BEXXiMQ1.js → graph_explorer-LCTji9_2.js} +1 -1
  78. package/dist/inspector/assets/{home-3AZtmjKp.js → home-EisPy9sH.js} +1 -1
  79. package/dist/inspector/assets/{index-fc4sMprn.js → index-B6DF8LVA.js} +2 -2
  80. package/dist/inspector/assets/{index-Dt_q_A1j.js → index-Cb4wreu4.js} +1 -1
  81. package/dist/inspector/assets/{index-Cii0RALL.js → index-gMZogIZg.js} +1 -1
  82. package/dist/inspector/assets/interpretations-BGaVaB-X.js +1 -0
  83. package/dist/inspector/assets/{interpretations-DtzoiGuK.js → interpretations-Cy0Bpx62.js} +1 -1
  84. package/dist/inspector/assets/{issue_author_attribution-DtmFaluD.js → issue_author_attribution-DcQIow4F.js} +1 -1
  85. package/dist/inspector/assets/{issue_detail-ChHiz9I_.js → issue_detail-DTjIEgh0.js} +1 -1
  86. package/dist/inspector/assets/{issues-BoxR2nB2.js → issues-Dphlhv_W.js} +1 -1
  87. package/dist/inspector/assets/{json_viewer-KAFp_j-8.js → json_viewer-BM4kmWFP.js} +1 -1
  88. package/dist/inspector/assets/{label-Dn0ARjYl.js → label-hdmBvRvv.js} +1 -1
  89. package/dist/inspector/assets/{live_relative_time-gOIFOOLR.js → live_relative_time-CYFW3IVl.js} +1 -1
  90. package/dist/inspector/assets/{mobile_filter_popover-2ezU-mlZ.js → mobile_filter_popover-KCC5eTUH.js} +1 -1
  91. package/dist/inspector/assets/{not_found-DwX7ikQC.js → not_found-NNkEa9Mr.js} +1 -1
  92. package/dist/inspector/assets/{oauth_callback-BDGLOyTN.js → oauth_callback-Vg8huIE7.js} +1 -1
  93. package/dist/inspector/assets/{oauth_signin-CGcCtq-V.js → oauth_signin-DgBwjyyR.js} +1 -1
  94. package/dist/inspector/assets/{observations-DvcUGpHm.js → observations-DtOGIRUt.js} +1 -1
  95. package/dist/inspector/assets/{page_shell-DiwchdUC.js → page_shell-ekehM_7R.js} +1 -1
  96. package/dist/inspector/assets/{pagination-BGIUHQkm.js → pagination-DqHnb2pk.js} +1 -1
  97. package/dist/inspector/assets/{peer_detail-DeD1sTeJ.js → peer_detail-Gkxcd75E.js} +1 -1
  98. package/dist/inspector/assets/{peers-CXe47m55.js → peers-CbWw6lyc.js} +1 -1
  99. package/dist/inspector/assets/{pin_primitive_button-C37Ha0Bt.js → pin_primitive_button-B4r-7dqY.js} +1 -1
  100. package/dist/inspector/assets/{recent_activity-CzQjt4ym.js → recent_activity-C6PVuidG.js} +1 -1
  101. package/dist/inspector/assets/{recent_conversations-BnUl4h4t.js → recent_conversations-CIdElm4H.js} +1 -1
  102. package/dist/inspector/assets/{recent_conversations-BFYZTxUJ.js → recent_conversations-D0yaACqZ.js} +1 -1
  103. package/dist/inspector/assets/{recent_records_feed-y1n0RuMa.js → recent_records_feed-CIXUCAzn.js} +1 -1
  104. package/dist/inspector/assets/record_activity-BjhZYy74.js +1 -0
  105. package/dist/inspector/assets/{relationship_detail-ic83ZCwG.js → relationship_detail-Bpefk_R5.js} +1 -1
  106. package/dist/inspector/assets/{relationship_panel_groups-CI1fZIU_.js → relationship_panel_groups-DDXpEtW5.js} +1 -1
  107. package/dist/inspector/assets/{relationships-C7iSdgXG.js → relationships-B3QrncvI.js} +1 -1
  108. package/dist/inspector/assets/{relationships-C1JrEl85.js → relationships-M99riRdd.js} +1 -1
  109. package/dist/inspector/assets/{sandbox-Dst-WJhB.js → sandbox-DucoYAes.js} +1 -1
  110. package/dist/inspector/assets/{schema_detail-C7_JSWAw.js → schema_detail-CN_3OF1B.js} +1 -1
  111. package/dist/inspector/assets/{schemas-BgrIpRVJ.js → schemas-rRFQFZKI.js} +1 -1
  112. package/dist/inspector/assets/{search-BUmT32dy.js → search-CtnCyQ8D.js} +1 -1
  113. package/dist/inspector/assets/{segmented_control-t1pBImFE.js → segmented_control-DSHm0DuI.js} +1 -1
  114. package/dist/inspector/assets/{select-DU7Jwzuy.js → select-DhzhhG8n.js} +1 -1
  115. package/dist/inspector/assets/{settings-BAPHY6RY.js → settings-B7cfSG_W.js} +1 -1
  116. package/dist/inspector/assets/{source_content-CIhKrGsl.js → source_content-Bhwy7rhS.js} +1 -1
  117. package/dist/inspector/assets/{source_content_open_button-Erw2ErgG.js → source_content_open_button-C6vUIgFc.js} +1 -1
  118. package/dist/inspector/assets/{source_detail-C0XOo0Uu.js → source_detail-C1JXqtvA.js} +1 -1
  119. package/dist/inspector/assets/{source_link-CkcRMEO3.js → source_link-BUk8ACVx.js} +1 -1
  120. package/dist/inspector/assets/{sources-C0JBEINb.js → sources-NTyTD2hT.js} +1 -1
  121. package/dist/inspector/assets/{subscriptions-DxU4kHGt.js → subscriptions-CNA06mS4.js} +1 -1
  122. package/dist/inspector/assets/{switch-BhKadp29.js → switch-DLHM_uAC.js} +1 -1
  123. package/dist/inspector/assets/{tabs-d81XObYb.js → tabs-D2_FUlH4.js} +1 -1
  124. package/dist/inspector/assets/{textarea-DTiKLH24.js → textarea-DS0t72g6.js} +1 -1
  125. package/dist/inspector/assets/{timeline-BEyKQpER.js → timeline-CVhW-34e.js} +1 -1
  126. package/dist/inspector/assets/{timeline-98QXcGln.js → timeline-CZehuTIb.js} +1 -1
  127. package/dist/inspector/assets/{timeline_event_detail-DzGzqtrx.js → timeline_event_detail-KYTlaJ99.js} +1 -1
  128. package/dist/inspector/assets/{turn_detail-CDP_FEPT.js → turn_detail-DN4VR_ut.js} +1 -1
  129. package/dist/inspector/assets/{turns-DLmr1Iue.js → turns-Bq8p8bUB.js} +1 -1
  130. package/dist/inspector/assets/{use_agents-D3rvlr5v.js → use_agents-GVOD0Ky2.js} +1 -1
  131. package/dist/inspector/assets/{use_entities-CVikeUOv.js → use_entities-Buvb5BTb.js} +1 -1
  132. package/dist/inspector/assets/use_interpretations-DDEREnBJ.js +1 -0
  133. package/dist/inspector/assets/{use_mutations-BhwSLXcJ.js → use_mutations-DbLUsoYs.js} +1 -1
  134. package/dist/inspector/assets/{use_peers-QTm1Z_BV.js → use_peers-DyQGh7km.js} +1 -1
  135. package/dist/inspector/assets/{use_relationships-DtymxAI9.js → use_relationships-djzl2cEw.js} +1 -1
  136. package/dist/inspector/assets/{use_stats-BW1Z-dI2.js → use_stats-DvaDtejF.js} +1 -1
  137. package/dist/inspector/assets/{use_timeline-DND87Sof.js → use_timeline-BL3A-Im3.js} +1 -1
  138. package/dist/inspector/assets/{use_turns-Dfb6Q8Ru.js → use_turns-DEvDeYgu.js} +1 -1
  139. package/dist/inspector/assets/{world_time_event_timeline-DxzejNrJ.js → world_time_event_timeline-DjPxlzYn.js} +1 -1
  140. package/dist/inspector/index.html +1 -1
  141. package/dist/reducers/observation_reducer.d.ts +7 -0
  142. package/dist/reducers/observation_reducer.d.ts.map +1 -1
  143. package/dist/reducers/observation_reducer.js +60 -7
  144. package/dist/reducers/observation_reducer.js.map +1 -1
  145. package/dist/repositories/sqlite/sqlite_client.d.ts.map +1 -1
  146. package/dist/repositories/sqlite/sqlite_client.js +30 -0
  147. package/dist/repositories/sqlite/sqlite_client.js.map +1 -1
  148. package/dist/server.d.ts +10 -0
  149. package/dist/server.d.ts.map +1 -1
  150. package/dist/server.js +157 -18
  151. package/dist/server.js.map +1 -1
  152. package/dist/services/agent_capabilities.d.ts +25 -1
  153. package/dist/services/agent_capabilities.d.ts.map +1 -1
  154. package/dist/services/agent_capabilities.js +5 -8
  155. package/dist/services/agent_capabilities.js.map +1 -1
  156. package/dist/services/agent_grants.d.ts.map +1 -1
  157. package/dist/services/agent_grants.js +7 -0
  158. package/dist/services/agent_grants.js.map +1 -1
  159. package/dist/services/batch_correction.d.ts +2 -1
  160. package/dist/services/batch_correction.d.ts.map +1 -1
  161. package/dist/services/batch_correction.js +29 -1
  162. package/dist/services/batch_correction.js.map +1 -1
  163. package/dist/services/bearer_slots.d.ts +109 -0
  164. package/dist/services/bearer_slots.d.ts.map +1 -0
  165. package/dist/services/bearer_slots.js +275 -0
  166. package/dist/services/bearer_slots.js.map +1 -0
  167. package/dist/services/bundles/activation.d.ts +4 -2
  168. package/dist/services/bundles/activation.d.ts.map +1 -1
  169. package/dist/services/bundles/activation.js +13 -9
  170. package/dist/services/bundles/activation.js.map +1 -1
  171. package/dist/services/correction.d.ts.map +1 -1
  172. package/dist/services/correction.js +14 -2
  173. package/dist/services/correction.js.map +1 -1
  174. package/dist/services/correction_identity.d.ts +63 -0
  175. package/dist/services/correction_identity.d.ts.map +1 -0
  176. package/dist/services/correction_identity.js +57 -0
  177. package/dist/services/correction_identity.js.map +1 -0
  178. package/dist/services/entity_lifecycle_storage.d.ts.map +1 -1
  179. package/dist/services/entity_lifecycle_storage.js +17 -4
  180. package/dist/services/entity_lifecycle_storage.js.map +1 -1
  181. package/dist/services/entity_population_certificate.d.ts +2 -0
  182. package/dist/services/entity_population_certificate.d.ts.map +1 -0
  183. package/dist/services/entity_population_certificate.js +63 -0
  184. package/dist/services/entity_population_certificate.js.map +1 -0
  185. package/dist/services/entity_queries.d.ts.map +1 -1
  186. package/dist/services/entity_queries.js +82 -41
  187. package/dist/services/entity_queries.js.map +1 -1
  188. package/dist/services/interpretation.d.ts +12 -0
  189. package/dist/services/interpretation.d.ts.map +1 -1
  190. package/dist/services/interpretation.js +88 -29
  191. package/dist/services/interpretation.js.map +1 -1
  192. package/dist/services/mutation_capability.d.ts +105 -0
  193. package/dist/services/mutation_capability.d.ts.map +1 -0
  194. package/dist/services/mutation_capability.js +262 -0
  195. package/dist/services/mutation_capability.js.map +1 -0
  196. package/dist/services/net/private_host_guard.d.ts +6 -2
  197. package/dist/services/net/private_host_guard.d.ts.map +1 -1
  198. package/dist/services/net/private_host_guard.js +14 -3
  199. package/dist/services/net/private_host_guard.js.map +1 -1
  200. package/dist/services/oauth_key_gate.d.ts.map +1 -1
  201. package/dist/services/oauth_key_gate.js +5 -0
  202. package/dist/services/oauth_key_gate.js.map +1 -1
  203. package/dist/services/observation_storage.d.ts.map +1 -1
  204. package/dist/services/observation_storage.js +4 -0
  205. package/dist/services/observation_storage.js.map +1 -1
  206. package/dist/services/rendered_page/copy_controls.d.ts +8 -0
  207. package/dist/services/rendered_page/copy_controls.d.ts.map +1 -0
  208. package/dist/services/rendered_page/copy_controls.js +122 -0
  209. package/dist/services/rendered_page/copy_controls.js.map +1 -0
  210. package/dist/services/rendered_page/html_template.d.ts.map +1 -1
  211. package/dist/services/rendered_page/html_template.js +9 -0
  212. package/dist/services/rendered_page/html_template.js.map +1 -1
  213. package/dist/services/root_landing/harness_snippets.d.ts.map +1 -1
  214. package/dist/services/root_landing/harness_snippets.js +23 -49
  215. package/dist/services/root_landing/harness_snippets.js.map +1 -1
  216. package/dist/services/root_landing/index.d.ts +1 -6
  217. package/dist/services/root_landing/index.d.ts.map +1 -1
  218. package/dist/services/root_landing/index.js +2 -16
  219. package/dist/services/root_landing/index.js.map +1 -1
  220. package/dist/services/root_landing/site_nav.js +1 -1
  221. package/dist/services/root_landing/site_nav.js.map +1 -1
  222. package/dist/services/store_admission.d.ts +26 -0
  223. package/dist/services/store_admission.d.ts.map +1 -1
  224. package/dist/services/store_admission.js +74 -6
  225. package/dist/services/store_admission.js.map +1 -1
  226. package/dist/services/sync/conflict_resolver.d.ts +39 -5
  227. package/dist/services/sync/conflict_resolver.d.ts.map +1 -1
  228. package/dist/services/sync/conflict_resolver.js +250 -18
  229. package/dist/services/sync/conflict_resolver.js.map +1 -1
  230. package/dist/services/sync/full_sync.d.ts +12 -0
  231. package/dist/services/sync/full_sync.d.ts.map +1 -1
  232. package/dist/services/sync/full_sync.js +78 -9
  233. package/dist/services/sync/full_sync.js.map +1 -1
  234. package/dist/services/sync/peer_ops.d.ts +8 -0
  235. package/dist/services/sync/peer_ops.d.ts.map +1 -1
  236. package/dist/services/sync/peer_ops.js +26 -0
  237. package/dist/services/sync/peer_ops.js.map +1 -1
  238. package/dist/services/sync/remote_snapshot_admission.d.ts +144 -0
  239. package/dist/services/sync/remote_snapshot_admission.d.ts.map +1 -0
  240. package/dist/services/sync/remote_snapshot_admission.js +248 -0
  241. package/dist/services/sync/remote_snapshot_admission.js.map +1 -0
  242. package/dist/services/sync/seed_peer_schema.d.ts.map +1 -1
  243. package/dist/services/sync/seed_peer_schema.js +8 -0
  244. package/dist/services/sync/seed_peer_schema.js.map +1 -1
  245. package/dist/services/sync/sync_webhook_inbound.d.ts.map +1 -1
  246. package/dist/services/sync/sync_webhook_inbound.js +37 -9
  247. package/dist/services/sync/sync_webhook_inbound.js.map +1 -1
  248. package/dist/services/sync/sync_webhook_outbound.d.ts +8 -0
  249. package/dist/services/sync/sync_webhook_outbound.d.ts.map +1 -1
  250. package/dist/services/sync/sync_webhook_outbound.js +74 -0
  251. package/dist/services/sync/sync_webhook_outbound.js.map +1 -1
  252. package/dist/shared/action_handlers/entity_handlers.d.ts.map +1 -1
  253. package/dist/shared/action_handlers/entity_handlers.js +3 -20
  254. package/dist/shared/action_handlers/entity_handlers.js.map +1 -1
  255. package/dist/shared/action_schemas.d.ts +12 -0
  256. package/dist/shared/action_schemas.d.ts.map +1 -1
  257. package/dist/shared/action_schemas.js +8 -2
  258. package/dist/shared/action_schemas.js.map +1 -1
  259. package/dist/shared/harness_connections.d.ts +37 -0
  260. package/dist/shared/harness_connections.d.ts.map +1 -0
  261. package/dist/shared/harness_connections.js +339 -0
  262. package/dist/shared/harness_connections.js.map +1 -0
  263. package/dist/shared/http_content_negotiation.d.ts +7 -0
  264. package/dist/shared/http_content_negotiation.d.ts.map +1 -0
  265. package/dist/shared/http_content_negotiation.js +17 -0
  266. package/dist/shared/http_content_negotiation.js.map +1 -0
  267. package/dist/shared/openapi_types.d.ts +333 -9
  268. package/dist/shared/openapi_types.d.ts.map +1 -1
  269. package/dist/tool_definitions.d.ts +6 -0
  270. package/dist/tool_definitions.d.ts.map +1 -1
  271. package/dist/tool_definitions.js +12 -5
  272. package/dist/tool_definitions.js.map +1 -1
  273. package/docs/README.md +1 -1
  274. package/docs/developer/mcp/instructions.md +8 -2
  275. package/openapi.yaml +269 -7
  276. package/package.json +5 -5
  277. package/dist/inspector/assets/agent_grant_form-BoNBvzEf.js +0 -1
  278. package/dist/inspector/assets/interpretations-CjR2csNL.js +0 -1
  279. package/dist/inspector/assets/record_activity-kXm-jtQ6.js +0 -1
  280. package/dist/inspector/assets/use_interpretations-CCoQ6ihs.js +0 -1
package/README.md CHANGED
@@ -61,13 +61,13 @@ graph LR
61
61
 
62
62
  ## What you can do with it
63
63
 
64
- Neotoma v0.26.0 exposes 67 MCP tools and 112 REST paths in its OpenAPI spec. They cover largely the same capabilities, but the MCP server, the REST API, and the CLI are separate implementations, and some checks and attribution differ between them (see Known limitations). The capability surface includes:
64
+ Neotoma v0.27.0 exposes 67 MCP tools and 112 REST paths in its OpenAPI spec. They cover largely the same capabilities, but the MCP server, the REST API, and the CLI are separate implementations, and some checks and attribution differ between them (see Known limitations). The capability surface includes:
65
65
 
66
66
  **Ingest and store.** Store structured records or raw files in one call. File ingestion extracts text from PDF (with a first-page image fallback), CSV (with adaptive chunking for large files), Parquet, JSON, and plain text; images and audio are stored as raw sources. A committed, keyed structured store started on v0.26.0 that stops partway finishes its missing observations on a same-key retry; a store carrying an interpretation returns `ERR_STORE_WRITE_INCOMPLETE`, and keys left over from earlier versions behave differently over MCP and HTTP (see Known limitations). See Known limitations.
67
67
 
68
68
  **Resolve, retrieve, and search.** Look up entities by identifier (name, email, and similar), resolve identity from multiple signals with confidence scoring, list observations, retrieve a field's provenance chain, traverse the relationship graph N hops, and pull a full graph neighborhood. When an embedding key is configured, semantic vector search runs over entity snapshots (stored locally in sqlite-vec); keyword filtering works without it.
69
69
 
70
- **Correct and evolve.** Submit corrections as high-priority observations, never edits; the earlier observation stays readable. Schemas are inferred from your data, recommended from recurring unknown fields, and can be auto-enhanced or updated incrementally with versioning. New entity types work without any code change.
70
+ **Correct and evolve.** Submit corrections as observations marked as corrections, never edits: a correction wins in the snapshot until a later correction for the same field replaces it, on array fields too, and the earlier observation stays readable. Schemas are inferred from your data, recommended from recurring unknown fields, and can be auto-enhanced or updated incrementally with versioning. New entity types work without any code change.
71
71
 
72
72
  **Relate and sequence.** Create typed relationships (for example `PART_OF`, `DEPENDS_ON`, `REFERS_TO`, `DUPLICATE_OF`), query timeline events across types and date ranges, and read an entity's observation history in a deterministic order.
73
73
 
@@ -111,7 +111,7 @@ neotoma init
111
111
  neotoma setup --tool claude-code
112
112
  ```
113
113
 
114
- In v0.26.0, `neotoma setup --tool claude-code` writes the MCP entries and more:
114
+ In v0.27.0, `neotoma setup --tool claude-code` writes the MCP entries and more:
115
115
 
116
116
  - Two MCP entries in the project's `.mcp.json`: `neotoma-dev` (development profile, `neotoma.db`) and `neotoma` (production profile, `neotoma.prod.db`). They use separate databases, so an agent on one entry does not see what an agent on the other stored.
117
117
  - CLI instruction files for Claude Code, Cursor, and Codex in the project: `.claude/rules/neotoma_cli.mdc`, `.cursor/rules/neotoma_cli.mdc`, and `.codex/neotoma_cli.md`.
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
package/dist/actions.js CHANGED
@@ -1,4 +1,4 @@
1
- import { preflightStructuredStoreAdmission, } from "./services/store_admission.js";
1
+ import { assertCurrentAgentMayStoreEntityTypes, assertStoreEntityTypesNamed, InvalidEntityTypeError, preflightStructuredStoreAdmission, } from "./services/store_admission.js";
2
2
  import express from "express";
3
3
  import cookieParser from "cookie-parser";
4
4
  import cors from "cors";
@@ -38,6 +38,7 @@ import { CursorError } from "./services/entity_cursor.js";
38
38
  import { assertNoShadowedRoutes } from "./services/route_shadowing.js";
39
39
  import { StorePolicyDeniedError, StorePolicyUnavailableError } from "./services/instance_policy.js";
40
40
  import { AgentCapabilityError, contextFromAgentIdentity, enforceAgentCapability, } from "./services/agent_capabilities.js";
41
+ import { ISSUE_THREAD_ENTITY_TYPES, assertCurrentAgentMay, assertCurrentAgentMayLink, assertCurrentAgentMayOnEntities, assetEntityTypeForMimeType, } from "./services/mutation_capability.js";
41
42
  import { AccessPolicyError } from "./services/access_policy.js";
42
43
  import { hashGuestAccessToken } from "./services/guest_access_token.js";
43
44
  import { subscriptionWithinGuestScope } from "./services/subscriptions/guest_scope.js";
@@ -73,6 +74,7 @@ import { getSandboxTermsResponse } from "./services/sandbox/terms.js";
73
74
  import { resolveSandboxReportTransport } from "./services/sandbox/transport.js";
74
75
  import { getDb } from "./repositories/db/connection.js";
75
76
  import { getMcpAuthToken } from "./crypto/mcp_auth_token.js";
77
+ import { announceBearerHandoverStatus, matchConfiguredBearer, recordPreviousBearerUse, } from "./services/bearer_slots.js";
76
78
  import { isOauthKeyCredentialValid, normalizeOauthNextPath, OAuthKeySessionStore, } from "./services/oauth_key_gate.js";
77
79
  import { buildGoogleAuthorizeUrl, createGoogleSigninNonce, consumeGoogleSigninNonce, exchangeGoogleAuthorizationCode, getSharedGraphUserId, GoogleIdTokenError, isGoogleSigninEnabled, verifyGoogleIdToken, } from "./services/google_oidc.js";
78
80
  import { AnalyzeSchemaCandidatesRequestSchema, AuditUndeclaredFragmentsRequestSchema, CorrectEntityRequestSchema, PatchArrayItemRequestSchema, CreateInterpretationRequestSchema, CreateRelationshipsRequestSchema, CreateRelationshipRequestSchema, DeleteEntityRequestSchema, DeleteRelationshipRequestSchema, IssuesBulkEntityIdsRequestSchema, IssuesAddMessageRequestSchema, IssuesGetStatusRequestSchema, IssuesSubmitRequestSchema, IssuesSyncRequestSchema, EntitiesQueryRequestSchema, EntitySnapshotRequestSchema, FieldProvenanceRequestSchema, GetSchemaRecommendationsRequestSchema, ListObservationsRequestSchema, ListRelationshipsRequestSchema, MergeEntitiesRequestSchema, SplitEntityRequestSchema, ObservationsQueryRequestSchema, RegisterSchemaRequestSchema, RelationshipSnapshotRequestSchema, RestoreEntityRequestSchema, RestoreRelationshipRequestSchema, RetrieveEntityByIdentifierSchema, RetrieveGraphNeighborhoodSchema, RetrieveRelatedEntitiesSchema, RELATIONSHIP_ENTITY_ID_FORMAT_HINT, RELATIONSHIP_ENTITY_ID_FORMAT_ISSUE_CODE, ObservationSourceSchema, StoreRequestSchema, UpdateSchemaIncrementalRequestSchema, } from "./shared/action_schemas.js";
@@ -1805,7 +1807,20 @@ app.all("/mcp", async (req, res) => {
1805
1807
  }
1806
1808
  if (authHeader?.startsWith("Bearer ") && process.env.NEOTOMA_BEARER_TOKEN) {
1807
1809
  const token = authHeader.slice(7).trim();
1808
- if (safeCompareTokens(token, process.env.NEOTOMA_BEARER_TOKEN)) {
1810
+ // Either configured slot (primary, or the retiring bearer while its
1811
+ // handover window is open) takes the SAME branch: same principal,
1812
+ // same grants. See src/services/bearer_slots.ts.
1813
+ const slot = matchConfiguredBearer(token);
1814
+ if (slot) {
1815
+ if (slot === "previous") {
1816
+ recordPreviousBearerUse({
1817
+ surface: "mcp",
1818
+ method: req.method,
1819
+ path: req.path,
1820
+ userAgent: req.headers["user-agent"],
1821
+ clientName: req.headers["x-client-name"],
1822
+ });
1823
+ }
1809
1824
  setGateConnectionIdHeader(req, "dev-local");
1810
1825
  connectionIdHeader = "dev-local";
1811
1826
  bearerValidated = true;
@@ -3825,10 +3840,22 @@ app.use(async (req, res, next) => {
3825
3840
  }
3826
3841
  if (headerAuth.startsWith("Bearer ") && process.env.NEOTOMA_BEARER_TOKEN) {
3827
3842
  const token = headerAuth.slice(7).trim();
3828
- if (safeCompareTokens(token, process.env.NEOTOMA_BEARER_TOKEN)) {
3843
+ // Either configured slot takes the SAME branch: same principal, same
3844
+ // grants. See src/services/bearer_slots.ts.
3845
+ const slot = matchConfiguredBearer(token);
3846
+ if (slot) {
3847
+ if (slot === "previous") {
3848
+ recordPreviousBearerUse({
3849
+ surface: "rest",
3850
+ method: req.method,
3851
+ path: req.path,
3852
+ userAgent: req.headers["user-agent"],
3853
+ clientName: req.headers["x-client-name"],
3854
+ });
3855
+ }
3829
3856
  const devUser = await ensureLocalDevUser();
3830
3857
  stampUserPrincipal(req, devUser.id);
3831
- logger.info(`[Auth] ${req.method} ${req.path} auth_method=bearer_env user_id=${devUser.id}`);
3858
+ logger.info(`[Auth] ${req.method} ${req.path} auth_method=${slot === "previous" ? "bearer_env_previous" : "bearer_env"} user_id=${devUser.id}`);
3832
3859
  return next();
3833
3860
  }
3834
3861
  }
@@ -4594,26 +4621,10 @@ app.get("/entities/:id/html", async (req, res) => {
4594
4621
  if (etag)
4595
4622
  res.setHeader("ETag", etag);
4596
4623
  res.setHeader("Content-Type", "text/html; charset=utf-8");
4597
- // SECURITY (Phase 2, stored XSS in publish_rendered_page): html_body is
4598
- // author-supplied and served verbatim, and the GLOBAL CSP allows
4599
- // 'unsafe-inline' scripts — so an injected <script> in a rendered page would
4600
- // execute in this origin (a page minted with a guest access_token is viewable
4601
- // unauthenticated). Rendered pages are static CONTENT, never applications:
4602
- // they never need to run script. Override the global policy for THIS response
4603
- // with a strict, self-contained CSP that blocks all script execution (inline
4604
- // and external) and sandboxes the document, neutralizing stored XSS regardless
4605
- // of html_body contents. Inline <style> from the template is still allowed.
4606
- res.setHeader("Content-Security-Policy", [
4607
- "default-src 'none'",
4608
- "script-src 'none'",
4609
- "style-src 'unsafe-inline'",
4610
- "img-src 'self' data:",
4611
- "font-src 'self' data:",
4612
- "base-uri 'none'",
4613
- "form-action 'none'",
4614
- "frame-ancestors 'self'",
4615
- "sandbox allow-same-origin",
4616
- ].join("; "));
4624
+ // Author scripts stay blocked. Opted-in copy blocks permit only the fixed
4625
+ // renderer-owned helper, confined to an opaque-origin sandbox.
4626
+ const { renderedPageContentSecurityPolicy } = await import("./services/rendered_page/copy_controls.js");
4627
+ res.setHeader("Content-Security-Policy", renderedPageContentSecurityPolicy(htmlBody));
4617
4628
  res.setHeader("X-Content-Type-Options", "nosniff");
4618
4629
  return res.send(html);
4619
4630
  }
@@ -4671,6 +4682,10 @@ app.post("/entities/:id/batch_correct", async (req, res) => {
4671
4682
  if (error instanceof Error && error.message.includes("Not authenticated")) {
4672
4683
  return sendError(res, 401, "AUTH_REQUIRED", error.message);
4673
4684
  }
4685
+ // Capability denial: same 403 `capability_denied` envelope as /correct.
4686
+ if (error instanceof AgentCapabilityError) {
4687
+ return handleApiError(req, res, error, "Failed to apply batch correction", "DB_QUERY_FAILED", "AgentCapabilityRejection:entity_batch_correct");
4688
+ }
4674
4689
  logError("APIError:entity_batch_correct", req, error);
4675
4690
  const message = error instanceof Error ? error.message : "Failed to apply batch correction";
4676
4691
  return sendError(res, 500, "DB_QUERY_FAILED", message);
@@ -6097,6 +6112,10 @@ app.post("/interpretations/create", async (req, res) => {
6097
6112
  }
6098
6113
  try {
6099
6114
  const userId = await getAuthenticatedUserId(req, parsed.data.user_id);
6115
+ // Same per-type `store` capability scope `/store` applies, before any
6116
+ // source lookup or write. No-op without an agent identity.
6117
+ const { assertInterpretationStoreCapability, runInterpretation } = await import("./services/interpretation.js");
6118
+ await assertInterpretationStoreCapability(userId, parsed.data.entities);
6100
6119
  const { data: source, error: sourceError } = await db
6101
6120
  .from("sources")
6102
6121
  .select("id")
@@ -6108,7 +6127,6 @@ app.post("/interpretations/create", async (req, res) => {
6108
6127
  if (!source) {
6109
6128
  return sendError(res, 404, "SOURCE_NOT_FOUND", "Source not found for authenticated user");
6110
6129
  }
6111
- const { runInterpretation } = await import("./services/interpretation.js");
6112
6130
  const interpretationResult = await runInterpretation({
6113
6131
  userId,
6114
6132
  sourceId: parsed.data.source_id,
@@ -6190,6 +6208,14 @@ app.post("/interpretations/create", async (req, res) => {
6190
6208
  });
6191
6209
  }
6192
6210
  catch (error) {
6211
+ // Capability denial: same 403 `capability_denied` envelope as `/store`.
6212
+ if (error instanceof AgentCapabilityError) {
6213
+ return handleApiError(req, res, error, "Failed to create interpretation", "INTERPRETATION_CREATE_FAILED", "AgentCapabilityRejection:interpretations_create");
6214
+ }
6215
+ if (error instanceof InvalidEntityTypeError) {
6216
+ logWarn("InvalidEntityTypeError:interpretations_create", req, { code: error.code });
6217
+ return sendError(res, 400, error.code, error.message, { hint: error.hint });
6218
+ }
6193
6219
  logError("APIError:interpretations_create", req, error);
6194
6220
  const message = error instanceof Error ? error.message : "Failed to create interpretation";
6195
6221
  return sendError(res, 500, "INTERPRETATION_CREATE_FAILED", message);
@@ -6302,6 +6328,9 @@ app.post("/observations/create", async (req, res) => {
6302
6328
  .status(403)
6303
6329
  .json(buildErrorEnvelope("FORBIDDEN", "user_id does not match authenticated user."));
6304
6330
  }
6331
+ // Same per-type `store` capability scope `/store` applies, before the
6332
+ // entity is resolved or created. No-op without an agent identity.
6333
+ assertCurrentAgentMayStoreEntityTypes([entity_type]);
6305
6334
  const { resolveEntity } = await import("./services/entity_resolution.js");
6306
6335
  const { createObservation } = await import("./services/observation_storage.js");
6307
6336
  const { getSnapshot, recomputeSnapshot } = await import("./services/snapshot_computation.js");
@@ -6333,6 +6362,10 @@ app.post("/observations/create", async (req, res) => {
6333
6362
  });
6334
6363
  }
6335
6364
  catch (error) {
6365
+ // Capability denial: same 403 `capability_denied` envelope as `/store`.
6366
+ if (error instanceof AgentCapabilityError) {
6367
+ return handleApiError(req, res, error, "Failed to create observation", "DB_QUERY_FAILED", "AgentCapabilityRejection:observations_create");
6368
+ }
6336
6369
  logError("APIError:observations_create", req, error);
6337
6370
  const message = error instanceof Error ? error.message : "Failed to create observation";
6338
6371
  return res.status(500).json(buildErrorEnvelope("DB_QUERY_FAILED", message));
@@ -7619,6 +7652,9 @@ export async function storeUnstructuredForApi(params) {
7619
7652
  observations_created: 0,
7620
7653
  };
7621
7654
  }
7655
+ // Agent grants: an upload is recorded under its asset type (the type the
7656
+ // MCP leg writes for the same bytes). Checked before the source is stored.
7657
+ assertCurrentAgentMay("store", [assetEntityTypeForMimeType(mimeType)], { guestCapable: true });
7622
7658
  if (storageMode === "reference") {
7623
7659
  if (!filePath) {
7624
7660
  throw new Error("filePath is required for reference storage mode");
@@ -7693,9 +7729,24 @@ async function handleStorePost(req, res) {
7693
7729
  const { assertConditionalStoreRequest } = await import("./services/store_condition_request.js");
7694
7730
  assertConditionalStoreRequest(parsed.data);
7695
7731
  const hasEntities = Boolean(parsed.data.entities?.length);
7732
+ // Every entity must name its type as a non-empty string, for every caller
7733
+ // kind, before either leg of the request writes anything.
7734
+ if (hasEntities)
7735
+ assertStoreEntityTypesNamed(parsed.data.entities);
7696
7736
  const hasFileContent = Boolean(parsed.data.file_content && parsed.data.mime_type);
7697
7737
  const hasFilePath = Boolean(parsed.data.file_path);
7698
7738
  const hasUnstructured = hasFileContent || hasFilePath;
7739
+ // Agent grants on the file leg, before either leg writes, so a combined
7740
+ // entities-and-file call refused on the file writes no entities either.
7741
+ if (hasUnstructured && parsed.data.commit !== false) {
7742
+ const uploadMime = parsed.data.mime_type ||
7743
+ (parsed.data.file_path
7744
+ ? getMimeTypeFromExtension(path.extname(parsed.data.file_path).toLowerCase())
7745
+ : undefined);
7746
+ assertCurrentAgentMay("store", [assetEntityTypeForMimeType(uploadMime)], {
7747
+ guestCapable: true,
7748
+ });
7749
+ }
7699
7750
  if (hasEntities && hasUnstructured && parsed.data.commit !== false) {
7700
7751
  const { claimCombinedStoreKeys } = await import("./services/store_combined_admission.js");
7701
7752
  await claimCombinedStoreKeys({
@@ -7863,6 +7914,10 @@ async function handleStorePost(req, res) {
7863
7914
  logWarn("AgentGrantPinConflict:store", req, { code: error.code });
7864
7915
  return sendError(res, 409, error.code, error.message, { field: error.field });
7865
7916
  }
7917
+ if (error instanceof InvalidEntityTypeError) {
7918
+ logWarn("InvalidEntityTypeError:store", req, { code: error.code });
7919
+ return sendError(res, 400, error.code, error.message, { hint: error.hint });
7920
+ }
7866
7921
  if (errCode === "ERR_FORBIDDEN_ENTITY_TYPE" || errCode === "ERR_PLURAL_ENTITY_TYPE") {
7867
7922
  const message = error instanceof Error ? error.message : String(error);
7868
7923
  logWarn("EntityTypeGuardError:store", req, { code: errCode, message });
@@ -8083,6 +8138,10 @@ app.post("/sync/webhook", express.raw({ type: "application/json", limit: "2mb" }
8083
8138
  if (msg === "INVALID_JSON" || msg.startsWith("VALIDATION_ERROR")) {
8084
8139
  return sendError(res, 400, "VALIDATION_ERROR", msg);
8085
8140
  }
8141
+ if (msg.startsWith("REMOTE_ENTITY_TYPE_REFUSED")) {
8142
+ const { SYNC_ENTITY_TYPE_REFUSED_ERROR_CODE } = await import("./services/sync/remote_snapshot_admission.js");
8143
+ return sendError(res, 403, SYNC_ENTITY_TYPE_REFUSED_ERROR_CODE, msg);
8144
+ }
8086
8145
  logError("APIError:sync_webhook", req, err);
8087
8146
  return sendError(res, 500, "SYNC_WEBHOOK_FAILED", msg);
8088
8147
  }
@@ -8159,6 +8218,9 @@ app.post("/peers", express.json(), async (req, res) => {
8159
8218
  return res.status(201).json(out);
8160
8219
  }
8161
8220
  catch (error) {
8221
+ if (error instanceof AgentCapabilityError) {
8222
+ return handleApiError(req, res, error, "Failed to add peer");
8223
+ }
8162
8224
  logError("APIError:peers_add", req, error);
8163
8225
  const message = error instanceof Error ? error.message : "Failed to add peer";
8164
8226
  if (message.includes("Maximum peers")) {
@@ -8167,8 +8229,11 @@ app.post("/peers", express.json(), async (req, res) => {
8167
8229
  return sendError(res, 500, "PEER_ADD_FAILED", message);
8168
8230
  }
8169
8231
  });
8170
- // POST /peers/resolve_sync_conflict — stub (use `correct` today). Registered
8171
- // before `/peers/:peer_id` so `resolve_sync_conflict` is not captured as a peer_id.
8232
+ // POST /peers/resolve_sync_conflict — resolve a replication conflict. `prefer_remote`
8233
+ // and `manual` write correction-tier values, so they run the same `correct` capability
8234
+ // gate as `/correct`; `prefer_remote` applies the differing fields as one correction
8235
+ // transaction and reports applied and withheld fields. Registered before
8236
+ // `/peers/:peer_id` so `resolve_sync_conflict` is not captured as a peer_id.
8172
8237
  app.post("/peers/resolve_sync_conflict", express.json(), async (req, res) => {
8173
8238
  const schema = z.object({
8174
8239
  entity_id: z.string().min(1),
@@ -8199,6 +8264,14 @@ app.post("/peers/resolve_sync_conflict", express.json(), async (req, res) => {
8199
8264
  return res.json(result);
8200
8265
  }
8201
8266
  catch (error) {
8267
+ // A capability or protected-type refusal is the caller's authorization,
8268
+ // not a server fault: 403 with the envelope `/correct` returns.
8269
+ if (error instanceof AgentCapabilityError) {
8270
+ logWarn("AgentCapabilityRejection:peers_resolve", req, error.toErrorEnvelope());
8271
+ return res
8272
+ .status(403)
8273
+ .json(buildErrorEnvelope(error.code, error.message, error.toErrorEnvelope()));
8274
+ }
8202
8275
  logError("APIError:peers_resolve", req, error);
8203
8276
  const message = error instanceof Error ? error.message : "resolve failed";
8204
8277
  return sendError(res, 500, "PEER_RESOLVE_FAILED", message);
@@ -8225,11 +8298,16 @@ app.get("/peers/:peer_id", async (req, res) => {
8225
8298
  app.delete("/peers/:peer_id", async (req, res) => {
8226
8299
  try {
8227
8300
  const userId = await getAuthenticatedUserId(req);
8301
+ // Agent grants: removing a peer corrects its peer_config.
8302
+ assertCurrentAgentMay("correct", ["peer_config"]);
8228
8303
  const { removePeerForUser } = await import("./services/sync/peer_ops.js");
8229
8304
  await removePeerForUser({ userId, peer_id: req.params.peer_id });
8230
8305
  return res.json({ success: true });
8231
8306
  }
8232
8307
  catch (error) {
8308
+ if (error instanceof AgentCapabilityError) {
8309
+ return handleApiError(req, res, error, "Failed to remove peer");
8310
+ }
8233
8311
  logError("APIError:peers_remove", req, error);
8234
8312
  const message = error instanceof Error ? error.message : "Failed to remove peer";
8235
8313
  if (message.includes("not found")) {
@@ -8245,11 +8323,17 @@ app.post("/peers/:peer_id/sync", express.json(), async (req, res) => {
8245
8323
  const bodySchema = z.object({ limit: z.number().int().positive().max(500).optional() });
8246
8324
  const bodyParsed = bodySchema.safeParse(req.body ?? {});
8247
8325
  const limit = bodyParsed.success ? bodyParsed.data.limit : undefined;
8326
+ // Agent grants: a sync run sends local data to the peer and advances the
8327
+ // peer_config watermark; pulled rows are still checked per type by store.
8328
+ assertCurrentAgentMay("correct", ["peer_config"]);
8248
8329
  const { syncPeerFull } = await import("./services/sync/full_sync.js");
8249
8330
  const result = await syncPeerFull({ userId, peer_id: req.params.peer_id, limit });
8250
8331
  return res.json(result);
8251
8332
  }
8252
8333
  catch (error) {
8334
+ if (error instanceof AgentCapabilityError) {
8335
+ return handleApiError(req, res, error, "sync_peer failed");
8336
+ }
8253
8337
  logError("APIError:peers_sync", req, error);
8254
8338
  const message = error instanceof Error ? error.message : "sync_peer failed";
8255
8339
  return sendError(res, 500, "PEER_SYNC_FAILED", message);
@@ -8350,6 +8434,8 @@ app.post("/entities/merge", async (req, res) => {
8350
8434
  if (providedUserId && providedUserId !== authenticatedUserId) {
8351
8435
  return sendError(res, 403, "FORBIDDEN", "user_id does not match authenticated user.");
8352
8436
  }
8437
+ // Agent grants: `merge` on both entities' stored types, before any write.
8438
+ await assertCurrentAgentMayOnEntities("merge", user_id, [from_entity_id, to_entity_id]);
8353
8439
  const { mergeEntities } = await import("./services/entity_merge.js");
8354
8440
  const result = await mergeEntities({
8355
8441
  fromEntityId: from_entity_id,
@@ -8361,6 +8447,9 @@ app.post("/entities/merge", async (req, res) => {
8361
8447
  return res.json(result);
8362
8448
  }
8363
8449
  catch (error) {
8450
+ if (error instanceof AgentCapabilityError) {
8451
+ return handleApiError(req, res, error, "Failed to merge entities");
8452
+ }
8364
8453
  const { EntityNotFoundError, EntityAlreadyMergedError } = await import("./services/entity_merge.js");
8365
8454
  if (error instanceof EntityNotFoundError) {
8366
8455
  return sendError(res, 404, "RESOURCE_NOT_FOUND", error.message);
@@ -8390,6 +8479,9 @@ app.post("/entities/split", async (req, res) => {
8390
8479
  return sendError(res, 403, "FORBIDDEN", "user_id does not match authenticated user.");
8391
8480
  }
8392
8481
  const userId = providedUserId || authenticatedUserId;
8482
+ // Agent grants: `split` on the source's stored type, the new entity's
8483
+ // type and, when the split targets an existing entity, its stored type.
8484
+ await assertCurrentAgentMayOnEntities("split", userId, [parsed.data.source_entity_id, parsed.data.new_entity.target_entity_id ?? ""], [parsed.data.new_entity.entity_type]);
8393
8485
  const { splitEntity } = await import("./services/entity_split.js");
8394
8486
  const result = await splitEntity({
8395
8487
  sourceEntityId: parsed.data.source_entity_id,
@@ -8407,6 +8499,9 @@ app.post("/entities/split", async (req, res) => {
8407
8499
  return res.json(result);
8408
8500
  }
8409
8501
  catch (error) {
8502
+ if (error instanceof AgentCapabilityError) {
8503
+ return handleApiError(req, res, error, "Failed to split entity");
8504
+ }
8410
8505
  const { EntityNotFoundError, EntityAlreadyMergedError, SplitPredicateMatchedNothingError, SplitPredicateMatchedAllError, IdempotencyMismatchError, } = await import("./services/entity_split.js");
8411
8506
  if (error instanceof EntityNotFoundError) {
8412
8507
  return sendError(res, 404, "RESOURCE_NOT_FOUND", error.message);
@@ -9177,6 +9272,9 @@ app.post("/delete_entity", async (req, res) => {
9177
9272
  try {
9178
9273
  const userId = await getAuthenticatedUserId(req, parsed.data.user_id);
9179
9274
  const { entity_id, entity_type, reason } = parsed.data;
9275
+ // Agent grants: `delete` on the stored type (and the type the request
9276
+ // names), before the deletion observation is written.
9277
+ await assertCurrentAgentMayOnEntities("delete", userId, [entity_id], [entity_type]);
9180
9278
  const { softDeleteEntity } = await import("./services/deletion.js");
9181
9279
  const result = await softDeleteEntity(entity_id, entity_type, userId, reason);
9182
9280
  if (!result.success) {
@@ -9199,6 +9297,8 @@ app.post("/issues/bulk_close", async (req, res) => {
9199
9297
  }
9200
9298
  try {
9201
9299
  const userId = await getAuthenticatedUserId(req, parsed.data.user_id);
9300
+ // Agent grants: closing corrects the issue (and its GitHub state).
9301
+ await assertCurrentAgentMayOnEntities("correct", userId, parsed.data.entity_ids, ["issue"]);
9202
9302
  const { bulkCloseIssues } = await import("./services/issues/inspector_bulk.js");
9203
9303
  const { results } = await bulkCloseIssues(userId, parsed.data.entity_ids);
9204
9304
  logDebug("Success:issues_bulk_close", req, { count: results.length });
@@ -9217,6 +9317,8 @@ app.post("/issues/bulk_remove", async (req, res) => {
9217
9317
  }
9218
9318
  try {
9219
9319
  const userId = await getAuthenticatedUserId(req, parsed.data.user_id);
9320
+ // Agent grants: removal closes and soft-deletes the issue.
9321
+ await assertCurrentAgentMayOnEntities("delete", userId, parsed.data.entity_ids, ["issue"]);
9220
9322
  const { bulkRemoveIssues } = await import("./services/issues/inspector_bulk.js");
9221
9323
  const { results } = await bulkRemoveIssues(userId, parsed.data.entity_ids);
9222
9324
  logDebug("Success:issues_bulk_remove", req, { count: results.length });
@@ -9239,6 +9341,15 @@ const handleIssuesAddMessageHttp = async (req, res) => {
9239
9341
  const userId = principal.kind === "guest"
9240
9342
  ? (await resolveGuestScopedEntityAccess(principal, parsed.data.entity_id?.trim() || "", "issue")).userId
9241
9343
  : await getAuthenticatedUserId(req, parsed.data.user_id);
9344
+ // Agent grants on the owner path: a thread message is an issue-thread
9345
+ // write (and a GitHub comment). The in-process operations layer below does
9346
+ // not carry the caller's grant, so the check runs here, before anything is
9347
+ // written. The guest path stays scoped by its guest access token.
9348
+ if (principal.kind !== "guest") {
9349
+ assertCurrentAgentMay("store", ISSUE_THREAD_ENTITY_TYPES, { guestCapable: true });
9350
+ // Edges from the issue to entities the caller names.
9351
+ await assertCurrentAgentMayLink(userId, "issue", "REFERS_TO", parsed.data.entity_ids_to_link ?? [], { guestCapable: true });
9352
+ }
9242
9353
  const { createOperations } = await import("./core/operations.js");
9243
9354
  const { NeotomaServer } = await import("./server.js");
9244
9355
  const { addIssueMessage, appendGuestIssueMessage } = await import("./services/issues/issue_operations.js");
@@ -9311,6 +9422,16 @@ const handleIssuesSubmitHttp = async (req, res) => {
9311
9422
  ? ((await resolveGuestUserId(req, principal)) ??
9312
9423
  (await getAuthenticatedUserId(req, parsed.data.user_id)))
9313
9424
  : await getAuthenticatedUserId(req, parsed.data.user_id);
9425
+ // Agent grants on the owner path: it writes an issue thread under the
9426
+ // owner and may open a GitHub issue. The in-process operations layer below
9427
+ // does not carry the caller's grant, so the check runs here, before
9428
+ // anything is written. The guest path stays under access policy, as for
9429
+ // any guest.
9430
+ if (!(principal.kind === "guest" || guestSubmitPayload)) {
9431
+ assertCurrentAgentMay("store", ISSUE_THREAD_ENTITY_TYPES, { guestCapable: true });
9432
+ // Edges from the new issue to entities the caller names.
9433
+ await assertCurrentAgentMayLink(userId, "issue", "REFERS_TO", [...(parsed.data.entity_ids_to_link ?? []), parsed.data.conversation_turn_id ?? ""], { guestCapable: true });
9434
+ }
9314
9435
  const { createOperations } = await import("./core/operations.js");
9315
9436
  const { NeotomaServer } = await import("./server.js");
9316
9437
  const { submitIssue, submitGuestIssue } = await import("./services/issues/issue_operations.js");
@@ -9434,6 +9555,10 @@ const handleIssuesSyncHttp = async (req, res) => {
9434
9555
  }
9435
9556
  try {
9436
9557
  const userId = await getAuthenticatedUserId(req, parsed.data.user_id);
9558
+ // Agent grants: a sync stores new issue threads, corrects existing ones
9559
+ // and can push local issues to GitHub.
9560
+ assertCurrentAgentMay("store", ISSUE_THREAD_ENTITY_TYPES);
9561
+ assertCurrentAgentMay("correct", ISSUE_THREAD_ENTITY_TYPES);
9437
9562
  const { createOperations } = await import("./core/operations.js");
9438
9563
  const { NeotomaServer } = await import("./server.js");
9439
9564
  const { syncIssuesFromGitHub } = await import("./services/issues/sync_issues_from_github.js");
@@ -9480,6 +9605,9 @@ app.post("/restore_entity", async (req, res) => {
9480
9605
  try {
9481
9606
  const userId = await getAuthenticatedUserId(req, parsed.data.user_id);
9482
9607
  const { entity_id, entity_type, reason } = parsed.data;
9608
+ // Agent grants: `restore` on the stored type (and the type the request
9609
+ // names), before the restoration observation is written.
9610
+ await assertCurrentAgentMayOnEntities("restore", userId, [entity_id], [entity_type]);
9483
9611
  const { restoreEntity } = await import("./services/deletion.js");
9484
9612
  const result = await restoreEntity(entity_id, entity_type, userId, reason);
9485
9613
  if (!result.success) {
@@ -9750,6 +9878,8 @@ app.post("/update_schema_incremental", async (req, res) => {
9750
9878
  // can defer to whichever scope its own read resolved instead of being
9751
9879
  // told "global" by a default this route manufactured.
9752
9880
  user_specific, activate = true, migrate_existing = false, force = false, } = parsed.data;
9881
+ // Agent grants: `register_schema` on the entity type, before any write.
9882
+ assertCurrentAgentMay("register_schema", [entity_type]);
9753
9883
  const { schemaRegistry, loadCodeDefinedSchemaEntry } = await import("./services/schema_registry.js");
9754
9884
  // #2454 / #2374 REST parity with the MCP handler: the existence guard
9755
9885
  // resolves the SAME row `updateSchemaIncremental` will read —
@@ -10032,6 +10162,8 @@ app.post("/register_schema", async (req, res) => {
10032
10162
  try {
10033
10163
  const userId = await getAuthenticatedUserId(req, parsed.data.user_id);
10034
10164
  const { entity_type, schema_definition, reducer_config, schema_version = "1.0", user_specific = false, activate = false, force = false, } = parsed.data;
10165
+ // Agent grants: `register_schema` on the entity type, before any write.
10166
+ assertCurrentAgentMay("register_schema", [entity_type]);
10035
10167
  const { schemaRegistry } = await import("./services/schema_registry.js");
10036
10168
  // R2 back-compat: existing HTTP/CLI callers may register schemas
10037
10169
  // without declaring canonical_name_fields or identity_opt_out (e.g. the
@@ -10582,6 +10714,8 @@ app.post("/unsubscribe", guestWriteRateLimit, async (req, res) => {
10582
10714
  return sendError(res, 403, "FORBIDDEN", "Guest access token does not grant access to this subscription");
10583
10715
  }
10584
10716
  }
10717
+ // Agent grants: unsubscribing corrects the subscription (active=false).
10718
+ assertCurrentAgentMay("correct", ["subscription"], { guestCapable: true });
10585
10719
  await unsubscribeUser({ userId, subscription_id: parsed.data.subscription_id });
10586
10720
  return res.json({ success: true });
10587
10721
  }
@@ -11279,6 +11413,10 @@ export async function startHTTPServer() {
11279
11413
  }
11280
11414
  throw err;
11281
11415
  }
11416
+ // Report the bearer handover slot (NEOTOMA_BEARER_TOKEN_PREVIOUS) at boot,
11417
+ // so a misconfigured slot is loud at startup rather than at the first
11418
+ // consumer's 401. Fail-closed parsing lives in services/bearer_slots.ts.
11419
+ announceBearerHandoverStatus();
11282
11420
  // Initialize encryption service
11283
11421
  await initServerKeys();
11284
11422
  // Seed the built-in schema registry from ENTITY_SCHEMAS (issue #1968).