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
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useI18n } from "vue-i18n";
|
|
3
|
+
import { formatSmartTime } from "../../../utils/format/date";
|
|
4
|
+
import type { SnapshotSummary } from "./api";
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
snapshot: SnapshotSummary;
|
|
8
|
+
/** True while the parent's POST is in flight; disables both
|
|
9
|
+
* buttons and surfaces a spinner on the action button. */
|
|
10
|
+
restoring: boolean;
|
|
11
|
+
}>();
|
|
12
|
+
|
|
13
|
+
const emit = defineEmits<{
|
|
14
|
+
cancel: [];
|
|
15
|
+
confirm: [];
|
|
16
|
+
}>();
|
|
17
|
+
|
|
18
|
+
const { t } = useI18n();
|
|
19
|
+
|
|
20
|
+
function editorLabel(editor: SnapshotSummary["editor"]): string {
|
|
21
|
+
if (editor === "llm") return t("pluginWiki.history.editorBadgeLLM");
|
|
22
|
+
if (editor === "system") return t("pluginWiki.history.editorBadgeSystem");
|
|
23
|
+
return t("pluginWiki.history.editorBadgeUser");
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<div
|
|
29
|
+
class="fixed inset-0 z-40 flex items-center justify-center bg-black/40"
|
|
30
|
+
data-testid="wiki-history-restore-confirm"
|
|
31
|
+
@click.self="!restoring && emit('cancel')"
|
|
32
|
+
>
|
|
33
|
+
<div class="bg-white rounded-lg shadow-xl max-w-md w-full mx-4 p-5">
|
|
34
|
+
<h3 class="text-lg font-semibold text-gray-800 mb-3">
|
|
35
|
+
{{ t("pluginWiki.history.restoreConfirmTitle") }}
|
|
36
|
+
</h3>
|
|
37
|
+
<p class="text-sm text-gray-700 leading-relaxed">
|
|
38
|
+
{{ t("pluginWiki.history.restoreConfirmBody", { ts: formatSmartTime(props.snapshot.ts), editor: editorLabel(props.snapshot.editor) }) }}
|
|
39
|
+
</p>
|
|
40
|
+
<div class="mt-5 flex items-center justify-end gap-2">
|
|
41
|
+
<button
|
|
42
|
+
type="button"
|
|
43
|
+
class="h-8 px-3 rounded text-sm text-gray-700 hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
44
|
+
:disabled="restoring"
|
|
45
|
+
data-testid="wiki-history-restore-cancel"
|
|
46
|
+
@click="emit('cancel')"
|
|
47
|
+
>
|
|
48
|
+
{{ t("pluginWiki.history.restoreConfirmCancel") }}
|
|
49
|
+
</button>
|
|
50
|
+
<button
|
|
51
|
+
type="button"
|
|
52
|
+
class="h-8 px-3 rounded text-sm bg-blue-600 hover:bg-blue-700 text-white disabled:opacity-60 disabled:cursor-not-allowed flex items-center gap-1 transition-colors"
|
|
53
|
+
:disabled="restoring"
|
|
54
|
+
data-testid="wiki-history-restore-confirm-action"
|
|
55
|
+
@click="emit('confirm')"
|
|
56
|
+
>
|
|
57
|
+
<span v-if="restoring" class="material-icons text-base animate-spin">progress_activity</span>
|
|
58
|
+
{{ t("pluginWiki.history.restoreConfirmAction") }}
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</template>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { apiGet, apiPost, type ApiResult } from "../../../utils/api.js";
|
|
2
|
+
import { pluginEndpoints } from "../../api.js";
|
|
3
|
+
import type { WikiEndpoints } from "../index.js";
|
|
4
|
+
|
|
5
|
+
export interface SnapshotSummary {
|
|
6
|
+
stamp: string;
|
|
7
|
+
bytes: number;
|
|
8
|
+
ts: string;
|
|
9
|
+
editor: "user" | "llm" | "system";
|
|
10
|
+
sessionId?: string;
|
|
11
|
+
reason?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface SnapshotContent extends SnapshotSummary {
|
|
15
|
+
meta: Record<string, unknown>;
|
|
16
|
+
body: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ListResponse {
|
|
20
|
+
slug: string;
|
|
21
|
+
snapshots: SnapshotSummary[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface ReadResponse {
|
|
25
|
+
slug: string;
|
|
26
|
+
snapshot: SnapshotContent;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface RestoreResponse {
|
|
30
|
+
slug: string;
|
|
31
|
+
restored: { fromStamp: string };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function fillRoute(template: string, params: Record<string, string>): string {
|
|
35
|
+
return template.replace(/:([a-zA-Z]+)/g, (_, key: string) => encodeURIComponent(params[key]));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function endpoints(): WikiEndpoints {
|
|
39
|
+
return pluginEndpoints<WikiEndpoints>("wiki");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function fetchHistoryList(slug: string): Promise<ApiResult<ListResponse>> {
|
|
43
|
+
return apiGet<ListResponse>(fillRoute(endpoints().pageHistory, { slug }));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function fetchHistorySnapshot(slug: string, stamp: string): Promise<ApiResult<ReadResponse>> {
|
|
47
|
+
return apiGet<ReadResponse>(fillRoute(endpoints().pageHistorySnapshot, { slug, stamp }));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function restoreHistorySnapshot(slug: string, stamp: string): Promise<ApiResult<RestoreResponse>> {
|
|
51
|
+
return apiPost<RestoreResponse>(fillRoute(endpoints().pageHistoryRestore, { slug, stamp }));
|
|
52
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { diffLines } from "diff";
|
|
2
|
+
|
|
3
|
+
// Keys that `writeWikiPage` auto-stamps on every save. Diffing
|
|
4
|
+
// these would surface a change on every snapshot even when the
|
|
5
|
+
// user touched nothing meaningful (Q5 in the PR 3 plan).
|
|
6
|
+
const AUTO_STAMP_KEYS = ["updated", "editor"] as const;
|
|
7
|
+
|
|
8
|
+
export const DIFF_LINE_KIND = {
|
|
9
|
+
context: "context",
|
|
10
|
+
add: "add",
|
|
11
|
+
del: "del",
|
|
12
|
+
} as const;
|
|
13
|
+
export type DiffLineKind = (typeof DIFF_LINE_KIND)[keyof typeof DIFF_LINE_KIND];
|
|
14
|
+
|
|
15
|
+
export interface DiffLine {
|
|
16
|
+
kind: DiffLineKind;
|
|
17
|
+
text: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A contiguous viewport into the diff. Between hunks there are
|
|
21
|
+
* unchanged lines that have been collapsed to keep the view
|
|
22
|
+
* readable; the renderer surfaces those gaps via `hiddenBefore`
|
|
23
|
+
* and (on the last hunk only) `hiddenAfter`. */
|
|
24
|
+
export interface DiffHunk {
|
|
25
|
+
lines: DiffLine[];
|
|
26
|
+
/** Unchanged lines collapsed before this hunk (i.e. between the
|
|
27
|
+
* previous hunk's end and this hunk's start, or between BOF and
|
|
28
|
+
* the first hunk). 0 when nothing is hidden. */
|
|
29
|
+
hiddenBefore: number;
|
|
30
|
+
/** Unchanged lines collapsed after this hunk and before EOF.
|
|
31
|
+
* Always 0 except on the last hunk. */
|
|
32
|
+
hiddenAfter: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Compute a line-level unified diff with ±N context.
|
|
36
|
+
*
|
|
37
|
+
* Returns an empty array when `left === right` — there are no
|
|
38
|
+
* changes to surface. Otherwise builds hunks: each one is a
|
|
39
|
+
* contiguous run that contains at least one add/del line plus up
|
|
40
|
+
* to `contextLines` unchanged lines on each side. When two
|
|
41
|
+
* changes are within `2 * contextLines` of each other their
|
|
42
|
+
* context windows overlap and the hunks merge. */
|
|
43
|
+
export function renderUnifiedDiff(left: string, right: string, contextLines = 3): DiffHunk[] {
|
|
44
|
+
if (left === right) return [];
|
|
45
|
+
|
|
46
|
+
const changes = diffLines(left, right);
|
|
47
|
+
const lines: DiffLine[] = [];
|
|
48
|
+
for (const change of changes) {
|
|
49
|
+
const kind: DiffLineKind = change.added ? DIFF_LINE_KIND.add : change.removed ? DIFF_LINE_KIND.del : DIFF_LINE_KIND.context;
|
|
50
|
+
for (const text of splitLines(change.value)) {
|
|
51
|
+
lines.push({ kind, text });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const changedIndices: number[] = [];
|
|
56
|
+
lines.forEach((line, idx) => {
|
|
57
|
+
if (line.kind !== DIFF_LINE_KIND.context) changedIndices.push(idx);
|
|
58
|
+
});
|
|
59
|
+
if (changedIndices.length === 0) return [];
|
|
60
|
+
|
|
61
|
+
const ranges = mergeWithContext(changedIndices, contextLines, lines.length);
|
|
62
|
+
|
|
63
|
+
return ranges.map((range, idx) => {
|
|
64
|
+
const hunkLines = lines.slice(range.start, range.end + 1);
|
|
65
|
+
const prevEnd = idx === 0 ? -1 : ranges[idx - 1].end;
|
|
66
|
+
const hiddenBefore = range.start - prevEnd - 1;
|
|
67
|
+
const hiddenAfter = idx === ranges.length - 1 ? lines.length - 1 - range.end : 0;
|
|
68
|
+
return { lines: hunkLines, hiddenBefore, hiddenAfter };
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface Range {
|
|
73
|
+
start: number;
|
|
74
|
+
end: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function mergeWithContext(changedIndices: number[], contextLines: number, totalLines: number): Range[] {
|
|
78
|
+
const out: Range[] = [];
|
|
79
|
+
for (const idx of changedIndices) {
|
|
80
|
+
const start = Math.max(0, idx - contextLines);
|
|
81
|
+
const end = Math.min(totalLines - 1, idx + contextLines);
|
|
82
|
+
const last = out[out.length - 1];
|
|
83
|
+
// Two ranges merge when their context windows are adjacent or
|
|
84
|
+
// overlap — the gap-of-zero case (last.end + 1 === start) is a
|
|
85
|
+
// legitimate merge because there are no hidden lines between.
|
|
86
|
+
if (last && last.end + 1 >= start) {
|
|
87
|
+
last.end = Math.max(last.end, end);
|
|
88
|
+
} else {
|
|
89
|
+
out.push({ start, end });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function splitLines(text: string): string[] {
|
|
96
|
+
if (text === "") return [];
|
|
97
|
+
const parts = text.split("\n");
|
|
98
|
+
// A block that ended with `\n` produces an empty trailing element
|
|
99
|
+
// from `split` — drop it. A block that did NOT end with `\n` (rare
|
|
100
|
+
// with diffLines, but possible at EOF) keeps its content.
|
|
101
|
+
if (parts.length > 0 && parts[parts.length - 1] === "") parts.pop();
|
|
102
|
+
return parts;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Strip the keys that `writeWikiPage` auto-stamps on every save
|
|
106
|
+
* so the diff focuses on user-meaningful frontmatter only (Q5). */
|
|
107
|
+
export function stripAutoStampKeys(meta: Record<string, unknown>): Record<string, unknown> {
|
|
108
|
+
const out: Record<string, unknown> = {};
|
|
109
|
+
for (const [key, value] of Object.entries(meta)) {
|
|
110
|
+
if ((AUTO_STAMP_KEYS as readonly string[]).includes(key)) continue;
|
|
111
|
+
out[key] = value;
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Re-serialise `frontmatter + body` for diffing. The result is a
|
|
117
|
+
* plain string — the diff library doesn't care about YAML; it
|
|
118
|
+
* just needs two strings to compare. We sort frontmatter keys so
|
|
119
|
+
* semantic equality (same keys, possibly reordered) doesn't show
|
|
120
|
+
* up as a diff. */
|
|
121
|
+
export function joinFrontmatterAndBody(meta: Record<string, unknown>, body: string): string {
|
|
122
|
+
const sortedKeys = Object.keys(meta).sort();
|
|
123
|
+
if (sortedKeys.length === 0) return body;
|
|
124
|
+
const frontmatterLines = ["---"];
|
|
125
|
+
for (const key of sortedKeys) {
|
|
126
|
+
frontmatterLines.push(`${key}: ${formatYamlValue(meta[key])}`);
|
|
127
|
+
}
|
|
128
|
+
frontmatterLines.push("---");
|
|
129
|
+
frontmatterLines.push("");
|
|
130
|
+
return `${frontmatterLines.join("\n")}\n${body}`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function formatYamlValue(value: unknown): string {
|
|
134
|
+
if (value === null || value === undefined) return "";
|
|
135
|
+
if (Array.isArray(value)) return `[${value.map((item) => formatYamlValue(item)).join(", ")}]`;
|
|
136
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
137
|
+
if (typeof value === "string") {
|
|
138
|
+
// Quote when needed — leading / trailing whitespace, special
|
|
139
|
+
// YAML chars, or embedded colon-space (which YAML reads as a
|
|
140
|
+
// mapping). Plain alphanumerics + hyphens stay unquoted.
|
|
141
|
+
if (/^[A-Za-z0-9_\-./]+$/.test(value)) return value;
|
|
142
|
+
return JSON.stringify(value);
|
|
143
|
+
}
|
|
144
|
+
return String(value);
|
|
145
|
+
}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
1
|
+
import type { PluginEntry, PluginRegistration } from "../../tools/types";
|
|
2
|
+
import { wrapWithScope } from "../scope";
|
|
3
3
|
import View from "./View.vue";
|
|
4
4
|
import Preview from "./Preview.vue";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
|
|
6
|
+
const TOOL_NAME = "manageWiki";
|
|
7
|
+
|
|
8
|
+
export interface WikiEndpoints {
|
|
9
|
+
[key: string]: string;
|
|
10
|
+
base: string;
|
|
11
|
+
pageHistory: string;
|
|
12
|
+
pageHistorySnapshot: string;
|
|
13
|
+
pageHistoryRestore: string;
|
|
14
|
+
internalSnapshot: string;
|
|
15
|
+
}
|
|
9
16
|
|
|
10
17
|
export interface WikiPageEntry {
|
|
11
18
|
title: string;
|
|
@@ -21,35 +28,38 @@ export interface WikiData {
|
|
|
21
28
|
pageEntries?: WikiPageEntry[];
|
|
22
29
|
pageName?: string;
|
|
23
30
|
pageExists?: boolean;
|
|
31
|
+
// ── `page-edit` action (Stage 3a, #963) ──────────────────────
|
|
32
|
+
// Server emits these when an LLM Write/Edit hits a wiki page.
|
|
33
|
+
// The View fetches the snapshot body via /api/wiki/pages/<slug>/
|
|
34
|
+
// history/<stamp> and renders it inline, falling back to
|
|
35
|
+
// pagePath if the snapshot has been gc'd.
|
|
36
|
+
slug?: string;
|
|
37
|
+
stamp?: string;
|
|
38
|
+
pagePath?: string;
|
|
24
39
|
}
|
|
25
40
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
return {
|
|
43
|
-
...result.data,
|
|
44
|
-
toolName: "manageWiki",
|
|
45
|
-
uuid: result.data.uuid ?? makeUuid(),
|
|
46
|
-
};
|
|
41
|
+
// View-only registry entry (Stage 3b, #963). The plugin no longer
|
|
42
|
+
// exposes an MCP tool to the LLM, but the canvas dispatch
|
|
43
|
+
// (`getPlugin("manageWiki")`) still finds it so:
|
|
44
|
+
// (a) the server-emitted `page-edit` action toolResult renders
|
|
45
|
+
// via the same `View.vue` branches the live page action used,
|
|
46
|
+
// (b) historical chat sessions saved with `toolName: "manageWiki"`
|
|
47
|
+
// continue to replay correctly.
|
|
48
|
+
const wikiPlugin: PluginEntry = {
|
|
49
|
+
toolDefinition: {
|
|
50
|
+
type: "function",
|
|
51
|
+
name: TOOL_NAME,
|
|
52
|
+
prompt: "[deprecated] Replaced by inline page-edit rendering (#963). Kept registered for historical chat-history rendering only.",
|
|
53
|
+
description: "[deprecated] Replaced by inline page-edit rendering (#963). Kept registered for historical chat-history rendering only.",
|
|
54
|
+
parameters: { type: "object", properties: {}, required: [] },
|
|
47
55
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
generatingMessage: "Loading wiki...",
|
|
51
|
-
viewComponent: View,
|
|
52
|
-
previewComponent: Preview,
|
|
56
|
+
viewComponent: wrapWithScope("wiki", View),
|
|
57
|
+
previewComponent: wrapWithScope("wiki", Preview),
|
|
53
58
|
};
|
|
54
59
|
|
|
55
60
|
export default wikiPlugin;
|
|
61
|
+
|
|
62
|
+
export const REGISTRATION: PluginRegistration = {
|
|
63
|
+
toolName: TOOL_NAME,
|
|
64
|
+
entry: wikiPlugin,
|
|
65
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { definePluginMeta } from "../meta-types";
|
|
2
|
+
|
|
3
|
+
// View-only registry entry (Stage 3b, #963). The MCP tool was removed
|
|
4
|
+
// from the LLM but the plugin entry stays so server-emitted
|
|
5
|
+
// `page-edit` toolResults render in chat. No `apiRoutes` here — the
|
|
6
|
+
// /api/wiki host routes (history, snapshots) stay HOST-owned because
|
|
7
|
+
// they're consumed by both the wiki UI and the wiki-write hook.
|
|
8
|
+
export const META = definePluginMeta({
|
|
9
|
+
toolName: "manageWiki",
|
|
10
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Loader for the `page-edit` wiki action (Stage 3a, #963). Returns
|
|
2
|
+
// the full markdown content (frontmatter + body) for an LLM-edit
|
|
3
|
+
// inline preview. Tries the snapshot file first; falls back to the
|
|
4
|
+
// live page if the snapshot has been gc'd; reports `deleted` when
|
|
5
|
+
// neither survives.
|
|
6
|
+
|
|
7
|
+
import { apiGet } from "../../utils/api";
|
|
8
|
+
import { pluginEndpoints } from "../api";
|
|
9
|
+
import type { WikiEndpoints } from "./index";
|
|
10
|
+
import { serializeWithFrontmatter } from "../../utils/markdown/frontmatter";
|
|
11
|
+
|
|
12
|
+
export type PageEditLoadResult = { kind: "snapshot"; content: string; ts: string } | { kind: "current"; content: string } | { kind: "deleted" };
|
|
13
|
+
|
|
14
|
+
interface SnapshotResponse {
|
|
15
|
+
snapshot: {
|
|
16
|
+
body: string;
|
|
17
|
+
meta: Record<string, unknown>;
|
|
18
|
+
ts: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface CurrentPageResponse {
|
|
23
|
+
data: {
|
|
24
|
+
content?: string;
|
|
25
|
+
pageExists?: boolean;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Fetch the snapshot at `(slug, stamp)`; on 404 fall through to
|
|
30
|
+
* the live page (`pagePath` lives at `data/wiki/pages/<slug>.md`
|
|
31
|
+
* by convention, but the slug already encodes that — pagePath is
|
|
32
|
+
* carried along as audit metadata). */
|
|
33
|
+
export async function loadPageEdit(slug: string, stamp: string): Promise<PageEditLoadResult> {
|
|
34
|
+
const wikiEndpoints = pluginEndpoints<WikiEndpoints>("wiki");
|
|
35
|
+
const snap = await apiGet<SnapshotResponse>(`${wikiEndpoints.base}/pages/${encodeURIComponent(slug)}/history/${encodeURIComponent(stamp)}`);
|
|
36
|
+
if (snap.ok) {
|
|
37
|
+
const { body, meta, ts } = snap.data.snapshot;
|
|
38
|
+
return { kind: "snapshot", content: serializeWithFrontmatter(meta, body), ts };
|
|
39
|
+
}
|
|
40
|
+
if (snap.status !== 404) {
|
|
41
|
+
// Network / 5xx: surface as deleted-equivalent for now. The
|
|
42
|
+
// banner stays neutral ("page deleted") rather than leaking
|
|
43
|
+
// transient errors into the UI; refresh recovers when the
|
|
44
|
+
// server is healthy again.
|
|
45
|
+
return { kind: "deleted" };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const current = await apiGet<CurrentPageResponse>(`${wikiEndpoints.base}?slug=${encodeURIComponent(slug)}`);
|
|
49
|
+
if (current.ok && current.data.data.pageExists && typeof current.data.data.content === "string") {
|
|
50
|
+
return { kind: "current", content: current.data.data.content };
|
|
51
|
+
}
|
|
52
|
+
return { kind: "deleted" };
|
|
53
|
+
}
|
|
@@ -101,6 +101,10 @@ export function buildWikiRouteParams(target: WikiTarget): Record<string, string>
|
|
|
101
101
|
return { section: WIKI_ROUTE_SECTION.log, slug: "" };
|
|
102
102
|
case "lint_report":
|
|
103
103
|
return { section: WIKI_ROUTE_SECTION.lintReport, slug: "" };
|
|
104
|
+
default: {
|
|
105
|
+
const exhaustive: never = target;
|
|
106
|
+
throw new Error(`unreachable WikiTarget kind: ${JSON.stringify(exhaustive)}`);
|
|
107
|
+
}
|
|
104
108
|
}
|
|
105
109
|
}
|
|
106
110
|
|
|
@@ -117,5 +121,9 @@ export function wikiActionFor(target: WikiTarget): WikiAction {
|
|
|
117
121
|
return WIKI_ACTION.log;
|
|
118
122
|
case "lint_report":
|
|
119
123
|
return WIKI_ACTION.lintReport;
|
|
124
|
+
default: {
|
|
125
|
+
const exhaustive: never = target;
|
|
126
|
+
throw new Error(`unreachable WikiTarget kind: ${JSON.stringify(exhaustive)}`);
|
|
127
|
+
}
|
|
120
128
|
}
|
|
121
129
|
}
|
package/src/router/guards.ts
CHANGED
|
@@ -27,7 +27,7 @@ function isValidSessionId(value: unknown): boolean {
|
|
|
27
27
|
export function installGuards(router: Router): void {
|
|
28
28
|
router.beforeEach((dest) => {
|
|
29
29
|
if (dest.name === "chat") {
|
|
30
|
-
const sessionId = dest.params
|
|
30
|
+
const { sessionId } = dest.params;
|
|
31
31
|
if (isNonEmptyString(sessionId) && !isValidSessionId(sessionId)) {
|
|
32
32
|
return { name: "chat", params: {}, query: {}, replace: true };
|
|
33
33
|
}
|
|
@@ -76,5 +76,6 @@ export function installGuards(router: Router): void {
|
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
+
return undefined;
|
|
79
80
|
});
|
|
80
81
|
}
|
package/src/router/index.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { defineComponent, h } from "vue";
|
|
16
16
|
import { createRouter, createWebHistory, type RouteRecordRaw } from "vue-router";
|
|
17
17
|
import { PAGE_ROUTES, type PageRouteName } from "./pageRoutes";
|
|
18
|
+
import { HOST_EVENTS } from "../config/hostEvents";
|
|
18
19
|
|
|
19
20
|
// Re-export the constants so existing `import { PAGE_ROUTES } from
|
|
20
21
|
// "./router"` call sites keep working. The actual definitions live
|
|
@@ -66,6 +67,10 @@ const routes: RouteRecordRaw[] = [
|
|
|
66
67
|
// News viewer (#761). Optional `?source=<slug>` query for the
|
|
67
68
|
// Sources-page deep link.
|
|
68
69
|
{ path: "/news", name: PAGE_ROUTES.news, component: Stub },
|
|
70
|
+
// Debug page (#feat-encore PR 1 follow-up). Standalone playground for
|
|
71
|
+
// experimental plugin features (notifier engine, etc.). Rendered by
|
|
72
|
+
// the @mulmoclaude/debug-plugin runtime plugin.
|
|
73
|
+
{ path: "/debug", name: PAGE_ROUTES.debug, component: Stub },
|
|
69
74
|
{ path: "/:pathMatch(.*)*", redirect: "/chat" },
|
|
70
75
|
];
|
|
71
76
|
|
|
@@ -74,4 +79,18 @@ const router = createRouter({
|
|
|
74
79
|
routes,
|
|
75
80
|
});
|
|
76
81
|
|
|
82
|
+
// Bridge SPA navigation to a DOM CustomEvent so runtime-loaded plugins
|
|
83
|
+
// (which can't import vue-router without extra plumbing) can react to
|
|
84
|
+
// route changes without polling. Fires on every commit, including
|
|
85
|
+
// query-only changes that don't remount the matched component.
|
|
86
|
+
//
|
|
87
|
+
// Subscriber: `@mulmoclaude/debug-plugin` View, which uses it to
|
|
88
|
+
// re-evaluate `?mode=` and `?notificationId=` params after the host
|
|
89
|
+
// notifier popup pushes a new URL. The event name lives in
|
|
90
|
+
// `src/config/hostEvents.ts` so the contract isn't a magic string
|
|
91
|
+
// duplicated between host and plugin.
|
|
92
|
+
router.afterEach((toRoute) => {
|
|
93
|
+
window.dispatchEvent(new CustomEvent(HOST_EVENTS.routeChange, { detail: { fullPath: toRoute.fullPath } }));
|
|
94
|
+
});
|
|
95
|
+
|
|
77
96
|
export default router;
|
package/src/router/pageRoutes.ts
CHANGED
package/src/tools/index.ts
CHANGED
|
@@ -1,59 +1,58 @@
|
|
|
1
|
+
// Central tool registry. Two stages of lookup:
|
|
2
|
+
//
|
|
3
|
+
// 1. Build-time-bundled plugins (the "built-in" set) — assembled
|
|
4
|
+
// generically from `BUILT_IN_PLUGINS` exported by
|
|
5
|
+
// `src/plugins/index.ts`. Each plugin self-registers via a
|
|
6
|
+
// `REGISTRATION` export co-locating `TOOL_NAMES.x` with its
|
|
7
|
+
// `PluginEntry`. Adding a new built-in plugin does NOT touch
|
|
8
|
+
// this file.
|
|
9
|
+
//
|
|
10
|
+
// 2. Runtime-installed plugins (#1043 C-2) — loaded from the
|
|
11
|
+
// workspace ledger at boot via `runtimeLoader`. Looked up
|
|
12
|
+
// after the built-in set so a static plugin always wins on
|
|
13
|
+
// collision (mirrors the server-side collision policy in
|
|
14
|
+
// `server/plugins/runtime-registry.ts`).
|
|
15
|
+
|
|
1
16
|
import type { PluginEntry } from "./types";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import markdownPlugin from "../plugins/markdown/index";
|
|
5
|
-
import spreadsheetPlugin from "../plugins/spreadsheet/index";
|
|
6
|
-
import MindMapPlugin from "@gui-chat-plugin/mindmap/vue";
|
|
7
|
-
import generateImagePlugin from "../plugins/generateImage/index";
|
|
8
|
-
import QuizPlugin from "@mulmochat-plugin/quiz/vue";
|
|
9
|
-
import presentFormPlugin from "../plugins/presentForm/index";
|
|
10
|
-
import canvasPlugin from "../plugins/canvas/index";
|
|
11
|
-
import editImagePlugin from "../plugins/editImage/index";
|
|
12
|
-
import Present3DPlugin from "@gui-chat-plugin/present3d/vue";
|
|
13
|
-
import WeatherPlugin from "@gui-chat-plugin/weather/vue";
|
|
14
|
-
import todoPlugin from "../plugins/todo/index";
|
|
15
|
-
import { manageCalendarPlugin, manageAutomationsPlugin, legacyManageSchedulerEntry } from "../plugins/scheduler/index";
|
|
16
|
-
import manageRolesPlugin from "../plugins/manageRoles/index";
|
|
17
|
-
import manageSkillsPlugin from "../plugins/manageSkills/index";
|
|
18
|
-
import manageSourcePlugin from "../plugins/manageSource/index";
|
|
19
|
-
import wikiPlugin from "../plugins/wiki/index";
|
|
20
|
-
import presentMulmoScriptPlugin from "../plugins/presentMulmoScript/index";
|
|
21
|
-
import presentHtmlPlugin from "../plugins/presentHtml/index";
|
|
22
|
-
import presentChartPlugin from "../plugins/chart/index";
|
|
17
|
+
import { getRuntimePluginEntry, getRuntimeToolNames } from "./runtimeLoader";
|
|
18
|
+
import { BUILT_IN_PLUGINS } from "../plugins";
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
20
|
+
// Build the lookup with explicit duplicate detection. `BUILT_IN_PLUGINS`
|
|
21
|
+
// is the union of generated registrations (one per built-in META) and
|
|
22
|
+
// `EXTERNAL_PLUGIN_REGISTRATIONS` (still-unmigrated plugins). The
|
|
23
|
+
// META aggregator already screens its half for collisions, but a
|
|
24
|
+
// duplicate `toolName` between an external registration and a META
|
|
25
|
+
// would slip past `Object.fromEntries` silently with last-writer-wins.
|
|
26
|
+
// Throwing at boot is the right move — silent dispatch hijack is
|
|
27
|
+
// strictly worse than a hard error during start-up (CR review #1125).
|
|
28
|
+
//
|
|
29
|
+
// Use a null-prototype dictionary so:
|
|
30
|
+
// 1. The `in` / `hasOwn` check doesn't walk a prototype chain — a
|
|
31
|
+
// legitimate `toolName` like `"toString"` or `"hasOwnProperty"`
|
|
32
|
+
// can't false-positive as a duplicate.
|
|
33
|
+
// 2. The bracket assign at the end can't trigger `__proto__`
|
|
34
|
+
// prototype-mutation semantics if a future registration value
|
|
35
|
+
// ever flows from less-trusted code.
|
|
36
|
+
// Codex review on PR #1156.
|
|
37
|
+
const plugins: Record<string, PluginEntry> = (() => {
|
|
38
|
+
const out: Record<string, PluginEntry> = Object.create(null);
|
|
39
|
+
for (const registration of BUILT_IN_PLUGINS) {
|
|
40
|
+
if (Object.prototype.hasOwnProperty.call(out, registration.toolName)) {
|
|
41
|
+
throw new Error(`Duplicate built-in plugin registration for "${registration.toolName}"`);
|
|
42
|
+
}
|
|
43
|
+
out[registration.toolName] = registration.entry;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
})();
|
|
52
47
|
|
|
53
48
|
export function getPlugin(name: string): PluginEntry | null {
|
|
54
|
-
|
|
49
|
+
// Static (build-time) plugins win on collision — runtime plugins
|
|
50
|
+
// are registered in mcp-server.ts only when their tool name does
|
|
51
|
+
// not already exist in the static set, so this lookup order keeps
|
|
52
|
+
// the contracts symmetric across server and frontend.
|
|
53
|
+
return plugins[name] ?? getRuntimePluginEntry(name);
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
export function getAllPluginNames(): string[] {
|
|
58
|
-
return
|
|
57
|
+
return [...BUILT_IN_PLUGINS.map((registration) => registration.toolName), ...getRuntimeToolNames()];
|
|
59
58
|
}
|