mulmoclaude 0.5.2 → 0.6.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 (486) hide show
  1. package/Dockerfile.sandbox +100 -0
  2. package/README.md +17 -4
  3. package/bin/mulmoclaude.js +46 -15
  4. package/bin/prepare-dist.js +18 -2
  5. package/client/assets/chunk-CernVdwh.js +1 -0
  6. package/client/assets/chunk-D8eiyYIV-C1eAZMzz.js +1 -0
  7. package/client/assets/html2canvas-CDGcmOD3-BbPeutDg.js +5 -0
  8. package/client/assets/index-BbgSjFQ8.js +4968 -0
  9. package/client/assets/index-ECD0lgIv.css +2 -0
  10. package/client/assets/{index.es-D4YyL_Dg-BgT6a3Nd.js → index.es-DqtpmBm8-DJdTPdnc.js} +5 -5
  11. package/client/assets/material-symbols-outlined-BLDfUw-_.woff2 +0 -0
  12. package/client/assets/runtime-protocol-vue-6WYa8hAs.js +1 -0
  13. package/client/assets/runtime-vue-BVUzgYGA.js +1 -0
  14. package/client/assets/typeof-DBp4T-Ny-C2xoZtcz.js +1 -0
  15. package/client/assets/vue-1e_vz2LW.js +1 -0
  16. package/client/assets/vue.runtime.esm-bundler-DQ8Kjjui.js +4 -0
  17. package/client/index.html +33 -2
  18. package/package.json +20 -18
  19. package/sandbox-entrypoint.sh +106 -0
  20. package/server/accounting/accountNormalize.ts +32 -0
  21. package/server/accounting/defaultAccounts.ts +87 -0
  22. package/server/accounting/eventPublisher.ts +51 -0
  23. package/server/accounting/journal.ts +252 -0
  24. package/server/accounting/openingBalances.ts +114 -0
  25. package/server/accounting/report.ts +237 -0
  26. package/server/accounting/service.ts +718 -0
  27. package/server/accounting/snapshotCache.ts +333 -0
  28. package/server/accounting/timeSeries.ts +265 -0
  29. package/server/accounting/types.ts +148 -0
  30. package/server/agent/activeTools.ts +128 -0
  31. package/server/agent/attachmentConverter.ts +10 -5
  32. package/server/agent/backend/claude-code.ts +8 -2
  33. package/server/agent/backend/types.ts +1 -1
  34. package/server/agent/config.ts +101 -31
  35. package/server/agent/index.ts +45 -33
  36. package/server/agent/mcp-server.ts +146 -69
  37. package/server/agent/mcp-tools/index.ts +1 -5
  38. package/server/agent/mcp-tools/notify.ts +2 -22
  39. package/server/agent/mcp-tools/x.ts +0 -4
  40. package/server/agent/mcpHealth.ts +168 -0
  41. package/server/agent/plugin-names.ts +20 -77
  42. package/server/agent/prompt.ts +259 -51
  43. package/server/agent/resumeFailover.ts +1 -1
  44. package/server/agent/stream.ts +0 -1
  45. package/server/api/auth/bearerAuth.ts +5 -5
  46. package/server/api/csrfGuard.ts +1 -1
  47. package/server/api/routes/accounting.ts +366 -0
  48. package/server/api/routes/agent.ts +509 -46
  49. package/server/api/routes/attachment.ts +104 -0
  50. package/server/api/routes/chart.ts +2 -1
  51. package/server/api/routes/config.ts +12 -12
  52. package/server/api/routes/files.ts +105 -48
  53. package/server/api/routes/image.ts +70 -25
  54. package/server/api/routes/journal.ts +35 -0
  55. package/server/api/routes/mulmo-script.ts +358 -118
  56. package/server/api/routes/mulmoScriptValidate.ts +1 -1
  57. package/server/api/routes/news.ts +1 -1
  58. package/server/api/routes/notifications.ts +92 -22
  59. package/server/api/routes/notifier.ts +98 -0
  60. package/server/api/routes/pdf.ts +188 -48
  61. package/server/api/routes/plugins.ts +34 -14
  62. package/server/api/routes/presentHtml.ts +58 -3
  63. package/server/api/routes/roles.ts +1 -8
  64. package/server/api/routes/runtime-plugin.ts +224 -0
  65. package/server/api/routes/scheduler.ts +7 -5
  66. package/server/api/routes/schedulerHandlers.ts +1 -1
  67. package/server/api/routes/schedulerTasks.ts +8 -7
  68. package/server/api/routes/sessions.ts +234 -121
  69. package/server/api/routes/skills.ts +56 -51
  70. package/server/api/routes/sources.ts +52 -45
  71. package/server/api/routes/translation.ts +44 -0
  72. package/server/api/routes/wiki/frontmatter.ts +13 -65
  73. package/server/api/routes/wiki/history.ts +261 -0
  74. package/server/api/routes/wiki/pageIndex.ts +1 -1
  75. package/server/api/routes/wiki.ts +50 -26
  76. package/server/events/file-change.ts +83 -0
  77. package/server/events/notifications.ts +247 -91
  78. package/server/events/pub-sub/index.ts +1 -1
  79. package/server/events/relay-client.ts +5 -5
  80. package/server/events/scheduler-adapter.ts +2 -2
  81. package/server/events/session-store/index.ts +110 -22
  82. package/server/events/task-manager/index.ts +10 -9
  83. package/server/index.ts +509 -33
  84. package/server/notifier/engine.ts +419 -0
  85. package/server/notifier/legacy-adapters.ts +76 -0
  86. package/server/notifier/runtime-api.ts +74 -0
  87. package/server/notifier/store.ts +70 -0
  88. package/server/notifier/types.ts +121 -0
  89. package/server/plugins/dev-loader.ts +171 -0
  90. package/server/plugins/dev-watcher.ts +150 -0
  91. package/server/plugins/diagnostics.ts +188 -0
  92. package/server/plugins/preset-list.ts +52 -0
  93. package/server/plugins/preset-loader.ts +112 -0
  94. package/server/plugins/runtime-chat-api.ts +38 -0
  95. package/server/plugins/runtime-loader.ts +430 -0
  96. package/server/plugins/runtime-registry.ts +112 -0
  97. package/server/plugins/runtime-tasks-api.ts +50 -0
  98. package/server/plugins/runtime.ts +378 -0
  99. package/server/services/translation/cache.ts +72 -0
  100. package/server/services/translation/index.ts +106 -0
  101. package/server/services/translation/llm.ts +140 -0
  102. package/server/services/translation/types.ts +35 -0
  103. package/server/system/credentials.ts +13 -2
  104. package/server/system/env.ts +6 -1
  105. package/server/system/logger/formatters.ts +46 -4
  106. package/server/system/logger/index.ts +4 -4
  107. package/server/system/logger/sinks.ts +26 -5
  108. package/server/system/logger/types.ts +2 -2
  109. package/server/utils/dev-plugin-args.d.mts +11 -0
  110. package/server/utils/dev-plugin-args.mjs +43 -0
  111. package/server/utils/errors.ts +13 -4
  112. package/server/utils/files/accounting-io.ts +295 -0
  113. package/server/utils/files/atomic.ts +17 -49
  114. package/server/utils/files/attachment-store.ts +182 -0
  115. package/server/utils/files/html-io.ts +1 -7
  116. package/server/utils/files/html-store.ts +19 -0
  117. package/server/utils/files/image-store.ts +20 -22
  118. package/server/utils/files/index.ts +5 -15
  119. package/server/utils/files/journal-io.ts +7 -35
  120. package/server/utils/files/json.ts +2 -29
  121. package/server/utils/files/markdown-image-fill.ts +6 -37
  122. package/server/utils/files/markdown-store.ts +6 -21
  123. package/server/utils/files/naming.ts +3 -39
  124. package/server/utils/files/plugins-io.ts +100 -0
  125. package/server/utils/files/reference-dirs-io.ts +1 -9
  126. package/server/utils/files/roles-io.ts +2 -10
  127. package/server/utils/files/safe.ts +17 -19
  128. package/server/utils/files/scheduler-io.ts +1 -7
  129. package/server/utils/files/scheduler-overrides-io.ts +3 -12
  130. package/server/utils/files/session-io.ts +21 -30
  131. package/server/utils/files/spreadsheet-store.ts +9 -22
  132. package/server/utils/files/translation-io.ts +46 -0
  133. package/server/utils/files/user-tasks-io.ts +1 -7
  134. package/server/utils/files/workspace-io.ts +3 -79
  135. package/server/utils/gemini.ts +33 -11
  136. package/server/utils/html/htmlArtifactSplicer.ts +41 -0
  137. package/server/utils/markdown/frontmatter.ts +112 -0
  138. package/server/utils/regex.ts +56 -0
  139. package/server/utils/router.ts +41 -0
  140. package/server/utils/slug.ts +5 -3
  141. package/server/utils/time.ts +12 -0
  142. package/server/workspace/chat-index/indexer.ts +15 -2
  143. package/server/workspace/chat-index/summarizer.ts +1 -1
  144. package/server/workspace/custom-dirs.ts +1 -1
  145. package/server/workspace/helps/gemini.md +1 -1
  146. package/server/workspace/helps/guide.md +61 -0
  147. package/server/workspace/helps/index.md +4 -0
  148. package/server/workspace/helps/presenthtml.md +80 -0
  149. package/server/workspace/helps/sandbox.md +7 -0
  150. package/server/workspace/helps/storyteller.md +101 -0
  151. package/server/workspace/helps/telegram.md +1 -0
  152. package/server/workspace/helps/wiki.md +9 -7
  153. package/server/workspace/journal/archivist-cli.ts +7 -33
  154. package/server/workspace/journal/archivist-schemas.ts +5 -43
  155. package/server/workspace/journal/dailyPass.ts +34 -187
  156. package/server/workspace/journal/diff.ts +3 -28
  157. package/server/workspace/journal/index.ts +10 -81
  158. package/server/workspace/journal/indexFile.ts +3 -24
  159. package/server/workspace/journal/latestDaily.ts +51 -0
  160. package/server/workspace/journal/memoryExtractor.ts +4 -20
  161. package/server/workspace/journal/optimizationPass.ts +4 -21
  162. package/server/workspace/journal/paths.ts +4 -23
  163. package/server/workspace/journal/state.ts +6 -29
  164. package/server/workspace/memory/io.ts +213 -0
  165. package/server/workspace/memory/llm-classifier.ts +158 -0
  166. package/server/workspace/memory/migrate.ts +263 -0
  167. package/server/workspace/memory/run.ts +84 -0
  168. package/server/workspace/memory/topic-cluster.ts +218 -0
  169. package/server/workspace/memory/topic-detect.ts +67 -0
  170. package/server/workspace/memory/topic-index-hook.ts +128 -0
  171. package/server/workspace/memory/topic-io.ts +180 -0
  172. package/server/workspace/memory/topic-migrate.ts +248 -0
  173. package/server/workspace/memory/topic-run.ts +172 -0
  174. package/server/workspace/memory/topic-swap.ts +135 -0
  175. package/server/workspace/memory/topic-types.ts +142 -0
  176. package/server/workspace/memory/types.ts +83 -0
  177. package/server/workspace/news/reader.ts +4 -5
  178. package/server/workspace/paths.ts +124 -47
  179. package/server/workspace/roles.ts +2 -11
  180. package/server/workspace/skills/parser.ts +38 -55
  181. package/server/workspace/skills/user-tasks.ts +1 -2
  182. package/server/workspace/skills-preset/mc-library/SKILL.md +188 -0
  183. package/server/workspace/skills-preset.ts +196 -0
  184. package/server/workspace/sources/fetchers/githubIssues.ts +13 -11
  185. package/server/workspace/sources/fetchers/index.ts +1 -1
  186. package/server/workspace/sources/fetchers/rssParser.ts +1 -1
  187. package/server/workspace/sources/pipeline/index.ts +2 -2
  188. package/server/workspace/sources/pipeline/notify.ts +3 -3
  189. package/server/workspace/sources/pipeline/write.ts +2 -2
  190. package/server/workspace/sources/registry.ts +39 -61
  191. package/server/workspace/sources/robots.ts +1 -1
  192. package/server/workspace/tool-trace/classify.ts +2 -1
  193. package/server/workspace/tool-trace/index.ts +1 -1
  194. package/server/workspace/tool-trace/writeSearch.ts +6 -1
  195. package/server/workspace/wiki-backlinks/index.ts +19 -7
  196. package/server/workspace/wiki-backlinks/sessionBacklinks.ts +1 -0
  197. package/server/workspace/wiki-history/hook/snapshot.mjs +98 -0
  198. package/server/workspace/wiki-history/hook/snapshot.ts +135 -0
  199. package/server/workspace/wiki-history/provision.ts +181 -0
  200. package/server/workspace/wiki-pages/io.ts +217 -0
  201. package/server/workspace/wiki-pages/snapshot.ts +380 -0
  202. package/server/workspace/workspace.ts +75 -13
  203. package/src/App.vue +115 -40
  204. package/src/_runtime/protocol-vue.ts +21 -0
  205. package/src/_runtime/vue.ts +22 -0
  206. package/src/components/ChatInput.vue +14 -10
  207. package/src/components/CopyChatButton.vue +76 -0
  208. package/src/components/FileContentRenderer.vue +67 -14
  209. package/src/components/FileTree.vue +2 -2
  210. package/src/components/FilesView.vue +17 -1
  211. package/src/components/NewsView.vue +16 -2
  212. package/src/components/NotificationBell.vue +320 -93
  213. package/src/components/PageChatComposer.vue +5 -4
  214. package/src/components/PluginLauncher.vue +42 -6
  215. package/src/components/PluginScopedRoot.vue +87 -0
  216. package/src/components/RoleSelector.vue +12 -1
  217. package/src/components/RolesView.vue +562 -0
  218. package/src/components/SentAttachmentChip.vue +102 -0
  219. package/src/components/SessionHistoryPanel.vue +109 -20
  220. package/src/components/SessionRoleIcon.vue +7 -4
  221. package/src/components/SessionSidebar.vue +20 -7
  222. package/src/components/SessionTabBar.vue +1 -1
  223. package/src/components/SettingsMcpTab.vue +4 -4
  224. package/src/components/SettingsModal.vue +2 -0
  225. package/src/components/SidebarHeader.vue +16 -5
  226. package/src/components/SourcesManager.vue +23 -9
  227. package/src/components/SourcesView.vue +1 -1
  228. package/src/components/StackView.vue +102 -6
  229. package/src/components/SuggestionsPanel.vue +105 -16
  230. package/src/components/SystemFileBanner.vue +1 -1
  231. package/src/components/TodoExplorer.vue +4 -5
  232. package/src/components/todo/TodoAddDialog.vue +2 -3
  233. package/src/components/todo/TodoEditDialog.vue +1 -2
  234. package/src/components/todo/TodoEditPanel.vue +2 -3
  235. package/src/components/todo/TodoKanbanView.vue +8 -5
  236. package/src/components/todo/TodoListView.vue +3 -5
  237. package/src/components/todo/TodoTableView.vue +7 -5
  238. package/src/composables/useAccountingChannel.ts +58 -0
  239. package/src/composables/useActiveSession.ts +4 -25
  240. package/src/composables/useAppApi.ts +6 -44
  241. package/src/composables/useClipboardCopy.ts +3 -20
  242. package/src/composables/useContentDisplay.ts +33 -2
  243. package/src/composables/useDevPluginReload.ts +23 -0
  244. package/src/composables/useDynamicFavicon.ts +5 -31
  245. package/src/composables/useEventListeners.ts +0 -20
  246. package/src/composables/useExpandedDirs.ts +4 -15
  247. package/src/composables/useFaviconState.ts +12 -46
  248. package/src/composables/useFileChange.ts +53 -0
  249. package/src/composables/useFreshPluginData.ts +6 -43
  250. package/src/composables/useHealth.ts +14 -43
  251. package/src/composables/useImageErrorRepair.ts +104 -0
  252. package/src/composables/useLatestDaily.ts +40 -0
  253. package/src/composables/useMarkdownDoc.ts +39 -0
  254. package/src/composables/useMarkdownLinkHandler.ts +1 -1
  255. package/src/composables/useMcpTools.ts +3 -16
  256. package/src/composables/useNotifications.ts +138 -112
  257. package/src/composables/usePdfDownload.ts +17 -3
  258. package/src/composables/usePendingCalls.ts +8 -26
  259. package/src/composables/usePluginErrorBoundary.ts +68 -0
  260. package/src/composables/usePubSub.ts +9 -17
  261. package/src/composables/useRunElapsed.ts +5 -22
  262. package/src/composables/useSandboxStatus.ts +4 -20
  263. package/src/composables/useSessionDerived.ts +7 -15
  264. package/src/composables/useSessionHistory.ts +70 -29
  265. package/src/composables/useSessionSync.ts +25 -3
  266. package/src/composables/useSkillsList.ts +59 -0
  267. package/src/composables/useTranslatedQueries.ts +109 -0
  268. package/src/config/apiRoutes.ts +181 -80
  269. package/src/config/historyFilters.ts +5 -3
  270. package/src/config/hostEvents.ts +17 -0
  271. package/src/config/mcpCatalog.ts +277 -5
  272. package/src/config/pubsubChannels.ts +134 -12
  273. package/src/config/roles.ts +212 -147
  274. package/src/config/systemFileDescriptors.ts +5 -5
  275. package/src/config/toolNames.ts +52 -30
  276. package/src/config/workspacePaths.ts +26 -2
  277. package/src/lang/de.ts +483 -27
  278. package/src/lang/en.ts +448 -27
  279. package/src/lang/es.ts +474 -27
  280. package/src/lang/fr.ts +476 -27
  281. package/src/lang/ja.ts +465 -27
  282. package/src/lang/ko.ts +466 -27
  283. package/src/lang/pt-BR.ts +473 -27
  284. package/src/lang/zh.ts +463 -27
  285. package/src/lib/vue-i18n.ts +1 -1
  286. package/src/lib/wiki-page/slug.ts +66 -0
  287. package/src/main.ts +85 -0
  288. package/src/plugins/_extras.ts +58 -0
  289. package/src/plugins/_generated/metas.ts +42 -0
  290. package/src/plugins/_generated/registrations.ts +44 -0
  291. package/src/plugins/_generated/server-bindings.ts +47 -0
  292. package/src/plugins/accounting/Preview.vue +106 -0
  293. package/src/plugins/accounting/View.vue +632 -0
  294. package/src/plugins/accounting/actions.ts +34 -0
  295. package/src/plugins/accounting/api.ts +301 -0
  296. package/src/plugins/accounting/components/AccountEditor.vue +250 -0
  297. package/src/plugins/accounting/components/AccountRow.vue +50 -0
  298. package/src/plugins/accounting/components/AccountsList.vue +102 -0
  299. package/src/plugins/accounting/components/AccountsModal.vue +300 -0
  300. package/src/plugins/accounting/components/BalanceSheet.vue +186 -0
  301. package/src/plugins/accounting/components/BookSettings.vue +284 -0
  302. package/src/plugins/accounting/components/BookSwitcher.vue +78 -0
  303. package/src/plugins/accounting/components/DateRangePicker.vue +140 -0
  304. package/src/plugins/accounting/components/JournalEntryForm.vue +504 -0
  305. package/src/plugins/accounting/components/JournalList.vue +553 -0
  306. package/src/plugins/accounting/components/Ledger.vue +206 -0
  307. package/src/plugins/accounting/components/NewBookForm.vue +211 -0
  308. package/src/plugins/accounting/components/OpeningBalancesForm.vue +271 -0
  309. package/src/plugins/accounting/components/ProfitLoss.vue +160 -0
  310. package/src/plugins/accounting/components/accountDraft.ts +13 -0
  311. package/src/plugins/accounting/components/accountNumbering.ts +103 -0
  312. package/src/plugins/accounting/components/accountValidation.ts +75 -0
  313. package/src/plugins/accounting/components/useLatestRequest.ts +44 -0
  314. package/src/plugins/accounting/countries.ts +158 -0
  315. package/src/plugins/accounting/currencies.ts +64 -0
  316. package/src/plugins/accounting/dates.ts +51 -0
  317. package/src/plugins/accounting/definition.ts +199 -0
  318. package/src/plugins/accounting/fiscalYear.ts +136 -0
  319. package/src/plugins/accounting/index.ts +49 -0
  320. package/src/plugins/accounting/meta.ts +91 -0
  321. package/src/plugins/accounting/timeSeriesEnums.ts +16 -0
  322. package/src/plugins/api.ts +125 -0
  323. package/src/plugins/canvas/View.vue +38 -28
  324. package/src/plugins/canvas/definition.ts +10 -8
  325. package/src/plugins/canvas/index.ts +15 -8
  326. package/src/plugins/canvas/meta.ts +12 -0
  327. package/src/plugins/chart/Preview.vue +1 -1
  328. package/src/plugins/chart/View.vue +2 -2
  329. package/src/plugins/chart/definition.ts +12 -2
  330. package/src/plugins/chart/index.ts +15 -7
  331. package/src/plugins/chart/meta.ts +18 -0
  332. package/src/plugins/editImages/definition.ts +44 -0
  333. package/src/plugins/editImages/index.ts +43 -0
  334. package/src/plugins/editImages/meta.ts +5 -0
  335. package/src/plugins/generateImage/View.vue +3 -1
  336. package/src/plugins/generateImage/definition.ts +2 -0
  337. package/src/plugins/generateImage/index.ts +13 -5
  338. package/src/plugins/generateImage/meta.ts +5 -0
  339. package/src/plugins/index.ts +35 -0
  340. package/src/plugins/manageRoles/Preview.vue +7 -4
  341. package/src/plugins/manageRoles/View.vue +12 -8
  342. package/src/plugins/manageRoles/definition.ts +6 -0
  343. package/src/plugins/manageRoles/index.ts +7 -6
  344. package/src/plugins/manageSkills/View.vue +11 -7
  345. package/src/plugins/manageSkills/definition.ts +4 -1
  346. package/src/plugins/manageSkills/index.ts +14 -7
  347. package/src/plugins/manageSkills/meta.ts +21 -0
  348. package/src/plugins/manageSource/definition.ts +4 -1
  349. package/src/plugins/manageSource/index.ts +15 -7
  350. package/src/plugins/manageSource/meta.ts +21 -0
  351. package/src/plugins/markdown/Preview.vue +10 -8
  352. package/src/plugins/markdown/View.vue +84 -17
  353. package/src/plugins/markdown/definition.ts +7 -1
  354. package/src/plugins/markdown/index.ts +15 -8
  355. package/src/plugins/markdown/meta.ts +16 -0
  356. package/src/plugins/meta-types.ts +97 -0
  357. package/src/plugins/metas.ts +224 -0
  358. package/src/plugins/presentForm/Preview.vue +4 -15
  359. package/src/plugins/presentForm/View.vue +35 -78
  360. package/src/plugins/presentForm/definition.ts +7 -6
  361. package/src/plugins/presentForm/index.ts +12 -5
  362. package/src/plugins/presentForm/meta.ts +11 -0
  363. package/src/plugins/presentForm/plugin.ts +8 -9
  364. package/src/plugins/presentForm/types.ts +0 -24
  365. package/src/plugins/presentHtml/Preview.vue +1 -8
  366. package/src/plugins/presentHtml/View.vue +401 -30
  367. package/src/plugins/presentHtml/definition.ts +8 -5
  368. package/src/plugins/presentHtml/index.ts +15 -8
  369. package/src/plugins/presentHtml/meta.ts +14 -0
  370. package/src/plugins/presentMulmoScript/View.vue +327 -107
  371. package/src/plugins/presentMulmoScript/definition.ts +34 -7
  372. package/src/plugins/presentMulmoScript/helpers.ts +4 -5
  373. package/src/plugins/presentMulmoScript/index.ts +20 -7
  374. package/src/plugins/presentMulmoScript/meta.ts +52 -0
  375. package/src/plugins/scheduler/AutomationsPreview.vue +2 -8
  376. package/src/plugins/scheduler/Preview.vue +5 -2
  377. package/src/plugins/scheduler/TasksTab.vue +16 -36
  378. package/src/plugins/scheduler/View.vue +22 -54
  379. package/src/plugins/scheduler/automationsDefinition.ts +14 -9
  380. package/src/plugins/scheduler/automationsMeta.ts +5 -0
  381. package/src/plugins/scheduler/calendarDefinition.ts +4 -7
  382. package/src/plugins/scheduler/calendarMeta.ts +28 -0
  383. package/src/plugins/scheduler/formatSchedule.ts +6 -24
  384. package/src/plugins/scheduler/index.ts +26 -52
  385. package/src/plugins/scope.ts +57 -0
  386. package/src/plugins/server-bindings-types.ts +38 -0
  387. package/src/plugins/server.ts +32 -0
  388. package/src/plugins/skill/Preview.vue +25 -0
  389. package/src/plugins/skill/View.vue +125 -0
  390. package/src/plugins/skill/definition.ts +23 -0
  391. package/src/plugins/skill/index.ts +36 -0
  392. package/src/plugins/skill/plugin.ts +31 -0
  393. package/src/plugins/skill/types.ts +21 -0
  394. package/src/plugins/spreadsheet/Preview.vue +1 -3
  395. package/src/plugins/spreadsheet/View.vue +29 -49
  396. package/src/plugins/spreadsheet/cellHighlights.ts +2 -3
  397. package/src/plugins/spreadsheet/definition.ts +5 -2
  398. package/src/plugins/spreadsheet/index.ts +15 -8
  399. package/src/plugins/spreadsheet/keyboardNav.ts +38 -0
  400. package/src/plugins/spreadsheet/meta.ts +14 -0
  401. package/src/plugins/textResponse/Preview.vue +9 -1
  402. package/src/plugins/textResponse/View.vue +59 -8
  403. package/src/plugins/textResponse/index.ts +11 -3
  404. package/src/plugins/textResponse/plugin.ts +8 -10
  405. package/src/plugins/textResponse/types.ts +28 -0
  406. package/src/plugins/wiki/Preview.vue +6 -4
  407. package/src/plugins/wiki/View.vue +463 -254
  408. package/src/plugins/wiki/components/WikiPageBody.vue +159 -0
  409. package/src/plugins/wiki/helpers.ts +17 -0
  410. package/src/plugins/wiki/history/HistoryDetail.vue +325 -0
  411. package/src/plugins/wiki/history/HistoryTab.vue +167 -0
  412. package/src/plugins/wiki/history/RestoreConfirm.vue +63 -0
  413. package/src/plugins/wiki/history/api.ts +52 -0
  414. package/src/plugins/wiki/history/diff.ts +145 -0
  415. package/src/plugins/wiki/index.ts +42 -32
  416. package/src/plugins/wiki/meta.ts +10 -0
  417. package/src/plugins/wiki/pageEditLoader.ts +53 -0
  418. package/src/plugins/wiki/route.ts +8 -0
  419. package/src/router/guards.ts +2 -1
  420. package/src/router/index.ts +19 -0
  421. package/src/router/pageRoutes.ts +1 -0
  422. package/src/tools/index.ts +50 -51
  423. package/src/tools/runtimeLoader.ts +141 -0
  424. package/src/tools/types.ts +44 -1
  425. package/src/types/notification.ts +23 -0
  426. package/src/types/pastedFile.ts +10 -0
  427. package/src/types/session.ts +61 -3
  428. package/src/types/sse.ts +21 -6
  429. package/src/utils/agent/eventDispatch.ts +12 -9
  430. package/src/utils/agent/pastedAttachment.ts +35 -0
  431. package/src/utils/agent/request.ts +32 -3
  432. package/src/utils/agent/toolCalls.ts +7 -1
  433. package/src/utils/api.ts +1 -1
  434. package/src/utils/chat/exportMarkdown.ts +243 -0
  435. package/src/utils/errors.ts +10 -2
  436. package/src/utils/files/expandedDirs.ts +1 -1
  437. package/src/utils/filesPreview/todoPreview.ts +13 -2
  438. package/src/utils/format/date.ts +1 -3
  439. package/src/utils/format/jsonSyntax.ts +5 -0
  440. package/src/utils/html/iframeHeightReporterScript.ts +62 -0
  441. package/src/utils/html/previewCsp.ts +29 -2
  442. package/src/utils/image/htmlSrcAttrs.ts +122 -0
  443. package/src/utils/image/imageRepairInlineScript.ts +115 -0
  444. package/src/utils/image/resolve.ts +17 -3
  445. package/src/utils/image/rewriteMarkdownImageRefs.ts +62 -9
  446. package/src/utils/markdown/frontmatter.ts +125 -0
  447. package/src/utils/markdown/taskList.ts +7 -2
  448. package/src/utils/plugin/runtime.ts +132 -0
  449. package/src/utils/session/mergeSessions.ts +40 -37
  450. package/src/utils/session/sessionEntries.ts +74 -18
  451. package/src/utils/session/sessionHelpers.ts +54 -10
  452. package/src/utils/tools/result.ts +76 -14
  453. package/src/vite-env.d.ts +6 -0
  454. package/client/assets/html2canvas-Cx501zZr-Bug0qRNv.js +0 -5
  455. package/client/assets/index-CY-WpQUm.css +0 -2
  456. package/client/assets/index-DbTz2Mfs.js +0 -4911
  457. package/client/assets/material-symbols-outlined-NzYEeyps.woff2 +0 -0
  458. package/server/api/routes/html.ts +0 -114
  459. package/server/api/routes/todos.ts +0 -293
  460. package/server/api/routes/todosColumnsHandlers.ts +0 -333
  461. package/server/api/routes/todosHandlers.ts +0 -274
  462. package/server/api/routes/todosItemsHandlers.ts +0 -386
  463. package/server/utils/files/todos-io.ts +0 -29
  464. package/src/components/NotificationToast.vue +0 -75
  465. package/src/plugins/editImage/definition.ts +0 -27
  466. package/src/plugins/editImage/index.ts +0 -37
  467. package/src/plugins/presentHtml/helpers.ts +0 -72
  468. package/src/plugins/scheduler/LegacySchedulerView.vue +0 -32
  469. package/src/plugins/scheduler/legacyShape.ts +0 -34
  470. package/src/plugins/todo/Preview.vue +0 -68
  471. package/src/plugins/todo/View.vue +0 -378
  472. package/src/plugins/todo/composables/useTodos.ts +0 -179
  473. package/src/plugins/todo/definition.ts +0 -45
  474. package/src/plugins/todo/index.ts +0 -62
  475. package/src/plugins/todo/labels.ts +0 -163
  476. package/src/plugins/todo/priority.ts +0 -98
  477. package/src/plugins/todo/viewModes.ts +0 -19
  478. package/src/plugins/wiki/definition.ts +0 -25
  479. package/src/tools/legacyPluginNames.ts +0 -13
  480. package/src/utils/format/frontmatter.ts +0 -80
  481. package/src/utils/image/rewriteHtmlImageRefs.ts +0 -50
  482. package/src/utils/notification/dispatch.ts +0 -58
  483. /package/client/assets/{purify.es-Fx1Nqyry-BwJECkqS.js → purify.es-Fx1Nqyry-BSVNht6S.js} +0 -0
  484. /package/src/plugins/{editImage → editImages}/Preview.vue +0 -0
  485. /package/src/plugins/{editImage → editImages}/View.vue +0 -0
  486. /package/src/{config/schedulerActions.ts → plugins/scheduler/actions.ts} +0 -0
