mulmoclaude 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (408) hide show
  1. package/README.md +44 -0
  2. package/bin/mulmoclaude.js +202 -0
  3. package/bin/prepare-dist.js +93 -0
  4. package/client/assets/chunk-vKJrgz-R-C_I3GbVV.js +1 -0
  5. package/client/assets/html2canvas-Cx501zZr-BF5dYYkY.js +5 -0
  6. package/client/assets/index-D8rhwXLq.js +4906 -0
  7. package/client/assets/index-KNLBjwuh.css +1 -0
  8. package/client/assets/index.es-D4YyL_Dg-BfRHLTZV.js +5 -0
  9. package/client/assets/material-icons-Dr0goTwe.woff +0 -0
  10. package/client/assets/material-icons-kAwBdRge.woff2 +0 -0
  11. package/client/assets/material-icons-outlined-BpWbwl2n.woff +0 -0
  12. package/client/assets/material-icons-outlined-DZhiGvEA.woff2 +0 -0
  13. package/client/assets/material-icons-round-BDlwx-sv.woff +0 -0
  14. package/client/assets/material-icons-round-DrirKXBx.woff2 +0 -0
  15. package/client/assets/material-icons-sharp-CH1KkVu7.woff +0 -0
  16. package/client/assets/material-icons-sharp-gidztirS.woff2 +0 -0
  17. package/client/assets/material-icons-two-tone-B7wz7mED.woff +0 -0
  18. package/client/assets/material-icons-two-tone-DuNIpaEj.woff2 +0 -0
  19. package/client/assets/mulmo_bw-ERmkSv0a.png +0 -0
  20. package/client/assets/purify.es-Fx1Nqyry-PeS5RUhs.js +2 -0
  21. package/client/assets/typeof-DBp4T-Ny-BC0P-2DM.js +1 -0
  22. package/client/index.html +28 -0
  23. package/package.json +66 -0
  24. package/server/agent/attachmentConverter.ts +270 -0
  25. package/server/agent/config.ts +414 -0
  26. package/server/agent/index.ts +260 -0
  27. package/server/agent/mcp-server.ts +412 -0
  28. package/server/agent/mcp-tools/index.ts +63 -0
  29. package/server/agent/mcp-tools/x.ts +188 -0
  30. package/server/agent/plugin-names.ts +75 -0
  31. package/server/agent/prompt.ts +349 -0
  32. package/server/agent/resumeFailover.ts +129 -0
  33. package/server/agent/sandboxMounts.ts +329 -0
  34. package/server/agent/stream.ts +194 -0
  35. package/server/api/auth/bearerAuth.ts +61 -0
  36. package/server/api/auth/token.ts +98 -0
  37. package/server/api/csrfGuard.ts +85 -0
  38. package/server/api/routes/agent.ts +478 -0
  39. package/server/api/routes/chart.ts +98 -0
  40. package/server/api/routes/chat-index.ts +46 -0
  41. package/server/api/routes/config.ts +258 -0
  42. package/server/api/routes/dispatchResponse.ts +79 -0
  43. package/server/api/routes/files.ts +812 -0
  44. package/server/api/routes/html.ts +101 -0
  45. package/server/api/routes/image.ts +169 -0
  46. package/server/api/routes/mulmo-script.ts +712 -0
  47. package/server/api/routes/mulmoScriptValidate.ts +101 -0
  48. package/server/api/routes/notifications.ts +69 -0
  49. package/server/api/routes/pdf.ts +163 -0
  50. package/server/api/routes/plugins.ts +276 -0
  51. package/server/api/routes/presentHtml.ts +48 -0
  52. package/server/api/routes/roles.ts +125 -0
  53. package/server/api/routes/scheduler.ts +153 -0
  54. package/server/api/routes/schedulerHandlers.ts +151 -0
  55. package/server/api/routes/schedulerTasks.ts +163 -0
  56. package/server/api/routes/sessions.ts +294 -0
  57. package/server/api/routes/sessionsCursor.ts +59 -0
  58. package/server/api/routes/skills.ts +195 -0
  59. package/server/api/routes/sources.ts +540 -0
  60. package/server/api/routes/todos.ts +263 -0
  61. package/server/api/routes/todosColumnsHandlers.ts +347 -0
  62. package/server/api/routes/todosHandlers.ts +274 -0
  63. package/server/api/routes/todosItemsHandlers.ts +386 -0
  64. package/server/api/routes/wiki/pageIndex.ts +53 -0
  65. package/server/api/routes/wiki.ts +363 -0
  66. package/server/api/sandboxStatus.ts +64 -0
  67. package/server/events/notifications.ts +160 -0
  68. package/server/events/pub-sub/index.ts +45 -0
  69. package/server/events/relay-client.ts +288 -0
  70. package/server/events/scheduler-adapter.ts +302 -0
  71. package/server/events/session-store/index.ts +492 -0
  72. package/server/events/task-manager/index.ts +181 -0
  73. package/server/index.ts +572 -0
  74. package/server/system/config.ts +243 -0
  75. package/server/system/credentials.ts +220 -0
  76. package/server/system/docker.ts +97 -0
  77. package/server/system/env.ts +109 -0
  78. package/server/system/logger/config.ts +112 -0
  79. package/server/system/logger/formatters.ts +40 -0
  80. package/server/system/logger/index.ts +53 -0
  81. package/server/system/logger/rotation.ts +37 -0
  82. package/server/system/logger/sinks.ts +101 -0
  83. package/server/system/logger/types.ts +29 -0
  84. package/server/utils/date.ts +57 -0
  85. package/server/utils/errors.ts +7 -0
  86. package/server/utils/fetch.ts +27 -0
  87. package/server/utils/files/atomic.ts +125 -0
  88. package/server/utils/files/html-io.ts +20 -0
  89. package/server/utils/files/image-store.ts +66 -0
  90. package/server/utils/files/index.ts +45 -0
  91. package/server/utils/files/journal-io.ts +213 -0
  92. package/server/utils/files/json.ts +69 -0
  93. package/server/utils/files/markdown-store.ts +33 -0
  94. package/server/utils/files/naming.ts +50 -0
  95. package/server/utils/files/reference-dirs-io.ts +45 -0
  96. package/server/utils/files/roles-io.ts +45 -0
  97. package/server/utils/files/safe.ts +106 -0
  98. package/server/utils/files/scheduler-io.ts +20 -0
  99. package/server/utils/files/scheduler-overrides-io.ts +64 -0
  100. package/server/utils/files/session-io.ts +136 -0
  101. package/server/utils/files/spreadsheet-store.ts +63 -0
  102. package/server/utils/files/todos-io.ts +29 -0
  103. package/server/utils/files/user-tasks-io.ts +25 -0
  104. package/server/utils/files/workspace-io.ts +221 -0
  105. package/server/utils/gemini.ts +59 -0
  106. package/server/utils/gitignore.ts +69 -0
  107. package/server/utils/http.ts +15 -0
  108. package/server/utils/httpError.ts +61 -0
  109. package/server/utils/id.ts +16 -0
  110. package/server/utils/json.ts +83 -0
  111. package/server/utils/logBackgroundError.ts +22 -0
  112. package/server/utils/markdown.ts +82 -0
  113. package/server/utils/request.ts +29 -0
  114. package/server/utils/slug.ts +50 -0
  115. package/server/utils/spawn.ts +62 -0
  116. package/server/utils/time.ts +34 -0
  117. package/server/utils/types.ts +47 -0
  118. package/server/workspace/chat-index/index.ts +153 -0
  119. package/server/workspace/chat-index/indexer.ts +209 -0
  120. package/server/workspace/chat-index/paths.ts +34 -0
  121. package/server/workspace/chat-index/summarizer.ts +247 -0
  122. package/server/workspace/chat-index/types.ts +38 -0
  123. package/server/workspace/custom-dirs.ts +220 -0
  124. package/server/workspace/helps/business.md +104 -0
  125. package/server/workspace/helps/github.md +23 -0
  126. package/server/workspace/helps/index.md +60 -0
  127. package/server/workspace/helps/mulmoscript.md +249 -0
  128. package/server/workspace/helps/sandbox.md +90 -0
  129. package/server/workspace/helps/spreadsheet.md +43 -0
  130. package/server/workspace/helps/telegram.md +135 -0
  131. package/server/workspace/helps/wiki.md +131 -0
  132. package/server/workspace/journal/archivist.ts +386 -0
  133. package/server/workspace/journal/dailyPass.ts +743 -0
  134. package/server/workspace/journal/diff.ts +71 -0
  135. package/server/workspace/journal/index.ts +185 -0
  136. package/server/workspace/journal/indexFile.ts +136 -0
  137. package/server/workspace/journal/linkRewrite.ts +4 -0
  138. package/server/workspace/journal/memoryExtractor.ts +130 -0
  139. package/server/workspace/journal/optimizationPass.ts +160 -0
  140. package/server/workspace/journal/paths.ts +76 -0
  141. package/server/workspace/journal/state.ts +125 -0
  142. package/server/workspace/paths.ts +158 -0
  143. package/server/workspace/reference-dirs.ts +252 -0
  144. package/server/workspace/roles.ts +37 -0
  145. package/server/workspace/skills/discovery.ts +125 -0
  146. package/server/workspace/skills/index.ts +10 -0
  147. package/server/workspace/skills/parser.ts +144 -0
  148. package/server/workspace/skills/paths.ts +41 -0
  149. package/server/workspace/skills/scheduler.ts +149 -0
  150. package/server/workspace/skills/types.ts +30 -0
  151. package/server/workspace/skills/user-tasks.ts +257 -0
  152. package/server/workspace/skills/writer.ts +189 -0
  153. package/server/workspace/sources/arxivDiscovery.ts +182 -0
  154. package/server/workspace/sources/classifier.ts +268 -0
  155. package/server/workspace/sources/fetchers/arxiv.ts +170 -0
  156. package/server/workspace/sources/fetchers/github.ts +106 -0
  157. package/server/workspace/sources/fetchers/githubIssues.ts +208 -0
  158. package/server/workspace/sources/fetchers/githubReleases.ts +186 -0
  159. package/server/workspace/sources/fetchers/index.ts +71 -0
  160. package/server/workspace/sources/fetchers/registerAll.ts +15 -0
  161. package/server/workspace/sources/fetchers/rss.ts +141 -0
  162. package/server/workspace/sources/fetchers/rssParser.ts +295 -0
  163. package/server/workspace/sources/httpFetcher.ts +230 -0
  164. package/server/workspace/sources/interests.ts +120 -0
  165. package/server/workspace/sources/paths.ts +110 -0
  166. package/server/workspace/sources/pipeline/dedup.ts +60 -0
  167. package/server/workspace/sources/pipeline/fetch.ts +136 -0
  168. package/server/workspace/sources/pipeline/index.ts +249 -0
  169. package/server/workspace/sources/pipeline/notify.ts +72 -0
  170. package/server/workspace/sources/pipeline/plan.ts +66 -0
  171. package/server/workspace/sources/pipeline/summarize.ts +189 -0
  172. package/server/workspace/sources/pipeline/write.ts +185 -0
  173. package/server/workspace/sources/rateLimiter.ts +148 -0
  174. package/server/workspace/sources/registry.ts +326 -0
  175. package/server/workspace/sources/robots.ts +271 -0
  176. package/server/workspace/sources/sourceState.ts +135 -0
  177. package/server/workspace/sources/taxonomy.ts +74 -0
  178. package/server/workspace/sources/types.ts +144 -0
  179. package/server/workspace/sources/urls.ts +112 -0
  180. package/server/workspace/tool-trace/classify.ts +114 -0
  181. package/server/workspace/tool-trace/index.ts +250 -0
  182. package/server/workspace/tool-trace/writeSearch.ts +98 -0
  183. package/server/workspace/wiki-backlinks/index.ts +107 -0
  184. package/server/workspace/wiki-backlinks/sessionBacklinks.ts +144 -0
  185. package/server/workspace/workspace.ts +66 -0
  186. package/src/App.vue +720 -0
  187. package/src/assets/mulmo_bw.png +0 -0
  188. package/src/components/CanvasViewToggle.vue +27 -0
  189. package/src/components/ChatAttachmentPreview.vue +45 -0
  190. package/src/components/ChatImagePreview.vue +17 -0
  191. package/src/components/ChatInput.vue +208 -0
  192. package/src/components/FileContentHeader.vue +49 -0
  193. package/src/components/FileContentRenderer.vue +162 -0
  194. package/src/components/FileTree.vue +115 -0
  195. package/src/components/FileTreePane.vue +85 -0
  196. package/src/components/FilesView.vue +206 -0
  197. package/src/components/LockStatusPopup.vue +111 -0
  198. package/src/components/NotificationBell.vue +131 -0
  199. package/src/components/NotificationToast.vue +72 -0
  200. package/src/components/PluginLauncher.vue +138 -0
  201. package/src/components/RightSidebar.vue +113 -0
  202. package/src/components/RoleSelector.vue +64 -0
  203. package/src/components/SessionHistoryPanel.vue +176 -0
  204. package/src/components/SessionTabBar.vue +81 -0
  205. package/src/components/SettingsMcpTab.vue +350 -0
  206. package/src/components/SettingsModal.vue +275 -0
  207. package/src/components/SettingsReferenceDirsTab.vue +173 -0
  208. package/src/components/SettingsWorkspaceDirsTab.vue +174 -0
  209. package/src/components/SidebarHeader.vue +69 -0
  210. package/src/components/StackView.vue +360 -0
  211. package/src/components/SuggestionsPanel.vue +65 -0
  212. package/src/components/TodoExplorer.vue +358 -0
  213. package/src/components/ToolResultsPanel.vue +77 -0
  214. package/src/components/todo/TodoAddDialog.vue +131 -0
  215. package/src/components/todo/TodoEditDialog.vue +47 -0
  216. package/src/components/todo/TodoEditPanel.vue +113 -0
  217. package/src/components/todo/TodoKanbanView.vue +249 -0
  218. package/src/components/todo/TodoListView.vue +79 -0
  219. package/src/components/todo/TodoTableView.vue +177 -0
  220. package/src/composables/useActiveSession.ts +40 -0
  221. package/src/composables/useAppApi.ts +45 -0
  222. package/src/composables/useCanvasViewMode.ts +121 -0
  223. package/src/composables/useChatScroll.ts +47 -0
  224. package/src/composables/useClickOutside.ts +26 -0
  225. package/src/composables/useClipboardCopy.ts +44 -0
  226. package/src/composables/useContentDisplay.ts +52 -0
  227. package/src/composables/useDebugBeat.ts +23 -0
  228. package/src/composables/useDynamicFavicon.ts +115 -0
  229. package/src/composables/useEventListeners.ts +42 -0
  230. package/src/composables/useExpandedDirs.ts +64 -0
  231. package/src/composables/useFaviconState.ts +30 -0
  232. package/src/composables/useFileSelection.ts +115 -0
  233. package/src/composables/useFileSortMode.ts +24 -0
  234. package/src/composables/useFileTree.ts +85 -0
  235. package/src/composables/useFreshPluginData.ts +89 -0
  236. package/src/composables/useHealth.ts +38 -0
  237. package/src/composables/useImeAwareEnter.ts +57 -0
  238. package/src/composables/useKeyNavigation.ts +60 -0
  239. package/src/composables/useMarkdownLinkHandler.ts +46 -0
  240. package/src/composables/useMarkdownMode.ts +17 -0
  241. package/src/composables/useMcpTools.ts +71 -0
  242. package/src/composables/useMergedSessions.ts +27 -0
  243. package/src/composables/useNotifications.ts +90 -0
  244. package/src/composables/usePdfDownload.ts +60 -0
  245. package/src/composables/usePendingCalls.ts +77 -0
  246. package/src/composables/usePubSub.ts +85 -0
  247. package/src/composables/useRightSidebar.ts +23 -0
  248. package/src/composables/useRoles.ts +34 -0
  249. package/src/composables/useSandboxStatus.ts +67 -0
  250. package/src/composables/useSelectedResult.ts +49 -0
  251. package/src/composables/useSessionDerived.ts +51 -0
  252. package/src/composables/useSessionHistory.ts +81 -0
  253. package/src/composables/useSessionSync.ts +57 -0
  254. package/src/composables/useViewLayout.ts +55 -0
  255. package/src/config/apiRoutes.ts +173 -0
  256. package/src/config/pubsubChannels.ts +45 -0
  257. package/src/config/roles.ts +335 -0
  258. package/src/config/schedulerActions.ts +25 -0
  259. package/src/config/toolNames.ts +71 -0
  260. package/src/config/workspacePaths.ts +24 -0
  261. package/src/index.css +107 -0
  262. package/src/main.ts +25 -0
  263. package/src/plugins/canvas/Preview.vue +13 -0
  264. package/src/plugins/canvas/View.vue +333 -0
  265. package/src/plugins/canvas/definition.ts +38 -0
  266. package/src/plugins/canvas/index.ts +36 -0
  267. package/src/plugins/chart/Preview.vue +49 -0
  268. package/src/plugins/chart/View.vue +143 -0
  269. package/src/plugins/chart/definition.ts +58 -0
  270. package/src/plugins/chart/index.ts +52 -0
  271. package/src/plugins/editImage/Preview.vue +13 -0
  272. package/src/plugins/editImage/View.vue +13 -0
  273. package/src/plugins/editImage/definition.ts +27 -0
  274. package/src/plugins/editImage/index.ts +36 -0
  275. package/src/plugins/generateImage/Preview.vue +13 -0
  276. package/src/plugins/generateImage/View.vue +33 -0
  277. package/src/plugins/generateImage/definition.ts +32 -0
  278. package/src/plugins/generateImage/index.ts +56 -0
  279. package/src/plugins/manageRoles/Preview.vue +49 -0
  280. package/src/plugins/manageRoles/View.vue +525 -0
  281. package/src/plugins/manageRoles/definition.ts +43 -0
  282. package/src/plugins/manageRoles/index.ts +47 -0
  283. package/src/plugins/manageSkills/Preview.vue +21 -0
  284. package/src/plugins/manageSkills/View.vue +321 -0
  285. package/src/plugins/manageSkills/definition.ts +49 -0
  286. package/src/plugins/manageSkills/index.ts +49 -0
  287. package/src/plugins/manageSource/Preview.vue +33 -0
  288. package/src/plugins/manageSource/View.vue +697 -0
  289. package/src/plugins/manageSource/definition.ts +63 -0
  290. package/src/plugins/manageSource/index.ts +66 -0
  291. package/src/plugins/markdown/Preview.vue +77 -0
  292. package/src/plugins/markdown/View.vue +476 -0
  293. package/src/plugins/markdown/definition.ts +50 -0
  294. package/src/plugins/markdown/index.ts +36 -0
  295. package/src/plugins/presentHtml/Preview.vue +25 -0
  296. package/src/plugins/presentHtml/View.vue +52 -0
  297. package/src/plugins/presentHtml/definition.ts +27 -0
  298. package/src/plugins/presentHtml/helpers.ts +72 -0
  299. package/src/plugins/presentHtml/index.ts +41 -0
  300. package/src/plugins/presentMulmoScript/Preview.vue +23 -0
  301. package/src/plugins/presentMulmoScript/View.vue +1166 -0
  302. package/src/plugins/presentMulmoScript/definition.ts +95 -0
  303. package/src/plugins/presentMulmoScript/helpers.ts +162 -0
  304. package/src/plugins/presentMulmoScript/index.ts +40 -0
  305. package/src/plugins/scheduler/Preview.vue +67 -0
  306. package/src/plugins/scheduler/TasksTab.vue +205 -0
  307. package/src/plugins/scheduler/View.vue +565 -0
  308. package/src/plugins/scheduler/definition.ts +57 -0
  309. package/src/plugins/scheduler/index.ts +45 -0
  310. package/src/plugins/scheduler/viewModes.ts +26 -0
  311. package/src/plugins/spreadsheet/Preview.vue +29 -0
  312. package/src/plugins/spreadsheet/View.vue +997 -0
  313. package/src/plugins/spreadsheet/cellHighlights.ts +79 -0
  314. package/src/plugins/spreadsheet/definition.ts +121 -0
  315. package/src/plugins/spreadsheet/engine/calculator.ts +459 -0
  316. package/src/plugins/spreadsheet/engine/cellBuilder.ts +81 -0
  317. package/src/plugins/spreadsheet/engine/date-parser.ts +220 -0
  318. package/src/plugins/spreadsheet/engine/date-utils.ts +56 -0
  319. package/src/plugins/spreadsheet/engine/engine.ts +176 -0
  320. package/src/plugins/spreadsheet/engine/evaluator.ts +390 -0
  321. package/src/plugins/spreadsheet/engine/formatter.ts +172 -0
  322. package/src/plugins/spreadsheet/engine/formulaRefs.ts +101 -0
  323. package/src/plugins/spreadsheet/engine/functions/date.ts +299 -0
  324. package/src/plugins/spreadsheet/engine/functions/financial.ts +387 -0
  325. package/src/plugins/spreadsheet/engine/functions/index.ts +16 -0
  326. package/src/plugins/spreadsheet/engine/functions/logical.ts +262 -0
  327. package/src/plugins/spreadsheet/engine/functions/lookup.ts +400 -0
  328. package/src/plugins/spreadsheet/engine/functions/mathematical.ts +297 -0
  329. package/src/plugins/spreadsheet/engine/functions/statistical.ts +338 -0
  330. package/src/plugins/spreadsheet/engine/functions/text.ts +389 -0
  331. package/src/plugins/spreadsheet/engine/index.ts +27 -0
  332. package/src/plugins/spreadsheet/engine/jsonCellLocator.ts +111 -0
  333. package/src/plugins/spreadsheet/engine/parser.ts +143 -0
  334. package/src/plugins/spreadsheet/engine/registry.ts +150 -0
  335. package/src/plugins/spreadsheet/engine/responseDecoder.ts +67 -0
  336. package/src/plugins/spreadsheet/engine/types.ts +64 -0
  337. package/src/plugins/spreadsheet/index.ts +36 -0
  338. package/src/plugins/textResponse/Preview.vue +94 -0
  339. package/src/plugins/textResponse/View.vue +503 -0
  340. package/src/plugins/textResponse/definition.ts +34 -0
  341. package/src/plugins/textResponse/index.ts +27 -0
  342. package/src/plugins/textResponse/plugin.ts +29 -0
  343. package/src/plugins/textResponse/samples.ts +97 -0
  344. package/src/plugins/textResponse/types.ts +11 -0
  345. package/src/plugins/todo/Preview.vue +63 -0
  346. package/src/plugins/todo/View.vue +364 -0
  347. package/src/plugins/todo/composables/useTodos.ts +177 -0
  348. package/src/plugins/todo/definition.ts +45 -0
  349. package/src/plugins/todo/index.ts +61 -0
  350. package/src/plugins/todo/labels.ts +163 -0
  351. package/src/plugins/todo/priority.ts +98 -0
  352. package/src/plugins/todo/viewModes.ts +19 -0
  353. package/src/plugins/ui-image/ImagePreview.vue +23 -0
  354. package/src/plugins/ui-image/ImageView.vue +34 -0
  355. package/src/plugins/ui-image/index.ts +3 -0
  356. package/src/plugins/ui-image/types.ts +4 -0
  357. package/src/plugins/wiki/Preview.vue +65 -0
  358. package/src/plugins/wiki/View.vue +342 -0
  359. package/src/plugins/wiki/definition.ts +25 -0
  360. package/src/plugins/wiki/helpers.ts +59 -0
  361. package/src/plugins/wiki/index.ts +52 -0
  362. package/src/router/guards.ts +61 -0
  363. package/src/router/index.ts +50 -0
  364. package/src/tools/index.ts +52 -0
  365. package/src/tools/types.ts +27 -0
  366. package/src/types/events.ts +16 -0
  367. package/src/types/fileTree.ts +13 -0
  368. package/src/types/notification.ts +67 -0
  369. package/src/types/session.ts +116 -0
  370. package/src/types/sse.ts +90 -0
  371. package/src/types/toolCallHistory.ts +13 -0
  372. package/src/utils/agent/eventDispatch.ts +74 -0
  373. package/src/utils/agent/request.ts +55 -0
  374. package/src/utils/agent/toolCalls.ts +62 -0
  375. package/src/utils/api.ts +218 -0
  376. package/src/utils/canvas/viewMode.ts +46 -0
  377. package/src/utils/dom/authTokenMeta.ts +20 -0
  378. package/src/utils/dom/clickOutside.ts +11 -0
  379. package/src/utils/dom/externalLink.ts +57 -0
  380. package/src/utils/dom/scrollable.ts +24 -0
  381. package/src/utils/errors.ts +11 -0
  382. package/src/utils/files/expandedDirs.ts +25 -0
  383. package/src/utils/files/filename.ts +12 -0
  384. package/src/utils/files/sortChildren.ts +20 -0
  385. package/src/utils/filesPreview/schedulerPreview.ts +38 -0
  386. package/src/utils/filesPreview/todoPreview.ts +40 -0
  387. package/src/utils/format/date.ts +85 -0
  388. package/src/utils/format/frontmatter.ts +80 -0
  389. package/src/utils/format/jsonSyntax.ts +109 -0
  390. package/src/utils/html/previewCsp.ts +65 -0
  391. package/src/utils/image/resolve.ts +8 -0
  392. package/src/utils/image/rewriteMarkdownImageRefs.ts +182 -0
  393. package/src/utils/markdown/extractFirstH1.ts +39 -0
  394. package/src/utils/notification/dispatch.ts +22 -0
  395. package/src/utils/path/relativeLink.ts +130 -0
  396. package/src/utils/role/icon.ts +20 -0
  397. package/src/utils/role/merge.ts +10 -0
  398. package/src/utils/role/plugins.ts +12 -0
  399. package/src/utils/session/mergeSessions.ts +103 -0
  400. package/src/utils/session/seedRoleDefault.ts +35 -0
  401. package/src/utils/session/sessionEntries.ts +121 -0
  402. package/src/utils/session/sessionFactory.ts +22 -0
  403. package/src/utils/session/sessionHelpers.ts +99 -0
  404. package/src/utils/tools/dedup.ts +17 -0
  405. package/src/utils/tools/mcp.ts +33 -0
  406. package/src/utils/tools/pendingCalls.ts +16 -0
  407. package/src/utils/tools/result.ts +40 -0
  408. package/src/utils/types.ts +44 -0
