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,17 +1,10 @@
1
1
  <template>
2
2
  <div class="h-full bg-white flex flex-col">
3
- <!-- API error banner — surfaces POST /api/scheduler failures so a
4
- delete/add/replace that silently no-ops becomes diagnosable. -->
3
+ <!-- Surfaces POST /api/scheduler failures so silent no-ops are diagnosable. -->
5
4
  <div v-if="apiError" class="px-4 py-2 bg-red-50 border-b border-red-200 text-sm text-red-700" role="alert" data-testid="scheduler-api-error">
6
5
  {{ t("pluginScheduler.apiError", { error: apiError }) }}
7
6
  </div>
8
- <!-- Top-level tab bar: Calendar / Tasks. Hidden when the
9
- component is mounted as a standalone page (`forceTab`
10
- set by CalendarView / AutomationsView) — the page itself
11
- already identifies which feature the user is on, so a
12
- tab bar would duplicate that affordance. Still rendered
13
- when the component appears as a `manageScheduler` tool
14
- result inside /chat, where the user can switch freely. -->
7
+ <!-- Hidden when mounted as a standalone page (forceTab) the page already identifies the feature. -->
15
8
  <div v-if="!forceTab" class="flex border-b border-gray-200 px-6">
16
9
  <button
17
10
  class="px-4 py-2 text-sm font-medium border-b-2 -mb-px"
@@ -31,19 +24,15 @@
31
24
  </button>
32
25
  </div>
33
26
 
34
- <!-- Tasks tab -->
35
27
  <TasksTab v-if="activeTab === SCHEDULER_TAB.tasks" />
36
28
 
37
- <!-- Calendar tab (existing content) -->
38
29
  <template v-if="activeTab === SCHEDULER_TAB.calendar">
39
- <!-- Header -->
40
30
  <div class="flex items-center justify-between gap-2 px-3 py-2 border-b border-gray-100">
41
31
  <div class="flex items-center gap-2">
42
32
  <h2 class="text-lg font-semibold text-gray-800">{{ t("pluginScheduler.heading") }}</h2>
43
33
  <span class="text-sm text-gray-500">{{ t("pluginScheduler.itemCount", items.length, { named: { count: items.length } }) }}</span>
44
34
  </div>
45
35
  <div class="flex items-center gap-2">
46
- <!-- Navigation (calendar modes only) -->
47
36
  <template v-if="viewMode !== SCHEDULER_VIEW.list">
48
37
  <div class="flex gap-0.5">
49
38
  <button
@@ -70,7 +59,6 @@
70
59
  </div>
71
60
  <span class="text-sm text-gray-600 min-w-[140px] text-center">{{ headerLabel }}</span>
72
61
  </template>
73
- <!-- View mode toggle -->
74
62
  <div class="flex border border-gray-300 rounded overflow-hidden">
75
63
  <button
76
64
  v-for="mode in VIEW_MODES"
@@ -86,7 +74,6 @@
86
74
  </div>
87
75
  </div>
88
76
 
89
- <!-- List view -->
90
77
  <div v-if="viewMode === SCHEDULER_VIEW.list" class="flex-1 overflow-y-auto min-h-0">
91
78
  <div v-if="items.length === 0" class="flex items-center justify-center h-full text-gray-400">{{ t("pluginScheduler.noScheduled") }}</div>
92
79
 
@@ -124,11 +111,9 @@
124
111
  </ul>
125
112
  </div>
126
113
 
127
- <!-- Week view -->
128
114
  <div v-else-if="viewMode === SCHEDULER_VIEW.week" class="flex-1 overflow-y-auto min-h-0">
129
115
  <div class="grid grid-cols-7 border-b border-gray-200">
130
116
  <div v-for="day in weekDays" :key="day.toISOString()" class="border-r last:border-r-0 border-gray-200 min-h-[200px] flex flex-col">
131
- <!-- Day header -->
132
117
  <div class="px-2 py-1.5 text-center border-b border-gray-100 sticky top-0 bg-white" :class="isToday(day) ? 'bg-blue-50' : ''">
133
118
  <div class="text-xs text-gray-400">{{ dayLabel(day) }}</div>
134
119
  <div
@@ -138,7 +123,6 @@
138
123
  {{ day.getDate() }}
139
124
  </div>
140
125
  </div>
141
- <!-- Day items -->
142
126
  <div class="flex-1 p-1 space-y-0.5">
143
127
  <div
144
128
  v-for="item in itemsForDay(day)"
@@ -153,7 +137,6 @@
153
137
  </div>
154
138
  </div>
155
139
  </div>
