@invect/ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/dist/Invect-CWpIwZ5F.js +92738 -0
  4. package/dist/Invect.d.ts +25 -0
  5. package/dist/InvectShell.d.ts +14 -0
  6. package/dist/api/agent-tools.api.d.ts +1 -0
  7. package/dist/api/client.d.ts +207 -0
  8. package/dist/api/credentials.api.d.ts +47 -0
  9. package/dist/api/executions.api.d.ts +43 -0
  10. package/dist/api/flows.api.d.ts +100 -0
  11. package/dist/api/index.d.ts +9 -0
  12. package/dist/api/node-data.api.d.ts +66 -0
  13. package/dist/api/query-keys.d.ts +22 -0
  14. package/dist/api/triggers.api.d.ts +44 -0
  15. package/dist/api/types.d.ts +147 -0
  16. package/dist/api/use-flow-run-stream.d.ts +12 -0
  17. package/dist/assets/invect-branding.d.ts +4 -0
  18. package/dist/assets/provider-icons/index.d.ts +8 -0
  19. package/dist/babel-C9OtljFZ.js +9721 -0
  20. package/dist/components/PageLayout.d.ts +17 -0
  21. package/dist/components/chat/ChatInput.d.ts +17 -0
  22. package/dist/components/chat/ChatMessageList.d.ts +14 -0
  23. package/dist/components/chat/ChatModelSelector.d.ts +11 -0
  24. package/dist/components/chat/ChatPanel.d.ts +19 -0
  25. package/dist/components/chat/ChatPromptOverlay.d.ts +13 -0
  26. package/dist/components/chat/ChatProviderSelector.d.ts +9 -0
  27. package/dist/components/chat/ChatSettingsPanel.d.ts +11 -0
  28. package/dist/components/chat/InlineCredentialSetup.d.ts +9 -0
  29. package/dist/components/chat/MarkdownRenderer.d.ts +7 -0
  30. package/dist/components/chat/chat-memory.d.ts +21 -0
  31. package/dist/components/chat/chat.store.d.ts +416 -0
  32. package/dist/components/chat/index.d.ts +5 -0
  33. package/dist/components/chat/use-chat.d.ts +28 -0
  34. package/dist/components/credentials/CreateCredentialModal.d.ts +13 -0
  35. package/dist/components/credentials/CredentialDetailDialog.d.ts +17 -0
  36. package/dist/components/credentials/EditCredentialModal.d.ts +11 -0
  37. package/dist/components/credentials/OAuth2ConnectButton.d.ts +38 -0
  38. package/dist/components/credentials/OAuth2ProviderSelector.d.ts +15 -0
  39. package/dist/components/credentials/credential-utils.d.ts +12 -0
  40. package/dist/components/credentials/index.d.ts +9 -0
  41. package/dist/components/dashboard/FailedRunsAlert.d.ts +3 -0
  42. package/dist/components/dashboard/FlowCard.d.ts +7 -0
  43. package/dist/components/dashboard/RecentActivityTable.d.ts +9 -0
  44. package/dist/components/dashboard/StatCard.d.ts +10 -0
  45. package/dist/components/dashboard/index.d.ts +5 -0
  46. package/dist/components/dashboard/status-helpers.d.ts +5 -0
  47. package/dist/components/flow-editor/ActionsSidebar.d.ts +2 -0
  48. package/dist/components/flow-editor/FlowEditor.d.ts +21 -0
  49. package/dist/components/flow-editor/FlowHeader.d.ts +9 -0
  50. package/dist/components/flow-editor/FlowLayout.d.ts +24 -0
  51. package/dist/components/flow-editor/ModeSwitcher.d.ts +7 -0
  52. package/dist/components/flow-editor/NodeSidebar.d.ts +24 -0
  53. package/dist/components/flow-editor/RunControls.d.ts +12 -0
  54. package/dist/components/flow-editor/ToolConfigPanel.d.ts +16 -0
  55. package/dist/components/flow-editor/ValidationPanel.d.ts +5 -0
  56. package/dist/components/flow-editor/flow-editor.store.d.ts +1 -0
  57. package/dist/components/flow-editor/index.d.ts +6 -0
  58. package/dist/components/flow-editor/inline-edit.d.ts +10 -0
  59. package/dist/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.d.ts +26 -0
  60. package/dist/components/flow-editor/node-config-panel/CredentialCombobox.d.ts +21 -0
  61. package/dist/components/flow-editor/node-config-panel/CredentialsSection.d.ts +19 -0
  62. package/dist/components/flow-editor/node-config-panel/DroppableInput.d.ts +20 -0
  63. package/dist/components/flow-editor/node-config-panel/DynamicSelectField.d.ts +22 -0
  64. package/dist/components/flow-editor/node-config-panel/JsonPreviewPanel.d.ts +25 -0
  65. package/dist/components/flow-editor/node-config-panel/NodeConfigPanel.d.ts +14 -0
  66. package/dist/components/flow-editor/node-config-panel/NodeConfigPanelHeader.d.ts +15 -0
  67. package/dist/components/flow-editor/node-config-panel/ParametersSection.d.ts +16 -0
  68. package/dist/components/flow-editor/node-config-panel/SearchableSelectField.d.ts +17 -0
  69. package/dist/components/flow-editor/node-config-panel/SwitchCasesField.d.ts +18 -0
  70. package/dist/components/flow-editor/node-config-panel/hooks/index.d.ts +2 -0
  71. package/dist/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.d.ts +24 -0
  72. package/dist/components/flow-editor/node-config-panel/hooks/use-node-execution.d.ts +46 -0
  73. package/dist/components/flow-editor/node-config-panel/hooks/use-upstream-slots.d.ts +16 -0
  74. package/dist/components/flow-editor/node-config-panel/panels/AgentToolsPanel.d.ts +18 -0
  75. package/dist/components/flow-editor/node-config-panel/panels/ConfigurationPanel.d.ts +49 -0
  76. package/dist/components/flow-editor/node-config-panel/panels/DataMapperPane.d.ts +40 -0
  77. package/dist/components/flow-editor/node-config-panel/panels/InputPanel.d.ts +49 -0
  78. package/dist/components/flow-editor/node-config-panel/panels/OutputPanel.d.ts +7 -0
  79. package/dist/components/flow-editor/node-config-panel/panels/index.d.ts +4 -0
  80. package/dist/components/flow-editor/node-config-panel/types.d.ts +19 -0
  81. package/dist/components/flow-editor/node-config-panel/use-node-config-panel-store.d.ts +49 -0
  82. package/dist/components/flow-editor/node-config-panel/use-node-config-state.d.ts +26 -0
  83. package/dist/components/flow-editor/node-config-panel/use-run-node.d.ts +16 -0
  84. package/dist/components/flow-editor/node-config-panel/utils.d.ts +9 -0
  85. package/dist/components/flow-editor/serialize-to-sdk.d.ts +20 -0
  86. package/dist/components/flow-editor/toolbar-context.d.ts +2 -0
  87. package/dist/components/flow-editor/use-copy-paste.d.ts +7 -0
  88. package/dist/components/flow-editor/use-copy-paste.types.d.ts +38 -0
  89. package/dist/components/flow-editor/use-flow-editor.d.ts +44 -0
  90. package/dist/components/flow-runs-table/FlowRunsTable.d.ts +6 -0
  91. package/dist/components/flow-runs-table/index.d.ts +1 -0
  92. package/dist/components/flow-viewer/FlowRunsView.d.ts +7 -0
  93. package/dist/components/flow-viewer/FlowStatusView.d.ts +21 -0
  94. package/dist/components/flow-viewer/RunSelector.d.ts +13 -0
  95. package/dist/components/flow-viewer/RunsSidebar.d.ts +14 -0
  96. package/dist/components/flow-viewer/agent-tool-executions-list.d.ts +7 -0
  97. package/dist/components/flow-viewer/index.d.ts +1 -0
  98. package/dist/components/flow-viewer/logs-panel.d.ts +18 -0
  99. package/dist/components/flow-viewer/use-execution-log-data.d.ts +113 -0
  100. package/dist/components/graph/BatchFlowEdge.d.ts +33 -0
  101. package/dist/components/graph/LayoutSelector.d.ts +9 -0
  102. package/dist/components/graph/index.d.ts +47 -0
  103. package/dist/components/graph/styleUtils.d.ts +124 -0
  104. package/dist/components/nodes/AgentConfigPanel.d.ts +24 -0
  105. package/dist/components/nodes/AgentNode.d.ts +8 -0
  106. package/dist/components/nodes/AgentToolsBox.d.ts +41 -0
  107. package/dist/components/nodes/NodeAppendix.d.ts +19 -0
  108. package/dist/components/nodes/NodeStatusIndicator.d.ts +30 -0
  109. package/dist/components/nodes/NodeViewContext.d.ts +18 -0
  110. package/dist/components/nodes/ToolParamField.d.ts +28 -0
  111. package/dist/components/nodes/ToolSelectorModal.d.ts +80 -0
  112. package/dist/components/nodes/ToolSelectorParts.d.ts +30 -0
  113. package/dist/components/nodes/UniversalNode.d.ts +2 -0
  114. package/dist/components/nodes/createContextAwareNodes.d.ts +6 -0
  115. package/dist/components/nodes/index.d.ts +22 -0
  116. package/dist/components/nodes/nodeRegistry.d.ts +13 -0
  117. package/dist/components/nodes/withNodeContext.d.ts +7 -0
  118. package/dist/components/shared/InvectLoader.d.ts +8 -0
  119. package/dist/components/shared/InvectLogo.d.ts +9 -0
  120. package/dist/components/shared/ProviderIcon.d.ts +23 -0
  121. package/dist/components/side-menu/side-menu.d.ts +4 -0
  122. package/dist/components/sidebar/BaseSidebar.d.ts +17 -0
  123. package/dist/components/sidebar/index.d.ts +1 -0
  124. package/dist/components/triggers/CronPreview.d.ts +12 -0
  125. package/dist/components/triggers/index.d.ts +1 -0
  126. package/dist/components/ui/alert-dialog.d.ts +18 -0
  127. package/dist/components/ui/badge.d.ts +9 -0
  128. package/dist/components/ui/button.d.ts +13 -0
  129. package/dist/components/ui/card.d.ts +9 -0
  130. package/dist/components/ui/codemirror-js-editor.d.ts +25 -0
  131. package/dist/components/ui/codemirror-json-editor.d.ts +18 -0
  132. package/dist/components/ui/codemirror-nunjucks-editor.d.ts +13 -0
  133. package/dist/components/ui/codemirror-vscode-theme.d.ts +24 -0
  134. package/dist/components/ui/collapsible.d.ts +6 -0
  135. package/dist/components/ui/command.d.ts +18 -0
  136. package/dist/components/ui/dialog.d.ts +18 -0
  137. package/dist/components/ui/dropdown-menu.d.ts +25 -0
  138. package/dist/components/ui/empty-state.d.ts +21 -0
  139. package/dist/components/ui/input.d.ts +3 -0
  140. package/dist/components/ui/label.d.ts +4 -0
  141. package/dist/components/ui/popover.d.ts +10 -0
  142. package/dist/components/ui/resizable.d.ts +8 -0
  143. package/dist/components/ui/scroll-area.d.ts +5 -0
  144. package/dist/components/ui/select.d.ts +18 -0
  145. package/dist/components/ui/separator.d.ts +4 -0
  146. package/dist/components/ui/slider.d.ts +4 -0
  147. package/dist/components/ui/switch.d.ts +3 -0
  148. package/dist/components/ui/table.d.ts +10 -0
  149. package/dist/components/ui/textarea.d.ts +3 -0
  150. package/dist/components/ui/tooltip.d.ts +7 -0
  151. package/dist/components/ui/tree-view.d.ts +107 -0
  152. package/dist/contexts/AgentToolCallbacksContext.d.ts +23 -0
  153. package/dist/contexts/ApiContext.d.ts +11 -0
  154. package/dist/contexts/FlowDataContext.d.ts +9 -0
  155. package/dist/contexts/NodeRegistryContext.d.ts +14 -0
  156. package/dist/contexts/PluginRegistryContext.d.ts +39 -0
  157. package/dist/contexts/ThemeProvider.d.ts +18 -0
  158. package/dist/contexts/ValidationContext.d.ts +22 -0
  159. package/dist/demo/DemoInvect.d.ts +11 -0
  160. package/dist/demo/FlowViewer.d.ts +31 -0
  161. package/dist/demo/demo-api-client.d.ts +33 -0
  162. package/dist/demo/index.d.ts +6 -0
  163. package/dist/demo/sample-data.d.ts +1538 -0
  164. package/dist/demo.d.ts +2 -0
  165. package/dist/demo.js +2774 -0
  166. package/dist/estree-ClbRfS-1.js +7076 -0
  167. package/dist/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
  168. package/dist/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
  169. package/dist/fonts/geist-latin-wght-normal.woff2 +0 -0
  170. package/dist/fonts/iosevka-latin-400-normal.woff2 +0 -0
  171. package/dist/hooks/index.d.ts +1 -0
  172. package/dist/hooks/use-document-title.d.ts +1 -0
  173. package/dist/hooks/use-flow-data.d.ts +22 -0
  174. package/dist/hooks/use-invect-portal-class.d.ts +21 -0
  175. package/dist/hooks/useFlowEditorStore.d.ts +1 -0
  176. package/dist/index.css +3 -0
  177. package/dist/index.d.ts +22 -0
  178. package/dist/index.js +717 -0
  179. package/dist/lib/utils.d.ts +2 -0
  180. package/dist/prettier.d.ts +13 -0
  181. package/dist/routes/all-flow-runs.d.ts +5 -0
  182. package/dist/routes/credentials.d.ts +5 -0
  183. package/dist/routes/flow-route-layout.d.ts +19 -0
  184. package/dist/routes/flow-runs.d.ts +5 -0
  185. package/dist/routes/flow.d.ts +5 -0
  186. package/dist/routes/home.d.ts +5 -0
  187. package/dist/services/index.d.ts +1 -0
  188. package/dist/standalone-C3Df7W52.js +3463 -0
  189. package/dist/stores/executionViewStore.d.ts +64 -0
  190. package/dist/stores/flow-editor.store.d.ts +137 -0
  191. package/dist/stores/flowEditorStore.d.ts +1 -0
  192. package/dist/stores/index.d.ts +2 -0
  193. package/dist/stores/uiStore.d.ts +45 -0
  194. package/dist/types/agent-tools.types.d.ts +53 -0
  195. package/dist/types/index.d.ts +2 -0
  196. package/dist/types/node-definition.types.d.ts +85 -0
  197. package/dist/types/plugin.types.d.ts +100 -0
  198. package/dist/utils/credentialBranding.d.ts +8 -0
  199. package/dist/utils/credentialFiltering.d.ts +20 -0
  200. package/dist/utils/flowTransformations.d.ts +16 -0
  201. package/dist/utils/layoutUtils.d.ts +23 -0
  202. package/dist/utils/nodeReferenceUtils.d.ts +37 -0
  203. package/dist/vendor.d.ts +5 -0
  204. package/package.json +130 -0
  205. package/src/.DS_Store +0 -0
  206. package/src/Invect.tsx +229 -0
  207. package/src/InvectShell.tsx +55 -0
  208. package/src/api/agent-tools.api.ts +23 -0
  209. package/src/api/client.ts +899 -0
  210. package/src/api/credentials.api.ts +197 -0
  211. package/src/api/executions.api.ts +228 -0
  212. package/src/api/flows.api.ts +195 -0
  213. package/src/api/index.ts +17 -0
  214. package/src/api/node-data.api.ts +167 -0
  215. package/src/api/query-keys.ts +44 -0
  216. package/src/api/triggers.api.ts +120 -0
  217. package/src/api/types.ts +212 -0
  218. package/src/api/use-flow-run-stream.ts +206 -0
  219. package/src/app.css +560 -0
  220. package/src/assets/.DS_Store +0 -0
  221. package/src/assets/favicon.ico +0 -0
  222. package/src/assets/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
  223. package/src/assets/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
  224. package/src/assets/fonts/geist-latin-wght-normal.woff2 +0 -0
  225. package/src/assets/fonts/iosevka-latin-400-normal.woff2 +0 -0
  226. package/src/assets/invect-branding.ts +51 -0
  227. package/src/assets/provider-icons/anthropic.svg +1 -0
  228. package/src/assets/provider-icons/anthropic_light.svg +1 -0
  229. package/src/assets/provider-icons/github.svg +1 -0
  230. package/src/assets/provider-icons/github_light.svg +1 -0
  231. package/src/assets/provider-icons/gmail.svg +1 -0
  232. package/src/assets/provider-icons/google_calendar.svg +1 -0
  233. package/src/assets/provider-icons/google_docs.svg +1 -0
  234. package/src/assets/provider-icons/google_drive.svg +1 -0
  235. package/src/assets/provider-icons/google_sheets.svg +1 -0
  236. package/src/assets/provider-icons/index.ts +55 -0
  237. package/src/assets/provider-icons/linear.svg +1 -0
  238. package/src/assets/provider-icons/openai.svg +1 -0
  239. package/src/assets/provider-icons/postgres.svg +1 -0
  240. package/src/assets/provider-icons/slack.svg +1 -0
  241. package/src/assets/small-loader-dark.svg +22 -0
  242. package/src/assets/small-loader-light.svg +22 -0
  243. package/src/assets/small.svg +7 -0
  244. package/src/components/.DS_Store +0 -0
  245. package/src/components/PageLayout.tsx +55 -0
  246. package/src/components/chat/ChatInput.tsx +115 -0
  247. package/src/components/chat/ChatMessageList.tsx +788 -0
  248. package/src/components/chat/ChatModelSelector.tsx +208 -0
  249. package/src/components/chat/ChatPanel.tsx +243 -0
  250. package/src/components/chat/ChatPromptOverlay.tsx +150 -0
  251. package/src/components/chat/ChatProviderSelector.tsx +135 -0
  252. package/src/components/chat/ChatSettingsPanel.tsx +277 -0
  253. package/src/components/chat/InlineCredentialSetup.tsx +343 -0
  254. package/src/components/chat/MarkdownRenderer.tsx +140 -0
  255. package/src/components/chat/chat-memory.ts +88 -0
  256. package/src/components/chat/chat.store.ts +479 -0
  257. package/src/components/chat/index.ts +5 -0
  258. package/src/components/chat/use-chat.ts +473 -0
  259. package/src/components/credentials/CreateCredentialModal.tsx +609 -0
  260. package/src/components/credentials/CredentialDetailDialog.tsx +882 -0
  261. package/src/components/credentials/EditCredentialModal.tsx +399 -0
  262. package/src/components/credentials/OAuth2ConnectButton.tsx +288 -0
  263. package/src/components/credentials/OAuth2ProviderSelector.tsx +360 -0
  264. package/src/components/credentials/credential-utils.ts +99 -0
  265. package/src/components/credentials/index.ts +10 -0
  266. package/src/components/dashboard/FailedRunsAlert.tsx +67 -0
  267. package/src/components/dashboard/FlowCard.tsx +64 -0
  268. package/src/components/dashboard/RecentActivityTable.tsx +92 -0
  269. package/src/components/dashboard/StatCard.tsx +32 -0
  270. package/src/components/dashboard/index.ts +5 -0
  271. package/src/components/dashboard/status-helpers.tsx +102 -0
  272. package/src/components/flow-editor/ActionsSidebar.tsx +503 -0
  273. package/src/components/flow-editor/FlowEditor.tsx +1002 -0
  274. package/src/components/flow-editor/FlowHeader.tsx +87 -0
  275. package/src/components/flow-editor/FlowLayout.tsx +117 -0
  276. package/src/components/flow-editor/ModeSwitcher.tsx +49 -0
  277. package/src/components/flow-editor/NodeSidebar.tsx +343 -0
  278. package/src/components/flow-editor/RunControls.tsx +109 -0
  279. package/src/components/flow-editor/ToolConfigPanel.tsx +434 -0
  280. package/src/components/flow-editor/ValidationPanel.tsx +167 -0
  281. package/src/components/flow-editor/flow-editor.store.ts +2 -0
  282. package/src/components/flow-editor/index.ts +6 -0
  283. package/src/components/flow-editor/inline-edit.tsx +111 -0
  284. package/src/components/flow-editor/node-config-panel/ConfigFieldWithTemplate.tsx +334 -0
  285. package/src/components/flow-editor/node-config-panel/CredentialCombobox.tsx +217 -0
  286. package/src/components/flow-editor/node-config-panel/CredentialsSection.tsx +154 -0
  287. package/src/components/flow-editor/node-config-panel/DroppableInput.tsx +45 -0
  288. package/src/components/flow-editor/node-config-panel/DynamicSelectField.tsx +223 -0
  289. package/src/components/flow-editor/node-config-panel/JsonPreviewPanel.tsx +134 -0
  290. package/src/components/flow-editor/node-config-panel/NodeConfigPanel.tsx +650 -0
  291. package/src/components/flow-editor/node-config-panel/NodeConfigPanelHeader.tsx +91 -0
  292. package/src/components/flow-editor/node-config-panel/ParametersSection.tsx +144 -0
  293. package/src/components/flow-editor/node-config-panel/SearchableSelectField.tsx +126 -0
  294. package/src/components/flow-editor/node-config-panel/SwitchCasesField.tsx +212 -0
  295. package/src/components/flow-editor/node-config-panel/hooks/index.ts +2 -0
  296. package/src/components/flow-editor/node-config-panel/hooks/use-node-config-panel-state.ts +284 -0
  297. package/src/components/flow-editor/node-config-panel/hooks/use-node-execution.ts +287 -0
  298. package/src/components/flow-editor/node-config-panel/hooks/use-upstream-slots.ts +310 -0
  299. package/src/components/flow-editor/node-config-panel/panels/AgentToolsPanel.tsx +837 -0
  300. package/src/components/flow-editor/node-config-panel/panels/ConfigurationPanel.tsx +383 -0
  301. package/src/components/flow-editor/node-config-panel/panels/DataMapperPane.tsx +456 -0
  302. package/src/components/flow-editor/node-config-panel/panels/InputPanel.tsx +338 -0
  303. package/src/components/flow-editor/node-config-panel/panels/OutputPanel.tsx +109 -0
  304. package/src/components/flow-editor/node-config-panel/panels/index.ts +4 -0
  305. package/src/components/flow-editor/node-config-panel/types.ts +20 -0
  306. package/src/components/flow-editor/node-config-panel/use-node-config-panel-store.ts +283 -0
  307. package/src/components/flow-editor/node-config-panel/use-node-config-state.ts +172 -0
  308. package/src/components/flow-editor/node-config-panel/use-run-node.ts +147 -0
  309. package/src/components/flow-editor/node-config-panel/utils.ts +73 -0
  310. package/src/components/flow-editor/serialize-to-sdk.ts +204 -0
  311. package/src/components/flow-editor/toolbar-context.ts +9 -0
  312. package/src/components/flow-editor/use-copy-paste.ts +575 -0
  313. package/src/components/flow-editor/use-copy-paste.types.ts +35 -0
  314. package/src/components/flow-editor/use-flow-editor.ts +241 -0
  315. package/src/components/flow-runs-table/FlowRunsTable.tsx +631 -0
  316. package/src/components/flow-runs-table/index.ts +1 -0
  317. package/src/components/flow-viewer/FlowRunsView.tsx +268 -0
  318. package/src/components/flow-viewer/FlowStatusView.tsx +351 -0
  319. package/src/components/flow-viewer/RunSelector.tsx +422 -0
  320. package/src/components/flow-viewer/RunsSidebar.tsx +125 -0
  321. package/src/components/flow-viewer/agent-tool-executions-list.tsx +298 -0
  322. package/src/components/flow-viewer/index.ts +1 -0
  323. package/src/components/flow-viewer/logs-panel.tsx +567 -0
  324. package/src/components/flow-viewer/use-execution-log-data.ts +374 -0
  325. package/src/components/graph/BatchFlowEdge.tsx +229 -0
  326. package/src/components/graph/LayoutSelector.tsx +42 -0
  327. package/src/components/graph/index.ts +61 -0
  328. package/src/components/graph/styleUtils.ts +375 -0
  329. package/src/components/nodes/.DS_Store +0 -0
  330. package/src/components/nodes/AgentConfigPanel.tsx +1033 -0
  331. package/src/components/nodes/AgentNode.tsx +298 -0
  332. package/src/components/nodes/AgentToolsBox.tsx +193 -0
  333. package/src/components/nodes/NodeAppendix.tsx +98 -0
  334. package/src/components/nodes/NodeStatusIndicator.tsx +74 -0
  335. package/src/components/nodes/NodeViewContext.tsx +45 -0
  336. package/src/components/nodes/ToolParamField.tsx +282 -0
  337. package/src/components/nodes/ToolSelectorModal.tsx +648 -0
  338. package/src/components/nodes/ToolSelectorParts.tsx +505 -0
  339. package/src/components/nodes/UniversalNode.tsx +356 -0
  340. package/src/components/nodes/createContextAwareNodes.ts +19 -0
  341. package/src/components/nodes/index.ts +45 -0
  342. package/src/components/nodes/nodeRegistry.ts +50 -0
  343. package/src/components/nodes/withNodeContext.tsx +55 -0
  344. package/src/components/shared/InvectLoader.tsx +59 -0
  345. package/src/components/shared/InvectLogo.tsx +59 -0
  346. package/src/components/shared/ProviderIcon.tsx +115 -0
  347. package/src/components/side-menu/side-menu.tsx +267 -0
  348. package/src/components/sidebar/BaseSidebar.tsx +148 -0
  349. package/src/components/sidebar/index.ts +1 -0
  350. package/src/components/triggers/CronPreview.tsx +243 -0
  351. package/src/components/triggers/index.ts +1 -0
  352. package/src/components/ui/alert-dialog.tsx +152 -0
  353. package/src/components/ui/badge.tsx +39 -0
  354. package/src/components/ui/button.tsx +58 -0
  355. package/src/components/ui/card.tsx +75 -0
  356. package/src/components/ui/codemirror-js-editor.tsx +432 -0
  357. package/src/components/ui/codemirror-json-editor.tsx +816 -0
  358. package/src/components/ui/codemirror-nunjucks-editor.tsx +451 -0
  359. package/src/components/ui/codemirror-vscode-theme.ts +243 -0
  360. package/src/components/ui/collapsible.tsx +12 -0
  361. package/src/components/ui/command.tsx +162 -0
  362. package/src/components/ui/dialog.tsx +140 -0
  363. package/src/components/ui/dropdown-menu.tsx +232 -0
  364. package/src/components/ui/empty-state.tsx +93 -0
  365. package/src/components/ui/input.tsx +26 -0
  366. package/src/components/ui/label.tsx +19 -0
  367. package/src/components/ui/popover.tsx +53 -0
  368. package/src/components/ui/resizable.tsx +61 -0
  369. package/src/components/ui/scroll-area.tsx +56 -0
  370. package/src/components/ui/select.tsx +179 -0
  371. package/src/components/ui/separator.tsx +26 -0
  372. package/src/components/ui/slider.tsx +58 -0
  373. package/src/components/ui/switch.tsx +22 -0
  374. package/src/components/ui/table.tsx +90 -0
  375. package/src/components/ui/textarea.tsx +23 -0
  376. package/src/components/ui/tooltip.tsx +54 -0
  377. package/src/components/ui/tree-view.tsx +574 -0
  378. package/src/contexts/AgentToolCallbacksContext.tsx +31 -0
  379. package/src/contexts/ApiContext.tsx +51 -0
  380. package/src/contexts/FlowDataContext.tsx +21 -0
  381. package/src/contexts/NodeRegistryContext.tsx +54 -0
  382. package/src/contexts/PluginRegistryContext.tsx +182 -0
  383. package/src/contexts/ThemeProvider.tsx +106 -0
  384. package/src/contexts/ValidationContext.tsx +122 -0
  385. package/src/demo/DemoInvect.tsx +42 -0
  386. package/src/demo/FlowViewer.tsx +294 -0
  387. package/src/demo/demo-api-client.ts +246 -0
  388. package/src/demo/index.ts +28 -0
  389. package/src/demo/sample-data.ts +1980 -0
  390. package/src/hooks/index.ts +1 -0
  391. package/src/hooks/use-document-title.ts +8 -0
  392. package/src/hooks/use-flow-data.ts +144 -0
  393. package/src/hooks/use-invect-portal-class.ts +27 -0
  394. package/src/hooks/useFlowEditorStore.ts +2 -0
  395. package/src/index.ts +70 -0
  396. package/src/lib/utils.ts +6 -0
  397. package/src/prettier.d.ts +13 -0
  398. package/src/routes/all-flow-runs.tsx +27 -0
  399. package/src/routes/credentials.tsx +362 -0
  400. package/src/routes/flow-route-layout.tsx +113 -0
  401. package/src/routes/flow-runs.tsx +22 -0
  402. package/src/routes/flow.tsx +22 -0
  403. package/src/routes/home.tsx +282 -0
  404. package/src/services/index.ts +6 -0
  405. package/src/stores/executionViewStore.ts +211 -0
  406. package/src/stores/flow-editor.store.ts +738 -0
  407. package/src/stores/flowEditorStore.ts +2 -0
  408. package/src/stores/index.ts +10 -0
  409. package/src/stores/uiStore.ts +189 -0
  410. package/src/types/agent-tools.types.ts +64 -0
  411. package/src/types/index.ts +5 -0
  412. package/src/types/node-definition.types.ts +104 -0
  413. package/src/types/plugin.types.ts +123 -0
  414. package/src/utils/credentialBranding.ts +116 -0
  415. package/src/utils/credentialFiltering.ts +68 -0
  416. package/src/utils/flowTransformations.ts +137 -0
  417. package/src/utils/layoutUtils.ts +127 -0
  418. package/src/utils/nodeReferenceUtils.ts +135 -0
  419. package/src/vendor.d.ts +7 -0
