mulmoclaude 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile.sandbox +100 -0
- package/README.md +17 -4
- package/bin/mulmoclaude.js +46 -15
- package/bin/prepare-dist.js +18 -2
- package/client/assets/chunk-CernVdwh.js +1 -0
- package/client/assets/chunk-D8eiyYIV-C1eAZMzz.js +1 -0
- package/client/assets/html2canvas-CDGcmOD3-BbPeutDg.js +5 -0
- package/client/assets/index-BbgSjFQ8.js +4968 -0
- package/client/assets/index-ECD0lgIv.css +2 -0
- package/client/assets/{index.es-D4YyL_Dg-BgT6a3Nd.js → index.es-DqtpmBm8-DJdTPdnc.js} +5 -5
- package/client/assets/material-symbols-outlined-BLDfUw-_.woff2 +0 -0
- package/client/assets/runtime-protocol-vue-6WYa8hAs.js +1 -0
- package/client/assets/runtime-vue-BVUzgYGA.js +1 -0
- package/client/assets/typeof-DBp4T-Ny-C2xoZtcz.js +1 -0
- package/client/assets/vue-1e_vz2LW.js +1 -0
- package/client/assets/vue.runtime.esm-bundler-DQ8Kjjui.js +4 -0
- package/client/index.html +33 -2
- package/package.json +20 -18
- package/sandbox-entrypoint.sh +106 -0
- package/server/accounting/accountNormalize.ts +32 -0
- package/server/accounting/defaultAccounts.ts +87 -0
- package/server/accounting/eventPublisher.ts +51 -0
- package/server/accounting/journal.ts +252 -0
- package/server/accounting/openingBalances.ts +114 -0
- package/server/accounting/report.ts +237 -0
- package/server/accounting/service.ts +718 -0
- package/server/accounting/snapshotCache.ts +333 -0
- package/server/accounting/timeSeries.ts +265 -0
- package/server/accounting/types.ts +148 -0
- package/server/agent/activeTools.ts +128 -0
- package/server/agent/attachmentConverter.ts +10 -5
- package/server/agent/backend/claude-code.ts +8 -2
- package/server/agent/backend/types.ts +1 -1
- package/server/agent/config.ts +101 -31
- package/server/agent/index.ts +45 -33
- package/server/agent/mcp-server.ts +146 -69
- package/server/agent/mcp-tools/index.ts +1 -5
- package/server/agent/mcp-tools/notify.ts +2 -22
- package/server/agent/mcp-tools/x.ts +0 -4
- package/server/agent/mcpHealth.ts +168 -0
- package/server/agent/plugin-names.ts +20 -77
- package/server/agent/prompt.ts +259 -51
- package/server/agent/resumeFailover.ts +1 -1
- package/server/agent/stream.ts +0 -1
- package/server/api/auth/bearerAuth.ts +5 -5
- package/server/api/csrfGuard.ts +1 -1
- package/server/api/routes/accounting.ts +366 -0
- package/server/api/routes/agent.ts +509 -46
- package/server/api/routes/attachment.ts +104 -0
- package/server/api/routes/chart.ts +2 -1
- package/server/api/routes/config.ts +12 -12
- package/server/api/routes/files.ts +105 -48
- package/server/api/routes/image.ts +70 -25
- package/server/api/routes/journal.ts +35 -0
- package/server/api/routes/mulmo-script.ts +358 -118
- package/server/api/routes/mulmoScriptValidate.ts +1 -1
- package/server/api/routes/news.ts +1 -1
- package/server/api/routes/notifications.ts +92 -22
- package/server/api/routes/notifier.ts +98 -0
- package/server/api/routes/pdf.ts +188 -48
- package/server/api/routes/plugins.ts +34 -14
- package/server/api/routes/presentHtml.ts +58 -3
- package/server/api/routes/roles.ts +1 -8
- package/server/api/routes/runtime-plugin.ts +224 -0
- package/server/api/routes/scheduler.ts +7 -5
- package/server/api/routes/schedulerHandlers.ts +1 -1
- package/server/api/routes/schedulerTasks.ts +8 -7
- package/server/api/routes/sessions.ts +234 -121
- package/server/api/routes/skills.ts +56 -51
- package/server/api/routes/sources.ts +52 -45
- package/server/api/routes/translation.ts +44 -0
- package/server/api/routes/wiki/frontmatter.ts +13 -65
- package/server/api/routes/wiki/history.ts +261 -0
- package/server/api/routes/wiki/pageIndex.ts +1 -1
- package/server/api/routes/wiki.ts +50 -26
- package/server/events/file-change.ts +83 -0
- package/server/events/notifications.ts +247 -91
- package/server/events/pub-sub/index.ts +1 -1
- package/server/events/relay-client.ts +5 -5
- package/server/events/scheduler-adapter.ts +2 -2
- package/server/events/session-store/index.ts +110 -22
- package/server/events/task-manager/index.ts +10 -9
- package/server/index.ts +509 -33
- package/server/notifier/engine.ts +419 -0
- package/server/notifier/legacy-adapters.ts +76 -0
- package/server/notifier/runtime-api.ts +74 -0
- package/server/notifier/store.ts +70 -0
- package/server/notifier/types.ts +121 -0
- package/server/plugins/dev-loader.ts +171 -0
- package/server/plugins/dev-watcher.ts +150 -0
- package/server/plugins/diagnostics.ts +188 -0
- package/server/plugins/preset-list.ts +52 -0
- package/server/plugins/preset-loader.ts +112 -0
- package/server/plugins/runtime-chat-api.ts +38 -0
- package/server/plugins/runtime-loader.ts +430 -0
- package/server/plugins/runtime-registry.ts +112 -0
- package/server/plugins/runtime-tasks-api.ts +50 -0
- package/server/plugins/runtime.ts +378 -0
- package/server/services/translation/cache.ts +72 -0
- package/server/services/translation/index.ts +106 -0
- package/server/services/translation/llm.ts +140 -0
- package/server/services/translation/types.ts +35 -0
- package/server/system/credentials.ts +13 -2
- package/server/system/env.ts +6 -1
- package/server/system/logger/formatters.ts +46 -4
- package/server/system/logger/index.ts +4 -4
- package/server/system/logger/sinks.ts +26 -5
- package/server/system/logger/types.ts +2 -2
- package/server/utils/dev-plugin-args.d.mts +11 -0
- package/server/utils/dev-plugin-args.mjs +43 -0
- package/server/utils/errors.ts +13 -4
- package/server/utils/files/accounting-io.ts +295 -0
- package/server/utils/files/atomic.ts +17 -49
- package/server/utils/files/attachment-store.ts +182 -0
- package/server/utils/files/html-io.ts +1 -7
- package/server/utils/files/html-store.ts +19 -0
- package/server/utils/files/image-store.ts +20 -22
- package/server/utils/files/index.ts +5 -15
- package/server/utils/files/journal-io.ts +7 -35
- package/server/utils/files/json.ts +2 -29
- package/server/utils/files/markdown-image-fill.ts +6 -37
- package/server/utils/files/markdown-store.ts +6 -21
- package/server/utils/files/naming.ts +3 -39
- package/server/utils/files/plugins-io.ts +100 -0
- package/server/utils/files/reference-dirs-io.ts +1 -9
- package/server/utils/files/roles-io.ts +2 -10
- package/server/utils/files/safe.ts +17 -19
- package/server/utils/files/scheduler-io.ts +1 -7
- package/server/utils/files/scheduler-overrides-io.ts +3 -12
- package/server/utils/files/session-io.ts +21 -30
- package/server/utils/files/spreadsheet-store.ts +9 -22
- package/server/utils/files/translation-io.ts +46 -0
- package/server/utils/files/user-tasks-io.ts +1 -7
- package/server/utils/files/workspace-io.ts +3 -79
- package/server/utils/gemini.ts +33 -11
- package/server/utils/html/htmlArtifactSplicer.ts +41 -0
- package/server/utils/markdown/frontmatter.ts +112 -0
- package/server/utils/regex.ts +56 -0
- package/server/utils/router.ts +41 -0
- package/server/utils/slug.ts +5 -3
- package/server/utils/time.ts +12 -0
- package/server/workspace/chat-index/indexer.ts +15 -2
- package/server/workspace/chat-index/summarizer.ts +1 -1
- package/server/workspace/custom-dirs.ts +1 -1
- package/server/workspace/helps/gemini.md +1 -1
- package/server/workspace/helps/guide.md +61 -0
- package/server/workspace/helps/index.md +4 -0
- package/server/workspace/helps/presenthtml.md +80 -0
- package/server/workspace/helps/sandbox.md +7 -0
- package/server/workspace/helps/storyteller.md +101 -0
- package/server/workspace/helps/telegram.md +1 -0
- package/server/workspace/helps/wiki.md +9 -7
- package/server/workspace/journal/archivist-cli.ts +7 -33
- package/server/workspace/journal/archivist-schemas.ts +5 -43
- package/server/workspace/journal/dailyPass.ts +34 -187
- package/server/workspace/journal/diff.ts +3 -28
- package/server/workspace/journal/index.ts +10 -81
- package/server/workspace/journal/indexFile.ts +3 -24
- package/server/workspace/journal/latestDaily.ts +51 -0
- package/server/workspace/journal/memoryExtractor.ts +4 -20
- package/server/workspace/journal/optimizationPass.ts +4 -21
- package/server/workspace/journal/paths.ts +4 -23
- package/server/workspace/journal/state.ts +6 -29
- package/server/workspace/memory/io.ts +213 -0
- package/server/workspace/memory/llm-classifier.ts +158 -0
- package/server/workspace/memory/migrate.ts +263 -0
- package/server/workspace/memory/run.ts +84 -0
- package/server/workspace/memory/topic-cluster.ts +218 -0
- package/server/workspace/memory/topic-detect.ts +67 -0
- package/server/workspace/memory/topic-index-hook.ts +128 -0
- package/server/workspace/memory/topic-io.ts +180 -0
- package/server/workspace/memory/topic-migrate.ts +248 -0
- package/server/workspace/memory/topic-run.ts +172 -0
- package/server/workspace/memory/topic-swap.ts +135 -0
- package/server/workspace/memory/topic-types.ts +142 -0
- package/server/workspace/memory/types.ts +83 -0
- package/server/workspace/news/reader.ts +4 -5
- package/server/workspace/paths.ts +124 -47
- package/server/workspace/roles.ts +2 -11
- package/server/workspace/skills/parser.ts +38 -55
- package/server/workspace/skills/user-tasks.ts +1 -2
- package/server/workspace/skills-preset/mc-library/SKILL.md +188 -0
- package/server/workspace/skills-preset.ts +196 -0
- package/server/workspace/sources/fetchers/githubIssues.ts +13 -11
- package/server/workspace/sources/fetchers/index.ts +1 -1
- package/server/workspace/sources/fetchers/rssParser.ts +1 -1
- package/server/workspace/sources/pipeline/index.ts +2 -2
- package/server/workspace/sources/pipeline/notify.ts +3 -3
- package/server/workspace/sources/pipeline/write.ts +2 -2
- package/server/workspace/sources/registry.ts +39 -61
- package/server/workspace/sources/robots.ts +1 -1
- package/server/workspace/tool-trace/classify.ts +2 -1
- package/server/workspace/tool-trace/index.ts +1 -1
- package/server/workspace/tool-trace/writeSearch.ts +6 -1
- package/server/workspace/wiki-backlinks/index.ts +19 -7
- package/server/workspace/wiki-backlinks/sessionBacklinks.ts +1 -0
- package/server/workspace/wiki-history/hook/snapshot.mjs +98 -0
- package/server/workspace/wiki-history/hook/snapshot.ts +135 -0
- package/server/workspace/wiki-history/provision.ts +181 -0
- package/server/workspace/wiki-pages/io.ts +217 -0
- package/server/workspace/wiki-pages/snapshot.ts +380 -0
- package/server/workspace/workspace.ts +75 -13
- package/src/App.vue +115 -40
- package/src/_runtime/protocol-vue.ts +21 -0
- package/src/_runtime/vue.ts +22 -0
- package/src/components/ChatInput.vue +14 -10
- package/src/components/CopyChatButton.vue +76 -0
- package/src/components/FileContentRenderer.vue +67 -14
- package/src/components/FileTree.vue +2 -2
- package/src/components/FilesView.vue +17 -1
- package/src/components/NewsView.vue +16 -2
- package/src/components/NotificationBell.vue +320 -93
- package/src/components/PageChatComposer.vue +5 -4
- package/src/components/PluginLauncher.vue +42 -6
- package/src/components/PluginScopedRoot.vue +87 -0
- package/src/components/RoleSelector.vue +12 -1
- package/src/components/RolesView.vue +562 -0
- package/src/components/SentAttachmentChip.vue +102 -0
- package/src/components/SessionHistoryPanel.vue +109 -20
- package/src/components/SessionRoleIcon.vue +7 -4
- package/src/components/SessionSidebar.vue +20 -7
- package/src/components/SessionTabBar.vue +1 -1
- package/src/components/SettingsMcpTab.vue +4 -4
- package/src/components/SettingsModal.vue +2 -0
- package/src/components/SidebarHeader.vue +16 -5
- package/src/components/SourcesManager.vue +23 -9
- package/src/components/SourcesView.vue +1 -1
- package/src/components/StackView.vue +102 -6
- package/src/components/SuggestionsPanel.vue +105 -16
- package/src/components/SystemFileBanner.vue +1 -1
- package/src/components/TodoExplorer.vue +4 -5
- package/src/components/todo/TodoAddDialog.vue +2 -3
- package/src/components/todo/TodoEditDialog.vue +1 -2
- package/src/components/todo/TodoEditPanel.vue +2 -3
- package/src/components/todo/TodoKanbanView.vue +8 -5
- package/src/components/todo/TodoListView.vue +3 -5
- package/src/components/todo/TodoTableView.vue +7 -5
- package/src/composables/useAccountingChannel.ts +58 -0
- package/src/composables/useActiveSession.ts +4 -25
- package/src/composables/useAppApi.ts +6 -44
- package/src/composables/useClipboardCopy.ts +3 -20
- package/src/composables/useContentDisplay.ts +33 -2
- package/src/composables/useDevPluginReload.ts +23 -0
- package/src/composables/useDynamicFavicon.ts +5 -31
- package/src/composables/useEventListeners.ts +0 -20
- package/src/composables/useExpandedDirs.ts +4 -15
- package/src/composables/useFaviconState.ts +12 -46
- package/src/composables/useFileChange.ts +53 -0
- package/src/composables/useFreshPluginData.ts +6 -43
- package/src/composables/useHealth.ts +14 -43
- package/src/composables/useImageErrorRepair.ts +104 -0
- package/src/composables/useLatestDaily.ts +40 -0
- package/src/composables/useMarkdownDoc.ts +39 -0
- package/src/composables/useMarkdownLinkHandler.ts +1 -1
- package/src/composables/useMcpTools.ts +3 -16
- package/src/composables/useNotifications.ts +138 -112
- package/src/composables/usePdfDownload.ts +17 -3
- package/src/composables/usePendingCalls.ts +8 -26
- package/src/composables/usePluginErrorBoundary.ts +68 -0
- package/src/composables/usePubSub.ts +9 -17
- package/src/composables/useRunElapsed.ts +5 -22
- package/src/composables/useSandboxStatus.ts +4 -20
- package/src/composables/useSessionDerived.ts +7 -15
- package/src/composables/useSessionHistory.ts +70 -29
- package/src/composables/useSessionSync.ts +25 -3
- package/src/composables/useSkillsList.ts +59 -0
- package/src/composables/useTranslatedQueries.ts +109 -0
- package/src/config/apiRoutes.ts +181 -80
- package/src/config/historyFilters.ts +5 -3
- package/src/config/hostEvents.ts +17 -0
- package/src/config/mcpCatalog.ts +277 -5
- package/src/config/pubsubChannels.ts +134 -12
- package/src/config/roles.ts +212 -147
- package/src/config/systemFileDescriptors.ts +5 -5
- package/src/config/toolNames.ts +52 -30
- package/src/config/workspacePaths.ts +26 -2
- package/src/lang/de.ts +483 -27
- package/src/lang/en.ts +448 -27
- package/src/lang/es.ts +474 -27
- package/src/lang/fr.ts +476 -27
- package/src/lang/ja.ts +465 -27
- package/src/lang/ko.ts +466 -27
- package/src/lang/pt-BR.ts +473 -27
- package/src/lang/zh.ts +463 -27
- package/src/lib/vue-i18n.ts +1 -1
- package/src/lib/wiki-page/slug.ts +66 -0
- package/src/main.ts +85 -0
- package/src/plugins/_extras.ts +58 -0
- package/src/plugins/_generated/metas.ts +42 -0
- package/src/plugins/_generated/registrations.ts +44 -0
- package/src/plugins/_generated/server-bindings.ts +47 -0
- package/src/plugins/accounting/Preview.vue +106 -0
- package/src/plugins/accounting/View.vue +632 -0
- package/src/plugins/accounting/actions.ts +34 -0
- package/src/plugins/accounting/api.ts +301 -0
- package/src/plugins/accounting/components/AccountEditor.vue +250 -0
- package/src/plugins/accounting/components/AccountRow.vue +50 -0
- package/src/plugins/accounting/components/AccountsList.vue +102 -0
- package/src/plugins/accounting/components/AccountsModal.vue +300 -0
- package/src/plugins/accounting/components/BalanceSheet.vue +186 -0
- package/src/plugins/accounting/components/BookSettings.vue +284 -0
- package/src/plugins/accounting/components/BookSwitcher.vue +78 -0
- package/src/plugins/accounting/components/DateRangePicker.vue +140 -0
- package/src/plugins/accounting/components/JournalEntryForm.vue +504 -0
- package/src/plugins/accounting/components/JournalList.vue +553 -0
- package/src/plugins/accounting/components/Ledger.vue +206 -0
- package/src/plugins/accounting/components/NewBookForm.vue +211 -0
- package/src/plugins/accounting/components/OpeningBalancesForm.vue +271 -0
- package/src/plugins/accounting/components/ProfitLoss.vue +160 -0
- package/src/plugins/accounting/components/accountDraft.ts +13 -0
- package/src/plugins/accounting/components/accountNumbering.ts +103 -0
- package/src/plugins/accounting/components/accountValidation.ts +75 -0
- package/src/plugins/accounting/components/useLatestRequest.ts +44 -0
- package/src/plugins/accounting/countries.ts +158 -0
- package/src/plugins/accounting/currencies.ts +64 -0
- package/src/plugins/accounting/dates.ts +51 -0
- package/src/plugins/accounting/definition.ts +199 -0
- package/src/plugins/accounting/fiscalYear.ts +136 -0
- package/src/plugins/accounting/index.ts +49 -0
- package/src/plugins/accounting/meta.ts +91 -0
- package/src/plugins/accounting/timeSeriesEnums.ts +16 -0
- package/src/plugins/api.ts +125 -0
- package/src/plugins/canvas/View.vue +38 -28
- package/src/plugins/canvas/definition.ts +10 -8
- package/src/plugins/canvas/index.ts +15 -8
- package/src/plugins/canvas/meta.ts +12 -0
- package/src/plugins/chart/Preview.vue +1 -1
- package/src/plugins/chart/View.vue +2 -2
- package/src/plugins/chart/definition.ts +12 -2
- package/src/plugins/chart/index.ts +15 -7
- package/src/plugins/chart/meta.ts +18 -0
- package/src/plugins/editImages/definition.ts +44 -0
- package/src/plugins/editImages/index.ts +43 -0
- package/src/plugins/editImages/meta.ts +5 -0
- package/src/plugins/generateImage/View.vue +3 -1
- package/src/plugins/generateImage/definition.ts +2 -0
- package/src/plugins/generateImage/index.ts +13 -5
- package/src/plugins/generateImage/meta.ts +5 -0
- package/src/plugins/index.ts +35 -0
- package/src/plugins/manageRoles/Preview.vue +7 -4
- package/src/plugins/manageRoles/View.vue +12 -8
- package/src/plugins/manageRoles/definition.ts +6 -0
- package/src/plugins/manageRoles/index.ts +7 -6
- package/src/plugins/manageSkills/View.vue +11 -7
- package/src/plugins/manageSkills/definition.ts +4 -1
- package/src/plugins/manageSkills/index.ts +14 -7
- package/src/plugins/manageSkills/meta.ts +21 -0
- package/src/plugins/manageSource/definition.ts +4 -1
- package/src/plugins/manageSource/index.ts +15 -7
- package/src/plugins/manageSource/meta.ts +21 -0
- package/src/plugins/markdown/Preview.vue +10 -8
- package/src/plugins/markdown/View.vue +84 -17
- package/src/plugins/markdown/definition.ts +7 -1
- package/src/plugins/markdown/index.ts +15 -8
- package/src/plugins/markdown/meta.ts +16 -0
- package/src/plugins/meta-types.ts +97 -0
- package/src/plugins/metas.ts +224 -0
- package/src/plugins/presentForm/Preview.vue +4 -15
- package/src/plugins/presentForm/View.vue +35 -78
- package/src/plugins/presentForm/definition.ts +7 -6
- package/src/plugins/presentForm/index.ts +12 -5
- package/src/plugins/presentForm/meta.ts +11 -0
- package/src/plugins/presentForm/plugin.ts +8 -9
- package/src/plugins/presentForm/types.ts +0 -24
- package/src/plugins/presentHtml/Preview.vue +1 -8
- package/src/plugins/presentHtml/View.vue +401 -30
- package/src/plugins/presentHtml/definition.ts +8 -5
- package/src/plugins/presentHtml/index.ts +15 -8
- package/src/plugins/presentHtml/meta.ts +14 -0
- package/src/plugins/presentMulmoScript/View.vue +327 -107
- package/src/plugins/presentMulmoScript/definition.ts +34 -7
- package/src/plugins/presentMulmoScript/helpers.ts +4 -5
- package/src/plugins/presentMulmoScript/index.ts +20 -7
- package/src/plugins/presentMulmoScript/meta.ts +52 -0
- package/src/plugins/scheduler/AutomationsPreview.vue +2 -8
- package/src/plugins/scheduler/Preview.vue +5 -2
- package/src/plugins/scheduler/TasksTab.vue +16 -36
- package/src/plugins/scheduler/View.vue +22 -54
- package/src/plugins/scheduler/automationsDefinition.ts +14 -9
- package/src/plugins/scheduler/automationsMeta.ts +5 -0
- package/src/plugins/scheduler/calendarDefinition.ts +4 -7
- package/src/plugins/scheduler/calendarMeta.ts +28 -0
- package/src/plugins/scheduler/formatSchedule.ts +6 -24
- package/src/plugins/scheduler/index.ts +26 -52
- package/src/plugins/scope.ts +57 -0
- package/src/plugins/server-bindings-types.ts +38 -0
- package/src/plugins/server.ts +32 -0
- package/src/plugins/skill/Preview.vue +25 -0
- package/src/plugins/skill/View.vue +125 -0
- package/src/plugins/skill/definition.ts +23 -0
- package/src/plugins/skill/index.ts +36 -0
- package/src/plugins/skill/plugin.ts +31 -0
- package/src/plugins/skill/types.ts +21 -0
- package/src/plugins/spreadsheet/Preview.vue +1 -3
- package/src/plugins/spreadsheet/View.vue +29 -49
- package/src/plugins/spreadsheet/cellHighlights.ts +2 -3
- package/src/plugins/spreadsheet/definition.ts +5 -2
- package/src/plugins/spreadsheet/index.ts +15 -8
- package/src/plugins/spreadsheet/keyboardNav.ts +38 -0
- package/src/plugins/spreadsheet/meta.ts +14 -0
- package/src/plugins/textResponse/Preview.vue +9 -1
- package/src/plugins/textResponse/View.vue +59 -8
- package/src/plugins/textResponse/index.ts +11 -3
- package/src/plugins/textResponse/plugin.ts +8 -10
- package/src/plugins/textResponse/types.ts +28 -0
- package/src/plugins/wiki/Preview.vue +6 -4
- package/src/plugins/wiki/View.vue +463 -254
- package/src/plugins/wiki/components/WikiPageBody.vue +159 -0
- package/src/plugins/wiki/helpers.ts +17 -0
- package/src/plugins/wiki/history/HistoryDetail.vue +325 -0
- package/src/plugins/wiki/history/HistoryTab.vue +167 -0
- package/src/plugins/wiki/history/RestoreConfirm.vue +63 -0
- package/src/plugins/wiki/history/api.ts +52 -0
- package/src/plugins/wiki/history/diff.ts +145 -0
- package/src/plugins/wiki/index.ts +42 -32
- package/src/plugins/wiki/meta.ts +10 -0
- package/src/plugins/wiki/pageEditLoader.ts +53 -0
- package/src/plugins/wiki/route.ts +8 -0
- package/src/router/guards.ts +2 -1
- package/src/router/index.ts +19 -0
- package/src/router/pageRoutes.ts +1 -0
- package/src/tools/index.ts +50 -51
- package/src/tools/runtimeLoader.ts +141 -0
- package/src/tools/types.ts +44 -1
- package/src/types/notification.ts +23 -0
- package/src/types/pastedFile.ts +10 -0
- package/src/types/session.ts +61 -3
- package/src/types/sse.ts +21 -6
- package/src/utils/agent/eventDispatch.ts +12 -9
- package/src/utils/agent/pastedAttachment.ts +35 -0
- package/src/utils/agent/request.ts +32 -3
- package/src/utils/agent/toolCalls.ts +7 -1
- package/src/utils/api.ts +1 -1
- package/src/utils/chat/exportMarkdown.ts +243 -0
- package/src/utils/errors.ts +10 -2
- package/src/utils/files/expandedDirs.ts +1 -1
- package/src/utils/filesPreview/todoPreview.ts +13 -2
- package/src/utils/format/date.ts +1 -3
- package/src/utils/format/jsonSyntax.ts +5 -0
- package/src/utils/html/iframeHeightReporterScript.ts +62 -0
- package/src/utils/html/previewCsp.ts +29 -2
- package/src/utils/image/htmlSrcAttrs.ts +122 -0
- package/src/utils/image/imageRepairInlineScript.ts +115 -0
- package/src/utils/image/resolve.ts +17 -3
- package/src/utils/image/rewriteMarkdownImageRefs.ts +62 -9
- package/src/utils/markdown/frontmatter.ts +125 -0
- package/src/utils/markdown/taskList.ts +7 -2
- package/src/utils/plugin/runtime.ts +132 -0
- package/src/utils/session/mergeSessions.ts +40 -37
- package/src/utils/session/sessionEntries.ts +74 -18
- package/src/utils/session/sessionHelpers.ts +54 -10
- package/src/utils/tools/result.ts +76 -14
- package/src/vite-env.d.ts +6 -0
- package/client/assets/html2canvas-Cx501zZr-Bug0qRNv.js +0 -5
- package/client/assets/index-CY-WpQUm.css +0 -2
- package/client/assets/index-DbTz2Mfs.js +0 -4911
- package/client/assets/material-symbols-outlined-NzYEeyps.woff2 +0 -0
- package/server/api/routes/html.ts +0 -114
- package/server/api/routes/todos.ts +0 -293
- package/server/api/routes/todosColumnsHandlers.ts +0 -333
- package/server/api/routes/todosHandlers.ts +0 -274
- package/server/api/routes/todosItemsHandlers.ts +0 -386
- package/server/utils/files/todos-io.ts +0 -29
- package/src/components/NotificationToast.vue +0 -75
- package/src/plugins/editImage/definition.ts +0 -27
- package/src/plugins/editImage/index.ts +0 -37
- package/src/plugins/presentHtml/helpers.ts +0 -72
- package/src/plugins/scheduler/LegacySchedulerView.vue +0 -32
- package/src/plugins/scheduler/legacyShape.ts +0 -34
- package/src/plugins/todo/Preview.vue +0 -68
- package/src/plugins/todo/View.vue +0 -378
- package/src/plugins/todo/composables/useTodos.ts +0 -179
- package/src/plugins/todo/definition.ts +0 -45
- package/src/plugins/todo/index.ts +0 -62
- package/src/plugins/todo/labels.ts +0 -163
- package/src/plugins/todo/priority.ts +0 -98
- package/src/plugins/todo/viewModes.ts +0 -19
- package/src/plugins/wiki/definition.ts +0 -25
- package/src/tools/legacyPluginNames.ts +0 -13
- package/src/utils/format/frontmatter.ts +0 -80
- package/src/utils/image/rewriteHtmlImageRefs.ts +0 -50
- package/src/utils/notification/dispatch.ts +0 -58
- /package/client/assets/{purify.es-Fx1Nqyry-BwJECkqS.js → purify.es-Fx1Nqyry-BSVNht6S.js} +0 -0
- /package/src/plugins/{editImage → editImages}/Preview.vue +0 -0
- /package/src/plugins/{editImage → editImages}/View.vue +0 -0
- /package/src/{config/schedulerActions.ts → plugins/scheduler/actions.ts} +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// Country utilities for the accounting plugin.
|
|
2
|
+
//
|
|
3
|
+
// The book's country (ISO 3166-1 alpha-2) identifies the tax
|
|
4
|
+
// jurisdiction the book is kept under. The Accounting role uses it
|
|
5
|
+
// to give country-aware advice — Japanese T-number under
|
|
6
|
+
// インボイス制度, EU VAT ID, UK VAT, GSTIN, ABN, etc.
|
|
7
|
+
//
|
|
8
|
+
// Curated against the supported currency list and the tax-regime
|
|
9
|
+
// guidance in `src/config/roles.ts` (Accounting role prompt).
|
|
10
|
+
// Intl.DisplayNames provides the localized human name at render
|
|
11
|
+
// time, so this stays a flat list of codes.
|
|
12
|
+
|
|
13
|
+
/** ISO 3166-1 alpha-2 country codes shown in the book country
|
|
14
|
+
* dropdown. Curated to cover every jurisdiction the Accounting role
|
|
15
|
+
* has explicit tax-registration advice for, plus the major economies
|
|
16
|
+
* represented in `SUPPORTED_CURRENCY_CODES`. */
|
|
17
|
+
export const SUPPORTED_COUNTRY_CODES = [
|
|
18
|
+
"US",
|
|
19
|
+
"JP",
|
|
20
|
+
"GB",
|
|
21
|
+
"CA",
|
|
22
|
+
"AU",
|
|
23
|
+
"NZ",
|
|
24
|
+
"DE",
|
|
25
|
+
"FR",
|
|
26
|
+
"IT",
|
|
27
|
+
"ES",
|
|
28
|
+
"NL",
|
|
29
|
+
"BE",
|
|
30
|
+
"AT",
|
|
31
|
+
"IE",
|
|
32
|
+
"PT",
|
|
33
|
+
"FI",
|
|
34
|
+
"SE",
|
|
35
|
+
"DK",
|
|
36
|
+
"PL",
|
|
37
|
+
"CH",
|
|
38
|
+
"NO",
|
|
39
|
+
"CN",
|
|
40
|
+
"KR",
|
|
41
|
+
"TW",
|
|
42
|
+
"HK",
|
|
43
|
+
"SG",
|
|
44
|
+
"IN",
|
|
45
|
+
"BR",
|
|
46
|
+
"MX",
|
|
47
|
+
] as const;
|
|
48
|
+
|
|
49
|
+
export type SupportedCountryCode = (typeof SUPPORTED_COUNTRY_CODES)[number];
|
|
50
|
+
|
|
51
|
+
/** EU member states as of 2026. Used by the role-prompt advice path
|
|
52
|
+
* to recommend a VAT identification number when the book country is
|
|
53
|
+
* in the EU. */
|
|
54
|
+
export const EU_COUNTRY_CODES: ReadonlySet<string> = new Set([
|
|
55
|
+
"AT",
|
|
56
|
+
"BE",
|
|
57
|
+
"BG",
|
|
58
|
+
"CY",
|
|
59
|
+
"CZ",
|
|
60
|
+
"DE",
|
|
61
|
+
"DK",
|
|
62
|
+
"EE",
|
|
63
|
+
"ES",
|
|
64
|
+
"FI",
|
|
65
|
+
"FR",
|
|
66
|
+
"GR",
|
|
67
|
+
"HR",
|
|
68
|
+
"HU",
|
|
69
|
+
"IE",
|
|
70
|
+
"IT",
|
|
71
|
+
"LT",
|
|
72
|
+
"LU",
|
|
73
|
+
"LV",
|
|
74
|
+
"MT",
|
|
75
|
+
"NL",
|
|
76
|
+
"PL",
|
|
77
|
+
"PT",
|
|
78
|
+
"RO",
|
|
79
|
+
"SE",
|
|
80
|
+
"SI",
|
|
81
|
+
"SK",
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
/** Localized human name for a country code. Falls back to the code
|
|
85
|
+
* itself if the runtime can't resolve the name. */
|
|
86
|
+
export function localizedCountryName(code: string, locale: string): string {
|
|
87
|
+
try {
|
|
88
|
+
return new Intl.DisplayNames([locale], { type: "region" }).of(code) ?? code;
|
|
89
|
+
} catch {
|
|
90
|
+
return code;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Runtime guard for `BookSummary.country`. The type is the union
|
|
95
|
+
* `SupportedCountryCode`, but every entry point that takes user /
|
|
96
|
+
* LLM input arrives as raw `string` (form submit, JSON-RPC body),
|
|
97
|
+
* so the service layer narrows here before persisting. */
|
|
98
|
+
export function isSupportedCountryCode(value: unknown): value is SupportedCountryCode {
|
|
99
|
+
return typeof value === "string" && (SUPPORTED_COUNTRY_CODES as readonly string[]).includes(value);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Country-gated UI features. Each key is a feature name; the value
|
|
103
|
+
* is the set of country codes for which the feature is enabled.
|
|
104
|
+
* Components ask `countryHasFeature("...", country)` instead of
|
|
105
|
+
* hard-coding country lists at the call site.
|
|
106
|
+
*
|
|
107
|
+
* Add a new country-specific feature by adding a new key here and
|
|
108
|
+
* reading it via `countryHasFeature`. An unknown / undefined
|
|
109
|
+
* country never has any feature — components fall back to neutral
|
|
110
|
+
* default UI rather than guessing.
|
|
111
|
+
*
|
|
112
|
+
* Mirrors the "Country-aware tax behaviour" prose in the
|
|
113
|
+
* Accounting role prompt (`src/config/roles.ts`). The two MUST
|
|
114
|
+
* stay in sync — drift means the LLM and the form give the user
|
|
115
|
+
* contradictory advice. The prompt is the source of truth for
|
|
116
|
+
* agent behaviour; this table is structured-data sibling for the
|
|
117
|
+
* form. */
|
|
118
|
+
export const COUNTRY_FEATURES = {
|
|
119
|
+
/** Show an amber "missing tax ID" warning + helper text on a
|
|
120
|
+
* postable 14xx (input-tax) line whose taxRegistrationId is
|
|
121
|
+
* blank. Limited to jurisdictions where the role prompt
|
|
122
|
+
* explicitly requires the counterparty registration number
|
|
123
|
+
* (JP T-number, EU VAT ID, GB VAT, GSTIN, ABN, NZ GST, CA BN).
|
|
124
|
+
* The "other countries" bucket and US (no federal sales-tax
|
|
125
|
+
* registration) intentionally stay quiet. 24xx output-tax
|
|
126
|
+
* lines don't trigger the warning — see `isTaxAccountCode`. */
|
|
127
|
+
warnMissingTaxRegistrationId: new Set<SupportedCountryCode>([
|
|
128
|
+
"JP",
|
|
129
|
+
"GB",
|
|
130
|
+
"DE",
|
|
131
|
+
"FR",
|
|
132
|
+
"IT",
|
|
133
|
+
"ES",
|
|
134
|
+
"NL",
|
|
135
|
+
"BE",
|
|
136
|
+
"AT",
|
|
137
|
+
"IE",
|
|
138
|
+
"PT",
|
|
139
|
+
"FI",
|
|
140
|
+
"SE",
|
|
141
|
+
"DK",
|
|
142
|
+
"PL",
|
|
143
|
+
"IN",
|
|
144
|
+
"AU",
|
|
145
|
+
"NZ",
|
|
146
|
+
"CA",
|
|
147
|
+
]),
|
|
148
|
+
} as const;
|
|
149
|
+
|
|
150
|
+
export type CountryFeature = keyof typeof COUNTRY_FEATURES;
|
|
151
|
+
|
|
152
|
+
/** Resolve a country-gated feature flag. Returns `false` when the
|
|
153
|
+
* country is undefined / unsupported — components default to the
|
|
154
|
+
* neutral path (no warning, no extra UI) rather than guessing. */
|
|
155
|
+
export function countryHasFeature(feature: CountryFeature, country: SupportedCountryCode | undefined): boolean {
|
|
156
|
+
if (!country) return false;
|
|
157
|
+
return COUNTRY_FEATURES[feature].has(country);
|
|
158
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Currency utilities for the accounting plugin.
|
|
2
|
+
//
|
|
3
|
+
// We expose a curated list of ISO 4217 codes for the New Book
|
|
4
|
+
// dropdown — covering the major reserve currencies plus the most
|
|
5
|
+
// requested Asian / regional ones — plus per-currency formatting
|
|
6
|
+
// helpers built on Intl.NumberFormat.
|
|
7
|
+
//
|
|
8
|
+
// The book's currency is per-book metadata (BookSummary.currency)
|
|
9
|
+
// and only matters once the user has opened the book; cross-book
|
|
10
|
+
// aggregation isn't supported.
|
|
11
|
+
|
|
12
|
+
/** ISO 4217 codes shown in the New Book dropdown. Curated for
|
|
13
|
+
* recognisability — Intl.DisplayNames provides the localised
|
|
14
|
+
* human name at render time, so this stays a flat list of codes. */
|
|
15
|
+
export const SUPPORTED_CURRENCY_CODES = ["USD", "EUR", "JPY", "GBP", "CNY", "KRW", "TWD", "HKD", "SGD", "AUD", "CAD", "CHF", "INR", "BRL", "MXN"] as const;
|
|
16
|
+
|
|
17
|
+
export type SupportedCurrencyCode = (typeof SUPPORTED_CURRENCY_CODES)[number];
|
|
18
|
+
|
|
19
|
+
const DEFAULT_FALLBACK_DIGITS = 2;
|
|
20
|
+
|
|
21
|
+
/** Localised human name for a currency code. Falls back to the
|
|
22
|
+
* code itself if the runtime can't resolve the name. */
|
|
23
|
+
export function localizedCurrencyName(code: string, locale: string): string {
|
|
24
|
+
try {
|
|
25
|
+
return new Intl.DisplayNames([locale], { type: "currency" }).of(code) ?? code;
|
|
26
|
+
} catch {
|
|
27
|
+
return code;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Number of fraction digits ISO 4217 specifies for a currency.
|
|
32
|
+
* JPY = 0, USD = 2, KWD = 3. Used both for amount formatting and
|
|
33
|
+
* for the HTML input step on debit/credit fields. */
|
|
34
|
+
export function fractionDigitsFor(currency: string): number {
|
|
35
|
+
try {
|
|
36
|
+
const opts = new Intl.NumberFormat("en", { style: "currency", currency }).resolvedOptions();
|
|
37
|
+
return opts.maximumFractionDigits ?? DEFAULT_FALLBACK_DIGITS;
|
|
38
|
+
} catch {
|
|
39
|
+
return DEFAULT_FALLBACK_DIGITS;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** "1" for JPY, "0.01" for USD, "0.001" for KWD. Used as the HTML
|
|
44
|
+
* input step on debit/credit fields so a JPY book doesn't let the
|
|
45
|
+
* user type cents that would just round-trip back through the
|
|
46
|
+
* decimal validator. */
|
|
47
|
+
export function inputStepFor(currency: string): string {
|
|
48
|
+
const digits = fractionDigitsFor(currency);
|
|
49
|
+
if (digits === 0) return "1";
|
|
50
|
+
return (1 / 10 ** digits).toFixed(digits);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Locale-aware currency formatter — returns "¥1,130" / "$1,130.00"
|
|
54
|
+
* etc. Falls back to fixed-point formatting if the runtime can't
|
|
55
|
+
* resolve the currency code; the fallback still respects the
|
|
56
|
+
* currency's natural fraction-digit count so JPY shows whole
|
|
57
|
+
* numbers even on the slow path. */
|
|
58
|
+
export function formatAmount(value: number, currency: string, locale?: string): string {
|
|
59
|
+
try {
|
|
60
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(value);
|
|
61
|
+
} catch {
|
|
62
|
+
return value.toFixed(fractionDigitsFor(currency));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Local-calendar date helpers for the accounting forms.
|
|
2
|
+
//
|
|
3
|
+
// Why not `new Date().toISOString().slice(0, 10)`? `toISOString` is
|
|
4
|
+
// UTC. In a negative-offset zone (US Pacific, Eastern, …) the UTC
|
|
5
|
+
// date crosses to "tomorrow" several hours before midnight local,
|
|
6
|
+
// so a naively prefilled date input would post entries into the
|
|
7
|
+
// wrong accounting day. Same mistake near month boundaries flips
|
|
8
|
+
// the default Balance Sheet period to the next month.
|
|
9
|
+
//
|
|
10
|
+
// All four helpers below are pure local-calendar formatters built
|
|
11
|
+
// from `getFullYear` / `getMonth` / `getDate`, which the JS engine
|
|
12
|
+
// resolves in the user's local timezone.
|
|
13
|
+
|
|
14
|
+
function pad2(num: number): string {
|
|
15
|
+
return String(num).padStart(2, "0");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Today as `YYYY-MM-DD` in the user's local timezone. */
|
|
19
|
+
export function localDateString(now: Date = new Date()): string {
|
|
20
|
+
return `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Current month as `YYYY-MM` in the user's local timezone. */
|
|
24
|
+
export function localMonthString(now: Date = new Date()): string {
|
|
25
|
+
return `${now.getFullYear()}-${pad2(now.getMonth() + 1)}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** First day of the current calendar year as `YYYY-MM-DD`. */
|
|
29
|
+
export function localStartOfYearString(now: Date = new Date()): string {
|
|
30
|
+
return `${now.getFullYear()}-01-01`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Previous calendar month as `YYYY-MM` in the user's local timezone. */
|
|
34
|
+
export function previousMonthString(now: Date = new Date()): string {
|
|
35
|
+
const target = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
|
36
|
+
return `${target.getFullYear()}-${pad2(target.getMonth() + 1)}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Last month of the previous calendar quarter as `YYYY-MM`. Calendar
|
|
40
|
+
* quarters: Q1=Jan–Mar, Q2=Apr–Jun, Q3=Jul–Sep, Q4=Oct–Dec. When the
|
|
41
|
+
* current month is in Q1, this rolls back to December of last year. */
|
|
42
|
+
export function lastMonthOfPreviousQuarterString(now: Date = new Date()): string {
|
|
43
|
+
const firstMonthOfCurrentQuarter = Math.floor(now.getMonth() / 3) * 3;
|
|
44
|
+
const target = new Date(now.getFullYear(), firstMonthOfCurrentQuarter - 1, 1);
|
|
45
|
+
return `${target.getFullYear()}-${pad2(target.getMonth() + 1)}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** December of the previous calendar year as `YYYY-MM`. */
|
|
49
|
+
export function decemberOfPreviousYearString(now: Date = new Date()): string {
|
|
50
|
+
return `${now.getFullYear() - 1}-12`;
|
|
51
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { ToolDefinition } from "gui-chat-protocol";
|
|
2
|
+
import { META } from "./meta";
|
|
3
|
+
import { ACCOUNTING_ACTIONS } from "./actions";
|
|
4
|
+
import { SUPPORTED_COUNTRY_CODES } from "./countries";
|
|
5
|
+
import { FISCAL_YEAR_ENDS } from "./fiscalYear";
|
|
6
|
+
import { TIME_SERIES_GRANULARITIES, TIME_SERIES_METRICS } from "./timeSeriesEnums";
|
|
7
|
+
|
|
8
|
+
// MCP tool definition for the accounting plugin.
|
|
9
|
+
//
|
|
10
|
+
// **Opt-in only.** Not added to any built-in Role's
|
|
11
|
+
// `availablePlugins` (see plans/done/feat-accounting.md hard
|
|
12
|
+
// constraint 1). A user wanting access creates a custom Role and
|
|
13
|
+
// includes `manageAccounting` in its plugin list.
|
|
14
|
+
//
|
|
15
|
+
// The `openBook` action returns an "accounting-app" tool-result
|
|
16
|
+
// envelope that the frontend renderer mounts as the full
|
|
17
|
+
// `<AccountingApp>` View. Every other action returns a compact
|
|
18
|
+
// data payload that renders inline via `Preview.vue`.
|
|
19
|
+
|
|
20
|
+
const toolDefinition: ToolDefinition = {
|
|
21
|
+
type: "function",
|
|
22
|
+
name: META.toolName,
|
|
23
|
+
prompt:
|
|
24
|
+
"When the user asks to open / view their books, or to record, look up, or summarise journal entries / balances / opening balances, use manageAccounting. Use action='openBook' (with the target bookId) to switch the canvas to a specific existing book; use the specific action (addEntries / getReport / etc.) for narrowly-scoped operations the user asked about by name. On a fresh workspace call 'createBook' (always pass `country` so tax-registration advice is country-aware) — the accounting view picks up the new book automatically (no follow-up 'openBook' needed for this id). Use 'updateBook' to change a book's name or country (currency cannot be changed). Reach for 'openBook' only when switching to a different existing book. For cross-period charts and dashboards (\"chart my quarterly revenue over the last two years\", \"show net income month-over-month for this fiscal year\", \"plot the cash balance by month\") use action='getTimeSeries' — it returns one chart-ready point per bucket in a single round-trip; do NOT loop over 'getReport' to assemble a series yourself.",
|
|
25
|
+
description:
|
|
26
|
+
"Manage a double-entry accounting book stored in the workspace file system. Supports multiple books (entities), opening balances for adoption from existing books, journal entries, voiding (append-only — corrections are reversing pairs), and balance-sheet / profit-loss / ledger reports. Action='openBook' mounts the full accounting UI in the canvas (requires bookId); 'getTimeSeries' returns chart-ready (label, value)[] series for revenue / expense / netIncome / accountBalance over time; specific actions return compact results that render inline.",
|
|
27
|
+
parameters: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
action: {
|
|
31
|
+
type: "string",
|
|
32
|
+
enum: Object.values(ACCOUNTING_ACTIONS),
|
|
33
|
+
description:
|
|
34
|
+
"Operation to perform. 'openBook' mounts the full UI for a specific book; others perform a single read or write. Use 'openBook' when the user wants to browse / interact, and a specific action when the user named the operation.",
|
|
35
|
+
},
|
|
36
|
+
bookId: {
|
|
37
|
+
type: "string",
|
|
38
|
+
description:
|
|
39
|
+
"Target book id. Required for every action that reads or writes book data, including 'openBook'; call 'getBooks' first to enumerate available ids. The only actions that do NOT take a bookId are 'getBooks' and 'createBook' (which creates a fresh one).",
|
|
40
|
+
},
|
|
41
|
+
// openBook / createBook / updateBook
|
|
42
|
+
name: { type: "string", description: "For 'createBook' / 'updateBook': human-readable book name." },
|
|
43
|
+
currency: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "For 'createBook': ISO 4217 currency code (default USD). Single-currency per book — cannot be changed once set.",
|
|
46
|
+
},
|
|
47
|
+
country: {
|
|
48
|
+
type: "string",
|
|
49
|
+
// Pinning the enum locks the LLM to the same curated set the
|
|
50
|
+
// UI dropdown offers and the service-layer guard accepts —
|
|
51
|
+
// any value outside this list 400s, so emitting a typo or an
|
|
52
|
+
// unsupported jurisdiction is a wasted tool call. Pass `""`
|
|
53
|
+
// to 'updateBook' to explicitly clear the country.
|
|
54
|
+
enum: [...SUPPORTED_COUNTRY_CODES, ""],
|
|
55
|
+
description:
|
|
56
|
+
"For 'createBook' / 'updateBook': ISO 3166-1 alpha-2 country code identifying the tax jurisdiction. Drives country-aware advice — e.g. when set to 'JP', strongly suggest the supplier's T-number (適格請求書発行事業者登録番号) on tax-related lines under インボイス制度. Only the codes listed in the enum are accepted; pass an empty string to 'updateBook' to clear the field.",
|
|
57
|
+
},
|
|
58
|
+
fiscalYearEnd: {
|
|
59
|
+
type: "string",
|
|
60
|
+
enum: [...FISCAL_YEAR_ENDS],
|
|
61
|
+
description:
|
|
62
|
+
"For 'createBook' / 'updateBook': which calendar-quarter end is this book's fiscal year end — Q1 = March 31, Q2 = June 30, Q3 = September 30, Q4 = December 31 (calendar year, the default). Drives the date-range shortcuts in the UI ('current quarter', 'current year', etc.). Pure metadata: changing it does not move existing entries.",
|
|
63
|
+
},
|
|
64
|
+
initialTab: { type: "string", description: "For 'openBook': initial tab to show (e.g. 'journal', 'opening', 'balanceSheet')." },
|
|
65
|
+
confirm: { type: "boolean", description: "For 'deleteBook': must be true to actually delete (guard against accidental deletion)." },
|
|
66
|
+
// accounts
|
|
67
|
+
account: {
|
|
68
|
+
type: "object",
|
|
69
|
+
description: "For 'upsertAccount': the account to insert or update (matched by code).",
|
|
70
|
+
properties: {
|
|
71
|
+
code: { type: "string" },
|
|
72
|
+
name: { type: "string" },
|
|
73
|
+
type: { type: "string", enum: ["asset", "liability", "equity", "income", "expense"] },
|
|
74
|
+
note: { type: "string" },
|
|
75
|
+
active: {
|
|
76
|
+
type: "boolean",
|
|
77
|
+
description:
|
|
78
|
+
"Soft-delete flag. `false` deactivates the account (hides it from entry / ledger dropdowns while keeping it visible in Manage Accounts and historical entries — accounting integrity requires that a code referenced by a journal line never disappears). `true` reactivates a previously-deactivated account. Omit to preserve the existing state — handy when updating name / type / note without touching the active flag.",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
required: ["code", "name", "type"],
|
|
82
|
+
},
|
|
83
|
+
// entries (addEntries — batched)
|
|
84
|
+
entries: {
|
|
85
|
+
type: "array",
|
|
86
|
+
description:
|
|
87
|
+
"For 'addEntries': one or more journal entries to post atomically (all-or-nothing — if any entry fails validation, the whole batch is rejected and nothing is written). Use a single-element array to post one entry. Each entry has its own date, lines, optional memo, and optional replacesEntryId.",
|
|
88
|
+
items: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {
|
|
91
|
+
date: { type: "string", description: "YYYY-MM-DD booking date." },
|
|
92
|
+
lines: {
|
|
93
|
+
type: "array",
|
|
94
|
+
description: "Journal lines for this entry. Each line sets exactly one of debit or credit (positive amount). Σ debit must equal Σ credit.",
|
|
95
|
+
items: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {
|
|
98
|
+
accountCode: { type: "string" },
|
|
99
|
+
debit: { type: "number" },
|
|
100
|
+
credit: { type: "number" },
|
|
101
|
+
memo: { type: "string" },
|
|
102
|
+
taxRegistrationId: {
|
|
103
|
+
type: "string",
|
|
104
|
+
description:
|
|
105
|
+
"Optional counterparty tax-authority registration ID for this line (Japan T-number, EU VAT ID, UK VAT registration number, India GSTIN, Australia ABN, etc.). Free-form string, max 32 chars. Required for input-tax-credit eligibility under regimes like Japan's インボイス制度.",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
required: ["accountCode"],
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
memo: { type: "string", description: "Optional entry-level memo." },
|
|
112
|
+
replacesEntryId: {
|
|
113
|
+
type: "string",
|
|
114
|
+
description:
|
|
115
|
+
"Optional — id of an entry this one replaces (the 'edit' flow). The caller MUST issue a 'voidEntry' for that id immediately before this addEntries call; the void + post pair is not atomic on the server.",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
required: ["date", "lines"],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
// setOpeningBalances — single opening entry (top-level lines / memo)
|
|
122
|
+
lines: {
|
|
123
|
+
type: "array",
|
|
124
|
+
description:
|
|
125
|
+
"For 'setOpeningBalances': journal lines. Each line sets exactly one of debit or credit (positive amount). Σ debit must equal Σ credit. Only balance-sheet accounts (asset / liability / equity) are accepted.",
|
|
126
|
+
items: {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {
|
|
129
|
+
accountCode: { type: "string" },
|
|
130
|
+
debit: { type: "number" },
|
|
131
|
+
credit: { type: "number" },
|
|
132
|
+
memo: { type: "string" },
|
|
133
|
+
taxRegistrationId: { type: "string" },
|
|
134
|
+
},
|
|
135
|
+
required: ["accountCode"],
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
memo: { type: "string", description: "For 'setOpeningBalances': optional entry-level memo." },
|
|
139
|
+
// void
|
|
140
|
+
entryId: { type: "string", description: "For 'voidEntry': id of the entry to void. The reverse + marker pair is appended (journal stays append-only)." },
|
|
141
|
+
reason: { type: "string", description: "For 'voidEntry': human-readable reason." },
|
|
142
|
+
voidDate: { type: "string", description: "For 'voidEntry': YYYY-MM-DD date for the reverse entry (defaults to today)." },
|
|
143
|
+
// getJournalEntries / getReport / getTimeSeries ranges
|
|
144
|
+
from: {
|
|
145
|
+
type: "string",
|
|
146
|
+
description:
|
|
147
|
+
"For 'getJournalEntries': inclusive YYYY-MM-DD lower bound on entry date. For 'getTimeSeries': inclusive YYYY-MM-DD lower bound — the first bucket is the one CONTAINING this date (it can extend earlier).",
|
|
148
|
+
},
|
|
149
|
+
to: {
|
|
150
|
+
type: "string",
|
|
151
|
+
description:
|
|
152
|
+
"For 'getJournalEntries': inclusive YYYY-MM-DD upper bound on entry date. For 'getTimeSeries': inclusive YYYY-MM-DD upper bound — the last bucket is the one CONTAINING this date (it can extend later).",
|
|
153
|
+
},
|
|
154
|
+
accountCode: {
|
|
155
|
+
type: "string",
|
|
156
|
+
description:
|
|
157
|
+
"For 'getJournalEntries' / 'getReport' (kind=ledger): filter to entries that touch a specific account code. For 'getTimeSeries' with metric='accountBalance': REQUIRED — the account whose closing balance to plot per bucket. Forbidden for the other metrics.",
|
|
158
|
+
},
|
|
159
|
+
// getTimeSeries
|
|
160
|
+
metric: {
|
|
161
|
+
type: "string",
|
|
162
|
+
enum: [...TIME_SERIES_METRICS],
|
|
163
|
+
description:
|
|
164
|
+
"For 'getTimeSeries': what to plot per bucket. 'revenue' = sum of income-account presentation values within the bucket (positive = money earned). 'expense' = sum of expense accounts within the bucket (positive = money spent). 'netIncome' = revenue − expense (positive = profit). 'accountBalance' = closing balance of `accountCode` at the end of each bucket (cumulative, includes opening balances).",
|
|
165
|
+
},
|
|
166
|
+
granularity: {
|
|
167
|
+
type: "string",
|
|
168
|
+
enum: [...TIME_SERIES_GRANULARITIES],
|
|
169
|
+
description:
|
|
170
|
+
"For 'getTimeSeries': bucket size. 'month' uses calendar months (label format YYYY-MM). 'quarter' and 'year' honour the book's fiscalYearEnd — for a Q4 book they coincide with calendar quarters / years; Q1/Q2/Q3 books shift accordingly. Quarter labels are 'FY{endYear}-Q{1..4}', year labels are 'FY{endYear}'; the FY is named by its END calendar year (e.g. an FY running Apr 2025 – Mar 2026 is FY2026).",
|
|
171
|
+
},
|
|
172
|
+
// opening
|
|
173
|
+
asOfDate: {
|
|
174
|
+
type: "string",
|
|
175
|
+
description: "For 'setOpeningBalances': YYYY-MM-DD date the balances are stated as-of. Must be on or before any existing entry.",
|
|
176
|
+
},
|
|
177
|
+
// getReport
|
|
178
|
+
kind: {
|
|
179
|
+
type: "string",
|
|
180
|
+
enum: ["balance", "pl", "ledger"],
|
|
181
|
+
description: "For 'getReport': which report. 'balance' = balance sheet; 'pl' = profit & loss; 'ledger' = per-account running balance.",
|
|
182
|
+
},
|
|
183
|
+
period: {
|
|
184
|
+
type: "object",
|
|
185
|
+
description: "For 'getReport': either a single closing month or a date range.",
|
|
186
|
+
properties: {
|
|
187
|
+
kind: { type: "string", enum: ["month", "range"] },
|
|
188
|
+
period: { type: "string", description: "For kind='month': YYYY-MM." },
|
|
189
|
+
from: { type: "string" },
|
|
190
|
+
to: { type: "string" },
|
|
191
|
+
},
|
|
192
|
+
required: ["kind"],
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
required: ["action"],
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export default toolDefinition;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// Fiscal-year arithmetic for the accounting plugin.
|
|
2
|
+
//
|
|
3
|
+
// Each book stores a `fiscalYearEnd` token (Q1..Q4) that says which
|
|
4
|
+
// calendar-quarter end is the book's fiscal year end:
|
|
5
|
+
//
|
|
6
|
+
// Q1 → fiscal year ends March 31 (FY runs Apr 1 → Mar 31)
|
|
7
|
+
// Q2 → fiscal year ends June 30 (FY runs Jul 1 → Jun 30)
|
|
8
|
+
// Q3 → fiscal year ends September 30 (FY runs Oct 1 → Sep 30)
|
|
9
|
+
// Q4 → fiscal year ends December 31 (FY runs Jan 1 → Dec 31; default)
|
|
10
|
+
//
|
|
11
|
+
// "Current quarter" / "current year" everywhere in the UI refer to
|
|
12
|
+
// the *fiscal* quarter / *fiscal* year that contains today, under the
|
|
13
|
+
// active book's `fiscalYearEnd`. For Q4 books fiscal quarters and
|
|
14
|
+
// fiscal years coincide with calendar quarters / calendar years; for
|
|
15
|
+
// the other three a shift applies.
|
|
16
|
+
//
|
|
17
|
+
// All helpers return `YYYY-MM-DD` strings in the user's local
|
|
18
|
+
// timezone — same convention as `dates.ts`.
|
|
19
|
+
|
|
20
|
+
export const FISCAL_YEAR_ENDS = ["Q1", "Q2", "Q3", "Q4"] as const;
|
|
21
|
+
export type FiscalYearEnd = (typeof FISCAL_YEAR_ENDS)[number];
|
|
22
|
+
|
|
23
|
+
export const DEFAULT_FISCAL_YEAR_END: FiscalYearEnd = "Q4";
|
|
24
|
+
|
|
25
|
+
export function isFiscalYearEnd(value: unknown): value is FiscalYearEnd {
|
|
26
|
+
return typeof value === "string" && (FISCAL_YEAR_ENDS as readonly string[]).includes(value);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Books written before the field existed are treated as Q4 in code
|
|
30
|
+
* but never auto-rewritten on disk. The settings UI persists through
|
|
31
|
+
* the field the next time the user saves anything on the book. */
|
|
32
|
+
export function resolveFiscalYearEnd(value: FiscalYearEnd | undefined): FiscalYearEnd {
|
|
33
|
+
return value ?? DEFAULT_FISCAL_YEAR_END;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Last calendar month (1-12) of the fiscal year for the given Q. */
|
|
37
|
+
export function fiscalYearEndMonth(end: FiscalYearEnd): 3 | 6 | 9 | 12 {
|
|
38
|
+
if (end === "Q1") return 3;
|
|
39
|
+
if (end === "Q2") return 6;
|
|
40
|
+
if (end === "Q3") return 9;
|
|
41
|
+
return 12;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface DateRange {
|
|
45
|
+
/** Inclusive lower bound (YYYY-MM-DD). Empty string = unbounded. */
|
|
46
|
+
from: string;
|
|
47
|
+
/** Inclusive upper bound (YYYY-MM-DD). Empty string = unbounded. */
|
|
48
|
+
to: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function pad2(num: number): string {
|
|
52
|
+
return String(num).padStart(2, "0");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function lastDayOfMonth(year: number, monthZeroBased: number): number {
|
|
56
|
+
// Day 0 of next month = last day of this month, all in local time.
|
|
57
|
+
return new Date(year, monthZeroBased + 1, 0).getDate();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function ymd(year: number, monthOneBased: number, day: number): string {
|
|
61
|
+
return `${year}-${pad2(monthOneBased)}-${pad2(day)}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Fiscal quarter index (0..3) of the given local date under `end`,
|
|
65
|
+
* where 0 is the first quarter of the fiscal year (right after the
|
|
66
|
+
* prior year's close) and 3 is the closing quarter. */
|
|
67
|
+
function fiscalQuarterIndex(end: FiscalYearEnd, today: Date): number {
|
|
68
|
+
const closingMonth = fiscalYearEndMonth(end); // 1-based
|
|
69
|
+
const month = today.getMonth() + 1; // 1-based local month
|
|
70
|
+
// Months past the close of the prior fiscal year, mod 12.
|
|
71
|
+
const offset = (month - closingMonth - 1 + 12) % 12;
|
|
72
|
+
return Math.floor(offset / 3);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Calendar (year, monthOneBased) of the *first* month of the fiscal
|
|
76
|
+
* quarter at index `index` in the fiscal year that *contains*
|
|
77
|
+
* `today`. Returned both as the first day of that month and as the
|
|
78
|
+
* count of months covered (always 3 — exposed as a constant). */
|
|
79
|
+
function fiscalQuarterStart(end: FiscalYearEnd, today: Date, index: number): { year: number; month: number } {
|
|
80
|
+
const closingMonth = fiscalYearEndMonth(end);
|
|
81
|
+
const todayMonth = today.getMonth() + 1;
|
|
82
|
+
const todayYear = today.getFullYear();
|
|
83
|
+
// Month after the close of the prior fiscal year — fiscal-year start month.
|
|
84
|
+
const startMonth = (closingMonth % 12) + 1;
|
|
85
|
+
// The fiscal year that contains `today` started in the calendar
|
|
86
|
+
// year ≤ today's year. Specifically: if today's calendar month is
|
|
87
|
+
// ≥ startMonth (or startMonth is 1, which is the Q4 case), the FY
|
|
88
|
+
// started this calendar year; otherwise it started last year.
|
|
89
|
+
const fyStartYear = todayMonth >= startMonth ? todayYear : todayYear - 1;
|
|
90
|
+
// Month of the requested fiscal quarter's first month, expressed
|
|
91
|
+
// as a 1-based offset from January of fyStartYear.
|
|
92
|
+
const flatMonth = startMonth + index * 3; // 1-based, may exceed 12
|
|
93
|
+
const year = fyStartYear + Math.floor((flatMonth - 1) / 12);
|
|
94
|
+
const month = ((flatMonth - 1) % 12) + 1;
|
|
95
|
+
return { year, month };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function quarterRangeAt(end: FiscalYearEnd, today: Date, index: number): DateRange {
|
|
99
|
+
const start = fiscalQuarterStart(end, today, index);
|
|
100
|
+
// Quarter spans 3 calendar months starting at `start`.
|
|
101
|
+
const lastMonthFlat = start.month - 1 + 2; // 0-based offset of the third month
|
|
102
|
+
const lastMonthYear = start.year + Math.floor(lastMonthFlat / 12);
|
|
103
|
+
const lastMonth = (lastMonthFlat % 12) + 1; // 1-based
|
|
104
|
+
const lastDay = lastDayOfMonth(lastMonthYear, lastMonth - 1);
|
|
105
|
+
return {
|
|
106
|
+
from: ymd(start.year, start.month, 1),
|
|
107
|
+
to: ymd(lastMonthYear, lastMonth, lastDay),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function currentQuarterRange(end: FiscalYearEnd, today: Date = new Date()): DateRange {
|
|
112
|
+
return quarterRangeAt(end, today, fiscalQuarterIndex(end, today));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function previousQuarterRange(end: FiscalYearEnd, today: Date = new Date()): DateRange {
|
|
116
|
+
const idx = fiscalQuarterIndex(end, today);
|
|
117
|
+
if (idx > 0) return quarterRangeAt(end, today, idx - 1);
|
|
118
|
+
// Wrap to Q4 of the prior fiscal year. Step `today` back 3 months
|
|
119
|
+
// — that lands inside the prior fiscal year regardless of `end`,
|
|
120
|
+
// and Q4 (closing) is index 3 within whichever FY contains it.
|
|
121
|
+
const stepped = new Date(today.getFullYear(), today.getMonth() - 3, 1);
|
|
122
|
+
return quarterRangeAt(end, stepped, 3);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Current fiscal year — Q0 start through Q3 close. */
|
|
126
|
+
export function currentFiscalYearRange(end: FiscalYearEnd, today: Date = new Date()): DateRange {
|
|
127
|
+
const first = quarterRangeAt(end, today, 0);
|
|
128
|
+
const last = quarterRangeAt(end, today, 3);
|
|
129
|
+
return { from: first.from, to: last.to };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function previousFiscalYearRange(end: FiscalYearEnd, today: Date = new Date()): DateRange {
|
|
133
|
+
// Step a year back so `quarterRangeAt` resolves the prior FY.
|
|
134
|
+
const stepped = new Date(today.getFullYear() - 1, today.getMonth(), today.getDate());
|
|
135
|
+
return currentFiscalYearRange(end, stepped);
|
|
136
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { PluginRegistration, 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 { META } from "./meta";
|
|
7
|
+
import { wrapWithScope } from "../scope";
|
|
8
|
+
import { apiCall } from "../../utils/api";
|
|
9
|
+
import { makeUuid } from "../../utils/id";
|
|
10
|
+
|
|
11
|
+
// MulmoClaude never invokes `execute()` at runtime (see ToolPlugin
|
|
12
|
+
// contract in src/tools/types.ts) — Claude → MCP → REST goes
|
|
13
|
+
// straight to /api/accounting. The implementation is kept as a
|
|
14
|
+
// one-line passthrough to satisfy the gui-chat-protocol shape.
|
|
15
|
+
export type AccountingActionData = Record<string, unknown>;
|
|
16
|
+
|
|
17
|
+
const accountingPlugin: ToolPlugin<AccountingActionData> = {
|
|
18
|
+
toolDefinition,
|
|
19
|
+
|
|
20
|
+
async execute(_context, args) {
|
|
21
|
+
const toolName = toolDefinition.name;
|
|
22
|
+
const { method, path } = META.apiRoutes.dispatch;
|
|
23
|
+
const result = await apiCall<ToolResult<AccountingActionData>>(`/api/${META.apiNamespace}${path}`, { method, body: args });
|
|
24
|
+
if (!result.ok) {
|
|
25
|
+
return {
|
|
26
|
+
toolName,
|
|
27
|
+
uuid: makeUuid(),
|
|
28
|
+
message: result.error,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
...result.data,
|
|
33
|
+
toolName,
|
|
34
|
+
uuid: result.data.uuid ?? makeUuid(),
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
isEnabled: () => true,
|
|
39
|
+
generatingMessage: "Working on the books...",
|
|
40
|
+
viewComponent: wrapWithScope("accounting", View),
|
|
41
|
+
previewComponent: wrapWithScope("accounting", Preview),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default accountingPlugin;
|
|
45
|
+
|
|
46
|
+
export const REGISTRATION: PluginRegistration = {
|
|
47
|
+
toolName: META.toolName,
|
|
48
|
+
entry: accountingPlugin,
|
|
49
|
+
};
|