mulmoclaude 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/bin/mulmoclaude.js +202 -0
- package/bin/prepare-dist.js +93 -0
- package/client/assets/chunk-vKJrgz-R-C_I3GbVV.js +1 -0
- package/client/assets/html2canvas-Cx501zZr-BF5dYYkY.js +5 -0
- package/client/assets/index-D8rhwXLq.js +4906 -0
- package/client/assets/index-KNLBjwuh.css +1 -0
- package/client/assets/index.es-D4YyL_Dg-BfRHLTZV.js +5 -0
- package/client/assets/material-icons-Dr0goTwe.woff +0 -0
- package/client/assets/material-icons-kAwBdRge.woff2 +0 -0
- package/client/assets/material-icons-outlined-BpWbwl2n.woff +0 -0
- package/client/assets/material-icons-outlined-DZhiGvEA.woff2 +0 -0
- package/client/assets/material-icons-round-BDlwx-sv.woff +0 -0
- package/client/assets/material-icons-round-DrirKXBx.woff2 +0 -0
- package/client/assets/material-icons-sharp-CH1KkVu7.woff +0 -0
- package/client/assets/material-icons-sharp-gidztirS.woff2 +0 -0
- package/client/assets/material-icons-two-tone-B7wz7mED.woff +0 -0
- package/client/assets/material-icons-two-tone-DuNIpaEj.woff2 +0 -0
- package/client/assets/mulmo_bw-ERmkSv0a.png +0 -0
- package/client/assets/purify.es-Fx1Nqyry-PeS5RUhs.js +2 -0
- package/client/assets/typeof-DBp4T-Ny-BC0P-2DM.js +1 -0
- package/client/index.html +28 -0
- package/package.json +66 -0
- package/server/agent/attachmentConverter.ts +270 -0
- package/server/agent/config.ts +414 -0
- package/server/agent/index.ts +260 -0
- package/server/agent/mcp-server.ts +412 -0
- package/server/agent/mcp-tools/index.ts +63 -0
- package/server/agent/mcp-tools/x.ts +188 -0
- package/server/agent/plugin-names.ts +75 -0
- package/server/agent/prompt.ts +349 -0
- package/server/agent/resumeFailover.ts +129 -0
- package/server/agent/sandboxMounts.ts +329 -0
- package/server/agent/stream.ts +194 -0
- package/server/api/auth/bearerAuth.ts +61 -0
- package/server/api/auth/token.ts +98 -0
- package/server/api/csrfGuard.ts +85 -0
- package/server/api/routes/agent.ts +478 -0
- package/server/api/routes/chart.ts +98 -0
- package/server/api/routes/chat-index.ts +46 -0
- package/server/api/routes/config.ts +258 -0
- package/server/api/routes/dispatchResponse.ts +79 -0
- package/server/api/routes/files.ts +812 -0
- package/server/api/routes/html.ts +101 -0
- package/server/api/routes/image.ts +169 -0
- package/server/api/routes/mulmo-script.ts +712 -0
- package/server/api/routes/mulmoScriptValidate.ts +101 -0
- package/server/api/routes/notifications.ts +69 -0
- package/server/api/routes/pdf.ts +163 -0
- package/server/api/routes/plugins.ts +276 -0
- package/server/api/routes/presentHtml.ts +48 -0
- package/server/api/routes/roles.ts +125 -0
- package/server/api/routes/scheduler.ts +153 -0
- package/server/api/routes/schedulerHandlers.ts +151 -0
- package/server/api/routes/schedulerTasks.ts +163 -0
- package/server/api/routes/sessions.ts +294 -0
- package/server/api/routes/sessionsCursor.ts +59 -0
- package/server/api/routes/skills.ts +195 -0
- package/server/api/routes/sources.ts +540 -0
- package/server/api/routes/todos.ts +263 -0
- package/server/api/routes/todosColumnsHandlers.ts +347 -0
- package/server/api/routes/todosHandlers.ts +274 -0
- package/server/api/routes/todosItemsHandlers.ts +386 -0
- package/server/api/routes/wiki/pageIndex.ts +53 -0
- package/server/api/routes/wiki.ts +363 -0
- package/server/api/sandboxStatus.ts +64 -0
- package/server/events/notifications.ts +160 -0
- package/server/events/pub-sub/index.ts +45 -0
- package/server/events/relay-client.ts +288 -0
- package/server/events/scheduler-adapter.ts +302 -0
- package/server/events/session-store/index.ts +492 -0
- package/server/events/task-manager/index.ts +181 -0
- package/server/index.ts +572 -0
- package/server/system/config.ts +243 -0
- package/server/system/credentials.ts +220 -0
- package/server/system/docker.ts +97 -0
- package/server/system/env.ts +109 -0
- package/server/system/logger/config.ts +112 -0
- package/server/system/logger/formatters.ts +40 -0
- package/server/system/logger/index.ts +53 -0
- package/server/system/logger/rotation.ts +37 -0
- package/server/system/logger/sinks.ts +101 -0
- package/server/system/logger/types.ts +29 -0
- package/server/utils/date.ts +57 -0
- package/server/utils/errors.ts +7 -0
- package/server/utils/fetch.ts +27 -0
- package/server/utils/files/atomic.ts +125 -0
- package/server/utils/files/html-io.ts +20 -0
- package/server/utils/files/image-store.ts +66 -0
- package/server/utils/files/index.ts +45 -0
- package/server/utils/files/journal-io.ts +213 -0
- package/server/utils/files/json.ts +69 -0
- package/server/utils/files/markdown-store.ts +33 -0
- package/server/utils/files/naming.ts +50 -0
- package/server/utils/files/reference-dirs-io.ts +45 -0
- package/server/utils/files/roles-io.ts +45 -0
- package/server/utils/files/safe.ts +106 -0
- package/server/utils/files/scheduler-io.ts +20 -0
- package/server/utils/files/scheduler-overrides-io.ts +64 -0
- package/server/utils/files/session-io.ts +136 -0
- package/server/utils/files/spreadsheet-store.ts +63 -0
- package/server/utils/files/todos-io.ts +29 -0
- package/server/utils/files/user-tasks-io.ts +25 -0
- package/server/utils/files/workspace-io.ts +221 -0
- package/server/utils/gemini.ts +59 -0
- package/server/utils/gitignore.ts +69 -0
- package/server/utils/http.ts +15 -0
- package/server/utils/httpError.ts +61 -0
- package/server/utils/id.ts +16 -0
- package/server/utils/json.ts +83 -0
- package/server/utils/logBackgroundError.ts +22 -0
- package/server/utils/markdown.ts +82 -0
- package/server/utils/request.ts +29 -0
- package/server/utils/slug.ts +50 -0
- package/server/utils/spawn.ts +62 -0
- package/server/utils/time.ts +34 -0
- package/server/utils/types.ts +47 -0
- package/server/workspace/chat-index/index.ts +153 -0
- package/server/workspace/chat-index/indexer.ts +209 -0
- package/server/workspace/chat-index/paths.ts +34 -0
- package/server/workspace/chat-index/summarizer.ts +247 -0
- package/server/workspace/chat-index/types.ts +38 -0
- package/server/workspace/custom-dirs.ts +220 -0
- package/server/workspace/helps/business.md +104 -0
- package/server/workspace/helps/github.md +23 -0
- package/server/workspace/helps/index.md +60 -0
- package/server/workspace/helps/mulmoscript.md +249 -0
- package/server/workspace/helps/sandbox.md +90 -0
- package/server/workspace/helps/spreadsheet.md +43 -0
- package/server/workspace/helps/telegram.md +135 -0
- package/server/workspace/helps/wiki.md +131 -0
- package/server/workspace/journal/archivist.ts +386 -0
- package/server/workspace/journal/dailyPass.ts +743 -0
- package/server/workspace/journal/diff.ts +71 -0
- package/server/workspace/journal/index.ts +185 -0
- package/server/workspace/journal/indexFile.ts +136 -0
- package/server/workspace/journal/linkRewrite.ts +4 -0
- package/server/workspace/journal/memoryExtractor.ts +130 -0
- package/server/workspace/journal/optimizationPass.ts +160 -0
- package/server/workspace/journal/paths.ts +76 -0
- package/server/workspace/journal/state.ts +125 -0
- package/server/workspace/paths.ts +158 -0
- package/server/workspace/reference-dirs.ts +252 -0
- package/server/workspace/roles.ts +37 -0
- package/server/workspace/skills/discovery.ts +125 -0
- package/server/workspace/skills/index.ts +10 -0
- package/server/workspace/skills/parser.ts +144 -0
- package/server/workspace/skills/paths.ts +41 -0
- package/server/workspace/skills/scheduler.ts +149 -0
- package/server/workspace/skills/types.ts +30 -0
- package/server/workspace/skills/user-tasks.ts +257 -0
- package/server/workspace/skills/writer.ts +189 -0
- package/server/workspace/sources/arxivDiscovery.ts +182 -0
- package/server/workspace/sources/classifier.ts +268 -0
- package/server/workspace/sources/fetchers/arxiv.ts +170 -0
- package/server/workspace/sources/fetchers/github.ts +106 -0
- package/server/workspace/sources/fetchers/githubIssues.ts +208 -0
- package/server/workspace/sources/fetchers/githubReleases.ts +186 -0
- package/server/workspace/sources/fetchers/index.ts +71 -0
- package/server/workspace/sources/fetchers/registerAll.ts +15 -0
- package/server/workspace/sources/fetchers/rss.ts +141 -0
- package/server/workspace/sources/fetchers/rssParser.ts +295 -0
- package/server/workspace/sources/httpFetcher.ts +230 -0
- package/server/workspace/sources/interests.ts +120 -0
- package/server/workspace/sources/paths.ts +110 -0
- package/server/workspace/sources/pipeline/dedup.ts +60 -0
- package/server/workspace/sources/pipeline/fetch.ts +136 -0
- package/server/workspace/sources/pipeline/index.ts +249 -0
- package/server/workspace/sources/pipeline/notify.ts +72 -0
- package/server/workspace/sources/pipeline/plan.ts +66 -0
- package/server/workspace/sources/pipeline/summarize.ts +189 -0
- package/server/workspace/sources/pipeline/write.ts +185 -0
- package/server/workspace/sources/rateLimiter.ts +148 -0
- package/server/workspace/sources/registry.ts +326 -0
- package/server/workspace/sources/robots.ts +271 -0
- package/server/workspace/sources/sourceState.ts +135 -0
- package/server/workspace/sources/taxonomy.ts +74 -0
- package/server/workspace/sources/types.ts +144 -0
- package/server/workspace/sources/urls.ts +112 -0
- package/server/workspace/tool-trace/classify.ts +114 -0
- package/server/workspace/tool-trace/index.ts +250 -0
- package/server/workspace/tool-trace/writeSearch.ts +98 -0
- package/server/workspace/wiki-backlinks/index.ts +107 -0
- package/server/workspace/wiki-backlinks/sessionBacklinks.ts +144 -0
- package/server/workspace/workspace.ts +66 -0
- package/src/App.vue +720 -0
- package/src/assets/mulmo_bw.png +0 -0
- package/src/components/CanvasViewToggle.vue +27 -0
- package/src/components/ChatAttachmentPreview.vue +45 -0
- package/src/components/ChatImagePreview.vue +17 -0
- package/src/components/ChatInput.vue +208 -0
- package/src/components/FileContentHeader.vue +49 -0
- package/src/components/FileContentRenderer.vue +162 -0
- package/src/components/FileTree.vue +115 -0
- package/src/components/FileTreePane.vue +85 -0
- package/src/components/FilesView.vue +206 -0
- package/src/components/LockStatusPopup.vue +111 -0
- package/src/components/NotificationBell.vue +131 -0
- package/src/components/NotificationToast.vue +72 -0
- package/src/components/PluginLauncher.vue +138 -0
- package/src/components/RightSidebar.vue +113 -0
- package/src/components/RoleSelector.vue +64 -0
- package/src/components/SessionHistoryPanel.vue +176 -0
- package/src/components/SessionTabBar.vue +81 -0
- package/src/components/SettingsMcpTab.vue +350 -0
- package/src/components/SettingsModal.vue +275 -0
- package/src/components/SettingsReferenceDirsTab.vue +173 -0
- package/src/components/SettingsWorkspaceDirsTab.vue +174 -0
- package/src/components/SidebarHeader.vue +69 -0
- package/src/components/StackView.vue +360 -0
- package/src/components/SuggestionsPanel.vue +65 -0
- package/src/components/TodoExplorer.vue +358 -0
- package/src/components/ToolResultsPanel.vue +77 -0
- package/src/components/todo/TodoAddDialog.vue +131 -0
- package/src/components/todo/TodoEditDialog.vue +47 -0
- package/src/components/todo/TodoEditPanel.vue +113 -0
- package/src/components/todo/TodoKanbanView.vue +249 -0
- package/src/components/todo/TodoListView.vue +79 -0
- package/src/components/todo/TodoTableView.vue +177 -0
- package/src/composables/useActiveSession.ts +40 -0
- package/src/composables/useAppApi.ts +45 -0
- package/src/composables/useCanvasViewMode.ts +121 -0
- package/src/composables/useChatScroll.ts +47 -0
- package/src/composables/useClickOutside.ts +26 -0
- package/src/composables/useClipboardCopy.ts +44 -0
- package/src/composables/useContentDisplay.ts +52 -0
- package/src/composables/useDebugBeat.ts +23 -0
- package/src/composables/useDynamicFavicon.ts +115 -0
- package/src/composables/useEventListeners.ts +42 -0
- package/src/composables/useExpandedDirs.ts +64 -0
- package/src/composables/useFaviconState.ts +30 -0
- package/src/composables/useFileSelection.ts +115 -0
- package/src/composables/useFileSortMode.ts +24 -0
- package/src/composables/useFileTree.ts +85 -0
- package/src/composables/useFreshPluginData.ts +89 -0
- package/src/composables/useHealth.ts +38 -0
- package/src/composables/useImeAwareEnter.ts +57 -0
- package/src/composables/useKeyNavigation.ts +60 -0
- package/src/composables/useMarkdownLinkHandler.ts +46 -0
- package/src/composables/useMarkdownMode.ts +17 -0
- package/src/composables/useMcpTools.ts +71 -0
- package/src/composables/useMergedSessions.ts +27 -0
- package/src/composables/useNotifications.ts +90 -0
- package/src/composables/usePdfDownload.ts +60 -0
- package/src/composables/usePendingCalls.ts +77 -0
- package/src/composables/usePubSub.ts +85 -0
- package/src/composables/useRightSidebar.ts +23 -0
- package/src/composables/useRoles.ts +34 -0
- package/src/composables/useSandboxStatus.ts +67 -0
- package/src/composables/useSelectedResult.ts +49 -0
- package/src/composables/useSessionDerived.ts +51 -0
- package/src/composables/useSessionHistory.ts +81 -0
- package/src/composables/useSessionSync.ts +57 -0
- package/src/composables/useViewLayout.ts +55 -0
- package/src/config/apiRoutes.ts +173 -0
- package/src/config/pubsubChannels.ts +45 -0
- package/src/config/roles.ts +335 -0
- package/src/config/schedulerActions.ts +25 -0
- package/src/config/toolNames.ts +71 -0
- package/src/config/workspacePaths.ts +24 -0
- package/src/index.css +107 -0
- package/src/main.ts +25 -0
- package/src/plugins/canvas/Preview.vue +13 -0
- package/src/plugins/canvas/View.vue +333 -0
- package/src/plugins/canvas/definition.ts +38 -0
- package/src/plugins/canvas/index.ts +36 -0
- package/src/plugins/chart/Preview.vue +49 -0
- package/src/plugins/chart/View.vue +143 -0
- package/src/plugins/chart/definition.ts +58 -0
- package/src/plugins/chart/index.ts +52 -0
- package/src/plugins/editImage/Preview.vue +13 -0
- package/src/plugins/editImage/View.vue +13 -0
- package/src/plugins/editImage/definition.ts +27 -0
- package/src/plugins/editImage/index.ts +36 -0
- package/src/plugins/generateImage/Preview.vue +13 -0
- package/src/plugins/generateImage/View.vue +33 -0
- package/src/plugins/generateImage/definition.ts +32 -0
- package/src/plugins/generateImage/index.ts +56 -0
- package/src/plugins/manageRoles/Preview.vue +49 -0
- package/src/plugins/manageRoles/View.vue +525 -0
- package/src/plugins/manageRoles/definition.ts +43 -0
- package/src/plugins/manageRoles/index.ts +47 -0
- package/src/plugins/manageSkills/Preview.vue +21 -0
- package/src/plugins/manageSkills/View.vue +321 -0
- package/src/plugins/manageSkills/definition.ts +49 -0
- package/src/plugins/manageSkills/index.ts +49 -0
- package/src/plugins/manageSource/Preview.vue +33 -0
- package/src/plugins/manageSource/View.vue +697 -0
- package/src/plugins/manageSource/definition.ts +63 -0
- package/src/plugins/manageSource/index.ts +66 -0
- package/src/plugins/markdown/Preview.vue +77 -0
- package/src/plugins/markdown/View.vue +476 -0
- package/src/plugins/markdown/definition.ts +50 -0
- package/src/plugins/markdown/index.ts +36 -0
- package/src/plugins/presentHtml/Preview.vue +25 -0
- package/src/plugins/presentHtml/View.vue +52 -0
- package/src/plugins/presentHtml/definition.ts +27 -0
- package/src/plugins/presentHtml/helpers.ts +72 -0
- package/src/plugins/presentHtml/index.ts +41 -0
- package/src/plugins/presentMulmoScript/Preview.vue +23 -0
- package/src/plugins/presentMulmoScript/View.vue +1166 -0
- package/src/plugins/presentMulmoScript/definition.ts +95 -0
- package/src/plugins/presentMulmoScript/helpers.ts +162 -0
- package/src/plugins/presentMulmoScript/index.ts +40 -0
- package/src/plugins/scheduler/Preview.vue +67 -0
- package/src/plugins/scheduler/TasksTab.vue +205 -0
- package/src/plugins/scheduler/View.vue +565 -0
- package/src/plugins/scheduler/definition.ts +57 -0
- package/src/plugins/scheduler/index.ts +45 -0
- package/src/plugins/scheduler/viewModes.ts +26 -0
- package/src/plugins/spreadsheet/Preview.vue +29 -0
- package/src/plugins/spreadsheet/View.vue +997 -0
- package/src/plugins/spreadsheet/cellHighlights.ts +79 -0
- package/src/plugins/spreadsheet/definition.ts +121 -0
- package/src/plugins/spreadsheet/engine/calculator.ts +459 -0
- package/src/plugins/spreadsheet/engine/cellBuilder.ts +81 -0
- package/src/plugins/spreadsheet/engine/date-parser.ts +220 -0
- package/src/plugins/spreadsheet/engine/date-utils.ts +56 -0
- package/src/plugins/spreadsheet/engine/engine.ts +176 -0
- package/src/plugins/spreadsheet/engine/evaluator.ts +390 -0
- package/src/plugins/spreadsheet/engine/formatter.ts +172 -0
- package/src/plugins/spreadsheet/engine/formulaRefs.ts +101 -0
- package/src/plugins/spreadsheet/engine/functions/date.ts +299 -0
- package/src/plugins/spreadsheet/engine/functions/financial.ts +387 -0
- package/src/plugins/spreadsheet/engine/functions/index.ts +16 -0
- package/src/plugins/spreadsheet/engine/functions/logical.ts +262 -0
- package/src/plugins/spreadsheet/engine/functions/lookup.ts +400 -0
- package/src/plugins/spreadsheet/engine/functions/mathematical.ts +297 -0
- package/src/plugins/spreadsheet/engine/functions/statistical.ts +338 -0
- package/src/plugins/spreadsheet/engine/functions/text.ts +389 -0
- package/src/plugins/spreadsheet/engine/index.ts +27 -0
- package/src/plugins/spreadsheet/engine/jsonCellLocator.ts +111 -0
- package/src/plugins/spreadsheet/engine/parser.ts +143 -0
- package/src/plugins/spreadsheet/engine/registry.ts +150 -0
- package/src/plugins/spreadsheet/engine/responseDecoder.ts +67 -0
- package/src/plugins/spreadsheet/engine/types.ts +64 -0
- package/src/plugins/spreadsheet/index.ts +36 -0
- package/src/plugins/textResponse/Preview.vue +94 -0
- package/src/plugins/textResponse/View.vue +503 -0
- package/src/plugins/textResponse/definition.ts +34 -0
- package/src/plugins/textResponse/index.ts +27 -0
- package/src/plugins/textResponse/plugin.ts +29 -0
- package/src/plugins/textResponse/samples.ts +97 -0
- package/src/plugins/textResponse/types.ts +11 -0
- package/src/plugins/todo/Preview.vue +63 -0
- package/src/plugins/todo/View.vue +364 -0
- package/src/plugins/todo/composables/useTodos.ts +177 -0
- package/src/plugins/todo/definition.ts +45 -0
- package/src/plugins/todo/index.ts +61 -0
- package/src/plugins/todo/labels.ts +163 -0
- package/src/plugins/todo/priority.ts +98 -0
- package/src/plugins/todo/viewModes.ts +19 -0
- package/src/plugins/ui-image/ImagePreview.vue +23 -0
- package/src/plugins/ui-image/ImageView.vue +34 -0
- package/src/plugins/ui-image/index.ts +3 -0
- package/src/plugins/ui-image/types.ts +4 -0
- package/src/plugins/wiki/Preview.vue +65 -0
- package/src/plugins/wiki/View.vue +342 -0
- package/src/plugins/wiki/definition.ts +25 -0
- package/src/plugins/wiki/helpers.ts +59 -0
- package/src/plugins/wiki/index.ts +52 -0
- package/src/router/guards.ts +61 -0
- package/src/router/index.ts +50 -0
- package/src/tools/index.ts +52 -0
- package/src/tools/types.ts +27 -0
- package/src/types/events.ts +16 -0
- package/src/types/fileTree.ts +13 -0
- package/src/types/notification.ts +67 -0
- package/src/types/session.ts +116 -0
- package/src/types/sse.ts +90 -0
- package/src/types/toolCallHistory.ts +13 -0
- package/src/utils/agent/eventDispatch.ts +74 -0
- package/src/utils/agent/request.ts +55 -0
- package/src/utils/agent/toolCalls.ts +62 -0
- package/src/utils/api.ts +218 -0
- package/src/utils/canvas/viewMode.ts +46 -0
- package/src/utils/dom/authTokenMeta.ts +20 -0
- package/src/utils/dom/clickOutside.ts +11 -0
- package/src/utils/dom/externalLink.ts +57 -0
- package/src/utils/dom/scrollable.ts +24 -0
- package/src/utils/errors.ts +11 -0
- package/src/utils/files/expandedDirs.ts +25 -0
- package/src/utils/files/filename.ts +12 -0
- package/src/utils/files/sortChildren.ts +20 -0
- package/src/utils/filesPreview/schedulerPreview.ts +38 -0
- package/src/utils/filesPreview/todoPreview.ts +40 -0
- package/src/utils/format/date.ts +85 -0
- package/src/utils/format/frontmatter.ts +80 -0
- package/src/utils/format/jsonSyntax.ts +109 -0
- package/src/utils/html/previewCsp.ts +65 -0
- package/src/utils/image/resolve.ts +8 -0
- package/src/utils/image/rewriteMarkdownImageRefs.ts +182 -0
- package/src/utils/markdown/extractFirstH1.ts +39 -0
- package/src/utils/notification/dispatch.ts +22 -0
- package/src/utils/path/relativeLink.ts +130 -0
- package/src/utils/role/icon.ts +20 -0
- package/src/utils/role/merge.ts +10 -0
- package/src/utils/role/plugins.ts +12 -0
- package/src/utils/session/mergeSessions.ts +103 -0
- package/src/utils/session/seedRoleDefault.ts +35 -0
- package/src/utils/session/sessionEntries.ts +121 -0
- package/src/utils/session/sessionFactory.ts +22 -0
- package/src/utils/session/sessionHelpers.ts +99 -0
- package/src/utils/tools/dedup.ts +17 -0
- package/src/utils/tools/mcp.ts +33 -0
- package/src/utils/tools/pendingCalls.ts +16 -0
- package/src/utils/tools/result.ts +40 -0
- package/src/utils/types.ts +44 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:r,getOwnPropertyDescriptor:i}=Object,{freeze:a,seal:o,create:s}=Object,{apply:c,construct:l}=typeof Reflect<`u`&&Reflect;a||=function(e){return e},o||=function(e){return e},c||=function(e,t){var n=[...arguments].slice(2);return e.apply(t,n)},l||=function(e){return new e(...[...arguments].slice(1))};var u=v(Array.prototype.forEach),d=v(Array.prototype.lastIndexOf),ee=v(Array.prototype.pop),f=v(Array.prototype.push),te=v(Array.prototype.splice),p=v(String.prototype.toLowerCase),ne=v(String.prototype.toString),re=v(String.prototype.match),m=v(String.prototype.replace),ie=v(String.prototype.indexOf),ae=v(String.prototype.trim),h=v(Object.prototype.hasOwnProperty),g=v(RegExp.prototype.test),_=oe(TypeError);function v(e){return function(t){t instanceof RegExp&&(t.lastIndex=0);var n=[...arguments].slice(1);return c(e,t,n)}}function oe(e){return function(){return l(e,[...arguments])}}function y(e,r){let i=arguments.length>2&&arguments[2]!==void 0?arguments[2]:p;t&&t(e,null);let a=r.length;for(;a--;){let t=r[a];if(typeof t==`string`){let e=i(t);e!==t&&(n(r)||(r[a]=e),t=e)}e[t]=!0}return e}function b(e){for(let t=0;t<e.length;t++)h(e,t)||(e[t]=null);return e}function x(t){let n=s(null);for(let[r,i]of e(t))h(t,r)&&(Array.isArray(i)?n[r]=b(i):i&&typeof i==`object`&&i.constructor===Object?n[r]=x(i):n[r]=i);return n}function S(e,t){for(;e!==null;){let n=i(e,t);if(n){if(n.get)return v(n.get);if(typeof n.value==`function`)return v(n.value)}e=r(e)}function n(){return null}return n}var se=a(`a.abbr.acronym.address.area.article.aside.audio.b.bdi.bdo.big.blink.blockquote.body.br.button.canvas.caption.center.cite.code.col.colgroup.content.data.datalist.dd.decorator.del.details.dfn.dialog.dir.div.dl.dt.element.em.fieldset.figcaption.figure.font.footer.form.h1.h2.h3.h4.h5.h6.head.header.hgroup.hr.html.i.img.input.ins.kbd.label.legend.li.main.map.mark.marquee.menu.menuitem.meter.nav.nobr.ol.optgroup.option.output.p.picture.pre.progress.q.rp.rt.ruby.s.samp.search.section.select.shadow.slot.small.source.spacer.span.strike.strong.style.sub.summary.sup.table.tbody.td.template.textarea.tfoot.th.thead.time.tr.track.tt.u.ul.var.video.wbr`.split(`.`)),ce=a(`svg.a.altglyph.altglyphdef.altglyphitem.animatecolor.animatemotion.animatetransform.circle.clippath.defs.desc.ellipse.enterkeyhint.exportparts.filter.font.g.glyph.glyphref.hkern.image.inputmode.line.lineargradient.marker.mask.metadata.mpath.part.path.pattern.polygon.polyline.radialgradient.rect.stop.style.switch.symbol.text.textpath.title.tref.tspan.view.vkern`.split(`.`)),le=a([`feBlend`,`feColorMatrix`,`feComponentTransfer`,`feComposite`,`feConvolveMatrix`,`feDiffuseLighting`,`feDisplacementMap`,`feDistantLight`,`feDropShadow`,`feFlood`,`feFuncA`,`feFuncB`,`feFuncG`,`feFuncR`,`feGaussianBlur`,`feImage`,`feMerge`,`feMergeNode`,`feMorphology`,`feOffset`,`fePointLight`,`feSpecularLighting`,`feSpotLight`,`feTile`,`feTurbulence`]),ue=a([`animate`,`color-profile`,`cursor`,`discard`,`font-face`,`font-face-format`,`font-face-name`,`font-face-src`,`font-face-uri`,`foreignobject`,`hatch`,`hatchpath`,`mesh`,`meshgradient`,`meshpatch`,`meshrow`,`missing-glyph`,`script`,`set`,`solidcolor`,`unknown`,`use`]),de=a(`math.menclose.merror.mfenced.mfrac.mglyph.mi.mlabeledtr.mmultiscripts.mn.mo.mover.mpadded.mphantom.mroot.mrow.ms.mspace.msqrt.mstyle.msub.msup.msubsup.mtable.mtd.mtext.mtr.munder.munderover.mprescripts`.split(`.`)),fe=a([`maction`,`maligngroup`,`malignmark`,`mlongdiv`,`mscarries`,`mscarry`,`msgroup`,`mstack`,`msline`,`msrow`,`semantics`,`annotation`,`annotation-xml`,`mprescripts`,`none`]),pe=a([`#text`]),me=a(`accept.action.align.alt.autocapitalize.autocomplete.autopictureinpicture.autoplay.background.bgcolor.border.capture.cellpadding.cellspacing.checked.cite.class.clear.color.cols.colspan.controls.controlslist.coords.crossorigin.datetime.decoding.default.dir.disabled.disablepictureinpicture.disableremoteplayback.download.draggable.enctype.enterkeyhint.exportparts.face.for.headers.height.hidden.high.href.hreflang.id.inert.inputmode.integrity.ismap.kind.label.lang.list.loading.loop.low.max.maxlength.media.method.min.minlength.multiple.muted.name.nonce.noshade.novalidate.nowrap.open.optimum.part.pattern.placeholder.playsinline.popover.popovertarget.popovertargetaction.poster.preload.pubdate.radiogroup.readonly.rel.required.rev.reversed.role.rows.rowspan.spellcheck.scope.selected.shape.size.sizes.slot.span.srclang.start.src.srcset.step.style.summary.tabindex.title.translate.type.usemap.valign.value.width.wrap.xmlns.slot`.split(`.`)),he=a(`accent-height.accumulate.additive.alignment-baseline.amplitude.ascent.attributename.attributetype.azimuth.basefrequency.baseline-shift.begin.bias.by.class.clip.clippathunits.clip-path.clip-rule.color.color-interpolation.color-interpolation-filters.color-profile.color-rendering.cx.cy.d.dx.dy.diffuseconstant.direction.display.divisor.dur.edgemode.elevation.end.exponent.fill.fill-opacity.fill-rule.filter.filterunits.flood-color.flood-opacity.font-family.font-size.font-size-adjust.font-stretch.font-style.font-variant.font-weight.fx.fy.g1.g2.glyph-name.glyphref.gradientunits.gradienttransform.height.href.id.image-rendering.in.in2.intercept.k.k1.k2.k3.k4.kerning.keypoints.keysplines.keytimes.lang.lengthadjust.letter-spacing.kernelmatrix.kernelunitlength.lighting-color.local.marker-end.marker-mid.marker-start.markerheight.markerunits.markerwidth.maskcontentunits.maskunits.max.mask.mask-type.media.method.mode.min.name.numoctaves.offset.operator.opacity.order.orient.orientation.origin.overflow.paint-order.path.pathlength.patterncontentunits.patterntransform.patternunits.points.preservealpha.preserveaspectratio.primitiveunits.r.rx.ry.radius.refx.refy.repeatcount.repeatdur.restart.result.rotate.scale.seed.shape-rendering.slope.specularconstant.specularexponent.spreadmethod.startoffset.stddeviation.stitchtiles.stop-color.stop-opacity.stroke-dasharray.stroke-dashoffset.stroke-linecap.stroke-linejoin.stroke-miterlimit.stroke-opacity.stroke.stroke-width.style.surfacescale.systemlanguage.tabindex.tablevalues.targetx.targety.transform.transform-origin.text-anchor.text-decoration.text-rendering.textlength.type.u1.u2.unicode.values.viewbox.visibility.version.vert-adv-y.vert-origin-x.vert-origin-y.width.word-spacing.wrap.writing-mode.xchannelselector.ychannelselector.x.x1.x2.xmlns.y.y1.y2.z.zoomandpan`.split(`.`)),ge=a(`accent.accentunder.align.bevelled.close.columnsalign.columnlines.columnspan.denomalign.depth.dir.display.displaystyle.encoding.fence.frame.height.href.id.largeop.length.linethickness.lspace.lquote.mathbackground.mathcolor.mathsize.mathvariant.maxsize.minsize.movablelimits.notation.numalign.open.rowalign.rowlines.rowspacing.rowspan.rspace.rquote.scriptlevel.scriptminsize.scriptsizemultiplier.selection.separator.separators.stretchy.subscriptshift.supscriptshift.symmetric.voffset.width.xmlns`.split(`.`)),_e=a([`xlink:href`,`xml:id`,`xlink:title`,`xml:space`,`xmlns:xlink`]),ve=o(/\{\{[\w\W]*|[\w\W]*\}\}/gm),ye=o(/<%[\w\W]*|[\w\W]*%>/gm),be=o(/\$\{[\w\W]*/gm),C=o(/^data-[\-\w.\u00B7-\uFFFF]+$/),w=o(/^aria-[\-\w]+$/),xe=o(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Se=o(/^(?:\w+script|data):/i),Ce=o(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),we=o(/^html$/i),Te=o(/^[a-z][.\w]*(-[.\w]+)+$/i),Ee=Object.freeze({__proto__:null,ARIA_ATTR:w,ATTR_WHITESPACE:Ce,CUSTOM_ELEMENT:Te,DATA_ATTR:C,DOCTYPE_NAME:we,ERB_EXPR:ye,IS_ALLOWED_URI:xe,IS_SCRIPT_OR_DATA:Se,MUSTACHE_EXPR:ve,TMPLIT_EXPR:be}),T={element:1,attribute:2,text:3,cdataSection:4,entityReference:5,entityNode:6,progressingInstruction:7,comment:8,document:9,documentType:10,documentFragment:11,notation:12},De=function(){return typeof window>`u`?null:window},Oe=function(e,t){if(typeof e!=`object`||typeof e.createPolicy!=`function`)return null;let n=null,r=`data-tt-policy-suffix`;t&&t.hasAttribute(r)&&(n=t.getAttribute(r));let i=`dompurify`+(n?`#`+n:``);try{return e.createPolicy(i,{createHTML(e){return e},createScriptURL(e){return e}})}catch{return console.warn(`TrustedTypes policy `+i+` could not be created.`),null}},ke=function(){return{afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}};function Ae(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:De(),n=e=>Ae(e);if(n.version=`3.3.3`,n.removed=[],!t||!t.document||t.document.nodeType!==T.document||!t.Element)return n.isSupported=!1,n;let{document:r}=t,i=r,o=i.currentScript,{DocumentFragment:c,HTMLTemplateElement:l,Node:v,Element:oe,NodeFilter:b,NamedNodeMap:ve=t.NamedNodeMap||t.MozNamedAttrMap,HTMLFormElement:ye,DOMParser:be,trustedTypes:C}=t,w=oe.prototype,Se=S(w,`cloneNode`),Ce=S(w,`remove`),Te=S(w,`nextSibling`),je=S(w,`childNodes`),E=S(w,`parentNode`);if(typeof l==`function`){let e=r.createElement(`template`);e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let D,O=``,{implementation:Me,createNodeIterator:Ne,createDocumentFragment:Pe,getElementsByTagName:Fe}=r,{importNode:Ie}=i,k=ke();n.isSupported=typeof e==`function`&&typeof E==`function`&&Me&&Me.createHTMLDocument!==void 0;let{MUSTACHE_EXPR:Le,ERB_EXPR:Re,TMPLIT_EXPR:ze,DATA_ATTR:Be,ARIA_ATTR:Ve,IS_SCRIPT_OR_DATA:He,ATTR_WHITESPACE:Ue,CUSTOM_ELEMENT:We}=Ee,{IS_ALLOWED_URI:Ge}=Ee,A=null,Ke=y({},[...se,...ce,...le,...de,...pe]),j=null,qe=y({},[...me,...he,...ge,..._e]),M=Object.seal(s(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),N=null,Je=null,P=Object.seal(s(null,{tagCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeCheck:{writable:!0,configurable:!1,enumerable:!0,value:null}})),Ye=!0,Xe=!0,Ze=!1,Qe=!0,F=!1,I=!0,L=!1,$e=!1,et=!1,R=!1,z=!1,B=!1,tt=!0,nt=!1,rt=!0,V=!1,H={},U=null,it=y({},[`annotation-xml`,`audio`,`colgroup`,`desc`,`foreignobject`,`head`,`iframe`,`math`,`mi`,`mn`,`mo`,`ms`,`mtext`,`noembed`,`noframes`,`noscript`,`plaintext`,`script`,`style`,`svg`,`template`,`thead`,`title`,`video`,`xmp`]),at=null,ot=y({},[`audio`,`video`,`img`,`source`,`image`,`track`]),st=null,ct=y({},[`alt`,`class`,`for`,`id`,`label`,`name`,`pattern`,`placeholder`,`role`,`summary`,`title`,`value`,`style`,`xmlns`]),W=`http://www.w3.org/1998/Math/MathML`,G=`http://www.w3.org/2000/svg`,K=`http://www.w3.org/1999/xhtml`,q=K,lt=!1,ut=null,dt=y({},[W,G,K],ne),ft=y({},[`mi`,`mo`,`mn`,`ms`,`mtext`]),pt=y({},[`annotation-xml`]),mt=y({},[`title`,`style`,`font`,`a`,`script`]),J=null,ht=[`application/xhtml+xml`,`text/html`],Y=null,X=null,gt=r.createElement(`form`),_t=function(e){return e instanceof RegExp||e instanceof Function},vt=function(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};if(!(X&&X===e)){if((!e||typeof e!=`object`)&&(e={}),e=x(e),J=ht.indexOf(e.PARSER_MEDIA_TYPE)===-1?`text/html`:e.PARSER_MEDIA_TYPE,Y=J===`application/xhtml+xml`?ne:p,A=h(e,`ALLOWED_TAGS`)?y({},e.ALLOWED_TAGS,Y):Ke,j=h(e,`ALLOWED_ATTR`)?y({},e.ALLOWED_ATTR,Y):qe,ut=h(e,`ALLOWED_NAMESPACES`)?y({},e.ALLOWED_NAMESPACES,ne):dt,st=h(e,`ADD_URI_SAFE_ATTR`)?y(x(ct),e.ADD_URI_SAFE_ATTR,Y):ct,at=h(e,`ADD_DATA_URI_TAGS`)?y(x(ot),e.ADD_DATA_URI_TAGS,Y):ot,U=h(e,`FORBID_CONTENTS`)?y({},e.FORBID_CONTENTS,Y):it,N=h(e,`FORBID_TAGS`)?y({},e.FORBID_TAGS,Y):x({}),Je=h(e,`FORBID_ATTR`)?y({},e.FORBID_ATTR,Y):x({}),H=h(e,`USE_PROFILES`)?e.USE_PROFILES:!1,Ye=e.ALLOW_ARIA_ATTR!==!1,Xe=e.ALLOW_DATA_ATTR!==!1,Ze=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Qe=e.ALLOW_SELF_CLOSE_IN_ATTR!==!1,F=e.SAFE_FOR_TEMPLATES||!1,I=e.SAFE_FOR_XML!==!1,L=e.WHOLE_DOCUMENT||!1,R=e.RETURN_DOM||!1,z=e.RETURN_DOM_FRAGMENT||!1,B=e.RETURN_TRUSTED_TYPE||!1,et=e.FORCE_BODY||!1,tt=e.SANITIZE_DOM!==!1,nt=e.SANITIZE_NAMED_PROPS||!1,rt=e.KEEP_CONTENT!==!1,V=e.IN_PLACE||!1,Ge=e.ALLOWED_URI_REGEXP||xe,q=e.NAMESPACE||K,ft=e.MATHML_TEXT_INTEGRATION_POINTS||ft,pt=e.HTML_INTEGRATION_POINTS||pt,M=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&_t(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(M.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&_t(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(M.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements==`boolean`&&(M.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),F&&(Xe=!1),z&&(R=!0),H&&(A=y({},pe),j=s(null),H.html===!0&&(y(A,se),y(j,me)),H.svg===!0&&(y(A,ce),y(j,he),y(j,_e)),H.svgFilters===!0&&(y(A,le),y(j,he),y(j,_e)),H.mathMl===!0&&(y(A,de),y(j,ge),y(j,_e))),h(e,`ADD_TAGS`)||(P.tagCheck=null),h(e,`ADD_ATTR`)||(P.attributeCheck=null),e.ADD_TAGS&&(typeof e.ADD_TAGS==`function`?P.tagCheck=e.ADD_TAGS:(A===Ke&&(A=x(A)),y(A,e.ADD_TAGS,Y))),e.ADD_ATTR&&(typeof e.ADD_ATTR==`function`?P.attributeCheck=e.ADD_ATTR:(j===qe&&(j=x(j)),y(j,e.ADD_ATTR,Y))),e.ADD_URI_SAFE_ATTR&&y(st,e.ADD_URI_SAFE_ATTR,Y),e.FORBID_CONTENTS&&(U===it&&(U=x(U)),y(U,e.FORBID_CONTENTS,Y)),e.ADD_FORBID_CONTENTS&&(U===it&&(U=x(U)),y(U,e.ADD_FORBID_CONTENTS,Y)),rt&&(A[`#text`]=!0),L&&y(A,[`html`,`head`,`body`]),A.table&&(y(A,[`tbody`]),delete N.tbody),e.TRUSTED_TYPES_POLICY){if(typeof e.TRUSTED_TYPES_POLICY.createHTML!=`function`)throw _(`TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.`);if(typeof e.TRUSTED_TYPES_POLICY.createScriptURL!=`function`)throw _(`TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.`);D=e.TRUSTED_TYPES_POLICY,O=D.createHTML(``)}else D===void 0&&(D=Oe(C,o)),D!==null&&typeof O==`string`&&(O=D.createHTML(``));a&&a(e),X=e}},yt=y({},[...ce,...le,...ue]),bt=y({},[...de,...fe]),xt=function(e){let t=E(e);(!t||!t.tagName)&&(t={namespaceURI:q,tagName:`template`});let n=p(e.tagName),r=p(t.tagName);return ut[e.namespaceURI]?e.namespaceURI===G?t.namespaceURI===K?n===`svg`:t.namespaceURI===W?n===`svg`&&(r===`annotation-xml`||ft[r]):!!yt[n]:e.namespaceURI===W?t.namespaceURI===K?n===`math`:t.namespaceURI===G?n===`math`&&pt[r]:!!bt[n]:e.namespaceURI===K?t.namespaceURI===G&&!pt[r]||t.namespaceURI===W&&!ft[r]?!1:!bt[n]&&(mt[n]||!yt[n]):!!(J===`application/xhtml+xml`&&ut[e.namespaceURI]):!1},Z=function(e){f(n.removed,{element:e});try{E(e).removeChild(e)}catch{Ce(e)}},Q=function(e,t){try{f(n.removed,{attribute:t.getAttributeNode(e),from:t})}catch{f(n.removed,{attribute:null,from:t})}if(t.removeAttribute(e),e===`is`)if(R||z)try{Z(t)}catch{}else try{t.setAttribute(e,``)}catch{}},St=function(e){let t=null,n=null;if(et)e=`<remove></remove>`+e;else{let t=re(e,/^[\r\n\t ]+/);n=t&&t[0]}J===`application/xhtml+xml`&&q===K&&(e=`<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>`+e+`</body></html>`);let i=D?D.createHTML(e):e;if(q===K)try{t=new be().parseFromString(i,J)}catch{}if(!t||!t.documentElement){t=Me.createDocument(q,`template`,null);try{t.documentElement.innerHTML=lt?O:i}catch{}}let a=t.body||t.documentElement;return e&&n&&a.insertBefore(r.createTextNode(n),a.childNodes[0]||null),q===K?Fe.call(t,L?`html`:`body`)[0]:L?t.documentElement:a},Ct=function(e){return Ne.call(e.ownerDocument||e,e,b.SHOW_ELEMENT|b.SHOW_COMMENT|b.SHOW_TEXT|b.SHOW_PROCESSING_INSTRUCTION|b.SHOW_CDATA_SECTION,null)},wt=function(e){return e instanceof ye&&(typeof e.nodeName!=`string`||typeof e.textContent!=`string`||typeof e.removeChild!=`function`||!(e.attributes instanceof ve)||typeof e.removeAttribute!=`function`||typeof e.setAttribute!=`function`||typeof e.namespaceURI!=`string`||typeof e.insertBefore!=`function`||typeof e.hasChildNodes!=`function`)},Tt=function(e){return typeof v==`function`&&e instanceof v};function $(e,t,r){u(e,e=>{e.call(n,t,r,X)})}let Et=function(e){let t=null;if($(k.beforeSanitizeElements,e,null),wt(e))return Z(e),!0;let r=Y(e.nodeName);if($(k.uponSanitizeElement,e,{tagName:r,allowedTags:A}),I&&e.hasChildNodes()&&!Tt(e.firstElementChild)&&g(/<[/\w!]/g,e.innerHTML)&&g(/<[/\w!]/g,e.textContent)||e.nodeType===T.progressingInstruction||I&&e.nodeType===T.comment&&g(/<[/\w]/g,e.data))return Z(e),!0;if(!(P.tagCheck instanceof Function&&P.tagCheck(r))&&(!A[r]||N[r])){if(!N[r]&&Ot(r)&&(M.tagNameCheck instanceof RegExp&&g(M.tagNameCheck,r)||M.tagNameCheck instanceof Function&&M.tagNameCheck(r)))return!1;if(rt&&!U[r]){let t=E(e)||e.parentNode,n=je(e)||e.childNodes;if(n&&t){let r=n.length;for(let i=r-1;i>=0;--i){let r=Se(n[i],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,Te(e))}}}return Z(e),!0}return e instanceof oe&&!xt(e)||(r===`noscript`||r===`noembed`||r===`noframes`)&&g(/<\/no(script|embed|frames)/i,e.innerHTML)?(Z(e),!0):(F&&e.nodeType===T.text&&(t=e.textContent,u([Le,Re,ze],e=>{t=m(t,e,` `)}),e.textContent!==t&&(f(n.removed,{element:e.cloneNode()}),e.textContent=t)),$(k.afterSanitizeElements,e,null),!1)},Dt=function(e,t,n){if(Je[t]||tt&&(t===`id`||t===`name`)&&(n in r||n in gt))return!1;if(!(Xe&&!Je[t]&&g(Be,t))&&!(Ye&&g(Ve,t))&&!(P.attributeCheck instanceof Function&&P.attributeCheck(t,e))){if(!j[t]||Je[t]){if(!(Ot(e)&&(M.tagNameCheck instanceof RegExp&&g(M.tagNameCheck,e)||M.tagNameCheck instanceof Function&&M.tagNameCheck(e))&&(M.attributeNameCheck instanceof RegExp&&g(M.attributeNameCheck,t)||M.attributeNameCheck instanceof Function&&M.attributeNameCheck(t,e))||t===`is`&&M.allowCustomizedBuiltInElements&&(M.tagNameCheck instanceof RegExp&&g(M.tagNameCheck,n)||M.tagNameCheck instanceof Function&&M.tagNameCheck(n))))return!1}else if(!st[t]&&!g(Ge,m(n,Ue,``))&&!((t===`src`||t===`xlink:href`||t===`href`)&&e!==`script`&&ie(n,`data:`)===0&&at[e])&&!(Ze&&!g(He,m(n,Ue,``)))&&n)return!1}return!0},Ot=function(e){return e!==`annotation-xml`&&re(e,We)},kt=function(e){$(k.beforeSanitizeAttributes,e,null);let{attributes:t}=e;if(!t||wt(e))return;let r={attrName:``,attrValue:``,keepAttr:!0,allowedAttributes:j,forceKeepAttr:void 0},i=t.length;for(;i--;){let{name:a,namespaceURI:o,value:s}=t[i],c=Y(a),l=s,d=a===`value`?l:ae(l);if(r.attrName=c,r.attrValue=d,r.keepAttr=!0,r.forceKeepAttr=void 0,$(k.uponSanitizeAttribute,e,r),d=r.attrValue,nt&&(c===`id`||c===`name`)&&(Q(a,e),d=`user-content-`+d),I&&g(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i,d)){Q(a,e);continue}if(c===`attributename`&&re(d,`href`)){Q(a,e);continue}if(r.forceKeepAttr)continue;if(!r.keepAttr){Q(a,e);continue}if(!Qe&&g(/\/>/i,d)){Q(a,e);continue}F&&u([Le,Re,ze],e=>{d=m(d,e,` `)});let f=Y(e.nodeName);if(!Dt(f,c,d)){Q(a,e);continue}if(D&&typeof C==`object`&&typeof C.getAttributeType==`function`&&!o)switch(C.getAttributeType(f,c)){case`TrustedHTML`:d=D.createHTML(d);break;case`TrustedScriptURL`:d=D.createScriptURL(d);break}if(d!==l)try{o?e.setAttributeNS(o,a,d):e.setAttribute(a,d),wt(e)?Z(e):ee(n.removed)}catch{Q(a,e)}}$(k.afterSanitizeAttributes,e,null)},At=function e(t){let n=null,r=Ct(t);for($(k.beforeSanitizeShadowDOM,t,null);n=r.nextNode();)$(k.uponSanitizeShadowNode,n,null),Et(n),kt(n),n.content instanceof c&&e(n.content);$(k.afterSanitizeShadowDOM,t,null)};return n.sanitize=function(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},r=null,a=null,o=null,s=null;if(lt=!e,lt&&(e=`<!-->`),typeof e!=`string`&&!Tt(e))if(typeof e.toString==`function`){if(e=e.toString(),typeof e!=`string`)throw _(`dirty is not a string, aborting`)}else throw _(`toString is not a function`);if(!n.isSupported)return e;if($e||vt(t),n.removed=[],typeof e==`string`&&(V=!1),V){if(e.nodeName){let t=Y(e.nodeName);if(!A[t]||N[t])throw _(`root node is forbidden and cannot be sanitized in-place`)}}else if(e instanceof v)r=St(`<!---->`),a=r.ownerDocument.importNode(e,!0),a.nodeType===T.element&&a.nodeName===`BODY`||a.nodeName===`HTML`?r=a:r.appendChild(a);else{if(!R&&!F&&!L&&e.indexOf(`<`)===-1)return D&&B?D.createHTML(e):e;if(r=St(e),!r)return R?null:B?O:``}r&&et&&Z(r.firstChild);let l=Ct(V?e:r);for(;o=l.nextNode();)Et(o),kt(o),o.content instanceof c&&At(o.content);if(V)return e;if(R){if(z)for(s=Pe.call(r.ownerDocument);r.firstChild;)s.appendChild(r.firstChild);else s=r;return(j.shadowroot||j.shadowrootmode)&&(s=Ie.call(i,s,!0)),s}let d=L?r.outerHTML:r.innerHTML;return L&&A[`!doctype`]&&r.ownerDocument&&r.ownerDocument.doctype&&r.ownerDocument.doctype.name&&g(we,r.ownerDocument.doctype.name)&&(d=`<!DOCTYPE `+r.ownerDocument.doctype.name+`>
|
|
2
|
+
`+d),F&&u([Le,Re,ze],e=>{d=m(d,e,` `)}),D&&B?D.createHTML(d):d},n.setConfig=function(){vt(arguments.length>0&&arguments[0]!==void 0?arguments[0]:{}),$e=!0},n.clearConfig=function(){X=null,$e=!1},n.isValidAttribute=function(e,t,n){return X||vt({}),Dt(Y(e),Y(t),n)},n.addHook=function(e,t){typeof t==`function`&&f(k[e],t)},n.removeHook=function(e,t){if(t!==void 0){let n=d(k[e],t);return n===-1?void 0:te(k[e],n,1)[0]}return ee(k[e])},n.removeHooks=function(e){k[e]=[]},n.removeAllHooks=function(){k=ke()},n}var je=Ae();export{je as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(t){"@babel/helpers - typeof";return e=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},e(t)}export{e as t};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<!--
|
|
7
|
+
Bearer auth token (#272). The placeholder string is rewritten
|
|
8
|
+
per-request:
|
|
9
|
+
- dev: Vite plugin `mulmoclaudeAuthTokenPlugin` in vite.config.ts
|
|
10
|
+
reads `<workspace>/.session-token` and substitutes.
|
|
11
|
+
- prod: Express handler in `server/index.ts` substitutes when
|
|
12
|
+
serving the built client/index.html.
|
|
13
|
+
Vue bootstrap (src/main.ts) reads the content attribute and calls
|
|
14
|
+
setAuthToken() so every apiFetch attaches an Authorization header.
|
|
15
|
+
-->
|
|
16
|
+
<meta name="mulmoclaude-auth" content="__MULMOCLAUDE_AUTH_TOKEN__" />
|
|
17
|
+
<title>MulmoClaude</title>
|
|
18
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='30' height='30' x='1' y='1' rx='6' fill='%236B7280'/><text x='16' y='17' text-anchor='middle' dominant-baseline='central' font-family='sans-serif' font-weight='bold' font-size='20' fill='white'>M</text></svg>" />
|
|
19
|
+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
20
|
+
<script type="module" crossorigin src="/assets/index-D8rhwXLq.js"></script>
|
|
21
|
+
<link rel="modulepreload" crossorigin href="/assets/chunk-vKJrgz-R-C_I3GbVV.js">
|
|
22
|
+
<link rel="modulepreload" crossorigin href="/assets/typeof-DBp4T-Ny-BC0P-2DM.js">
|
|
23
|
+
<link rel="stylesheet" crossorigin href="/assets/index-KNLBjwuh.css">
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<div id="app"></div>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mulmoclaude",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MulmoClaude — GUI-chat with Claude Code + long-term memory. One command to start.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mulmoclaude": "bin/mulmoclaude.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"prepublishOnly": "node bin/prepare-dist.js",
|
|
11
|
+
"typecheck": "echo \"mulmoclaude: no typecheck (launcher is plain JS; server and src are dist artifacts)\"",
|
|
12
|
+
"test": "echo no tests yet"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin/",
|
|
16
|
+
"client/",
|
|
17
|
+
"server/",
|
|
18
|
+
"src/"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@mulmobridge/chat-service": "^0.1.0",
|
|
22
|
+
"@mulmobridge/client": "^0.1.0",
|
|
23
|
+
"@mulmobridge/protocol": "^0.1.0",
|
|
24
|
+
"@receptron/task-scheduler": "^0.1.0",
|
|
25
|
+
"@google/genai": "^1.50.1",
|
|
26
|
+
"@gui-chat-plugin/mindmap": "^0.4.0",
|
|
27
|
+
"@gui-chat-plugin/present3d": "^0.1.0",
|
|
28
|
+
"@gui-chat-plugin/browse": "^0.2.0",
|
|
29
|
+
"@gui-chat-plugin/camera": "^0.4.0",
|
|
30
|
+
"@gui-chat-plugin/weather": "^0.1.0",
|
|
31
|
+
"@mulmochat-plugin/form": "0.5.0",
|
|
32
|
+
"@mulmochat-plugin/quiz": "0.4.0",
|
|
33
|
+
"@mulmochat-plugin/ui-image": "^0.3.0",
|
|
34
|
+
"cors": "^2.8.6",
|
|
35
|
+
"dotenv": "^17.4.2",
|
|
36
|
+
"express": "^5.2.1",
|
|
37
|
+
"fast-xml-parser": "^5.7.1",
|
|
38
|
+
"gui-chat-protocol": "0.1.0",
|
|
39
|
+
"ignore": "^7.0.5",
|
|
40
|
+
"mammoth": "^1.12.0",
|
|
41
|
+
"marked": "^18.0.2",
|
|
42
|
+
"socket.io": "^4.8.3",
|
|
43
|
+
"socket.io-client": "^4.8.3",
|
|
44
|
+
"uuid": "^13.0.0",
|
|
45
|
+
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
46
|
+
"zod": "^4.3.6",
|
|
47
|
+
"tsx": "^4.19.0"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=20"
|
|
51
|
+
},
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "git+https://github.com/receptron/mulmoclaude.git",
|
|
56
|
+
"directory": "packages/mulmoclaude"
|
|
57
|
+
},
|
|
58
|
+
"keywords": [
|
|
59
|
+
"claude",
|
|
60
|
+
"ai",
|
|
61
|
+
"agent",
|
|
62
|
+
"chat",
|
|
63
|
+
"gui",
|
|
64
|
+
"mulmoclaude"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// Converts non-native attachment types into content blocks that
|
|
2
|
+
// Claude can consume. Called by `buildUserMessageLine` before
|
|
3
|
+
// assembling the JSON message line.
|
|
4
|
+
//
|
|
5
|
+
// Supported conversions:
|
|
6
|
+
// text/* → decode UTF-8 → text block
|
|
7
|
+
// application/json, .xml, .yaml, .toml, .csv → same (text)
|
|
8
|
+
// application/vnd...wordprocessingml (docx) → mammoth → text block
|
|
9
|
+
// application/vnd...spreadsheetml (xlsx) → xlsx → CSV text block
|
|
10
|
+
// application/vnd...presentationml (pptx) → libreoffice → PDF doc block (Docker only)
|
|
11
|
+
//
|
|
12
|
+
// Each converter returns an array of content blocks (usually one).
|
|
13
|
+
// Returns null when the type is not convertible — the caller skips it.
|
|
14
|
+
|
|
15
|
+
import mammoth from "mammoth";
|
|
16
|
+
import * as XLSX from "xlsx";
|
|
17
|
+
import { execFile } from "child_process";
|
|
18
|
+
import { mkdtemp, readFile, writeFile, rm } from "fs/promises";
|
|
19
|
+
import path from "path";
|
|
20
|
+
import os from "os";
|
|
21
|
+
import { promisify } from "util";
|
|
22
|
+
|
|
23
|
+
const execFileAsync = promisify(execFile);
|
|
24
|
+
import type { Attachment } from "@mulmobridge/protocol";
|
|
25
|
+
import { SUBPROCESS_PROBE_TIMEOUT_MS, SUBPROCESS_WORK_TIMEOUT_MS } from "../utils/time.js";
|
|
26
|
+
import { errorMessage } from "../utils/errors.js";
|
|
27
|
+
|
|
28
|
+
export interface ContentBlock {
|
|
29
|
+
type: string;
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ── Plain text ────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
const TEXT_MIME_TYPES = new Set([
|
|
36
|
+
"text/plain",
|
|
37
|
+
"text/csv",
|
|
38
|
+
"text/html",
|
|
39
|
+
"text/xml",
|
|
40
|
+
"text/markdown",
|
|
41
|
+
"text/yaml",
|
|
42
|
+
"text/x-yaml",
|
|
43
|
+
"application/json",
|
|
44
|
+
"application/xml",
|
|
45
|
+
"application/x-yaml",
|
|
46
|
+
"application/toml",
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
function isTextMime(mime: string): boolean {
|
|
50
|
+
return mime.startsWith("text/") || TEXT_MIME_TYPES.has(mime);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function decodeBase64Text(data: string): string {
|
|
54
|
+
return Buffer.from(data, "base64").toString("utf-8");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ── DOCX ──────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
const DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
60
|
+
|
|
61
|
+
async function convertDocx(data: string): Promise<string> {
|
|
62
|
+
const buf = Buffer.from(data, "base64");
|
|
63
|
+
const result = await mammoth.extractRawText({ buffer: buf });
|
|
64
|
+
return result.value;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── XLSX ──────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
const XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
70
|
+
|
|
71
|
+
function convertXlsx(data: string): string {
|
|
72
|
+
const buf = Buffer.from(data, "base64");
|
|
73
|
+
const workbook = XLSX.read(buf, { type: "buffer" });
|
|
74
|
+
const parts: string[] = [];
|
|
75
|
+
for (const name of workbook.SheetNames) {
|
|
76
|
+
const sheet = workbook.Sheets[name];
|
|
77
|
+
const csv = XLSX.utils.sheet_to_csv(sheet);
|
|
78
|
+
if (workbook.SheetNames.length > 1) {
|
|
79
|
+
parts.push(`## Sheet: ${name}\n\n${csv}`);
|
|
80
|
+
} else {
|
|
81
|
+
parts.push(csv);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return parts.join("\n\n");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ── PPTX (Docker/libreoffice only) ───────────────────────────
|
|
88
|
+
|
|
89
|
+
const PPTX_MIME = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
90
|
+
|
|
91
|
+
// LibreOffice runs inside the Docker sandbox image, not on the host.
|
|
92
|
+
// We spin up a temporary container to do the conversion, mounting a
|
|
93
|
+
// temp directory for input/output. On non-Docker hosts where
|
|
94
|
+
// libreoffice is installed natively, the direct path also works.
|
|
95
|
+
|
|
96
|
+
async function tryNativeLibreOffice(): Promise<boolean> {
|
|
97
|
+
try {
|
|
98
|
+
await execFileAsync("libreoffice", ["--version"], {
|
|
99
|
+
timeout: SUBPROCESS_PROBE_TIMEOUT_MS,
|
|
100
|
+
});
|
|
101
|
+
return true;
|
|
102
|
+
} catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function tryDockerLibreOffice(): Promise<boolean> {
|
|
108
|
+
try {
|
|
109
|
+
await execFileAsync("docker", ["image", "inspect", "mulmoclaude-sandbox"], {
|
|
110
|
+
timeout: SUBPROCESS_PROBE_TIMEOUT_MS,
|
|
111
|
+
});
|
|
112
|
+
return true;
|
|
113
|
+
} catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function convertPptxToPdf(data: string): Promise<Buffer | null> {
|
|
119
|
+
const tmpDir = await mkdtemp(path.join(os.tmpdir(), "pptx-"));
|
|
120
|
+
const inputPath = path.join(tmpDir, "input.pptx");
|
|
121
|
+
const outputPath = path.join(tmpDir, "input.pdf");
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
await writeFile(inputPath, Buffer.from(data, "base64"));
|
|
125
|
+
|
|
126
|
+
if (await tryNativeLibreOffice()) {
|
|
127
|
+
// Host has libreoffice installed natively
|
|
128
|
+
await execFileAsync("libreoffice", ["--headless", "--convert-to", "pdf", "--outdir", tmpDir, inputPath], { timeout: SUBPROCESS_WORK_TIMEOUT_MS });
|
|
129
|
+
} else if (await tryDockerLibreOffice()) {
|
|
130
|
+
// Use the sandbox Docker image for conversion
|
|
131
|
+
await execFileAsync(
|
|
132
|
+
"docker",
|
|
133
|
+
[
|
|
134
|
+
"run",
|
|
135
|
+
"--rm",
|
|
136
|
+
"-v",
|
|
137
|
+
`${tmpDir}:/data`,
|
|
138
|
+
"mulmoclaude-sandbox",
|
|
139
|
+
"libreoffice",
|
|
140
|
+
"--headless",
|
|
141
|
+
"--convert-to",
|
|
142
|
+
"pdf",
|
|
143
|
+
"--outdir",
|
|
144
|
+
"/data",
|
|
145
|
+
"/data/input.pptx",
|
|
146
|
+
],
|
|
147
|
+
{ timeout: SUBPROCESS_WORK_TIMEOUT_MS },
|
|
148
|
+
);
|
|
149
|
+
} else {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return await readFile(outputPath);
|
|
154
|
+
} catch {
|
|
155
|
+
return null;
|
|
156
|
+
} finally {
|
|
157
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ── Public API ────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
export type ConversionResult = { kind: "converted"; blocks: ContentBlock[] } | { kind: "skipped"; reason: string };
|
|
164
|
+
|
|
165
|
+
function textBlocks(att: Attachment, content: string): ContentBlock[] {
|
|
166
|
+
const label = att.filename ? `[File: ${att.filename}]\n\n` : "";
|
|
167
|
+
return [{ type: "text", text: `${label}${content}` }];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function tryConvertDocx(att: Attachment): Promise<ConversionResult> {
|
|
171
|
+
try {
|
|
172
|
+
return {
|
|
173
|
+
kind: "converted",
|
|
174
|
+
blocks: textBlocks(att, await convertDocx(att.data)),
|
|
175
|
+
};
|
|
176
|
+
} catch (err) {
|
|
177
|
+
return {
|
|
178
|
+
kind: "skipped",
|
|
179
|
+
reason: `DOCX conversion failed: ${errorMessage(err)}`,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function tryConvertXlsx(att: Attachment): ConversionResult {
|
|
185
|
+
try {
|
|
186
|
+
return {
|
|
187
|
+
kind: "converted",
|
|
188
|
+
blocks: textBlocks(att, convertXlsx(att.data)),
|
|
189
|
+
};
|
|
190
|
+
} catch (err) {
|
|
191
|
+
return {
|
|
192
|
+
kind: "skipped",
|
|
193
|
+
reason: `XLSX conversion failed: ${errorMessage(err)}`,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function tryConvertPptx(att: Attachment): Promise<ConversionResult> {
|
|
199
|
+
const pdfBuf = await convertPptxToPdf(att.data);
|
|
200
|
+
if (!pdfBuf) {
|
|
201
|
+
const name = att.filename ?? "presentation.pptx";
|
|
202
|
+
return {
|
|
203
|
+
kind: "converted",
|
|
204
|
+
blocks: [
|
|
205
|
+
{
|
|
206
|
+
type: "text",
|
|
207
|
+
text: `[PPTX file "${name}" attached but cannot be converted — LibreOffice is not available. Run in Docker sandbox mode for PPTX support.]`,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
kind: "converted",
|
|
214
|
+
blocks: [
|
|
215
|
+
{
|
|
216
|
+
type: "document",
|
|
217
|
+
source: {
|
|
218
|
+
type: "base64",
|
|
219
|
+
media_type: "application/pdf",
|
|
220
|
+
data: pdfBuf.toString("base64"),
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Convert an attachment into content blocks Claude can consume.
|
|
229
|
+
* Returns `{ kind: "converted", blocks }` on success, or
|
|
230
|
+
* `{ kind: "skipped", reason }` when conversion fails or the
|
|
231
|
+
* MIME type is not convertible — so the caller can distinguish
|
|
232
|
+
* "unsupported type" from "conversion error" in logs.
|
|
233
|
+
*/
|
|
234
|
+
export async function convertAttachment(att: Attachment): Promise<ConversionResult> {
|
|
235
|
+
if (isTextMime(att.mimeType)) {
|
|
236
|
+
return {
|
|
237
|
+
kind: "converted",
|
|
238
|
+
blocks: textBlocks(att, decodeBase64Text(att.data)),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
if (att.mimeType === DOCX_MIME) return tryConvertDocx(att);
|
|
242
|
+
if (att.mimeType === XLSX_MIME) return tryConvertXlsx(att);
|
|
243
|
+
if (att.mimeType === PPTX_MIME) return tryConvertPptx(att);
|
|
244
|
+
return { kind: "skipped", reason: `unsupported MIME type: ${att.mimeType}` };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** MIME types that can be converted (for UI accept list).
|
|
248
|
+
* Must stay aligned with isTextMime() + the office constants. */
|
|
249
|
+
export const CONVERTIBLE_MIME_TYPES = [
|
|
250
|
+
// Text
|
|
251
|
+
"text/plain",
|
|
252
|
+
"text/csv",
|
|
253
|
+
"text/html",
|
|
254
|
+
"text/xml",
|
|
255
|
+
"text/markdown",
|
|
256
|
+
"text/yaml",
|
|
257
|
+
"text/x-yaml",
|
|
258
|
+
"application/json",
|
|
259
|
+
"application/xml",
|
|
260
|
+
"application/x-yaml",
|
|
261
|
+
"application/toml",
|
|
262
|
+
// Office
|
|
263
|
+
DOCX_MIME,
|
|
264
|
+
XLSX_MIME,
|
|
265
|
+
PPTX_MIME,
|
|
266
|
+
] as const;
|
|
267
|
+
|
|
268
|
+
export function isConvertibleMime(mime: string): boolean {
|
|
269
|
+
return isTextMime(mime) || mime === DOCX_MIME || mime === XLSX_MIME || mime === PPTX_MIME;
|
|
270
|
+
}
|