@flowdot.ai/mcp-server 1.0.3 → 1.0.5

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 (514) hide show
  1. package/LICENSE +45 -21
  2. package/README.md +439 -162
  3. package/bin/flowdot-mcp.js +15 -15
  4. package/dist/api-client.d.ts +0 -6
  5. package/dist/api-client.js +0 -6
  6. package/dist/index.d.ts +0 -23
  7. package/dist/index.js +0 -24
  8. package/dist/resources/index.d.ts +1 -11
  9. package/dist/resources/index.js +2882 -2127
  10. package/dist/server.d.ts +0 -12
  11. package/dist/server.js +23 -21
  12. package/dist/tools/add-connection.d.ts +2 -8
  13. package/dist/tools/add-connection.js +0 -6
  14. package/dist/tools/add-custom-node-comment.d.ts +2 -9
  15. package/dist/tools/add-custom-node-comment.js +0 -7
  16. package/dist/tools/add-node.d.ts +2 -8
  17. package/dist/tools/add-node.js +0 -6
  18. package/dist/tools/add-recipe-step.d.ts +3 -9
  19. package/dist/tools/add-recipe-step.js +95 -101
  20. package/dist/tools/add-recipe-store.d.ts +2 -8
  21. package/dist/tools/add-recipe-store.js +30 -36
  22. package/dist/tools/add-shared-result-comment.d.ts +2 -8
  23. package/dist/tools/add-shared-result-comment.js +0 -7
  24. package/dist/tools/add-workflow-comment.d.ts +2 -8
  25. package/dist/tools/add-workflow-comment.js +0 -7
  26. package/dist/tools/agent-chat.d.ts +2 -8
  27. package/dist/tools/agent-chat.js +0 -10
  28. package/dist/tools/agent-toolkits.d.ts +3 -10
  29. package/dist/tools/agent-toolkits.js +294 -336
  30. package/dist/tools/append-app-code.d.ts +2 -10
  31. package/dist/tools/append-app-code.js +27 -35
  32. package/dist/tools/browse-recipes.d.ts +2 -8
  33. package/dist/tools/browse-recipes.js +0 -7
  34. package/dist/tools/cancel-execution.d.ts +2 -8
  35. package/dist/tools/cancel-execution.js +0 -7
  36. package/dist/tools/clone-app.d.ts +2 -9
  37. package/dist/tools/clone-app.js +20 -27
  38. package/dist/tools/copy-custom-node.d.ts +2 -9
  39. package/dist/tools/copy-custom-node.js +0 -7
  40. package/dist/tools/create-app-file.d.ts +2 -9
  41. package/dist/tools/create-app-file.js +18 -25
  42. package/dist/tools/create-app.d.ts +2 -9
  43. package/dist/tools/create-app.js +123 -130
  44. package/dist/tools/create-custom-node.d.ts +3 -10
  45. package/dist/tools/create-custom-node.js +66 -75
  46. package/dist/tools/create-input-preset.d.ts +2 -8
  47. package/dist/tools/create-input-preset.js +0 -7
  48. package/dist/tools/create-knowledge-category.d.ts +2 -9
  49. package/dist/tools/create-knowledge-category.js +0 -7
  50. package/dist/tools/create-recipe.d.ts +2 -8
  51. package/dist/tools/create-recipe.js +21 -27
  52. package/dist/tools/create-shared-result.d.ts +2 -8
  53. package/dist/tools/create-shared-result.js +0 -6
  54. package/dist/tools/create-workflow.d.ts +2 -8
  55. package/dist/tools/create-workflow.js +0 -6
  56. package/dist/tools/delete-app-file.d.ts +2 -9
  57. package/dist/tools/delete-app-file.js +9 -16
  58. package/dist/tools/delete-app.d.ts +2 -9
  59. package/dist/tools/delete-app.js +3 -10
  60. package/dist/tools/delete-connection.d.ts +2 -8
  61. package/dist/tools/delete-connection.js +0 -7
  62. package/dist/tools/delete-custom-node.d.ts +2 -9
  63. package/dist/tools/delete-custom-node.js +0 -7
  64. package/dist/tools/delete-input-preset.d.ts +2 -8
  65. package/dist/tools/delete-input-preset.js +0 -6
  66. package/dist/tools/delete-knowledge-category.d.ts +2 -8
  67. package/dist/tools/delete-knowledge-category.js +0 -6
  68. package/dist/tools/delete-knowledge-document.d.ts +2 -8
  69. package/dist/tools/delete-knowledge-document.js +0 -6
  70. package/dist/tools/delete-node.d.ts +2 -8
  71. package/dist/tools/delete-node.js +0 -7
  72. package/dist/tools/delete-recipe-step.d.ts +2 -8
  73. package/dist/tools/delete-recipe-step.js +2 -8
  74. package/dist/tools/delete-recipe-store.d.ts +2 -8
  75. package/dist/tools/delete-recipe-store.js +2 -8
  76. package/dist/tools/delete-recipe.d.ts +2 -8
  77. package/dist/tools/delete-recipe.js +0 -6
  78. package/dist/tools/delete-workflow.d.ts +2 -8
  79. package/dist/tools/delete-workflow.js +0 -7
  80. package/dist/tools/duplicate-workflow.d.ts +2 -8
  81. package/dist/tools/duplicate-workflow.js +0 -6
  82. package/dist/tools/edit-app-code.d.ts +2 -10
  83. package/dist/tools/edit-app-code.js +34 -43
  84. package/dist/tools/execute-workflow.d.ts +2 -8
  85. package/dist/tools/execute-workflow.js +0 -11
  86. package/dist/tools/favorite-custom-node.d.ts +2 -9
  87. package/dist/tools/favorite-custom-node.js +0 -8
  88. package/dist/tools/favorite-recipe.d.ts +2 -8
  89. package/dist/tools/favorite-recipe.js +2 -8
  90. package/dist/tools/favorite-workflow.d.ts +2 -8
  91. package/dist/tools/favorite-workflow.js +0 -7
  92. package/dist/tools/fork-recipe.d.ts +2 -8
  93. package/dist/tools/fork-recipe.js +7 -13
  94. package/dist/tools/get-app-file.d.ts +2 -9
  95. package/dist/tools/get-app-file.js +20 -28
  96. package/dist/tools/get-app-template.d.ts +1 -8
  97. package/dist/tools/get-app-template.js +827 -834
  98. package/dist/tools/get-app.d.ts +2 -9
  99. package/dist/tools/get-app.js +54 -66
  100. package/dist/tools/get-custom-node-comments.d.ts +2 -9
  101. package/dist/tools/get-custom-node-comments.js +0 -7
  102. package/dist/tools/get-custom-node-template.d.ts +1 -8
  103. package/dist/tools/get-custom-node-template.js +60 -73
  104. package/dist/tools/get-custom-node.d.ts +2 -9
  105. package/dist/tools/get-custom-node.js +0 -12
  106. package/dist/tools/get-execution-history.d.ts +2 -8
  107. package/dist/tools/get-execution-history.js +0 -7
  108. package/dist/tools/get-execution.d.ts +2 -8
  109. package/dist/tools/get-execution.js +0 -7
  110. package/dist/tools/get-input-preset.d.ts +2 -8
  111. package/dist/tools/get-input-preset.js +0 -7
  112. package/dist/tools/get-knowledge-document-content.d.ts +6 -0
  113. package/dist/tools/get-knowledge-document-content.js +42 -0
  114. package/dist/tools/get-knowledge-document.d.ts +2 -8
  115. package/dist/tools/get-knowledge-document.js +0 -6
  116. package/dist/tools/get-knowledge-storage.d.ts +2 -8
  117. package/dist/tools/get-knowledge-storage.js +0 -7
  118. package/dist/tools/get-node-connections.d.ts +2 -8
  119. package/dist/tools/get-node-connections.js +0 -7
  120. package/dist/tools/get-node-schema.d.ts +2 -8
  121. package/dist/tools/get-node-schema.js +0 -13
  122. package/dist/tools/get-public-workflows.d.ts +2 -8
  123. package/dist/tools/get-public-workflows.js +0 -7
  124. package/dist/tools/get-recipe-definition.d.ts +2 -10
  125. package/dist/tools/get-recipe-definition.js +1 -10
  126. package/dist/tools/get-recipe.d.ts +2 -8
  127. package/dist/tools/get-recipe.js +10 -19
  128. package/dist/tools/get-shared-result-comments.d.ts +2 -8
  129. package/dist/tools/get-shared-result-comments.js +0 -6
  130. package/dist/tools/get-shared-result.d.ts +2 -8
  131. package/dist/tools/get-shared-result.js +0 -8
  132. package/dist/tools/get-workflow-comments.d.ts +2 -8
  133. package/dist/tools/get-workflow-comments.js +0 -7
  134. package/dist/tools/get-workflow-details.d.ts +2 -8
  135. package/dist/tools/get-workflow-details.js +0 -8
  136. package/dist/tools/get-workflow-graph.d.ts +2 -8
  137. package/dist/tools/get-workflow-graph.js +1 -10
  138. package/dist/tools/get-workflow-inputs-schema.d.ts +2 -8
  139. package/dist/tools/get-workflow-inputs-schema.js +0 -7
  140. package/dist/tools/get-workflow-metrics.d.ts +2 -8
  141. package/dist/tools/get-workflow-metrics.js +1 -9
  142. package/dist/tools/get-workflow-public-url.d.ts +2 -8
  143. package/dist/tools/get-workflow-public-url.js +0 -6
  144. package/dist/tools/get-workflow-tags.d.ts +2 -8
  145. package/dist/tools/get-workflow-tags.js +0 -7
  146. package/dist/tools/index.d.ts +2 -11
  147. package/dist/tools/index.js +12 -139
  148. package/dist/tools/insert-app-code.d.ts +2 -10
  149. package/dist/tools/insert-app-code.js +35 -43
  150. package/dist/tools/link-app-workflow.d.ts +2 -9
  151. package/dist/tools/link-app-workflow.js +21 -28
  152. package/dist/tools/link-recipe.d.ts +2 -8
  153. package/dist/tools/link-recipe.js +18 -24
  154. package/dist/tools/list-app-files.d.ts +2 -9
  155. package/dist/tools/list-app-files.js +10 -20
  156. package/dist/tools/list-apps.d.ts +2 -9
  157. package/dist/tools/list-apps.js +8 -15
  158. package/dist/tools/list-available-nodes.d.ts +2 -8
  159. package/dist/tools/list-available-nodes.js +0 -13
  160. package/dist/tools/list-custom-nodes.d.ts +2 -9
  161. package/dist/tools/list-custom-nodes.js +0 -7
  162. package/dist/tools/list-input-presets.d.ts +2 -8
  163. package/dist/tools/list-input-presets.js +0 -7
  164. package/dist/tools/list-knowledge-categories.d.ts +2 -9
  165. package/dist/tools/list-knowledge-categories.js +0 -11
  166. package/dist/tools/list-knowledge-documents.d.ts +2 -9
  167. package/dist/tools/list-knowledge-documents.js +0 -10
  168. package/dist/tools/list-recipe-steps.d.ts +2 -8
  169. package/dist/tools/list-recipe-steps.js +1 -8
  170. package/dist/tools/list-recipe-stores.d.ts +2 -8
  171. package/dist/tools/list-recipe-stores.js +0 -6
  172. package/dist/tools/list-recipes.d.ts +2 -8
  173. package/dist/tools/list-recipes.js +22 -31
  174. package/dist/tools/list-shared-results.d.ts +2 -8
  175. package/dist/tools/list-shared-results.js +0 -6
  176. package/dist/tools/list-user-teams.d.ts +2 -9
  177. package/dist/tools/list-user-teams.js +0 -7
  178. package/dist/tools/list-workflows.d.ts +2 -8
  179. package/dist/tools/list-workflows.js +0 -8
  180. package/dist/tools/move-document-to-category.d.ts +2 -8
  181. package/dist/tools/move-document-to-category.js +0 -6
  182. package/dist/tools/patch-knowledge-document-section.d.ts +8 -0
  183. package/dist/tools/patch-knowledge-document-section.js +47 -0
  184. package/dist/tools/prepend-app-code.d.ts +2 -10
  185. package/dist/tools/prepend-app-code.js +23 -31
  186. package/dist/tools/publish-app.d.ts +2 -9
  187. package/dist/tools/publish-app.js +7 -14
  188. package/dist/tools/query-knowledge-base.d.ts +2 -9
  189. package/dist/tools/query-knowledge-base.js +1 -15
  190. package/dist/tools/rename-app-file.d.ts +2 -9
  191. package/dist/tools/rename-app-file.js +16 -23
  192. package/dist/tools/reprocess-document.d.ts +2 -8
  193. package/dist/tools/reprocess-document.js +0 -6
  194. package/dist/tools/retry-execution.d.ts +2 -8
  195. package/dist/tools/retry-execution.js +0 -6
  196. package/dist/tools/search-apps.d.ts +2 -9
  197. package/dist/tools/search-apps.js +13 -20
  198. package/dist/tools/search-public-custom-nodes.d.ts +2 -9
  199. package/dist/tools/search-public-custom-nodes.js +0 -7
  200. package/dist/tools/search-workflows.d.ts +2 -8
  201. package/dist/tools/search-workflows.js +0 -8
  202. package/dist/tools/search.d.ts +2 -8
  203. package/dist/tools/search.js +1 -7
  204. package/dist/tools/set-app-entry-file.d.ts +2 -9
  205. package/dist/tools/set-app-entry-file.js +13 -20
  206. package/dist/tools/set-workflow-tags.d.ts +2 -8
  207. package/dist/tools/set-workflow-tags.js +0 -7
  208. package/dist/tools/stream-execution.d.ts +2 -9
  209. package/dist/tools/stream-execution.js +0 -8
  210. package/dist/tools/toggle-community-inputs.d.ts +2 -8
  211. package/dist/tools/toggle-community-inputs.js +0 -6
  212. package/dist/tools/toggle-custom-node-visibility.d.ts +2 -9
  213. package/dist/tools/toggle-custom-node-visibility.js +0 -8
  214. package/dist/tools/toggle-workflow-public.d.ts +2 -8
  215. package/dist/tools/toggle-workflow-public.js +0 -7
  216. package/dist/tools/transfer-document-ownership.d.ts +2 -9
  217. package/dist/tools/transfer-document-ownership.js +0 -7
  218. package/dist/tools/unlink-app-workflow.d.ts +2 -9
  219. package/dist/tools/unlink-app-workflow.js +2 -9
  220. package/dist/tools/unpublish-app.d.ts +2 -9
  221. package/dist/tools/unpublish-app.js +2 -9
  222. package/dist/tools/update-app-file.d.ts +2 -9
  223. package/dist/tools/update-app-file.js +15 -22
  224. package/dist/tools/update-app.d.ts +2 -9
  225. package/dist/tools/update-app.js +14 -21
  226. package/dist/tools/update-custom-node.d.ts +3 -10
  227. package/dist/tools/update-custom-node.js +11 -24
  228. package/dist/tools/update-input-preset.d.ts +2 -8
  229. package/dist/tools/update-input-preset.js +0 -7
  230. package/dist/tools/update-knowledge-category.d.ts +2 -8
  231. package/dist/tools/update-knowledge-category.js +0 -6
  232. package/dist/tools/update-knowledge-document-content.d.ts +7 -0
  233. package/dist/tools/update-knowledge-document-content.js +42 -0
  234. package/dist/tools/update-node.d.ts +2 -8
  235. package/dist/tools/update-node.js +0 -7
  236. package/dist/tools/update-recipe-step.d.ts +2 -8
  237. package/dist/tools/update-recipe-step.js +6 -12
  238. package/dist/tools/update-recipe-store.d.ts +2 -8
  239. package/dist/tools/update-recipe-store.js +5 -11
  240. package/dist/tools/update-recipe.d.ts +2 -8
  241. package/dist/tools/update-recipe.js +14 -20
  242. package/dist/tools/upload-document-from-url.d.ts +2 -9
  243. package/dist/tools/upload-document-from-url.js +0 -7
  244. package/dist/tools/upload-text-document.d.ts +2 -9
  245. package/dist/tools/upload-text-document.js +0 -7
  246. package/dist/tools/validate-workflow.d.ts +2 -8
  247. package/dist/tools/validate-workflow.js +0 -8
  248. package/dist/tools/vote-custom-node.d.ts +2 -9
  249. package/dist/tools/vote-custom-node.js +0 -7
  250. package/dist/tools/vote-input-preset.d.ts +2 -8
  251. package/dist/tools/vote-input-preset.js +0 -6
  252. package/dist/tools/vote-recipe.d.ts +2 -8
  253. package/dist/tools/vote-recipe.js +2 -8
  254. package/dist/tools/vote-shared-result.d.ts +2 -8
  255. package/dist/tools/vote-shared-result.js +0 -6
  256. package/dist/tools/vote-workflow.d.ts +2 -8
  257. package/dist/tools/vote-workflow.js +0 -6
  258. package/dist/types.d.ts +0 -6
  259. package/dist/types.js +0 -6
  260. package/dist/utils/script-validator.d.ts +1 -18
  261. package/dist/utils/script-validator.js +5 -44
  262. package/package.json +81 -62
  263. package/dist/api-client.d.ts.map +0 -1
  264. package/dist/api-client.js.map +0 -1
  265. package/dist/index.d.ts.map +0 -1
  266. package/dist/index.js.map +0 -1
  267. package/dist/resources/index.d.ts.map +0 -1
  268. package/dist/resources/index.js.map +0 -1
  269. package/dist/server.d.ts.map +0 -1
  270. package/dist/server.js.map +0 -1
  271. package/dist/tools/add-connection.d.ts.map +0 -1
  272. package/dist/tools/add-connection.js.map +0 -1
  273. package/dist/tools/add-custom-node-comment.d.ts.map +0 -1
  274. package/dist/tools/add-custom-node-comment.js.map +0 -1
  275. package/dist/tools/add-node.d.ts.map +0 -1
  276. package/dist/tools/add-node.js.map +0 -1
  277. package/dist/tools/add-recipe-step.d.ts.map +0 -1
  278. package/dist/tools/add-recipe-step.js.map +0 -1
  279. package/dist/tools/add-recipe-store.d.ts.map +0 -1
  280. package/dist/tools/add-recipe-store.js.map +0 -1
  281. package/dist/tools/add-shared-result-comment.d.ts.map +0 -1
  282. package/dist/tools/add-shared-result-comment.js.map +0 -1
  283. package/dist/tools/add-workflow-comment.d.ts.map +0 -1
  284. package/dist/tools/add-workflow-comment.js.map +0 -1
  285. package/dist/tools/agent-chat.d.ts.map +0 -1
  286. package/dist/tools/agent-chat.js.map +0 -1
  287. package/dist/tools/agent-toolkits.d.ts.map +0 -1
  288. package/dist/tools/agent-toolkits.js.map +0 -1
  289. package/dist/tools/append-app-code.d.ts.map +0 -1
  290. package/dist/tools/append-app-code.js.map +0 -1
  291. package/dist/tools/browse-recipes.d.ts.map +0 -1
  292. package/dist/tools/browse-recipes.js.map +0 -1
  293. package/dist/tools/cancel-execution.d.ts.map +0 -1
  294. package/dist/tools/cancel-execution.js.map +0 -1
  295. package/dist/tools/clone-app.d.ts.map +0 -1
  296. package/dist/tools/clone-app.js.map +0 -1
  297. package/dist/tools/copy-custom-node.d.ts.map +0 -1
  298. package/dist/tools/copy-custom-node.js.map +0 -1
  299. package/dist/tools/create-app-file.d.ts.map +0 -1
  300. package/dist/tools/create-app-file.js.map +0 -1
  301. package/dist/tools/create-app.d.ts.map +0 -1
  302. package/dist/tools/create-app.js.map +0 -1
  303. package/dist/tools/create-custom-node.d.ts.map +0 -1
  304. package/dist/tools/create-custom-node.js.map +0 -1
  305. package/dist/tools/create-input-preset.d.ts.map +0 -1
  306. package/dist/tools/create-input-preset.js.map +0 -1
  307. package/dist/tools/create-knowledge-category.d.ts.map +0 -1
  308. package/dist/tools/create-knowledge-category.js.map +0 -1
  309. package/dist/tools/create-recipe.d.ts.map +0 -1
  310. package/dist/tools/create-recipe.js.map +0 -1
  311. package/dist/tools/create-shared-result.d.ts.map +0 -1
  312. package/dist/tools/create-shared-result.js.map +0 -1
  313. package/dist/tools/create-workflow.d.ts.map +0 -1
  314. package/dist/tools/create-workflow.js.map +0 -1
  315. package/dist/tools/delete-app-file.d.ts.map +0 -1
  316. package/dist/tools/delete-app-file.js.map +0 -1
  317. package/dist/tools/delete-app.d.ts.map +0 -1
  318. package/dist/tools/delete-app.js.map +0 -1
  319. package/dist/tools/delete-connection.d.ts.map +0 -1
  320. package/dist/tools/delete-connection.js.map +0 -1
  321. package/dist/tools/delete-custom-node.d.ts.map +0 -1
  322. package/dist/tools/delete-custom-node.js.map +0 -1
  323. package/dist/tools/delete-input-preset.d.ts.map +0 -1
  324. package/dist/tools/delete-input-preset.js.map +0 -1
  325. package/dist/tools/delete-knowledge-category.d.ts.map +0 -1
  326. package/dist/tools/delete-knowledge-category.js.map +0 -1
  327. package/dist/tools/delete-knowledge-document.d.ts.map +0 -1
  328. package/dist/tools/delete-knowledge-document.js.map +0 -1
  329. package/dist/tools/delete-node.d.ts.map +0 -1
  330. package/dist/tools/delete-node.js.map +0 -1
  331. package/dist/tools/delete-recipe-step.d.ts.map +0 -1
  332. package/dist/tools/delete-recipe-step.js.map +0 -1
  333. package/dist/tools/delete-recipe-store.d.ts.map +0 -1
  334. package/dist/tools/delete-recipe-store.js.map +0 -1
  335. package/dist/tools/delete-recipe.d.ts.map +0 -1
  336. package/dist/tools/delete-recipe.js.map +0 -1
  337. package/dist/tools/delete-workflow.d.ts.map +0 -1
  338. package/dist/tools/delete-workflow.js.map +0 -1
  339. package/dist/tools/duplicate-workflow.d.ts.map +0 -1
  340. package/dist/tools/duplicate-workflow.js.map +0 -1
  341. package/dist/tools/edit-app-code.d.ts.map +0 -1
  342. package/dist/tools/edit-app-code.js.map +0 -1
  343. package/dist/tools/execute-workflow.d.ts.map +0 -1
  344. package/dist/tools/execute-workflow.js.map +0 -1
  345. package/dist/tools/favorite-custom-node.d.ts.map +0 -1
  346. package/dist/tools/favorite-custom-node.js.map +0 -1
  347. package/dist/tools/favorite-recipe.d.ts.map +0 -1
  348. package/dist/tools/favorite-recipe.js.map +0 -1
  349. package/dist/tools/favorite-workflow.d.ts.map +0 -1
  350. package/dist/tools/favorite-workflow.js.map +0 -1
  351. package/dist/tools/fork-recipe.d.ts.map +0 -1
  352. package/dist/tools/fork-recipe.js.map +0 -1
  353. package/dist/tools/get-app-file.d.ts.map +0 -1
  354. package/dist/tools/get-app-file.js.map +0 -1
  355. package/dist/tools/get-app-template.d.ts.map +0 -1
  356. package/dist/tools/get-app-template.js.map +0 -1
  357. package/dist/tools/get-app.d.ts.map +0 -1
  358. package/dist/tools/get-app.js.map +0 -1
  359. package/dist/tools/get-custom-node-comments.d.ts.map +0 -1
  360. package/dist/tools/get-custom-node-comments.js.map +0 -1
  361. package/dist/tools/get-custom-node-template.d.ts.map +0 -1
  362. package/dist/tools/get-custom-node-template.js.map +0 -1
  363. package/dist/tools/get-custom-node.d.ts.map +0 -1
  364. package/dist/tools/get-custom-node.js.map +0 -1
  365. package/dist/tools/get-execution-history.d.ts.map +0 -1
  366. package/dist/tools/get-execution-history.js.map +0 -1
  367. package/dist/tools/get-execution.d.ts.map +0 -1
  368. package/dist/tools/get-execution.js.map +0 -1
  369. package/dist/tools/get-input-preset.d.ts.map +0 -1
  370. package/dist/tools/get-input-preset.js.map +0 -1
  371. package/dist/tools/get-knowledge-document.d.ts.map +0 -1
  372. package/dist/tools/get-knowledge-document.js.map +0 -1
  373. package/dist/tools/get-knowledge-storage.d.ts.map +0 -1
  374. package/dist/tools/get-knowledge-storage.js.map +0 -1
  375. package/dist/tools/get-node-connections.d.ts.map +0 -1
  376. package/dist/tools/get-node-connections.js.map +0 -1
  377. package/dist/tools/get-node-schema.d.ts.map +0 -1
  378. package/dist/tools/get-node-schema.js.map +0 -1
  379. package/dist/tools/get-public-workflows.d.ts.map +0 -1
  380. package/dist/tools/get-public-workflows.js.map +0 -1
  381. package/dist/tools/get-recipe-definition.d.ts.map +0 -1
  382. package/dist/tools/get-recipe-definition.js.map +0 -1
  383. package/dist/tools/get-recipe.d.ts.map +0 -1
  384. package/dist/tools/get-recipe.js.map +0 -1
  385. package/dist/tools/get-shared-result-comments.d.ts.map +0 -1
  386. package/dist/tools/get-shared-result-comments.js.map +0 -1
  387. package/dist/tools/get-shared-result.d.ts.map +0 -1
  388. package/dist/tools/get-shared-result.js.map +0 -1
  389. package/dist/tools/get-workflow-comments.d.ts.map +0 -1
  390. package/dist/tools/get-workflow-comments.js.map +0 -1
  391. package/dist/tools/get-workflow-details.d.ts.map +0 -1
  392. package/dist/tools/get-workflow-details.js.map +0 -1
  393. package/dist/tools/get-workflow-graph.d.ts.map +0 -1
  394. package/dist/tools/get-workflow-graph.js.map +0 -1
  395. package/dist/tools/get-workflow-inputs-schema.d.ts.map +0 -1
  396. package/dist/tools/get-workflow-inputs-schema.js.map +0 -1
  397. package/dist/tools/get-workflow-metrics.d.ts.map +0 -1
  398. package/dist/tools/get-workflow-metrics.js.map +0 -1
  399. package/dist/tools/get-workflow-public-url.d.ts.map +0 -1
  400. package/dist/tools/get-workflow-public-url.js.map +0 -1
  401. package/dist/tools/get-workflow-tags.d.ts.map +0 -1
  402. package/dist/tools/get-workflow-tags.js.map +0 -1
  403. package/dist/tools/index.d.ts.map +0 -1
  404. package/dist/tools/index.js.map +0 -1
  405. package/dist/tools/insert-app-code.d.ts.map +0 -1
  406. package/dist/tools/insert-app-code.js.map +0 -1
  407. package/dist/tools/link-app-workflow.d.ts.map +0 -1
  408. package/dist/tools/link-app-workflow.js.map +0 -1
  409. package/dist/tools/link-recipe.d.ts.map +0 -1
  410. package/dist/tools/link-recipe.js.map +0 -1
  411. package/dist/tools/list-app-files.d.ts.map +0 -1
  412. package/dist/tools/list-app-files.js.map +0 -1
  413. package/dist/tools/list-apps.d.ts.map +0 -1
  414. package/dist/tools/list-apps.js.map +0 -1
  415. package/dist/tools/list-available-nodes.d.ts.map +0 -1
  416. package/dist/tools/list-available-nodes.js.map +0 -1
  417. package/dist/tools/list-custom-nodes.d.ts.map +0 -1
  418. package/dist/tools/list-custom-nodes.js.map +0 -1
  419. package/dist/tools/list-input-presets.d.ts.map +0 -1
  420. package/dist/tools/list-input-presets.js.map +0 -1
  421. package/dist/tools/list-knowledge-categories.d.ts.map +0 -1
  422. package/dist/tools/list-knowledge-categories.js.map +0 -1
  423. package/dist/tools/list-knowledge-documents.d.ts.map +0 -1
  424. package/dist/tools/list-knowledge-documents.js.map +0 -1
  425. package/dist/tools/list-recipe-steps.d.ts.map +0 -1
  426. package/dist/tools/list-recipe-steps.js.map +0 -1
  427. package/dist/tools/list-recipe-stores.d.ts.map +0 -1
  428. package/dist/tools/list-recipe-stores.js.map +0 -1
  429. package/dist/tools/list-recipes.d.ts.map +0 -1
  430. package/dist/tools/list-recipes.js.map +0 -1
  431. package/dist/tools/list-shared-results.d.ts.map +0 -1
  432. package/dist/tools/list-shared-results.js.map +0 -1
  433. package/dist/tools/list-user-teams.d.ts.map +0 -1
  434. package/dist/tools/list-user-teams.js.map +0 -1
  435. package/dist/tools/list-workflows.d.ts.map +0 -1
  436. package/dist/tools/list-workflows.js.map +0 -1
  437. package/dist/tools/move-document-to-category.d.ts.map +0 -1
  438. package/dist/tools/move-document-to-category.js.map +0 -1
  439. package/dist/tools/prepend-app-code.d.ts.map +0 -1
  440. package/dist/tools/prepend-app-code.js.map +0 -1
  441. package/dist/tools/publish-app.d.ts.map +0 -1
  442. package/dist/tools/publish-app.js.map +0 -1
  443. package/dist/tools/query-knowledge-base.d.ts.map +0 -1
  444. package/dist/tools/query-knowledge-base.js.map +0 -1
  445. package/dist/tools/rename-app-file.d.ts.map +0 -1
  446. package/dist/tools/rename-app-file.js.map +0 -1
  447. package/dist/tools/reprocess-document.d.ts.map +0 -1
  448. package/dist/tools/reprocess-document.js.map +0 -1
  449. package/dist/tools/retry-execution.d.ts.map +0 -1
  450. package/dist/tools/retry-execution.js.map +0 -1
  451. package/dist/tools/search-apps.d.ts.map +0 -1
  452. package/dist/tools/search-apps.js.map +0 -1
  453. package/dist/tools/search-public-custom-nodes.d.ts.map +0 -1
  454. package/dist/tools/search-public-custom-nodes.js.map +0 -1
  455. package/dist/tools/search-workflows.d.ts.map +0 -1
  456. package/dist/tools/search-workflows.js.map +0 -1
  457. package/dist/tools/search.d.ts.map +0 -1
  458. package/dist/tools/search.js.map +0 -1
  459. package/dist/tools/set-app-entry-file.d.ts.map +0 -1
  460. package/dist/tools/set-app-entry-file.js.map +0 -1
  461. package/dist/tools/set-workflow-tags.d.ts.map +0 -1
  462. package/dist/tools/set-workflow-tags.js.map +0 -1
  463. package/dist/tools/stream-execution.d.ts.map +0 -1
  464. package/dist/tools/stream-execution.js.map +0 -1
  465. package/dist/tools/toggle-community-inputs.d.ts.map +0 -1
  466. package/dist/tools/toggle-community-inputs.js.map +0 -1
  467. package/dist/tools/toggle-custom-node-visibility.d.ts.map +0 -1
  468. package/dist/tools/toggle-custom-node-visibility.js.map +0 -1
  469. package/dist/tools/toggle-workflow-public.d.ts.map +0 -1
  470. package/dist/tools/toggle-workflow-public.js.map +0 -1
  471. package/dist/tools/transfer-document-ownership.d.ts.map +0 -1
  472. package/dist/tools/transfer-document-ownership.js.map +0 -1
  473. package/dist/tools/unlink-app-workflow.d.ts.map +0 -1
  474. package/dist/tools/unlink-app-workflow.js.map +0 -1
  475. package/dist/tools/unpublish-app.d.ts.map +0 -1
  476. package/dist/tools/unpublish-app.js.map +0 -1
  477. package/dist/tools/update-app-file.d.ts.map +0 -1
  478. package/dist/tools/update-app-file.js.map +0 -1
  479. package/dist/tools/update-app.d.ts.map +0 -1
  480. package/dist/tools/update-app.js.map +0 -1
  481. package/dist/tools/update-custom-node.d.ts.map +0 -1
  482. package/dist/tools/update-custom-node.js.map +0 -1
  483. package/dist/tools/update-input-preset.d.ts.map +0 -1
  484. package/dist/tools/update-input-preset.js.map +0 -1
  485. package/dist/tools/update-knowledge-category.d.ts.map +0 -1
  486. package/dist/tools/update-knowledge-category.js.map +0 -1
  487. package/dist/tools/update-node.d.ts.map +0 -1
  488. package/dist/tools/update-node.js.map +0 -1
  489. package/dist/tools/update-recipe-step.d.ts.map +0 -1
  490. package/dist/tools/update-recipe-step.js.map +0 -1
  491. package/dist/tools/update-recipe-store.d.ts.map +0 -1
  492. package/dist/tools/update-recipe-store.js.map +0 -1
  493. package/dist/tools/update-recipe.d.ts.map +0 -1
  494. package/dist/tools/update-recipe.js.map +0 -1
  495. package/dist/tools/upload-document-from-url.d.ts.map +0 -1
  496. package/dist/tools/upload-document-from-url.js.map +0 -1
  497. package/dist/tools/upload-text-document.d.ts.map +0 -1
  498. package/dist/tools/upload-text-document.js.map +0 -1
  499. package/dist/tools/validate-workflow.d.ts.map +0 -1
  500. package/dist/tools/validate-workflow.js.map +0 -1
  501. package/dist/tools/vote-custom-node.d.ts.map +0 -1
  502. package/dist/tools/vote-custom-node.js.map +0 -1
  503. package/dist/tools/vote-input-preset.d.ts.map +0 -1
  504. package/dist/tools/vote-input-preset.js.map +0 -1
  505. package/dist/tools/vote-recipe.d.ts.map +0 -1
  506. package/dist/tools/vote-recipe.js.map +0 -1
  507. package/dist/tools/vote-shared-result.d.ts.map +0 -1
  508. package/dist/tools/vote-shared-result.js.map +0 -1
  509. package/dist/tools/vote-workflow.d.ts.map +0 -1
  510. package/dist/tools/vote-workflow.js.map +0 -1
  511. package/dist/types.d.ts.map +0 -1
  512. package/dist/types.js.map +0 -1
  513. package/dist/utils/script-validator.d.ts.map +0 -1
  514. package/dist/utils/script-validator.js.map +0 -1