@@ -0,0 +1,343 @@
1
+ /**
2
+ * InlineCredentialSetup — Inline form for creating an LLM credential
3
+ * directly inside the chat panel (no modal, no navigation).
4
+ *
5
+ * If existing LLM credentials exist, shows a quick picker first.
6
+ * Otherwise shows: Provider (OpenAI/Anthropic/OpenRouter), Name, API Key.
7
+ * On submit: creates credential → validates via list-models → auto-selects.
8
+ */
9
+
10
+ import React, { useState, useCallback } from 'react';
11
+ import {
12
+ KeyRound,
13
+ Loader2,
14
+ CheckCircle2,
15
+ AlertCircle,
16
+ Eye,
17
+ EyeOff,
18
+ Plus,
19
+ ChevronRight,
20
+ } from 'lucide-react';
21
+ import { Button } from '~/components/ui/button';
22
+ import { Input } from '~/components/ui/input';
23
+ import {
24
+ Select,
25
+ SelectContent,
26
+ SelectItem,
27
+ SelectTrigger,
28
+ SelectValue,
29
+ } from '~/components/ui/select';
30
+ import { useApiClient } from '~/contexts/ApiContext';
31
+ import { useCredentials, useCreateCredential } from '~/api/credentials.api';
32
+ import { useChatStore } from './chat.store';
33
+
34
+ // =====================================
35
+ // Provider presets
36
+ // =====================================
37
+
38
+ const LLM_PROVIDERS = [
39
+ { value: 'openai', label: 'OpenAI', placeholder: 'sk-...' },
40
+ { value: 'anthropic', label: 'Anthropic', placeholder: 'sk-ant-...' },
41
+ { value: 'openrouter', label: 'OpenRouter', placeholder: 'sk-or-...' },
42
+ ] as const;
43
+
44
+ type LlmProvider = (typeof LLM_PROVIDERS)[number]['value'];
45
+
46
+ function getDefaultName(provider: LlmProvider): string {
47
+ const label = LLM_PROVIDERS.find((p) => p.value === provider)?.label ?? provider;
48
+ return `${label} (Chat)`;
49
+ }
50
+
51
+ function getBaseUrl(provider: LlmProvider): string | undefined {
52
+ if (provider === 'openrouter') {
53
+ return 'https://openrouter.ai/api/v1';
54
+ }
55
+ return undefined;
56
+ }
57
+
58
+ // =====================================
59
+ // Component
60
+ // =====================================
61
+
62
+ type FormState = 'idle' | 'creating' | 'validating' | 'success' | 'error';
63
+
64
+ export function InlineCredentialSetup() {
65
+ const { data: existingCredentials = [] } = useCredentials({ type: 'llm', isActive: true });
66
+ const [showCreateForm, setShowCreateForm] = useState(false);
67
+
68
+ // If existing credentials exist and user hasn't clicked "create new", show the picker
69
+ if (existingCredentials.length > 0 && !showCreateForm) {
70
+ return (
71
+ <ExistingCredentialPicker
72
+ credentials={existingCredentials}
73
+ onCreateNew={() => setShowCreateForm(true)}
74
+ />
75
+ );
76
+ }
77
+
78
+ return (
79
+ <CreateCredentialForm
80
+ onBack={existingCredentials.length > 0 ? () => setShowCreateForm(false) : undefined}
81
+ />
82
+ );
83
+ }
84
+
85
+ // =====================================
86
+ // ExistingCredentialPicker
87
+ // =====================================
88
+
89
+ function ExistingCredentialPicker({
90
+ credentials,
91
+ onCreateNew,
92
+ }: {
93
+ credentials: Array<{ id: string; name: string }>;
94
+ onCreateNew: () => void;
95
+ }) {
96
+ const handleSelect = useCallback((id: string) => {
97
+ useChatStore.getState().updateSettings({ credentialId: id });
98
+ }, []);
99
+
100
+ return (
101
+ <div className="flex flex-col gap-3 rounded-xl border bg-muted/20 p-4 mx-2 w-full max-w-sm">
102
+ <div className="flex flex-col items-center gap-2 pb-1">
103
+ <div className="flex size-9 items-center justify-center rounded-full bg-primary/10">
104
+ <KeyRound className="size-4 text-primary" />
105
+ </div>
106
+ <div className="text-center">
107
+ <p className="text-sm font-semibold text-foreground">Select an LLM provider</p>
108
+ <p className="mt-0.5 text-[11px] text-muted-foreground">
109
+ Choose a credential to power the chat assistant.
110
+ </p>
111
+ </div>
112
+ </div>
113
+
114
+ <div className="flex flex-col gap-1.5">
115
+ {credentials.map((c) => (
116
+ <button
117
+ key={c.id}
118
+ type="button"
119
+ onClick={() => handleSelect(c.id)}
120
+ className="flex items-center gap-2 px-3 py-2 text-xs text-left transition-colors border rounded-lg text-foreground/80 border-border/50 bg-background hover:bg-accent/50 hover:border-border"
121
+ >
122
+ <KeyRound className="size-3 text-muted-foreground/50 shrink-0" />
123
+ <span className="flex-1 truncate">{c.name}</span>
124
+ <ChevronRight className="size-3 text-muted-foreground/40 shrink-0" />
125
+ </button>
126
+ ))}
127
+ </div>
128
+
129
+ <div className="relative flex items-center gap-2 py-0.5">
130
+ <div className="flex-1 border-t border-border/40" />
131
+ <span className="text-[10px] text-muted-foreground/60">or</span>
132
+ <div className="flex-1 border-t border-border/40" />
133
+ </div>
134
+
135
+ <Button variant="outline" size="sm" className="w-full gap-1.5 text-xs" onClick={onCreateNew}>
136
+ <Plus className="size-3.5" />
137
+ Add New Provider
138
+ </Button>
139
+ </div>
140
+ );
141
+ }
142
+
143
+ // =====================================
144
+ // CreateCredentialForm
145
+ // =====================================
146
+
147
+ function CreateCredentialForm({ onBack }: { onBack?: () => void }) {
148
+ const apiClient = useApiClient();
149
+ const createCredential = useCreateCredential();
150
+
151
+ const [provider, setProvider] = useState<LlmProvider>('openai');
152
+ const [name, setName] = useState('');
153
+ const [apiKey, setApiKey] = useState('');
154
+ const [showKey, setShowKey] = useState(false);
155
+ const [formState, setFormState] = useState<FormState>('idle');
156
+ const [errorMsg, setErrorMsg] = useState('');
157
+ const [modelCount, setModelCount] = useState(0);
158
+
159
+ const effectiveName = name.trim() || getDefaultName(provider);
160
+ const canSubmit =
161
+ apiKey.trim().length > 0 && formState !== 'creating' && formState !== 'validating';
162
+
163
+ const handleSubmit = useCallback(
164
+ async (e: React.FormEvent) => {
165
+ e.preventDefault();
166
+ if (!canSubmit) {
167
+ return;
168
+ }
169
+
170
+ setErrorMsg('');
171
+ setFormState('creating');
172
+
173
+ try {
174
+ // 1. Create the credential
175
+ const credential = await createCredential.mutateAsync({
176
+ name: effectiveName,
177
+ type: 'llm',
178
+ authType: 'apiKey',
179
+ config: {
180
+ apiKey: apiKey.trim(),
181
+ ...(getBaseUrl(provider) ? { baseUrl: getBaseUrl(provider) } : {}),
182
+ },
183
+ metadata: { provider },
184
+ });
185
+
186
+ // 2. Validate by listing models
187
+ setFormState('validating');
188
+ try {
189
+ const models = await apiClient.getChatModels(credential.id);
190
+ setModelCount(models.length);
191
+ } catch {
192
+ // Key created but validation failed — still usable, warn user
193
+ setModelCount(0);
194
+ }
195
+
196
+ // 3. Auto-select in chat settings
197
+ useChatStore.getState().updateSettings({ credentialId: credential.id });
198
+
199
+ setFormState('success');
200
+ } catch (err: unknown) {
201
+ setFormState('error');
202
+ setErrorMsg((err as Error).message || 'Failed to create credential');
203
+ }
204
+ },
205
+ [canSubmit, effectiveName, apiKey, provider, createCredential, apiClient],
206
+ );
207
+
208
+ // After success, show brief confirmation then the chat will re-render
209
+ // (because hasConfiguredCredential becomes true via the store update)
210
+ if (formState === 'success') {
211
+ return (
212
+ <div className="flex flex-col items-center gap-3 rounded-xl border bg-muted/20 p-5 mx-2 w-full max-w-sm">
213
+ <div className="flex size-10 items-center justify-center rounded-full bg-success/10">
214
+ <CheckCircle2 className="size-5 text-success" />
215
+ </div>
216
+ <div className="text-center">
217
+ <p className="text-sm font-semibold text-foreground">Provider connected</p>
218
+ <p className="mt-1 text-xs text-muted-foreground">
219
+ {modelCount > 0
220
+ ? `API key verified — ${modelCount} models available.`
221
+ : 'Credential saved. You can start chatting now.'}
222
+ </p>
223
+ </div>
224
+ </div>
225
+ );
226
+ }
227
+
228
+ return (
229
+ <form
230
+ onSubmit={handleSubmit}
231
+ className="flex flex-col gap-3.5 rounded-xl border bg-muted/20 p-4 mx-2 w-full max-w-sm"
232
+ >
233
+ {/* Header */}
234
+ <div className="flex flex-col items-center gap-2 pb-1">
235
+ <div className="flex size-9 items-center justify-center rounded-full bg-primary/10">
236
+ <KeyRound className="size-4 text-primary" />
237
+ </div>
238
+ <div className="text-center">
239
+ <p className="text-sm font-semibold text-foreground">Connect an LLM provider</p>
240
+ <p className="mt-0.5 text-[11px] text-muted-foreground">
241
+ Add an API key to start chatting with the assistant.
242
+ </p>
243
+ </div>
244
+ </div>
245
+
246
+ {/* Provider */}
247
+ <div className="space-y-1">
248
+ <label className="text-[11px] font-medium text-muted-foreground">Provider</label>
249
+ <Select
250
+ value={provider}
251
+ onValueChange={(v) => {
252
+ setProvider(v as LlmProvider);
253
+ if (!name.trim()) {
254
+ setName('');
255
+ }
256
+ }}
257
+ >
258
+ <SelectTrigger className="h-8 text-xs">
259
+ <SelectValue />
260
+ </SelectTrigger>
261
+ <SelectContent>
262
+ {LLM_PROVIDERS.map((p) => (
263
+ <SelectItem key={p.value} value={p.value}>
264
+ {p.label}
265
+ </SelectItem>
266
+ ))}
267
+ </SelectContent>
268
+ </Select>
269
+ </div>
270
+
271
+ {/* Name */}
272
+ <div className="space-y-1">
273
+ <label className="text-[11px] font-medium text-muted-foreground">Name</label>
274
+ <Input
275
+ value={name}
276
+ onChange={(e) => setName(e.target.value)}
277
+ placeholder={getDefaultName(provider)}
278
+ className="h-8 text-xs"
279
+ />
280
+ </div>
281
+
282
+ {/* API Key */}
283
+ <div className="space-y-1">
284
+ <label className="text-[11px] font-medium text-muted-foreground">API Key</label>
285
+ <div className="relative">
286
+ <Input
287
+ type={showKey ? 'text' : 'password'}
288
+ value={apiKey}
289
+ onChange={(e) => setApiKey(e.target.value)}
290
+ placeholder={LLM_PROVIDERS.find((p) => p.value === provider)?.placeholder ?? 'sk-...'}
291
+ className="h-8 pr-8 text-xs font-mono"
292
+ autoComplete="off"
293
+ spellCheck={false}
294
+ />
295
+ <button
296
+ type="button"
297
+ onClick={() => setShowKey((s) => !s)}
298
+ className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground/60 hover:text-muted-foreground transition-colors"
299
+ tabIndex={-1}
300
+ >
301
+ {showKey ? <EyeOff className="size-3.5" /> : <Eye className="size-3.5" />}
302
+ </button>
303
+ </div>
304
+ </div>
305
+
306
+ {/* Error */}
307
+ {formState === 'error' && errorMsg && (
308
+ <div className="flex items-start gap-2 rounded-lg bg-destructive/10 px-3 py-2 text-xs text-destructive">
309
+ <AlertCircle className="mt-0.5 size-3.5 shrink-0" />
310
+ <span>{errorMsg}</span>
311
+ </div>
312
+ )}
313
+
314
+ {/* Submit */}
315
+ <Button type="submit" size="sm" className="w-full gap-1.5 text-xs" disabled={!canSubmit}>
316
+ {formState === 'creating' ? (
317
+ <>
318
+ <Loader2 className="size-3.5 animate-spin" />
319
+ Saving…
320
+ </>
321
+ ) : formState === 'validating' ? (
322
+ <>
323
+ <Loader2 className="size-3.5 animate-spin" />
324
+ Verifying key…
325
+ </>
326
+ ) : (
327
+ 'Connect Provider'
328
+ )}
329
+ </Button>
330
+
331
+ {/* Back link */}
332
+ {onBack && (
333
+ <button
334
+ type="button"
335
+ onClick={onBack}
336
+ className="text-[11px] text-muted-foreground hover:text-foreground transition-colors"
337
+ >
338
+ ← Back to existing providers
339
+ </button>
340
+ )}
341
+ </form>
342
+ );
343
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * MarkdownRenderer — renders markdown content with theme-aware styling.
3
+ *
4
+ * Uses react-markdown + remark-gfm for full GitHub-flavored markdown support.
5
+ * All styles use CSS variables from the tailwind theme so they adapt to
6
+ * light/dark mode automatically.
7
+ */
8
+
9
+ import React, { memo } from 'react';
10
+ import ReactMarkdown from 'react-markdown';
11
+ import remarkGfm from 'remark-gfm';
12
+ import { cn } from '~/lib/utils';
13
+
14
+ interface MarkdownRendererProps {
15
+ content: string;
16
+ className?: string;
17
+ }
18
+
19
+ export const MarkdownRenderer = memo(function MarkdownRenderer({
20
+ content,
21
+ className,
22
+ }: MarkdownRendererProps) {
23
+ return (
24
+ <div className={cn('chat-markdown w-full min-w-0 overflow-hidden break-words', className)}>
25
+ <ReactMarkdown
26
+ remarkPlugins={[remarkGfm]}
27
+ components={{
28
+ // Paragraphs
29
+ p: ({ children }) => (
30
+ <p className="mb-2 leading-relaxed break-words last:mb-0">{children}</p>
31
+ ),
32
+
33
+ // Headings
34
+ h1: ({ children }) => (
35
+ <h1 className="mt-3 mb-2 text-base font-bold first:mt-0 text-foreground">{children}</h1>
36
+ ),
37
+ h2: ({ children }) => (
38
+ <h2 className="text-sm font-bold mb-1.5 mt-2.5 first:mt-0 text-foreground">
39
+ {children}
40
+ </h2>
41
+ ),
42
+ h3: ({ children }) => (
43
+ <h3 className="mt-2 mb-1 text-sm font-semibold first:mt-0 text-foreground">
44
+ {children}
45
+ </h3>
46
+ ),
47
+
48
+ // Inline code
49
+ code: ({ children, className: codeClassName }) => {
50
+ // Detect if this is inside a <pre> (fenced code block)
51
+ const isBlock = codeClassName?.startsWith('language-');
52
+ if (isBlock) {
53
+ return <code className={cn('text-[11px]', codeClassName)}>{children}</code>;
54
+ }
55
+ return (
56
+ <code className="px-1 py-0.5 rounded-sm bg-muted text-foreground text-[11px] font-medium break-all">
57
+ {children}
58
+ </code>
59
+ );
60
+ },
61
+
62
+ // Code blocks
63
+ pre: ({ children }) => (
64
+ <pre className="mb-2 last:mb-0 p-2.5 rounded-sm bg-muted border border-border text-[11px] leading-relaxed overflow-x-auto max-w-full">
65
+ {children}
66
+ </pre>
67
+ ),
68
+
69
+ // Lists
70
+ ul: ({ children }) => (
71
+ <ul className="mb-2 last:mb-0 pl-6 list-disc space-y-0.5 marker:text-muted-foreground">
72
+ {children}
73
+ </ul>
74
+ ),
75
+ ol: ({ children }) => (
76
+ <ol className="mb-2 last:mb-0 pl-6 list-decimal space-y-0.5 marker:text-muted-foreground">
77
+ {children}
78
+ </ol>
79
+ ),
80
+ li: ({ children }) => <li className="leading-relaxed break-words">{children}</li>,
81
+
82
+ // Blockquotes
83
+ blockquote: ({ children }) => (
84
+ <blockquote className="pl-3 mb-2 italic border-l-2 last:mb-0 border-border text-muted-foreground">
85
+ {children}
86
+ </blockquote>
87
+ ),
88
+
89
+ // Links
90
+ a: ({ href, children }) => (
91
+ <a
92
+ href={href}
93
+ target="_blank"
94
+ rel="noopener noreferrer"
95
+ className="underline transition-colors text-primary underline-offset-2 hover:text-foreground"
96
+ >
97
+ {children}
98
+ </a>
99
+ ),
100
+
101
+ // Bold & emphasis
102
+ strong: ({ children }) => (
103
+ <strong className="font-semibold text-foreground">{children}</strong>
104
+ ),
105
+ em: ({ children }) => <em className="italic">{children}</em>,
106
+
107
+ // Horizontal rule
108
+ hr: () => <hr className="my-3 border-border" />,
109
+
110
+ // Tables
111
+ table: ({ children }) => (
112
+ <div className="max-w-full mb-2 overflow-x-auto last:mb-0">
113
+ <table className="w-full text-[11px] border-collapse border border-border">
114
+ {children}
115
+ </table>
116
+ </div>
117
+ ),
118
+ thead: ({ children }) => <thead className="bg-muted">{children}</thead>,
119
+ th: ({ children }) => (
120
+ <th className="px-2 py-1 font-semibold text-left border border-border text-foreground">
121
+ {children}
122
+ </th>
123
+ ),
124
+ td: ({ children }) => <td className="px-2 py-1 border border-border">{children}</td>,
125
+
126
+ // Images — basic support
127
+ img: ({ src, alt }) => (
128
+ <img
129
+ src={src}
130
+ alt={alt ?? ''}
131
+ className="max-w-full my-1 border rounded-sm border-border"
132
+ />
133
+ ),
134
+ }}
135
+ >
136
+ {content}
137
+ </ReactMarkdown>
138
+ </div>
139
+ );
140
+ });
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Chat Memory — Browser-local persistence via localStorage.
3
+ *
4
+ * Stores notes in two scopes:
5
+ * - Flow-scoped: localStorage key = `invect:chat-memory:flow:<flowId>`
6
+ * - Workspace-scoped: localStorage key = `invect:chat-memory:workspace`
7
+ *
8
+ * Each key stores a JSON array of strings (the note contents).
9
+ * Maximum 50 notes per scope to prevent unbounded growth.
10
+ */
11
+
12
+ const FLOW_KEY_PREFIX = 'invect:chat-memory:flow:';
13
+ const WORKSPACE_KEY = 'invect:chat-memory:workspace';
14
+ const MAX_NOTES = 50;
15
+
16
+ function getKey(scope: 'flow' | 'workspace', flowId?: string): string {
17
+ if (scope === 'flow') {
18
+ if (!flowId) {
19
+ throw new Error('flowId required for flow-scoped memory');
20
+ }
21
+ return `${FLOW_KEY_PREFIX}${flowId}`;
22
+ }
23
+ return WORKSPACE_KEY;
24
+ }
25
+
26
+ function readNotes(key: string): string[] {
27
+ try {
28
+ const raw = localStorage.getItem(key);
29
+ if (!raw) {
30
+ return [];
31
+ }
32
+ const parsed = JSON.parse(raw);
33
+ return Array.isArray(parsed) ? parsed.filter((n): n is string => typeof n === 'string') : [];
34
+ } catch {
35
+ return [];
36
+ }
37
+ }
38
+
39
+ function writeNotes(key: string, notes: string[]): void {
40
+ localStorage.setItem(key, JSON.stringify(notes.slice(0, MAX_NOTES)));
41
+ }
42
+
43
+ // =====================================
44
+ // Public API
45
+ // =====================================
46
+
47
+ export function getMemoryNotes(scope: 'flow' | 'workspace', flowId?: string): string[] {
48
+ return readNotes(getKey(scope, flowId));
49
+ }
50
+
51
+ export function saveMemoryNote(
52
+ scope: 'flow' | 'workspace',
53
+ content: string,
54
+ flowId?: string,
55
+ ): void {
56
+ const key = getKey(scope, flowId);
57
+ const notes = readNotes(key);
58
+ // Avoid duplicates
59
+ if (!notes.includes(content)) {
60
+ notes.push(content);
61
+ writeNotes(key, notes);
62
+ }
63
+ }
64
+
65
+ export function deleteMemoryNote(
66
+ scope: 'flow' | 'workspace',
67
+ content: string,
68
+ flowId?: string,
69
+ ): void {
70
+ const key = getKey(scope, flowId);
71
+ const notes = readNotes(key);
72
+ const filtered = notes.filter((n) => n !== content);
73
+ writeNotes(key, filtered);
74
+ }
75
+
76
+ /**
77
+ * Get all memory notes for a flow (flow-scoped + workspace-scoped).
78
+ * Returns the shape expected by ChatContext.memoryNotes.
79
+ */
80
+ export function getAllMemoryNotes(flowId?: string): {
81
+ flowNotes: string[];
82
+ workspaceNotes: string[];
83
+ } {
84
+ return {
85
+ flowNotes: flowId ? getMemoryNotes('flow', flowId) : [],
86
+ workspaceNotes: getMemoryNotes('workspace'),
87
+ };
88
+ }