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,46 @@
|
|
|
1
|
+
// Debug trigger endpoint for the chat indexer. The normal path is
|
|
2
|
+
// the agent `finally` hook in server/routes/agent.ts — one session
|
|
3
|
+
// at a time, with a 15-minute freshness throttle. This endpoint
|
|
4
|
+
// exists so the user can force-rebuild every session's summary on
|
|
5
|
+
// demand without restarting the server, which is useful for
|
|
6
|
+
// testing the feature against an existing workspace full of
|
|
7
|
+
// never-indexed sessions.
|
|
8
|
+
//
|
|
9
|
+
// Usage:
|
|
10
|
+
// curl -X POST http://localhost:3000/api/chat-index/rebuild
|
|
11
|
+
|
|
12
|
+
import { Router, Request, Response } from "express";
|
|
13
|
+
import { backfillAllSessions } from "../../workspace/chat-index/index.js";
|
|
14
|
+
import { log } from "../../system/logger/index.js";
|
|
15
|
+
import { serverError } from "../../utils/httpError.js";
|
|
16
|
+
import { API_ROUTES } from "../../../src/config/apiRoutes.js";
|
|
17
|
+
|
|
18
|
+
interface RebuildResponse {
|
|
19
|
+
total: number;
|
|
20
|
+
indexed: number;
|
|
21
|
+
skipped: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface RebuildErrorResponse {
|
|
25
|
+
error: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const router = Router();
|
|
29
|
+
|
|
30
|
+
router.post(API_ROUTES.chatIndex.rebuild, async (_req: Request, res: Response<RebuildResponse | RebuildErrorResponse>) => {
|
|
31
|
+
try {
|
|
32
|
+
log.info("chat-index", "manual rebuild triggered");
|
|
33
|
+
const result = await backfillAllSessions();
|
|
34
|
+
log.info("chat-index", "rebuild complete", {
|
|
35
|
+
indexed: result.indexed,
|
|
36
|
+
total: result.total,
|
|
37
|
+
skipped: result.skipped,
|
|
38
|
+
});
|
|
39
|
+
res.json(result);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
log.warn("chat-index", "rebuild failed", { error: String(err) });
|
|
42
|
+
serverError(res, err instanceof Error ? err.message : "unknown error");
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export default router;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { Router, type Request, type Response } from "express";
|
|
2
|
+
import {
|
|
3
|
+
fromMcpEntries,
|
|
4
|
+
isAppSettings,
|
|
5
|
+
loadMcpConfig,
|
|
6
|
+
loadSettings,
|
|
7
|
+
saveMcpConfig,
|
|
8
|
+
saveSettings,
|
|
9
|
+
toMcpEntries,
|
|
10
|
+
type AppSettings,
|
|
11
|
+
type McpConfigFile,
|
|
12
|
+
type McpServerEntry,
|
|
13
|
+
} from "../../system/config.js";
|
|
14
|
+
import { badRequest, serverError } from "../../utils/httpError.js";
|
|
15
|
+
import { isRecord } from "../../utils/types.js";
|
|
16
|
+
import { API_ROUTES } from "../../../src/config/apiRoutes.js";
|
|
17
|
+
import { loadCustomDirs, saveCustomDirs, ensureCustomDirs, validateCustomDirs, type CustomDirEntry } from "../../workspace/custom-dirs.js";
|
|
18
|
+
import { loadReferenceDirs, saveReferenceDirs, validateReferenceDirs, type ReferenceDirEntry } from "../../workspace/reference-dirs.js";
|
|
19
|
+
|
|
20
|
+
// Public surface of /api/config. GET returns the full config tree so
|
|
21
|
+
// the client can render every section in one request. PUT surfaces are
|
|
22
|
+
// per-section to keep payloads small and validation obvious.
|
|
23
|
+
export interface ConfigResponse {
|
|
24
|
+
settings: AppSettings;
|
|
25
|
+
mcp: { servers: McpServerEntry[] };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ConfigErrorResponse {
|
|
29
|
+
error: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type ConfigRes = Response<ConfigResponse | ConfigErrorResponse>;
|
|
33
|
+
|
|
34
|
+
function buildFullResponse(): ConfigResponse {
|
|
35
|
+
return {
|
|
36
|
+
settings: loadSettings(),
|
|
37
|
+
mcp: { servers: toMcpEntries(loadMcpConfig()) },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isMcpPutBody(value: unknown): value is { servers: McpServerEntry[] } {
|
|
42
|
+
if (!isRecord(value)) return false;
|
|
43
|
+
if (!Array.isArray(value.servers)) return false;
|
|
44
|
+
// Full shape validation happens inside fromMcpEntries (throws on
|
|
45
|
+
// anything malformed). Here we just confirm the envelope.
|
|
46
|
+
return value.servers.every((e) => isRecord(e) && "id" in e && "spec" in e);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Parse an MCP payload through `fromMcpEntries` (which does the full
|
|
50
|
+
// shape validation and throws on anything malformed). On failure,
|
|
51
|
+
// respond 400 and return null so the caller can early-return.
|
|
52
|
+
function parseMcpPayloadOrFail(res: ConfigRes, servers: McpServerEntry[]): McpConfigFile | null {
|
|
53
|
+
try {
|
|
54
|
+
return fromMcpEntries(servers);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
badRequest(res, err instanceof Error ? err.message : "invalid mcp entries");
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Run a filesystem save. On failure, respond 500 with the error's
|
|
62
|
+
// message and return false so the caller can early-return. Returns
|
|
63
|
+
// true on success.
|
|
64
|
+
function runSaveOrFail(res: ConfigRes, save: () => void, fallback: string): boolean {
|
|
65
|
+
try {
|
|
66
|
+
save();
|
|
67
|
+
return true;
|
|
68
|
+
} catch (err) {
|
|
69
|
+
serverError(res, err instanceof Error ? err.message : fallback);
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const router = Router();
|
|
75
|
+
|
|
76
|
+
router.get(API_ROUTES.config.base, (_req: Request, res: Response<ConfigResponse>) => {
|
|
77
|
+
res.json(buildFullResponse());
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Atomic save for both settings and MCP. Validates both payloads first
|
|
81
|
+
// (no writes happen until every input is known-good), then writes
|
|
82
|
+
// settings and captures the previous state so a subsequent saveMcpConfig
|
|
83
|
+
// failure can roll back. This is the endpoint the Settings modal should
|
|
84
|
+
// use; the per-section PUTs below remain for targeted updates.
|
|
85
|
+
interface PutConfigBody {
|
|
86
|
+
settings: AppSettings;
|
|
87
|
+
mcp: { servers: McpServerEntry[] };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function isPutConfigBody(value: unknown): value is PutConfigBody {
|
|
91
|
+
if (!isRecord(value)) return false;
|
|
92
|
+
return isAppSettings(value.settings) && isMcpPutBody(value.mcp);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
router.put(API_ROUTES.config.base, (req: Request<unknown, unknown, PutConfigBody>, res: ConfigRes) => {
|
|
96
|
+
const body = req.body;
|
|
97
|
+
if (!isPutConfigBody(body)) {
|
|
98
|
+
badRequest(res, "Invalid config payload");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const mcpCfg = parseMcpPayloadOrFail(res, body.mcp.servers);
|
|
102
|
+
if (!mcpCfg) return;
|
|
103
|
+
|
|
104
|
+
// Snapshot previous settings so we can roll back if the second
|
|
105
|
+
// write fails — a cross-file atomic write isn't possible, but
|
|
106
|
+
// rollback keeps the pair consistent from the user's perspective.
|
|
107
|
+
const previousSettings = loadSettings();
|
|
108
|
+
if (!runSaveOrFail(res, () => saveSettings(body.settings), "saveSettings failed")) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (!runSaveOrFail(res, () => saveMcpConfig(mcpCfg), "saveMcpConfig failed")) {
|
|
112
|
+
// Best-effort rollback; if it fails too, the original mcp error
|
|
113
|
+
// is already on the wire.
|
|
114
|
+
try {
|
|
115
|
+
saveSettings(previousSettings);
|
|
116
|
+
} catch {
|
|
117
|
+
/* swallow — original error already sent */
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
res.json(buildFullResponse());
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
router.put(API_ROUTES.config.settings, (req: Request<unknown, unknown, AppSettings>, res: ConfigRes) => {
|
|
125
|
+
const body = req.body;
|
|
126
|
+
if (!isAppSettings(body)) {
|
|
127
|
+
badRequest(res, "Invalid AppSettings payload");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!runSaveOrFail(res, () => saveSettings(body), "saveSettings failed")) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
res.json(buildFullResponse());
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
router.put(API_ROUTES.config.mcp, (req: Request<unknown, unknown, { servers: McpServerEntry[] }>, res: ConfigRes) => {
|
|
137
|
+
const body = req.body;
|
|
138
|
+
if (!isMcpPutBody(body)) {
|
|
139
|
+
badRequest(res, "Invalid mcp payload envelope");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// fromMcpEntries rejects malformed client input (400). saveMcpConfig
|
|
143
|
+
// can fail for server-side reasons like disk/permission errors (500).
|
|
144
|
+
const cfg = parseMcpPayloadOrFail(res, body.servers);
|
|
145
|
+
if (!cfg) return;
|
|
146
|
+
if (!runSaveOrFail(res, () => saveMcpConfig(cfg), "saveMcpConfig failed")) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
res.json(buildFullResponse());
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// ── Workspace custom directories (#239) ──────────────────────────
|
|
153
|
+
|
|
154
|
+
router.get(API_ROUTES.config.workspaceDirs, (_req: Request, res: Response<{ dirs: CustomDirEntry[] }>) => {
|
|
155
|
+
res.json({ dirs: loadCustomDirs() });
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
router.put(
|
|
159
|
+
API_ROUTES.config.workspaceDirs,
|
|
160
|
+
(req: Request<unknown, unknown, { dirs: unknown }>, res: Response<{ dirs: CustomDirEntry[] } | ConfigErrorResponse>) => {
|
|
161
|
+
const body = req.body;
|
|
162
|
+
if (!isRecord(body) || !("dirs" in body)) {
|
|
163
|
+
badRequest(res, "expected { dirs: [...] }");
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const result = validateCustomDirs(body.dirs);
|
|
167
|
+
if ("error" in result) {
|
|
168
|
+
badRequest(res, result.error);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
saveCustomDirs(result.entries);
|
|
173
|
+
ensureCustomDirs(result.entries);
|
|
174
|
+
res.json({ dirs: result.entries });
|
|
175
|
+
} catch (err) {
|
|
176
|
+
serverError(res, err instanceof Error ? err.message : "save failed");
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
// ── Reference directories (#455) ────────────────────────────────
|
|
182
|
+
|
|
183
|
+
router.get(API_ROUTES.config.referenceDirs, (_req: Request, res: Response<{ dirs: ReferenceDirEntry[] }>) => {
|
|
184
|
+
res.json({ dirs: loadReferenceDirs() });
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
router.put(
|
|
188
|
+
API_ROUTES.config.referenceDirs,
|
|
189
|
+
(req: Request<unknown, unknown, { dirs: unknown }>, res: Response<{ dirs: ReferenceDirEntry[] } | ConfigErrorResponse>) => {
|
|
190
|
+
const body = req.body;
|
|
191
|
+
if (!isRecord(body) || !("dirs" in body)) {
|
|
192
|
+
badRequest(res, "expected { dirs: [...] }");
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const result = validateReferenceDirs(body.dirs);
|
|
196
|
+
if ("error" in result) {
|
|
197
|
+
badRequest(res, result.error);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
saveReferenceDirs(result.entries);
|
|
202
|
+
res.json({ dirs: result.entries });
|
|
203
|
+
} catch (err) {
|
|
204
|
+
serverError(res, err instanceof Error ? err.message : "save failed");
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
// ── Scheduler overrides (#493) ──────────────────────────────────
|
|
210
|
+
|
|
211
|
+
import { loadSchedulerOverrides, saveSchedulerOverrides, UTC_HH_MM_RE, type ScheduleOverrides } from "../../utils/files/scheduler-overrides-io.js";
|
|
212
|
+
import { applyScheduleOverride } from "../../events/scheduler-adapter.js";
|
|
213
|
+
import { SCHEDULE_TYPES } from "@receptron/task-scheduler";
|
|
214
|
+
|
|
215
|
+
router.get(API_ROUTES.config.schedulerOverrides, (_req: Request, res: Response<{ overrides: ScheduleOverrides }>) => {
|
|
216
|
+
res.json({ overrides: loadSchedulerOverrides() });
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
router.put(
|
|
220
|
+
API_ROUTES.config.schedulerOverrides,
|
|
221
|
+
async (req: Request<unknown, unknown, { overrides: unknown }>, res: Response<{ overrides: ScheduleOverrides } | ConfigErrorResponse>) => {
|
|
222
|
+
const body = req.body;
|
|
223
|
+
if (!isRecord(body) || !("overrides" in body)) {
|
|
224
|
+
badRequest(res, "expected { overrides: { ... } }");
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const raw = body.overrides;
|
|
228
|
+
if (!isRecord(raw)) {
|
|
229
|
+
badRequest(res, "overrides must be an object");
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const overrides = raw as ScheduleOverrides;
|
|
233
|
+
try {
|
|
234
|
+
saveSchedulerOverrides(overrides);
|
|
235
|
+
|
|
236
|
+
// Apply to running task-manager immediately
|
|
237
|
+
for (const [taskId, ovr] of Object.entries(overrides)) {
|
|
238
|
+
if (typeof ovr.intervalMs === "number" && ovr.intervalMs > 0) {
|
|
239
|
+
await applyScheduleOverride(taskId, {
|
|
240
|
+
type: SCHEDULE_TYPES.interval,
|
|
241
|
+
intervalMs: ovr.intervalMs,
|
|
242
|
+
});
|
|
243
|
+
} else if (typeof ovr.time === "string" && UTC_HH_MM_RE.test(ovr.time)) {
|
|
244
|
+
await applyScheduleOverride(taskId, {
|
|
245
|
+
type: SCHEDULE_TYPES.daily,
|
|
246
|
+
time: ovr.time,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
res.json({ overrides: loadSchedulerOverrides() });
|
|
252
|
+
} catch (err) {
|
|
253
|
+
serverError(res, err instanceof Error ? err.message : "save failed");
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
export default router;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Shared HTTP response plumbing for dispatcher-style POST routes
|
|
2
|
+
// (currently todos and scheduler). Both routes follow the same
|
|
3
|
+
// pattern: load items, run a pure dispatch function that returns a
|
|
4
|
+
// discriminated `{ kind: "error" | "success" }` result, persist on
|
|
5
|
+
// success when applicable, and translate to JSON. This module owns
|
|
6
|
+
// the translation step so each route handler stays a few lines.
|
|
7
|
+
|
|
8
|
+
import type { Response } from "express";
|
|
9
|
+
import { errorMessage } from "../../utils/errors.js";
|
|
10
|
+
import { sendError, serverError } from "../../utils/httpError.js";
|
|
11
|
+
|
|
12
|
+
export type DispatchResult<T> =
|
|
13
|
+
| { kind: "error"; status: number; error: string }
|
|
14
|
+
| {
|
|
15
|
+
kind: "success";
|
|
16
|
+
items: T[];
|
|
17
|
+
message: string;
|
|
18
|
+
jsonData: Record<string, unknown>;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export interface DispatchSuccessResponse<T> {
|
|
22
|
+
data: { items: T[] };
|
|
23
|
+
message: string;
|
|
24
|
+
jsonData: Record<string, unknown>;
|
|
25
|
+
instructions: string;
|
|
26
|
+
updating: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface DispatchErrorResponse {
|
|
30
|
+
error: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface RespondOptions<T> {
|
|
34
|
+
// Whether to call the persist callback before responding. Different
|
|
35
|
+
// routes have different read-only action rules (e.g. todos has a
|
|
36
|
+
// READ_ONLY_ACTIONS set, scheduler exempts only "show"), so the
|
|
37
|
+
// caller decides per-request.
|
|
38
|
+
shouldPersist: boolean;
|
|
39
|
+
// Per-route instructions string baked into the response.
|
|
40
|
+
instructions: string;
|
|
41
|
+
// Persistence callback. Called with the post-dispatch items only
|
|
42
|
+
// when shouldPersist is true.
|
|
43
|
+
persist: (items: T[]) => void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Translate a DispatchResult into the JSON response shape used by
|
|
47
|
+
// dispatcher-style routes. Side-effects: calls `options.persist` on
|
|
48
|
+
// success when `options.shouldPersist` is true; writes the response.
|
|
49
|
+
//
|
|
50
|
+
// Persistence failures are caught and translated into a structured
|
|
51
|
+
// 500 JSON error so the route's response contract stays consistent —
|
|
52
|
+
// otherwise an fs.writeFileSync throw would bubble out and trigger
|
|
53
|
+
// Express's default HTML error page instead of the JSON shape that
|
|
54
|
+
// clients expect.
|
|
55
|
+
export function respondWithDispatchResult<T>(
|
|
56
|
+
res: Response<DispatchSuccessResponse<T> | DispatchErrorResponse>,
|
|
57
|
+
result: DispatchResult<T>,
|
|
58
|
+
options: RespondOptions<T>,
|
|
59
|
+
): void {
|
|
60
|
+
if (result.kind === "error") {
|
|
61
|
+
sendError(res, result.status, result.error);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (options.shouldPersist) {
|
|
65
|
+
try {
|
|
66
|
+
options.persist(result.items);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
serverError(res, `Failed to persist changes: ${errorMessage(err)}`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
res.json({
|
|
73
|
+
data: { items: result.items },
|
|
74
|
+
message: result.message,
|
|
75
|
+
jsonData: result.jsonData,
|
|
76
|
+
instructions: options.instructions,
|
|
77
|
+
updating: true,
|
|
78
|
+
});
|
|
79
|
+
}
|