neotoma 0.10.0 → 0.11.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 (257) hide show
  1. package/README.md +2 -1
  2. package/dist/actions.d.ts +9 -4
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +209 -56
  5. package/dist/actions.js.map +1 -1
  6. package/dist/cli/aauth_signer.d.ts +9 -2
  7. package/dist/cli/aauth_signer.d.ts.map +1 -1
  8. package/dist/cli/aauth_signer.js +40 -8
  9. package/dist/cli/aauth_signer.js.map +1 -1
  10. package/dist/cli/agent_instructions_scan.d.ts +12 -3
  11. package/dist/cli/agent_instructions_scan.d.ts.map +1 -1
  12. package/dist/cli/agent_instructions_scan.js +55 -64
  13. package/dist/cli/agent_instructions_scan.js.map +1 -1
  14. package/dist/cli/auth_keygen.d.ts +11 -0
  15. package/dist/cli/auth_keygen.d.ts.map +1 -0
  16. package/dist/cli/auth_keygen.js +110 -0
  17. package/dist/cli/auth_keygen.js.map +1 -0
  18. package/dist/cli/commands/processes.d.ts +33 -0
  19. package/dist/cli/commands/processes.d.ts.map +1 -0
  20. package/dist/cli/commands/processes.js +385 -0
  21. package/dist/cli/commands/processes.js.map +1 -0
  22. package/dist/cli/config.d.ts +10 -0
  23. package/dist/cli/config.d.ts.map +1 -1
  24. package/dist/cli/config.js +70 -7
  25. package/dist/cli/config.js.map +1 -1
  26. package/dist/cli/doctor.d.ts +2 -0
  27. package/dist/cli/doctor.d.ts.map +1 -1
  28. package/dist/cli/doctor.js +14 -7
  29. package/dist/cli/doctor.js.map +1 -1
  30. package/dist/cli/harness_configure.d.ts +36 -0
  31. package/dist/cli/harness_configure.d.ts.map +1 -0
  32. package/dist/cli/harness_configure.js +42 -0
  33. package/dist/cli/harness_configure.js.map +1 -0
  34. package/dist/cli/hooks.d.ts.map +1 -1
  35. package/dist/cli/hooks.js +85 -7
  36. package/dist/cli/hooks.js.map +1 -1
  37. package/dist/cli/hooks_detect.d.ts.map +1 -1
  38. package/dist/cli/hooks_detect.js +6 -2
  39. package/dist/cli/hooks_detect.js.map +1 -1
  40. package/dist/cli/index.d.ts.map +1 -1
  41. package/dist/cli/index.js +523 -247
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/cli/inspector_admin_unlock_url.d.ts +13 -0
  44. package/dist/cli/inspector_admin_unlock_url.d.ts.map +1 -0
  45. package/dist/cli/inspector_admin_unlock_url.js +36 -0
  46. package/dist/cli/inspector_admin_unlock_url.js.map +1 -0
  47. package/dist/cli/mcp_config_scan.d.ts +31 -0
  48. package/dist/cli/mcp_config_scan.d.ts.map +1 -1
  49. package/dist/cli/mcp_config_scan.js +276 -31
  50. package/dist/cli/mcp_config_scan.js.map +1 -1
  51. package/dist/cli/mcp_proxy.d.ts +9 -0
  52. package/dist/cli/mcp_proxy.d.ts.map +1 -0
  53. package/dist/cli/mcp_proxy.js +114 -0
  54. package/dist/cli/mcp_proxy.js.map +1 -0
  55. package/dist/cli/setup.d.ts +6 -2
  56. package/dist/cli/setup.d.ts.map +1 -1
  57. package/dist/cli/setup.js +32 -9
  58. package/dist/cli/setup.js.map +1 -1
  59. package/dist/cli/setup_runners.d.ts +16 -0
  60. package/dist/cli/setup_runners.d.ts.map +1 -0
  61. package/dist/cli/setup_runners.js +141 -0
  62. package/dist/cli/setup_runners.js.map +1 -0
  63. package/dist/config.d.ts +2 -0
  64. package/dist/config.d.ts.map +1 -1
  65. package/dist/config.js +3 -0
  66. package/dist/config.js.map +1 -1
  67. package/dist/core/operations.d.ts +2 -2
  68. package/dist/core/operations.d.ts.map +1 -1
  69. package/dist/core/operations.js +2 -2
  70. package/dist/core/operations.js.map +1 -1
  71. package/dist/inspector/assets/{Combination-BP0-kPZX.js → Combination-C22tNG3c.js} +1 -1
  72. package/dist/inspector/assets/{agent_badge-BZT-JO2h.js → agent_badge-ihPeARQV.js} +1 -1
  73. package/dist/inspector/assets/{agent_detail-BGMLF8-n.js → agent_detail-BtdIGuk2.js} +1 -1
  74. package/dist/inspector/assets/{agent_filter-DMC4CzhM.js → agent_filter-L0NhixFq.js} +1 -1
  75. package/dist/inspector/assets/{agent_grant_detail-Brqy5K7M.js → agent_grant_detail-DOfwRmj4.js} +1 -1
  76. package/dist/inspector/assets/{agent_grant_form-BLDkUh1Y.js → agent_grant_form-D-_IJrLI.js} +1 -1
  77. package/dist/inspector/assets/{agent_grants-B2StunRb.js → agent_grants-BkUTzkwq.js} +1 -1
  78. package/dist/inspector/assets/{agents-lYmKs-fG.js → agents-C8qGnNCU.js} +1 -1
  79. package/dist/inspector/assets/{arrow-left-D1s7DOns.js → arrow-left-C5PI116n.js} +1 -1
  80. package/dist/inspector/assets/{attribution_card-D-bp008l.js → attribution_card-BKw4xb01.js} +1 -1
  81. package/dist/inspector/assets/{attribution_summary-Cs9Ccvt3.js → attribution_summary-S6yX8918.js} +1 -1
  82. package/dist/inspector/assets/{card-Btqgzh6p.js → card-BKx8ifPf.js} +1 -1
  83. package/dist/inspector/assets/{check-DAyRtq63.js → check-D7bS4rbb.js} +1 -1
  84. package/dist/inspector/assets/{checkbox-BrpwHaRo.js → checkbox-BE774kci.js} +1 -1
  85. package/dist/inspector/assets/{chevron-down-CCk_jMPN.js → chevron-down-DWeHLqJP.js} +1 -1
  86. package/dist/inspector/assets/{chevron-right-C9NbdZtC.js → chevron-right-D-MVwNt0.js} +1 -1
  87. package/dist/inspector/assets/{compliance-BHiHtgfg.js → compliance-DIVlTxir.js} +1 -1
  88. package/dist/inspector/assets/{confirm-dialog-BcxtVONz.js → confirm-dialog-DZ91UiLx.js} +1 -1
  89. package/dist/inspector/assets/{conversation_common-Dw5j3QuN.js → conversation_common-B9QrB_mG.js} +1 -1
  90. package/dist/inspector/assets/{conversation_detail-BR_rBMFV.js → conversation_detail-BX-DgWqj.js} +1 -1
  91. package/dist/inspector/assets/{copy_id_button-CyjfY7dx.js → copy_id_button-DbNXOvuH.js} +2 -2
  92. package/dist/inspector/assets/{corrections-DFExbcsm.js → corrections-UTXmEFqm.js} +1 -1
  93. package/dist/inspector/assets/{dashboard-CxnNRphy.js → dashboard-D7o1n0lS.js} +1 -1
  94. package/dist/inspector/assets/{data-table-CazqdSem.js → data-table-DFBYvAjA.js} +1 -1
  95. package/dist/inspector/assets/{dialog-X5X7rLah.js → dialog-DE3AWlG_.js} +1 -1
  96. package/dist/inspector/assets/{dropdown-menu-CmZjxUWM.js → dropdown-menu-BVwBx2B7.js} +1 -1
  97. package/dist/inspector/assets/{entities-l6icu6fc.js → entities-i3yWeDP0.js} +1 -1
  98. package/dist/inspector/assets/{entity_detail-daoxB-h1.js → entity_detail-BJNaEXGZ.js} +1 -1
  99. package/dist/inspector/assets/{entity_link-DtMv__WC.js → entity_link-JLwqX81Y.js} +1 -1
  100. package/dist/inspector/assets/{external-link-BBoTnT-P.js → external-link-BK31dJyN.js} +1 -1
  101. package/dist/inspector/assets/feedback-COEQSnd9.js +45 -0
  102. package/dist/inspector/assets/feedback_admin-CJnr7E0r.js +6 -0
  103. package/dist/inspector/assets/feedback_admin_unlock-BxcDo5G7.js +6 -0
  104. package/dist/inspector/assets/{graph_explorer-BvicLJEW.js → graph_explorer-O8YY1xwo.js} +1 -1
  105. package/dist/inspector/assets/{index-D5i6AEXI.js → index-BKbdoU0r.js} +1 -1
  106. package/dist/inspector/assets/{index-Czej0Y93.js → index-Bb004UmS.js} +1 -1
  107. package/dist/inspector/assets/index-BgQagyt9.css +1 -0
  108. package/dist/inspector/assets/{index-DJuPlRtP.js → index-CisbTUN-.js} +1 -1
  109. package/dist/inspector/assets/index-DZyW9wwm.js +224 -0
  110. package/dist/inspector/assets/{interpretations-E0sIBf-l.js → interpretations-Bz1Jx0gm.js} +1 -1
  111. package/dist/inspector/assets/interpretations-D0k7qwZ6.js +1 -0
  112. package/dist/inspector/assets/{json_viewer-ojLDPDtf.js → json_viewer-1-geEBU4.js} +1 -1
  113. package/dist/inspector/assets/{label-DWyQNl4E.js → label-DK8No7os.js} +1 -1
  114. package/dist/inspector/assets/{live_relative_time-DzLnsA9y.js → live_relative_time-Ca29xr4q.js} +1 -1
  115. package/dist/inspector/assets/{observations-Ds0kFmaM.js → observations-BEYPLgsw.js} +1 -1
  116. package/dist/inspector/assets/{page_shell-C-4AKr0Y.js → page_shell-Z_K8-xVN.js} +1 -1
  117. package/dist/inspector/assets/{pagination-lSg-a95h.js → pagination-55slcMsJ.js} +1 -1
  118. package/dist/inspector/assets/{plus-CQMoR71F.js → plus-Df5osCTJ.js} +1 -1
  119. package/dist/inspector/assets/{query_refresh_indicator-Bewf0Dj1.js → query_refresh_indicator-B2ayQ-9R.js} +1 -1
  120. package/dist/inspector/assets/{recent_activity-Csh_YraY.js → recent_activity-D4P724bj.js} +1 -1
  121. package/dist/inspector/assets/{recent_conversations-CBengQjb.js → recent_conversations-B-iJ9x-v.js} +1 -1
  122. package/dist/inspector/assets/{recent_conversations-MKmxYevd.js → recent_conversations-BXAUdAC5.js} +1 -1
  123. package/dist/inspector/assets/{recent_records_feed-CCrBRfkG.js → recent_records_feed-Bm8kGd63.js} +1 -1
  124. package/dist/inspector/assets/{relationship_detail-CUz_GhPI.js → relationship_detail-BMhsfgCR.js} +1 -1
  125. package/dist/inspector/assets/{relationships-Z9ALu9Oa.js → relationships-BphnuyTR.js} +1 -1
  126. package/dist/inspector/assets/{relationships-Ulajo16_.js → relationships-DBLA0hRd.js} +1 -1
  127. package/dist/inspector/assets/{sandbox-CfD5QvC5.js → sandbox-BWLbx8xY.js} +1 -1
  128. package/dist/inspector/assets/{schema_detail-B1W8rbzV.js → schema_detail-Den0dtKn.js} +1 -1
  129. package/dist/inspector/assets/{schemas-DVlEFPuf.js → schemas-CZNE7ILQ.js} +1 -1
  130. package/dist/inspector/assets/{search-BccQXyTN.js → search-BpeIvjlx.js} +1 -1
  131. package/dist/inspector/assets/{select-Dv1QM6oO.js → select-vjNrYLub.js} +2 -2
  132. package/dist/inspector/assets/{settings-B4U8tFYI.js → settings-Db5j2L-M.js} +1 -1
  133. package/dist/inspector/assets/{source_detail-B1JlZBBx.js → source_detail-DAAnuO9d.js} +1 -1
  134. package/dist/inspector/assets/{source_link-p8KzI1os.js → source_link-B3bG6OoM.js} +1 -1
  135. package/dist/inspector/assets/{sources-B5ssCN-s.js → sources-CqJaDvnU.js} +1 -1
  136. package/dist/inspector/assets/{switch-BPI_y_Z3.js → switch-N1yvDIln.js} +1 -1
  137. package/dist/inspector/assets/{tabs-HUG-sxc2.js → tabs-DDLnWpd7.js} +1 -1
  138. package/dist/inspector/assets/{textarea-DNz92WE1.js → textarea-DwpRHIdg.js} +1 -1
  139. package/dist/inspector/assets/{timeline-HN2EoMGt.js → timeline-DGZTAraG.js} +1 -1
  140. package/dist/inspector/assets/{timeline-DRqxyQUF.js → timeline-DgfkLScO.js} +1 -1
  141. package/dist/inspector/assets/{timeline_event_detail-DbA5EpiN.js → timeline_event_detail-GKr9VYPf.js} +1 -1
  142. package/dist/inspector/assets/{trash-2-BAfHKatZ.js → trash-2-aTmwwD61.js} +1 -1
  143. package/dist/inspector/assets/{turn_detail-BUHzIhWX.js → turn_detail-DJi1gGc5.js} +1 -1
  144. package/dist/inspector/assets/{turns-ADRkuqKL.js → turns-oYp0HVIa.js} +1 -1
  145. package/dist/inspector/assets/{use_agents-CTZrpsvS.js → use_agents-GiTdp_mh.js} +1 -1
  146. package/dist/inspector/assets/{use_entities-BEhy6HWn.js → use_entities-CTSlt7S0.js} +1 -1
  147. package/dist/inspector/assets/use_interpretations-DUaKZMXF.js +1 -0
  148. package/dist/inspector/assets/{use_mutations-B4y1qmV5.js → use_mutations-XlZmJD0t.js} +1 -1
  149. package/dist/inspector/assets/use_recent_conversations-vxIe2glX.js +1 -0
  150. package/dist/inspector/assets/{use_relationships-Cl-o_7u6.js → use_relationships-Ct8x9Wl7.js} +1 -1
  151. package/dist/inspector/assets/{use_schemas-Bl11WNgP.js → use_schemas-DI772015.js} +1 -1
  152. package/dist/inspector/assets/{use_sources-DkJZZBDp.js → use_sources-BSwgjmqJ.js} +1 -1
  153. package/dist/inspector/assets/{use_stats-Cn1a3yt-.js → use_stats--S9rYQbr.js} +1 -1
  154. package/dist/inspector/assets/{use_timeline-DZkbwA-7.js → use_timeline-XjpDP_2Y.js} +1 -1
  155. package/dist/inspector/assets/{use_turns-BHfaal9v.js → use_turns-DnqJYe1l.js} +1 -1
  156. package/dist/inspector/index.html +2 -2
  157. package/dist/mcp_instruction_doc.d.ts +11 -0
  158. package/dist/mcp_instruction_doc.d.ts.map +1 -0
  159. package/dist/mcp_instruction_doc.js +39 -0
  160. package/dist/mcp_instruction_doc.js.map +1 -0
  161. package/dist/proxy/aauth_client_signer.d.ts +37 -0
  162. package/dist/proxy/aauth_client_signer.d.ts.map +1 -0
  163. package/dist/proxy/aauth_client_signer.js +172 -0
  164. package/dist/proxy/aauth_client_signer.js.map +1 -0
  165. package/dist/proxy/index.d.ts +7 -0
  166. package/dist/proxy/index.d.ts.map +1 -0
  167. package/dist/proxy/index.js +4 -0
  168. package/dist/proxy/index.js.map +1 -0
  169. package/dist/proxy/mcp_stdio_proxy.d.ts +32 -0
  170. package/dist/proxy/mcp_stdio_proxy.d.ts.map +1 -0
  171. package/dist/proxy/mcp_stdio_proxy.js +250 -0
  172. package/dist/proxy/mcp_stdio_proxy.js.map +1 -0
  173. package/dist/proxy/preflight.d.ts +15 -0
  174. package/dist/proxy/preflight.d.ts.map +1 -0
  175. package/dist/proxy/preflight.js +71 -0
  176. package/dist/proxy/preflight.js.map +1 -0
  177. package/dist/repositories/sqlite/sqlite_client.d.ts.map +1 -1
  178. package/dist/repositories/sqlite/sqlite_client.js +2 -0
  179. package/dist/repositories/sqlite/sqlite_client.js.map +1 -1
  180. package/dist/server.d.ts +7 -8
  181. package/dist/server.d.ts.map +1 -1
  182. package/dist/server.js +306 -137
  183. package/dist/server.js.map +1 -1
  184. package/dist/services/agent_capabilities.d.ts +1 -1
  185. package/dist/services/agent_capabilities.d.ts.map +1 -1
  186. package/dist/services/agent_capabilities.js +7 -1
  187. package/dist/services/agent_capabilities.js.map +1 -1
  188. package/dist/services/agent_grants.d.ts.map +1 -1
  189. package/dist/services/agent_grants.js +1 -0
  190. package/dist/services/agent_grants.js.map +1 -1
  191. package/dist/services/dashboard_stats.d.ts.map +1 -1
  192. package/dist/services/dashboard_stats.js +3 -0
  193. package/dist/services/dashboard_stats.js.map +1 -1
  194. package/dist/services/entity_queries.d.ts.map +1 -1
  195. package/dist/services/entity_queries.js +68 -20
  196. package/dist/services/entity_queries.js.map +1 -1
  197. package/dist/services/feedback/admin_proxy.d.ts +28 -9
  198. package/dist/services/feedback/admin_proxy.d.ts.map +1 -1
  199. package/dist/services/feedback/admin_proxy.js +145 -24
  200. package/dist/services/feedback/admin_proxy.js.map +1 -1
  201. package/dist/services/feedback/admin_session.d.ts +36 -0
  202. package/dist/services/feedback/admin_session.d.ts.map +1 -0
  203. package/dist/services/feedback/admin_session.js +147 -0
  204. package/dist/services/feedback/admin_session.js.map +1 -0
  205. package/dist/services/inspector_mount.d.ts.map +1 -1
  206. package/dist/services/inspector_mount.js +9 -0
  207. package/dist/services/inspector_mount.js.map +1 -1
  208. package/dist/services/interpretation.d.ts.map +1 -1
  209. package/dist/services/interpretation.js +8 -4
  210. package/dist/services/interpretation.js.map +1 -1
  211. package/dist/services/observation_storage.js +1 -1
  212. package/dist/services/observation_storage.js.map +1 -1
  213. package/dist/services/raw_fragments.d.ts +3 -0
  214. package/dist/services/raw_fragments.d.ts.map +1 -1
  215. package/dist/services/raw_fragments.js +18 -8
  216. package/dist/services/raw_fragments.js.map +1 -1
  217. package/dist/services/root_landing/harness_snippets.d.ts +12 -0
  218. package/dist/services/root_landing/harness_snippets.d.ts.map +1 -1
  219. package/dist/services/root_landing/harness_snippets.js +50 -1
  220. package/dist/services/root_landing/harness_snippets.js.map +1 -1
  221. package/dist/services/root_landing/html_template.d.ts.map +1 -1
  222. package/dist/services/root_landing/html_template.js +12 -4
  223. package/dist/services/root_landing/html_template.js.map +1 -1
  224. package/dist/services/root_landing/md_template.d.ts.map +1 -1
  225. package/dist/services/root_landing/md_template.js +3 -0
  226. package/dist/services/root_landing/md_template.js.map +1 -1
  227. package/dist/services/schema_registry.d.ts +2 -1
  228. package/dist/services/schema_registry.d.ts.map +1 -1
  229. package/dist/services/schema_registry.js +31 -9
  230. package/dist/services/schema_registry.js.map +1 -1
  231. package/dist/shared/action_schemas.d.ts +166 -0
  232. package/dist/shared/action_schemas.d.ts.map +1 -1
  233. package/dist/shared/action_schemas.js +17 -0
  234. package/dist/shared/action_schemas.js.map +1 -1
  235. package/dist/shared/contract_mappings.d.ts.map +1 -1
  236. package/dist/shared/contract_mappings.js +19 -15
  237. package/dist/shared/contract_mappings.js.map +1 -1
  238. package/dist/shared/openapi_types.d.ts +98 -37
  239. package/dist/shared/openapi_types.d.ts.map +1 -1
  240. package/dist/tool_definitions.d.ts +1 -1
  241. package/dist/tool_definitions.d.ts.map +1 -1
  242. package/dist/tool_definitions.js +13 -38
  243. package/dist/tool_definitions.js.map +1 -1
  244. package/dist/utils/local_http_port_file.d.ts +16 -0
  245. package/dist/utils/local_http_port_file.d.ts.map +1 -0
  246. package/dist/utils/local_http_port_file.js +46 -0
  247. package/dist/utils/local_http_port_file.js.map +1 -0
  248. package/docs/developer/mcp/instructions.md +211 -0
  249. package/openapi.yaml +113 -17
  250. package/package.json +4 -3
  251. package/skills/store-data/SKILL.md +1 -3
  252. package/dist/inspector/assets/feedback-DeFhdWId.js +0 -35
  253. package/dist/inspector/assets/index-B2zHigxN.js +0 -199
  254. package/dist/inspector/assets/index-Df569_c9.css +0 -1
  255. package/dist/inspector/assets/interpretations-D9gWqVhy.js +0 -1
  256. package/dist/inspector/assets/use_interpretations-CKN63UxX.js +0 -1
  257. package/dist/inspector/assets/use_recent_conversations-CIBgmz9B.js +0 -1