156
- <!-- Unscheduled -->
157
140
  <div v-if="unscheduledItems.length > 0" class="p-3 border-t border-gray-200">
158
141
  <div class="text-xs text-gray-400 mb-1.5">{{ t("pluginScheduler.unscheduled") }}</div>
159
142
  <div class="flex flex-wrap gap-1">
@@ -170,15 +153,12 @@
170
153
  </div>
171
154
  </div>
172
155
 
173
- <!-- Month view -->
174
156
  <div v-else class="flex-1 overflow-y-auto min-h-0">
175
- <!-- Weekday headers -->
176
157
  <div class="grid grid-cols-7 border-b border-gray-200 sticky top-0 bg-white z-10">
177
158
  <div v-for="label in WEEKDAY_LABELS" :key="label" class="text-xs text-center text-gray-400 py-1.5 border-r last:border-r-0 border-gray-100">
178
159
  {{ label }}
179
160
  </div>
180
161
  </div>
181
- <!-- Month grid -->
182
162
  <div v-for="(week, wi) in monthGrid" :key="wi" class="grid grid-cols-7 border-b border-gray-100">
183
163
  <div
184
164
  v-for="day in week"
@@ -206,7 +186,6 @@
206
186
  </div>
207
187
  </div>
208
188
  </div>
209
- <!-- Unscheduled -->
210
189
  <div v-if="unscheduledItems.length > 0" class="p-3 border-t border-gray-200">
211
190
  <div class="text-xs text-gray-400 mb-1.5">{{ t("pluginScheduler.unscheduled") }}</div>
212
191
  <div class="flex flex-wrap gap-1">
@@ -223,7 +202,6 @@
223
202
  </div>
224
203
  </div>
225
204
 
226
- <!-- Item YAML editor -->
227
205
  <div v-if="selectedId" class="border-t border-blue-200 bg-blue-50 shrink-0">
228
206
  <div class="flex items-center justify-between px-4 py-2 text-sm font-medium text-blue-700">
229
207
  <span>{{ t("pluginScheduler.editItem") }}</span>
@@ -244,7 +222,6 @@
244
222
  </div>
245
223
  </div>
246
224
 
247
- <!-- JSON source editor -->
248
225
  <details class="border-t border-gray-200 bg-gray-50 shrink-0">
249
226
  <summary class="cursor-pointer select-none px-4 py-2 text-sm font-medium text-gray-600 hover:bg-gray-100">
250
227
  {{ t("pluginScheduler.editSource") }}
@@ -278,10 +255,12 @@ import type { ToolResultComplete } from "gui-chat-protocol/vue";
278
255
  import type { SchedulerData, ScheduledItem } from "./index";
279
256
  import { useFreshPluginData } from "../../composables/useFreshPluginData";
280
257
  import { apiPost } from "../../utils/api";
281
- import { API_ROUTES } from "../../config/apiRoutes";
258
+ import { pluginEndpoints } from "../api";
259
+ import type { SchedulerEndpoints } from "./automationsDefinition";
282
260
  import TasksTab from "./TasksTab.vue";
283
261
  import { isToday } from "../../utils/format/date";
284
262
  import { errorMessage } from "../../utils/errors";
263
+ import { SCHEDULER_VIEW, SCHEDULER_VIEW_MODES as VIEW_MODES, SCHEDULER_TAB, type SchedulerViewMode as ViewMode, type SchedulerTab } from "./viewModes";
285
264
 
286
265
  const { t } = useI18n();
287
266
 
@@ -289,10 +268,7 @@ type YamlScalar = string | number | boolean | null;
289
268
 
290
269
  const props = defineProps<{
291
270
  selectedResult?: ToolResultComplete<SchedulerData>;
292
- // Standalone page mode: when set, hides the tab bar and locks the
293
- // view to the given tab. Used by CalendarView / AutomationsView
294
- // wrappers (#758). Undefined in the /chat tool-result context, so
295
- // there the tab-switcher stays interactive.
271
+ // Set by CalendarView / AutomationsView page wrappers (#758) to lock the tab; undefined in /chat tool-result context.
296
272
  forceTab?: SchedulerTab;
297
273
  }>();
298
274
  const emit = defineEmits<{ updateResult: [result: ToolResultComplete] }>();
@@ -306,8 +282,7 @@ function detectInitialTab(result?: ToolResultComplete<SchedulerData>): Scheduler
306
282
  }
307
283
 
308
284
  const activeTab = ref<SchedulerTab>(props.forceTab ?? detectInitialTab(props.selectedResult));