@@ -1,82 +1,76 @@
1
- /**
2
- * get_app_template Tool
3
- *
4
- * Get example code and templates for creating FlowDot apps.
5
- * No API call required - returns pre-defined templates.
6
- */
7
1
  export const getAppTemplateTool = {
8
2
  name: 'get_app_template',
9
- description: `Get example code and templates for creating FlowDot apps.
10
-
11
- ## EXECUTION ENVIRONMENT
12
- FlowDot apps run in a sandboxed browser iframe with:
13
- - React 18 (global - use React.useState, React.useEffect, etc.)
14
- - Tailwind CSS (full utility classes available)
15
- - FlowDot color tokens: primary-50 to primary-900, secondary-50 to secondary-900
16
- - invokeWorkflow(workflowHash, inputs) - to call linked workflows
17
-
18
- ## CRITICAL CODE RULES
19
- 1. NO IMPORTS - React is global (use React.useState, React.useEffect, React.useRef, etc.)
20
- 2. MUST include export default at the end: export default MyAppName;
21
- 3. Function must be named: function MyAppName() { ... }
22
- 4. Use Tailwind CSS for ALL styling
23
- 5. NO FORM ELEMENTS - Never use <form> tags (sandbox blocks form submissions)
24
- 6. ALL BUTTONS need type="button" to prevent unwanted form submission behavior
25
-
26
- ## IMPORTANT: NO FORM ELEMENTS
27
- The sandbox does not allow form submissions. NEVER use <form> tags.
28
-
29
- ❌ WRONG:
30
- <form onSubmit={handleSubmit}>
31
- <button type="submit">Submit</button>
32
- </form>
33
-
34
- ✅ CORRECT:
35
- <div>
36
- <input onKeyDown={(e) => e.key === 'Enter' && handleClick()} />
37
- <button type="button" onClick={handleClick}>Submit</button>
38
- </div>
39
-
40
- ## WORKFLOW RESPONSE FORMAT
41
- invokeWorkflow returns data in this structure:
42
- {
43
- "data": {
44
- "[nodeId]": {
45
- "nodeId": "uuid",
46
- "nodeTitle": "My Output Node",
47
- "nodeType": "text_output",
48
- "outputs": {
49
- "Consolidated Text": { "value": "the actual data", "metadata": {...} }
50
- }
51
- }
52
- }
53
- }
54
-
55
- IMPORTANT: Use this helper function to extract outputs safely:
56
- const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
57
- if (!result?.data) return null;
58
- const node = Object.values(result.data).find(n => n.nodeTitle === nodeTitle);
59
- return node?.outputs?.[socketName]?.value;
60
- };
61
-
62
- Example:
63
- const result = await invokeWorkflow('hash', { input });
64
- const data = getNodeOutput(result, 'Output Node');
65
- if (data) { /* use data */ }
66
-
67
- ## DISPLAY MODES
68
- Set config.displayMode to:
69
- - "windowed": Standard view with FlowDot header (default)
70
- - "fullscreen": Full viewport, minimal floating control bar
71
- - "embedded": No FlowDot UI, for iframe embedding
72
-
73
- Available templates:
74
- - "basic" - Simple form that invokes a workflow
75
- - "chat" - Chat interface with streaming
76
- - "dashboard" - Dashboard with multiple workflow calls
77
- - "form-builder" - Dynamic form based on workflow schema
78
- - "data-viewer" - Display workflow results in tables/charts
79
-
3
+ description: `Get example code and templates for creating FlowDot apps.
4
+
5
+ ## EXECUTION ENVIRONMENT
6
+ FlowDot apps run in a sandboxed browser iframe with:
7
+ - React 18 (global - use React.useState, React.useEffect, etc.)
8
+ - Tailwind CSS (full utility classes available)
9
+ - FlowDot color tokens: primary-50 to primary-900, secondary-50 to secondary-900
10
+ - invokeWorkflow(workflowHash, inputs) - to call linked workflows
11
+
12
+ ## CRITICAL CODE RULES
13
+ 1. NO IMPORTS - React is global (use React.useState, React.useEffect, React.useRef, etc.)
14
+ 2. MUST include export default at the end: export default MyAppName;
15
+ 3. Function must be named: function MyAppName() { ... }
16
+ 4. Use Tailwind CSS for ALL styling
17
+ 5. NO FORM ELEMENTS - Never use <form> tags (sandbox blocks form submissions)
18
+ 6. ALL BUTTONS need type="button" to prevent unwanted form submission behavior
19
+
20
+ ## IMPORTANT: NO FORM ELEMENTS
21
+ The sandbox does not allow form submissions. NEVER use <form> tags.
22
+
23
+ ❌ WRONG:
24
+ <form onSubmit={handleSubmit}>
25
+ <button type="submit">Submit</button>
26
+ </form>
27
+
28
+ ✅ CORRECT:
29
+ <div>
30
+ <input onKeyDown={(e) => e.key === 'Enter' && handleClick()} />
31
+ <button type="button" onClick={handleClick}>Submit</button>
32
+ </div>
33
+
34
+ ## WORKFLOW RESPONSE FORMAT
35
+ invokeWorkflow returns data in this structure:
36
+ {
37
+ "data": {
38
+ "[nodeId]": {
39
+ "nodeId": "uuid",
40
+ "nodeTitle": "My Output Node",
41
+ "nodeType": "text_output",
42
+ "outputs": {
43
+ "Consolidated Text": { "value": "the actual data", "metadata": {...} }
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ IMPORTANT: Use this helper function to extract outputs safely:
50
+ const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
51
+ if (!result?.data) return null;
52
+ const node = Object.values(result.data).find(n => n.nodeTitle === nodeTitle);
53
+ return node?.outputs?.[socketName]?.value;
54
+ };
55
+
56
+ Example:
57
+ const result = await invokeWorkflow('hash', { input });
58
+ const data = getNodeOutput(result, 'Output Node');
59
+ if (data) { /* use data */ }
60
+
61
+ ## DISPLAY MODES
62
+ Set config.displayMode to:
63
+ - "windowed": Standard view with FlowDot header (default)
64
+ - "fullscreen": Full viewport, minimal floating control bar
65
+ - "embedded": No FlowDot UI, for iframe embedding
66
+
67
+ Available templates:
68
+ - "basic" - Simple form that invokes a workflow
69
+ - "chat" - Chat interface with streaming
70
+ - "dashboard" - Dashboard with multiple workflow calls
71
+ - "form-builder" - Dynamic form based on workflow schema
72
+ - "data-viewer" - Display workflow results in tables/charts
73
+
80
74
  You can also request "all" to see all templates at once.`,
81
75
  inputSchema: {
82
76
  type: 'object',
@@ -93,667 +87,667 @@ const TEMPLATES = {
93
87
  basic: {
94
88
  name: 'Basic Form App',
95
89
  description: 'A simple form that submits data to a workflow and displays results.',
96
- code: `function BasicFormApp() {
97
- const [input, setInput] = React.useState('');
98
- const [result, setResult] = React.useState(null);
99
- const [loading, setLoading] = React.useState(false);
100
- const [error, setError] = React.useState(null);
101
-
102
- // Helper to extract output from workflow response by node title
103
- const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
104
- if (!result?.data) return null;
105
- const node = Object.values(result.data).find(n => n.nodeTitle === nodeTitle);
106
- return node?.outputs?.[socketName]?.value;
107
- };
108
-
109
- const handleSubmit = async () => {
110
- if (!input.trim() || loading) return;
111
-
112
- setLoading(true);
113
- setError(null);
114
-
115
- try {
116
- // Replace 'YOUR_WORKFLOW_HASH' with your actual workflow hash
117
- const response = await invokeWorkflow('YOUR_WORKFLOW_HASH', {
118
- text: input
119
- });
120
- // Extract the output - replace 'Output' with your node's title
121
- const output = getNodeOutput(response, 'Output');
122
- setResult(output || response);
123
- } catch (err) {
124
- setError(err.message || 'An error occurred');
125
- } finally {
126
- setLoading(false);
127
- }
128
- };
129
-
130
- const handleKeyDown = (e) => {
131
- if (e.key === 'Enter' && !loading) {
132
- handleSubmit();
133
- }
134
- };
135
-
136
- return (
137
- <div className="min-h-screen bg-gray-50 p-6">
138
- <div className="max-w-2xl mx-auto">
139
- <h1 className="text-2xl font-bold mb-6">My FlowDot App</h1>
140
-
141
- <div className="space-y-4">
142
- <div>
143
- <label className="block text-sm font-medium mb-1">Input</label>
144
- <input
145
- type="text"
146
- value={input}
147
- onChange={(e) => setInput(e.target.value)}
148
- onKeyDown={handleKeyDown}
149
- placeholder="Enter your text..."
150
- className="w-full p-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
151
- disabled={loading}
152
- />
153
- </div>
154
-
155
- <button
156
- type="button"
157
- onClick={handleSubmit}
158
- disabled={loading || !input.trim()}
159
- className="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 disabled:opacity-50"
160
- >
161
- {loading ? 'Processing...' : 'Submit'}
162
- </button>
163
- </div>
164
-
165
- {error && (
166
- <div className="mt-4 p-4 bg-red-50 text-red-700 rounded-lg">
167
- {error}
168
- </div>
169
- )}
170
-
171
- {result && (
172
- <div className="mt-6 p-4 bg-gray-50 rounded-lg">
173
- <h2 className="font-semibold mb-2">Result:</h2>
174
- <pre className="whitespace-pre-wrap text-sm">
175
- {typeof result === 'string' ? result : JSON.stringify(result, null, 2)}
176
- </pre>
177
- </div>
178
- )}
179
- </div>
180
- </div>
181
- );
182
- }
183
-
90
+ code: `function BasicFormApp() {
91
+ const [input, setInput] = React.useState('');
92
+ const [result, setResult] = React.useState(null);
93
+ const [loading, setLoading] = React.useState(false);
94
+ const [error, setError] = React.useState(null);
95
+
96
+ // Helper to extract output from workflow response by node title
97
+ const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
98
+ if (!result?.data) return null;
99
+ const node = Object.values(result.data).find(n => n.nodeTitle === nodeTitle);
100
+ return node?.outputs?.[socketName]?.value;
101
+ };
102
+
103
+ const handleSubmit = async () => {
104
+ if (!input.trim() || loading) return;
105
+
106
+ setLoading(true);
107
+ setError(null);
108
+
109
+ try {
110
+ // Replace 'YOUR_WORKFLOW_HASH' with your actual workflow hash
111
+ const response = await invokeWorkflow('YOUR_WORKFLOW_HASH', {
112
+ text: input
113
+ });
114
+ // Extract the output - replace 'Output' with your node's title
115
+ const output = getNodeOutput(response, 'Output');
116
+ setResult(output || response);
117
+ } catch (err) {
118
+ setError(err.message || 'An error occurred');
119
+ } finally {
120
+ setLoading(false);
121
+ }
122
+ };
123
+
124
+ const handleKeyDown = (e) => {
125
+ if (e.key === 'Enter' && !loading) {
126
+ handleSubmit();
127
+ }
128
+ };
129
+
130
+ return (
131
+ <div className="min-h-screen bg-gray-50 p-6">
132
+ <div className="max-w-2xl mx-auto">
133
+ <h1 className="text-2xl font-bold mb-6">My FlowDot App</h1>
134
+
135
+ <div className="space-y-4">
136
+ <div>
137
+ <label className="block text-sm font-medium mb-1">Input</label>
138
+ <input
139
+ type="text"
140
+ value={input}
141
+ onChange={(e) => setInput(e.target.value)}
142
+ onKeyDown={handleKeyDown}
143
+ placeholder="Enter your text..."
144
+ className="w-full p-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
145
+ disabled={loading}
146
+ />
147
+ </div>
148
+
149
+ <button
150
+ type="button"
151
+ onClick={handleSubmit}
152
+ disabled={loading || !input.trim()}
153
+ className="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 disabled:opacity-50"
154
+ >
155
+ {loading ? 'Processing...' : 'Submit'}
156
+ </button>
157
+ </div>
158
+
159
+ {error && (
160
+ <div className="mt-4 p-4 bg-red-50 text-red-700 rounded-lg">
161
+ {error}
162
+ </div>
163
+ )}
164
+
165
+ {result && (
166
+ <div className="mt-6 p-4 bg-gray-50 rounded-lg">
167
+ <h2 className="font-semibold mb-2">Result:</h2>
168
+ <pre className="whitespace-pre-wrap text-sm">
169
+ {typeof result === 'string' ? result : JSON.stringify(result, null, 2)}
170
+ </pre>
171
+ </div>
172
+ )}
173
+ </div>
174
+ </div>
175
+ );
176
+ }
177
+
184
178
  export default BasicFormApp;`,
185
179
  },
186
180
  chat: {
187
181
  name: 'Chat Interface',
188
182
  description: 'A chat-style interface for conversational workflows.',
189
- code: `function ChatApp() {
190
- const [messages, setMessages] = React.useState([]);
191
- const [input, setInput] = React.useState('');
192
- const [loading, setLoading] = React.useState(false);
193
- const messagesEndRef = React.useRef(null);
194
-
195
- // Helper to extract output from workflow response by node title
196
- const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
197
- const node = Object.values(result?.data || {}).find(n => n.nodeTitle === nodeTitle);
198
- return node?.outputs?.[socketName]?.value;
199
- };
200
-
201
- const scrollToBottom = () => {
202
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
203
- };
204
-
205
- React.useEffect(() => {
206
- scrollToBottom();
207
- }, [messages]);
208
-
209
- const handleSend = async () => {
210
- if (!input.trim() || loading) return;
211
-
212
- const userMessage = { role: 'user', content: input };
213
- setMessages(prev => [...prev, userMessage]);
214
- setInput('');
215
- setLoading(true);
216
-
217
- try {
218
- // Replace 'YOUR_WORKFLOW_HASH' with your LLM workflow hash
219
- const response = await invokeWorkflow('YOUR_WORKFLOW_HASH', {
220
- message: input,
221
- history: messages.map(m => ({ role: m.role, content: m.content }))
222
- });
223
-
224
- // Extract the response - replace 'Response' with your output node's title
225
- const responseText = getNodeOutput(response, 'Response') || JSON.stringify(response);
226
- const assistantMessage = {
227
- role: 'assistant',
228
- content: responseText
229
- };
230
- setMessages(prev => [...prev, assistantMessage]);
231
- } catch (err) {
232
- setMessages(prev => [...prev, {
233
- role: 'error',
234
- content: err.message || 'Failed to get response'
235
- }]);
236
- } finally {
237
- setLoading(false);
238
- }
239
- };
240
-
241
- const handleKeyPress = (e) => {
242
- if (e.key === 'Enter' && !e.shiftKey) {
243
- e.preventDefault();
244
- handleSend();
245
- }
246
- };
247
-
248
- return (
249
- <div className="flex flex-col h-screen bg-gray-50">
250
- <div className="bg-white border-b p-4">
251
- <h1 className="text-xl font-bold">Chat Assistant</h1>
252
- </div>
253
-
254
- <div className="flex-1 overflow-y-auto p-4 space-y-4">
255
- {messages.length === 0 && (
256
- <div className="text-center text-gray-500 mt-8">
257
- Start a conversation by typing a message below.
258
- </div>
259
- )}
260
-
261
- {messages.map((msg, idx) => (
262
- <div
263
- key={idx}
264
- className={\`flex \${msg.role === 'user' ? 'justify-end' : 'justify-start'}\`}
265
- >
266
- <div
267
- className={\`max-w-[80%] p-3 rounded-lg \${
268
- msg.role === 'user'
269
- ? 'bg-blue-600 text-white'
270
- : msg.role === 'error'
271
- ? 'bg-red-100 text-red-700'
272
- : 'bg-gray-100 text-gray-900'
273
- }\`}
274
- >
275
- <p className="whitespace-pre-wrap">{msg.content}</p>
276
- </div>
277
- </div>
278
- ))}
279
-
280
- {loading && (
281
- <div className="flex justify-start">
282
- <div className="bg-gray-100 p-3 rounded-lg">
283
- <div className="flex space-x-2">
284
- <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" />
285
- <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce delay-100" />
286
- <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce delay-200" />
287
- </div>
288
- </div>
289
- </div>
290
- )}
291
-
292
- <div ref={messagesEndRef} />
293
- </div>
294
-
295
- <div className="border-t bg-white p-4">
296
- <div className="flex space-x-2 max-w-3xl mx-auto">
297
- <input
298
- type="text"
299
- value={input}
300
- onChange={(e) => setInput(e.target.value)}
301
- onKeyPress={handleKeyPress}
302
- placeholder="Type your message..."
303
- className="flex-1 p-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
304
- disabled={loading}
305
- />
306
- <button
307
- onClick={handleSend}
308
- disabled={loading || !input.trim()}
309
- className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50"
310
- >
311
- Send
312
- </button>
313
- </div>
314
- </div>
315
- </div>
316
- );
317
- }
318
-
183
+ code: `function ChatApp() {
184
+ const [messages, setMessages] = React.useState([]);
185
+ const [input, setInput] = React.useState('');
186
+ const [loading, setLoading] = React.useState(false);
187
+ const messagesEndRef = React.useRef(null);
188
+
189
+ // Helper to extract output from workflow response by node title
190
+ const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
191
+ const node = Object.values(result?.data || {}).find(n => n.nodeTitle === nodeTitle);
192
+ return node?.outputs?.[socketName]?.value;
193
+ };
194
+
195
+ const scrollToBottom = () => {
196
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
197
+ };
198
+
199
+ React.useEffect(() => {
200
+ scrollToBottom();
201
+ }, [messages]);
202
+
203
+ const handleSend = async () => {
204
+ if (!input.trim() || loading) return;
205
+
206
+ const userMessage = { role: 'user', content: input };
207
+ setMessages(prev => [...prev, userMessage]);
208
+ setInput('');
209
+ setLoading(true);
210
+
211
+ try {
212
+ // Replace 'YOUR_WORKFLOW_HASH' with your LLM workflow hash
213
+ const response = await invokeWorkflow('YOUR_WORKFLOW_HASH', {
214
+ message: input,
215
+ history: messages.map(m => ({ role: m.role, content: m.content }))
216
+ });
217
+
218
+ // Extract the response - replace 'Response' with your output node's title
219
+ const responseText = getNodeOutput(response, 'Response') || JSON.stringify(response);
220
+ const assistantMessage = {
221
+ role: 'assistant',
222
+ content: responseText
223
+ };
224
+ setMessages(prev => [...prev, assistantMessage]);
225
+ } catch (err) {
226
+ setMessages(prev => [...prev, {
227
+ role: 'error',
228
+ content: err.message || 'Failed to get response'
229
+ }]);
230
+ } finally {
231
+ setLoading(false);
232
+ }
233
+ };
234
+
235
+ const handleKeyPress = (e) => {
236
+ if (e.key === 'Enter' && !e.shiftKey) {
237
+ e.preventDefault();
238
+ handleSend();
239
+ }
240
+ };
241
+
242
+ return (
243
+ <div className="flex flex-col h-screen bg-gray-50">
244
+ <div className="bg-white border-b p-4">
245
+ <h1 className="text-xl font-bold">Chat Assistant</h1>
246
+ </div>
247
+
248
+ <div className="flex-1 overflow-y-auto p-4 space-y-4">
249
+ {messages.length === 0 && (
250
+ <div className="text-center text-gray-500 mt-8">
251
+ Start a conversation by typing a message below.
252
+ </div>
253
+ )}
254
+
255
+ {messages.map((msg, idx) => (
256
+ <div
257
+ key={idx}
258
+ className={\`flex \${msg.role === 'user' ? 'justify-end' : 'justify-start'}\`}
259
+ >
260
+ <div
261
+ className={\`max-w-[80%] p-3 rounded-lg \${
262
+ msg.role === 'user'
263
+ ? 'bg-blue-600 text-white'
264
+ : msg.role === 'error'
265
+ ? 'bg-red-100 text-red-700'
266
+ : 'bg-gray-100 text-gray-900'
267
+ }\`}
268
+ >
269
+ <p className="whitespace-pre-wrap">{msg.content}</p>
270
+ </div>
271
+ </div>
272
+ ))}
273
+
274
+ {loading && (
275
+ <div className="flex justify-start">
276
+ <div className="bg-gray-100 p-3 rounded-lg">
277
+ <div className="flex space-x-2">
278
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" />
279
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce delay-100" />
280
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce delay-200" />
281
+ </div>
282
+ </div>
283
+ </div>
284
+ )}
285
+
286
+ <div ref={messagesEndRef} />
287
+ </div>
288
+
289
+ <div className="border-t bg-white p-4">
290
+ <div className="flex space-x-2 max-w-3xl mx-auto">
291
+ <input
292
+ type="text"
293
+ value={input}
294
+ onChange={(e) => setInput(e.target.value)}
295
+ onKeyPress={handleKeyPress}
296
+ placeholder="Type your message..."
297
+ className="flex-1 p-2 border rounded-lg focus:ring-2 focus:ring-blue-500"
298
+ disabled={loading}
299
+ />
300
+ <button
301
+ onClick={handleSend}
302
+ disabled={loading || !input.trim()}
303
+ className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50"
304
+ >
305
+ Send
306
+ </button>
307
+ </div>
308
+ </div>
309
+ </div>
310
+ );
311
+ }
312
+
319
313
  export default ChatApp;`,
320
314
  },
321
315
  dashboard: {
322
316
  name: 'Dashboard App',
323
317
  description: 'A dashboard that displays data from multiple workflow calls.',
324
- code: `function DashboardApp() {
325
- const [stats, setStats] = React.useState(null);
326
- const [items, setItems] = React.useState([]);
327
- const [loading, setLoading] = React.useState(true);
328
- const [error, setError] = React.useState(null);
329
-
330
- // Helper to extract output from workflow response by node title
331
- const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
332
- const node = Object.values(result?.data || {}).find(n => n.nodeTitle === nodeTitle);
333
- return node?.outputs?.[socketName]?.value;
334
- };
335
-
336
- const loadDashboardData = async () => {
337
- setLoading(true);
338
- setError(null);
339
-
340
- try {
341
- // Load data from multiple workflows in parallel
342
- const [statsResult, itemsResult] = await Promise.all([
343
- invokeWorkflow('STATS_WORKFLOW_HASH', {}),
344
- invokeWorkflow('ITEMS_WORKFLOW_HASH', { limit: 10 })
345
- ]);
346
-
347
- // Extract outputs - replace node titles with your actual node names
348
- const statsData = getNodeOutput(statsResult, 'Stats Output');
349
- const itemsData = getNodeOutput(itemsResult, 'Items Output');
350
-
351
- setStats(statsData ? JSON.parse(statsData) : statsResult);
352
- setItems(itemsData ? JSON.parse(itemsData) : itemsResult.items || []);
353
- } catch (err) {
354
- setError(err.message || 'Failed to load dashboard data');
355
- } finally {
356
- setLoading(false);
357
- }
358
- };
359
-
360
- React.useEffect(() => {
361
- loadDashboardData();
362
- }, []);
363
-
364
- if (loading) {
365
- return (
366
- <div className="min-h-screen bg-gray-50 flex items-center justify-center">
367
- <div className="text-lg text-gray-500">Loading dashboard...</div>
368
- </div>
369
- );
370
- }
371
-
372
- if (error) {
373
- return (
374
- <div className="min-h-screen bg-gray-50 p-6">
375
- <div className="bg-red-50 text-red-700 p-4 rounded-lg">
376
- {error}
377
- <button
378
- onClick={loadDashboardData}
379
- className="ml-4 underline hover:no-underline"
380
- >
381
- Retry
382
- </button>
383
- </div>
384
- </div>
385
- );
386
- }
387
-
388
- return (
389
- <div className="min-h-screen bg-gray-50 p-6 space-y-6">
390
- <div className="flex justify-between items-center">
391
- <h1 className="text-2xl font-bold">Dashboard</h1>
392
- <button
393
- onClick={loadDashboardData}
394
- className="px-4 py-2 bg-gray-100 rounded-lg hover:bg-gray-200"
395
- >
396
- Refresh
397
- </button>
398
- </div>
399
-
400
- {/* Stats Cards */}
401
- <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
402
- {stats && Object.entries(stats).map(([key, value]) => (
403
- <div key={key} className="bg-white p-6 rounded-lg shadow">
404
- <div className="text-sm text-gray-500 uppercase">{key}</div>
405
- <div className="text-3xl font-bold mt-1">
406
- {typeof value === 'number' ? value.toLocaleString() : value}
407
- </div>
408
- </div>
409
- ))}
410
- </div>
411
-
412
- {/* Items Table */}
413
- <div className="bg-white rounded-lg shadow overflow-hidden">
414
- <table className="w-full">
415
- <thead className="bg-gray-50">
416
- <tr>
417
- <th className="px-4 py-3 text-left text-sm font-medium text-gray-500">Name</th>
418
- <th className="px-4 py-3 text-left text-sm font-medium text-gray-500">Status</th>
419
- <th className="px-4 py-3 text-left text-sm font-medium text-gray-500">Date</th>
420
- </tr>
421
- </thead>
422
- <tbody className="divide-y">
423
- {items.map((item, idx) => (
424
- <tr key={idx} className="hover:bg-gray-50">
425
- <td className="px-4 py-3">{item.name}</td>
426
- <td className="px-4 py-3">
427
- <span className={\`px-2 py-1 text-xs rounded-full \${
428
- item.status === 'active' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'
429
- }\`}>
430
- {item.status}
431
- </span>
432
- </td>
433
- <td className="px-4 py-3 text-gray-500">{item.date}</td>
434
- </tr>
435
- ))}
436
- </tbody>
437
- </table>
438
- </div>
439
- </div>
440
- );
441
- }
442
-
318
+ code: `function DashboardApp() {
319
+ const [stats, setStats] = React.useState(null);
320
+ const [items, setItems] = React.useState([]);
321
+ const [loading, setLoading] = React.useState(true);
322
+ const [error, setError] = React.useState(null);
323
+
324
+ // Helper to extract output from workflow response by node title
325
+ const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
326
+ const node = Object.values(result?.data || {}).find(n => n.nodeTitle === nodeTitle);
327
+ return node?.outputs?.[socketName]?.value;
328
+ };
329
+
330
+ const loadDashboardData = async () => {
331
+ setLoading(true);
332
+ setError(null);
333
+
334
+ try {
335
+ // Load data from multiple workflows in parallel
336
+ const [statsResult, itemsResult] = await Promise.all([
337
+ invokeWorkflow('STATS_WORKFLOW_HASH', {}),
338
+ invokeWorkflow('ITEMS_WORKFLOW_HASH', { limit: 10 })
339
+ ]);
340
+
341
+ // Extract outputs - replace node titles with your actual node names
342
+ const statsData = getNodeOutput(statsResult, 'Stats Output');
343
+ const itemsData = getNodeOutput(itemsResult, 'Items Output');
344
+
345
+ setStats(statsData ? JSON.parse(statsData) : statsResult);
346
+ setItems(itemsData ? JSON.parse(itemsData) : itemsResult.items || []);
347
+ } catch (err) {
348
+ setError(err.message || 'Failed to load dashboard data');
349
+ } finally {
350
+ setLoading(false);
351
+ }
352
+ };
353
+
354
+ React.useEffect(() => {
355
+ loadDashboardData();
356
+ }, []);
357
+
358
+ if (loading) {
359
+ return (
360
+ <div className="min-h-screen bg-gray-50 flex items-center justify-center">
361
+ <div className="text-lg text-gray-500">Loading dashboard...</div>
362
+ </div>
363
+ );
364
+ }
365
+
366
+ if (error) {
367
+ return (
368
+ <div className="min-h-screen bg-gray-50 p-6">
369
+ <div className="bg-red-50 text-red-700 p-4 rounded-lg">
370
+ {error}
371
+ <button
372
+ onClick={loadDashboardData}
373
+ className="ml-4 underline hover:no-underline"
374
+ >
375
+ Retry
376
+ </button>
377
+ </div>
378
+ </div>
379
+ );
380
+ }
381
+
382
+ return (
383
+ <div className="min-h-screen bg-gray-50 p-6 space-y-6">
384
+ <div className="flex justify-between items-center">
385
+ <h1 className="text-2xl font-bold">Dashboard</h1>
386
+ <button
387
+ onClick={loadDashboardData}
388
+ className="px-4 py-2 bg-gray-100 rounded-lg hover:bg-gray-200"
389
+ >
390
+ Refresh
391
+ </button>
392
+ </div>
393
+
394
+ {/* Stats Cards */}
395
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
396
+ {stats && Object.entries(stats).map(([key, value]) => (
397
+ <div key={key} className="bg-white p-6 rounded-lg shadow">
398
+ <div className="text-sm text-gray-500 uppercase">{key}</div>
399
+ <div className="text-3xl font-bold mt-1">
400
+ {typeof value === 'number' ? value.toLocaleString() : value}
401
+ </div>
402
+ </div>
403
+ ))}
404
+ </div>
405
+
406
+ {/* Items Table */}
407
+ <div className="bg-white rounded-lg shadow overflow-hidden">
408
+ <table className="w-full">
409
+ <thead className="bg-gray-50">
410
+ <tr>
411
+ <th className="px-4 py-3 text-left text-sm font-medium text-gray-500">Name</th>
412
+ <th className="px-4 py-3 text-left text-sm font-medium text-gray-500">Status</th>
413
+ <th className="px-4 py-3 text-left text-sm font-medium text-gray-500">Date</th>
414
+ </tr>
415
+ </thead>
416
+ <tbody className="divide-y">
417
+ {items.map((item, idx) => (
418
+ <tr key={idx} className="hover:bg-gray-50">
419
+ <td className="px-4 py-3">{item.name}</td>
420
+ <td className="px-4 py-3">
421
+ <span className={\`px-2 py-1 text-xs rounded-full \${
422
+ item.status === 'active' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'
423
+ }\`}>
424
+ {item.status}
425
+ </span>
426
+ </td>
427
+ <td className="px-4 py-3 text-gray-500">{item.date}</td>
428
+ </tr>
429
+ ))}
430
+ </tbody>
431
+ </table>
432
+ </div>
433
+ </div>
434
+ );
435
+ }
436
+
443
437
  export default DashboardApp;`,
444
438
  },
445
439
  'form-builder': {
446
440
  name: 'Dynamic Form Builder',
447
441
  description: 'A form that dynamically generates fields based on workflow input schema.',
448
- code: `function DynamicFormApp() {
449
- const [formData, setFormData] = React.useState({});
450
- const [result, setResult] = React.useState(null);
451
- const [loading, setLoading] = React.useState(false);
452
- const [schemaLoading, setSchemaLoading] = React.useState(true);
453
-
454
- // Define your workflow hash here
455
- const WORKFLOW_HASH = 'YOUR_WORKFLOW_HASH';
456
-
457
- // Helper to extract output from workflow response by node title
458
- const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
459
- if (!result?.data) return null;
460
- const node = Object.values(result.data).find(n => n.nodeTitle === nodeTitle);
461
- return node?.outputs?.[socketName]?.value;
462
- };
463
-
464
- // Define the expected input schema
465
- // This would typically come from the workflow's signature
466
- const inputSchema = [
467
- { name: 'text', type: 'string', description: 'Text input', required: true },
468
- { name: 'count', type: 'number', description: 'Number of items', required: false },
469
- { name: 'enabled', type: 'boolean', description: 'Enable feature', required: false },
470
- { name: 'options', type: 'select', options: ['option1', 'option2', 'option3'], required: false },
471
- ];
472
-
473
- React.useEffect(() => {
474
- // Initialize form data with defaults
475
- const defaults = {};
476
- inputSchema.forEach(field => {
477
- if (field.type === 'boolean') defaults[field.name] = false;
478
- else if (field.type === 'number') defaults[field.name] = 0;
479
- else defaults[field.name] = '';
480
- });
481
- setFormData(defaults);
482
- setSchemaLoading(false);
483
- }, []);
484
-
485
- const handleChange = (name, value) => {
486
- setFormData(prev => ({ ...prev, [name]: value }));
487
- };
488
-
489
- const handleSubmit = async () => {
490
- if (loading) return;
491
-
492
- setLoading(true);
493
-
494
- try {
495
- const response = await invokeWorkflow(WORKFLOW_HASH, formData);
496
- // Extract the output - replace 'Output' with your node's title
497
- const output = getNodeOutput(response, 'Output');
498
- setResult(output || response);
499
- } catch (err) {
500
- setResult({ error: err.message });
501
- } finally {
502
- setLoading(false);
503
- }
504
- };
505
-
506
- const renderField = (field) => {
507
- const value = formData[field.name];
508
-
509
- switch (field.type) {
510
- case 'boolean':
511
- return (
512
- <label className="flex items-center space-x-2">
513
- <input
514
- type="checkbox"
515
- checked={value || false}
516
- onChange={(e) => handleChange(field.name, e.target.checked)}
517
- className="rounded"
518
- />
519
- <span>{field.description}</span>
520
- </label>
521
- );
522
- case 'number':
523
- return (
524
- <input
525
- type="number"
526
- value={value || 0}
527
- onChange={(e) => handleChange(field.name, Number(e.target.value))}
528
- className="w-full p-2 border rounded-lg"
529
- />
530
- );
531
- case 'select':
532
- return (
533
- <select
534
- value={value || ''}
535
- onChange={(e) => handleChange(field.name, e.target.value)}
536
- className="w-full p-2 border rounded-lg"
537
- >
538
- <option value="">Select...</option>
539
- {field.options?.map(opt => (
540
- <option key={opt} value={opt}>{opt}</option>
541
- ))}
542
- </select>
543
- );
544
- default:
545
- return (
546
- <input
547
- type="text"
548
- value={value || ''}
549
- onChange={(e) => handleChange(field.name, e.target.value)}
550
- onKeyDown={(e) => e.key === 'Enter' && !loading && handleSubmit()}
551
- placeholder={field.description}
552
- className="w-full p-2 border rounded-lg"
553
- />
554
- );
555
- }
556
- };
557
-
558
- if (schemaLoading) {
559
- return <div className="min-h-screen bg-gray-50 p-6 text-center">Loading form...</div>;
560
- }
561
-
562
- return (
563
- <div className="min-h-screen bg-gray-50 p-6">
564
- <div className="max-w-2xl mx-auto">
565
- <h1 className="text-2xl font-bold mb-6">Dynamic Form</h1>
566
-
567
- <div className="space-y-4">
568
- {inputSchema.map(field => (
569
- <div key={field.name}>
570
- <label className="block text-sm font-medium mb-1">
571
- {field.name}
572
- {field.required && <span className="text-red-500">*</span>}
573
- </label>
574
- {renderField(field)}
575
- {field.description && field.type !== 'boolean' && (
576
- <p className="text-xs text-gray-500 mt-1">{field.description}</p>
577
- )}
578
- </div>
579
- ))}
580
-
581
- <button
582
- type="button"
583
- onClick={handleSubmit}
584
- disabled={loading}
585
- className="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 disabled:opacity-50"
586
- >
587
- {loading ? 'Processing...' : 'Submit'}
588
- </button>
589
- </div>
590
-
591
- {result && (
592
- <div className="mt-6 p-4 bg-white rounded-lg shadow">
593
- <h2 className="font-semibold mb-2">Result:</h2>
594
- <pre className="whitespace-pre-wrap text-sm overflow-x-auto">
595
- {JSON.stringify(result, null, 2)}
596
- </pre>
597
- </div>
598
- )}
599
- </div>
600
- </div>
601
- );
602
- }
603
-
442
+ code: `function DynamicFormApp() {
443
+ const [formData, setFormData] = React.useState({});
444
+ const [result, setResult] = React.useState(null);
445
+ const [loading, setLoading] = React.useState(false);
446
+ const [schemaLoading, setSchemaLoading] = React.useState(true);
447
+
448
+ // Define your workflow hash here
449
+ const WORKFLOW_HASH = 'YOUR_WORKFLOW_HASH';
450
+
451
+ // Helper to extract output from workflow response by node title
452
+ const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
453
+ if (!result?.data) return null;
454
+ const node = Object.values(result.data).find(n => n.nodeTitle === nodeTitle);
455
+ return node?.outputs?.[socketName]?.value;
456
+ };
457
+
458
+ // Define the expected input schema
459
+ // This would typically come from the workflow's signature
460
+ const inputSchema = [
461
+ { name: 'text', type: 'string', description: 'Text input', required: true },
462
+ { name: 'count', type: 'number', description: 'Number of items', required: false },
463
+ { name: 'enabled', type: 'boolean', description: 'Enable feature', required: false },
464
+ { name: 'options', type: 'select', options: ['option1', 'option2', 'option3'], required: false },
465
+ ];
466
+
467
+ React.useEffect(() => {
468
+ // Initialize form data with defaults
469
+ const defaults = {};
470
+ inputSchema.forEach(field => {
471
+ if (field.type === 'boolean') defaults[field.name] = false;
472
+ else if (field.type === 'number') defaults[field.name] = 0;
473
+ else defaults[field.name] = '';
474
+ });
475
+ setFormData(defaults);
476
+ setSchemaLoading(false);
477
+ }, []);
478
+
479
+ const handleChange = (name, value) => {
480
+ setFormData(prev => ({ ...prev, [name]: value }));
481
+ };
482
+
483
+ const handleSubmit = async () => {
484
+ if (loading) return;
485
+
486
+ setLoading(true);
487
+
488
+ try {
489
+ const response = await invokeWorkflow(WORKFLOW_HASH, formData);
490
+ // Extract the output - replace 'Output' with your node's title
491
+ const output = getNodeOutput(response, 'Output');
492
+ setResult(output || response);
493
+ } catch (err) {
494
+ setResult({ error: err.message });
495
+ } finally {
496
+ setLoading(false);
497
+ }
498
+ };
499
+
500
+ const renderField = (field) => {
501
+ const value = formData[field.name];
502
+
503
+ switch (field.type) {
504
+ case 'boolean':
505
+ return (
506
+ <label className="flex items-center space-x-2">
507
+ <input
508
+ type="checkbox"
509
+ checked={value || false}
510
+ onChange={(e) => handleChange(field.name, e.target.checked)}
511
+ className="rounded"
512
+ />
513
+ <span>{field.description}</span>
514
+ </label>
515
+ );
516
+ case 'number':
517
+ return (
518
+ <input
519
+ type="number"
520
+ value={value || 0}
521
+ onChange={(e) => handleChange(field.name, Number(e.target.value))}
522
+ className="w-full p-2 border rounded-lg"
523
+ />
524
+ );
525
+ case 'select':
526
+ return (
527
+ <select
528
+ value={value || ''}
529
+ onChange={(e) => handleChange(field.name, e.target.value)}
530
+ className="w-full p-2 border rounded-lg"
531
+ >
532
+ <option value="">Select...</option>
533
+ {field.options?.map(opt => (
534
+ <option key={opt} value={opt}>{opt}</option>
535
+ ))}
536
+ </select>
537
+ );
538
+ default:
539
+ return (
540
+ <input
541
+ type="text"
542
+ value={value || ''}
543
+ onChange={(e) => handleChange(field.name, e.target.value)}
544
+ onKeyDown={(e) => e.key === 'Enter' && !loading && handleSubmit()}
545
+ placeholder={field.description}
546
+ className="w-full p-2 border rounded-lg"
547
+ />
548
+ );
549
+ }
550
+ };
551
+
552
+ if (schemaLoading) {
553
+ return <div className="min-h-screen bg-gray-50 p-6 text-center">Loading form...</div>;
554
+ }
555
+
556
+ return (
557
+ <div className="min-h-screen bg-gray-50 p-6">
558
+ <div className="max-w-2xl mx-auto">
559
+ <h1 className="text-2xl font-bold mb-6">Dynamic Form</h1>
560
+
561
+ <div className="space-y-4">
562
+ {inputSchema.map(field => (
563
+ <div key={field.name}>
564
+ <label className="block text-sm font-medium mb-1">
565
+ {field.name}
566
+ {field.required && <span className="text-red-500">*</span>}
567
+ </label>
568
+ {renderField(field)}
569
+ {field.description && field.type !== 'boolean' && (
570
+ <p className="text-xs text-gray-500 mt-1">{field.description}</p>
571
+ )}
572
+ </div>
573
+ ))}
574
+
575
+ <button
576
+ type="button"
577
+ onClick={handleSubmit}
578
+ disabled={loading}
579
+ className="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 disabled:opacity-50"
580
+ >
581
+ {loading ? 'Processing...' : 'Submit'}
582
+ </button>
583
+ </div>
584
+
585
+ {result && (
586
+ <div className="mt-6 p-4 bg-white rounded-lg shadow">
587
+ <h2 className="font-semibold mb-2">Result:</h2>
588
+ <pre className="whitespace-pre-wrap text-sm overflow-x-auto">
589
+ {JSON.stringify(result, null, 2)}
590
+ </pre>
591
+ </div>
592
+ )}
593
+ </div>
594
+ </div>
595
+ );
596
+ }
597
+
604
598
  export default DynamicFormApp;`,
605
599
  },
606
600
  'data-viewer': {
607
601
  name: 'Data Viewer',
608
602
  description: 'Display workflow results in tables and charts.',
609
- code: `function DataViewerApp() {
610
- const [data, setData] = React.useState([]);
611
- const [loading, setLoading] = React.useState(false);
612
- const [viewMode, setViewMode] = React.useState('table'); // 'table' or 'cards'
613
- const [sortField, setSortField] = React.useState(null);
614
- const [sortDirection, setSortDirection] = React.useState('asc');
615
-
616
- // Helper to extract output from workflow response by node title
617
- const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
618
- const node = Object.values(result?.data || {}).find(n => n.nodeTitle === nodeTitle);
619
- return node?.outputs?.[socketName]?.value;
620
- };
621
-
622
- const loadData = async () => {
623
- setLoading(true);
624
- try {
625
- const result = await invokeWorkflow('YOUR_WORKFLOW_HASH', {});
626
- // Extract the data - replace 'Data Output' with your node's title
627
- const outputData = getNodeOutput(result, 'Data Output');
628
- // Parse if it's JSON string, otherwise use as-is
629
- const parsed = outputData ? JSON.parse(outputData) : result;
630
- setData(parsed.items || parsed.data || parsed || []);
631
- } catch (err) {
632
- console.error('Failed to load data:', err);
633
- } finally {
634
- setLoading(false);
635
- }
636
- };
637
-
638
- React.useEffect(() => {
639
- loadData();
640
- }, []);
641
-
642
- const handleSort = (field) => {
643
- if (sortField === field) {
644
- setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc');
645
- } else {
646
- setSortField(field);
647
- setSortDirection('asc');
648
- }
649
- };
650
-
651
- const sortedData = React.useMemo(() => {
652
- if (!sortField) return data;
653
- return [...data].sort((a, b) => {
654
- const aVal = a[sortField];
655
- const bVal = b[sortField];
656
- const direction = sortDirection === 'asc' ? 1 : -1;
657
- if (typeof aVal === 'number') return (aVal - bVal) * direction;
658
- return String(aVal).localeCompare(String(bVal)) * direction;
659
- });
660
- }, [data, sortField, sortDirection]);
661
-
662
- // Get column headers from first item
663
- const columns = data.length > 0 ? Object.keys(data[0]) : [];
664
-
665
- return (
666
- <div className="min-h-screen bg-gray-50 p-6">
667
- <div className="flex justify-between items-center mb-6">
668
- <h1 className="text-2xl font-bold">Data Viewer</h1>
669
- <div className="flex space-x-2">
670
- <button
671
- onClick={() => setViewMode('table')}
672
- className={\`px-3 py-1 rounded \${viewMode === 'table' ? 'bg-blue-600 text-white' : 'bg-gray-100'}\`}
673
- >
674
- Table
675
- </button>
676
- <button
677
- onClick={() => setViewMode('cards')}
678
- className={\`px-3 py-1 rounded \${viewMode === 'cards' ? 'bg-blue-600 text-white' : 'bg-gray-100'}\`}
679
- >
680
- Cards
681
- </button>
682
- <button
683
- onClick={loadData}
684
- disabled={loading}
685
- className="px-3 py-1 bg-gray-100 rounded hover:bg-gray-200 disabled:opacity-50"
686
- >
687
- {loading ? 'Loading...' : 'Refresh'}
688
- </button>
689
- </div>
690
- </div>
691
-
692
- {viewMode === 'table' ? (
693
- <div className="bg-white rounded-lg shadow overflow-x-auto">
694
- <table className="w-full">
695
- <thead className="bg-gray-50">
696
- <tr>
697
- {columns.map(col => (
698
- <th
699
- key={col}
700
- onClick={() => handleSort(col)}
701
- className="px-4 py-3 text-left text-sm font-medium text-gray-500 cursor-pointer hover:bg-gray-100"
702
- >
703
- {col}
704
- {sortField === col && (
705
- <span className="ml-1">{sortDirection === 'asc' ? '↑' : '↓'}</span>
706
- )}
707
- </th>
708
- ))}
709
- </tr>
710
- </thead>
711
- <tbody className="divide-y">
712
- {sortedData.map((row, idx) => (
713
- <tr key={idx} className="hover:bg-gray-50">
714
- {columns.map(col => (
715
- <td key={col} className="px-4 py-3 text-sm">
716
- {typeof row[col] === 'object'
717
- ? JSON.stringify(row[col])
718
- : String(row[col])
719
- }
720
- </td>
721
- ))}
722
- </tr>
723
- ))}
724
- </tbody>
725
- </table>
726
- {data.length === 0 && !loading && (
727
- <div className="text-center py-8 text-gray-500">No data available</div>
728
- )}
729
- </div>
730
- ) : (
731
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
732
- {sortedData.map((item, idx) => (
733
- <div key={idx} className="bg-white p-4 rounded-lg shadow">
734
- {columns.map(col => (
735
- <div key={col} className="mb-2">
736
- <span className="text-xs text-gray-500 uppercase">{col}</span>
737
- <div className="font-medium">
738
- {typeof item[col] === 'object'
739
- ? JSON.stringify(item[col])
740
- : String(item[col])
741
- }
742
- </div>
743
- </div>
744
- ))}
745
- </div>
746
- ))}
747
- </div>
748
- )}
749
-
750
- <div className="mt-4 text-sm text-gray-500">
751
- Showing {data.length} items
752
- </div>
753
- </div>
754
- );
755
- }
756
-
603
+ code: `function DataViewerApp() {
604
+ const [data, setData] = React.useState([]);
605
+ const [loading, setLoading] = React.useState(false);
606
+ const [viewMode, setViewMode] = React.useState('table'); // 'table' or 'cards'
607
+ const [sortField, setSortField] = React.useState(null);
608
+ const [sortDirection, setSortDirection] = React.useState('asc');
609
+
610
+ // Helper to extract output from workflow response by node title
611
+ const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
612
+ const node = Object.values(result?.data || {}).find(n => n.nodeTitle === nodeTitle);
613
+ return node?.outputs?.[socketName]?.value;
614
+ };
615
+
616
+ const loadData = async () => {
617
+ setLoading(true);
618
+ try {
619
+ const result = await invokeWorkflow('YOUR_WORKFLOW_HASH', {});
620
+ // Extract the data - replace 'Data Output' with your node's title
621
+ const outputData = getNodeOutput(result, 'Data Output');
622
+ // Parse if it's JSON string, otherwise use as-is
623
+ const parsed = outputData ? JSON.parse(outputData) : result;
624
+ setData(parsed.items || parsed.data || parsed || []);
625
+ } catch (err) {
626
+ console.error('Failed to load data:', err);
627
+ } finally {
628
+ setLoading(false);
629
+ }
630
+ };
631
+
632
+ React.useEffect(() => {
633
+ loadData();
634
+ }, []);
635
+
636
+ const handleSort = (field) => {
637
+ if (sortField === field) {
638
+ setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc');
639
+ } else {
640
+ setSortField(field);
641
+ setSortDirection('asc');
642
+ }
643
+ };
644
+
645
+ const sortedData = React.useMemo(() => {
646
+ if (!sortField) return data;
647
+ return [...data].sort((a, b) => {
648
+ const aVal = a[sortField];
649
+ const bVal = b[sortField];
650
+ const direction = sortDirection === 'asc' ? 1 : -1;
651
+ if (typeof aVal === 'number') return (aVal - bVal) * direction;
652
+ return String(aVal).localeCompare(String(bVal)) * direction;
653
+ });
654
+ }, [data, sortField, sortDirection]);
655
+
656
+ // Get column headers from first item
657
+ const columns = data.length > 0 ? Object.keys(data[0]) : [];
658
+
659
+ return (
660
+ <div className="min-h-screen bg-gray-50 p-6">
661
+ <div className="flex justify-between items-center mb-6">
662
+ <h1 className="text-2xl font-bold">Data Viewer</h1>
663
+ <div className="flex space-x-2">
664
+ <button
665
+ onClick={() => setViewMode('table')}
666
+ className={\`px-3 py-1 rounded \${viewMode === 'table' ? 'bg-blue-600 text-white' : 'bg-gray-100'}\`}
667
+ >
668
+ Table
669
+ </button>
670
+ <button
671
+ onClick={() => setViewMode('cards')}
672
+ className={\`px-3 py-1 rounded \${viewMode === 'cards' ? 'bg-blue-600 text-white' : 'bg-gray-100'}\`}
673
+ >
674
+ Cards
675
+ </button>
676
+ <button
677
+ onClick={loadData}
678
+ disabled={loading}
679
+ className="px-3 py-1 bg-gray-100 rounded hover:bg-gray-200 disabled:opacity-50"
680
+ >
681
+ {loading ? 'Loading...' : 'Refresh'}
682
+ </button>
683
+ </div>
684
+ </div>
685
+
686
+ {viewMode === 'table' ? (
687
+ <div className="bg-white rounded-lg shadow overflow-x-auto">
688
+ <table className="w-full">
689
+ <thead className="bg-gray-50">
690
+ <tr>
691
+ {columns.map(col => (
692
+ <th
693
+ key={col}
694
+ onClick={() => handleSort(col)}
695
+ className="px-4 py-3 text-left text-sm font-medium text-gray-500 cursor-pointer hover:bg-gray-100"
696
+ >
697
+ {col}
698
+ {sortField === col && (
699
+ <span className="ml-1">{sortDirection === 'asc' ? '↑' : '↓'}</span>
700
+ )}
701
+ </th>
702
+ ))}
703
+ </tr>
704
+ </thead>
705
+ <tbody className="divide-y">
706
+ {sortedData.map((row, idx) => (
707
+ <tr key={idx} className="hover:bg-gray-50">
708
+ {columns.map(col => (
709
+ <td key={col} className="px-4 py-3 text-sm">
710
+ {typeof row[col] === 'object'
711
+ ? JSON.stringify(row[col])
712
+ : String(row[col])
713
+ }
714
+ </td>
715
+ ))}
716
+ </tr>
717
+ ))}
718
+ </tbody>
719
+ </table>
720
+ {data.length === 0 && !loading && (
721
+ <div className="text-center py-8 text-gray-500">No data available</div>
722
+ )}
723
+ </div>
724
+ ) : (
725
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
726
+ {sortedData.map((item, idx) => (
727
+ <div key={idx} className="bg-white p-4 rounded-lg shadow">
728
+ {columns.map(col => (
729
+ <div key={col} className="mb-2">
730
+ <span className="text-xs text-gray-500 uppercase">{col}</span>
731
+ <div className="font-medium">
732
+ {typeof item[col] === 'object'
733
+ ? JSON.stringify(item[col])
734
+ : String(item[col])
735
+ }
736
+ </div>
737
+ </div>
738
+ ))}
739
+ </div>
740
+ ))}
741
+ </div>
742
+ )}
743
+
744
+ <div className="mt-4 text-sm text-gray-500">
745
+ Showing {data.length} items
746
+ </div>
747
+ </div>
748
+ );
749
+ }
750
+
757
751
  export default DataViewerApp;`,
758
752
  },
759
753
  };
@@ -762,79 +756,79 @@ export async function handleGetAppTemplate(args) {
762
756
  if (templateName === 'all') {
763
757
  const allTemplates = Object.entries(TEMPLATES)
764
758
  .map(([key, template]) => {
765
- return `## ${template.name} (${key})
766
-
767
- ${template.description}
768
-
769
- \`\`\`jsx
770
- ${template.code}
759
+ return `## ${template.name} (${key})
760
+
761
+ ${template.description}
762
+
763
+ \`\`\`jsx
764
+ ${template.code}
771
765
  \`\`\``;
772
766
  })
773
767
  .join('\n\n---\n\n');
774
- const text = `# FlowDot App Templates
775
-
776
- Below are all available app templates. Each template demonstrates a different pattern for building FlowDot apps.
777
-
778
- ## EXECUTION ENVIRONMENT
779
-
780
- Apps run in a sandboxed browser iframe with:
781
- - React 18 (global - use React.useState, React.useEffect, etc.)
782
- - Tailwind CSS (full utility classes available)
783
- - FlowDot color tokens: primary-50 to primary-900, secondary-50 to secondary-900
784
- - invokeWorkflow(workflowHash, inputs) - to call linked workflows
785
-
786
- ## CRITICAL CODE RULES
787
-
788
- 1. **NO IMPORTS** - React is global (use React.useState, React.useEffect, React.useRef, React.useMemo, React.useCallback)
789
- 2. **NO EXPORTS** - Just define your function, the system handles the rest
790
- 3. **Function naming** - Must be: function MyAppName() { ... }
791
- 4. **Styling** - Use Tailwind CSS for ALL styling (no inline style objects, no CSS-in-JS)
792
-
793
- ## WORKFLOW RESPONSE FORMAT
794
-
795
- invokeWorkflow returns data in this structure:
796
- \`\`\`json
797
- {
798
- "data": {
799
- "[nodeId]": {
800
- "nodeId": "uuid",
801
- "nodeTitle": "My Output Node",
802
- "nodeType": "text_output",
803
- "outputs": {
804
- "Consolidated Text": { "value": "the actual data", "metadata": {...} }
805
- }
806
- }
807
- }
808
- }
809
- \`\`\`
810
-
811
- **IMPORTANT**: Use this helper function to extract outputs by node title:
812
- \`\`\`javascript
813
- const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
814
- const node = Object.values(result?.data || {}).find(n => n.nodeTitle === nodeTitle);
815
- return node?.outputs?.[socketName]?.value;
816
- };
817
- \`\`\`
818
-
819
- Example: \`const weatherData = getNodeOutput(result, 'Weather Results', 'Consolidated Text');\`
820
-
821
- ## DISPLAY MODES
822
-
823
- Set config.displayMode when creating/updating an app:
824
- - "windowed": Standard view with FlowDot header (default)
825
- - "fullscreen": Full viewport, minimal floating control bar
826
- - "embedded": No FlowDot UI, for iframe embedding
827
-
828
- ---
829
-
830
- ${allTemplates}
831
-
832
- ## Tips
833
-
834
- 1. Replace 'YOUR_WORKFLOW_HASH' with your actual workflow hash
835
- 2. Link workflows to your app using link_app_workflow
836
- 3. Test locally before publishing
837
- 4. Use mobile_code for mobile-specific layouts
768
+ const text = `# FlowDot App Templates
769
+
770
+ Below are all available app templates. Each template demonstrates a different pattern for building FlowDot apps.
771
+
772
+ ## EXECUTION ENVIRONMENT
773
+
774
+ Apps run in a sandboxed browser iframe with:
775
+ - React 18 (global - use React.useState, React.useEffect, etc.)
776
+ - Tailwind CSS (full utility classes available)
777
+ - FlowDot color tokens: primary-50 to primary-900, secondary-50 to secondary-900
778
+ - invokeWorkflow(workflowHash, inputs) - to call linked workflows
779
+
780
+ ## CRITICAL CODE RULES
781
+
782
+ 1. **NO IMPORTS** - React is global (use React.useState, React.useEffect, React.useRef, React.useMemo, React.useCallback)
783
+ 2. **NO EXPORTS** - Just define your function, the system handles the rest
784
+ 3. **Function naming** - Must be: function MyAppName() { ... }
785
+ 4. **Styling** - Use Tailwind CSS for ALL styling (no inline style objects, no CSS-in-JS)
786
+
787
+ ## WORKFLOW RESPONSE FORMAT
788
+
789
+ invokeWorkflow returns data in this structure:
790
+ \`\`\`json
791
+ {
792
+ "data": {
793
+ "[nodeId]": {
794
+ "nodeId": "uuid",
795
+ "nodeTitle": "My Output Node",
796
+ "nodeType": "text_output",
797
+ "outputs": {
798
+ "Consolidated Text": { "value": "the actual data", "metadata": {...} }
799
+ }
800
+ }
801
+ }
802
+ }
803
+ \`\`\`
804
+
805
+ **IMPORTANT**: Use this helper function to extract outputs by node title:
806
+ \`\`\`javascript
807
+ const getNodeOutput = (result, nodeTitle, socketName = 'Consolidated Text') => {
808
+ const node = Object.values(result?.data || {}).find(n => n.nodeTitle === nodeTitle);
809
+ return node?.outputs?.[socketName]?.value;
810
+ };
811
+ \`\`\`
812
+
813
+ Example: \`const weatherData = getNodeOutput(result, 'Weather Results', 'Consolidated Text');\`
814
+
815
+ ## DISPLAY MODES
816
+
817
+ Set config.displayMode when creating/updating an app:
818
+ - "windowed": Standard view with FlowDot header (default)
819
+ - "fullscreen": Full viewport, minimal floating control bar
820
+ - "embedded": No FlowDot UI, for iframe embedding
821
+
822
+ ---
823
+
824
+ ${allTemplates}
825
+
826
+ ## Tips
827
+
828
+ 1. Replace 'YOUR_WORKFLOW_HASH' with your actual workflow hash
829
+ 2. Link workflows to your app using link_app_workflow
830
+ 3. Test locally before publishing
831
+ 4. Use mobile_code for mobile-specific layouts
838
832
  5. Use min-h-screen for fullscreen apps`;
839
833
  return {
840
834
  content: [{ type: 'text', text }],
@@ -847,54 +841,53 @@ ${allTemplates}
847
841
  content: [{ type: 'text', text: `Unknown template: "${templateName}". Available templates: ${available}, all` }],
848
842
  };
849
843
  }
850
- const text = `# ${template.name}
851
-
852
- ${template.description}
853
-
854
- ## Code
855
-
856
- \`\`\`jsx
857
- ${template.code}
858
- \`\`\`
859
-
860
- ## Usage
861
-
862
- 1. Create a new app using create_app with this code
863
- 2. Replace 'YOUR_WORKFLOW_HASH' with your actual workflow hash
864
- 3. Replace node titles in getNodeOutput() calls with your actual node names
865
- 4. Link the workflow using link_app_workflow
866
- 5. Test and publish when ready
867
-
868
- ## Workflow Response Format
869
-
870
- invokeWorkflow returns data in this structure:
871
- \`\`\`json
872
- {
873
- "data": {
874
- "[nodeId]": {
875
- "nodeId": "uuid",
876
- "nodeTitle": "My Output Node",
877
- "outputs": { "Consolidated Text": { "value": "the data" } }
878
- }
879
- }
880
- }
881
- \`\`\`
882
-
883
- Use the getNodeOutput helper (included in templates) to extract by node title.
884
-
885
- ## Critical Rules
886
-
887
- - **NO IMPORTS** - React is global (use React.useState, React.useEffect, etc.)
888
- - **NO EXPORTS** - Just define your function
889
- - **invokeWorkflow(hash, inputs)** - Call a linked workflow
890
- - **Tailwind CSS** - Full Tailwind for styling
891
-
892
- ## Other Templates
893
-
894
- Available templates: ${Object.keys(TEMPLATES).join(', ')}
844
+ const text = `# ${template.name}
845
+
846
+ ${template.description}
847
+
848
+ ## Code
849
+
850
+ \`\`\`jsx
851
+ ${template.code}
852
+ \`\`\`
853
+
854
+ ## Usage
855
+
856
+ 1. Create a new app using create_app with this code
857
+ 2. Replace 'YOUR_WORKFLOW_HASH' with your actual workflow hash
858
+ 3. Replace node titles in getNodeOutput() calls with your actual node names
859
+ 4. Link the workflow using link_app_workflow
860
+ 5. Test and publish when ready
861
+
862
+ ## Workflow Response Format
863
+
864
+ invokeWorkflow returns data in this structure:
865
+ \`\`\`json
866
+ {
867
+ "data": {
868
+ "[nodeId]": {
869
+ "nodeId": "uuid",
870
+ "nodeTitle": "My Output Node",
871
+ "outputs": { "Consolidated Text": { "value": "the data" } }
872
+ }
873
+ }
874
+ }
875
+ \`\`\`
876
+
877
+ Use the getNodeOutput helper (included in templates) to extract by node title.
878
+
879
+ ## Critical Rules
880
+
881
+ - **NO IMPORTS** - React is global (use React.useState, React.useEffect, etc.)
882
+ - **NO EXPORTS** - Just define your function
883
+ - **invokeWorkflow(hash, inputs)** - Call a linked workflow
884
+ - **Tailwind CSS** - Full Tailwind for styling
885
+
886
+ ## Other Templates
887
+
888
+ Available templates: ${Object.keys(TEMPLATES).join(', ')}
895
889
  Use \`get_app_template(template: "all")\` to see all templates.`;
896
890
  return {
897
891
  content: [{ type: 'text', text }],
898
892
  };
899
893
  }
900
- //# sourceMappingURL=get-app-template.js.map