@agent-native/core 0.37.3 → 0.39.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 (476) hide show
  1. package/README.md +19 -6
  2. package/dist/action.d.ts +60 -2
  3. package/dist/action.d.ts.map +1 -1
  4. package/dist/action.js +6 -2
  5. package/dist/action.js.map +1 -1
  6. package/dist/agent/production-agent.d.ts +12 -6
  7. package/dist/agent/production-agent.d.ts.map +1 -1
  8. package/dist/agent/production-agent.js +161 -11
  9. package/dist/agent/production-agent.js.map +1 -1
  10. package/dist/agent/types.d.ts +2 -0
  11. package/dist/agent/types.d.ts.map +1 -1
  12. package/dist/agent/types.js.map +1 -1
  13. package/dist/catalog.json +2 -2
  14. package/dist/cli/connect.d.ts.map +1 -1
  15. package/dist/cli/connect.js +15 -0
  16. package/dist/cli/connect.js.map +1 -1
  17. package/dist/cli/create.d.ts.map +1 -1
  18. package/dist/cli/create.js +8 -1
  19. package/dist/cli/create.js.map +1 -1
  20. package/dist/cli/index.js +10 -6
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/cli/plan-publish-store.d.ts +52 -0
  23. package/dist/cli/plan-publish-store.d.ts.map +1 -0
  24. package/dist/cli/plan-publish-store.js +103 -0
  25. package/dist/cli/plan-publish-store.js.map +1 -0
  26. package/dist/cli/skills.d.ts +30 -4
  27. package/dist/cli/skills.d.ts.map +1 -1
  28. package/dist/cli/skills.js +1240 -339
  29. package/dist/cli/skills.js.map +1 -1
  30. package/dist/cli/templates-meta.js +12 -12
  31. package/dist/cli/templates-meta.js.map +1 -1
  32. package/dist/client/AssistantChat.d.ts +3 -1
  33. package/dist/client/AssistantChat.d.ts.map +1 -1
  34. package/dist/client/AssistantChat.js +65 -15
  35. package/dist/client/AssistantChat.js.map +1 -1
  36. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  37. package/dist/client/MultiTabAssistantChat.js +20 -2
  38. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  39. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  40. package/dist/client/agent-chat-adapter.js +12 -0
  41. package/dist/client/agent-chat-adapter.js.map +1 -1
  42. package/dist/client/agent-engine-key.d.ts +24 -0
  43. package/dist/client/agent-engine-key.d.ts.map +1 -0
  44. package/dist/client/agent-engine-key.js +49 -0
  45. package/dist/client/agent-engine-key.js.map +1 -0
  46. package/dist/client/analytics.d.ts.map +1 -1
  47. package/dist/client/analytics.js +34 -0
  48. package/dist/client/analytics.js.map +1 -1
  49. package/dist/client/blocks/BlockView.d.ts +35 -0
  50. package/dist/client/blocks/BlockView.d.ts.map +1 -0
  51. package/dist/client/blocks/BlockView.js +45 -0
  52. package/dist/client/blocks/BlockView.js.map +1 -0
  53. package/dist/client/blocks/SchemaBlockEditor.d.ts +25 -0
  54. package/dist/client/blocks/SchemaBlockEditor.d.ts.map +1 -0
  55. package/dist/client/blocks/SchemaBlockEditor.js +165 -0
  56. package/dist/client/blocks/SchemaBlockEditor.js.map +1 -0
  57. package/dist/client/blocks/agent.d.ts +30 -0
  58. package/dist/client/blocks/agent.d.ts.map +1 -0
  59. package/dist/client/blocks/agent.js +61 -0
  60. package/dist/client/blocks/agent.js.map +1 -0
  61. package/dist/client/blocks/index.d.ts +51 -0
  62. package/dist/client/blocks/index.d.ts.map +1 -0
  63. package/dist/client/blocks/index.js +67 -0
  64. package/dist/client/blocks/index.js.map +1 -0
  65. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts +6 -0
  66. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -0
  67. package/dist/client/blocks/library/AnnotatedCodeBlock.js +135 -0
  68. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -0
  69. package/dist/client/blocks/library/ApiEndpointBlock.d.ts +20 -0
  70. package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -0
  71. package/dist/client/blocks/library/ApiEndpointBlock.js +131 -0
  72. package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -0
  73. package/dist/client/blocks/library/DataModelBlock.d.ts +28 -0
  74. package/dist/client/blocks/library/DataModelBlock.d.ts.map +1 -0
  75. package/dist/client/blocks/library/DataModelBlock.js +222 -0
  76. package/dist/client/blocks/library/DataModelBlock.js.map +1 -0
  77. package/dist/client/blocks/library/DiffBlock.d.ts +6 -0
  78. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -0
  79. package/dist/client/blocks/library/DiffBlock.js +293 -0
  80. package/dist/client/blocks/library/DiffBlock.js.map +1 -0
  81. package/dist/client/blocks/library/FileTreeBlock.d.ts +23 -0
  82. package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -0
  83. package/dist/client/blocks/library/FileTreeBlock.js +225 -0
  84. package/dist/client/blocks/library/FileTreeBlock.js.map +1 -0
  85. package/dist/client/blocks/library/JsonExplorerBlock.d.ts +19 -0
  86. package/dist/client/blocks/library/JsonExplorerBlock.d.ts.map +1 -0
  87. package/dist/client/blocks/library/JsonExplorerBlock.js +171 -0
  88. package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -0
  89. package/dist/client/blocks/library/MermaidBlock.d.ts +17 -0
  90. package/dist/client/blocks/library/MermaidBlock.d.ts.map +1 -0
  91. package/dist/client/blocks/library/MermaidBlock.js +131 -0
  92. package/dist/client/blocks/library/MermaidBlock.js.map +1 -0
  93. package/dist/client/blocks/library/OpenApiSpecBlock.d.ts +19 -0
  94. package/dist/client/blocks/library/OpenApiSpecBlock.d.ts.map +1 -0
  95. package/dist/client/blocks/library/OpenApiSpecBlock.js +494 -0
  96. package/dist/client/blocks/library/OpenApiSpecBlock.js.map +1 -0
  97. package/dist/client/blocks/library/annotated-code.config.d.ts +58 -0
  98. package/dist/client/blocks/library/annotated-code.config.d.ts.map +1 -0
  99. package/dist/client/blocks/library/annotated-code.config.js +53 -0
  100. package/dist/client/blocks/library/annotated-code.config.js.map +1 -0
  101. package/dist/client/blocks/library/api-endpoint.config.d.ts +71 -0
  102. package/dist/client/blocks/library/api-endpoint.config.d.ts.map +1 -0
  103. package/dist/client/blocks/library/api-endpoint.config.js +91 -0
  104. package/dist/client/blocks/library/api-endpoint.config.js.map +1 -0
  105. package/dist/client/blocks/library/checklist.config.d.ts +36 -0
  106. package/dist/client/blocks/library/checklist.config.d.ts.map +1 -0
  107. package/dist/client/blocks/library/checklist.config.js +25 -0
  108. package/dist/client/blocks/library/checklist.config.js.map +1 -0
  109. package/dist/client/blocks/library/checklist.d.ts +26 -0
  110. package/dist/client/blocks/library/checklist.d.ts.map +1 -0
  111. package/dist/client/blocks/library/checklist.js +78 -0
  112. package/dist/client/blocks/library/checklist.js.map +1 -0
  113. package/dist/client/blocks/library/code-tabs.config.d.ts +36 -0
  114. package/dist/client/blocks/library/code-tabs.config.d.ts.map +1 -0
  115. package/dist/client/blocks/library/code-tabs.config.js +30 -0
  116. package/dist/client/blocks/library/code-tabs.config.js.map +1 -0
  117. package/dist/client/blocks/library/code-tabs.d.ts +3 -0
  118. package/dist/client/blocks/library/code-tabs.d.ts.map +1 -0
  119. package/dist/client/blocks/library/code-tabs.js +165 -0
  120. package/dist/client/blocks/library/code-tabs.js.map +1 -0
  121. package/dist/client/blocks/library/data-model.config.d.ts +72 -0
  122. package/dist/client/blocks/library/data-model.config.d.ts.map +1 -0
  123. package/dist/client/blocks/library/data-model.config.js +59 -0
  124. package/dist/client/blocks/library/data-model.config.js.map +1 -0
  125. package/dist/client/blocks/library/dev-doc-ui.d.ts +49 -0
  126. package/dist/client/blocks/library/dev-doc-ui.d.ts.map +1 -0
  127. package/dist/client/blocks/library/dev-doc-ui.js +50 -0
  128. package/dist/client/blocks/library/dev-doc-ui.js.map +1 -0
  129. package/dist/client/blocks/library/diff.config.d.ts +41 -0
  130. package/dist/client/blocks/library/diff.config.d.ts.map +1 -0
  131. package/dist/client/blocks/library/diff.config.js +34 -0
  132. package/dist/client/blocks/library/diff.config.js.map +1 -0
  133. package/dist/client/blocks/library/file-tree.config.d.ts +59 -0
  134. package/dist/client/blocks/library/file-tree.config.d.ts.map +1 -0
  135. package/dist/client/blocks/library/file-tree.config.js +45 -0
  136. package/dist/client/blocks/library/file-tree.config.js.map +1 -0
  137. package/dist/client/blocks/library/html.config.d.ts +37 -0
  138. package/dist/client/blocks/library/html.config.d.ts.map +1 -0
  139. package/dist/client/blocks/library/html.config.js +46 -0
  140. package/dist/client/blocks/library/html.config.js.map +1 -0
  141. package/dist/client/blocks/library/html.d.ts +21 -0
  142. package/dist/client/blocks/library/html.d.ts.map +1 -0
  143. package/dist/client/blocks/library/html.js +72 -0
  144. package/dist/client/blocks/library/html.js.map +1 -0
  145. package/dist/client/blocks/library/json-explorer.config.d.ts +46 -0
  146. package/dist/client/blocks/library/json-explorer.config.d.ts.map +1 -0
  147. package/dist/client/blocks/library/json-explorer.config.js +28 -0
  148. package/dist/client/blocks/library/json-explorer.config.js.map +1 -0
  149. package/dist/client/blocks/library/mermaid.config.d.ts +32 -0
  150. package/dist/client/blocks/library/mermaid.config.d.ts.map +1 -0
  151. package/dist/client/blocks/library/mermaid.config.js +24 -0
  152. package/dist/client/blocks/library/mermaid.config.js.map +1 -0
  153. package/dist/client/blocks/library/openapi-spec.config.d.ts +49 -0
  154. package/dist/client/blocks/library/openapi-spec.config.d.ts.map +1 -0
  155. package/dist/client/blocks/library/openapi-spec.config.js +24 -0
  156. package/dist/client/blocks/library/openapi-spec.config.js.map +1 -0
  157. package/dist/client/blocks/library/server-specs.d.ts +35 -0
  158. package/dist/client/blocks/library/server-specs.d.ts.map +1 -0
  159. package/dist/client/blocks/library/server-specs.js +171 -0
  160. package/dist/client/blocks/library/server-specs.js.map +1 -0
  161. package/dist/client/blocks/library/specs.d.ts +29 -0
  162. package/dist/client/blocks/library/specs.d.ts.map +1 -0
  163. package/dist/client/blocks/library/specs.js +229 -0
  164. package/dist/client/blocks/library/specs.js.map +1 -0
  165. package/dist/client/blocks/library/table.config.d.ts +30 -0
  166. package/dist/client/blocks/library/table.config.d.ts.map +1 -0
  167. package/dist/client/blocks/library/table.config.js +22 -0
  168. package/dist/client/blocks/library/table.config.js.map +1 -0
  169. package/dist/client/blocks/library/table.d.ts +8 -0
  170. package/dist/client/blocks/library/table.d.ts.map +1 -0
  171. package/dist/client/blocks/library/table.js +109 -0
  172. package/dist/client/blocks/library/table.js.map +1 -0
  173. package/dist/client/blocks/library/tabs.config.d.ts +56 -0
  174. package/dist/client/blocks/library/tabs.config.d.ts.map +1 -0
  175. package/dist/client/blocks/library/tabs.config.js +36 -0
  176. package/dist/client/blocks/library/tabs.config.js.map +1 -0
  177. package/dist/client/blocks/library/tabs.d.ts +20 -0
  178. package/dist/client/blocks/library/tabs.d.ts.map +1 -0
  179. package/dist/client/blocks/library/tabs.js +123 -0
  180. package/dist/client/blocks/library/tabs.js.map +1 -0
  181. package/dist/client/blocks/mdx.d.ts +74 -0
  182. package/dist/client/blocks/mdx.d.ts.map +1 -0
  183. package/dist/client/blocks/mdx.js +205 -0
  184. package/dist/client/blocks/mdx.js.map +1 -0
  185. package/dist/client/blocks/provider.d.ts +25 -0
  186. package/dist/client/blocks/provider.d.ts.map +1 -0
  187. package/dist/client/blocks/provider.js +19 -0
  188. package/dist/client/blocks/provider.js.map +1 -0
  189. package/dist/client/blocks/registry.d.ts +32 -0
  190. package/dist/client/blocks/registry.d.ts.map +1 -0
  191. package/dist/client/blocks/registry.js +65 -0
  192. package/dist/client/blocks/registry.js.map +1 -0
  193. package/dist/client/blocks/schema-form/introspect.d.ts +31 -0
  194. package/dist/client/blocks/schema-form/introspect.d.ts.map +1 -0
  195. package/dist/client/blocks/schema-form/introspect.js +164 -0
  196. package/dist/client/blocks/schema-form/introspect.js.map +1 -0
  197. package/dist/client/blocks/server.d.ts +31 -0
  198. package/dist/client/blocks/server.d.ts.map +1 -0
  199. package/dist/client/blocks/server.js +41 -0
  200. package/dist/client/blocks/server.js.map +1 -0
  201. package/dist/client/blocks/types.d.ts +252 -0
  202. package/dist/client/blocks/types.d.ts.map +1 -0
  203. package/dist/client/blocks/types.js +5 -0
  204. package/dist/client/blocks/types.js.map +1 -0
  205. package/dist/client/composer/ComposerPlusMenu.js +10 -1
  206. package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
  207. package/dist/client/guided-questions.d.ts +68 -0
  208. package/dist/client/guided-questions.d.ts.map +1 -1
  209. package/dist/client/guided-questions.js +158 -3
  210. package/dist/client/guided-questions.js.map +1 -1
  211. package/dist/client/index.d.ts +6 -1
  212. package/dist/client/index.d.ts.map +1 -1
  213. package/dist/client/index.js +24 -1
  214. package/dist/client/index.js.map +1 -1
  215. package/dist/client/rich-markdown-editor/BubbleToolbar.d.ts +37 -0
  216. package/dist/client/rich-markdown-editor/BubbleToolbar.d.ts.map +1 -0
  217. package/dist/client/rich-markdown-editor/BubbleToolbar.js +161 -0
  218. package/dist/client/rich-markdown-editor/BubbleToolbar.js.map +1 -0
  219. package/dist/client/rich-markdown-editor/DragHandle.d.ts +52 -0
  220. package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -0
  221. package/dist/client/rich-markdown-editor/DragHandle.js +403 -0
  222. package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -0
  223. package/dist/client/rich-markdown-editor/ImageExtension.d.ts +63 -0
  224. package/dist/client/rich-markdown-editor/ImageExtension.d.ts.map +1 -0
  225. package/dist/client/rich-markdown-editor/ImageExtension.js +242 -0
  226. package/dist/client/rich-markdown-editor/ImageExtension.js.map +1 -0
  227. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts +97 -0
  228. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -0
  229. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +214 -0
  230. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -0
  231. package/dist/client/rich-markdown-editor/RichMarkdownEditor.d.ts +51 -0
  232. package/dist/client/rich-markdown-editor/RichMarkdownEditor.d.ts.map +1 -0
  233. package/dist/client/rich-markdown-editor/RichMarkdownEditor.js +37 -0
  234. package/dist/client/rich-markdown-editor/RichMarkdownEditor.js.map +1 -0
  235. package/dist/client/rich-markdown-editor/RunId.d.ts +28 -0
  236. package/dist/client/rich-markdown-editor/RunId.d.ts.map +1 -0
  237. package/dist/client/rich-markdown-editor/RunId.js +60 -0
  238. package/dist/client/rich-markdown-editor/RunId.js.map +1 -0
  239. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +85 -0
  240. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -0
  241. package/dist/client/rich-markdown-editor/SharedRichEditor.js +130 -0
  242. package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -0
  243. package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts +36 -0
  244. package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts.map +1 -0
  245. package/dist/client/rich-markdown-editor/SlashCommandMenu.js +193 -0
  246. package/dist/client/rich-markdown-editor/SlashCommandMenu.js.map +1 -0
  247. package/dist/client/rich-markdown-editor/extensions.d.ts +166 -0
  248. package/dist/client/rich-markdown-editor/extensions.d.ts.map +1 -0
  249. package/dist/client/rich-markdown-editor/extensions.js +222 -0
  250. package/dist/client/rich-markdown-editor/extensions.js.map +1 -0
  251. package/dist/client/rich-markdown-editor/gfmDoc.d.ts +24 -0
  252. package/dist/client/rich-markdown-editor/gfmDoc.d.ts.map +1 -0
  253. package/dist/client/rich-markdown-editor/gfmDoc.js +83 -0
  254. package/dist/client/rich-markdown-editor/gfmDoc.js.map +1 -0
  255. package/dist/client/rich-markdown-editor/index.d.ts +14 -0
  256. package/dist/client/rich-markdown-editor/index.d.ts.map +1 -0
  257. package/dist/client/rich-markdown-editor/index.js +14 -0
  258. package/dist/client/rich-markdown-editor/index.js.map +1 -0
  259. package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts +46 -0
  260. package/dist/client/rich-markdown-editor/registrySlashCommands.d.ts.map +1 -0
  261. package/dist/client/rich-markdown-editor/registrySlashCommands.js +13 -0
  262. package/dist/client/rich-markdown-editor/registrySlashCommands.js.map +1 -0
  263. package/dist/client/rich-markdown-editor/uploadEditorImage.d.ts +18 -0
  264. package/dist/client/rich-markdown-editor/uploadEditorImage.d.ts.map +1 -0
  265. package/dist/client/rich-markdown-editor/uploadEditorImage.js +57 -0
  266. package/dist/client/rich-markdown-editor/uploadEditorImage.js.map +1 -0
  267. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts +91 -0
  268. package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -0
  269. package/dist/client/rich-markdown-editor/useCollabReconcile.js +375 -0
  270. package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -0
  271. package/dist/client/track.d.ts +25 -0
  272. package/dist/client/track.d.ts.map +1 -0
  273. package/dist/client/track.js +53 -0
  274. package/dist/client/track.js.map +1 -0
  275. package/dist/client/use-action.d.ts.map +1 -1
  276. package/dist/client/use-action.js +6 -0
  277. package/dist/client/use-action.js.map +1 -1
  278. package/dist/client/use-session.d.ts +3 -2
  279. package/dist/client/use-session.d.ts.map +1 -1
  280. package/dist/client/use-session.js +3 -2
  281. package/dist/client/use-session.js.map +1 -1
  282. package/dist/deploy/build.d.ts +5 -0
  283. package/dist/deploy/build.d.ts.map +1 -1
  284. package/dist/deploy/build.js +67 -1
  285. package/dist/deploy/build.js.map +1 -1
  286. package/dist/extensions/schema.d.ts +1 -1
  287. package/dist/mcp/build-server.d.ts.map +1 -1
  288. package/dist/mcp/build-server.js +9 -2
  289. package/dist/mcp/build-server.js.map +1 -1
  290. package/dist/mcp/server.d.ts +1 -1
  291. package/dist/mcp/server.d.ts.map +1 -1
  292. package/dist/mcp/server.js +35 -2
  293. package/dist/mcp/server.js.map +1 -1
  294. package/dist/provider-api/index.d.ts +1 -1
  295. package/dist/provider-api/index.d.ts.map +1 -1
  296. package/dist/scripts/docs/search.d.ts.map +1 -1
  297. package/dist/scripts/docs/search.js +5 -2
  298. package/dist/scripts/docs/search.js.map +1 -1
  299. package/dist/scripts/runner.d.ts.map +1 -1
  300. package/dist/scripts/runner.js +16 -3
  301. package/dist/scripts/runner.js.map +1 -1
  302. package/dist/server/action-discovery.d.ts.map +1 -1
  303. package/dist/server/action-discovery.js +2 -0
  304. package/dist/server/action-discovery.js.map +1 -1
  305. package/dist/server/action-routes.d.ts.map +1 -1
  306. package/dist/server/action-routes.js +30 -4
  307. package/dist/server/action-routes.js.map +1 -1
  308. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  309. package/dist/server/agent-chat-plugin.js +65 -19
  310. package/dist/server/agent-chat-plugin.js.map +1 -1
  311. package/dist/server/agent-teams.d.ts.map +1 -1
  312. package/dist/server/agent-teams.js +8 -1
  313. package/dist/server/agent-teams.js.map +1 -1
  314. package/dist/server/agents-bundle.d.ts +27 -1
  315. package/dist/server/agents-bundle.d.ts.map +1 -1
  316. package/dist/server/agents-bundle.js +41 -3
  317. package/dist/server/agents-bundle.js.map +1 -1
  318. package/dist/server/auth.d.ts.map +1 -1
  319. package/dist/server/auth.js +76 -3
  320. package/dist/server/auth.js.map +1 -1
  321. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  322. package/dist/server/core-routes-plugin.js +60 -0
  323. package/dist/server/core-routes-plugin.js.map +1 -1
  324. package/dist/server/onboarding-html.d.ts.map +1 -1
  325. package/dist/server/onboarding-html.js +160 -22
  326. package/dist/server/onboarding-html.js.map +1 -1
  327. package/dist/server/sentry.d.ts.map +1 -1
  328. package/dist/server/sentry.js +6 -0
  329. package/dist/server/sentry.js.map +1 -1
  330. package/dist/server/social-og-image.d.ts +2 -1
  331. package/dist/server/social-og-image.d.ts.map +1 -1
  332. package/dist/server/social-og-image.js +24 -4
  333. package/dist/server/social-og-image.js.map +1 -1
  334. package/dist/sharing/schema.d.ts +1 -1
  335. package/dist/styles/agent-native.css +1 -0
  336. package/dist/styles/rich-markdown-editor.css +439 -0
  337. package/dist/templates/default/.agents/skills/actions/SKILL.md +4 -1
  338. package/dist/templates/default/.agents/skills/security/SKILL.md +13 -4
  339. package/dist/templates/default/.agents/skills/storing-data/SKILL.md +15 -3
  340. package/dist/templates/default/AGENTS.md +1 -0
  341. package/dist/templates/default/DEVELOPING.md +2 -0
  342. package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +10 -3
  343. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +98 -10
  344. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +45 -3
  345. package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +2 -0
  346. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +37 -4
  347. package/dist/templates/workspace-core/.agents/skills/automations/SKILL.md +9 -4
  348. package/dist/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +2 -0
  349. package/dist/templates/workspace-core/.agents/skills/client-methods/SKILL.md +106 -0
  350. package/dist/templates/workspace-core/.agents/skills/client-methods/references/legacy-client-fetch-audit-2026-06-03.md +53 -0
  351. package/dist/templates/workspace-core/.agents/skills/client-side-routing/SKILL.md +2 -0
  352. package/dist/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +62 -61
  353. package/dist/templates/workspace-core/.agents/skills/context-xray/SKILL.md +47 -0
  354. package/dist/templates/workspace-core/.agents/skills/create-skill/SKILL.md +28 -0
  355. package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +52 -1
  356. package/dist/templates/workspace-core/.agents/skills/extension-points/SKILL.md +2 -0
  357. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +95 -433
  358. package/dist/templates/workspace-core/.agents/skills/extensions/references/api.md +285 -0
  359. package/dist/templates/workspace-core/.agents/skills/extensions/references/examples.md +259 -0
  360. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +398 -0
  361. package/dist/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +157 -0
  362. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +17 -0
  363. package/dist/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +13 -2
  364. package/dist/templates/workspace-core/.agents/skills/mvp-followup/SKILL.md +51 -0
  365. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +14 -4
  366. package/dist/templates/workspace-core/.agents/skills/onboarding/SKILL.md +13 -1
  367. package/dist/templates/workspace-core/.agents/skills/portability/SKILL.md +27 -5
  368. package/dist/templates/workspace-core/.agents/skills/qa/SKILL.md +24 -8
  369. package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +53 -7
  370. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +43 -10
  371. package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +2 -0
  372. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +43 -14
  373. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +50 -1
  374. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +4 -2
  375. package/dist/templates/workspace-core/.agents/skills/server-plugins/SKILL.md +11 -1
  376. package/dist/templates/workspace-core/.agents/skills/shadcn-ui/SKILL.md +15 -0
  377. package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +5 -1
  378. package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +48 -19
  379. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +7 -3
  380. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +13 -6
  381. package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +236 -0
  382. package/dist/templates/workspace-core/AGENTS.md +5 -1
  383. package/dist/templates/workspace-root/AGENTS.md +5 -2
  384. package/dist/tracking/route.d.ts +43 -0
  385. package/dist/tracking/route.d.ts.map +1 -0
  386. package/dist/tracking/route.js +85 -0
  387. package/dist/tracking/route.js.map +1 -0
  388. package/dist/vite/client.d.ts.map +1 -1
  389. package/dist/vite/client.js +15 -0
  390. package/dist/vite/client.js.map +1 -1
  391. package/docs/content/a2a-protocol.md +18 -4
  392. package/docs/content/actions.md +87 -0
  393. package/docs/content/agent-mentions.md +2 -1
  394. package/docs/content/authentication.md +2 -1
  395. package/docs/content/client.md +64 -13
  396. package/docs/content/cloneable-saas.md +1 -1
  397. package/docs/content/code-agents-ui.md +17 -11
  398. package/docs/content/context-awareness.md +23 -28
  399. package/docs/content/creating-templates.md +1 -1
  400. package/docs/content/drop-in-agent.md +2 -0
  401. package/docs/content/getting-started.md +2 -2
  402. package/docs/content/key-concepts.md +2 -2
  403. package/docs/content/messaging.md +57 -15
  404. package/docs/content/migration-workbench.md +1 -1
  405. package/docs/content/multi-app-workspace.md +1 -1
  406. package/docs/content/multi-tenancy.md +17 -15
  407. package/docs/content/real-time-collaboration.md +1 -1
  408. package/docs/content/recurring-jobs.md +1 -1
  409. package/docs/content/security.md +2 -2
  410. package/docs/content/server.md +4 -4
  411. package/docs/content/skills-guide.md +30 -0
  412. package/docs/content/template-analytics.md +2 -2
  413. package/docs/content/template-assets.md +17 -1
  414. package/docs/content/template-brain.md +2 -2
  415. package/docs/content/template-calendar.md +1 -1
  416. package/docs/content/template-clips.md +3 -3
  417. package/docs/content/template-content.md +2 -2
  418. package/docs/content/template-design.md +2 -2
  419. package/docs/content/template-dispatch.md +3 -3
  420. package/docs/content/template-forms.md +14 -2
  421. package/docs/content/template-mail.md +1 -3
  422. package/docs/content/template-plan.md +133 -0
  423. package/docs/content/template-slides.md +5 -4
  424. package/docs/content/template-starter.md +4 -4
  425. package/docs/content/template-videos.md +6 -11
  426. package/docs/content/tracking.md +21 -1
  427. package/docs/content/visual-plans.md +74 -0
  428. package/docs/content/workspace.md +9 -9
  429. package/package.json +26 -11
  430. package/src/templates/default/.agents/skills/actions/SKILL.md +4 -1
  431. package/src/templates/default/.agents/skills/security/SKILL.md +13 -4
  432. package/src/templates/default/.agents/skills/storing-data/SKILL.md +15 -3
  433. package/src/templates/default/AGENTS.md +1 -0
  434. package/src/templates/default/DEVELOPING.md +2 -0
  435. package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +10 -3
  436. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +98 -10
  437. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +45 -3
  438. package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +2 -0
  439. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +37 -4
  440. package/src/templates/workspace-core/.agents/skills/automations/SKILL.md +9 -4
  441. package/src/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +2 -0
  442. package/src/templates/workspace-core/.agents/skills/client-methods/SKILL.md +106 -0
  443. package/src/templates/workspace-core/.agents/skills/client-methods/references/legacy-client-fetch-audit-2026-06-03.md +53 -0
  444. package/src/templates/workspace-core/.agents/skills/client-side-routing/SKILL.md +2 -0
  445. package/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +62 -61
  446. package/src/templates/workspace-core/.agents/skills/context-xray/SKILL.md +47 -0
  447. package/src/templates/workspace-core/.agents/skills/create-skill/SKILL.md +28 -0
  448. package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +52 -1
  449. package/src/templates/workspace-core/.agents/skills/extension-points/SKILL.md +2 -0
  450. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +95 -433
  451. package/src/templates/workspace-core/.agents/skills/extensions/references/api.md +285 -0
  452. package/src/templates/workspace-core/.agents/skills/extensions/references/examples.md +259 -0
  453. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +398 -0
  454. package/src/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +157 -0
  455. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +17 -0
  456. package/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +13 -2
  457. package/src/templates/workspace-core/.agents/skills/mvp-followup/SKILL.md +51 -0
  458. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +14 -4
  459. package/src/templates/workspace-core/.agents/skills/onboarding/SKILL.md +13 -1
  460. package/src/templates/workspace-core/.agents/skills/portability/SKILL.md +27 -5
  461. package/src/templates/workspace-core/.agents/skills/qa/SKILL.md +24 -8
  462. package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +53 -7
  463. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +43 -10
  464. package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +2 -0
  465. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +43 -14
  466. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +50 -1
  467. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +4 -2
  468. package/src/templates/workspace-core/.agents/skills/server-plugins/SKILL.md +11 -1
  469. package/src/templates/workspace-core/.agents/skills/shadcn-ui/SKILL.md +15 -0
  470. package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +5 -1
  471. package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +48 -19
  472. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +7 -3
  473. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +13 -6
  474. package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +236 -0
  475. package/src/templates/workspace-core/AGENTS.md +5 -1
  476. package/src/templates/workspace-root/AGENTS.md +5 -2