309
- // In standalone page mode the tab is locked; swapping routes should
310
- // re-lock so the view follows. No-op in tool-result mode.
285
+ // Re-lock when forceTab swaps so route navigation follows; no-op in tool-result mode.
311
286
  watch(
312
287
  () => props.forceTab,
313
288
  (next) => {
@@ -316,8 +291,10 @@ watch(
316
291
  );
317
292
  const items = ref<ScheduledItem[]>(props.selectedResult?.data?.items ?? []);
318
293
 
294
+ const endpoints = pluginEndpoints<SchedulerEndpoints>("scheduler");
295
+
319
296
  const { refresh } = useFreshPluginData<ScheduledItem[]>({
320
- endpoint: () => API_ROUTES.scheduler.base,
297
+ endpoint: () => endpoints.list.url,
321
298
  extract: (json) => {
322
299
  const payload = (json as { data?: { items?: ScheduledItem[] } }).data?.items;
323
300
  return Array.isArray(payload) ? payload : null;
@@ -336,18 +313,12 @@ watch(
336
313
  },
337
314
  );
338
315
 
339
- // ── View mode ──────────────────────────────────────────────────────────────
340
-
341
- import { SCHEDULER_VIEW, SCHEDULER_VIEW_MODES as VIEW_MODES, SCHEDULER_TAB, type SchedulerViewMode as ViewMode, type SchedulerTab } from "./viewModes";
342
-
343
316
  const WEEKDAY_LABELS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
344
317
  const MAX_MONTH_ITEMS = 3;
345
318
 
346
319
  const viewMode = ref<ViewMode>(SCHEDULER_VIEW.month);
347
320
  const currentDate = ref(new Date());
348
321
 
349
- // ── Calendar utilities ─────────────────────────────────────────────────────
350
-
351
322
  function startOfWeek(date: Date): Date {
352
323
  const result = new Date(date);
353
324
  const day = result.getDay();
@@ -402,7 +373,7 @@ function itemsForDay(day: Date): ScheduledItem[] {
402
373
  const unscheduledItems = computed(() => items.value.filter((item) => !item.props.date));
403
374
 
404
375
  function itemTime(item: ScheduledItem): string {
405
- const time = item.props.time;
376
+ const { time } = item.props;
406
377
  return typeof time === "string" ? time : "";
407
378
  }
408
379
 
@@ -410,8 +381,6 @@ function dayLabel(date: Date): string {
410
381
  return WEEKDAY_LABELS[date.getDay() === 0 ? 6 : date.getDay() - 1];
411
382
  }
412
383
 
413
- // ── Navigation ─────────────────────────────────────────────────────────────
414
-
415
384
  const weekDays = computed(() => getWeekDays(currentDate.value));
416
385
 
417
386
  const monthGrid = computed(() => getMonthGrid(currentDate.value.getFullYear(), currentDate.value.getMonth()));
@@ -452,8 +421,6 @@ function goNext() {
452
421
  currentDate.value = next;
453
422
  }
454
423
 
455
- // ── YAML helpers ────────────────────────────────────────────────────────────
456
-
457
424
  function yamlStringValue(raw: string): string {
458
425
  const needsQuotes = raw === "" || /[:#[\]{},&*?|<>=!%@`]/.test(raw) || /^\s|\s$/.test(raw) || /^(true|false|null|~)$/i.test(raw) || /^\d/.test(raw);
459
426
  if (needsQuotes) {
@@ -504,18 +471,20 @@ function parseYaml(text: string): {
504
471
  const rawVal = line.slice(colonIdx + 2).trim();
505
472
  result[key] = parseYamlValue(rawVal);
506
473
  }
507
- const title = result["title"];
474
+ const { title } = result;
508
475
  if (typeof title !== "string" || !title) return null;
509
476
  const itemProps = { ...result };
510
477
  delete itemProps["title"];
511
478
  return { title, props: itemProps };
512
479
  }
513
480
 
514
- // ── Item selection & YAML edit ───────────────────────────────────────────────
515
-
516
481
  const selectedId = ref<string | null>(null);
517
482
  const yamlText = ref("");
518
483
  const yamlError = ref("");
484
+ // JSON source editor state (used by the watcher below as well, so
485
+ // declared up here to avoid TDZ ordering with the items-watch handler).
486
+ const editorText = ref("");
487
+ const parseError = ref("");
519
488
 
520
489
  function selectItem(item: ScheduledItem) {
521
490
  if (selectedId.value === item.id) {
@@ -556,21 +525,20 @@ async function applyItemEdit() {
556
525
  if (success) selectedId.value = null;
557
526
  }
558
527
 
559
- // ── JSON source editor ───────────────────────────────────────────────────────
560
-
561
528
  function toJson(its: ScheduledItem[]) {
562
529
  return JSON.stringify(its, null, 2);
563
530
  }
564
531
 
565
- const editorText = ref(toJson(items.value));
566
- const parseError = ref("");
567
- // Last POST /api/scheduler failure. Cleared on the next successful call
568
- // so the banner disappears as soon as things recover.
532
+ // Seed editorText now that toJson is in scope; the ref itself was
533
+ // declared earlier so the watcher above can reference it (#920).
534
+ editorText.value = toJson(items.value);
535
+
536
+ // Cleared on the next successful POST so the banner disappears as soon as things recover.
569
537
  const apiError = ref<string | null>(null);
570
538
  const isModified = computed(() => editorText.value !== toJson(items.value));
571
539
 
572
540
  async function callApi(body: Record<string, unknown>): Promise<boolean> {
573
- const response = await apiPost<{ data?: { items?: ScheduledItem[] } }>(API_ROUTES.scheduler.base, body);
541
+ const response = await apiPost<{ data?: { items?: ScheduledItem[] } }>(endpoints.dispatch.url, body);
574
542
  if (!response.ok) {
575
543
  apiError.value = response.error;
576
544
  return false;
@@ -1,18 +1,23 @@
1
- // MCP tool definition for the automations half of the former
2
- // `manageScheduler` (#824). Keeps the same backend route
3
- // (`/api/scheduler`) — server-side dispatch already routes
4
- // task-prefixed actions through the user-task subsystem via
5
- // `TASK_ACTIONS`, so the only thing changing here is the LLM
6
- // prompt and the tool name surfaced in chat.
7
-
8
1
  import type { ToolDefinition } from "gui-chat-protocol";
9
- import { SCHEDULER_ACTIONS } from "../../config/schedulerActions";
2
+ import { SCHEDULER_ACTIONS } from "./actions";
3
+ import { META as calendarMeta } from "./calendarMeta";
4
+ import type { ResolvedRoute } from "../meta-types";
5
+
6
+ export const TOOL_NAME = "manageAutomations";
7
+
8
+ /** Endpoint contract for the scheduler plugin (shared by calendar +
9
+ * automations definitions — both dispatch to the same `/api/scheduler`
10
+ * via the action enum). Routes are owned by the calendar META; the
11
+ * automations META is toolName-only because the binding row in
12
+ * `BUILT_IN_SERVER_BINDINGS` points the automations tool at the
13
+ * same dispatch URL. */
14
+ export type SchedulerEndpoints = { readonly [K in keyof typeof calendarMeta.apiRoutes]: ResolvedRoute };
10
15
 
11
16
  const AUTOMATION_ACTIONS = [SCHEDULER_ACTIONS.createTask, SCHEDULER_ACTIONS.listTasks, SCHEDULER_ACTIONS.deleteTask, SCHEDULER_ACTIONS.runTask] as const;
12
17
 
13
18
  const toolDefinition: ToolDefinition = {
14
19
  type: "function",
15
- name: "manageAutomations",
20
+ name: TOOL_NAME,
16
21
  prompt:
17
22
  "When users want a recurring automated task — something the agent runs on a schedule, not a single calendar event — use manageAutomations. " +
18
23
  "Examples: '毎朝8時にニュースまとめて', 'remind me every day', 'run this prompt hourly'. " +
@@ -0,0 +1,5 @@
1
+ import { definePluginMeta } from "../meta-types";
2
+
3
+ export const META = definePluginMeta({
4
+ toolName: "manageAutomations",
5
+ });
@@ -1,16 +1,13 @@
1
- // MCP tool definition for the calendar half of the former
2
- // `manageScheduler` (#824). Keeps the same backend route
3
- // (`/api/scheduler`) — the action enum is just narrowed to the
4
- // calendar-only subset so the LLM's prompt is unambiguous.
5
-
6
1
  import type { ToolDefinition } from "gui-chat-protocol";
7
- import { SCHEDULER_ACTIONS } from "../../config/schedulerActions";
2
+ import { SCHEDULER_ACTIONS } from "./actions";
3
+
4
+ export const TOOL_NAME = "manageCalendar";
8
5
 
9
6
  const CALENDAR_ACTIONS = [SCHEDULER_ACTIONS.show, SCHEDULER_ACTIONS.add, SCHEDULER_ACTIONS.update, SCHEDULER_ACTIONS.delete] as const;
10
7
 
11
8
  const toolDefinition: ToolDefinition = {
12
9
  type: "function",
13
- name: "manageCalendar",
10
+ name: TOOL_NAME,
14
11
  prompt:
15
12
  "When users mention calendar events, appointments, meetings, or one-off reminders that have a date/time, use manageCalendar. " +
16
13
  "Use show to display the calendar, add to create an event, update to edit one, delete to remove one. " +
@@ -0,0 +1,28 @@
1
+ import { definePluginMeta } from "../meta-types";
2
+
3
+ export const META = definePluginMeta({
4
+ toolName: "manageCalendar",
5
+ apiNamespace: "scheduler",
6
+ apiRoutes: {
7
+ /** GET /api/scheduler — read calendar items. */
8
+ list: { method: "GET", path: "" },
9
+ /** POST /api/scheduler — calendar / automations action dispatch.
10
+ * The server splits calendar item actions from task-related
11
+ * actions via the `action` discriminator (see `TASK_ACTIONS`). */
12
+ dispatch: { method: "POST", path: "" },
13
+ /** GET /api/scheduler/tasks — list every registered task
14
+ * (system + user). */
15
+ tasksList: { method: "GET", path: "/tasks" },
16
+ /** POST /api/scheduler/tasks — create a user task. */
17
+ tasksCreate: { method: "POST", path: "/tasks" },
18
+ /** PUT /api/scheduler/tasks/:id — update a user task. */
19
+ taskUpdate: { method: "PUT", path: "/tasks/:id" },
20
+ /** DELETE /api/scheduler/tasks/:id — delete a user task. */
21
+ taskDelete: { method: "DELETE", path: "/tasks/:id" },
22
+ /** POST /api/scheduler/tasks/:id/run — fire a task immediately. */
23
+ taskRun: { method: "POST", path: "/tasks/:id/run" },
24
+ /** GET /api/scheduler/logs — newest-first scheduler execution log. */
25
+ logs: { method: "GET", path: "/logs" },
26
+ },
27
+ mcpDispatch: "dispatch",
28
+ });
@@ -1,11 +1,5 @@
1
- // Pure formatters for scheduler-task display. Extracted from
2
- // TasksTab.vue so the UTC local conversion can be unit-tested
3
- // without spinning up Vue.
4
- //
5
- // Internally every task stores its daily trigger as `HH:MM` in UTC
6
- // (that's what the scheduler engine fires on). The UI should show the
7
- // same moment in the viewer's local timezone so a user in Tokyo sees
8
- // "Daily 05:00 JST" instead of "Daily 20:00 UTC".
1
+ // Tasks store the daily trigger as `HH:MM` in UTC (that's what the engine fires on); the UI converts to the
2
+ // viewer's local zone so a user in Tokyo sees "Daily 05:00 JST" instead of "Daily 20:00 UTC".
9
3
 
10
4
  export interface DailySchedule {
11
5
  type: "daily";
@@ -21,20 +15,12 @@ export type TaskSchedule = DailySchedule | IntervalSchedule | { type: string; [k
21
15
 
22
16
  const DAILY_TIME_RE = /^(\d{1,2}):(\d{2})$/;
23
17
 
24
- // Build a Date anchored to `now`'s local calendar day but at the
25
- // requested UTC wall-clock hour/minute. Using today's date (rather
26
- // than epoch 1970) makes the DST/TZ conversion accurate for the
27
- // viewer's current moment — "20:00 UTC every day" in Europe/London
28
- // can differ by an hour between summer and winter.
18
+ // Anchor to today (not 1970) so DST conversion is accurate "20:00 UTC daily" can differ by an hour summer/winter in London.
29
19
  function buildUtcInstant(utcHour: number, utcMinute: number, now: Date): Date {
30
20
  return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), utcHour, utcMinute));
31
21
  }
32
22
 
33
- // Intl formatter configured to surface HH:MM + the short timezone
34
- // name (e.g. "JST", "PDT"). When the browser can't resolve a zone
35
- // abbreviation it falls back to the offset string ("GMT+9"), which
36
- // is fine — the point is that the user doesn't have to mentally
37
- // convert from UTC.
23
+ // Browsers without a zone abbreviation fall back to "GMT+9" — fine; the point is no manual UTC conversion.
38
24
  const LOCAL_TIME_FORMATTER = new Intl.DateTimeFormat(undefined, {
39
25
  hour: "2-digit",
40
26
  minute: "2-digit",
@@ -49,8 +35,7 @@ function extractHourMinuteTz(date: Date): { hourMinute: string; tzLabel: string
49
35
  const minute = parts.find((part) => part.type === "minute")?.value ?? "";
50
36
  const tzLabel = parts.find((part) => part.type === "timeZoneName")?.value ?? "";
51
37
  if (!hour || !minute) return null;
52
- // Intl returns "24" for midnight hour under `hour: "2-digit"` on
53
- // some runtimes — normalize so "Daily 24:00 JST" never appears.
38
+ // Some runtimes return "24" for midnight under hour:"2-digit" — normalize so "Daily 24:00 JST" never appears.
54
39
  const normalizedHour = hour === "24" ? "00" : hour;
55
40
  return { hourMinute: `${normalizedHour}:${minute}`, tzLabel };
56
41
  } catch {
@@ -58,10 +43,7 @@ function extractHourMinuteTz(date: Date): { hourMinute: string; tzLabel: string
58
43
  }
59
44
  }
60
45
 
61
- // Convert a UTC "HH:MM" into "Daily HH:MM <tz>" in the viewer's
62
- // local zone. Returns the original "Daily HH:MM UTC" string if the
63
- // input is malformed or the Intl machinery is unavailable — callers
64
- // never see `null`/throw for a scheduler entry.
46
+ // Falls back to "Daily HH:MM UTC" on malformed input or missing Intl — callers never see null/throw.
65
47
  export function formatDailyLocal(utcHHMM: string, now: Date = new Date()): string {
66
48
  const match = DAILY_TIME_RE.exec(utcHHMM);
67
49
  if (!match) return `Daily ${utcHHMM} UTC`;
@@ -1,23 +1,17 @@
1
- // Two plugins, one shared backend (#824). Both call /api/scheduler;
2
- // the server-side dispatcher already routes per-action via
3
- // TASK_ACTIONS, so the plugins are thin wrappers over the same
4
- // REST contract — they differ only in tool definition (the action
5
- // enum the LLM sees) and in the chat-side view (CalendarView vs
6
- // AutomationsView). The legacy unified `manageScheduler` plugin
7
- // went away with the rename; see plans/refactor-split-manageScheduler-824.md.
1
+ // #824: two plugins share /api/scheduler the server already dispatches per-action via TASK_ACTIONS, so each plugin
2
+ // just differs in the tool definition (action enum the LLM sees) and the View component.
8
3
 
9
- import type { PluginEntry } from "../../tools/types";
10
- import type { ToolPlugin } from "../../tools/types";
4
+ import type { PluginRegistration, ToolPlugin } from "../../tools/types";
11
5
  import type { ToolResult } from "gui-chat-protocol";
12
6
  import CalendarView from "./CalendarView.vue";
13
7
  import AutomationsView from "./AutomationsView.vue";
14
- import LegacySchedulerView from "./LegacySchedulerView.vue";
15
8
  import Preview from "./Preview.vue";
16
9
  import AutomationsPreview from "./AutomationsPreview.vue";
17
- import calendarDefinition from "./calendarDefinition";
18
- import automationsDefinition from "./automationsDefinition";
19
- import { apiPost } from "../../utils/api";
20
- import { API_ROUTES } from "../../config/apiRoutes";
10
+ import calendarDefinition, { TOOL_NAME as MANAGE_CALENDAR } from "./calendarDefinition";
11
+ import automationsDefinition, { TOOL_NAME as MANAGE_AUTOMATIONS, type SchedulerEndpoints } from "./automationsDefinition";
12
+ import { pluginEndpoints } from "../api";
13
+ import { wrapWithScope } from "../scope";
14
+ import { apiCall } from "../../utils/api";
21
15
  import { makeUuid } from "../../utils/id";
22
16
 
23
17
  export interface ScheduledItem {
@@ -31,12 +25,12 @@ export interface SchedulerData {
31
25
  items: ScheduledItem[];
32
26
  }
33
27
 
34
- // Shared executor for both plugins backend dispatch is identical.
35
- // `toolName` is captured by closure so the tool result carries the
36
- // matching name through to the chat history and the View lookup.
37
- function makeExecute(toolName: "manageCalendar" | "manageAutomations"): ToolPlugin<SchedulerData>["execute"] {
28
+ // `toolName` is captured so the result carries the matching name through to chat history and View lookup.
29
+ function makeExecute(toolName: typeof MANAGE_CALENDAR | typeof MANAGE_AUTOMATIONS): ToolPlugin<SchedulerData>["execute"] {
38
30
  return async function execute(_context, args) {
39
- const result = await apiPost<ToolResult<SchedulerData>>(API_ROUTES.scheduler.base, args);
31
+ const endpoints = pluginEndpoints<SchedulerEndpoints>("scheduler");
32
+ const { method, url } = endpoints.dispatch;
33
+ const result = await apiCall<ToolResult<SchedulerData>>(url, { method, body: args });
40
34
  if (!result.ok) {
41
35
  return {
42
36
  toolName,
@@ -54,46 +48,26 @@ function makeExecute(toolName: "manageCalendar" | "manageAutomations"): ToolPlug
54
48
 
55
49
  export const manageCalendarPlugin: ToolPlugin<SchedulerData> = {
56
50
  toolDefinition: calendarDefinition,
57
- execute: makeExecute("manageCalendar"),
51
+ execute: makeExecute(MANAGE_CALENDAR),
58
52
  isEnabled: () => true,
59
53
  generatingMessage: "Updating calendar...",
60
- viewComponent: CalendarView,
61
- previewComponent: Preview,
54
+ viewComponent: wrapWithScope("scheduler", CalendarView),
55
+ previewComponent: wrapWithScope("scheduler", Preview),
62
56
  };
63
57
 
64
58
  export const manageAutomationsPlugin: ToolPlugin<SchedulerData> = {
65
59
  toolDefinition: automationsDefinition,
66
- execute: makeExecute("manageAutomations"),
60
+ execute: makeExecute(MANAGE_AUTOMATIONS),
67
61
  isEnabled: () => true,
68
62
  generatingMessage: "Managing automations...",
69
- viewComponent: AutomationsView,
70
- // Previews must not share Preview.vue with manageCalendarPlugin
71
- // Preview.vue auto-refreshes from `/api/scheduler` which returns
72
- // calendar items, so the automations sidebar would show calendar
73
- // data after the first refresh tick (#828 follow-up).
74
- previewComponent: AutomationsPreview,
63
+ viewComponent: wrapWithScope("scheduler", AutomationsView),
64
+ // Cannot share Preview.vue with manageCalendar Preview auto-refreshes from /api/scheduler (calendar items), and
65
+ // the automations sidebar would otherwise show calendar data after the first refresh tick (#828 follow-up).
66
+ previewComponent: wrapWithScope("scheduler", AutomationsPreview),
75
67
  };
76
68
 
77
- // View-only fallback for tool results saved under the pre-split
78
- // `manageScheduler` name. Registered in src/tools/index.ts so
79
- // `getPlugin("manageScheduler")` returns this entry and historical
80
- // chat sessions still render the rich view (LegacySchedulerView
81
- // dispatches to CalendarView or AutomationsView by data shape).
82
- //
83
- // Deliberately a `PluginEntry` (not a `ToolPlugin`) so the absence
84
- // of `execute` / `isEnabled` makes its view-only nature explicit:
85
- // no LLM exposure path, no fresh dispatch, just the historical
86
- // renderer. The tool name is also absent from
87
- // server/agent/plugin-names.ts and src/config/toolNames.ts, so
88
- // new sessions cannot pick it up.
89
- export const legacyManageSchedulerEntry: PluginEntry = {
90
- toolDefinition: {
91
- type: "function",
92
- name: "manageScheduler",
93
- prompt: "[deprecated] Split into manageCalendar + manageAutomations (#824).",
94
- description: "[deprecated] Split into manageCalendar + manageAutomations (#824). Kept registered for legacy chat-history rendering only.",
95
- parameters: { type: "object", properties: {}, required: [] },
96
- },
97
- viewComponent: LegacySchedulerView,
98
- previewComponent: Preview,
99
- };
69
+ // One plugin module, two tool registrations see #824 split.
70
+ export const REGISTRATIONS: PluginRegistration[] = [
71
+ { toolName: MANAGE_CALENDAR, entry: manageCalendarPlugin },
72
+ { toolName: MANAGE_AUTOMATIONS, entry: manageAutomationsPlugin },
73
+ ];
@@ -0,0 +1,57 @@
1
+ // Built-in plugin scope wrapper. Wraps a built-in plugin's View /
2
+ // Preview component in `<PluginScopedRoot>` so descendants can pull
3
+ // the same `BrowserPluginRuntime` (via `useRuntime()` from
4
+ // `gui-chat-protocol/vue`) that runtime-loaded plugins receive.
5
+ //
6
+ // Why: the host's runtime plugin loader already wraps runtime
7
+ // plugins (`src/tools/runtimeLoader.ts#wrapWithScopedRoot`). For
8
+ // built-in plugins to opt into the same `useRuntime()` API — incl.
9
+ // `runtime.endpoints` for multi-URL plugins (gui-chat-protocol
10
+ // 0.3.1+) — they need a similar wrapper. This file is that
11
+ // wrapper, used at plugin-registration time so each plugin's
12
+ // `viewComponent` / `previewComponent` carries the scope provider.
13
+ //
14
+ // Endpoints come from the host's runtime registry at SETUP time
15
+ // (not module load) — `pluginEndpoints(scope)` reads from the
16
+ // `installHostContext` registry which is wired in `src/main.ts`
17
+ // before `app.mount`. By the time a plugin's setup() runs the
18
+ // registry is populated.
19
+
20
+ import { defineComponent, h, markRaw, type Component } from "vue";
21
+ import PluginScopedRoot from "../components/PluginScopedRoot.vue";
22
+ import { pluginEndpoints } from "./api";
23
+
24
+ /** Wrap a built-in plugin's component (`viewComponent` /
25
+ * `previewComponent`) so its descendants can call `useRuntime()`.
26
+ * The wrapped component:
27
+ *
28
+ * - looks up the plugin's endpoint group from the host's DI
29
+ * registry at setup time,
30
+ * - mounts `<PluginScopedRoot pkg-name=<scope> :endpoints>`,
31
+ * - forwards every prop / attr / slot through to the inner
32
+ * component verbatim.
33
+ *
34
+ * Returns `undefined` when `inner` is `undefined` — matches the
35
+ * `getPlugin().viewComponent` / `previewComponent` shape (presence
36
+ * is optional).
37
+ *
38
+ * @param scope plugin scope name (matches the install registry
39
+ * key, e.g. `"todos"`, `"wiki"`, `"mulmoScript"`).
40
+ * @param inner the plugin's raw View / Preview component. */
41
+ export function wrapWithScope<TInner extends Component | undefined>(scope: string, inner: TInner): TInner {
42
+ if (!inner) return inner;
43
+ // `markRaw` so reactive containers don't try to proxy this
44
+ // component object — Vue warns + the proxy can interfere with
45
+ // internal component identity tracking. Same pattern as
46
+ // `runtimeLoader.ts#wrapWithScopedRoot`.
47
+ return markRaw(
48
+ defineComponent({
49
+ name: `BuiltInPluginScope:${scope}`,
50
+ inheritAttrs: false,
51
+ setup(_props, { attrs, slots }) {
52
+ const endpoints = pluginEndpoints<Record<string, unknown>>(scope);
53
+ return () => h(PluginScopedRoot, { pkgName: scope, endpoints }, () => h(inner, attrs, slots));
54
+ },
55
+ }),
56
+ ) as TInner;
57
+ }
@@ -0,0 +1,38 @@
1
+ // Server-side MCP binding types + the META→endpoint resolver,
2
+ // extracted so both the codegen-generated barrel
3
+ // (`_generated/server-bindings.ts`) and the user-facing barrel
4
+ // (`server.ts`) can import them without a circular dependency.
5
+ //
6
+ // Browser-safe: no Vue / no Node-only imports — same constraint as
7
+ // `meta-types.ts`. Imported from server-side code via tsx.
8
+
9
+ import type { ToolDefinition } from "gui-chat-protocol";
10
+ import { API_ROUTES } from "../config/apiRoutes";
11
+ import type { PluginMeta, ResolvedRoute } from "./meta-types";
12
+
13
+ export interface ServerPluginBinding {
14
+ /** ToolDefinition object — the plugin's MCP-facing schema. The
15
+ * `name` field is the lookup key for the MCP tool registry. */
16
+ readonly def: ToolDefinition;
17
+ /** Where the MCP bridge POSTs tool calls for this plugin. */
18
+ readonly endpoint: string;
19
+ }
20
+
21
+ /** Resolve a plugin's MCP-dispatch URL from its META: looks up
22
+ * `apiNamespace`+`apiRoutes[mcpDispatch]` in the host's API_ROUTES
23
+ * registry and returns the composed `url`. Throws on a META that
24
+ * doesn't declare both fields — the binding can't dispatch without
25
+ * them. The lookup-by-namespace lets the host pick up route shape
26
+ * changes (path / verb edits) without `BUILT_IN_SERVER_BINDINGS`
27
+ * needing to know the URL. */
28
+ export function mcpEndpoint(meta: PluginMeta): string {
29
+ if (!meta.apiNamespace || !meta.mcpDispatch) {
30
+ throw new Error(`Plugin "${meta.toolName}" cannot register MCP binding: missing apiNamespace or mcpDispatch in META`);
31
+ }
32
+ const namespaceRecord = (API_ROUTES as unknown as Record<string, Record<string, ResolvedRoute>>)[meta.apiNamespace];
33
+ const route = namespaceRecord?.[meta.mcpDispatch];
34
+ if (!route) {
35
+ throw new Error(`Plugin "${meta.toolName}" mcpDispatch route "${meta.mcpDispatch}" not found under API_ROUTES.${meta.apiNamespace}`);
36
+ }
37
+ return route.url;
38
+ }