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,61 @@
|
|
|
1
|
+
import type { ToolPlugin } from "../../tools/types";
|
|
2
|
+
import type { ToolResult } from "gui-chat-protocol";
|
|
3
|
+
import View from "./View.vue";
|
|
4
|
+
import Preview from "./Preview.vue";
|
|
5
|
+
import toolDefinition from "./definition";
|
|
6
|
+
import { apiPost } from "../../utils/api";
|
|
7
|
+
import { API_ROUTES } from "../../config/apiRoutes";
|
|
8
|
+
|
|
9
|
+
export type TodoPriority = "low" | "medium" | "high" | "urgent";
|
|
10
|
+
|
|
11
|
+
export interface TodoItem {
|
|
12
|
+
id: string;
|
|
13
|
+
text: string;
|
|
14
|
+
note?: string;
|
|
15
|
+
labels?: string[];
|
|
16
|
+
completed: boolean;
|
|
17
|
+
createdAt: number;
|
|
18
|
+
// ── Added for the file-explorer kanban view ──
|
|
19
|
+
status?: string;
|
|
20
|
+
priority?: TodoPriority;
|
|
21
|
+
dueDate?: string;
|
|
22
|
+
order?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface StatusColumn {
|
|
26
|
+
id: string;
|
|
27
|
+
label: string;
|
|
28
|
+
isDone?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface TodoData {
|
|
32
|
+
items: TodoItem[];
|
|
33
|
+
columns?: StatusColumn[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const todoPlugin: ToolPlugin<TodoData> = {
|
|
37
|
+
toolDefinition,
|
|
38
|
+
|
|
39
|
+
async execute(_context, args) {
|
|
40
|
+
const result = await apiPost<ToolResult<TodoData>>(API_ROUTES.todos.dispatch, args);
|
|
41
|
+
if (!result.ok) {
|
|
42
|
+
return {
|
|
43
|
+
toolName: "manageTodoList",
|
|
44
|
+
uuid: crypto.randomUUID(),
|
|
45
|
+
message: result.error,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
...result.data,
|
|
50
|
+
toolName: "manageTodoList",
|
|
51
|
+
uuid: result.data.uuid ?? crypto.randomUUID(),
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
isEnabled: () => true,
|
|
56
|
+
generatingMessage: "Managing todos...",
|
|
57
|
+
viewComponent: View,
|
|
58
|
+
previewComponent: Preview,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export default todoPlugin;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// Pure helpers for todo labels. Used by both the server route
|
|
2
|
+
// (server/routes/todos.ts) and the Vue views (View.vue / Preview.vue),
|
|
3
|
+
// so the file is kept free of Node-only and browser-only APIs.
|
|
4
|
+
//
|
|
5
|
+
// Storage contract:
|
|
6
|
+
// - Labels are case-preserving strings (e.g. "Work", "Groceries")
|
|
7
|
+
// - Matching / deduplication is case-insensitive
|
|
8
|
+
// - Whitespace is trimmed and collapsed on normalise
|
|
9
|
+
// - Empty / whitespace-only labels are rejected
|
|
10
|
+
|
|
11
|
+
// ── Normalisation and comparison ──────────────────────────────────
|
|
12
|
+
|
|
13
|
+
// Trim leading/trailing whitespace and collapse internal whitespace
|
|
14
|
+
// runs to single spaces. Returns `null` for empty / whitespace-only
|
|
15
|
+
// input so callers can filter out bad entries at the boundary.
|
|
16
|
+
export function normalizeLabel(raw: string): string | null {
|
|
17
|
+
const collapsed = raw.replace(/\s+/g, " ").trim();
|
|
18
|
+
return collapsed.length > 0 ? collapsed : null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Case-insensitive label equality. Both inputs are normalised first
|
|
22
|
+
// so `" Work "` and `"work"` compare equal.
|
|
23
|
+
export function labelsEqual(left: string, right: string): boolean {
|
|
24
|
+
const normLeft = normalizeLabel(left);
|
|
25
|
+
const normRight = normalizeLabel(right);
|
|
26
|
+
if (normLeft === null || normRight === null) return false;
|
|
27
|
+
return normLeft.toLowerCase() === normRight.toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ── Colour assignment ─────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
// Eight Tailwind pastel chip styles. Enough visual variety without
|
|
33
|
+
// turning the UI into a rainbow. Every label maps deterministically
|
|
34
|
+
// to one of these via `colorForLabel`.
|
|
35
|
+
export const LABEL_PALETTE: readonly string[] = [
|
|
36
|
+
"bg-blue-100 text-blue-700",
|
|
37
|
+
"bg-green-100 text-green-700",
|
|
38
|
+
"bg-purple-100 text-purple-700",
|
|
39
|
+
"bg-yellow-100 text-yellow-700",
|
|
40
|
+
"bg-pink-100 text-pink-700",
|
|
41
|
+
"bg-indigo-100 text-indigo-700",
|
|
42
|
+
"bg-red-100 text-red-700",
|
|
43
|
+
"bg-teal-100 text-teal-700",
|
|
44
|
+
] as const;
|
|
45
|
+
|
|
46
|
+
// Deterministic colour class for a label. Same label → same colour
|
|
47
|
+
// across sessions and across clients. Case-insensitive so that
|
|
48
|
+
// `"Work"` and `"work"` look identical even if they drift in
|
|
49
|
+
// different items over time.
|
|
50
|
+
export function colorForLabel(label: string): string {
|
|
51
|
+
const key = label.toLowerCase();
|
|
52
|
+
let hash = 0;
|
|
53
|
+
for (let i = 0; i < key.length; i++) {
|
|
54
|
+
// Classic 31-multiplier string hash. Kept as unsigned via >>> 0
|
|
55
|
+
// so the modulo at the end doesn't produce negatives.
|
|
56
|
+
hash = (hash * 31 + key.charCodeAt(i)) >>> 0;
|
|
57
|
+
}
|
|
58
|
+
return LABEL_PALETTE[hash % LABEL_PALETTE.length];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ── Filtering ─────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
// OR-semantics filter: return items that have at least one label in
|
|
64
|
+
// `filterLabels`. Matching is case-insensitive. An empty filter list
|
|
65
|
+
// is a pass-through — callers don't need to special-case "no filter"
|
|
66
|
+
// themselves.
|
|
67
|
+
//
|
|
68
|
+
// Items whose `labels` is `undefined` or `[]` are excluded when
|
|
69
|
+
// `filterLabels` is non-empty, since they have nothing to match.
|
|
70
|
+
export function filterByLabels<T extends { labels?: string[] }>(items: readonly T[], filterLabels: readonly string[]): T[] {
|
|
71
|
+
if (filterLabels.length === 0) return [...items];
|
|
72
|
+
const wanted = new Set(
|
|
73
|
+
filterLabels
|
|
74
|
+
.map(normalizeLabel)
|
|
75
|
+
.filter((label): label is string => label !== null)
|
|
76
|
+
.map((label) => label.toLowerCase()),
|
|
77
|
+
);
|
|
78
|
+
if (wanted.size === 0) return [...items];
|
|
79
|
+
return items.filter((item) => {
|
|
80
|
+
const itemLabels = item.labels ?? [];
|
|
81
|
+
return itemLabels.some((label) => {
|
|
82
|
+
const normalized = normalizeLabel(label);
|
|
83
|
+
return normalized !== null && wanted.has(normalized.toLowerCase());
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ── Label inventory ──────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
// Distinct-label summary for the whole collection. Counts are
|
|
91
|
+
// case-insensitive: `"Work"` and `"work"` merge into one row. The
|
|
92
|
+
// displayed form is the first spelling encountered while scanning,
|
|
93
|
+
// which is usually the most recently added item at the top of the
|
|
94
|
+
// list — stable enough in practice and avoids a second full pass.
|
|
95
|
+
//
|
|
96
|
+
// Sorted by count desc, then by the displayed label asc (case-
|
|
97
|
+
// insensitive) for deterministic output.
|
|
98
|
+
export function listLabelsWithCount(items: readonly { labels?: string[] }[]): Array<{ label: string; count: number }> {
|
|
99
|
+
const groups = new Map<string, { label: string; count: number }>();
|
|
100
|
+
for (const item of items) {
|
|
101
|
+
const seenInItem = new Set<string>();
|
|
102
|
+
for (const raw of item.labels ?? []) {
|
|
103
|
+
const normalized = normalizeLabel(raw);
|
|
104
|
+
if (normalized === null) continue;
|
|
105
|
+
const key = normalized.toLowerCase();
|
|
106
|
+
// Guard against the same label appearing twice within one item
|
|
107
|
+
// (shouldn't happen post-mergeLabels but be safe).
|
|
108
|
+
if (seenInItem.has(key)) continue;
|
|
109
|
+
seenInItem.add(key);
|
|
110
|
+
const existing = groups.get(key);
|
|
111
|
+
if (existing) {
|
|
112
|
+
existing.count++;
|
|
113
|
+
} else {
|
|
114
|
+
groups.set(key, { label: normalized, count: 1 });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return [...groups.values()].sort((left, right) => {
|
|
119
|
+
if (right.count !== left.count) return right.count - left.count;
|
|
120
|
+
return left.label.toLowerCase() < right.label.toLowerCase() ? -1 : left.label.toLowerCase() > right.label.toLowerCase() ? 1 : 0;
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ── Set operations (for add_label / remove_label) ────────────────
|
|
125
|
+
|
|
126
|
+
// Union of `existing` and `adding`, de-duped case-insensitively.
|
|
127
|
+
// Preserves the order of `existing`, then appends newly-introduced
|
|
128
|
+
// labels in the order they appear in `adding`. Normalises both
|
|
129
|
+
// sides (trim/collapse) before comparison and storage.
|
|
130
|
+
export function mergeLabels(existing: readonly string[], adding: readonly string[]): string[] {
|
|
131
|
+
const result: string[] = [];
|
|
132
|
+
const seen = new Set<string>();
|
|
133
|
+
const push = (label: string): void => {
|
|
134
|
+
const normalized = normalizeLabel(label);
|
|
135
|
+
if (normalized === null) return;
|
|
136
|
+
const key = normalized.toLowerCase();
|
|
137
|
+
if (seen.has(key)) return;
|
|
138
|
+
seen.add(key);
|
|
139
|
+
result.push(normalized);
|
|
140
|
+
};
|
|
141
|
+
for (const label of existing) push(label);
|
|
142
|
+
for (const label of adding) push(label);
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Remove `removing` labels from `existing`, case-insensitively.
|
|
147
|
+
// Removing a label that isn't present is a no-op. The order of
|
|
148
|
+
// surviving labels is preserved. Normalises both sides first.
|
|
149
|
+
export function subtractLabels(existing: readonly string[], removing: readonly string[]): string[] {
|
|
150
|
+
const toRemove = new Set(
|
|
151
|
+
removing
|
|
152
|
+
.map(normalizeLabel)
|
|
153
|
+
.filter((label): label is string => label !== null)
|
|
154
|
+
.map((label) => label.toLowerCase()),
|
|
155
|
+
);
|
|
156
|
+
if (toRemove.size === 0) {
|
|
157
|
+
return existing.map(normalizeLabel).filter((label): label is string => label !== null);
|
|
158
|
+
}
|
|
159
|
+
return existing
|
|
160
|
+
.map(normalizeLabel)
|
|
161
|
+
.filter((label): label is string => label !== null)
|
|
162
|
+
.filter((label) => !toRemove.has(label.toLowerCase()));
|
|
163
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Pure helpers for the todo `priority` field. Used by the kanban
|
|
2
|
+
// cards, the table view, and any future plugin code that needs to
|
|
3
|
+
// render a priority badge — kept dependency-free so both the server
|
|
4
|
+
// and the browser can import it.
|
|
5
|
+
|
|
6
|
+
import type { TodoPriority } from "./index";
|
|
7
|
+
|
|
8
|
+
export const PRIORITY_ORDER: Record<TodoPriority, number> = {
|
|
9
|
+
low: 0,
|
|
10
|
+
medium: 1,
|
|
11
|
+
high: 2,
|
|
12
|
+
urgent: 3,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Display label for each priority level. Capitalised so it reads well
|
|
16
|
+
// in chips / dropdowns without further formatting at the call site.
|
|
17
|
+
export const PRIORITY_LABELS: Record<TodoPriority, string> = {
|
|
18
|
+
low: "Low",
|
|
19
|
+
medium: "Medium",
|
|
20
|
+
high: "High",
|
|
21
|
+
urgent: "Urgent",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Tailwind classes for the priority chip backgrounds. Picked to be
|
|
25
|
+
// distinguishable at small sizes without competing too hard with the
|
|
26
|
+
// label colours from labels.ts.
|
|
27
|
+
export const PRIORITY_CLASSES: Record<TodoPriority, string> = {
|
|
28
|
+
low: "bg-slate-100 text-slate-600",
|
|
29
|
+
medium: "bg-sky-100 text-sky-700",
|
|
30
|
+
high: "bg-orange-100 text-orange-700",
|
|
31
|
+
urgent: "bg-red-100 text-red-700",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Tailwind border-color classes for the kanban card left border.
|
|
35
|
+
// Slightly bolder than the chip palette so a card with no labels still
|
|
36
|
+
// shows priority at a glance.
|
|
37
|
+
export const PRIORITY_BORDER: Record<TodoPriority, string> = {
|
|
38
|
+
low: "border-l-slate-300",
|
|
39
|
+
medium: "border-l-sky-400",
|
|
40
|
+
high: "border-l-orange-400",
|
|
41
|
+
urgent: "border-l-red-500",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const PRIORITIES: readonly TodoPriority[] = ["low", "medium", "high", "urgent"];
|
|
45
|
+
|
|
46
|
+
export function isPriority(value: unknown): value is TodoPriority {
|
|
47
|
+
// Use hasOwnProperty rather than the `in` operator: `in` walks the
|
|
48
|
+
// prototype chain, so `"toString" in PRIORITY_ORDER` would return
|
|
49
|
+
// true and incorrectly narrow `"toString"` to TodoPriority. We use
|
|
50
|
+
// the .call form (rather than Object.hasOwn) because the project's
|
|
51
|
+
// client tsconfig targets ES2021, and Object.hasOwn is ES2022.
|
|
52
|
+
return typeof value === "string" && Object.prototype.hasOwnProperty.call(PRIORITY_ORDER, value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ── due date helpers ─────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
// Returns a Tailwind class string for a due-date badge based on how
|
|
58
|
+
// far the date is from today. The 4 buckets match what GitHub
|
|
59
|
+
// Projects shows in its kanban view.
|
|
60
|
+
export function dueDateClasses(dueDate: string | undefined): string {
|
|
61
|
+
if (!dueDate) return "";
|
|
62
|
+
const today = todayISO();
|
|
63
|
+
if (dueDate < today) return "bg-red-100 text-red-700";
|
|
64
|
+
if (dueDate === today) return "bg-orange-100 text-orange-700";
|
|
65
|
+
// Within 3 days?
|
|
66
|
+
const todayDate = new Date(today);
|
|
67
|
+
const dueDateObj = new Date(dueDate);
|
|
68
|
+
const diffDays = Math.round((dueDateObj.getTime() - todayDate.getTime()) / (1000 * 60 * 60 * 24));
|
|
69
|
+
if (diffDays <= 3) return "bg-yellow-100 text-yellow-700";
|
|
70
|
+
return "bg-gray-100 text-gray-600";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Today's date as YYYY-MM-DD in the user's local timezone. Avoiding
|
|
74
|
+
// `toISOString` here on purpose: that returns UTC, which would flip
|
|
75
|
+
// the day boundary for users west of UTC and lead to "due today"
|
|
76
|
+
// flickering at midnight.
|
|
77
|
+
export function todayISO(): string {
|
|
78
|
+
const now = new Date();
|
|
79
|
+
const yyyy = now.getFullYear();
|
|
80
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
81
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
82
|
+
return `${yyyy}-${month}-${day}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Pretty short label for the kanban card badges. "2026-04-12" →
|
|
86
|
+
// "Apr 12". Year is omitted unless it differs from the current one.
|
|
87
|
+
export function formatDueLabel(dueDate: string | undefined): string {
|
|
88
|
+
if (!dueDate) return "";
|
|
89
|
+
const date = new Date(`${dueDate}T00:00:00`);
|
|
90
|
+
if (Number.isNaN(date.getTime())) return dueDate;
|
|
91
|
+
const today = new Date();
|
|
92
|
+
const sameYear = date.getFullYear() === today.getFullYear();
|
|
93
|
+
return date.toLocaleDateString(undefined, {
|
|
94
|
+
month: "short",
|
|
95
|
+
day: "numeric",
|
|
96
|
+
...(sameYear ? {} : { year: "numeric" }),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// View mode constants for the Todo Explorer.
|
|
2
|
+
|
|
3
|
+
export const TODO_VIEW = {
|
|
4
|
+
kanban: "kanban",
|
|
5
|
+
table: "table",
|
|
6
|
+
list: "list",
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
export type TodoViewMode = (typeof TODO_VIEW)[keyof typeof TODO_VIEW];
|
|
10
|
+
|
|
11
|
+
export const TODO_VIEW_MODES: {
|
|
12
|
+
key: TodoViewMode;
|
|
13
|
+
label: string;
|
|
14
|
+
icon: string;
|
|
15
|
+
}[] = [
|
|
16
|
+
{ key: TODO_VIEW.kanban, label: "Kanban", icon: "view_kanban" },
|
|
17
|
+
{ key: TODO_VIEW.table, label: "Table", icon: "table_rows" },
|
|
18
|
+
{ key: TODO_VIEW.list, label: "List", icon: "view_list" },
|
|
19
|
+
];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="min-h-24 flex items-center justify-center">
|
|
3
|
+
<img v-if="resolvedSrc" :src="resolvedSrc" class="max-w-full h-auto rounded" :alt="alt" />
|
|
4
|
+
<div v-else class="text-gray-400 text-sm">No image yet</div>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup lang="ts">
|
|
9
|
+
import { computed } from "vue";
|
|
10
|
+
import type { ToolResult } from "gui-chat-protocol/vue";
|
|
11
|
+
import type { ImageToolData } from "./types";
|
|
12
|
+
import { resolveImageSrc } from "../../utils/image/resolve";
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(
|
|
15
|
+
defineProps<{
|
|
16
|
+
result: ToolResult<ImageToolData>;
|
|
17
|
+
alt?: string;
|
|
18
|
+
}>(),
|
|
19
|
+
{ alt: "Image" },
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const resolvedSrc = computed(() => (props.result.data?.imageData ? resolveImageSrc(props.result.data.imageData) : ""));
|
|
23
|
+
</script>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full h-full overflow-y-auto">
|
|
3
|
+
<div class="min-h-full flex flex-col items-center justify-center p-4">
|
|
4
|
+
<div v-if="resolvedSrc" class="flex-1 flex items-center justify-center min-h-0">
|
|
5
|
+
<img :src="resolvedSrc" class="max-w-full max-h-full object-contain rounded" :alt="alt" />
|
|
6
|
+
</div>
|
|
7
|
+
<div v-else class="flex-1 flex items-center justify-center text-gray-400 text-sm">No image yet</div>
|
|
8
|
+
<div v-if="selectedResult.data?.prompt" class="mt-4 p-3 bg-gray-100 rounded-lg max-w-full flex-shrink-0">
|
|
9
|
+
<p class="text-sm text-gray-700">
|
|
10
|
+
<span class="font-medium">{{ promptLabel }}:</span>
|
|
11
|
+
{{ selectedResult.data.prompt }}
|
|
12
|
+
</p>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
import { computed } from "vue";
|
|
20
|
+
import type { ToolResult } from "gui-chat-protocol/vue";
|
|
21
|
+
import type { ImageToolData } from "./types";
|
|
22
|
+
import { resolveImageSrc } from "../../utils/image/resolve";
|
|
23
|
+
|
|
24
|
+
const props = withDefaults(
|
|
25
|
+
defineProps<{
|
|
26
|
+
selectedResult: ToolResult<ImageToolData>;
|
|
27
|
+
alt?: string;
|
|
28
|
+
promptLabel?: string;
|
|
29
|
+
}>(),
|
|
30
|
+
{ alt: "Image", promptLabel: "Prompt" },
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const resolvedSrc = computed(() => (props.selectedResult.data?.imageData ? resolveImageSrc(props.selectedResult.data.imageData) : ""));
|
|
34
|
+
</script>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="text-sm">
|
|
3
|
+
<div class="flex items-center gap-1 font-medium text-gray-700 mb-1">
|
|
4
|
+
<span class="material-icons" style="font-size: 14px">menu_book</span>
|
|
5
|
+
<span>{{ label }}</span>
|
|
6
|
+
</div>
|
|
7
|
+
<div v-for="entry in previewEntries" :key="entry.slug" class="text-xs text-gray-500 truncate">
|
|
8
|
+
{{ entry.title }}
|
|
9
|
+
</div>
|
|
10
|
+
<div v-if="more > 0" class="text-xs text-gray-400">+ {{ more }} more…</div>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { computed, ref, watch } from "vue";
|
|
16
|
+
import type { ToolResultComplete } from "gui-chat-protocol/vue";
|
|
17
|
+
import type { WikiData, WikiPageEntry } from "./index";
|
|
18
|
+
import { useFreshPluginData } from "../../composables/useFreshPluginData";
|
|
19
|
+
import { API_ROUTES } from "../../config/apiRoutes";
|
|
20
|
+
|
|
21
|
+
const props = defineProps<{ result: ToolResultComplete<WikiData> }>();
|
|
22
|
+
|
|
23
|
+
const action = ref(props.result.data?.action ?? "index");
|
|
24
|
+
const title = ref(props.result.data?.title ?? "Wiki");
|
|
25
|
+
const pageEntries = ref<WikiPageEntry[]>(props.result.data?.pageEntries ?? []);
|
|
26
|
+
|
|
27
|
+
const { refresh } = useFreshPluginData<WikiData>({
|
|
28
|
+
endpoint: () => API_ROUTES.wiki.base,
|
|
29
|
+
extract: (json) => (json as { data?: WikiData }).data ?? null,
|
|
30
|
+
apply: (data) => {
|
|
31
|
+
// Bug fix (CodeRabbit V1 #6): /api/wiki (no slug) always
|
|
32
|
+
// returns the index payload. The Preview component is reused
|
|
33
|
+
// for page / log / lint_report previews as well, so blindly
|
|
34
|
+
// overwriting action/title/pageEntries would clobber non-index
|
|
35
|
+
// previews with "Wiki Index" the moment the fetch resolves.
|
|
36
|
+
// Only apply when this preview is currently showing the index.
|
|
37
|
+
if (action.value !== "index") return;
|
|
38
|
+
title.value = data.title ?? "Wiki";
|
|
39
|
+
pageEntries.value = data.pageEntries ?? [];
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
watch(
|
|
44
|
+
() => props.result.uuid,
|
|
45
|
+
() => {
|
|
46
|
+
const d = props.result.data;
|
|
47
|
+
if (d) {
|
|
48
|
+
action.value = d.action ?? "index";
|
|
49
|
+
title.value = d.title ?? "Wiki";
|
|
50
|
+
pageEntries.value = d.pageEntries ?? [];
|
|
51
|
+
}
|
|
52
|
+
void refresh();
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const label = computed(() => {
|
|
57
|
+
if (action.value === "index") return `Wiki Index (${pageEntries.value.length} pages)`;
|
|
58
|
+
if (action.value === "log") return "Wiki Log";
|
|
59
|
+
if (action.value === "lint_report") return "Wiki Lint";
|
|
60
|
+
return `Wiki: ${title.value}`;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const previewEntries = computed(() => pageEntries.value.slice(0, 3));
|
|
64
|
+
const more = computed(() => Math.max(0, pageEntries.value.length - 3));
|
|
65
|
+
</script>
|