@@ -0,0 +1,242 @@
1
+ import Image from "@tiptap/extension-image";
2
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
3
+ const sharedImageUploadPluginKey = new PluginKey("an-shared-image-upload");
4
+ /** A monotonically increasing id so concurrent uploads patch the right node. */
5
+ let uploadCounter = 0;
6
+ function nextUploadId() {
7
+ uploadCounter += 1;
8
+ return `an-img-${Date.now()}-${uploadCounter}`;
9
+ }
10
+ /** Image files only — never ingest non-image clipboard/drop payloads. */
11
+ function imageFilesFrom(data) {
12
+ if (!data)
13
+ return [];
14
+ return Array.from(data.files ?? []).filter((file) => file.type.startsWith("image/"));
15
+ }
16
+ /**
17
+ * Insert a placeholder `image` node (empty `src`, transient `uploadId`) at
18
+ * `pos` for every file, then resolve each upload and patch the matching node's
19
+ * `src`. Mirrors Content's optimistic upload flow but is self-contained in the
20
+ * shared extension so it works for ANY editor wrapper (the plan's
21
+ * `SharedRichEditor` and Content's hand-rolled `useEditor` alike) without a new
22
+ * `editorProps` seam.
23
+ */
24
+ function uploadAndInsertImages(view, files, pos, upload) {
25
+ if (files.length === 0)
26
+ return;
27
+ const pending = [];
28
+ // Insert all placeholders first, top-down from `pos`, so multi-file
29
+ // paste/drop keeps source order.
30
+ let insertAt = pos;
31
+ for (const file of files) {
32
+ const uploadId = nextUploadId();
33
+ const node = view.state.schema.nodes.image?.create({
34
+ src: "",
35
+ alt: "",
36
+ uploadId,
37
+ });
38
+ if (!node)
39
+ continue;
40
+ const tr = view.state.tr.insert(insertAt, node);
41
+ view.dispatch(tr);
42
+ pending.push({ uploadId, file });
43
+ // Advance past the inserted atom for the next placeholder.
44
+ insertAt += node.nodeSize;
45
+ }
46
+ for (const item of pending) {
47
+ void (async () => {
48
+ try {
49
+ const { src, alt } = await upload(item.file);
50
+ if (!view.dom.isConnected || view.isDestroyed)
51
+ return;
52
+ patchUploadNode(view, item.uploadId, { src, alt: alt ?? "" });
53
+ }
54
+ catch (error) {
55
+ console.error("Image upload failed:", error);
56
+ // Drop the placeholder so a failed upload does not leave an empty box.
57
+ if (view.dom.isConnected && !view.isDestroyed) {
58
+ removeUploadNode(view, item.uploadId);
59
+ }
60
+ }
61
+ })();
62
+ }
63
+ }
64
+ /** Find a placeholder node by its transient `uploadId` and return its position. */
65
+ function findUploadNode(view, uploadId) {
66
+ let found = null;
67
+ view.state.doc.descendants((node, pos) => {
68
+ if (found)
69
+ return false;
70
+ if (node.type.name === "image" && node.attrs.uploadId === uploadId) {
71
+ found = { pos, nodeSize: node.nodeSize };
72
+ return false;
73
+ }
74
+ return true;
75
+ });
76
+ return found;
77
+ }
78
+ /** Patch the resolved `src`/`alt` onto the placeholder and clear `uploadId`. */
79
+ function patchUploadNode(view, uploadId, attrs) {
80
+ const target = findUploadNode(view, uploadId);
81
+ if (!target)
82
+ return;
83
+ const node = view.state.doc.nodeAt(target.pos);
84
+ if (!node)
85
+ return;
86
+ const tr = view.state.tr.setNodeMarkup(target.pos, undefined, {
87
+ ...node.attrs,
88
+ src: attrs.src,
89
+ alt: attrs.alt,
90
+ uploadId: null,
91
+ });
92
+ view.dispatch(tr);
93
+ }
94
+ /** Remove a placeholder whose upload failed. */
95
+ function removeUploadNode(view, uploadId) {
96
+ const target = findUploadNode(view, uploadId);
97
+ if (!target)
98
+ return;
99
+ const tr = view.state.tr.delete(target.pos, target.pos + target.nodeSize);
100
+ view.dispatch(tr);
101
+ }
102
+ /**
103
+ * The SHARED block-level image node. Built on `@tiptap/extension-image` (a
104
+ * node named `image`), so:
105
+ *
106
+ * - **GFM serialization** emits pure `![alt](src)` markdown via a block-aware
107
+ * `addStorage().markdown.serialize` (it calls `closeBlock` so a block image
108
+ * keeps its blank-line separator, byte-stable). It emits NO `<img width>`
109
+ * HTML, so plans stay source-syncable under the GFM `html:false` contract.
110
+ * - **Paste / drop** of local image files is handled by a self-contained
111
+ * ProseMirror plugin that calls the injected {@link ImageUploadFn}. Pasting
112
+ * an image URL or `![](url)` markdown works through the base node's input
113
+ * rules even when no uploader is supplied.
114
+ *
115
+ * The node adds one transient `uploadId` attribute (never parsed/rendered to
116
+ * HTML, never serialized to markdown) used to track an in-flight upload.
117
+ *
118
+ * Content keeps its own richer `ImageNode` (Assets picker, AI alt-text, resize,
119
+ * NFM `{color}` serialization) and does NOT use this shared node — both nodes
120
+ * are named `image` but never coexist in the same editor because Content leaves
121
+ * `features.image` off and injects its own via `extraExtensions`.
122
+ */
123
+ export const SharedImage = Image.extend({
124
+ // Block-level atom (Content's image is also a block atom). The base extension
125
+ // is block when `inline:false`.
126
+ inline: false,
127
+ group: "block",
128
+ addOptions() {
129
+ return {
130
+ ...this.parent?.(),
131
+ onImageUpload: null,
132
+ };
133
+ },
134
+ addAttributes() {
135
+ return {
136
+ ...this.parent?.(),
137
+ // Transient: marks an in-flight upload so the plugin can patch `src` on
138
+ // resolve. Never written to HTML or markdown.
139
+ uploadId: {
140
+ default: null,
141
+ parseHTML: () => null,
142
+ renderHTML: () => ({}),
143
+ },
144
+ };
145
+ },
146
+ addStorage() {
147
+ return {
148
+ ...this.parent?.(),
149
+ // A BLOCK-aware markdown serializer. tiptap-markdown's built-in fallback
150
+ // for the `image` node is prosemirror-markdown's INLINE image serializer,
151
+ // which omits the trailing block separator — so an image immediately
152
+ // followed by a paragraph loses its blank line on round-trip. This
153
+ // node-level spec (merged OVER the fallback by tiptap-markdown's
154
+ // `getMarkdownSpec`) emits the same pure `![alt](src)` markdown but calls
155
+ // `closeBlock`, so a block image stays byte-stable and source-syncable.
156
+ // No `<img width>` / HTML is emitted, so the GFM `html:false` contract and
157
+ // the plan round-trip corpus are preserved.
158
+ markdown: {
159
+ serialize(state, node) {
160
+ const src = node.attrs.src ?? "";
161
+ const alt = node.attrs.alt ?? "";
162
+ const title = node.attrs.title ?? "";
163
+ const titleSuffix = title ? ` "${title.replace(/"/g, '\\"')}"` : "";
164
+ state.write(`![${state.esc(alt)}](${state.esc(src)}${titleSuffix})`);
165
+ state.closeBlock(node);
166
+ },
167
+ parse: {
168
+ // Parsing `![alt](src)` is handled by markdown-it + the base node's
169
+ // markdown input rule.
170
+ },
171
+ },
172
+ };
173
+ },
174
+ addProseMirrorPlugins() {
175
+ const upload = this.options.onImageUpload;
176
+ const parentPlugins = this.parent?.() ?? [];
177
+ if (!upload)
178
+ return parentPlugins;
179
+ return [
180
+ ...parentPlugins,
181
+ new Plugin({
182
+ key: sharedImageUploadPluginKey,
183
+ props: {
184
+ handlePaste(view, event) {
185
+ const files = imageFilesFrom(event.clipboardData);
186
+ if (files.length === 0)
187
+ return false;
188
+ event.preventDefault();
189
+ uploadAndInsertImages(view, files, view.state.selection.from, upload);
190
+ return true;
191
+ },
192
+ handleDrop(view, event) {
193
+ const files = imageFilesFrom(event.dataTransfer);
194
+ if (files.length === 0)
195
+ return false;
196
+ event.preventDefault();
197
+ const coords = view.posAtCoords({
198
+ left: event.clientX,
199
+ top: event.clientY,
200
+ });
201
+ const pos = coords?.pos ?? view.state.selection.from;
202
+ uploadAndInsertImages(view, files, pos, upload);
203
+ return true;
204
+ },
205
+ },
206
+ }),
207
+ ];
208
+ },
209
+ });
210
+ /**
211
+ * Build the shared image extension, optionally wired with an app uploader.
212
+ *
213
+ * @example
214
+ * createImageExtension({ onImageUpload: uploadEditorImage })
215
+ */
216
+ export function createImageExtension(options = {}) {
217
+ return SharedImage.configure({
218
+ onImageUpload: options.onImageUpload ?? null,
219
+ HTMLAttributes: { class: "an-rich-md-image" },
220
+ });
221
+ }
222
+ /**
223
+ * Open a native file picker, then upload + insert the chosen image(s) through
224
+ * the same flow as paste/drop. Used by the `/image` slash command.
225
+ */
226
+ export function pickAndInsertImage(view, upload) {
227
+ const input = document.createElement("input");
228
+ input.type = "file";
229
+ input.accept = "image/*";
230
+ input.multiple = true;
231
+ input.style.display = "none";
232
+ input.addEventListener("change", () => {
233
+ const files = Array.from(input.files ?? []).filter((file) => file.type.startsWith("image/"));
234
+ input.remove();
235
+ if (files.length === 0)
236
+ return;
237
+ uploadAndInsertImages(view, files, view.state.selection.from, upload);
238
+ });
239
+ document.body.appendChild(input);
240
+ input.click();
241
+ }
242
+ //# sourceMappingURL=ImageExtension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageExtension.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/ImageExtension.ts"],"names":[],"mappings":"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","sourcesContent":["import Image, { type ImageOptions } from \"@tiptap/extension-image\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport type { EditorView } from \"@tiptap/pm/view\";\n\n/**\n * The injectable async upload contract for the shared image block.\n *\n * An app provides this to turn a picked / pasted / dropped {@link File} into a\n * hosted image. It returns the final `src` (a hosted URL) plus an optional\n * `alt`. Plans wire it to the framework `upload-image` action; Content keeps its\n * own richer image block and does not use this contract.\n *\n * When NO upload function is supplied, the shared block still renders images and\n * round-trips `![alt](src)` markdown — it just cannot ingest local files (paste\n * of an image URL / markdown still works via the base node's input rules).\n */\nexport type ImageUploadFn = (\n file: File,\n) => Promise<{ src: string; alt?: string }>;\n\nexport interface SharedImageOptions extends ImageOptions {\n /**\n * App-injected uploader. When present, the shared block accepts pasted /\n * dropped image files and the `/image` slash command, uploading each file\n * through this function and patching the node's `src` on resolve.\n */\n onImageUpload?: ImageUploadFn | null;\n}\n\nconst sharedImageUploadPluginKey = new PluginKey(\"an-shared-image-upload\");\n\n/** A monotonically increasing id so concurrent uploads patch the right node. */\nlet uploadCounter = 0;\nfunction nextUploadId(): string {\n uploadCounter += 1;\n return `an-img-${Date.now()}-${uploadCounter}`;\n}\n\n/** Image files only — never ingest non-image clipboard/drop payloads. */\nfunction imageFilesFrom(data: DataTransfer | null | undefined): File[] {\n if (!data) return [];\n return Array.from(data.files ?? []).filter((file) =>\n file.type.startsWith(\"image/\"),\n );\n}\n\n/**\n * Insert a placeholder `image` node (empty `src`, transient `uploadId`) at\n * `pos` for every file, then resolve each upload and patch the matching node's\n * `src`. Mirrors Content's optimistic upload flow but is self-contained in the\n * shared extension so it works for ANY editor wrapper (the plan's\n * `SharedRichEditor` and Content's hand-rolled `useEditor` alike) without a new\n * `editorProps` seam.\n */\nfunction uploadAndInsertImages(\n view: EditorView,\n files: File[],\n pos: number,\n upload: ImageUploadFn,\n): void {\n if (files.length === 0) return;\n\n const pending: Array<{ uploadId: string; file: File }> = [];\n\n // Insert all placeholders first, top-down from `pos`, so multi-file\n // paste/drop keeps source order.\n let insertAt = pos;\n for (const file of files) {\n const uploadId = nextUploadId();\n const node = view.state.schema.nodes.image?.create({\n src: \"\",\n alt: \"\",\n uploadId,\n });\n if (!node) continue;\n const tr = view.state.tr.insert(insertAt, node);\n view.dispatch(tr);\n pending.push({ uploadId, file });\n // Advance past the inserted atom for the next placeholder.\n insertAt += node.nodeSize;\n }\n\n for (const item of pending) {\n void (async () => {\n try {\n const { src, alt } = await upload(item.file);\n if (!view.dom.isConnected || view.isDestroyed) return;\n patchUploadNode(view, item.uploadId, { src, alt: alt ?? \"\" });\n } catch (error) {\n console.error(\"Image upload failed:\", error);\n // Drop the placeholder so a failed upload does not leave an empty box.\n if (view.dom.isConnected && !view.isDestroyed) {\n removeUploadNode(view, item.uploadId);\n }\n }\n })();\n }\n}\n\n/** Find a placeholder node by its transient `uploadId` and return its position. */\nfunction findUploadNode(\n view: EditorView,\n uploadId: string,\n): { pos: number; nodeSize: number } | null {\n let found: { pos: number; nodeSize: number } | null = null;\n view.state.doc.descendants((node, pos) => {\n if (found) return false;\n if (node.type.name === \"image\" && node.attrs.uploadId === uploadId) {\n found = { pos, nodeSize: node.nodeSize };\n return false;\n }\n return true;\n });\n return found;\n}\n\n/** Patch the resolved `src`/`alt` onto the placeholder and clear `uploadId`. */\nfunction patchUploadNode(\n view: EditorView,\n uploadId: string,\n attrs: { src: string; alt: string },\n): void {\n const target = findUploadNode(view, uploadId);\n if (!target) return;\n const node = view.state.doc.nodeAt(target.pos);\n if (!node) return;\n const tr = view.state.tr.setNodeMarkup(target.pos, undefined, {\n ...node.attrs,\n src: attrs.src,\n alt: attrs.alt,\n uploadId: null,\n });\n view.dispatch(tr);\n}\n\n/** Remove a placeholder whose upload failed. */\nfunction removeUploadNode(view: EditorView, uploadId: string): void {\n const target = findUploadNode(view, uploadId);\n if (!target) return;\n const tr = view.state.tr.delete(target.pos, target.pos + target.nodeSize);\n view.dispatch(tr);\n}\n\n/**\n * The SHARED block-level image node. Built on `@tiptap/extension-image` (a\n * node named `image`), so:\n *\n * - **GFM serialization** emits pure `![alt](src)` markdown via a block-aware\n * `addStorage().markdown.serialize` (it calls `closeBlock` so a block image\n * keeps its blank-line separator, byte-stable). It emits NO `<img width>`\n * HTML, so plans stay source-syncable under the GFM `html:false` contract.\n * - **Paste / drop** of local image files is handled by a self-contained\n * ProseMirror plugin that calls the injected {@link ImageUploadFn}. Pasting\n * an image URL or `![](url)` markdown works through the base node's input\n * rules even when no uploader is supplied.\n *\n * The node adds one transient `uploadId` attribute (never parsed/rendered to\n * HTML, never serialized to markdown) used to track an in-flight upload.\n *\n * Content keeps its own richer `ImageNode` (Assets picker, AI alt-text, resize,\n * NFM `{color}` serialization) and does NOT use this shared node — both nodes\n * are named `image` but never coexist in the same editor because Content leaves\n * `features.image` off and injects its own via `extraExtensions`.\n */\nexport const SharedImage = Image.extend<SharedImageOptions>({\n // Block-level atom (Content's image is also a block atom). The base extension\n // is block when `inline:false`.\n inline: false,\n group: \"block\",\n\n addOptions() {\n return {\n ...this.parent?.(),\n onImageUpload: null,\n };\n },\n\n addAttributes() {\n return {\n ...this.parent?.(),\n // Transient: marks an in-flight upload so the plugin can patch `src` on\n // resolve. Never written to HTML or markdown.\n uploadId: {\n default: null,\n parseHTML: () => null,\n renderHTML: () => ({}),\n },\n };\n },\n\n addStorage() {\n return {\n ...this.parent?.(),\n // A BLOCK-aware markdown serializer. tiptap-markdown's built-in fallback\n // for the `image` node is prosemirror-markdown's INLINE image serializer,\n // which omits the trailing block separator — so an image immediately\n // followed by a paragraph loses its blank line on round-trip. This\n // node-level spec (merged OVER the fallback by tiptap-markdown's\n // `getMarkdownSpec`) emits the same pure `![alt](src)` markdown but calls\n // `closeBlock`, so a block image stays byte-stable and source-syncable.\n // No `<img width>` / HTML is emitted, so the GFM `html:false` contract and\n // the plan round-trip corpus are preserved.\n markdown: {\n serialize(\n state: {\n esc: (s: string) => string;\n write: (s: string) => void;\n closeBlock: (n: unknown) => void;\n },\n node: { attrs: { src?: string; alt?: string; title?: string } },\n ) {\n const src = node.attrs.src ?? \"\";\n const alt = node.attrs.alt ?? \"\";\n const title = node.attrs.title ?? \"\";\n const titleSuffix = title ? ` \"${title.replace(/\"/g, '\\\\\"')}\"` : \"\";\n state.write(`![${state.esc(alt)}](${state.esc(src)}${titleSuffix})`);\n state.closeBlock(node);\n },\n parse: {\n // Parsing `![alt](src)` is handled by markdown-it + the base node's\n // markdown input rule.\n },\n },\n };\n },\n\n addProseMirrorPlugins() {\n const upload = this.options.onImageUpload;\n const parentPlugins = this.parent?.() ?? [];\n if (!upload) return parentPlugins;\n\n return [\n ...parentPlugins,\n new Plugin({\n key: sharedImageUploadPluginKey,\n props: {\n handlePaste(view, event) {\n const files = imageFilesFrom(event.clipboardData);\n if (files.length === 0) return false;\n event.preventDefault();\n uploadAndInsertImages(\n view,\n files,\n view.state.selection.from,\n upload,\n );\n return true;\n },\n handleDrop(view, event) {\n const files = imageFilesFrom(event.dataTransfer);\n if (files.length === 0) return false;\n event.preventDefault();\n const coords = view.posAtCoords({\n left: event.clientX,\n top: event.clientY,\n });\n const pos = coords?.pos ?? view.state.selection.from;\n uploadAndInsertImages(view, files, pos, upload);\n return true;\n },\n },\n }),\n ];\n },\n});\n\n/**\n * Build the shared image extension, optionally wired with an app uploader.\n *\n * @example\n * createImageExtension({ onImageUpload: uploadEditorImage })\n */\nexport function createImageExtension(\n options: { onImageUpload?: ImageUploadFn | null } = {},\n) {\n return SharedImage.configure({\n onImageUpload: options.onImageUpload ?? null,\n HTMLAttributes: { class: \"an-rich-md-image\" },\n });\n}\n\n/**\n * Open a native file picker, then upload + insert the chosen image(s) through\n * the same flow as paste/drop. Used by the `/image` slash command.\n */\nexport function pickAndInsertImage(\n view: EditorView,\n upload: ImageUploadFn,\n): void {\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = \"image/*\";\n input.multiple = true;\n input.style.display = \"none\";\n input.addEventListener(\"change\", () => {\n const files = Array.from(input.files ?? []).filter((file) =>\n file.type.startsWith(\"image/\"),\n );\n input.remove();\n if (files.length === 0) return;\n uploadAndInsertImages(view, files, view.state.selection.from, upload);\n });\n document.body.appendChild(input);\n input.click();\n}\n"]}
@@ -0,0 +1,97 @@
1
+ import { type ReactNode } from "react";
2
+ import { Node, type NodeViewProps } from "@tiptap/react";
3
+ /** The minimal block shape the NodeView renders through `<BlockView>`. */
4
+ export interface RegistryBlockSideMapBlock {
5
+ id: string;
6
+ title?: string;
7
+ summary?: string;
8
+ data: unknown;
9
+ }
10
+ /**
11
+ * The side-map an editor host supplies so the registry NodeView can resolve a
12
+ * block's full typed `data` (and commit edits) by its stable id, without ever
13
+ * storing that data in the ProseMirror doc.
14
+ */
15
+ export interface RegistryBlockDataValue<TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock> {
16
+ /** Resolve a block's full record (incl. `data`) by its stable id. */
17
+ getBlock: (blockId: string) => TBlock | undefined;
18
+ /** Commit a new `data` value for a block (edit-mode only). */
19
+ onBlockDataChange: (blockId: string, nextData: unknown) => void;
20
+ /** Whether the document (and thus its blocks) is editable. */
21
+ editable: boolean;
22
+ /**
23
+ * When true, blocks whose type has no Notion (NFM) analog are badged so the
24
+ * author knows they won't sync. The host decides which types are incompatible
25
+ * via {@link isNotionIncompatibleType}; this flag just toggles the badge on.
26
+ */
27
+ notionSync?: boolean;
28
+ /**
29
+ * Decide whether a block type is Notion-incompatible (no NFM analog). Only
30
+ * consulted when {@link notionSync} is true. Injected by the host so the
31
+ * single registry-level allowlist (plan's `isNotionCompatibleBlockType`, or
32
+ * content's registry-derived gate) drives the badge — core stays policy-free.
33
+ */
34
+ isNotionIncompatibleType?: (blockType: string) => boolean;
35
+ /**
36
+ * Render a block whose type is NOT in the registry through the host's own
37
+ * dispatcher (plan: `PlanBlockView` for decision / legacy visual-questions /
38
+ * image; omitted in hosts with no legacy types), so every block type renders
39
+ * in the document instead of a bare fallback.
40
+ */
41
+ renderLegacyBlock?: (block: TBlock, options: {
42
+ editing: boolean;
43
+ }) => ReactNode;
44
+ }
45
+ export declare function RegistryBlockDataProvider<TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock>({ value, children, }: {
46
+ value: RegistryBlockDataValue<TBlock>;
47
+ children: ReactNode;
48
+ }): import("react/jsx-runtime").JSX.Element;
49
+ /** Read the registry block side-map. Returns `null` outside a provider. */
50
+ export declare function useRegistryBlockData<TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock>(): RegistryBlockDataValue<TBlock> | null;
51
+ /**
52
+ * Renders one registry-block atom. The block is non-editable as far as
53
+ * ProseMirror is concerned (`contentEditable={false}`); all interaction happens
54
+ * inside the registry-driven `<BlockView>`. Read vs edit is toggled by
55
+ * `props.selected` (the node is "selected" in the editor) AND the document being
56
+ * editable. `data-plan-interactive` keeps existing host click-guards from
57
+ * treating clicks inside the block as document clicks.
58
+ */
59
+ export declare function RegistryBlockNodeView(props: NodeViewProps): import("react/jsx-runtime").JSX.Element;
60
+ /** Options for {@link createRegistryBlockNode}. */
61
+ export interface CreateRegistryBlockNodeOptions {
62
+ /**
63
+ * The Tiptap node name (e.g. `"planBlock"`). Hosts that serialize the doc by
64
+ * node name (plan's `plan-doc.ts` keys off `"planBlock"`) must pass the exact
65
+ * name their serializer expects.
66
+ */
67
+ nodeName: string;
68
+ /**
69
+ * The HTML data-attribute that marks a serialized registry block on copy/paste
70
+ * round-trip (e.g. `"data-plan-block"`).
71
+ */
72
+ dataTag: string;
73
+ /**
74
+ * Mint a fresh, unique block id for a given block type. Used by the dedupe
75
+ * plugin to re-mint duplicate / missing ids (paste/duplicate). Plan passes
76
+ * `createPlanBlockId`.
77
+ */
78
+ mintId: (blockType: string) => string;
79
+ /** Node group (default `"block"`). */
80
+ group?: string;
81
+ }
82
+ /**
83
+ * Build the generic registry-block Tiptap atom node. Returns a Tiptap `Node`
84
+ * that:
85
+ * - carries identity attrs `blockType` / `blockId` / `title` / `summary`, a
86
+ * `sourceBlockId` (set when a duplicate is re-minted, so the host can copy the
87
+ * original block's data), and an optional `__raw` verbatim-MDX attr for
88
+ * byte-stable source round-trips;
89
+ * - is an atom + isolating + draggable block that renders through
90
+ * {@link RegistryBlockNodeView} (via `ReactNodeViewRenderer`);
91
+ * - installs a dedupe `appendTransaction` plugin that re-mints any duplicate or
92
+ * empty `blockId` (the classic paste/duplicate case), preserving the original
93
+ * block's id + side-map data and tagging its own transaction so it never
94
+ * loops.
95
+ */
96
+ export declare function createRegistryBlockNode(options: CreateRegistryBlockNodeOptions): Node<any, any>;
97
+ //# sourceMappingURL=RegistryBlockNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegistryBlockNode.d.ts","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/RegistryBlockNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,EACL,IAAI,EAIJ,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AAuBvB,0EAA0E;AAC1E,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB,CACrC,MAAM,SAAS,yBAAyB,GAAG,yBAAyB;IAEpE,qEAAqE;IACrE,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAClD,8DAA8D;IAC9D,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAChE,8DAA8D;IAC9D,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1D;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,KAC1B,SAAS,CAAC;CAChB;AAKD,wBAAgB,yBAAyB,CACvC,MAAM,SAAS,yBAAyB,GAAG,yBAAyB,EACpE,EACA,KAAK,EACL,QAAQ,GACT,EAAE;IACD,KAAK,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC;IACtC,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAMA;AAED,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAClC,MAAM,SAAS,yBAAyB,GAAG,yBAAyB,KACjE,sBAAsB,CAAC,MAAM,CAAC,GAAG,IAAI,CAIzC;AAMD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,aAAa,2CA2FzD;AAMD,mDAAmD;AACnD,MAAM,WAAW,8BAA8B;IAC7C;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,8BAA8B,kBAyJxC"}
@@ -0,0 +1,214 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ import { Node, NodeViewWrapper, ReactNodeViewRenderer, mergeAttributes, } from "@tiptap/react";
4
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
5
+ import { BlockView, useOptionalBlockRegistry } from "../blocks/index.js";
6
+ const RegistryBlockDataContext = createContext(null);
7
+ export function RegistryBlockDataProvider({ value, children, }) {
8
+ return (_jsx(RegistryBlockDataContext.Provider, { value: value, children: children }));
9
+ }
10
+ /** Read the registry block side-map. Returns `null` outside a provider. */
11
+ export function useRegistryBlockData() {
12
+ return useContext(RegistryBlockDataContext);
13
+ }
14
+ /* -------------------------------------------------------------------------- */
15
+ /* B. RegistryBlockNodeView (React) */
16
+ /* -------------------------------------------------------------------------- */
17
+ /**
18
+ * Renders one registry-block atom. The block is non-editable as far as
19
+ * ProseMirror is concerned (`contentEditable={false}`); all interaction happens
20
+ * inside the registry-driven `<BlockView>`. Read vs edit is toggled by
21
+ * `props.selected` (the node is "selected" in the editor) AND the document being
22
+ * editable. `data-plan-interactive` keeps existing host click-guards from
23
+ * treating clicks inside the block as document clicks.
24
+ */
25
+ export function RegistryBlockNodeView(props) {
26
+ const blockType = String(props.node.attrs.blockType ?? "");
27
+ const blockId = String(props.node.attrs.blockId ?? "");
28
+ const registryValue = useOptionalBlockRegistry();
29
+ const sideMap = useRegistryBlockData();
30
+ const block = sideMap?.getBlock(blockId);
31
+ const editable = sideMap?.editable ?? false;
32
+ const editing = editable && props.selected;
33
+ // In Notion-sync mode, flag blocks that have no Notion (NFM) analog so the
34
+ // author sees what won't push. Prose blocks aren't registry-block nodes, so
35
+ // this only ever covers structured blocks.
36
+ const incompatibleWithNotion = (sideMap?.notionSync ?? false) &&
37
+ (sideMap?.isNotionIncompatibleType?.(blockType) ?? false);
38
+ // The block data isn't in the side-map yet (e.g. a freshly inserted node whose
39
+ // store entry hasn't been seeded). Render a graceful placeholder.
40
+ if (!block) {
41
+ return (_jsx(NodeViewWrapper, { className: "plan-block-node", "data-block-id": blockId, children: _jsx("div", { contentEditable: false, "data-plan-interactive": true, className: "plan-block-node__placeholder rounded-md border border-dashed border-border px-3 py-2 text-sm text-muted-foreground", children: blockType ? `Loading ${blockType} block…` : "Loading block…" }) }));
42
+ }
43
+ const spec = registryValue?.registry.get(blockType);
44
+ // Choose how to render the block body:
45
+ // 1. Registered spec → the registry `BlockView` (Read, or the spec Edit /
46
+ // auto-form when selected). This is the common path (callout, table,
47
+ // code-tabs, wireframe, …).
48
+ // 2. No spec, but the side-map provides `renderLegacyBlock` → delegate to the
49
+ // host's dispatcher (decision, legacy visual-questions, image, and any
50
+ // other type rendered by a bespoke component rather than the registry), so
51
+ // EVERY block type renders in the document exactly as it does in the
52
+ // per-block reader — never a bare title fallback.
53
+ // 3. Neither → a small non-crashing fallback.
54
+ let body;
55
+ if (registryValue && spec) {
56
+ body = (_jsx(BlockView, { spec: spec, block: {
57
+ id: block.id,
58
+ title: block.title,
59
+ summary: block.summary,
60
+ data: block.data,
61
+ }, editing: editing, editable: editable, onChange: (nextData) => sideMap?.onBlockDataChange(blockId, nextData), ctx: registryValue.ctx }));
62
+ }
63
+ else if (sideMap?.renderLegacyBlock) {
64
+ body = sideMap.renderLegacyBlock(block, { editing });
65
+ }
66
+ else {
67
+ body = (_jsx("div", { className: "plan-block-node__fallback rounded-md border border-border px-3 py-2 text-sm text-muted-foreground", children: block.title || blockType || "Unsupported block" }));
68
+ }
69
+ return (_jsx(NodeViewWrapper, { className: "plan-block-node", "data-block-id": blockId, "data-notion-incompatible": incompatibleWithNotion ? "" : undefined, children: _jsxs("div", { contentEditable: false, "data-plan-interactive": true, children: [incompatibleWithNotion && (_jsx("span", { className: "plan-block-notion-badge", title: "This block type has no Notion equivalent and won't sync to Notion.", children: "Won't sync to Notion" })), body] }) }));
70
+ }
71
+ /**
72
+ * Build the generic registry-block Tiptap atom node. Returns a Tiptap `Node`
73
+ * that:
74
+ * - carries identity attrs `blockType` / `blockId` / `title` / `summary`, a
75
+ * `sourceBlockId` (set when a duplicate is re-minted, so the host can copy the
76
+ * original block's data), and an optional `__raw` verbatim-MDX attr for
77
+ * byte-stable source round-trips;
78
+ * - is an atom + isolating + draggable block that renders through
79
+ * {@link RegistryBlockNodeView} (via `ReactNodeViewRenderer`);
80
+ * - installs a dedupe `appendTransaction` plugin that re-mints any duplicate or
81
+ * empty `blockId` (the classic paste/duplicate case), preserving the original
82
+ * block's id + side-map data and tagging its own transaction so it never
83
+ * loops.
84
+ */
85
+ export function createRegistryBlockNode(options) {
86
+ const { nodeName, dataTag, mintId, group = "block" } = options;
87
+ const dedupeKey = new PluginKey(`${nodeName}DedupeIds`);
88
+ /**
89
+ * Collect every `blockId` currently present on this node type in a doc, with
90
+ * the position of each node, so duplicate ids (from paste/duplicate) can be
91
+ * detected and re-minted.
92
+ */
93
+ function collectEntries(state) {
94
+ const found = [];
95
+ state.doc.descendants((node, pos) => {
96
+ if (node.type.name === nodeName) {
97
+ found.push({
98
+ pos,
99
+ blockType: String(node.attrs.blockType ?? ""),
100
+ blockId: String(node.attrs.blockId ?? ""),
101
+ sourceBlockId: typeof node.attrs.sourceBlockId === "string"
102
+ ? node.attrs.sourceBlockId
103
+ : undefined,
104
+ });
105
+ }
106
+ return true;
107
+ });
108
+ return found;
109
+ }
110
+ /**
111
+ * Build a transaction that re-mints any duplicate / missing ids in `state`, or
112
+ * `null` when nothing needs changing. Only the *later* duplicate (and any node
113
+ * with an empty id) is re-minted, so the original keeps its id and side-map
114
+ * data.
115
+ */
116
+ function buildDedupeTransaction(state) {
117
+ const entries = collectEntries(state);
118
+ if (entries.length === 0)
119
+ return null;
120
+ const seen = new Set();
121
+ let tr = state.tr;
122
+ let changed = false;
123
+ for (const entry of entries) {
124
+ const needsNewId = !entry.blockId || seen.has(entry.blockId);
125
+ if (needsNewId) {
126
+ const freshId = mintId(entry.blockType || "block");
127
+ const node = state.doc.nodeAt(entry.pos);
128
+ if (node) {
129
+ tr = tr.setNodeMarkup(entry.pos, undefined, {
130
+ ...node.attrs,
131
+ blockId: freshId,
132
+ sourceBlockId: entry.sourceBlockId || entry.blockId || null,
133
+ });
134
+ changed = true;
135
+ }
136
+ seen.add(freshId);
137
+ }
138
+ else {
139
+ seen.add(entry.blockId);
140
+ }
141
+ }
142
+ return changed ? tr.setMeta(dedupeKey, true) : null;
143
+ }
144
+ return Node.create({
145
+ name: nodeName,
146
+ group,
147
+ atom: true,
148
+ draggable: true,
149
+ selectable: true,
150
+ isolating: true,
151
+ addAttributes() {
152
+ return {
153
+ blockType: { default: "" },
154
+ blockId: { default: "" },
155
+ title: { default: null },
156
+ summary: { default: null },
157
+ sourceBlockId: { default: null },
158
+ // Optional verbatim source for hosts that need byte-identical
159
+ // source-format round-trips without React (server pull, hashing). Plan
160
+ // never sets this.
161
+ __raw: { default: null, rendered: false },
162
+ };
163
+ },
164
+ parseHTML() {
165
+ return [
166
+ {
167
+ tag: `div[${dataTag}]`,
168
+ getAttrs: (element) => {
169
+ const node = element;
170
+ return {
171
+ blockType: node.getAttribute("data-block-type") || "",
172
+ blockId: node.getAttribute("data-block-id") || "",
173
+ title: node.getAttribute("data-title") || null,
174
+ summary: node.getAttribute("data-summary") || null,
175
+ sourceBlockId: node.getAttribute("data-source-block-id") || null,
176
+ };
177
+ },
178
+ },
179
+ ];
180
+ },
181
+ renderHTML({ HTMLAttributes }) {
182
+ return [
183
+ "div",
184
+ mergeAttributes(HTMLAttributes, {
185
+ [dataTag]: "",
186
+ "data-block-type": HTMLAttributes.blockType ?? "",
187
+ "data-block-id": HTMLAttributes.blockId ?? "",
188
+ "data-title": HTMLAttributes.title ?? undefined,
189
+ "data-summary": HTMLAttributes.summary ?? undefined,
190
+ "data-source-block-id": HTMLAttributes.sourceBlockId ?? undefined,
191
+ }),
192
+ ];
193
+ },
194
+ addNodeView() {
195
+ return ReactNodeViewRenderer(RegistryBlockNodeView);
196
+ },
197
+ addProseMirrorPlugins() {
198
+ return [
199
+ new Plugin({
200
+ key: dedupeKey,
201
+ appendTransaction(transactions, _oldState, newState) {
202
+ // Ignore our own re-mint, and skip when nothing changed the doc.
203
+ if (transactions.some((transaction) => transaction.getMeta(dedupeKey)) ||
204
+ !transactions.some((transaction) => transaction.docChanged)) {
205
+ return null;
206
+ }
207
+ return buildDedupeTransaction(newState);
208
+ },
209
+ }),
210
+ ];
211
+ },
212
+ });
213
+ }
214
+ //# sourceMappingURL=RegistryBlockNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegistryBlockNode.js","sourceRoot":"","sources":["../../../src/client/rich-markdown-editor/RegistryBlockNode.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, type ReactNode } from \"react\";\nimport {\n Node,\n NodeViewWrapper,\n ReactNodeViewRenderer,\n mergeAttributes,\n type NodeViewProps,\n} from \"@tiptap/react\";\nimport { Plugin, PluginKey, type EditorState } from \"@tiptap/pm/state\";\nimport { BlockView, useOptionalBlockRegistry } from \"../blocks/index.js\";\n\n/* -------------------------------------------------------------------------- */\n/* The generic registry-block side-map + Tiptap NodeView, lifted into core. */\n/* */\n/* This is the app-agnostic NodeView that renders registered block specs */\n/* inside a `SharedRichEditor` document. Hosts mount the node produced by */\n/* {@link createRegistryBlockNode} as an extra extension and wrap the editor */\n/* in a {@link RegistryBlockDataProvider}, sourcing the typed block `data` */\n/* from their own authoritative store (for example, PlanContent.blocks). The */\n/* node itself carries only lightweight identity attrs (type/id/title/summary) */\n/* plus an optional `__raw` verbatim-MDX attr for byte-stable source */\n/* round-trips; the heavy typed `data` is threaded through the side-map */\n/* context, keeping the doc small and the block data the single source of */\n/* truth. */\n/* -------------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------------- */\n/* C. Block-data side-map context */\n/* -------------------------------------------------------------------------- */\n\n/** The minimal block shape the NodeView renders through `<BlockView>`. */\nexport interface RegistryBlockSideMapBlock {\n id: string;\n title?: string;\n summary?: string;\n data: unknown;\n}\n\n/**\n * The side-map an editor host supplies so the registry NodeView can resolve a\n * block's full typed `data` (and commit edits) by its stable id, without ever\n * storing that data in the ProseMirror doc.\n */\nexport interface RegistryBlockDataValue<\n TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock,\n> {\n /** Resolve a block's full record (incl. `data`) by its stable id. */\n getBlock: (blockId: string) => TBlock | undefined;\n /** Commit a new `data` value for a block (edit-mode only). */\n onBlockDataChange: (blockId: string, nextData: unknown) => void;\n /** Whether the document (and thus its blocks) is editable. */\n editable: boolean;\n /**\n * When true, blocks whose type has no Notion (NFM) analog are badged so the\n * author knows they won't sync. The host decides which types are incompatible\n * via {@link isNotionIncompatibleType}; this flag just toggles the badge on.\n */\n notionSync?: boolean;\n /**\n * Decide whether a block type is Notion-incompatible (no NFM analog). Only\n * consulted when {@link notionSync} is true. Injected by the host so the\n * single registry-level allowlist (plan's `isNotionCompatibleBlockType`, or\n * content's registry-derived gate) drives the badge — core stays policy-free.\n */\n isNotionIncompatibleType?: (blockType: string) => boolean;\n /**\n * Render a block whose type is NOT in the registry through the host's own\n * dispatcher (plan: `PlanBlockView` for decision / legacy visual-questions /\n * image; omitted in hosts with no legacy types), so every block type renders\n * in the document instead of a bare fallback.\n */\n renderLegacyBlock?: (\n block: TBlock,\n options: { editing: boolean },\n ) => ReactNode;\n}\n\nconst RegistryBlockDataContext =\n createContext<RegistryBlockDataValue<any> | null>(null);\n\nexport function RegistryBlockDataProvider<\n TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock,\n>({\n value,\n children,\n}: {\n value: RegistryBlockDataValue<TBlock>;\n children: ReactNode;\n}) {\n return (\n <RegistryBlockDataContext.Provider value={value}>\n {children}\n </RegistryBlockDataContext.Provider>\n );\n}\n\n/** Read the registry block side-map. Returns `null` outside a provider. */\nexport function useRegistryBlockData<\n TBlock extends RegistryBlockSideMapBlock = RegistryBlockSideMapBlock,\n>(): RegistryBlockDataValue<TBlock> | null {\n return useContext(\n RegistryBlockDataContext,\n ) as RegistryBlockDataValue<TBlock> | null;\n}\n\n/* -------------------------------------------------------------------------- */\n/* B. RegistryBlockNodeView (React) */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Renders one registry-block atom. The block is non-editable as far as\n * ProseMirror is concerned (`contentEditable={false}`); all interaction happens\n * inside the registry-driven `<BlockView>`. Read vs edit is toggled by\n * `props.selected` (the node is \"selected\" in the editor) AND the document being\n * editable. `data-plan-interactive` keeps existing host click-guards from\n * treating clicks inside the block as document clicks.\n */\nexport function RegistryBlockNodeView(props: NodeViewProps) {\n const blockType = String(props.node.attrs.blockType ?? \"\");\n const blockId = String(props.node.attrs.blockId ?? \"\");\n\n const registryValue = useOptionalBlockRegistry();\n const sideMap = useRegistryBlockData();\n\n const block = sideMap?.getBlock(blockId);\n const editable = sideMap?.editable ?? false;\n const editing = editable && props.selected;\n // In Notion-sync mode, flag blocks that have no Notion (NFM) analog so the\n // author sees what won't push. Prose blocks aren't registry-block nodes, so\n // this only ever covers structured blocks.\n const incompatibleWithNotion =\n (sideMap?.notionSync ?? false) &&\n (sideMap?.isNotionIncompatibleType?.(blockType) ?? false);\n\n // The block data isn't in the side-map yet (e.g. a freshly inserted node whose\n // store entry hasn't been seeded). Render a graceful placeholder.\n if (!block) {\n return (\n <NodeViewWrapper className=\"plan-block-node\" data-block-id={blockId}>\n <div\n contentEditable={false}\n data-plan-interactive\n className=\"plan-block-node__placeholder rounded-md border border-dashed border-border px-3 py-2 text-sm text-muted-foreground\"\n >\n {blockType ? `Loading ${blockType} block…` : \"Loading block…\"}\n </div>\n </NodeViewWrapper>\n );\n }\n\n const spec = registryValue?.registry.get(blockType);\n\n // Choose how to render the block body:\n // 1. Registered spec → the registry `BlockView` (Read, or the spec Edit /\n // auto-form when selected). This is the common path (callout, table,\n // code-tabs, wireframe, …).\n // 2. No spec, but the side-map provides `renderLegacyBlock` → delegate to the\n // host's dispatcher (decision, legacy visual-questions, image, and any\n // other type rendered by a bespoke component rather than the registry), so\n // EVERY block type renders in the document exactly as it does in the\n // per-block reader — never a bare title fallback.\n // 3. Neither → a small non-crashing fallback.\n let body: ReactNode;\n if (registryValue && spec) {\n body = (\n <BlockView\n spec={spec}\n block={{\n id: block.id,\n title: block.title,\n summary: block.summary,\n data: (block as { data: unknown }).data,\n }}\n editing={editing}\n editable={editable}\n onChange={(nextData) => sideMap?.onBlockDataChange(blockId, nextData)}\n ctx={registryValue.ctx}\n />\n );\n } else if (sideMap?.renderLegacyBlock) {\n body = sideMap.renderLegacyBlock(block, { editing });\n } else {\n body = (\n <div className=\"plan-block-node__fallback rounded-md border border-border px-3 py-2 text-sm text-muted-foreground\">\n {block.title || blockType || \"Unsupported block\"}\n </div>\n );\n }\n\n return (\n <NodeViewWrapper\n className=\"plan-block-node\"\n data-block-id={blockId}\n data-notion-incompatible={incompatibleWithNotion ? \"\" : undefined}\n >\n <div contentEditable={false} data-plan-interactive>\n {incompatibleWithNotion && (\n <span\n className=\"plan-block-notion-badge\"\n title=\"This block type has no Notion equivalent and won't sync to Notion.\"\n >\n Won't sync to Notion\n </span>\n )}\n {body}\n </div>\n </NodeViewWrapper>\n );\n}\n\n/* -------------------------------------------------------------------------- */\n/* A. registry-block Tiptap node factory */\n/* -------------------------------------------------------------------------- */\n\n/** Options for {@link createRegistryBlockNode}. */\nexport interface CreateRegistryBlockNodeOptions {\n /**\n * The Tiptap node name (e.g. `\"planBlock\"`). Hosts that serialize the doc by\n * node name (plan's `plan-doc.ts` keys off `\"planBlock\"`) must pass the exact\n * name their serializer expects.\n */\n nodeName: string;\n /**\n * The HTML data-attribute that marks a serialized registry block on copy/paste\n * round-trip (e.g. `\"data-plan-block\"`).\n */\n dataTag: string;\n /**\n * Mint a fresh, unique block id for a given block type. Used by the dedupe\n * plugin to re-mint duplicate / missing ids (paste/duplicate). Plan passes\n * `createPlanBlockId`.\n */\n mintId: (blockType: string) => string;\n /** Node group (default `\"block\"`). */\n group?: string;\n}\n\n/**\n * Build the generic registry-block Tiptap atom node. Returns a Tiptap `Node`\n * that:\n * - carries identity attrs `blockType` / `blockId` / `title` / `summary`, a\n * `sourceBlockId` (set when a duplicate is re-minted, so the host can copy the\n * original block's data), and an optional `__raw` verbatim-MDX attr for\n * byte-stable source round-trips;\n * - is an atom + isolating + draggable block that renders through\n * {@link RegistryBlockNodeView} (via `ReactNodeViewRenderer`);\n * - installs a dedupe `appendTransaction` plugin that re-mints any duplicate or\n * empty `blockId` (the classic paste/duplicate case), preserving the original\n * block's id + side-map data and tagging its own transaction so it never\n * loops.\n */\nexport function createRegistryBlockNode(\n options: CreateRegistryBlockNodeOptions,\n) {\n const { nodeName, dataTag, mintId, group = \"block\" } = options;\n const dedupeKey = new PluginKey(`${nodeName}DedupeIds`);\n\n /**\n * Collect every `blockId` currently present on this node type in a doc, with\n * the position of each node, so duplicate ids (from paste/duplicate) can be\n * detected and re-minted.\n */\n function collectEntries(state: EditorState): Array<{\n pos: number;\n blockType: string;\n blockId: string;\n sourceBlockId?: string;\n }> {\n const found: Array<{\n pos: number;\n blockType: string;\n blockId: string;\n sourceBlockId?: string;\n }> = [];\n state.doc.descendants((node, pos) => {\n if (node.type.name === nodeName) {\n found.push({\n pos,\n blockType: String(node.attrs.blockType ?? \"\"),\n blockId: String(node.attrs.blockId ?? \"\"),\n sourceBlockId:\n typeof node.attrs.sourceBlockId === \"string\"\n ? node.attrs.sourceBlockId\n : undefined,\n });\n }\n return true;\n });\n return found;\n }\n\n /**\n * Build a transaction that re-mints any duplicate / missing ids in `state`, or\n * `null` when nothing needs changing. Only the *later* duplicate (and any node\n * with an empty id) is re-minted, so the original keeps its id and side-map\n * data.\n */\n function buildDedupeTransaction(state: EditorState) {\n const entries = collectEntries(state);\n if (entries.length === 0) return null;\n\n const seen = new Set<string>();\n let tr = state.tr;\n let changed = false;\n\n for (const entry of entries) {\n const needsNewId = !entry.blockId || seen.has(entry.blockId);\n if (needsNewId) {\n const freshId = mintId(entry.blockType || \"block\");\n const node = state.doc.nodeAt(entry.pos);\n if (node) {\n tr = tr.setNodeMarkup(entry.pos, undefined, {\n ...node.attrs,\n blockId: freshId,\n sourceBlockId: entry.sourceBlockId || entry.blockId || null,\n });\n changed = true;\n }\n seen.add(freshId);\n } else {\n seen.add(entry.blockId);\n }\n }\n\n return changed ? tr.setMeta(dedupeKey, true) : null;\n }\n\n return Node.create({\n name: nodeName,\n group,\n atom: true,\n draggable: true,\n selectable: true,\n isolating: true,\n\n addAttributes() {\n return {\n blockType: { default: \"\" },\n blockId: { default: \"\" },\n title: { default: null },\n summary: { default: null },\n sourceBlockId: { default: null },\n // Optional verbatim source for hosts that need byte-identical\n // source-format round-trips without React (server pull, hashing). Plan\n // never sets this.\n __raw: { default: null, rendered: false },\n };\n },\n\n parseHTML() {\n return [\n {\n tag: `div[${dataTag}]`,\n getAttrs: (element) => {\n const node = element as HTMLElement;\n return {\n blockType: node.getAttribute(\"data-block-type\") || \"\",\n blockId: node.getAttribute(\"data-block-id\") || \"\",\n title: node.getAttribute(\"data-title\") || null,\n summary: node.getAttribute(\"data-summary\") || null,\n sourceBlockId: node.getAttribute(\"data-source-block-id\") || null,\n };\n },\n },\n ];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n \"div\",\n mergeAttributes(HTMLAttributes, {\n [dataTag]: \"\",\n \"data-block-type\": HTMLAttributes.blockType ?? \"\",\n \"data-block-id\": HTMLAttributes.blockId ?? \"\",\n \"data-title\": HTMLAttributes.title ?? undefined,\n \"data-summary\": HTMLAttributes.summary ?? undefined,\n \"data-source-block-id\": HTMLAttributes.sourceBlockId ?? undefined,\n }),\n ];\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(RegistryBlockNodeView);\n },\n\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: dedupeKey,\n appendTransaction(transactions, _oldState, newState) {\n // Ignore our own re-mint, and skip when nothing changed the doc.\n if (\n transactions.some((transaction) =>\n transaction.getMeta(dedupeKey),\n ) ||\n !transactions.some((transaction) => transaction.docChanged)\n ) {\n return null;\n }\n return buildDedupeTransaction(newState);\n },\n }),\n ];\n },\n });\n}\n"]}