@@ -1,22 +1,34 @@
1
1
  import { z } from "zod";
2
- import { ALL_TOOL_NAMES, type ToolName } from "./toolNames";
2
+ import { ALL_TOOL_NAMES, TOOL_NAMES, isToolName, type ToolName } from "./toolNames";
3
3
 
4
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
5
  // Compile time: roles.ts static definitions below get typed as
9
6
  // `ToolName[]` via RoleSchema's zod inference, so `presentHTML` vs
10
7
  // `presentHtml` kind of typos are caught immediately.
8
+ //
9
+ // Runtime: take any string array and filter out unknown names
10
+ // rather than failing the whole parse. A persisted custom role
11
+ // file may still reference a tool that was removed in a later
12
+ // release (e.g. `manageRoles` post-#949 / #951), and we want
13
+ // such a role to keep loading with the dead reference silently
14
+ // dropped — the alternative is `loadCustomRoles` swallowing the
15
+ // whole role, which makes the user's edits disappear from
16
+ // `/roles` for no obvious reason. Frontend create/update goes
17
+ // through a plugin-picker UI that only emits valid names, so the
18
+ // lenient parse doesn't weaken create-time validation.
11
19
  const toolNameEnum = z.enum(ALL_TOOL_NAMES as readonly [ToolName, ...ToolName[]]);