@@ -0,0 +1,71 @@
1
+ // Single source of truth for every tool name (= MCP tool / plugin key)
2
+ // the app knows about. Centralised here so:
3
+ //
4
+ // - `Role.availablePlugins` can be typed as `ToolName[]` and typos
5
+ // get caught at compile time instead of silently dropping a
6
+ // plugin at runtime
7
+ // - grep for "every place that handles this tool" returns a list
8
+ // of `TOOL_NAMES.x` references rather than free-form strings
9
+ // - adding a new plugin is a one-line change here + register in
10
+ // `src/tools/index.ts` — and `typeof TOOL_NAMES` keeps both in
11
+ // sync through the type system
12
+ //
13
+ // Naming is intentionally the literal string the server / MCP
14
+ // protocol / jsonl files expect — rename-touching requires a
15
+ // coordinated server + client update, which is exactly when having
16
+ // a central list here helps.
17
+ //
18
+ // First slice of issue #289 (item 4: tool name literals).
19
+
20
+ export const TOOL_NAMES = {
21
+ // Text / base
22
+ textResponse: "text-response",
23
+
24
+ // Management plugins
25
+ manageTodoList: "manageTodoList",
26
+ manageScheduler: "manageScheduler",
27
+ manageRoles: "manageRoles",
28
+ manageSkills: "manageSkills",
29
+ manageSource: "manageSource",
30
+ manageWiki: "manageWiki",
31
+
32
+ // Presentational plugins
33
+ presentMulmoScript: "presentMulmoScript",
34
+ presentDocument: "presentDocument",
35
+ presentSpreadsheet: "presentSpreadsheet",
36
+ presentHtml: "presentHtml",
37
+ presentChart: "presentChart",
38
+ presentForm: "presentForm",
39
+ present3D: "present3D",
40
+
41
+ // Creation / generation
42
+ createMindMap: "createMindMap",
43
+ generateImage: "generateImage",
44
+ editImage: "editImage",
45
+ openCanvas: "openCanvas",
46
+
47
+ // Interactive / media
48
+ putQuestions: "putQuestions",
49
+ weather: "weather",
50
+
51
+ // MCP tools (server-side, not GUI plugins — registered in
52
+ // `server/mcp-tools/`). Listed here because they appear in a
53
+ // role's `availablePlugins` alongside GUI plugins.
54
+ readXPost: "readXPost",
55
+ searchX: "searchX",
56
+
57
+ // Built-in (handled specially by the MCP stdio bridge).
58
+ switchRole: "switchRole",
59
+ } as const;
60
+
61
+ export type ToolName = (typeof TOOL_NAMES)[keyof typeof TOOL_NAMES];
62
+
63
+ /** Runtime predicate — useful when string input (URL param, JSON
64
+ * payload) needs to be narrowed to a known tool. */
65
+ export function isToolName(value: unknown): value is ToolName {
66
+ if (typeof value !== "string") return false;
67
+ return (Object.values(TOOL_NAMES) as readonly string[]).includes(value);
68
+ }
69
+
70
+ /** Array of all known tool names, in declaration order. */
71
+ export const ALL_TOOL_NAMES: readonly ToolName[] = Object.values(TOOL_NAMES);
@@ -0,0 +1,24 @@
1
+ // Workspace-relative file paths — single source of truth.
2
+ //
3
+ // Shared by both the Vue frontend and the Express server.
4
+ // This file MUST NOT import node:path, node:os, or any Node-only
5
+ // module so it stays browser-compatible.
6
+ //
7
+ // The server's `server/workspace/paths.ts` imports these and
8
+ // joins them with the workspace root to produce absolute paths.
9
+
10
+ /** Well-known individual files. Values are workspace-relative paths. */
11
+ export const WORKSPACE_FILES = {
12
+ memory: "conversations/memory.md",
13
+ sessionToken: ".session-token",
14
+ wikiIndex: "data/wiki/index.md",
15
+ wikiLog: "data/wiki/log.md",
16
+ wikiSchema: "data/wiki/SCHEMA.md",
17
+ wikiSummary: "data/wiki/summary.md",
18
+ summariesIndex: "conversations/summaries/_index.md",
19
+ todosItems: "data/todos/todos.json",
20
+ todosColumns: "data/todos/columns.json",
21
+ schedulerItems: "data/scheduler/items.json",
22
+ schedulerUserTasks: "config/scheduler/tasks.json",
23
+ schedulerOverrides: "config/scheduler/overrides.json",
24
+ } as const;
package/src/index.css ADDED
@@ -0,0 +1,107 @@
1
+ @import "tailwindcss";
2
+
3
+ /* Markdown content styles.
4
+ The text-response plugin wraps rendered Markdown in a
5
+ `.markdown-content` container with `prose prose-slate` classes, but
6
+ Tailwind Typography isn't installed here so those classes don't do
7
+ anything. Provide a minimal baseline so headings, lists, code blocks
8
+ etc. look right in both chat responses and the Files-mode preview. */
9
+ .markdown-content h1 {
10
+ font-size: 1.5rem;
11
+ font-weight: 700;
12
+ margin-top: 1.5rem;
13
+ margin-bottom: 0.75rem;
14
+ color: #111827;
15
+ }
16
+ .markdown-content h2 {
17
+ font-size: 1.25rem;
18
+ font-weight: 700;
19
+ margin-top: 1.25rem;
20
+ margin-bottom: 0.5rem;
21
+ color: #1f2937;
22
+ border-bottom: 1px solid #e5e7eb;
23
+ padding-bottom: 0.25rem;
24
+ }
25
+ .markdown-content h3 {
26
+ font-size: 1.1rem;
27
+ font-weight: 600;
28
+ margin-top: 1rem;
29
+ margin-bottom: 0.5rem;
30
+ color: #374151;
31
+ }
32
+ .markdown-content h4 {
33
+ font-size: 1rem;
34
+ font-weight: 600;
35
+ margin-top: 0.75rem;
36
+ margin-bottom: 0.25rem;
37
+ color: #374151;
38
+ }
39
+ .markdown-content p {
40
+ margin-bottom: 0.75rem;
41
+ line-height: 1.6;
42
+ }
43
+ .markdown-content ul,
44
+ .markdown-content ol {
45
+ margin-left: 1.5rem;
46
+ margin-bottom: 0.75rem;
47
+ }
48
+ .markdown-content ul {
49
+ list-style-type: disc;
50
+ }
51
+ .markdown-content ol {
52
+ list-style-type: decimal;
53
+ }
54
+ .markdown-content li {
55
+ margin-bottom: 0.25rem;
56
+ line-height: 1.5;
57
+ }
58
+ .markdown-content code {
59
+ background: #f3f4f6;
60
+ padding: 0.1rem 0.3rem;
61
+ border-radius: 0.25rem;
62
+ font-size: 0.85em;
63
+ font-family: ui-monospace, SFMono-Regular, monospace;
64
+ }
65
+ .markdown-content pre {
66
+ background: #f3f4f6;
67
+ padding: 0.75rem;
68
+ border-radius: 0.375rem;
69
+ overflow-x: auto;
70
+ margin-bottom: 0.75rem;
71
+ }
72
+ .markdown-content pre code {
73
+ background: none;
74
+ padding: 0;
75
+ font-size: 0.85em;
76
+ }
77
+ .markdown-content blockquote {
78
+ border-left: 3px solid #d1d5db;
79
+ padding-left: 1rem;
80
+ color: #6b7280;
81
+ margin: 0.75rem 0;
82
+ }
83
+ .markdown-content a {
84
+ color: #2563eb;
85
+ text-decoration: underline;
86
+ }
87
+ .markdown-content hr {
88
+ border: none;
89
+ border-top: 1px solid #e5e7eb;
90
+ margin: 1rem 0;
91
+ }
92
+ .markdown-content table {
93
+ border-collapse: collapse;
94
+ width: 100%;
95
+ margin-bottom: 0.75rem;
96
+ font-size: 0.875rem;
97
+ }
98
+ .markdown-content th,
99
+ .markdown-content td {
100
+ border: 1px solid #e5e7eb;
101
+ padding: 0.5rem 0.75rem;
102
+ text-align: left;
103
+ }
104
+ .markdown-content th {
105
+ background: #f9fafb;
106
+ font-weight: 600;
107
+ }
package/src/main.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { createApp } from "vue";
2
+ import App from "./App.vue";
3
+ import router from "./router/index";
4
+ import { installGuards } from "./router/guards";
5
+ import { setAuthToken } from "./utils/api";
6
+ import { readAuthTokenFromMeta } from "./utils/dom/authTokenMeta";
7
+ import "./index.css";
8
+ import "material-icons/iconfont/material-icons.css";
9
+
10
+ import.meta.glob(["../node_modules/@gui-chat-plugin/*/dist/style.css", "../node_modules/@mulmochat-plugin/*/dist/style.css"], { eager: true });
11
+
12
+ // Bearer auth bootstrap (#272). The server embeds the per-startup
13
+ // token into `<meta name="mulmoclaude-auth" content="...">` when it
14
+ // serves index.html. Reading it here and handing to setAuthToken()
15
+ // wires every subsequent apiFetch / apiGet / ... to attach an
16
+ // `Authorization: Bearer ...` header. A missing or empty token means
17
+ // requests will 401 — that's the intended dev-time signal when the
18
+ // server isn't running.
19
+ setAuthToken(readAuthTokenFromMeta());
20
+
21
+ installGuards(router);
22
+
23
+ const app = createApp(App);
24
+ app.use(router);
25
+ app.mount("#app");
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <ImagePreview :result="result" alt="Canvas drawing" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { ImagePreview } from "../ui-image";
7
+ import type { ToolResult } from "gui-chat-protocol/vue";
8
+ import type { ImageToolData } from "./definition";
9
+
10
+ defineProps<{
11
+ result: ToolResult<ImageToolData>;
12
+ }>();
13
+ </script>
@@ -0,0 +1,333 @@
1
+ <template>
2
+ <div class="w-full h-full flex flex-col bg-white">
3
+ <div class="flex-shrink-0 px-4 py-2 border-b border-gray-100 bg-gray-50">
4
+ <div class="flex items-center justify-between gap-4">
5
+ <div class="flex items-center gap-4">
6
+ <div class="flex items-center gap-2">
7
+ <div class="flex gap-1">
8
+ <button
9
+ v-for="size in [2, 5, 10, 20]"
10
+ :key="size"
11
+ :class="[
12
+ 'w-8 h-8 rounded border-2 transition-colors',
13
+ brushSize === size ? 'border-blue-500 bg-blue-100' : 'border-gray-300 bg-white hover:bg-gray-50',
14
+ ]"
15
+ @click="brushSize = size"
16
+ >
17
+ <div
18
+ :class="'bg-gray-800 rounded-full mx-auto'"
19
+ :style="{
20
+ width: Math.max(2, size * 1) + 'px',
21
+ height: Math.max(2, size * 1) + 'px',
22
+ }"
23
+ ></div>
24
+ </button>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="flex items-center gap-2">
29
+ <input v-model="brushColor" type="color" class="w-12 h-8 rounded border border-gray-300" />
30
+ </div>
31
+ </div>
32
+
33
+ <div class="flex items-center gap-1">
34
+ <button class="w-8 h-8 flex items-center justify-center rounded border-2 border-gray-300 bg-white hover:bg-gray-50" title="Undo" @click="undo">
35
+ <span class="material-icons text-sm">undo</span>
36
+ </button>
37
+ <button class="w-8 h-8 flex items-center justify-center rounded border-2 border-gray-300 bg-white hover:bg-gray-50" title="Redo" @click="redo">
38
+ <span class="material-icons text-sm">redo</span>
39
+ </button>
40
+ <button class="w-8 h-8 flex items-center justify-center rounded border-2 border-red-300 bg-white hover:bg-red-50" title="Clear" @click="clear">
41
+ <span class="material-icons text-sm">delete</span>
42
+ </button>
43
+ </div>
44
+ </div>
45
+ </div>
46
+
47
+ <div class="flex-1 p-4 overflow-hidden">
48
+ <VueDrawingCanvas
49
+ ref="canvasRef"
50
+ :key="`${selectedResult?.uuid || 'default'}-${canvasRenderKey}`"
51
+ v-model:image="canvasImage"
52
+ :width="canvasWidth"
53
+ :height="canvasHeight"
54
+ :stroke-type="'dash'"
55
+ :line-cap="'round'"
56
+ :line-join="'round'"
57
+ :fill-shape="false"
58
+ :eraser="false"
59
+ :line-width="brushSize"
60
+ :color="brushColor"
61
+ :background-color="'#FFFFFF'"
62
+ :background-image="undefined"
63
+ :watermark="undefined"
64
+ :initial-image="initialStrokes"
65
+ save-as="png"
66
+ :styles="{
67
+ border: '1px solid #ddd',
68
+ borderRadius: '8px',
69
+ }"
70
+ :lock="false"
71
+ @mouseup="handleDrawingEnd"
72
+ @touchend="handleDrawingEnd"
73
+ />
74
+ <div class="flex items-center gap-2 flex-wrap mt-3">
75
+ <span class="text-xs text-gray-500 mr-1">Style:</span>
76
+ <button
77
+ v-for="style in artStyles"
78
+ :key="style.id"
79
+ class="px-3 py-1.5 text-xs rounded-full border border-gray-300 bg-white hover:bg-blue-50 hover:border-blue-400 transition-colors"
80
+ @click="applyStyle(style)"
81
+ >
82
+ {{ style.label }}
83
+ </button>
84
+ </div>
85
+ </div>
86
+ </div>
87
+ </template>
88
+
89
+ <script setup lang="ts">
90
+ import { ref, onMounted, onUnmounted, nextTick, watch } from "vue";
91
+ import VueDrawingCanvas from "vue-drawing-canvas";
92
+ import type { ToolResult } from "gui-chat-protocol/vue";
93
+ import type { ImageToolData, CanvasDrawingState } from "./definition";
94
+ import { apiPost, apiPut } from "../../utils/api";
95
+ import { API_ROUTES } from "../../config/apiRoutes";
96
+
97
+ const props = defineProps<{
98
+ selectedResult: ToolResult<ImageToolData> | null;
99
+ sendTextMessage?: (text: string) => void;
100
+ }>();
101
+
102
+ const emit = defineEmits<{
103
+ updateResult: [result: ToolResult<ImageToolData>];
104
+ }>();
105
+
106
+ const artStyles = [
107
+ { id: "ghibli", label: "Ghibli" },
108
+ { id: "ukiyoe", label: "Ukiyoe" },
109
+ { id: "sumie", label: "Sumi-e" },
110
+ { id: "picasso", label: "Picasso" },
111
+ { id: "gogh", label: "Van Gogh" },
112
+ { id: "photo", label: "Photo-realistic" },
113
+ { id: "watercolor", label: "Watercolor" },
114
+ { id: "popart", label: "Pop Art" },
115
+ { id: "american", label: "American Comic" },
116
+ { id: "cyberpunk", label: "Cyberpunk" },
117
+ { id: "pencilsketch", label: "Pencil Sketch" },
118
+ { id: "pixelart", label: "Pixel Art" },
119
+ ];
120
+
121
+ const applyStyle = async (style: { id: string; label: string }) => {
122
+ const saved = await saveDrawingState();
123
+ if (!saved) return;
124
+ if (props.sendTextMessage) {
125
+ props.sendTextMessage(`Turn my drawing on the canvas into a ${style.label} style image.`);
126
+ }
127
+ };
128
+
129
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
130
+ const canvasRef = ref<any>(null);
131
+ const canvasImage = ref("");
132
+ const brushSize = ref(5);
133
+ const brushColor = ref("#000000");
134
+ const initialStrokes = ref([]);
135
+ const canvasWidth = ref(800);
136
+ const canvasHeight = ref(600);
137
+ const canvasRenderKey = ref(0);
138
+
139
+ // Track the server-side image path for this canvas instance.
140
+ // Initialized from existing result data (if reopening a saved canvas).
141
+ const imagePath = ref(
142
+ props.selectedResult?.data?.imageData && !props.selectedResult.data.imageData.startsWith("data:") ? props.selectedResult.data.imageData : "",
143
+ );
144
+ let uploadInFlight = false;
145
+ let pendingSave = false;
146
+
147
+ const restoreDrawingState = () => {
148
+ if (props.selectedResult?.viewState?.drawingState) {
149
+ const state = props.selectedResult.viewState.drawingState as CanvasDrawingState;
150
+
151
+ brushSize.value = state.brushSize || 5;
152
+ brushColor.value = state.brushColor || "#000000";
153
+ canvasWidth.value = state.canvasWidth || 800;
154
+ canvasHeight.value = state.canvasHeight || 600;
155
+
156
+ if (state.strokes) {
157
+ initialStrokes.value = state.strokes as never[];
158
+ } else {
159
+ initialStrokes.value = [];
160
+ }
161
+ } else {
162
+ initialStrokes.value = [];
163
+ }
164
+ // Reinitialise imagePath from the incoming result so autosaves
165
+ // after a selectedResult change don't upload against the old path.
166
+ imagePath.value =
167
+ props.selectedResult?.data?.imageData && !props.selectedResult.data.imageData.startsWith("data:") ? props.selectedResult.data.imageData : "";
168
+ };
169
+ restoreDrawingState();
170
+
171
+ const undo = async () => {
172
+ if (canvasRef.value) {
173
+ try {
174
+ canvasRef.value.undo();
175
+ // Wait for the canvas to update, then save state
176
+ setTimeout(saveDrawingState, 50);
177
+ } catch (error) {
178
+ console.warn("Undo operation failed:", error);
179
+ }
180
+ }
181
+ };
182
+
183
+ const redo = async () => {
184
+ if (canvasRef.value) {
185
+ try {
186
+ canvasRef.value.redo();
187
+ // Wait for the canvas to update, then save state
188
+ setTimeout(saveDrawingState, 50);
189
+ } catch (error) {
190
+ console.warn("Redo operation failed:", error);
191
+ }
192
+ }
193
+ };
194
+
195
+ const clear = () => {
196
+ if (canvasRef.value) {
197
+ try {
198
+ canvasRef.value.reset();
199
+ saveDrawingState();
200
+ } catch (error) {
201
+ console.warn("Clear operation failed:", error);
202
+ }
203
+ }
204
+ };
205
+
206
+ const handleDrawingEnd = () => {
207
+ saveDrawingState();
208
+ };
209
+
210
+ // Returns true if the drawing was successfully persisted, false
211
+ // otherwise. Callers like applyStyle check the return value to avoid
212
+ // sending a style request against stale image data.
213
+ //
214
+ // Captures a local snapshot of props.selectedResult and imagePath at
215
+ // the start so an async upload never accidentally writes against a
216
+ // different result that was swapped in mid-flight.
217
+ const saveDrawingState = async (): Promise<boolean> => {
218
+ if (!canvasRef.value || !props.selectedResult) return false;
219
+ if (uploadInFlight) {
220
+ pendingSave = true;
221
+ return false;
222
+ }
223
+ // Snapshot the current result and path *before* any await so a
224
+ // concurrent selectedResult swap doesn't silently redirect the
225
+ // upload.
226
+ const boundResult = props.selectedResult;
227
+ const boundImagePath = imagePath.value;
228
+ uploadInFlight = true;
229
+ try {
230
+ const imageDataUri: string = await canvasRef.value.save();
231
+ const strokes = canvasRef.value.getAllStrokes();
232
+ const drawingState = {
233
+ strokes,
234
+ brushSize: brushSize.value,
235
+ brushColor: brushColor.value,
236
+ canvasWidth: canvasWidth.value,
237
+ canvasHeight: canvasHeight.value,
238
+ };
239
+
240
+ // If selectedResult changed while we were saving the canvas
241
+ // bitmap, abort — the upload would go to the wrong session.
242
+ if (boundResult !== props.selectedResult) return false;
243
+
244
+ const savedPath = boundImagePath
245
+ ? await (async () => {
246
+ const filename = boundImagePath.replace(/^images\//, "");
247
+ const result = await apiPut<{ path: string }>(API_ROUTES.image.update.replace(":filename", filename), { imageData: imageDataUri });
248
+ if (!result.ok) throw new Error(`PUT failed: ${result.error}`);
249
+ return result.data.path;
250
+ })()
251
+ : await (async () => {
252
+ const result = await apiPost<{ path: string }>(API_ROUTES.image.upload, {
253
+ imageData: imageDataUri,
254
+ });
255
+ if (!result.ok) throw new Error(`POST failed: ${result.error}`);
256
+ return result.data.path;
257
+ })();
258
+
259
+ imagePath.value = savedPath;
260
+
261
+ const updatedResult: ToolResult<ImageToolData> = {
262
+ ...boundResult,
263
+ data: {
264
+ prompt: boundResult.data?.prompt || "",
265
+ imageData: savedPath,
266
+ },
267
+ viewState: { drawingState },
268
+ };
269
+
270
+ emit("updateResult", updatedResult);
271
+ return true;
272
+ } catch (error) {
273
+ console.error("Failed to save drawing state:", error);
274
+ return false;
275
+ } finally {
276
+ uploadInFlight = false;
277
+ if (pendingSave) {
278
+ pendingSave = false;
279
+ void saveDrawingState();
280
+ }
281
+ }
282
+ };
283
+
284
+ // Watch for selectedResult changes to restore drawing state
285
+ watch(
286
+ () => props.selectedResult,
287
+ () => {
288
+ restoreDrawingState();
289
+ },
290
+ { immediate: false },
291
+ );
292
+
293
+ // Watch for changes to automatically save drawing state
294
+ watch([brushSize, brushColor], () => {
295
+ saveDrawingState();
296
+ });
297
+
298
+ // Watch for canvas size changes and force re-mount
299
+ watch([canvasWidth, canvasHeight], () => {
300
+ // Force canvas to re-mount with new dimensions by changing the key
301
+ canvasRenderKey.value++;
302
+ });
303
+ const updateCanvasSize = () => {
304
+ // Get the canvas container (the div with flex-1 p-4 overflow-hidden)
305
+ const canvasContainer = canvasRef.value?.$el?.parentElement;
306
+ if (canvasContainer) {
307
+ const containerRect = canvasContainer.getBoundingClientRect();
308
+
309
+ const padding = 32; // p-4 = 16px each side
310
+ const newWidth = Math.floor(containerRect.width - padding);
311
+ const newHeight = Math.floor((newWidth * 9) / 16);
312
+
313
+ // Only update if the size actually changed to avoid unnecessary re-renders
314
+ if (newWidth !== canvasWidth.value || newHeight !== canvasHeight.value) {
315
+ canvasWidth.value = newWidth;
316
+ canvasHeight.value = newHeight;
317
+ }
318
+ }
319
+ };
320
+
321
+ onMounted(async () => {
322
+ await nextTick();
323
+ updateCanvasSize();
324
+
325
+ // Listen for window resize to update canvas size
326
+ window.addEventListener("resize", updateCanvasSize);
327
+ });
328
+
329
+ // Clean up resize listener
330
+ onUnmounted(() => {
331
+ window.removeEventListener("resize", updateCanvasSize);
332
+ });
333
+ </script>
@@ -0,0 +1,38 @@
1
+ import type { ToolDefinition } from "gui-chat-protocol";
2
+
3
+ export const TOOL_NAME = "openCanvas";
4
+
5
+ export interface ImageToolData {
6
+ imageData: string;
7
+ prompt: string;
8
+ }
9
+
10
+ export interface CanvasDrawingState {
11
+ brushSize?: number;
12
+ brushColor?: string;
13
+ canvasWidth?: number;
14
+ canvasHeight?: number;
15
+ strokes?: unknown[];
16
+ }
17
+
18
+ const toolDefinition: ToolDefinition = {
19
+ type: "function",
20
+ name: TOOL_NAME,
21
+ description: "Open a drawing canvas for the user to create drawings, sketches, or diagrams.",
22
+ prompt: `When the user asks 'I want to draw an image.', call ${TOOL_NAME} API to open the canvas.`,
23
+ parameters: {
24
+ type: "object",
25
+ properties: {},
26
+ required: [] as string[],
27
+ },
28
+ };
29
+
30
+ export default toolDefinition;
31
+
32
+ export const executeOpenCanvas = async () => {
33
+ return {
34
+ message: "Drawing canvas opened",
35
+ instructions: "Tell the user that you are able to turn the drawing into a photographic image, a manga or any other art style.",
36
+ title: "Drawing Canvas",
37
+ };
38
+ };
@@ -0,0 +1,36 @@
1
+ import type { ToolPlugin } from "../../tools/types";
2
+ import type { ToolResult } from "gui-chat-protocol";
3
+ import toolDefinition, { TOOL_NAME } from "./definition";
4
+ import type { ImageToolData } from "./definition";
5
+ import View from "./View.vue";
6
+ import Preview from "./Preview.vue";
7
+ import { apiPost } from "../../utils/api";
8
+ import { API_ROUTES } from "../../config/apiRoutes";
9
+
10
+ const canvasPlugin: ToolPlugin<ImageToolData> = {
11
+ toolDefinition,
12
+
13
+ async execute(_context, args) {
14
+ const result = await apiPost<ToolResult<ImageToolData>>(API_ROUTES.plugins.canvas, args);
15
+ if (!result.ok) {
16
+ return {
17
+ toolName: TOOL_NAME,
18
+ uuid: crypto.randomUUID(),
19
+ message: result.error,
20
+ };
21
+ }
22
+ return {
23
+ ...result.data,
24
+ toolName: TOOL_NAME,
25
+ uuid: crypto.randomUUID(),
26
+ };
27
+ },
28
+
29
+ isEnabled: () => true,
30
+ generatingMessage: "Opening drawing canvas...",
31
+ viewComponent: View,
32
+ previewComponent: Preview,
33
+ };
34
+
35
+ export default canvasPlugin;
36
+ export { TOOL_NAME };