package/README.md CHANGED
@@ -100,6 +100,7 @@ The agent handles npm install, initialization, and MCP configuration. **Manual i
100
100
  ```bash
101
101
  npm install -g neotoma
102
102
  neotoma init
103
+ neotoma setup --tool <cursor|claude-code|codex> --yes
103
104
  neotoma mcp config
104
105
  ```
105
106
 
@@ -220,7 +221,7 @@ Neotoma exposes state via MCP. Local storage only in preview. Local built-in aut
220
221
 
221
222
  **Setup guides:** [Cursor](https://neotoma.io/neotoma-with-cursor) · [Claude Code](https://neotoma.io/neotoma-with-claude-code) · [Claude](https://neotoma.io/neotoma-with-claude) · [ChatGPT](https://neotoma.io/neotoma-with-chatgpt) · [Codex](https://neotoma.io/neotoma-with-codex) · [OpenCode](docs/integrations/hooks/opencode.md) · [OpenClaw](https://neotoma.io/neotoma-with-openclaw) · [IronClaw](https://neotoma.io/neotoma-with-ironclaw)
222
223
 
223
- For local source iteration, use the stable dev shim (`scripts/run_neotoma_mcp_stdio_dev_shim.sh` or `npm run dev:mcp:dev-shim`) instead of pointing installed MCP clients at a `tsx watch` stdio process. The shim keeps the client-facing JSON-RPC stream stable and asks clients to refresh or reconnect when the tool interface changes.
224
+ For local source iteration, use the stable dev shim (`scripts/run_neotoma_mcp_stdio_dev_shim.sh`) or signed shim (`scripts/run_neotoma_mcp_signed_stdio_dev_shim.sh`) instead of pointing installed MCP clients at a `tsx watch` stdio process. `neotoma mcp config` defaults to **`b`** for low-friction local stdio setup; use **`a`** for signed + AAuth HTTP `/mcp` proxy entries when the Neotoma API is running, **`c`** for direct stdio, or **`d`** when both MCP entries should target prod.
224
225
 
225
226
  **Agent behavior contract:** Store first, retrieve before storing, extract entities from user input, create tasks for commitments, and attach bounded host context such as repository name/root scope when available. Full instructions: [MCP instructions](docs/developer/mcp/instructions.md) and [CLI agent instructions](docs/developer/cli_agent_instructions.md).
226
227
 
package/dist/actions.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import express from "express";
2
+ import { type StoreInterpretationInput } from "./shared/action_schemas.js";
2
3
  export declare const app: import("express-serve-static-core").Express;
3
4
  /**
4
5
  * True when the request arrived over a loopback socket.
@@ -38,6 +39,8 @@ export declare function storeStructuredForApi(params: {
38
39
  idempotencyKey: string;
39
40
  originalFilename?: string;
40
41
  relationships?: StoreRelationshipRef[];
42
+ interpretation?: StoreInterpretationInput;
43
+ interpretationSourceId?: string;
41
44
  commit?: boolean;
42
45
  strict?: boolean;
43
46
  }): Promise<{
@@ -61,10 +64,6 @@ export declare function storeStructuredForApi(params: {
61
64
  identity_basis: string;
62
65
  identity_rule: string;
63
66
  }[] | undefined;
64
- success: boolean;
65
- replayed: boolean;
66
- commit: boolean;
67
- source_id: string | null;
68
67
  entities_created: number;
69
68
  observations_created: number;
70
69
  entities: {
@@ -91,6 +90,12 @@ export declare function storeStructuredForApi(params: {
91
90
  source_entity_id: string;
92
91
  target_entity_id: string;
93
92
  }[];
93
+ interpretation_id?: string | undefined;
94
+ interpretation_source_id?: string | undefined;
95
+ success: boolean;
96
+ replayed: boolean;
97
+ commit: boolean;
98
+ source_id: string | null;
94
99
  }>;
95
100
  export declare function startHTTPServer(): Promise<{
96
101
  server: import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>;
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAmK9B,eAAO,MAAM,GAAG,6CAAY,CAAC;AAif7B;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAU5D;AA4PD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAmBhD;AA4sHD,KAAK,oBAAoB,GAAG;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,4BAA4B,EAAE,iBAAiB,CAAC;IAC3E,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;;;;;;;;;;;;;cA+fS,MAAM;gBACJ,MAAM;2BACK,MAAM;qBACZ,MAAM;mBACR,MAAM;wBACD,MAAM;uBACP,MAAM;;;;;;;;;mBA3JV,MAAM;qBACJ,MAAM;wBACH,MAAM,GAAG,IAAI;2BACV,MAAM;;wBAET,MAAM;uBACP,MAAM,EAAE;wBACP,MAAM;uBACP,MAAM;;kBA9NX,MAAM;oBACJ,MAAM;yBACD,MAAM;4BACH,MAAM;2BACP,MAAM;;+BA4NF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;;;2BAkFlC,MAAM;0BACP,MAAM;0BACN,MAAM;;GA2F3B;AAuhED,wBAAsB,eAAe;;;eA2FpC"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AA4G9B,OAAO,EAyBL,KAAK,wBAAwB,EAE9B,MAAM,4BAA4B,CAAC;AA+BpC,eAAO,MAAM,GAAG,6CAAY,CAAC;AAygB7B;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAU5D;AA4PD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAmBhD;AAiyHD,KAAK,oBAAoB,GAAG;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAuDF,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,4BAA4B,EAAE,iBAAiB,CAAC;IAC3E,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACvC,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAC1C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;;;;;;;;;;;;;cA+gBS,MAAM;gBACJ,MAAM;2BACK,MAAM;qBACZ,MAAM;mBACR,MAAM;wBACD,MAAM;uBACP,MAAM;;;;;mBA3JV,MAAM;qBACJ,MAAM;wBACH,MAAM,GAAG,IAAI;2BACV,MAAM;;wBAET,MAAM;uBACP,MAAM,EAAE;wBACP,MAAM;uBACP,MAAM;;kBA9NX,MAAM;oBACJ,MAAM;yBACD,MAAM;4BACH,MAAM;2BACP,MAAM;;+BA4NF,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;;;2BAkFlC,MAAM;0BACP,MAAM;0BACN,MAAM;;;;;;;;GAsG3B;AAmhED,wBAAsB,eAAe;;;eA8FpC"}
package/dist/actions.js CHANGED
@@ -10,6 +10,7 @@ import { db } from "./db.js";
10
10
  import { config } from "./config.js";
11
11
  import fs from "fs";
12
12
  import path from "path";
13
+ import { writeLocalHttpPortFile } from "./utils/local_http_port_file.js";
13
14
  import yaml from "js-yaml";
14
15
  import { ensurePublicKeyRegistered, getPublicKey, getUserIdFromBearerToken, isBearerTokenValid, } from "./services/public_key_registry.js";
15
16
  import { verifyRequest, parseAuthHeader } from "./crypto/auth.js";
@@ -19,10 +20,10 @@ import { aauthVerify, getAAuthContextFromRequest, getAttributionDecisionFromRequ
19
20
  import { attributionContext } from "./middleware/attribution_context.js";
20
21
  import { aauthAdmission, getAAuthAdmissionFromRequest, } from "./middleware/aauth_admission.js";
21
22
  import { buildSessionInfo } from "./services/session_info.js";
22
- import { AttributionPolicyError } from "./services/attribution_policy.js";
23
+ import { AttributionPolicyError, enforceAttributionPolicy } from "./services/attribution_policy.js";
23
24
  import { registerFeedbackAdminProxyRoutes } from "./services/feedback/admin_proxy.js";
24
25
  import { AgentCapabilityError, contextFromAgentIdentity, enforceAgentCapability, } from "./services/agent_capabilities.js";
25
- import { getCurrentAAuthAdmission, getCurrentAgentIdentity, runWithRequestContext, } from "./services/request_context.js";
26
+ import { getCurrentAAuthAdmission, getCurrentAgentIdentity, getCurrentAttribution, runWithRequestContext, } from "./services/request_context.js";
26
27
  import { assertCanWriteProtectedBatch } from "./services/protected_entity_types.js";
27
28
  import { createAgentIdentity as buildAgentIdentity, getAgentIdentityFromRequest, normaliseClientName, } from "./crypto/agent_identity.js";
28
29
  import { initServerKeys } from "./services/encryption_service.js";
@@ -43,7 +44,7 @@ import { resolveSandboxReportTransport } from "./services/sandbox/transport.js";
43
44
  import { getSqliteDb } from "./repositories/sqlite/sqlite_client.js";
44
45
  import { getMcpAuthToken } from "./crypto/mcp_auth_token.js";
45
46
  import { isOauthKeyCredentialValid, normalizeOauthNextPath, OAuthKeySessionStore, } from "./services/oauth_key_gate.js";
46
- import { AnalyzeSchemaCandidatesRequestSchema, CorrectEntityRequestSchema, CreateRelationshipsRequestSchema, CreateRelationshipRequestSchema, DeleteEntityRequestSchema, DeleteRelationshipRequestSchema, EntitiesQueryRequestSchema, EntitySnapshotRequestSchema, FieldProvenanceRequestSchema, GetSchemaRecommendationsRequestSchema, ListObservationsRequestSchema, ListRelationshipsRequestSchema, MergeEntitiesRequestSchema, SplitEntityRequestSchema, ObservationsQueryRequestSchema, RegisterSchemaRequestSchema, RelationshipSnapshotRequestSchema, RestoreEntityRequestSchema, RestoreRelationshipRequestSchema, RetrieveEntityByIdentifierSchema, RetrieveGraphNeighborhoodSchema, RetrieveRelatedEntitiesSchema, StoreRequestSchema, StoreUnstructuredRequestSchema, UpdateSchemaIncrementalRequestSchema, } from "./shared/action_schemas.js";
47
+ import { AnalyzeSchemaCandidatesRequestSchema, CorrectEntityRequestSchema, CreateInterpretationRequestSchema, CreateRelationshipsRequestSchema, CreateRelationshipRequestSchema, DeleteEntityRequestSchema, DeleteRelationshipRequestSchema, EntitiesQueryRequestSchema, EntitySnapshotRequestSchema, FieldProvenanceRequestSchema, GetSchemaRecommendationsRequestSchema, ListObservationsRequestSchema, ListRelationshipsRequestSchema, MergeEntitiesRequestSchema, SplitEntityRequestSchema, ObservationsQueryRequestSchema, RegisterSchemaRequestSchema, RelationshipSnapshotRequestSchema, RestoreEntityRequestSchema, RestoreRelationshipRequestSchema, RetrieveEntityByIdentifierSchema, RetrieveGraphNeighborhoodSchema, RetrieveRelatedEntitiesSchema, StoreRequestSchema, UpdateSchemaIncrementalRequestSchema, } from "./shared/action_schemas.js";
47
48
  import { getMimeTypeFromExtension } from "./services/file_text_extraction.js";
48
49
  import { queryEntitiesWithCount } from "./shared/action_handlers/entity_handlers.js";
49
50
  import { retrieveEntityByIdentifierWithFallback } from "./shared/action_handlers/entity_identifier_handler.js";
@@ -496,6 +497,24 @@ app.get("/server-info", (_req, res) => {
496
497
  neotoma_env: readNeotomaConfigEnvironment(),
497
498
  });
498
499
  });
500
+ app.get("/mcp-interaction-instructions", (_req, res) => {
501
+ const instructionsPath = path.join(config.projectRoot, "docs", "developer", "mcp", "instructions.md");
502
+ try {
503
+ const raw = fs.readFileSync(instructionsPath, "utf-8");
504
+ const match = raw.match(/```\s*\n?([\s\S]*?)```/);
505
+ if (match && match[1]) {
506
+ const text = match[1].trim();
507
+ if (text) {
508
+ res.type("text/plain").send(text);
509
+ return;
510
+ }
511
+ }
512
+ }
513
+ catch {
514
+ // fall through to 404
515
+ }
516
+ res.status(404).json({ error: "instructions_not_found" });
517
+ });
499
518
  // ============================================================================
500
519
  // MCP StreamableHTTP Endpoint (OAuth-enabled MCP transport)
501
520
  // ============================================================================
@@ -3791,6 +3810,83 @@ app.get("/interpretations", async (req, res) => {
3791
3810
  return sendError(res, 500, "DB_QUERY_FAILED", message);
3792
3811
  }
3793
3812
  });
3813
+ app.post("/interpretations/create", async (req, res) => {
3814
+ const parsed = CreateInterpretationRequestSchema.safeParse(req.body);
3815
+ if (!parsed.success) {
3816
+ logWarn("ValidationError:interpretations_create", req, { issues: parsed.error.issues });
3817
+ return sendValidationError(res, parsed.error.issues);
3818
+ }
3819
+ try {
3820
+ const userId = await getAuthenticatedUserId(req, parsed.data.user_id);
3821
+ const { data: source, error: sourceError } = await db
3822
+ .from("sources")
3823
+ .select("id")
3824
+ .eq("id", parsed.data.source_id)
3825
+ .eq("user_id", userId)
3826
+ .maybeSingle();
3827
+ if (sourceError)
3828
+ throw sourceError;
3829
+ if (!source) {
3830
+ return sendError(res, 404, "SOURCE_NOT_FOUND", "Source not found for authenticated user");
3831
+ }
3832
+ const { runInterpretation } = await import("./services/interpretation.js");
3833
+ const interpretationResult = await runInterpretation({
3834
+ userId,
3835
+ sourceId: parsed.data.source_id,
3836
+ extractedData: parsed.data.entities,
3837
+ config: normalizeInterpretationConfig(parsed.data.interpretation_config),
3838
+ });
3839
+ const relationshipsCreated = [];
3840
+ if (parsed.data.relationships?.length) {
3841
+ const { relationshipsService } = await import("./services/relationships.js");
3842
+ for (const rel of parsed.data.relationships) {
3843
+ const sourceEntityId = typeof rel.source_entity_id === "string"
3844
+ ? rel.source_entity_id
3845
+ : typeof rel.source_index === "number"
3846
+ ? interpretationResult.entities[rel.source_index]?.entityId
3847
+ : undefined;
3848
+ const targetEntityId = typeof rel.target_entity_id === "string"
3849
+ ? rel.target_entity_id
3850
+ : typeof rel.target_index === "number"
3851
+ ? interpretationResult.entities[rel.target_index]?.entityId
3852
+ : undefined;
3853
+ if (!sourceEntityId || !targetEntityId)
3854
+ continue;
3855
+ await relationshipsService.createRelationship({
3856
+ source_entity_id: sourceEntityId,
3857
+ target_entity_id: targetEntityId,
3858
+ relationship_type: rel.relationship_type,
3859
+ source_id: parsed.data.source_id,
3860
+ metadata: rel.metadata ?? {},
3861
+ user_id: userId,
3862
+ });
3863
+ relationshipsCreated.push({
3864
+ relationship_type: rel.relationship_type,
3865
+ source_entity_id: sourceEntityId,
3866
+ target_entity_id: targetEntityId,
3867
+ });
3868
+ }
3869
+ }
3870
+ return res.json({
3871
+ success: true,
3872
+ interpretation_id: interpretationResult.interpretationId,
3873
+ source_id: parsed.data.source_id,
3874
+ entities: interpretationResult.entities.map((entity) => ({
3875
+ entity_id: entity.entityId,
3876
+ entity_type: entity.entityType,
3877
+ observation_id: entity.observationId,
3878
+ })),
3879
+ observations_created: interpretationResult.observationsCreated,
3880
+ unknown_fields_count: interpretationResult.unknownFieldsCount,
3881
+ relationships_created: relationshipsCreated,
3882
+ });
3883
+ }
3884
+ catch (error) {
3885
+ logError("APIError:interpretations_create", req, error);
3886
+ const message = error instanceof Error ? error.message : "Failed to create interpretation";
3887
+ return sendError(res, 500, "INTERPRETATION_CREATE_FAILED", message);
3888
+ }
3889
+ });
3794
3890
  // GET /api/observations - Get observations with filters (FU-302, FU-601)
3795
3891
  // REQUIRES AUTHENTICATION - all queries filtered by authenticated user_id
3796
3892
  app.get("/observations", async (req, res) => {
@@ -3906,8 +4002,47 @@ app.post("/observations/create", async (req, res) => {
3906
4002
  return res.status(500).json(buildErrorEnvelope("DB_QUERY_FAILED", message));
3907
4003
  }
3908
4004
  });
4005
+ function normalizeInterpretationConfig(configInput) {
4006
+ return {
4007
+ extractor_type: "agent",
4008
+ extractor_version: "unknown",
4009
+ schema_version: "1.0",
4010
+ ...configInput,
4011
+ };
4012
+ }
4013
+ async function createInterpretationRunForSource(params) {
4014
+ enforceAttributionPolicy("interpretations", getCurrentAgentIdentity());
4015
+ const attribution = getCurrentAttribution();
4016
+ const { data, error } = await db
4017
+ .from("interpretations")
4018
+ .insert({
4019
+ user_id: params.userId,
4020
+ source_id: params.sourceId,
4021
+ interpretation_config: normalizeInterpretationConfig(params.interpretationConfig),
4022
+ status: "running",
4023
+ started_at: new Date().toISOString(),
4024
+ ...(Object.keys(attribution).length > 0 ? { provenance: attribution } : {}),
4025
+ })
4026
+ .select("id")
4027
+ .single();
4028
+ if (error) {
4029
+ throw new Error(`Failed to create interpretation run: ${error.message}`);
4030
+ }
4031
+ return data.id;
4032
+ }
4033
+ async function completeInterpretationRun(params) {
4034
+ await db
4035
+ .from("interpretations")
4036
+ .update({
4037
+ status: "completed",
4038
+ completed_at: new Date().toISOString(),
4039
+ observations_created: params.observationsCreated,
4040
+ unknown_fields_count: params.unknownFieldsCount ?? 0,
4041
+ })
4042
+ .eq("id", params.interpretationId);
4043
+ }
3909
4044
  export async function storeStructuredForApi(params) {
3910
- const { userId, entities, sourcePriority, observationSource, idempotencyKey, originalFilename, relationships, commit: commitInput, strict: strictInput, } = params;
4045
+ const { userId, entities, sourcePriority, observationSource, idempotencyKey, originalFilename, relationships, interpretation, interpretationSourceId, commit: commitInput, strict: strictInput, } = params;
3911
4046
  const commit = commitInput !== false;
3912
4047
  const strict = strictInput === true;
3913
4048
  // Capability scoping: when the caller is an AAuth-verified agent covered
@@ -3919,7 +4054,7 @@ export async function storeStructuredForApi(params) {
3919
4054
  const entityTypes = entities
3920
4055
  .map((entity) => entity?.entity_type)
3921
4056
  .filter((t) => typeof t === "string" && t.length > 0);
3922
- enforceAgentCapability("store_structured", entityTypes, capabilityCtx);
4057
+ enforceAgentCapability("store", entityTypes, capabilityCtx);
3923
4058
  const relationshipOp = Array.isArray(relationships) && relationships.length > 0;
3924
4059
  if (relationshipOp) {
3925
4060
  enforceAgentCapability("create_relationship", entityTypes, capabilityCtx);
@@ -3935,7 +4070,7 @@ export async function storeStructuredForApi(params) {
3935
4070
  .filter((t) => typeof t === "string" && t.length > 0);
3936
4071
  assertCanWriteProtectedBatch({
3937
4072
  entity_types: entityTypes,
3938
- op: "store_structured",
4073
+ op: "store",
3939
4074
  identity: getCurrentAgentIdentity(),
3940
4075
  admission: getCurrentAAuthAdmission(),
3941
4076
  });
@@ -4006,6 +4141,17 @@ export async function storeStructuredForApi(params) {
4006
4141
  source_priority: sourcePriority,
4007
4142
  },
4008
4143
  });
4144
+ const resolvedInterpretationSourceId = interpretation?.source_id ??
4145
+ interpretationSourceId ??
4146
+ (interpretation?.source_ref === "structured" ? storageResult.sourceId : undefined);
4147
+ const interpretationId = commit && interpretation && resolvedInterpretationSourceId
4148
+ ? await createInterpretationRunForSource({
4149
+ userId,
4150
+ sourceId: resolvedInterpretationSourceId,
4151
+ interpretationConfig: interpretation.interpretation_config,
4152
+ })
4153
+ : null;
4154
+ const observationSourceId = resolvedInterpretationSourceId ?? storageResult.sourceId;
4009
4155
  // v0.5.1: structured guidance for the v0.5.0 breaking change where callers
4010
4156
  // nested fields under `attributes`. If resolution failed and the only
4011
4157
  // observed top-level keys are `attributes` (plus optionally `entity_type`),
@@ -4180,8 +4326,8 @@ export async function storeStructuredForApi(params) {
4180
4326
  entity_id: r.entity_id,
4181
4327
  entity_type: r.entity_type,
4182
4328
  schema_version: "1.0",
4183
- source_id: storageResult.sourceId,
4184
- interpretation_id: null,
4329
+ source_id: observationSourceId,
4330
+ interpretation_id: interpretationId,
4185
4331
  observed_at: new Date().toISOString(),
4186
4332
  specificity_score: 1.0,
4187
4333
  source_priority: sourcePriority,
@@ -4216,7 +4362,7 @@ export async function storeStructuredForApi(params) {
4216
4362
  fields: r.fields,
4217
4363
  schema: schemaEntry.schema_definition,
4218
4364
  userId,
4219
- sourceId: storageResult.sourceId,
4365
+ sourceId: observationSourceId,
4220
4366
  });
4221
4367
  }
4222
4368
  }
@@ -4268,7 +4414,7 @@ export async function storeStructuredForApi(params) {
4268
4414
  source_entity_id: sourceEntityId,
4269
4415
  target_entity_id: targetEntityId,
4270
4416
  relationship_type: rel.relationship_type,
4271
- source_id: storageResult.sourceId,
4417
+ source_id: observationSourceId,
4272
4418
  metadata: rel.metadata ?? {},
4273
4419
  user_id: userId,
4274
4420
  });
@@ -4303,11 +4449,21 @@ export async function storeStructuredForApi(params) {
4303
4449
  });
4304
4450
  }
4305
4451
  }
4452
+ if (commit && interpretationId) {
4453
+ await completeInterpretationRun({
4454
+ interpretationId,
4455
+ observationsCreated: createdEntities.filter((e) => e.observation_id).length,
4456
+ unknownFieldsCount: 0,
4457
+ });
4458
+ }
4306
4459
  return {
4307
4460
  success: true,
4308
4461
  replayed: false,
4309
4462
  commit,
4310
4463
  source_id: commit ? storageResult.sourceId : null,
4464
+ ...(interpretationId
4465
+ ? { interpretation_id: interpretationId, interpretation_source_id: observationSourceId }
4466
+ : {}),
4311
4467
  entities_created: commit
4312
4468
  ? createdEntities.filter((e) => e.action === "created" || e.action === "extended").length
4313
4469
  : 0,
@@ -4364,23 +4520,7 @@ async function handleStorePost(req, res) {
4364
4520
  const hasUnstructured = hasFileContent || hasFilePath;
4365
4521
  let structuredResult;
4366
4522
  let unstructuredResult;
4367
- if (hasEntities) {
4368
- if (!parsed.data.idempotency_key) {
4369
- return sendError(res, 400, "VALIDATION_ERROR", "idempotency_key is required when entities are provided");
4370
- }
4371
- structuredResult = await storeStructuredForApi({
4372
- userId,
4373
- entities: parsed.data.entities,
4374
- sourcePriority: parsed.data.source_priority ?? 100,
4375
- observationSource: parsed.data.observation_source,
4376
- idempotencyKey: parsed.data.idempotency_key,
4377
- originalFilename: parsed.data.original_filename,
4378
- relationships: parsed.data.relationships,
4379
- commit: parsed.data.commit,
4380
- strict: parsed.data.strict,
4381
- });
4382
- }
4383
- if (hasUnstructured) {
4523
+ const storeUnstructuredFromRequest = async () => {
4384
4524
  const fileContent = parsed.data.file_content;
4385
4525
  let mimeType = parsed.data.mime_type;
4386
4526
  let originalFilename = parsed.data.original_filename;
@@ -4397,9 +4537,10 @@ async function handleStorePost(req, res) {
4397
4537
  originalFilename = originalFilename || path.basename(resolvedPath);
4398
4538
  }
4399
4539
  if ((!fileContent && !resolvedFileBuffer) || !mimeType) {
4400
- return sendError(res, 400, "VALIDATION_ERROR", "Unstructured store requires file_content+mime_type or file_path");
4540
+ sendError(res, 400, "VALIDATION_ERROR", "Unstructured store requires file_content+mime_type or file_path");
4541
+ return null;
4401
4542
  }
4402
- unstructuredResult = await storeUnstructuredForApi({
4543
+ return await storeUnstructuredForApi({
4403
4544
  userId,
4404
4545
  fileContent,
4405
4546
  fileBuffer: resolvedFileBuffer,
@@ -4408,6 +4549,42 @@ async function handleStorePost(req, res) {
4408
4549
  (!hasEntities ? parsed.data.idempotency_key : undefined),
4409
4550
  originalFilename,
4410
4551
  });
4552
+ };
4553
+ if (hasUnstructured && parsed.data.interpretation?.source_ref === "unstructured") {
4554
+ const result = await storeUnstructuredFromRequest();
4555
+ if (!result) {
4556
+ return;
4557
+ }
4558
+ unstructuredResult = result;
4559
+ }
4560
+ if (hasEntities) {
4561
+ if (!parsed.data.idempotency_key) {
4562
+ return sendError(res, 400, "VALIDATION_ERROR", "idempotency_key is required when entities are provided");
4563
+ }
4564
+ structuredResult = await storeStructuredForApi({
4565
+ userId,
4566
+ entities: parsed.data.entities,
4567
+ sourcePriority: parsed.data.source_priority ?? 100,
4568
+ observationSource: parsed.data.observation_source,
4569
+ idempotencyKey: parsed.data.idempotency_key,
4570
+ originalFilename: parsed.data.original_filename,
4571
+ relationships: parsed.data.relationships,
4572
+ interpretation: parsed.data.interpretation,
4573
+ interpretationSourceId: parsed.data.interpretation?.source_ref === "unstructured" &&
4574
+ unstructuredResult &&
4575
+ typeof unstructuredResult.source_id === "string"
4576
+ ? unstructuredResult.source_id
4577
+ : undefined,
4578
+ commit: parsed.data.commit,
4579
+ strict: parsed.data.strict,
4580
+ });
4581
+ }
4582
+ if (hasUnstructured && !unstructuredResult) {
4583
+ const result = await storeUnstructuredFromRequest();
4584
+ if (!result) {
4585
+ return;
4586
+ }
4587
+ unstructuredResult = result;
4411
4588
  }
4412
4589
  if (structuredResult && unstructuredResult) {
4413
4590
  return res.json({
@@ -4487,33 +4664,6 @@ if (isSandboxMode()) {
4487
4664
  app.post("/sandbox/aauth-only/store", writeRateLimit, aauthRequired, handleStorePost);
4488
4665
  logger.info("[Sandbox] AAuth-required write route enabled at POST /sandbox/aauth-only/store");
4489
4666
  }
4490
- // POST /api/store/unstructured - Store raw file (base64), optional AI interpretation
4491
- app.post("/store/unstructured", async (req, res) => {
4492
- const parsed = StoreUnstructuredRequestSchema.safeParse(req.body);
4493
- if (!parsed.success) {
4494
- logWarn("ValidationError:store_unstructured", req, { issues: parsed.error.issues });
4495
- return sendValidationError(res, parsed.error.issues);
4496
- }
4497
- try {
4498
- const userId = await getAuthenticatedUserId(req, parsed.data.user_id);
4499
- const response = await storeUnstructuredForApi({
4500
- userId,
4501
- fileContent: parsed.data.file_content,
4502
- mimeType: parsed.data.mime_type,
4503
- idempotencyKey: parsed.data.idempotency_key,
4504
- originalFilename: parsed.data.original_filename,
4505
- });
4506
- return res.status(200).json(response);
4507
- }
4508
- catch (error) {
4509
- if (error instanceof Error && error.message.includes("Not authenticated")) {
4510
- return sendError(res, 401, "AUTH_REQUIRED", error.message);
4511
- }
4512
- logError("APIError:store_unstructured", req, error);
4513
- const message = error instanceof Error ? error.message : "Failed to store unstructured file";
4514
- return sendError(res, 500, "DB_QUERY_FAILED", message);
4515
- }
4516
- });
4517
4667
  // POST /api/observations/query - Query observations
4518
4668
  app.post("/observations/query", async (req, res) => {
4519
4669
  const parsed = ObservationsQueryRequestSchema.safeParse(req.body);
@@ -5976,6 +6126,9 @@ export async function startHTTPServer() {
5976
6126
  }
5977
6127
  // eslint-disable-next-line no-console
5978
6128
  console.log(`HTTP Actions listening on :${boundPort}`);
6129
+ if (process.env.NODE_ENV !== "test") {
6130
+ writeLocalHttpPortFile(config.projectRoot, boundPort);
6131
+ }
5979
6132
  // Start background OAuth state cleanup job
5980
6133
  import("./services/mcp_oauth.js").then((oauth) => {
5981
6134
  oauth.startStateCleanupJob();