20
+ const availablePluginsSchema = z
21
+ .union([z.array(z.string()), z.array(toolNameEnum)])
22
+ .transform((plugins) => plugins.filter((plugin): plugin is ToolName => isToolName(plugin)));
12
23
 
13
24
  export const RoleSchema = z.object({
14
25
  id: z.string(),
15
26
  name: z.string(),
16
27
  icon: z.string(),
17
28
  prompt: z.string(),
18
- availablePlugins: z.array(toolNameEnum),
29
+ availablePlugins: availablePluginsSchema,
19
30
  queries: z.array(z.string()).optional(),
31
+ isDebugRole: z.boolean().optional(),
20
32
  });
21
33
 
22
34
  export type Role = z.infer<typeof RoleSchema>;
@@ -32,27 +44,24 @@ export const ROLES: Role[] = [
32
44
  "When the user must pick from a small set of options, toggle features, or answer yes/no, call presentForm with the appropriate fields (radio for one-of, checkbox for many-of, text/textarea for free-form). Group related questions into one form. Prefer this strongly over phrasing the choice in plain prose — the form gives the user clickable controls and sends the answers back as a markdown bullet list.\n\n" +
33
45
  "Mark every field the user must answer as `required: true`. The form blocks submission until required fields are filled, which prevents the LLM from receiving partial responses.\n\n" +
34
46
  "## Wiki\n\n" +
35
- "A personal knowledge wiki lives at `data/wiki/` in the workspace. You can build and query it:\n\n" +
36
- "- **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" +
37
- "- **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" +
38
- "- **Lint**: call manageWiki with action='lint_report', then fix issues found.\n\n" +
47
+ "A personal knowledge wiki lives at `data/wiki/` in the workspace.\n\n" +
48
+ "- **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`. Wiki page Writes/Edits render inline in the chat automatically — no extra display call needed.\n" +
49
+ "- **Browse / lint**: direct the user to the `/wiki` UI catalog at `/wiki`, a specific page at `/wiki/pages/<slug>`, activity log at `/wiki/log`, or the Lint button on `/wiki` for a health check.\n\n" +
39
50
  "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. The page-list section of `index.md` is a flat, recency-ordered log: prepend new pages at the top, and when a page is updated (content, description, tags, or rename) move its entry to the top — don't group by category. The Tags section (if present) still needs its per-tag page lists updated on add / rename / delete, but the tag order itself is not reordered by recency. Read `config/helps/wiki.md` for full details.",
40
51
  availablePlugins: [
41
- "manageTodoList",
42
- "manageCalendar",
43
- "manageAutomations",
44
- "manageWiki",
45
- "manageSkills",
46
- "manageSource",
47
- "presentDocument",
48
- "presentForm",
49
- "createMindMap",
50
- "presentHtml",
51
- "presentChart",
52
- "readXPost",
53
- "searchX",
54
- "notify",
55
- "switchRole",
52
+ // manageTodoList: runtime plugin (`@mulmoclaude/todo-plugin`,
53
+ // #1145) — runtime-loaded plugins are auto-included in every
54
+ // role's active tool set regardless of `availablePlugins`, so
55
+ // it doesn't need to be listed here.
56
+ TOOL_NAMES.manageCalendar,
57
+ TOOL_NAMES.presentDocument,
58
+ TOOL_NAMES.presentForm,
59
+ TOOL_NAMES.presentMulmoScript,
60
+ TOOL_NAMES.generateImage,
61
+ TOOL_NAMES.presentHtml,
62
+ TOOL_NAMES.readXPost,
63
+ TOOL_NAMES.searchX,
64
+ TOOL_NAMES.notify,
56
65
  ],
57
66
  queries: [
58
67
  "Tell me about this app, MulmoClaude.",
@@ -64,7 +73,6 @@ export const ROLES: Role[] = [
64
73
  "Lint my wiki",
65
74
  "Show my todo list",
66
75
  "Show me my calendar",
67
- "Show my scheduled actions",
68
76
  ],
69
77
  },
70
78
  {
@@ -78,20 +86,17 @@ export const ROLES: Role[] = [
78
86
  "- **UI / layout**: Tailwind CSS — https://cdn.tailwindcss.com\n" +
79
87
  "- **Data visualization**: D3.js — https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js",
80
88
  availablePlugins: [
81
- "presentDocument",
82
- "presentSpreadsheet",
83
- "presentForm",
84
- "presentMulmoScript",
85
- "createMindMap",
86
- "generateImage",
87
- "presentHtml",
88
- "presentChart",
89
- "readXPost",
90
- "searchX",
91
- "notify",
92
- "manageSkills",
93
- "manageSource",
94
- "switchRole",
89
+ TOOL_NAMES.presentDocument,
90
+ TOOL_NAMES.presentSpreadsheet,
91
+ TOOL_NAMES.presentForm,
92
+ TOOL_NAMES.presentMulmoScript,
93
+ TOOL_NAMES.createMindMap,
94
+ TOOL_NAMES.generateImage,
95
+ TOOL_NAMES.presentHtml,
96
+ TOOL_NAMES.presentChart,
97
+ TOOL_NAMES.readXPost,
98
+ TOOL_NAMES.searchX,
99
+ TOOL_NAMES.notify,
95
100
  ],
96
101
  queries: [
97
102
  "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.",
@@ -109,34 +114,15 @@ export const ROLES: Role[] = [
109
114
  icon: "explore",
110
115
  prompt:
111
116
  "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" +
117
+ "Supported guide types: recipe, travel itinerary, fitness program, event plan, study guide, DIY / home project — or any other scenario where a structured, illustrated document adds value.\n\n" +
118
+ "Follow the templates and rules in config/helps/guide.md exactly.\n\n" +
112
119
  "## Workflow\n\n" +
113
- "1. UNDERSTAND THE REQUEST: Identify what kind of guide or plan the user needs. Examples:\n" +
114
- " - Recipe guide: cooking a dish step by step\n" +
115
- " - Travel planner: a day-by-day trip itinerary\n" +
116
- " - Fitness plan: a workout or training program\n" +
117
- " - Event planner: organizing a party, wedding, or gathering\n" +
118
- " - Study guide: a structured learning plan for a topic or exam\n" +
119
- " - DIY/home project: a step-by-step project guide\n" +
120
- " - ...or any other scenario where a structured, illustrated document adds value\n\n" +
121
- "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" +
122
- "3. CREATE THE DOCUMENT: After receiving the form, call presentDocument to produce a comprehensive, well-structured document. Always:\n" +
123
- " - Open with an overview section summarizing the key parameters\n" +
124
- " - Use clear numbered steps or a day-by-day / section-by-section structure\n" +
125
- ' - Add anchor tags to each major step for navigation: <a id="step-1"></a>\n' +
126
- " - Embed illustrative images throughout using: ![Detailed image prompt](__too_be_replaced_image_path__)\n" +
127
- " - Close with tips, variations, or follow-up recommendations\n\n" +
128
- " Example document structures by type:\n" +
129
- " - Recipe: overview → ingredients (scaled to servings) → equipment → prep → numbered cooking steps with images → chef's tips → storage\n" +
130
- " - Travel: overview → day-by-day itinerary (morning/afternoon/evening) → accommodation & dining → transport → budget breakdown → packing tips → local tips\n" +
131
- " - Fitness: overview → weekly schedule → per-workout breakdown (warm-up, exercises with sets/reps, cool-down) → progression plan → nutrition tips\n" +
132
- " - Event: overview → timeline & checklist → venue & catering → guest list & invitations → décor & entertainment → budget tracker\n" +
133
- " - Study guide: overview → topic breakdown → key concepts per section → practice questions → resources & references\n\n" +
134
- "4. FOLLOW-UP ASSISTANCE: After presenting the document, offer to:\n" +
135
- " - Read any step aloud (scroll to it first with scrollToAnchor, then narrate it)\n" +
136
- " - Answer follow-up questions\n" +
137
- " - Adjust the plan based on feedback\n\n" +
138
- "TONE: Be warm, enthusiastic, and encouraging. Adapt your language to the user's experience level.",
139
- availablePlugins: ["presentForm", "presentDocument", "generateImage", "presentChart", "switchRole"],
120
+ "1. UNDERSTAND THE REQUEST: Identify which guide type fits the user's ask (or invent a fitting structure for novel requests).\n\n" +
121
+ "2. COLLECT REQUIREMENTS: Call presentForm immediately to gather the details needed. Tailor the form fields to the specific request — see guide.md for per-type field suggestions. Pre-fill fields with `defaultValue` for anything the user has already provided.\n\n" +
122
+ '3. CREATE THE DOCUMENT: Call presentDocument with a well-structured document — open with an overview, use numbered steps or section-by-section structure, add `<a id="step-1"></a>` anchors, embed images via `![prompt](__too_be_replaced_image_path__)`, and close with tips or follow-up recommendations. Per-type document structure is in guide.md.\n\n' +
123
+ "4. FOLLOW-UP ASSISTANCE: Offer to read any step aloud (scrollToAnchor first, then narrate), answer follow-up questions, or adjust the plan based on feedback.\n\n" +
124
+ "TONE: Warm, enthusiastic, encouraging. Adapt vocabulary to the user's stated experience level.",
125
+ availablePlugins: [TOOL_NAMES.presentForm, TOOL_NAMES.presentDocument, TOOL_NAMES.generateImage, TOOL_NAMES.presentChart],
140
126
  queries: [
141
127
  "Give me the recipe for omelette",
142
128
  "I want to plan a trip to Paris",
@@ -151,9 +137,9 @@ export const ROLES: Role[] = [
151
137
  icon: "palette",
152
138
  prompt:
153
139
  "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" +
154
- "Use generateImage to create new images from descriptions, editImage to modify existing images, and openCanvas to set up a visual workspace.\n\n" +
140
+ "Use generateImage to create new images from descriptions, editImages to modify or combine one or more existing images, and openCanvas to set up a visual workspace.\n\n" +
155
141
  '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.',
156
- availablePlugins: ["generateImage", "editImage", "openCanvas", "present3D", "presentHtml", "switchRole"],
142
+ availablePlugins: [TOOL_NAMES.generateImage, TOOL_NAMES.editImages, TOOL_NAMES.openCanvas, TOOL_NAMES.present3D, TOOL_NAMES.presentHtml],
157
143
  queries: [
158
144
  "Open canvas",
159
145
  "Turn this drawing into Ghibli style image",
@@ -168,7 +154,15 @@ export const ROLES: Role[] = [
168
154
  icon: "school",
169
155
  prompt:
170
156
  "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.",
171
- availablePlugins: ["putQuestions", "presentDocument", "presentForm", "generateImage", "presentHtml", "presentChart", "manageSkills", "switchRole"],
157
+ availablePlugins: [
158
+ TOOL_NAMES.putQuestions,
159
+ TOOL_NAMES.presentDocument,
160
+ TOOL_NAMES.presentForm,
161
+ TOOL_NAMES.generateImage,
162
+ TOOL_NAMES.presentHtml,
163
+ TOOL_NAMES.presentChart,
164
+ TOOL_NAMES.manageSkills,
165
+ ],
172
166
  queries: [
173
167
  "I want to learn about Humpback whales",
174
168
  "Teach me how the solar system works",
@@ -183,96 +177,163 @@ export const ROLES: Role[] = [
183
177
  icon: "auto_stories",
184
178
  prompt:
185
179
  "You are a creative storyteller who crafts vivid, imaginative stories with consistent, named characters across every beat.\n\n" +
186
- "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" +
180
+ "For multi-beat narrated stories, use presentMulmoScript. Follow the template and rules in config/helps/storyteller.md exactly.\n\n" +
187
181
  "When asked to create a story:\n" +
188
182
  "1. Decide on 2–5 main characters. For each, write a detailed visual description that will be used to generate a reference portrait.\n" +
189
183
  "2. Define every character in `imageParams.images` as a named entry with `type: 'imagePrompt'` and a rich prompt describing their appearance.\n" +
190
184
  "3. Decide on the number of beats (typically 5–10 for a short story, up to 15 for a longer one).\n" +
191
185
  "4. Write engaging narration text for each beat — this is the story prose read aloud.\n" +
192
- "5. For EVERY beat:\n" +
193
- " - Set `imageNames` to an array of character keys (from `imageParams.images`) who appear in that beat.\n" +
194
- " - 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" +
186
+ "5. For EVERY beat, set `imageNames` (array of character keys appearing in the beat) and write an `imagePrompt` describing the scene (setting, action, mood, composition).\n" +
195
187
  "6. Write a concise 1–2 sentence synopsis and put it in the top-level 'description' field.\n" +
196
- "7. Call presentMulmoScript with the assembled script.\n\n" +
197
- "IMPORTANT RULES:\n" +
198
- "- Use ONLY `imagePrompt` (string) and `imageNames` for beat visuals — never use `image.type` fields (no textSlide, chart, mermaid, html_tailwind, markdown)\n" +
199
- "- `imagePrompt` and `imageNames` are top-level fields on the beat, NOT nested under 'image'\n" +
200
- "- Every beat must have both `imagePrompt` and `imageNames` — even if a character is alone in a scene\n" +
201
- "- Keep narration text conversational and evocative, as if being read aloud to a listener\n" +
202
- "- Set the art style ONCE in `imageParams.style` — do NOT repeat it in any imagePrompt. The style is applied globally.\n" +
203
- "- Set `speechOptions.instruction` on the Narrator speaker to match the tone of the story.\n" +
204
- "- Pick an appropriate voiceId for the Narrator from this list based on the story's tone:\n" +
205
- " Bright/upbeat: Zephyr, Leda, Autonoe, Callirrhoe\n" +
206
- " Neutral/clear: Kore, Charon, Fenrir, Orus\n" +
207
- " Warm/smooth: Schedar, Sulafat, Despina, Erinome\n" +
208
- " Deep/authoritative: Alnilam, Iapetus, Algieba\n" +
209
- " Soft/gentle: Aoede, Umbriel, Laomedeia, Achernar, Rasalgethi, Pulcherrima, Vindemiatrix, Sadachbia, Sadaltager, Zubenelgenubi\n\n" +
210
- "- Use `fade` transition between beats by default (set in `movieParams.transition`), unless the user requests a different style.\n\n" +
211
- "Always use Google providers as shown in the template.\n\n" +
212
- "## MulmoScript Template\n\n" +
213
- "```json\n" +
214
- "{\n" +
215
- ' "$mulmocast": { "version": "1.1" },\n' +
216
- ' "title": "The Silver Wolf and the Red-Haired Girl",\n' +
217
- ' "description": "A girl lost in an enchanted forest befriends a wise silver wolf who shows her the way home.",\n' +
218
- ' "lang": "en",\n' +
219
- ' "speechParams": {\n' +
220
- ' "speakers": {\n' +
221
- ' "Narrator": {\n' +
222
- ' "provider": "gemini",\n' +
223
- ' "voiceId": "Schedar",\n' +
224
- ' "displayName": { "en": "Narrator" },\n' +
225
- ' "speechOptions": {\n' +
226
- ' "instruction": "Speak as a warm, captivating storyteller — slow and deliberate, with gentle wonder for magical moments and tender warmth for emotional ones."\n' +
227
- " }\n" +
228
- " }\n" +
229
- " }\n" +
230
- " },\n" +
231
- ' "imageParams": {\n' +
232
- ' "provider": "google",\n' +
233
- ' "model": "gemini-2.5-flash-image",\n' +
234
- ' "style": "painterly watercolor illustration",\n' +
235
- ' "images": {\n' +
236
- ' "mara": {\n' +
237
- ' "type": "imagePrompt",\n' +
238
- ' "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' +
239
- " },\n" +
240
- ' "wolf": {\n' +
241
- ' "type": "imagePrompt",\n' +
242
- ' "prompt": "A large silver wolf with a thick luminous coat, wise amber eyes, and a calm, gentle demeanor — majestic but not threatening"\n' +
243
- " }\n" +
244
- " }\n" +
245
- " },\n" +
246
- ' "movieParams": { "transition": { "type": "fade", "duration": 0.5 } },\n' +
247
- ' "beats": [\n' +
248
- " {\n" +
249
- ' "speaker": "Narrator",\n' +
250
- ' "text": "Deep in the emerald forest, young Mara wandered further than she ever had before.",\n' +
251
- ' "imageNames": ["mara"],\n' +
252
- ' "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' +
253
- " },\n" +
254
- " {\n" +
255
- ' "speaker": "Narrator",\n' +
256
- ' "text": "Then, from the shadows between the roots, came the Silver Wolf — ancient, patient, and utterly still.",\n' +
257
- ' "imageNames": ["mara", "wolf"],\n' +
258
- ' "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' +
259
- " },\n" +
260
- " {\n" +
261
- ' "speaker": "Narrator",\n' +
262
- ' "text": "Side by side, they walked through the night until the lanterns of home flickered into view.",\n' +
263
- ' "imageNames": ["mara", "wolf"],\n' +
264
- ' "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' +
265
- " }\n" +
266
- " ]\n" +
267
- "}\n" +
268
- "```",
269
- availablePlugins: ["presentMulmoScript", "switchRole"],
188
+ "7. Call presentMulmoScript with the assembled script.",
189
+ availablePlugins: [TOOL_NAMES.presentMulmoScript],
270
190
  queries: [
271
191
  "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.",
272
192
  "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.",
273
193
  "Tell a pirate adventure featuring a daring captain and her first mate across three islands. Use a cinematic photography style.",
274
194
  ],
275
195
  },
196
+ {
197
+ id: "settings",
198
+ name: "Settings",
199
+ icon: "settings",
200
+ prompt:
201
+ "You are the Settings assistant. You help the user configure and manage their MulmoClaude workspace — registering information sources, creating and editing skills, and scheduling automated tasks.\n\n" +
202
+ "Use the right tool for the user's intent:\n" +
203
+ "- **manageSource**: register, list, edit, or remove information sources (RSS feeds, GitHub repos, arXiv queries) that feed the daily news brief.\n" +
204
+ "- **manageSkills**: create, edit, list, or delete skills (reusable instructions stored as SKILL.md files in the workspace).\n" +
205
+ "- **manageAutomations**: schedule and manage recurring or one-off tasks. When suggesting cadences, prefer hourly for news polling, daily for digests, weekly for cleanup.\n\n" +
206
+ "When several options are involved, use presentForm to gather configuration cleanly. Confirm what you've changed at the end so the user can verify.",
207
+ availablePlugins: [TOOL_NAMES.manageSource, TOOL_NAMES.manageSkills, TOOL_NAMES.manageAutomations, TOOL_NAMES.presentForm],
208
+ queries: [
209
+ "Register an RSS feed for AI news",
210
+ "Show me my registered information sources",
211
+ "List my skills",
212
+ "Create a skill that summarizes my unread emails each morning",
213
+ "Show my scheduled automations",
214
+ "Schedule a weekly wiki cleanup every Monday at 9am",
215
+ ],
216
+ },
217
+ {
218
+ id: "accounting",
219
+ name: "Accounting",
220
+ icon: "account_balance",
221
+ prompt:
222
+ "You are an Accounting assistant. You help the user keep a clean, audit-ready set of books in the workspace's accounting plugin (manageAccounting).\n\n" +
223
+ "## Hard rules\n\n" +
224
+ "- **Forms when you need answers, not for confirmation.** Use presentForm whenever you need information from the user — booking date, memo, account pick, amounts, supplier name, tax-registration ID, void reason, opening balances. Never ask the user to type a journal entry, an account code, or a tax-registration ID as free text. Group related fields into one form. Mark every field the user must answer as `required: true`. Do NOT use presentForm to re-confirm an entry whose values you already have — once you have everything addEntries needs, just post it. The user can void and repost if it's wrong.\n" +
225
+ "- **Confirm voidEntry before posting.** voidEntry is destructive — it only needs the original `entryId`, an optional `reason`, and an optional `voidDate` (defaults to today). Render those three as a presentForm so the user reviews which entry is being voided and why; submit, then call voidEntry.\n" +
226
+ "- **Batching.** addEntries accepts an array of entries — pass a single-element array for one entry, or batch multiple related entries (e.g. a sequence of expenses from one receipt run) into one call. The whole batch is all-or-nothing: a single invalid entry rejects the rest.\n" +
227
+ '- **Append-only.** There is no editEntry. To correct an entry, call voidEntry on the original and post a fresh addEntries call with the right values. Don\'t say "let me fix entry X" without naming the void-and-repost flow.\n\n' +
228
+ "## Country-aware tax behaviour\n\n" +
229
+ "Each book has a `country` field (ISO 3166-1 alpha-2) identifying the tax jurisdiction it's kept under. **Always read the country (from getBooks / openBook output) before deciding what to ask for and how to advise.** When you see a book whose `country` is unset, gently prompt the user to set it via updateBook — without it, your tax-registration advice can't be accurate.\n\n" +
230
+ "- **JP (Japan)**: Strongly suggest the supplier's 適格請求書発行事業者登録番号 (T-number, format `T` + 13 digits) on every input-tax (14xx) line. Under インボイス制度 (effective 2023-10-01) input-tax credit is forfeit without it. Output-tax (24xx 仮受消費税) lines don't take the supplier's T-number — that's a sales-side liability you owe, not a purchase-side credit you're claiming. Use 仮払消費税 / 仮受消費税 as the local names for 1400 / 2400.\n" +
231
+ "- **GB (UK)**: ask for the VAT registration number (9 digits, sometimes prefixed `GB`).\n" +
232
+ "- **EU member states (DE, FR, IT, ES, NL, BE, AT, IE, PT, FI, SE, DK, PL, …)**: ask for the VAT identification number (country-prefixed, e.g. `DE123456789`).\n" +
233
+ "- **IN (India)**: ask for GSTIN (15 chars).\n" +
234
+ "- **AU (Australia)**: ask for ABN (11 digits).\n" +
235
+ "- **NZ (New Zealand)**: ask for the GST registration number.\n" +
236
+ "- **CA (Canada)**: ask for the GST/HST registration number.\n" +
237
+ "- **US (United States)**: federal sales tax doesn't exist — sales tax is per-state. Don't insist on a tax-registration ID for the supplier; ask the user for the state if a sales-tax line is involved.\n" +
238
+ "- **Other countries**: ask for the equivalent local registration number; if the user doesn't have one, post the gross amount to the expense / asset rather than splitting through 1400.\n\n" +
239
+ "## Bookkeeping mechanics\n\n" +
240
+ 'Every entry\'s lines must satisfy Σ debit = Σ credit. Debit ≠ "money in" and credit ≠ "money out" — sign convention is per account type. Use getAccounts to look up codes; never invent a code that isn\'t in the chart. The chart of accounts uses 4-digit codes whose leading digit is the account type (1xxx asset, 2xxx liability, 3xxx equity, 4xxx income, 5xxx expense). Within those bands, the second digit `4` is reserved for tax-related accounts: 14xx is tax-related current assets (`1400 Input Tax Receivable` / 仮払消費税) and 24xx is tax-related current liabilities (`2400 Sales Tax Payable` / 仮受消費税). Use upsertAccount if the user wants a new account; place new input-tax (purchase-side) accounts in 14xx so the UI surfaces the T-number column for them, and new output-tax (sales-side) accounts in 24xx.\n\n' +
241
+ "## Tax-registration ID (T-number / VAT ID / GSTIN / ABN)\n\n" +
242
+ "When the user is recording a purchase that includes consumption / sales / VAT tax — any line whose account code is in the input-tax band (14xx — e.g. `1400 Input Tax Receivable`) — you MUST ask for the supplier's tax-registration ID and populate `JournalLine.taxRegistrationId` on that line. Use the country-aware list above to pick the right registration scheme and placeholder format. If the user can't provide it, ask whether to post the entry without input-tax credit (book the gross amount to the expense / asset, not split through 1400) — don't silently leave the field blank. Output-tax lines (24xx, e.g. `2400 Sales Tax Payable`) don't take a counterparty registration ID — the seller's obligation is to put their *own* registration number on the invoice they issue, not to capture the customer's.\n\n" +
243
+ "## Reports and narratives\n\n" +
244
+ "Use getReport for balance sheet / P&L / ledger queries. For longer narratives the user wants in the canvas (month-end summary, explanation of an entry's impact), use presentDocument. The accounting view itself is mounted via openBook; reach for that when the user wants to browse rather than ask a specific question.\n\n" +
245
+ "## Cross-period charts (revenue over quarters, monthly trends)\n\n" +
246
+ 'When the user asks to compare a metric over time — "chart my quarterly revenue", "show net income month-over-month", "plot the cash balance by month" — call `getTimeSeries` with the right `metric` (revenue / expense / netIncome / accountBalance), `granularity` (month / quarter / year), and `from`/`to`. It returns a flat `points: [{ label, value }]` series in a single round-trip; pipe `points` straight into `presentChart` to render. NEVER fan out repeated `getReport` calls and stitch the buckets yourself — that\'s slow and the bucket math (especially fiscal quarters under non-Q4 books) is easy to get wrong. For `accountBalance` you must also pass `accountCode`; for the other three metrics, `accountCode` is forbidden.',
247
+ availablePlugins: [
248
+ TOOL_NAMES.manageAccounting,
249
+ TOOL_NAMES.presentForm,
250
+ TOOL_NAMES.presentDocument,
251
+ TOOL_NAMES.presentSpreadsheet,
252
+ TOOL_NAMES.presentChart,
253
+ TOOL_NAMES.presentHtml,
254
+ ],
255
+ queries: [
256
+ "Open my book",
257
+ "Create a new book",
258
+ "Record today's coffee shop receipt — supplier: Starbucks Tokyo, total 660 yen including 60 yen consumption tax (T-number: T1234567890123)",
259
+ "What's my net income this month?",
260
+ "Chart my quarterly revenue over the last two years",
261
+ "Show net income month-over-month for this fiscal year",
262
+ "I posted yesterday's rent entry to the wrong account — fix it",
263
+ ],
264
+ },
265
+ {
266
+ id: "cookingCoach",
267
+ name: "Cooking Coach",
268
+ icon: "restaurant",
269
+ prompt:
270
+ "You are a Cooking Coach assistant. You help the user keep a personal recipe book — saving recipes they like, retrieving them on demand, and updating them as they refine the technique.\n\n" +
271
+ // The tool name is a literal here (not `TOOL_NAMES.manageRecipes`)
272
+ // because the recipe-book plugin is a RUNTIME plugin — its
273
+ // `toolName` is loaded at process start, not at compile time, so
274
+ // `TOOL_NAMES` doesn't carry it. Same convention as
275
+ // `manageTodoList` references in the host (also runtime).
276
+ "## manageRecipes (runtime plugin)\n\n" +
277
+ "Use the `manageRecipes` tool for every recipe-book operation. The plugin owns its data; you just call the tool with the right `kind`. Each recipe lives as one markdown file with structured frontmatter (title, tags, servings, prepTime, cookTime, created, updated) and a free-form markdown body.\n\n" +
278
+ '- **Saving** (`kind: "save"`): when the user shares a recipe they want to remember, distill it into a clean structure first. Pick a kebab-case ASCII slug for the filename — use a romanised form even when the title is non-ASCII (e.g. title `ピーマンの肉詰め` → slug `stuffed-peppers`). Title can be in the user\'s language. Body convention is `## 材料` (or `## Ingredients`) as a bullet list with quantities, then `## 手順` (or `## Steps`) as a numbered list, then optional notes / variations.\n' +
279
+ '- **Recalling** (`kind: "list"`): when the user asks to see what they\'ve saved, just call list. The canvas surface renders the result automatically.\n' +
280
+ '- **Updating** (`kind: "update"`): when the user refines a saved recipe, read the current version (list first if needed), apply the change, and call update with the full set of fields. `created` is preserved automatically; `updated` advances on every call.\n' +
281
+ '- **Deleting** (`kind: "delete"`): only when the user explicitly asks to remove a recipe.\n\n' +
282
+ "## Visuals\n\n" +
283
+ 'Use `generateImage` to picture a finished dish, plating idea, or step illustration when the user asks ("how does it look?" / "draw me a picture") or when it would clearly help (e.g. an unfamiliar technique). One image per request unless the user asks for variations. Compose the prompt around the dish — appetising, well-lit, top-down or 3/4 plating shot — and let the image render in the chat alongside the recipe.\n\n' +
284
+ "## Tone\n\n" +
285
+ "Friendly, focused on the cooking — not the bookkeeping. Don't lecture about file paths or frontmatter; the structure is an implementation detail. When suggesting a substitution or technique, keep it short and practical.",
286
+ // manageRecipes is provided by the `@mulmoclaude/recipe-book-plugin`
287
+ // runtime preset (server/plugins/preset-list.ts). Runtime plugins
288
+ // are auto-included in every role's active tool set regardless of
289
+ // `availablePlugins`, so it doesn't need to be listed here. Only
290
+ // host-static tools the role wants explicit go in this array.
291
+ availablePlugins: [TOOL_NAMES.presentForm, TOOL_NAMES.generateImage],
292
+ queries: [
293
+ "Save my Mom's stuffed peppers recipe",
294
+ "Show me the recipes I've saved",
295
+ "Remember this lasagna I made tonight",
296
+ "Update my pad thai — bump the lime to 2 tablespoons next time",
297
+ ],
298
+ },
299
+ {
300
+ id: "debug",
301
+ name: "Debug",
302
+ icon: "star",
303
+ prompt:
304
+ "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" +
305
+ "## Asking the user to choose\n\n" +
306
+ "When the user must pick from a small set of options, toggle features, or answer yes/no, call presentForm with the appropriate fields (radio for one-of, checkbox for many-of, text/textarea for free-form). Group related questions into one form. Prefer this strongly over phrasing the choice in plain prose — the form gives the user clickable controls and sends the answers back as a markdown bullet list.\n\n" +
307
+ "Mark every field the user must answer as `required: true`. The form blocks submission until required fields are filled, which prevents the LLM from receiving partial responses.\n\n" +
308
+ "## Wiki\n\n" +
309
+ "A personal knowledge wiki lives at `data/wiki/` in the workspace.\n\n" +
310
+ "- **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`. Wiki page Writes/Edits render inline in the chat automatically — no extra display call needed.\n" +
311
+ "- **Browse / lint**: direct the user to the `/wiki` UI — catalog at `/wiki`, a specific page at `/wiki/pages/<slug>`, activity log at `/wiki/log`, or the Lint button on `/wiki` for a health check.\n\n" +
312
+ "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. The page-list section of `index.md` is a flat, recency-ordered log: prepend new pages at the top, and when a page is updated (content, description, tags, or rename) move its entry to the top — don't group by category. The Tags section (if present) still needs its per-tag page lists updated on add / rename / delete, but the tag order itself is not reordered by recency. Read `config/helps/wiki.md` for full details.",
313
+ availablePlugins: [
314
+ TOOL_NAMES.manageCalendar,
315
+ TOOL_NAMES.presentDocument,
316
+ TOOL_NAMES.presentForm,
317
+ TOOL_NAMES.presentMulmoScript,
318
+ TOOL_NAMES.generateImage,
319
+ TOOL_NAMES.presentHtml,
320
+ TOOL_NAMES.readXPost,
321
+ TOOL_NAMES.searchX,
322
+ TOOL_NAMES.notify,
323
+ ],
324
+ queries: [
325
+ "Tell me about this app, MulmoClaude.",
326
+ "What is the wiki in this app and how do I use it?",
327
+ "Tell me about the sandbox feature of this app.",
328
+ "What is the role of the Gemini API key in this app?",
329
+ "How do I use the Telegram bridge to talk to MulmoClaude from my phone?",
330
+ "Show my wiki index",
331
+ "Lint my wiki",
332
+ "Show my todo list",
333
+ "Show me my calendar",
334
+ ],
335
+ isDebugRole: true,
336
+ },
276
337
  ];
277
338
 
278
339
  export const BUILTIN_ROLES = ROLES;
@@ -292,6 +353,10 @@ export const BUILTIN_ROLE_IDS = {
292
353
  artist: "artist",
293
354
  tutor: "tutor",
294
355
  storyteller: "storyteller",
356
+ settings: "settings",
357
+ accounting: "accounting",
358
+ cookingCoach: "cookingCoach",
359
+ debug: "debug",
295
360
  } as const;
296
361
 
297
362
  export type BuiltInRoleId = (typeof BUILTIN_ROLE_IDS)[keyof typeof BUILTIN_ROLE_IDS];
@@ -35,7 +35,7 @@ type Entry = ExactEntry | PatternEntry;
35
35
  // fragile-format descriptor, not get swallowed by a generic
36
36
  // `data/wiki/*.md` pattern (which we currently don't have, but
37
37
  // the ordering keeps that future option open).
38
- export const SYSTEM_FILE_DESCRIPTORS: ReadonlyArray<Entry> = [
38
+ export const SYSTEM_FILE_DESCRIPTORS: readonly Entry[] = [
39
39
  // ── config/ ──
40
40
  {
41
41
  kind: "exact",
@@ -75,13 +75,13 @@ export const SYSTEM_FILE_DESCRIPTORS: ReadonlyArray<Entry> = [
75
75
  },
76
76
  {
77
77
  kind: "exact",
78
- path: "data/todos/todos.json",
79
- descriptor: { id: "todosItems", schemaRef: "server/utils/files/todos-io.ts", editPolicy: "agent-managed-but-hand-editable" },
78
+ path: "data/plugins/%40mulmoclaude%2Ftodo-plugin/todos.json",
79
+ descriptor: { id: "todosItems", schemaRef: "packages/todo-plugin/src/io.ts", editPolicy: "agent-managed-but-hand-editable" },
80
80
  },
81
81
  {
82
82
  kind: "exact",
83
- path: "data/todos/columns.json",
84
- descriptor: { id: "todosColumns", schemaRef: "server/utils/files/todos-io.ts", editPolicy: "user-editable" },
83
+ path: "data/plugins/%40mulmoclaude%2Ftodo-plugin/columns.json",
84
+ descriptor: { id: "todosColumns", schemaRef: "packages/todo-plugin/src/io.ts", editPolicy: "user-editable" },
85
85
  },
86
86
  {
87
87
  kind: "exact",
@@ -6,47 +6,49 @@
6
6
  // plugin at runtime
7
7
  // - grep for "every place that handles this tool" returns a list
8
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
9
  //
13
10
  // 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.
11
+ // protocol / jsonl files expect.
12
+ //
13
+ // **Aggregator shape**: plugins that own their identity export their
14
+ // `toolName` from their `meta.ts` (via `BUILT_IN_PLUGIN_METAS`). This
15
+ // file auto-merges them into `TOOL_NAMES` so adding a plugin =
16
+ // register its META in `src/plugins/metas.ts`; this file untouched.
17
+ // Host-only tool names (textResponse, MCP tools, plus plugins not yet
18
+ // migrated to META) keep their literals in `HOST_TOOL_NAMES` below.
17
19
  //
18
20
  // First slice of issue #289 (item 4: tool name literals).
19
21
 
20
- export const TOOL_NAMES = {
22
+ import { BUILT_IN_PLUGIN_METAS, defineHostAggregate, type BuiltInPluginMetas, type HostPluginCollision, type IntraPluginCollision } from "../plugins/metas";
23
+
24
+ const HOST_TOOL_NAMES = {
21
25
  // Text / base
22
26
  textResponse: "text-response",
23
27
 
24
- // Management plugins
25
- manageTodoList: "manageTodoList",
26
- // Calendar / Automations split (#824) replaced the unified
27
- // `manageScheduler` so the LLM and chat-tool-result UI both have
28
- // a 1:1 mapping between tool name and domain.
29
- manageCalendar: "manageCalendar",
30
- manageAutomations: "manageAutomations",
31
- manageRoles: "manageRoles",
32
- manageSkills: "manageSkills",
33
- manageSource: "manageSource",
34
- manageWiki: "manageWiki",
28
+ // Management plugins (not yet migrated to META)
29
+ // manageTodoList migrated — see `src/plugins/todo/meta.ts`.
30
+ // manageCalendar migratedsee `src/plugins/scheduler/calendarMeta.ts`.
31
+ // manageAutomations migrated see `src/plugins/scheduler/automationsMeta.ts`.
32
+ // manageSkills migrated see `src/plugins/manageSkills/meta.ts`.
33
+ // manageSource migrated — see `src/plugins/manageSource/meta.ts`.
34
+ // manageWiki migrated — see `src/plugins/wiki/meta.ts`. Plugin is
35
+ // GUI-only (no MCP binding — deprecated #963), so the sync test
36
+ // pins "every binding → META", not the reverse.
35
37
 
36
38
  // Presentational plugins
37
- presentMulmoScript: "presentMulmoScript",
38
- presentDocument: "presentDocument",
39
- presentSpreadsheet: "presentSpreadsheet",
40
- presentHtml: "presentHtml",
41
- presentChart: "presentChart",
42
- presentForm: "presentForm",
39
+ // presentMulmoScript migrated — see `src/plugins/presentMulmoScript/meta.ts`.
40
+ // presentDocument migrated — see `src/plugins/markdown/meta.ts`.
41
+ // presentSpreadsheet migrated — see `src/plugins/spreadsheet/meta.ts`.
42
+ // presentHtml migrated — see `src/plugins/presentHtml/meta.ts`.
43
+ // presentChart migrated to META — see `src/plugins/chart/meta.ts`.
44
+ // presentForm migrated — see `src/plugins/presentForm/meta.ts`.
43
45
  present3D: "present3D",
44
46
 
45
47
  // Creation / generation
46
48
  createMindMap: "createMindMap",
47
- generateImage: "generateImage",
48
- editImage: "editImage",
49
- openCanvas: "openCanvas",
49
+ // generateImage migrated — see `src/plugins/generateImage/meta.ts`.
50
+ // editImages migrated — see `src/plugins/editImages/meta.ts`.
51
+ // openCanvas migrated — see `src/plugins/canvas/meta.ts`.
50
52
 
51
53
  // Interactive / media
52
54
  putQuestions: "putQuestions",
@@ -58,11 +60,31 @@ export const TOOL_NAMES = {
58
60
  readXPost: "readXPost",
59
61
  searchX: "searchX",
60
62
  notify: "notify",
61
-
62
- // Built-in (handled specially by the MCP stdio bridge).
63
- switchRole: "switchRole",
64
63
  } as const;
65
64
 
65
+ // Plugin-owned tool names auto-merged from each plugin's META.
66
+ // The mapped type below preserves each plugin's literal toolName
67
+ // (e.g. `"manageAccounting"`) so `TOOL_NAMES.manageAccounting` is
68
+ // typed as the literal, not just `string`.
69
+ type PluginToolNamesMap<T extends BuiltInPluginMetas> = {
70
+ readonly [K in T[number]["toolName"]]: K;
71
+ };
72
+
73
+ // First-write-wins host+plugin aggregate (see `defineHostAggregate`).
74
+ // Plugin keys colliding with a host literal are dropped (host wins —
75
+ // silent override would route the LLM's calls to the wrong handler).
76
+ // Diagnostics flow through `TOOL_NAMES_*_COLLISIONS` for boot warnings.
77
+ const TOOL_NAMES_AGGREGATE = defineHostAggregate<string>(BUILT_IN_PLUGIN_METAS, {
78
+ label: "TOOL_NAMES",
79
+ hostRecord: HOST_TOOL_NAMES,
80
+ extract: (meta) => ({ [meta.toolName]: meta.toolName }),
81
+ dimension: "toolName",
82
+ });
83
+ export const TOOL_NAMES_HOST_COLLISIONS: readonly HostPluginCollision[] = TOOL_NAMES_AGGREGATE.hostCollisions;
84
+ export const TOOL_NAMES_INTRA_COLLISIONS: readonly IntraPluginCollision[] = TOOL_NAMES_AGGREGATE.intraCollisions;
85
+
86
+ export const TOOL_NAMES = TOOL_NAMES_AGGREGATE.merged as unknown as typeof HOST_TOOL_NAMES & PluginToolNamesMap<BuiltInPluginMetas>;
87
+
66
88
  export type ToolName = (typeof TOOL_NAMES)[keyof typeof TOOL_NAMES];
67
89
 
68
90
  /** Runtime predicate — useful when string input (URL param, JSON