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.
- package/Dockerfile.sandbox +100 -0
- package/README.md +17 -4
- package/bin/mulmoclaude.js +46 -15
- package/bin/prepare-dist.js +18 -2
- package/client/assets/chunk-CernVdwh.js +1 -0
- package/client/assets/chunk-D8eiyYIV-C1eAZMzz.js +1 -0
- package/client/assets/html2canvas-CDGcmOD3-BbPeutDg.js +5 -0
- package/client/assets/index-BbgSjFQ8.js +4968 -0
- package/client/assets/index-ECD0lgIv.css +2 -0
- package/client/assets/{index.es-D4YyL_Dg-BgT6a3Nd.js → index.es-DqtpmBm8-DJdTPdnc.js} +5 -5
- package/client/assets/material-symbols-outlined-BLDfUw-_.woff2 +0 -0
- package/client/assets/runtime-protocol-vue-6WYa8hAs.js +1 -0
- package/client/assets/runtime-vue-BVUzgYGA.js +1 -0
- package/client/assets/typeof-DBp4T-Ny-C2xoZtcz.js +1 -0
- package/client/assets/vue-1e_vz2LW.js +1 -0
- package/client/assets/vue.runtime.esm-bundler-DQ8Kjjui.js +4 -0
- package/client/index.html +33 -2
- package/package.json +20 -18
- package/sandbox-entrypoint.sh +106 -0
- package/server/accounting/accountNormalize.ts +32 -0
- package/server/accounting/defaultAccounts.ts +87 -0
- package/server/accounting/eventPublisher.ts +51 -0
- package/server/accounting/journal.ts +252 -0
- package/server/accounting/openingBalances.ts +114 -0
- package/server/accounting/report.ts +237 -0
- package/server/accounting/service.ts +718 -0
- package/server/accounting/snapshotCache.ts +333 -0
- package/server/accounting/timeSeries.ts +265 -0
- package/server/accounting/types.ts +148 -0
- package/server/agent/activeTools.ts +128 -0
- package/server/agent/attachmentConverter.ts +10 -5
- package/server/agent/backend/claude-code.ts +8 -2
- package/server/agent/backend/types.ts +1 -1
- package/server/agent/config.ts +101 -31
- package/server/agent/index.ts +45 -33
- package/server/agent/mcp-server.ts +146 -69
- package/server/agent/mcp-tools/index.ts +1 -5
- package/server/agent/mcp-tools/notify.ts +2 -22
- package/server/agent/mcp-tools/x.ts +0 -4
- package/server/agent/mcpHealth.ts +168 -0
- package/server/agent/plugin-names.ts +20 -77
- package/server/agent/prompt.ts +259 -51
- package/server/agent/resumeFailover.ts +1 -1
- package/server/agent/stream.ts +0 -1
- package/server/api/auth/bearerAuth.ts +5 -5
- package/server/api/csrfGuard.ts +1 -1
- package/server/api/routes/accounting.ts +366 -0
- package/server/api/routes/agent.ts +509 -46
- package/server/api/routes/attachment.ts +104 -0
- package/server/api/routes/chart.ts +2 -1
- package/server/api/routes/config.ts +12 -12
- package/server/api/routes/files.ts +105 -48
- package/server/api/routes/image.ts +70 -25
- package/server/api/routes/journal.ts +35 -0
- package/server/api/routes/mulmo-script.ts +358 -118
- package/server/api/routes/mulmoScriptValidate.ts +1 -1
- package/server/api/routes/news.ts +1 -1
- package/server/api/routes/notifications.ts +92 -22
- package/server/api/routes/notifier.ts +98 -0
- package/server/api/routes/pdf.ts +188 -48
- package/server/api/routes/plugins.ts +34 -14
- package/server/api/routes/presentHtml.ts +58 -3
- package/server/api/routes/roles.ts +1 -8
- package/server/api/routes/runtime-plugin.ts +224 -0
- package/server/api/routes/scheduler.ts +7 -5
- package/server/api/routes/schedulerHandlers.ts +1 -1
- package/server/api/routes/schedulerTasks.ts +8 -7
- package/server/api/routes/sessions.ts +234 -121
- package/server/api/routes/skills.ts +56 -51
- package/server/api/routes/sources.ts +52 -45
- package/server/api/routes/translation.ts +44 -0
- package/server/api/routes/wiki/frontmatter.ts +13 -65
- package/server/api/routes/wiki/history.ts +261 -0
- package/server/api/routes/wiki/pageIndex.ts +1 -1
- package/server/api/routes/wiki.ts +50 -26
- package/server/events/file-change.ts +83 -0
- package/server/events/notifications.ts +247 -91
- package/server/events/pub-sub/index.ts +1 -1
- package/server/events/relay-client.ts +5 -5
- package/server/events/scheduler-adapter.ts +2 -2
- package/server/events/session-store/index.ts +110 -22
- package/server/events/task-manager/index.ts +10 -9
- package/server/index.ts +509 -33
- package/server/notifier/engine.ts +419 -0
- package/server/notifier/legacy-adapters.ts +76 -0
- package/server/notifier/runtime-api.ts +74 -0
- package/server/notifier/store.ts +70 -0
- package/server/notifier/types.ts +121 -0
- package/server/plugins/dev-loader.ts +171 -0
- package/server/plugins/dev-watcher.ts +150 -0
- package/server/plugins/diagnostics.ts +188 -0
- package/server/plugins/preset-list.ts +52 -0
- package/server/plugins/preset-loader.ts +112 -0
- package/server/plugins/runtime-chat-api.ts +38 -0
- package/server/plugins/runtime-loader.ts +430 -0
- package/server/plugins/runtime-registry.ts +112 -0
- package/server/plugins/runtime-tasks-api.ts +50 -0
- package/server/plugins/runtime.ts +378 -0
- package/server/services/translation/cache.ts +72 -0
- package/server/services/translation/index.ts +106 -0
- package/server/services/translation/llm.ts +140 -0
- package/server/services/translation/types.ts +35 -0
- package/server/system/credentials.ts +13 -2
- package/server/system/env.ts +6 -1
- package/server/system/logger/formatters.ts +46 -4
- package/server/system/logger/index.ts +4 -4
- package/server/system/logger/sinks.ts +26 -5
- package/server/system/logger/types.ts +2 -2
- package/server/utils/dev-plugin-args.d.mts +11 -0
- package/server/utils/dev-plugin-args.mjs +43 -0
- package/server/utils/errors.ts +13 -4
- package/server/utils/files/accounting-io.ts +295 -0
- package/server/utils/files/atomic.ts +17 -49
- package/server/utils/files/attachment-store.ts +182 -0
- package/server/utils/files/html-io.ts +1 -7
- package/server/utils/files/html-store.ts +19 -0
- package/server/utils/files/image-store.ts +20 -22
- package/server/utils/files/index.ts +5 -15
- package/server/utils/files/journal-io.ts +7 -35
- package/server/utils/files/json.ts +2 -29
- package/server/utils/files/markdown-image-fill.ts +6 -37
- package/server/utils/files/markdown-store.ts +6 -21
- package/server/utils/files/naming.ts +3 -39
- package/server/utils/files/plugins-io.ts +100 -0
- package/server/utils/files/reference-dirs-io.ts +1 -9
- package/server/utils/files/roles-io.ts +2 -10
- package/server/utils/files/safe.ts +17 -19
- package/server/utils/files/scheduler-io.ts +1 -7
- package/server/utils/files/scheduler-overrides-io.ts +3 -12
- package/server/utils/files/session-io.ts +21 -30
- package/server/utils/files/spreadsheet-store.ts +9 -22
- package/server/utils/files/translation-io.ts +46 -0
- package/server/utils/files/user-tasks-io.ts +1 -7
- package/server/utils/files/workspace-io.ts +3 -79
- package/server/utils/gemini.ts +33 -11
- package/server/utils/html/htmlArtifactSplicer.ts +41 -0
- package/server/utils/markdown/frontmatter.ts +112 -0
- package/server/utils/regex.ts +56 -0
- package/server/utils/router.ts +41 -0
- package/server/utils/slug.ts +5 -3
- package/server/utils/time.ts +12 -0
- package/server/workspace/chat-index/indexer.ts +15 -2
- package/server/workspace/chat-index/summarizer.ts +1 -1
- package/server/workspace/custom-dirs.ts +1 -1
- package/server/workspace/helps/gemini.md +1 -1
- package/server/workspace/helps/guide.md +61 -0
- package/server/workspace/helps/index.md +4 -0
- package/server/workspace/helps/presenthtml.md +80 -0
- package/server/workspace/helps/sandbox.md +7 -0
- package/server/workspace/helps/storyteller.md +101 -0
- package/server/workspace/helps/telegram.md +1 -0
- package/server/workspace/helps/wiki.md +9 -7
- package/server/workspace/journal/archivist-cli.ts +7 -33
- package/server/workspace/journal/archivist-schemas.ts +5 -43
- package/server/workspace/journal/dailyPass.ts +34 -187
- package/server/workspace/journal/diff.ts +3 -28
- package/server/workspace/journal/index.ts +10 -81
- package/server/workspace/journal/indexFile.ts +3 -24
- package/server/workspace/journal/latestDaily.ts +51 -0
- package/server/workspace/journal/memoryExtractor.ts +4 -20
- package/server/workspace/journal/optimizationPass.ts +4 -21
- package/server/workspace/journal/paths.ts +4 -23
- package/server/workspace/journal/state.ts +6 -29
- package/server/workspace/memory/io.ts +213 -0
- package/server/workspace/memory/llm-classifier.ts +158 -0
- package/server/workspace/memory/migrate.ts +263 -0
- package/server/workspace/memory/run.ts +84 -0
- package/server/workspace/memory/topic-cluster.ts +218 -0
- package/server/workspace/memory/topic-detect.ts +67 -0
- package/server/workspace/memory/topic-index-hook.ts +128 -0
- package/server/workspace/memory/topic-io.ts +180 -0
- package/server/workspace/memory/topic-migrate.ts +248 -0
- package/server/workspace/memory/topic-run.ts +172 -0
- package/server/workspace/memory/topic-swap.ts +135 -0
- package/server/workspace/memory/topic-types.ts +142 -0
- package/server/workspace/memory/types.ts +83 -0
- package/server/workspace/news/reader.ts +4 -5
- package/server/workspace/paths.ts +124 -47
- package/server/workspace/roles.ts +2 -11
- package/server/workspace/skills/parser.ts +38 -55
- package/server/workspace/skills/user-tasks.ts +1 -2
- package/server/workspace/skills-preset/mc-library/SKILL.md +188 -0
- package/server/workspace/skills-preset.ts +196 -0
- package/server/workspace/sources/fetchers/githubIssues.ts +13 -11
- package/server/workspace/sources/fetchers/index.ts +1 -1
- package/server/workspace/sources/fetchers/rssParser.ts +1 -1
- package/server/workspace/sources/pipeline/index.ts +2 -2
- package/server/workspace/sources/pipeline/notify.ts +3 -3
- package/server/workspace/sources/pipeline/write.ts +2 -2
- package/server/workspace/sources/registry.ts +39 -61
- package/server/workspace/sources/robots.ts +1 -1
- package/server/workspace/tool-trace/classify.ts +2 -1
- package/server/workspace/tool-trace/index.ts +1 -1
- package/server/workspace/tool-trace/writeSearch.ts +6 -1
- package/server/workspace/wiki-backlinks/index.ts +19 -7
- package/server/workspace/wiki-backlinks/sessionBacklinks.ts +1 -0
- package/server/workspace/wiki-history/hook/snapshot.mjs +98 -0
- package/server/workspace/wiki-history/hook/snapshot.ts +135 -0
- package/server/workspace/wiki-history/provision.ts +181 -0
- package/server/workspace/wiki-pages/io.ts +217 -0
- package/server/workspace/wiki-pages/snapshot.ts +380 -0
- package/server/workspace/workspace.ts +75 -13
- package/src/App.vue +115 -40
- package/src/_runtime/protocol-vue.ts +21 -0
- package/src/_runtime/vue.ts +22 -0
- package/src/components/ChatInput.vue +14 -10
- package/src/components/CopyChatButton.vue +76 -0
- package/src/components/FileContentRenderer.vue +67 -14
- package/src/components/FileTree.vue +2 -2
- package/src/components/FilesView.vue +17 -1
- package/src/components/NewsView.vue +16 -2
- package/src/components/NotificationBell.vue +320 -93
- package/src/components/PageChatComposer.vue +5 -4
- package/src/components/PluginLauncher.vue +42 -6
- package/src/components/PluginScopedRoot.vue +87 -0
- package/src/components/RoleSelector.vue +12 -1
- package/src/components/RolesView.vue +562 -0
- package/src/components/SentAttachmentChip.vue +102 -0
- package/src/components/SessionHistoryPanel.vue +109 -20
- package/src/components/SessionRoleIcon.vue +7 -4
- package/src/components/SessionSidebar.vue +20 -7
- package/src/components/SessionTabBar.vue +1 -1
- package/src/components/SettingsMcpTab.vue +4 -4
- package/src/components/SettingsModal.vue +2 -0
- package/src/components/SidebarHeader.vue +16 -5
- package/src/components/SourcesManager.vue +23 -9
- package/src/components/SourcesView.vue +1 -1
- package/src/components/StackView.vue +102 -6
- package/src/components/SuggestionsPanel.vue +105 -16
- package/src/components/SystemFileBanner.vue +1 -1
- package/src/components/TodoExplorer.vue +4 -5
- package/src/components/todo/TodoAddDialog.vue +2 -3
- package/src/components/todo/TodoEditDialog.vue +1 -2
- package/src/components/todo/TodoEditPanel.vue +2 -3
- package/src/components/todo/TodoKanbanView.vue +8 -5
- package/src/components/todo/TodoListView.vue +3 -5
- package/src/components/todo/TodoTableView.vue +7 -5
- package/src/composables/useAccountingChannel.ts +58 -0
- package/src/composables/useActiveSession.ts +4 -25
- package/src/composables/useAppApi.ts +6 -44
- package/src/composables/useClipboardCopy.ts +3 -20
- package/src/composables/useContentDisplay.ts +33 -2
- package/src/composables/useDevPluginReload.ts +23 -0
- package/src/composables/useDynamicFavicon.ts +5 -31
- package/src/composables/useEventListeners.ts +0 -20
- package/src/composables/useExpandedDirs.ts +4 -15
- package/src/composables/useFaviconState.ts +12 -46
- package/src/composables/useFileChange.ts +53 -0
- package/src/composables/useFreshPluginData.ts +6 -43
- package/src/composables/useHealth.ts +14 -43
- package/src/composables/useImageErrorRepair.ts +104 -0
- package/src/composables/useLatestDaily.ts +40 -0
- package/src/composables/useMarkdownDoc.ts +39 -0
- package/src/composables/useMarkdownLinkHandler.ts +1 -1
- package/src/composables/useMcpTools.ts +3 -16
- package/src/composables/useNotifications.ts +138 -112
- package/src/composables/usePdfDownload.ts +17 -3
- package/src/composables/usePendingCalls.ts +8 -26
- package/src/composables/usePluginErrorBoundary.ts +68 -0
- package/src/composables/usePubSub.ts +9 -17
- package/src/composables/useRunElapsed.ts +5 -22
- package/src/composables/useSandboxStatus.ts +4 -20
- package/src/composables/useSessionDerived.ts +7 -15
- package/src/composables/useSessionHistory.ts +70 -29
- package/src/composables/useSessionSync.ts +25 -3
- package/src/composables/useSkillsList.ts +59 -0
- package/src/composables/useTranslatedQueries.ts +109 -0
- package/src/config/apiRoutes.ts +181 -80
- package/src/config/historyFilters.ts +5 -3
- package/src/config/hostEvents.ts +17 -0
- package/src/config/mcpCatalog.ts +277 -5
- package/src/config/pubsubChannels.ts +134 -12
- package/src/config/roles.ts +212 -147
- package/src/config/systemFileDescriptors.ts +5 -5
- package/src/config/toolNames.ts +52 -30
- package/src/config/workspacePaths.ts +26 -2
- package/src/lang/de.ts +483 -27
- package/src/lang/en.ts +448 -27
- package/src/lang/es.ts +474 -27
- package/src/lang/fr.ts +476 -27
- package/src/lang/ja.ts +465 -27
- package/src/lang/ko.ts +466 -27
- package/src/lang/pt-BR.ts +473 -27
- package/src/lang/zh.ts +463 -27
- package/src/lib/vue-i18n.ts +1 -1
- package/src/lib/wiki-page/slug.ts +66 -0
- package/src/main.ts +85 -0
- package/src/plugins/_extras.ts +58 -0
- package/src/plugins/_generated/metas.ts +42 -0
- package/src/plugins/_generated/registrations.ts +44 -0
- package/src/plugins/_generated/server-bindings.ts +47 -0
- package/src/plugins/accounting/Preview.vue +106 -0
- package/src/plugins/accounting/View.vue +632 -0
- package/src/plugins/accounting/actions.ts +34 -0
- package/src/plugins/accounting/api.ts +301 -0
- package/src/plugins/accounting/components/AccountEditor.vue +250 -0
- package/src/plugins/accounting/components/AccountRow.vue +50 -0
- package/src/plugins/accounting/components/AccountsList.vue +102 -0
- package/src/plugins/accounting/components/AccountsModal.vue +300 -0
- package/src/plugins/accounting/components/BalanceSheet.vue +186 -0
- package/src/plugins/accounting/components/BookSettings.vue +284 -0
- package/src/plugins/accounting/components/BookSwitcher.vue +78 -0
- package/src/plugins/accounting/components/DateRangePicker.vue +140 -0
- package/src/plugins/accounting/components/JournalEntryForm.vue +504 -0
- package/src/plugins/accounting/components/JournalList.vue +553 -0
- package/src/plugins/accounting/components/Ledger.vue +206 -0
- package/src/plugins/accounting/components/NewBookForm.vue +211 -0
- package/src/plugins/accounting/components/OpeningBalancesForm.vue +271 -0
- package/src/plugins/accounting/components/ProfitLoss.vue +160 -0
- package/src/plugins/accounting/components/accountDraft.ts +13 -0
- package/src/plugins/accounting/components/accountNumbering.ts +103 -0
- package/src/plugins/accounting/components/accountValidation.ts +75 -0
- package/src/plugins/accounting/components/useLatestRequest.ts +44 -0
- package/src/plugins/accounting/countries.ts +158 -0
- package/src/plugins/accounting/currencies.ts +64 -0
- package/src/plugins/accounting/dates.ts +51 -0
- package/src/plugins/accounting/definition.ts +199 -0
- package/src/plugins/accounting/fiscalYear.ts +136 -0
- package/src/plugins/accounting/index.ts +49 -0
- package/src/plugins/accounting/meta.ts +91 -0
- package/src/plugins/accounting/timeSeriesEnums.ts +16 -0
- package/src/plugins/api.ts +125 -0
- package/src/plugins/canvas/View.vue +38 -28
- package/src/plugins/canvas/definition.ts +10 -8
- package/src/plugins/canvas/index.ts +15 -8
- package/src/plugins/canvas/meta.ts +12 -0
- package/src/plugins/chart/Preview.vue +1 -1
- package/src/plugins/chart/View.vue +2 -2
- package/src/plugins/chart/definition.ts +12 -2
- package/src/plugins/chart/index.ts +15 -7
- package/src/plugins/chart/meta.ts +18 -0
- package/src/plugins/editImages/definition.ts +44 -0
- package/src/plugins/editImages/index.ts +43 -0
- package/src/plugins/editImages/meta.ts +5 -0
- package/src/plugins/generateImage/View.vue +3 -1
- package/src/plugins/generateImage/definition.ts +2 -0
- package/src/plugins/generateImage/index.ts +13 -5
- package/src/plugins/generateImage/meta.ts +5 -0
- package/src/plugins/index.ts +35 -0
- package/src/plugins/manageRoles/Preview.vue +7 -4
- package/src/plugins/manageRoles/View.vue +12 -8
- package/src/plugins/manageRoles/definition.ts +6 -0
- package/src/plugins/manageRoles/index.ts +7 -6
- package/src/plugins/manageSkills/View.vue +11 -7
- package/src/plugins/manageSkills/definition.ts +4 -1
- package/src/plugins/manageSkills/index.ts +14 -7
- package/src/plugins/manageSkills/meta.ts +21 -0
- package/src/plugins/manageSource/definition.ts +4 -1
- package/src/plugins/manageSource/index.ts +15 -7
- package/src/plugins/manageSource/meta.ts +21 -0
- package/src/plugins/markdown/Preview.vue +10 -8
- package/src/plugins/markdown/View.vue +84 -17
- package/src/plugins/markdown/definition.ts +7 -1
- package/src/plugins/markdown/index.ts +15 -8
- package/src/plugins/markdown/meta.ts +16 -0
- package/src/plugins/meta-types.ts +97 -0
- package/src/plugins/metas.ts +224 -0
- package/src/plugins/presentForm/Preview.vue +4 -15
- package/src/plugins/presentForm/View.vue +35 -78
- package/src/plugins/presentForm/definition.ts +7 -6
- package/src/plugins/presentForm/index.ts +12 -5
- package/src/plugins/presentForm/meta.ts +11 -0
- package/src/plugins/presentForm/plugin.ts +8 -9
- package/src/plugins/presentForm/types.ts +0 -24
- package/src/plugins/presentHtml/Preview.vue +1 -8
- package/src/plugins/presentHtml/View.vue +401 -30
- package/src/plugins/presentHtml/definition.ts +8 -5
- package/src/plugins/presentHtml/index.ts +15 -8
- package/src/plugins/presentHtml/meta.ts +14 -0
- package/src/plugins/presentMulmoScript/View.vue +327 -107
- package/src/plugins/presentMulmoScript/definition.ts +34 -7
- package/src/plugins/presentMulmoScript/helpers.ts +4 -5
- package/src/plugins/presentMulmoScript/index.ts +20 -7
- package/src/plugins/presentMulmoScript/meta.ts +52 -0
- package/src/plugins/scheduler/AutomationsPreview.vue +2 -8
- package/src/plugins/scheduler/Preview.vue +5 -2
- package/src/plugins/scheduler/TasksTab.vue +16 -36
- package/src/plugins/scheduler/View.vue +22 -54
- package/src/plugins/scheduler/automationsDefinition.ts +14 -9
- package/src/plugins/scheduler/automationsMeta.ts +5 -0
- package/src/plugins/scheduler/calendarDefinition.ts +4 -7
- package/src/plugins/scheduler/calendarMeta.ts +28 -0
- package/src/plugins/scheduler/formatSchedule.ts +6 -24
- package/src/plugins/scheduler/index.ts +26 -52
- package/src/plugins/scope.ts +57 -0
- package/src/plugins/server-bindings-types.ts +38 -0
- package/src/plugins/server.ts +32 -0
- package/src/plugins/skill/Preview.vue +25 -0
- package/src/plugins/skill/View.vue +125 -0
- package/src/plugins/skill/definition.ts +23 -0
- package/src/plugins/skill/index.ts +36 -0
- package/src/plugins/skill/plugin.ts +31 -0
- package/src/plugins/skill/types.ts +21 -0
- package/src/plugins/spreadsheet/Preview.vue +1 -3
- package/src/plugins/spreadsheet/View.vue +29 -49
- package/src/plugins/spreadsheet/cellHighlights.ts +2 -3
- package/src/plugins/spreadsheet/definition.ts +5 -2
- package/src/plugins/spreadsheet/index.ts +15 -8
- package/src/plugins/spreadsheet/keyboardNav.ts +38 -0
- package/src/plugins/spreadsheet/meta.ts +14 -0
- package/src/plugins/textResponse/Preview.vue +9 -1
- package/src/plugins/textResponse/View.vue +59 -8
- package/src/plugins/textResponse/index.ts +11 -3
- package/src/plugins/textResponse/plugin.ts +8 -10
- package/src/plugins/textResponse/types.ts +28 -0
- package/src/plugins/wiki/Preview.vue +6 -4
- package/src/plugins/wiki/View.vue +463 -254
- package/src/plugins/wiki/components/WikiPageBody.vue +159 -0
- package/src/plugins/wiki/helpers.ts +17 -0
- package/src/plugins/wiki/history/HistoryDetail.vue +325 -0
- package/src/plugins/wiki/history/HistoryTab.vue +167 -0
- package/src/plugins/wiki/history/RestoreConfirm.vue +63 -0
- package/src/plugins/wiki/history/api.ts +52 -0
- package/src/plugins/wiki/history/diff.ts +145 -0
- package/src/plugins/wiki/index.ts +42 -32
- package/src/plugins/wiki/meta.ts +10 -0
- package/src/plugins/wiki/pageEditLoader.ts +53 -0
- package/src/plugins/wiki/route.ts +8 -0
- package/src/router/guards.ts +2 -1
- package/src/router/index.ts +19 -0
- package/src/router/pageRoutes.ts +1 -0
- package/src/tools/index.ts +50 -51
- package/src/tools/runtimeLoader.ts +141 -0
- package/src/tools/types.ts +44 -1
- package/src/types/notification.ts +23 -0
- package/src/types/pastedFile.ts +10 -0
- package/src/types/session.ts +61 -3
- package/src/types/sse.ts +21 -6
- package/src/utils/agent/eventDispatch.ts +12 -9
- package/src/utils/agent/pastedAttachment.ts +35 -0
- package/src/utils/agent/request.ts +32 -3
- package/src/utils/agent/toolCalls.ts +7 -1
- package/src/utils/api.ts +1 -1
- package/src/utils/chat/exportMarkdown.ts +243 -0
- package/src/utils/errors.ts +10 -2
- package/src/utils/files/expandedDirs.ts +1 -1
- package/src/utils/filesPreview/todoPreview.ts +13 -2
- package/src/utils/format/date.ts +1 -3
- package/src/utils/format/jsonSyntax.ts +5 -0
- package/src/utils/html/iframeHeightReporterScript.ts +62 -0
- package/src/utils/html/previewCsp.ts +29 -2
- package/src/utils/image/htmlSrcAttrs.ts +122 -0
- package/src/utils/image/imageRepairInlineScript.ts +115 -0
- package/src/utils/image/resolve.ts +17 -3
- package/src/utils/image/rewriteMarkdownImageRefs.ts +62 -9
- package/src/utils/markdown/frontmatter.ts +125 -0
- package/src/utils/markdown/taskList.ts +7 -2
- package/src/utils/plugin/runtime.ts +132 -0
- package/src/utils/session/mergeSessions.ts +40 -37
- package/src/utils/session/sessionEntries.ts +74 -18
- package/src/utils/session/sessionHelpers.ts +54 -10
- package/src/utils/tools/result.ts +76 -14
- package/src/vite-env.d.ts +6 -0
- package/client/assets/html2canvas-Cx501zZr-Bug0qRNv.js +0 -5
- package/client/assets/index-CY-WpQUm.css +0 -2
- package/client/assets/index-DbTz2Mfs.js +0 -4911
- package/client/assets/material-symbols-outlined-NzYEeyps.woff2 +0 -0
- package/server/api/routes/html.ts +0 -114
- package/server/api/routes/todos.ts +0 -293
- package/server/api/routes/todosColumnsHandlers.ts +0 -333
- package/server/api/routes/todosHandlers.ts +0 -274
- package/server/api/routes/todosItemsHandlers.ts +0 -386
- package/server/utils/files/todos-io.ts +0 -29
- package/src/components/NotificationToast.vue +0 -75
- package/src/plugins/editImage/definition.ts +0 -27
- package/src/plugins/editImage/index.ts +0 -37
- package/src/plugins/presentHtml/helpers.ts +0 -72
- package/src/plugins/scheduler/LegacySchedulerView.vue +0 -32
- package/src/plugins/scheduler/legacyShape.ts +0 -34
- package/src/plugins/todo/Preview.vue +0 -68
- package/src/plugins/todo/View.vue +0 -378
- package/src/plugins/todo/composables/useTodos.ts +0 -179
- package/src/plugins/todo/definition.ts +0 -45
- package/src/plugins/todo/index.ts +0 -62
- package/src/plugins/todo/labels.ts +0 -163
- package/src/plugins/todo/priority.ts +0 -98
- package/src/plugins/todo/viewModes.ts +0 -19
- package/src/plugins/wiki/definition.ts +0 -25
- package/src/tools/legacyPluginNames.ts +0 -13
- package/src/utils/format/frontmatter.ts +0 -80
- package/src/utils/image/rewriteHtmlImageRefs.ts +0 -50
- package/src/utils/notification/dispatch.ts +0 -58
- /package/client/assets/{purify.es-Fx1Nqyry-BwJECkqS.js → purify.es-Fx1Nqyry-BSVNht6S.js} +0 -0
- /package/src/plugins/{editImage → editImages}/Preview.vue +0 -0
- /package/src/plugins/{editImage → editImages}/View.vue +0 -0
- /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
|
-
<!--
|
|
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
|
-
<!--
|
|
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 {
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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: () =>
|
|
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
|
|
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
|
|
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
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
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[] } }>(
|
|
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 "
|
|
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:
|
|
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'. " +
|
|
@@ -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 "
|
|
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:
|
|
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
|
-
//
|
|
2
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
2
|
-
//
|
|
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 {
|
|
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 {
|
|
20
|
-
import {
|
|
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
|
-
//
|
|
35
|
-
|
|
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
|
|
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(
|
|
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(
|
|
60
|
+
execute: makeExecute(MANAGE_AUTOMATIONS),
|
|
67
61
|
isEnabled: () => true,
|
|
68
62
|
generatingMessage: "Managing automations...",
|
|
69
|
-
viewComponent: AutomationsView,
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
|
|
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
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
+
}
|