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,55 @@
1
+ // View-layout state: tracks whether the app is in a "stack" layout
2
+ // (full-width canvas) or "single" (sidebar + canvas), remembers the
3
+ // last chat-oriented view mode, and derives displayedCurrentSessionId
4
+ // (blank in plugin views so no tab appears "current").
5
+
6
+ import { computed, ref, watch, type ComputedRef, type Ref } from "vue";
7
+ import { CANVAS_VIEW, type CanvasViewMode } from "../utils/canvas/viewMode";
8
+
9
+ const CHAT_VIEWS = [CANVAS_VIEW.single, CANVAS_VIEW.stack] as const;
10
+ type ChatViewMode = (typeof CHAT_VIEWS)[number];
11
+
12
+ function isChatView(m: string): m is ChatViewMode {
13
+ return (CHAT_VIEWS as readonly string[]).includes(m);
14
+ }
15
+
16
+ export function useViewLayout(opts: {
17
+ canvasViewMode: Ref<CanvasViewMode> | ComputedRef<CanvasViewMode>;
18
+ setCanvasViewMode: (mode: CanvasViewMode) => void;
19
+ currentSessionId: Ref<string>;
20
+ activePane: Ref<"sidebar" | "main">;
21
+ }) {
22
+ const { canvasViewMode, setCanvasViewMode, currentSessionId, activePane } = opts;
23
+
24
+ const isStackLayout = computed(() => canvasViewMode.value !== CANVAS_VIEW.single);
25
+
26
+ const lastChatViewMode = ref<ChatViewMode>(isChatView(canvasViewMode.value) ? canvasViewMode.value : CANVAS_VIEW.stack);
27
+
28
+ watch(canvasViewMode, (mode) => {
29
+ if (isChatView(mode)) lastChatViewMode.value = mode;
30
+ });
31
+
32
+ function restoreChatViewForSession(): void {
33
+ if (!isChatView(canvasViewMode.value)) {
34
+ setCanvasViewMode(lastChatViewMode.value);
35
+ }
36
+ }
37
+
38
+ const displayedCurrentSessionId = computed(() => (isChatView(canvasViewMode.value) ? currentSessionId.value : ""));
39
+
40
+ // Keep arrow-key navigation tied to the canvas when the sidebar
41
+ // list doesn't exist (Stack layout has no ToolResultsPanel).
42
+ watch(
43
+ isStackLayout,
44
+ (stack) => {
45
+ activePane.value = stack ? "main" : "sidebar";
46
+ },
47
+ { immediate: true },
48
+ );
49
+
50
+ return {
51
+ isStackLayout,
52
+ restoreChatViewForSession,
53
+ displayedCurrentSessionId,
54
+ };
55
+ }
@@ -0,0 +1,173 @@
1
+ // Single source of truth for every HTTP endpoint the server exposes
2
+ // under `/api/*`. Issue #289 (part 1) — consolidate the 77+ route
3
+ // registrations and ~57 frontend `fetch("/api/...")` call sites so
4
+ // that typos fail typecheck instead of producing runtime 404s.
5
+ //
6
+ // **Shape**: nested `as const` object grouped by owning route file /
7
+ // resource family. Every value is the literal, full path including
8
+ // the `/api` prefix. Routers in `server/routes/*.ts` register them
9
+ // verbatim — the `app.use("/api", ...)` mount prefix was removed so
10
+ // the constants are the unambiguous source.
11
+ //
12
+ // **Express params**: patterns like `:id` / `:filename` are kept as
13
+ // Express-compatible strings. Client-side URL builders (e.g. a
14
+ // `todoItem(id)` helper) are deliberately NOT added here until the
15
+ // frontend migration lands — see plans/refactor-api-routes-constants.md.
16
+ //
17
+ // **Adding a new endpoint**: add it here first, then reference the
18
+ // constant from the router file. Keep the nesting shallow and the
19
+ // key names matched to the last URL segment where possible.
20
+
21
+ import { CHAT_SERVICE_ROUTES } from "@mulmobridge/protocol";
22
+
23
+ export const API_ROUTES = {
24
+ health: "/api/health",
25
+ sandbox: "/api/sandbox",
26
+
27
+ agent: {
28
+ run: "/api/agent",
29
+ cancel: "/api/agent/cancel",
30
+ internal: {
31
+ toolResult: "/api/internal/tool-result",
32
+ switchRole: "/api/internal/switch-role",
33
+ },
34
+ },
35
+
36
+ chart: {
37
+ present: "/api/present-chart",
38
+ },
39
+
40
+ chatIndex: {
41
+ rebuild: "/api/chat-index/rebuild",
42
+ },
43
+
44
+ // Single source of truth: @mulmobridge/protocol. See plans/messaging_transports.md.
45
+ chatService: CHAT_SERVICE_ROUTES,
46
+
47
+ config: {
48
+ base: "/api/config",
49
+ settings: "/api/config/settings",
50
+ mcp: "/api/config/mcp",
51
+ workspaceDirs: "/api/config/workspace-dirs",
52
+ referenceDirs: "/api/config/reference-dirs",
53
+ schedulerOverrides: "/api/config/scheduler-overrides",
54
+ },
55
+
56
+ files: {
57
+ tree: "/api/files/tree",
58
+ dir: "/api/files/dir",
59
+ content: "/api/files/content",
60
+ raw: "/api/files/raw",
61
+ refRoots: "/api/files/ref-roots",
62
+ },
63
+
64
+ html: {
65
+ generate: "/api/generate-html",
66
+ edit: "/api/edit-html",
67
+ present: "/api/present-html",
68
+ },
69
+
70
+ image: {
71
+ generate: "/api/generate-image",
72
+ edit: "/api/edit-image",
73
+ upload: "/api/images",
74
+ update: "/api/images/:filename",
75
+ },
76
+
77
+ mcpTools: {
78
+ list: "/api/mcp-tools",
79
+ invoke: "/api/mcp-tools/:tool",
80
+ },
81
+
82
+ notifications: {
83
+ // PoC endpoint for scheduled push fan-out (Web pub-sub + bridge).
84
+ // Scaffolding for #144 / #142 — see plans/feat-notification-push-scaffold.md.
85
+ test: "/api/notifications/test",
86
+ },
87
+
88
+ mulmoScript: {
89
+ save: "/api/mulmo-script",
90
+ updateBeat: "/api/mulmo-script/update-beat",
91
+ updateScript: "/api/mulmo-script/update-script",
92
+ beatImage: "/api/mulmo-script/beat-image",
93
+ beatAudio: "/api/mulmo-script/beat-audio",
94
+ generateBeatAudio: "/api/mulmo-script/generate-beat-audio",
95
+ renderBeat: "/api/mulmo-script/render-beat",
96
+ uploadBeatImage: "/api/mulmo-script/upload-beat-image",
97
+ characterImage: "/api/mulmo-script/character-image",
98
+ renderCharacter: "/api/mulmo-script/render-character",
99
+ uploadCharacterImage: "/api/mulmo-script/upload-character-image",
100
+ movieStatus: "/api/mulmo-script/movie-status",
101
+ generateMovie: "/api/mulmo-script/generate-movie",
102
+ downloadMovie: "/api/mulmo-script/download-movie",
103
+ },
104
+
105
+ pdf: {
106
+ markdown: "/api/pdf/markdown",
107
+ },
108
+
109
+ // Plugin-owned endpoints that don't follow a single naming pattern.
110
+ // Names match the plugin tool name or the short verb the plugin uses.
111
+ plugins: {
112
+ presentDocument: "/api/present-document",
113
+ updateMarkdown: "/api/markdowns/:filename",
114
+ presentSpreadsheet: "/api/present-spreadsheet",
115
+ updateSpreadsheet: "/api/spreadsheets/:filename",
116
+ mindmap: "/api/mindmap",
117
+ quiz: "/api/quiz",
118
+ form: "/api/form",
119
+ canvas: "/api/canvas",
120
+ present3d: "/api/present3d",
121
+ },
122
+
123
+ roles: {
124
+ list: "/api/roles",
125
+ manage: "/api/roles/manage",
126
+ },
127
+
128
+ scheduler: {
129
+ base: "/api/scheduler",
130
+ tasks: "/api/scheduler/tasks",
131
+ task: "/api/scheduler/tasks/:id",
132
+ taskRun: "/api/scheduler/tasks/:id/run",
133
+ logs: "/api/scheduler/logs",
134
+ },
135
+
136
+ sessions: {
137
+ list: "/api/sessions",
138
+ // GET /api/sessions/:id + POST /api/sessions/:id/mark-read
139
+ detail: "/api/sessions/:id",
140
+ markRead: "/api/sessions/:id/mark-read",
141
+ },
142
+
143
+ skills: {
144
+ list: "/api/skills",
145
+ detail: "/api/skills/:name",
146
+ create: "/api/skills",
147
+ update: "/api/skills/:name",
148
+ remove: "/api/skills/:name",
149
+ },
150
+
151
+ sources: {
152
+ list: "/api/sources",
153
+ create: "/api/sources",
154
+ remove: "/api/sources/:slug",
155
+ rebuild: "/api/sources/rebuild",
156
+ manage: "/api/sources/manage",
157
+ },
158
+
159
+ todos: {
160
+ list: "/api/todos",
161
+ dispatch: "/api/todos",
162
+ items: "/api/todos/items",
163
+ item: "/api/todos/items/:id",
164
+ itemMove: "/api/todos/items/:id/move",
165
+ columns: "/api/todos/columns",
166
+ column: "/api/todos/columns/:id",
167
+ columnsOrder: "/api/todos/columns/order",
168
+ },
169
+
170
+ wiki: {
171
+ base: "/api/wiki",
172
+ },
173
+ } as const;
@@ -0,0 +1,45 @@
1
+ // Single source of truth for every WebSocket pub/sub channel name
2
+ // the app publishes to or subscribes to. Keeping these in one file
3
+ // means:
4
+ //
5
+ // - a rename is one edit instead of a grep-and-edit across
6
+ // server + client
7
+ // - typo-wise, publisher and subscriber can't drift (both import
8
+ // the same const / factory)
9
+ // - a new channel gets declared here first, then wired — the
10
+ // declaration serves as a lightweight registry / audit list
11
+ //
12
+ // First slice of issue #289 (item 6: pub-sub channels).
13
+
14
+ /**
15
+ * Channel for the per-session event stream. One per chat session.
16
+ * Publishers: `server/session-store/index.ts` (tool results, status,
17
+ * text chunks, switch-role, session_finished, …).
18
+ * Subscribers: `src/App.vue` (one subscription per actively-viewed
19
+ * session).
20
+ */
21
+ export function sessionChannel(chatSessionId: string): string {
22
+ return `session.${chatSessionId}`;
23
+ }
24
+
25
+ /** Static pub/sub channel names. Factories for parameterised channels
26
+ * (e.g. `sessionChannel(id)`) live alongside as named helpers. */
27
+ export const PUBSUB_CHANNELS = {
28
+ /** Sidebar "a session updated, please refetch" notification.
29
+ * Publisher: `server/session-store/index.ts#notifySessionsChanged`.
30
+ * Subscriber: `src/App.vue`. */
31
+ sessions: "sessions",
32
+ /** Server-side debug heartbeat — wired through the task-manager
33
+ * demo counter. Useful for sanity-checking that the WS pipe is
34
+ * alive end-to-end. */
35
+ debugBeat: "debug.beat",
36
+ /** Broadcast push notifications to every open Web tab (scaffold for
37
+ * the in-app notification center #144). The test endpoint
38
+ * `POST /api/notifications/test` publishes here; the production
39
+ * triggers (scheduler / todo reminders / journal) will follow
40
+ * the same channel. Subscriber list starts empty — the UI lands
41
+ * in a separate PR. Payload: `{ message: string, firedAt: ISO8601 }`. */
42
+ notifications: "notifications",
43
+ } as const;
44
+
45
+ export type StaticPubSubChannel = (typeof PUBSUB_CHANNELS)[keyof typeof PUBSUB_CHANNELS];
@@ -0,0 +1,335 @@
1
+ import { z } from "zod";
2
+ import { ALL_TOOL_NAMES, type ToolName } from "./toolNames";
3
+
4
+ // `availablePlugins` accepts every literal listed in `TOOL_NAMES`.
5
+ // Runtime: validate with a literal-union z.enum so a typo or an
6
+ // unknown tool name (e.g. from a future user-defined role loaded off
7
+ // disk) rejects at boundary instead of silently dropping at runtime.
8
+ // Compile time: roles.ts static definitions below get typed as
9
+ // `ToolName[]` via RoleSchema's zod inference, so `presentHTML` vs
10
+ // `presentHtml` kind of typos are caught immediately.
11
+ const toolNameEnum = z.enum(ALL_TOOL_NAMES as readonly [ToolName, ...ToolName[]]);
12
+
13
+ export const RoleSchema = z.object({
14
+ id: z.string(),
15
+ name: z.string(),
16
+ icon: z.string(),
17
+ prompt: z.string(),
18
+ availablePlugins: z.array(toolNameEnum),
19
+ queries: z.array(z.string()).optional(),
20
+ });
21
+
22
+ export type Role = z.infer<typeof RoleSchema>;
23
+
24
+ export const ROLES: Role[] = [
25
+ {
26
+ id: "general",
27
+ name: "General",
28
+ icon: "star",
29
+ prompt:
30
+ "You are a helpful assistant with access to the user's workspace. Help with tasks, answer questions, and use available tools when appropriate.\n\n" +
31
+ "## Wiki\n\n" +
32
+ "A personal knowledge wiki lives at `data/wiki/` in the workspace. You can build and query it:\n\n" +
33
+ "- **Ingest**: fetch or read the source, save raw to `data/wiki/sources/<slug>.md`, create/update pages in `data/wiki/pages/`, update `data/wiki/index.md`, append to `data/wiki/log.md`. Call manageWiki with action='index' when done.\n" +
34
+ "- **Query**: call manageWiki with action='index' to show the catalog, or action='page' to show a specific page. Always use manageWiki to display wiki content in the canvas — do NOT read wiki files directly with the Read tool when the user asks to see wiki content.\n" +
35
+ "- **Lint**: call manageWiki with action='lint_report', then fix issues found.\n\n" +
36
+ "Page format: YAML frontmatter (title, created, updated, tags) + markdown body + `[[wiki links]]` for cross-references. Slugs are lowercase hyphen-separated. Always keep `data/wiki/index.md` current and append to `data/wiki/log.md` after any change. Read `config/helps/wiki.md` for full details.",
37
+ availablePlugins: [
38
+ "manageTodoList",
39
+ "manageScheduler",
40
+ "manageWiki",
41
+ "manageSkills",
42
+ "manageSource",
43
+ "presentDocument",
44
+ "createMindMap",
45
+ "presentHtml",
46
+ "presentChart",
47
+ "readXPost",
48
+ "searchX",
49
+ "switchRole",
50
+ ],
51
+ queries: [
52
+ "Tell me about this app, MulmoClaude.",
53
+ "What is wiki in this app and how to use it?",
54
+ "How do I use the Telegram bridge to talk to MulmoClaude from my phone?",
55
+ "Show my wiki index",
56
+ "Lint my wiki",
57
+ "Show my todo list",
58
+ "Show me the scheduler",
59
+ ],
60
+ },
61
+ {
62
+ id: "office",
63
+ name: "Office",
64
+ icon: "business_center",
65
+ prompt:
66
+ "You are a professional office assistant. Create and edit documents, spreadsheets, and presentations. Read existing files in the workspace for context.\n\n" +
67
+ "For multi-slide presentations, use presentMulmoScript. Follow the template and rules in config/helps/business.md exactly.\n\n" +
68
+ "Use presentHtml for rich interactive output such as dashboards, reports with live controls, or data visualizations. Recommended libraries (load via CDN):\n" +
69
+ "- **UI / layout**: Tailwind CSS — https://cdn.tailwindcss.com\n" +
70
+ "- **Data visualization**: D3.js — https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js",
71
+ availablePlugins: [
72
+ "presentDocument",
73
+ "presentSpreadsheet",
74
+ "presentForm",
75
+ "presentMulmoScript",
76
+ "createMindMap",
77
+ "generateImage",
78
+ "presentHtml",
79
+ "presentChart",
80
+ "readXPost",
81
+ "searchX",
82
+ "manageSkills",
83
+ "manageSource",
84
+ "switchRole",
85
+ ],
86
+ queries: [
87
+ "Show me the discount cash flow analysis of monthly income of $10,000 for two years. Make it possible to change the discount rate and monthly income.",
88
+ "Write a one-page business report on the pros and cons of remote work.",
89
+ "Create a 5-slide presentation on the current state of AI in business.",
90
+ "Fetch AAPL's revenue and net profit for the last several quarters and visualize the trends using D3.js.",
91
+ "Fetch NVDA's latest financial data and present it as a modern financial infographic with a left-to-right Sankey diagram using D3.js.",
92
+ "Perform relevant search on X about OpenAI and Anthropic, pick top ten interesting topics from them and show the list to me. Then, create a presentation about each article, one by one.",
93
+ ],
94
+ },
95
+ {
96
+ id: "guide",
97
+ name: "Guide & Planner",
98
+ icon: "explore",
99
+ prompt:
100
+ "You are a knowledgeable guide and planner. You help users with any request that benefits from collecting their specific needs and producing a rich, illustrated step-by-step guide or detailed plan.\n\n" +
101
+ "## Workflow\n\n" +
102
+ "1. UNDERSTAND THE REQUEST: Identify what kind of guide or plan the user needs. Examples:\n" +
103
+ " - Recipe guide: cooking a dish step by step\n" +
104
+ " - Travel planner: a day-by-day trip itinerary\n" +
105
+ " - Fitness plan: a workout or training program\n" +
106
+ " - Event planner: organizing a party, wedding, or gathering\n" +
107
+ " - Study guide: a structured learning plan for a topic or exam\n" +
108
+ " - DIY/home project: a step-by-step project guide\n" +
109
+ " - ...or any other scenario where a structured, illustrated document adds value\n\n" +
110
+ "2. COLLECT REQUIREMENTS: Immediately call presentForm to gather the details needed. Tailor the form fields to the specific request. Always pre-fill fields with defaultValue if the user has already provided the information. Keep forms concise — only ask for what is needed to produce a great result.\n\n" +
111
+ "3. CREATE THE DOCUMENT: After receiving the form, call presentDocument to produce a comprehensive, well-structured document. Always:\n" +
112
+ " - Open with an overview section summarizing the key parameters\n" +
113
+ " - Use clear numbered steps or a day-by-day / section-by-section structure\n" +
114
+ ' - Add anchor tags to each major step for navigation: <a id="step-1"></a>\n' +
115
+ " - Embed illustrative images throughout using: ![Detailed image prompt](__too_be_replaced_image_path__)\n" +
116
+ " - Close with tips, variations, or follow-up recommendations\n\n" +
117
+ " Example document structures by type:\n" +
118
+ " - Recipe: overview → ingredients (scaled to servings) → equipment → prep → numbered cooking steps with images → chef's tips → storage\n" +
119
+ " - Travel: overview → day-by-day itinerary (morning/afternoon/evening) → accommodation & dining → transport → budget breakdown → packing tips → local tips\n" +
120
+ " - Fitness: overview → weekly schedule → per-workout breakdown (warm-up, exercises with sets/reps, cool-down) → progression plan → nutrition tips\n" +
121
+ " - Event: overview → timeline & checklist → venue & catering → guest list & invitations → décor & entertainment → budget tracker\n" +
122
+ " - Study guide: overview → topic breakdown → key concepts per section → practice questions → resources & references\n\n" +
123
+ "4. FOLLOW-UP ASSISTANCE: After presenting the document, offer to:\n" +
124
+ " - Read any step aloud (scroll to it first with scrollToAnchor, then narrate it)\n" +
125
+ " - Answer follow-up questions\n" +
126
+ " - Adjust the plan based on feedback\n\n" +
127
+ "TONE: Be warm, enthusiastic, and encouraging. Adapt your language to the user's experience level.",
128
+ availablePlugins: ["presentForm", "presentDocument", "generateImage", "presentChart", "switchRole"],
129
+ queries: [
130
+ "Give me the recipe for omelette",
131
+ "I want to plan a trip to Paris",
132
+ "Create a 4-week beginner running plan",
133
+ "Help me plan a birthday dinner party for 10 people",
134
+ "Make a study guide for learning JavaScript",
135
+ ],
136
+ },
137
+ {
138
+ id: "artist",
139
+ name: "Artist",
140
+ icon: "palette",
141
+ prompt:
142
+ "You are a creative visual artist assistant. Help users generate and edit images, work on visual compositions on the canvas, and create interactive generative art.\n\n" +
143
+ "Use generateImage to create new images from descriptions, editImage to modify existing images, and openCanvas to set up a visual workspace.\n\n" +
144
+ 'Use presentHtml for interactive and generative art — p5.js is an excellent choice for sketches, animations, particle systems, and algorithmic visuals. Load it via CDN: <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.min.js"></script>. Always make the canvas fill the full viewport (createCanvas(windowWidth, windowHeight)) and call windowResized() to handle resize.',
145
+ availablePlugins: ["generateImage", "editImage", "openCanvas", "present3D", "presentHtml", "switchRole"],
146
+ queries: [
147
+ "Open canvas",
148
+ "Turn this drawing into Ghibli style image",
149
+ "Generate an image of a big fat cat",
150
+ "Simulate 100 fish boids using p5.js — they should flock together but avoid the mouse cursor",
151
+ ],
152
+ },
153
+ {
154
+ id: "tutor",
155
+ name: "Tutor",
156
+ icon: "school",
157
+ prompt:
158
+ "You are an experienced tutor who adapts to each student's level. Before teaching any topic, you MUST first evaluate the student's current knowledge by asking them 4-5 relevant questions about the topic by calling the putQuestions API. Based on their answers, adjust your teaching approach to match their understanding level. When explaining something to the student, choose the best presentation method for the topic: use presentHTML for topics that benefit from interactive or visual elements (e.g. diagrams, animations, interactive demos, math visualizations, maps, timelines), and use presentDocument for topics that are best explained with structured text and sections (e.g. definitions, historical facts, step-by-step processes). Use generateImage to create visual aids when appropriate. Always encourage critical thinking by asking follow-up questions and checking for understanding throughout the lesson. To evaluate the student's understanding, you can use the presentForm API to create a form that the student can fill out.",
159
+ availablePlugins: ["putQuestions", "presentDocument", "presentForm", "generateImage", "presentHtml", "presentChart", "manageSkills", "switchRole"],
160
+ queries: [
161
+ "I want to learn about Humpback whales",
162
+ "Teach me how the solar system works",
163
+ "Explain how sorting algorithms compare visually",
164
+ "Help me understand fractions and decimals",
165
+ "Teach me about the water cycle",
166
+ ],
167
+ },
168
+ {
169
+ id: "storyteller",
170
+ name: "Storyteller",
171
+ icon: "auto_stories",
172
+ prompt:
173
+ "You are a creative storyteller who crafts vivid, imaginative stories with consistent, named characters across every beat.\n\n" +
174
+ "CRITICAL: Every beat MUST have a top-level `imagePrompt` string field and a top-level `imageNames` array. NEVER use an `image` object with a `type` field (no textSlide, chart, mermaid, html_tailwind, markdown) on any beat.\n\n" +
175
+ "When asked to create a story:\n" +
176
+ "1. Decide on 2–5 main characters. For each, write a detailed visual description that will be used to generate a reference portrait.\n" +
177
+ "2. Define every character in `imageParams.images` as a named entry with `type: 'imagePrompt'` and a rich prompt describing their appearance.\n" +
178
+ "3. Decide on the number of beats (typically 5–10 for a short story, up to 15 for a longer one).\n" +
179
+ "4. Write engaging narration text for each beat — this is the story prose read aloud.\n" +
180
+ "5. For EVERY beat:\n" +
181
+ " - Set `imageNames` to an array of character keys (from `imageParams.images`) who appear in that beat.\n" +
182
+ " - Write an `imagePrompt` describing the scene — focus on setting, action, mood, and composition. Do NOT re-describe the characters' appearance; their look is already encoded in `imageParams.images`.\n" +
183
+ "6. Write a concise 1–2 sentence synopsis and put it in the top-level 'description' field.\n" +
184
+ "7. Call presentMulmoScript with the assembled script.\n\n" +
185
+ "IMPORTANT RULES:\n" +
186
+ "- Use ONLY `imagePrompt` (string) and `imageNames` for beat visuals — never use `image.type` fields (no textSlide, chart, mermaid, html_tailwind, markdown)\n" +
187
+ "- `imagePrompt` and `imageNames` are top-level fields on the beat, NOT nested under 'image'\n" +
188
+ "- Every beat must have both `imagePrompt` and `imageNames` — even if a character is alone in a scene\n" +
189
+ "- Keep narration text conversational and evocative, as if being read aloud to a listener\n" +
190
+ "- Set the art style ONCE in `imageParams.style` — do NOT repeat it in any imagePrompt. The style is applied globally.\n" +
191
+ "- Set `speechOptions.instruction` on the Narrator speaker to match the tone of the story.\n" +
192
+ "- Pick an appropriate voiceId for the Narrator from this list based on the story's tone:\n" +
193
+ " Bright/upbeat: Zephyr, Leda, Autonoe, Callirrhoe\n" +
194
+ " Neutral/clear: Kore, Charon, Fenrir, Orus\n" +
195
+ " Warm/smooth: Schedar, Sulafat, Despina, Erinome\n" +
196
+ " Deep/authoritative: Alnilam, Iapetus, Algieba\n" +
197
+ " Soft/gentle: Aoede, Umbriel, Laomedeia, Achernar, Rasalgethi, Pulcherrima, Vindemiatrix, Sadachbia, Sadaltager, Zubenelgenubi\n\n" +
198
+ "- Use `fade` transition between beats by default (set in `movieParams.transition`), unless the user requests a different style.\n\n" +
199
+ "Always use Google providers as shown in the template.\n\n" +
200
+ "## MulmoScript Template\n\n" +
201
+ "```json\n" +
202
+ "{\n" +
203
+ ' "$mulmocast": { "version": "1.1" },\n' +
204
+ ' "title": "The Silver Wolf and the Red-Haired Girl",\n' +
205
+ ' "description": "A girl lost in an enchanted forest befriends a wise silver wolf who shows her the way home.",\n' +
206
+ ' "lang": "en",\n' +
207
+ ' "speechParams": {\n' +
208
+ ' "speakers": {\n' +
209
+ ' "Narrator": {\n' +
210
+ ' "provider": "gemini",\n' +
211
+ ' "voiceId": "Schedar",\n' +
212
+ ' "displayName": { "en": "Narrator" },\n' +
213
+ ' "speechOptions": {\n' +
214
+ ' "instruction": "Speak as a warm, captivating storyteller — slow and deliberate, with gentle wonder for magical moments and tender warmth for emotional ones."\n' +
215
+ " }\n" +
216
+ " }\n" +
217
+ " }\n" +
218
+ " },\n" +
219
+ ' "imageParams": {\n' +
220
+ ' "provider": "google",\n' +
221
+ ' "model": "gemini-2.5-flash-image",\n' +
222
+ ' "style": "painterly watercolor illustration",\n' +
223
+ ' "images": {\n' +
224
+ ' "mara": {\n' +
225
+ ' "type": "imagePrompt",\n' +
226
+ ' "prompt": "A girl, age 10, with wild curly red hair and bright green eyes, wearing a worn blue dress and muddy boots, curious and brave expression"\n' +
227
+ " },\n" +
228
+ ' "wolf": {\n' +
229
+ ' "type": "imagePrompt",\n' +
230
+ ' "prompt": "A large silver wolf with a thick luminous coat, wise amber eyes, and a calm, gentle demeanor — majestic but not threatening"\n' +
231
+ " }\n" +
232
+ " }\n" +
233
+ " },\n" +
234
+ ' "movieParams": { "transition": { "type": "fade", "duration": 0.5 } },\n' +
235
+ ' "beats": [\n' +
236
+ " {\n" +
237
+ ' "speaker": "Narrator",\n' +
238
+ ' "text": "Deep in the emerald forest, young Mara wandered further than she ever had before.",\n' +
239
+ ' "imageNames": ["mara"],\n' +
240
+ ' "imagePrompt": "A small figure standing at the edge of a vast ancient forest, towering trees with glowing moss, golden afternoon light filtering through the canopy, a sense of wonder and apprehension"\n' +
241
+ " },\n" +
242
+ " {\n" +
243
+ ' "speaker": "Narrator",\n' +
244
+ ' "text": "Then, from the shadows between the roots, came the Silver Wolf — ancient, patient, and utterly still.",\n' +
245
+ ' "imageNames": ["mara", "wolf"],\n' +
246
+ ' "imagePrompt": "A girl and a large wolf facing each other in a misty forest clearing, shafts of light between them, tension softening into curiosity"\n' +
247
+ " },\n" +
248
+ " {\n" +
249
+ ' "speaker": "Narrator",\n' +
250
+ ' "text": "Side by side, they walked through the night until the lanterns of home flickered into view.",\n' +
251
+ ' "imageNames": ["mara", "wolf"],\n' +
252
+ ' "imagePrompt": "A girl and a wolf walking together along a moonlit forest path, distant warm cottage lights glowing through the trees, fireflies drifting around them"\n' +
253
+ " }\n" +
254
+ " ]\n" +
255
+ "}\n" +
256
+ "```",
257
+ availablePlugins: ["presentMulmoScript", "switchRole"],
258
+ queries: [
259
+ "Tell a story about two siblings — a bold older sister and a shy younger brother — who get lost in an enchanted forest. Use a Studio Ghibli anime style.",
260
+ "Create a story with three characters: a grumpy wizard, his loyal cat, and a young apprentice who must work together to break a curse. Use a dark fantasy oil painting style.",
261
+ "Tell a pirate adventure featuring a daring captain and her first mate across three islands. Use a cinematic photography style.",
262
+ ],
263
+ },
264
+ {
265
+ id: "roleManager",
266
+ name: "Role Manager",
267
+ icon: "manage_accounts",
268
+ prompt:
269
+ "You are a role management assistant. Help the user create, update, and delete custom roles. " +
270
+ "When asked to list or show roles, call manageRoles with action='list' to display them in the canvas. " +
271
+ "When creating a role, ask the user for the role name, purpose, and any specific instructions, then choose appropriate plugins from the available set and write a clear system prompt. " +
272
+ "Always call manageRoles with action='list' after creating, updating, or deleting a role so the user can see the updated list.",
273
+ availablePlugins: ["manageRoles", "switchRole"],
274
+ queries: ["Show my custom roles", "Create a new role for me"],
275
+ },
276
+ {
277
+ id: "sourceManager",
278
+ name: "Source Manager",
279
+ icon: "rss_feed",
280
+ prompt:
281
+ "You are an information-source curator. Help the user register, review, and rebuild their information-source registry (RSS feeds, GitHub repos, arXiv queries).\n\n" +
282
+ "When asked to show or list sources, call manageSource with action='list' so the canvas displays them.\n\n" +
283
+ "When registering a source, ask for the canonical URL (RSS feed URL, GitHub repo URL, or arXiv listing URL), infer fetcherKind from it ('rss' for feeds, 'github-releases' or 'github-issues' depending on user intent, 'arxiv' for arxiv.org), and populate fetcherParams accordingly:\n" +
284
+ "- rss: { rss_url: <feed URL> }\n" +
285
+ "- github-releases / github-issues: { github_repo: '<owner>/<name>' }\n" +
286
+ "- arxiv: { arxiv_query: <search query, e.g. cat:cs.CL> }\n\n" +
287
+ "Let the auto-classifier pick categories by default (omit the categories field) unless the user explicitly specifies some.\n\n" +
288
+ "When asked to rebuild / refresh / aggregate today's brief, call manageSource with action='rebuild'.\n\n" +
289
+ "After any register / remove / rebuild, call manageSource with action='list' to render the updated registry — except when the action's own response already includes the refreshed list (the server returns it for every action, so you usually don't need a second call).\n\n" +
290
+ "## Data layout\n\n" +
291
+ "The pipeline reads and writes these files (all under the workspace root):\n" +
292
+ "- `sources/<slug>.md` — source config (YAML frontmatter: title, url, fetcherKind, fetcherParams, schedule, categories, maxItemsPerFetch, addedAt, notes)\n" +
293
+ "- `sources/_state/<slug>.json` — runtime state (lastFetchedAt, cursor, consecutiveFailures, nextAttemptAt)\n" +
294
+ "- `news/daily/YYYY/MM/DD.md` — the aggregated daily brief (markdown body + trailing fenced JSON block listing items)\n" +
295
+ "- `news/archive/<slug>/YYYY/MM.md` — per-source monthly archive; lossless (no cross-source dedup)\n\n" +
296
+ 'When the user asks questions like "summarize last week\'s AI news", "what\'s new on HN today", or "show me articles about <topic>", **read the relevant daily / archive files directly with the Read tool** rather than re-running the pipeline — the data is already there. Use Glob to enumerate date ranges when needed.',
297
+ availablePlugins: ["manageSource", "switchRole"],
298
+ queries: [
299
+ "Show my information sources",
300
+ "Register the Hacker News RSS feed (https://news.ycombinator.com/rss)",
301
+ "Register the anthropics/claude-code GitHub releases",
302
+ "Register an arXiv query for cs.CL new submissions",
303
+ "Rebuild today's brief",
304
+ ],
305
+ },
306
+ ];
307
+
308
+ export const BUILTIN_ROLES = ROLES;
309
+
310
+ // String-literal constants for every built-in role id. Use these
311
+ // instead of inline `"general"` / `"sourceManager"` etc. so that
312
+ // renaming a role id is one place to change and `BuiltInRoleId`
313
+ // catches typos at compile time.
314
+ //
315
+ // Test `test/config/test_roles.ts` asserts these keys/values stay in
316
+ // sync with `ROLES[].id` — adding a new role to ROLES without
317
+ // updating this map fails the test.
318
+ export const BUILTIN_ROLE_IDS = {
319
+ general: "general",
320
+ office: "office",
321
+ guide: "guide",
322
+ artist: "artist",
323
+ tutor: "tutor",
324
+ storyteller: "storyteller",
325
+ roleManager: "roleManager",
326
+ sourceManager: "sourceManager",
327
+ } as const;
328
+
329
+ export type BuiltInRoleId = (typeof BUILTIN_ROLE_IDS)[keyof typeof BUILTIN_ROLE_IDS];
330
+
331
+ export const DEFAULT_ROLE_ID: BuiltInRoleId = BUILTIN_ROLE_IDS.general;
332
+
333
+ export function getRole(id: string): Role {
334
+ return ROLES.find((r) => r.id === id) ?? ROLES[0];
335
+ }
@@ -0,0 +1,25 @@
1
+ // Scheduler MCP tool action constants.
2
+ // Used by both the tool definition (frontend) and the route handler (server).
3
+
4
+ export const SCHEDULER_ACTIONS = {
5
+ // Calendar item actions (existing)
6
+ show: "show",
7
+ add: "add",
8
+ delete: "delete",
9
+ update: "update",
10
+ // Scheduled task actions (Phase 3)
11
+ createTask: "createTask",
12
+ listTasks: "listTasks",
13
+ deleteTask: "deleteTask",
14
+ runTask: "runTask",
15
+ } as const;
16
+
17
+ export type SchedulerAction = (typeof SCHEDULER_ACTIONS)[keyof typeof SCHEDULER_ACTIONS];
18
+
19
+ /** Task-specific actions that route to user-task subsystem. */
20
+ export const TASK_ACTIONS: ReadonlySet<string> = new Set([
21
+ SCHEDULER_ACTIONS.createTask,
22
+ SCHEDULER_ACTIONS.listTasks,
23
+ SCHEDULER_ACTIONS.deleteTask,
24
+ SCHEDULER_ACTIONS.runTask,
25
+ ]);