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.
Files changed (486) hide show
  1. package/Dockerfile.sandbox +100 -0
  2. package/README.md +17 -4
  3. package/bin/mulmoclaude.js +46 -15
  4. package/bin/prepare-dist.js +18 -2
  5. package/client/assets/chunk-CernVdwh.js +1 -0
  6. package/client/assets/chunk-D8eiyYIV-C1eAZMzz.js +1 -0
  7. package/client/assets/html2canvas-CDGcmOD3-BbPeutDg.js +5 -0
  8. package/client/assets/index-BbgSjFQ8.js +4968 -0
  9. package/client/assets/index-ECD0lgIv.css +2 -0
  10. package/client/assets/{index.es-D4YyL_Dg-BgT6a3Nd.js → index.es-DqtpmBm8-DJdTPdnc.js} +5 -5
  11. package/client/assets/material-symbols-outlined-BLDfUw-_.woff2 +0 -0
  12. package/client/assets/runtime-protocol-vue-6WYa8hAs.js +1 -0
  13. package/client/assets/runtime-vue-BVUzgYGA.js +1 -0
  14. package/client/assets/typeof-DBp4T-Ny-C2xoZtcz.js +1 -0
  15. package/client/assets/vue-1e_vz2LW.js +1 -0
  16. package/client/assets/vue.runtime.esm-bundler-DQ8Kjjui.js +4 -0
  17. package/client/index.html +33 -2
  18. package/package.json +20 -18
  19. package/sandbox-entrypoint.sh +106 -0
  20. package/server/accounting/accountNormalize.ts +32 -0
  21. package/server/accounting/defaultAccounts.ts +87 -0
  22. package/server/accounting/eventPublisher.ts +51 -0
  23. package/server/accounting/journal.ts +252 -0
  24. package/server/accounting/openingBalances.ts +114 -0
  25. package/server/accounting/report.ts +237 -0
  26. package/server/accounting/service.ts +718 -0
  27. package/server/accounting/snapshotCache.ts +333 -0
  28. package/server/accounting/timeSeries.ts +265 -0
  29. package/server/accounting/types.ts +148 -0
  30. package/server/agent/activeTools.ts +128 -0
  31. package/server/agent/attachmentConverter.ts +10 -5
  32. package/server/agent/backend/claude-code.ts +8 -2
  33. package/server/agent/backend/types.ts +1 -1
  34. package/server/agent/config.ts +101 -31
  35. package/server/agent/index.ts +45 -33
  36. package/server/agent/mcp-server.ts +146 -69
  37. package/server/agent/mcp-tools/index.ts +1 -5
  38. package/server/agent/mcp-tools/notify.ts +2 -22
  39. package/server/agent/mcp-tools/x.ts +0 -4
  40. package/server/agent/mcpHealth.ts +168 -0
  41. package/server/agent/plugin-names.ts +20 -77
  42. package/server/agent/prompt.ts +259 -51
  43. package/server/agent/resumeFailover.ts +1 -1
  44. package/server/agent/stream.ts +0 -1
  45. package/server/api/auth/bearerAuth.ts +5 -5
  46. package/server/api/csrfGuard.ts +1 -1
  47. package/server/api/routes/accounting.ts +366 -0
  48. package/server/api/routes/agent.ts +509 -46
  49. package/server/api/routes/attachment.ts +104 -0
  50. package/server/api/routes/chart.ts +2 -1
  51. package/server/api/routes/config.ts +12 -12
  52. package/server/api/routes/files.ts +105 -48
  53. package/server/api/routes/image.ts +70 -25
  54. package/server/api/routes/journal.ts +35 -0
  55. package/server/api/routes/mulmo-script.ts +358 -118
  56. package/server/api/routes/mulmoScriptValidate.ts +1 -1
  57. package/server/api/routes/news.ts +1 -1
  58. package/server/api/routes/notifications.ts +92 -22
  59. package/server/api/routes/notifier.ts +98 -0
  60. package/server/api/routes/pdf.ts +188 -48
  61. package/server/api/routes/plugins.ts +34 -14
  62. package/server/api/routes/presentHtml.ts +58 -3
  63. package/server/api/routes/roles.ts +1 -8
  64. package/server/api/routes/runtime-plugin.ts +224 -0
  65. package/server/api/routes/scheduler.ts +7 -5
  66. package/server/api/routes/schedulerHandlers.ts +1 -1
  67. package/server/api/routes/schedulerTasks.ts +8 -7
  68. package/server/api/routes/sessions.ts +234 -121
  69. package/server/api/routes/skills.ts +56 -51
  70. package/server/api/routes/sources.ts +52 -45
  71. package/server/api/routes/translation.ts +44 -0
  72. package/server/api/routes/wiki/frontmatter.ts +13 -65
  73. package/server/api/routes/wiki/history.ts +261 -0
  74. package/server/api/routes/wiki/pageIndex.ts +1 -1
  75. package/server/api/routes/wiki.ts +50 -26
  76. package/server/events/file-change.ts +83 -0
  77. package/server/events/notifications.ts +247 -91
  78. package/server/events/pub-sub/index.ts +1 -1
  79. package/server/events/relay-client.ts +5 -5
  80. package/server/events/scheduler-adapter.ts +2 -2
  81. package/server/events/session-store/index.ts +110 -22
  82. package/server/events/task-manager/index.ts +10 -9
  83. package/server/index.ts +509 -33
  84. package/server/notifier/engine.ts +419 -0
  85. package/server/notifier/legacy-adapters.ts +76 -0
  86. package/server/notifier/runtime-api.ts +74 -0
  87. package/server/notifier/store.ts +70 -0
  88. package/server/notifier/types.ts +121 -0
  89. package/server/plugins/dev-loader.ts +171 -0
  90. package/server/plugins/dev-watcher.ts +150 -0
  91. package/server/plugins/diagnostics.ts +188 -0
  92. package/server/plugins/preset-list.ts +52 -0
  93. package/server/plugins/preset-loader.ts +112 -0
  94. package/server/plugins/runtime-chat-api.ts +38 -0
  95. package/server/plugins/runtime-loader.ts +430 -0
  96. package/server/plugins/runtime-registry.ts +112 -0
  97. package/server/plugins/runtime-tasks-api.ts +50 -0
  98. package/server/plugins/runtime.ts +378 -0
  99. package/server/services/translation/cache.ts +72 -0
  100. package/server/services/translation/index.ts +106 -0
  101. package/server/services/translation/llm.ts +140 -0
  102. package/server/services/translation/types.ts +35 -0
  103. package/server/system/credentials.ts +13 -2
  104. package/server/system/env.ts +6 -1
  105. package/server/system/logger/formatters.ts +46 -4
  106. package/server/system/logger/index.ts +4 -4
  107. package/server/system/logger/sinks.ts +26 -5
  108. package/server/system/logger/types.ts +2 -2
  109. package/server/utils/dev-plugin-args.d.mts +11 -0
  110. package/server/utils/dev-plugin-args.mjs +43 -0
  111. package/server/utils/errors.ts +13 -4
  112. package/server/utils/files/accounting-io.ts +295 -0
  113. package/server/utils/files/atomic.ts +17 -49
  114. package/server/utils/files/attachment-store.ts +182 -0
  115. package/server/utils/files/html-io.ts +1 -7
  116. package/server/utils/files/html-store.ts +19 -0
  117. package/server/utils/files/image-store.ts +20 -22
  118. package/server/utils/files/index.ts +5 -15
  119. package/server/utils/files/journal-io.ts +7 -35
  120. package/server/utils/files/json.ts +2 -29
  121. package/server/utils/files/markdown-image-fill.ts +6 -37
  122. package/server/utils/files/markdown-store.ts +6 -21
  123. package/server/utils/files/naming.ts +3 -39
  124. package/server/utils/files/plugins-io.ts +100 -0
  125. package/server/utils/files/reference-dirs-io.ts +1 -9
  126. package/server/utils/files/roles-io.ts +2 -10
  127. package/server/utils/files/safe.ts +17 -19
  128. package/server/utils/files/scheduler-io.ts +1 -7
  129. package/server/utils/files/scheduler-overrides-io.ts +3 -12
  130. package/server/utils/files/session-io.ts +21 -30
  131. package/server/utils/files/spreadsheet-store.ts +9 -22
  132. package/server/utils/files/translation-io.ts +46 -0
  133. package/server/utils/files/user-tasks-io.ts +1 -7
  134. package/server/utils/files/workspace-io.ts +3 -79
  135. package/server/utils/gemini.ts +33 -11
  136. package/server/utils/html/htmlArtifactSplicer.ts +41 -0
  137. package/server/utils/markdown/frontmatter.ts +112 -0
  138. package/server/utils/regex.ts +56 -0
  139. package/server/utils/router.ts +41 -0
  140. package/server/utils/slug.ts +5 -3
  141. package/server/utils/time.ts +12 -0
  142. package/server/workspace/chat-index/indexer.ts +15 -2
  143. package/server/workspace/chat-index/summarizer.ts +1 -1
  144. package/server/workspace/custom-dirs.ts +1 -1
  145. package/server/workspace/helps/gemini.md +1 -1
  146. package/server/workspace/helps/guide.md +61 -0
  147. package/server/workspace/helps/index.md +4 -0
  148. package/server/workspace/helps/presenthtml.md +80 -0
  149. package/server/workspace/helps/sandbox.md +7 -0
  150. package/server/workspace/helps/storyteller.md +101 -0
  151. package/server/workspace/helps/telegram.md +1 -0
  152. package/server/workspace/helps/wiki.md +9 -7
  153. package/server/workspace/journal/archivist-cli.ts +7 -33
  154. package/server/workspace/journal/archivist-schemas.ts +5 -43
  155. package/server/workspace/journal/dailyPass.ts +34 -187
  156. package/server/workspace/journal/diff.ts +3 -28
  157. package/server/workspace/journal/index.ts +10 -81
  158. package/server/workspace/journal/indexFile.ts +3 -24
  159. package/server/workspace/journal/latestDaily.ts +51 -0
  160. package/server/workspace/journal/memoryExtractor.ts +4 -20
  161. package/server/workspace/journal/optimizationPass.ts +4 -21
  162. package/server/workspace/journal/paths.ts +4 -23
  163. package/server/workspace/journal/state.ts +6 -29
  164. package/server/workspace/memory/io.ts +213 -0
  165. package/server/workspace/memory/llm-classifier.ts +158 -0
  166. package/server/workspace/memory/migrate.ts +263 -0
  167. package/server/workspace/memory/run.ts +84 -0
  168. package/server/workspace/memory/topic-cluster.ts +218 -0
  169. package/server/workspace/memory/topic-detect.ts +67 -0
  170. package/server/workspace/memory/topic-index-hook.ts +128 -0
  171. package/server/workspace/memory/topic-io.ts +180 -0
  172. package/server/workspace/memory/topic-migrate.ts +248 -0
  173. package/server/workspace/memory/topic-run.ts +172 -0
  174. package/server/workspace/memory/topic-swap.ts +135 -0
  175. package/server/workspace/memory/topic-types.ts +142 -0
  176. package/server/workspace/memory/types.ts +83 -0
  177. package/server/workspace/news/reader.ts +4 -5
  178. package/server/workspace/paths.ts +124 -47
  179. package/server/workspace/roles.ts +2 -11
  180. package/server/workspace/skills/parser.ts +38 -55
  181. package/server/workspace/skills/user-tasks.ts +1 -2
  182. package/server/workspace/skills-preset/mc-library/SKILL.md +188 -0
  183. package/server/workspace/skills-preset.ts +196 -0
  184. package/server/workspace/sources/fetchers/githubIssues.ts +13 -11
  185. package/server/workspace/sources/fetchers/index.ts +1 -1
  186. package/server/workspace/sources/fetchers/rssParser.ts +1 -1
  187. package/server/workspace/sources/pipeline/index.ts +2 -2
  188. package/server/workspace/sources/pipeline/notify.ts +3 -3
  189. package/server/workspace/sources/pipeline/write.ts +2 -2
  190. package/server/workspace/sources/registry.ts +39 -61
  191. package/server/workspace/sources/robots.ts +1 -1
  192. package/server/workspace/tool-trace/classify.ts +2 -1
  193. package/server/workspace/tool-trace/index.ts +1 -1
  194. package/server/workspace/tool-trace/writeSearch.ts +6 -1
  195. package/server/workspace/wiki-backlinks/index.ts +19 -7
  196. package/server/workspace/wiki-backlinks/sessionBacklinks.ts +1 -0
  197. package/server/workspace/wiki-history/hook/snapshot.mjs +98 -0
  198. package/server/workspace/wiki-history/hook/snapshot.ts +135 -0
  199. package/server/workspace/wiki-history/provision.ts +181 -0
  200. package/server/workspace/wiki-pages/io.ts +217 -0
  201. package/server/workspace/wiki-pages/snapshot.ts +380 -0
  202. package/server/workspace/workspace.ts +75 -13
  203. package/src/App.vue +115 -40
  204. package/src/_runtime/protocol-vue.ts +21 -0
  205. package/src/_runtime/vue.ts +22 -0
  206. package/src/components/ChatInput.vue +14 -10
  207. package/src/components/CopyChatButton.vue +76 -0
  208. package/src/components/FileContentRenderer.vue +67 -14
  209. package/src/components/FileTree.vue +2 -2
  210. package/src/components/FilesView.vue +17 -1
  211. package/src/components/NewsView.vue +16 -2
  212. package/src/components/NotificationBell.vue +320 -93
  213. package/src/components/PageChatComposer.vue +5 -4
  214. package/src/components/PluginLauncher.vue +42 -6
  215. package/src/components/PluginScopedRoot.vue +87 -0
  216. package/src/components/RoleSelector.vue +12 -1
  217. package/src/components/RolesView.vue +562 -0
  218. package/src/components/SentAttachmentChip.vue +102 -0
  219. package/src/components/SessionHistoryPanel.vue +109 -20
  220. package/src/components/SessionRoleIcon.vue +7 -4
  221. package/src/components/SessionSidebar.vue +20 -7
  222. package/src/components/SessionTabBar.vue +1 -1
  223. package/src/components/SettingsMcpTab.vue +4 -4
  224. package/src/components/SettingsModal.vue +2 -0
  225. package/src/components/SidebarHeader.vue +16 -5
  226. package/src/components/SourcesManager.vue +23 -9
  227. package/src/components/SourcesView.vue +1 -1
  228. package/src/components/StackView.vue +102 -6
  229. package/src/components/SuggestionsPanel.vue +105 -16
  230. package/src/components/SystemFileBanner.vue +1 -1
  231. package/src/components/TodoExplorer.vue +4 -5
  232. package/src/components/todo/TodoAddDialog.vue +2 -3
  233. package/src/components/todo/TodoEditDialog.vue +1 -2
  234. package/src/components/todo/TodoEditPanel.vue +2 -3
  235. package/src/components/todo/TodoKanbanView.vue +8 -5
  236. package/src/components/todo/TodoListView.vue +3 -5
  237. package/src/components/todo/TodoTableView.vue +7 -5
  238. package/src/composables/useAccountingChannel.ts +58 -0
  239. package/src/composables/useActiveSession.ts +4 -25
  240. package/src/composables/useAppApi.ts +6 -44
  241. package/src/composables/useClipboardCopy.ts +3 -20
  242. package/src/composables/useContentDisplay.ts +33 -2
  243. package/src/composables/useDevPluginReload.ts +23 -0
  244. package/src/composables/useDynamicFavicon.ts +5 -31
  245. package/src/composables/useEventListeners.ts +0 -20
  246. package/src/composables/useExpandedDirs.ts +4 -15
  247. package/src/composables/useFaviconState.ts +12 -46
  248. package/src/composables/useFileChange.ts +53 -0
  249. package/src/composables/useFreshPluginData.ts +6 -43
  250. package/src/composables/useHealth.ts +14 -43
  251. package/src/composables/useImageErrorRepair.ts +104 -0
  252. package/src/composables/useLatestDaily.ts +40 -0
  253. package/src/composables/useMarkdownDoc.ts +39 -0
  254. package/src/composables/useMarkdownLinkHandler.ts +1 -1
  255. package/src/composables/useMcpTools.ts +3 -16
  256. package/src/composables/useNotifications.ts +138 -112
  257. package/src/composables/usePdfDownload.ts +17 -3
  258. package/src/composables/usePendingCalls.ts +8 -26
  259. package/src/composables/usePluginErrorBoundary.ts +68 -0
  260. package/src/composables/usePubSub.ts +9 -17
  261. package/src/composables/useRunElapsed.ts +5 -22
  262. package/src/composables/useSandboxStatus.ts +4 -20
  263. package/src/composables/useSessionDerived.ts +7 -15
  264. package/src/composables/useSessionHistory.ts +70 -29
  265. package/src/composables/useSessionSync.ts +25 -3
  266. package/src/composables/useSkillsList.ts +59 -0
  267. package/src/composables/useTranslatedQueries.ts +109 -0
  268. package/src/config/apiRoutes.ts +181 -80
  269. package/src/config/historyFilters.ts +5 -3
  270. package/src/config/hostEvents.ts +17 -0
  271. package/src/config/mcpCatalog.ts +277 -5
  272. package/src/config/pubsubChannels.ts +134 -12
  273. package/src/config/roles.ts +212 -147
  274. package/src/config/systemFileDescriptors.ts +5 -5
  275. package/src/config/toolNames.ts +52 -30
  276. package/src/config/workspacePaths.ts +26 -2
  277. package/src/lang/de.ts +483 -27
  278. package/src/lang/en.ts +448 -27
  279. package/src/lang/es.ts +474 -27
  280. package/src/lang/fr.ts +476 -27
  281. package/src/lang/ja.ts +465 -27
  282. package/src/lang/ko.ts +466 -27
  283. package/src/lang/pt-BR.ts +473 -27
  284. package/src/lang/zh.ts +463 -27
  285. package/src/lib/vue-i18n.ts +1 -1
  286. package/src/lib/wiki-page/slug.ts +66 -0
  287. package/src/main.ts +85 -0
  288. package/src/plugins/_extras.ts +58 -0
  289. package/src/plugins/_generated/metas.ts +42 -0
  290. package/src/plugins/_generated/registrations.ts +44 -0
  291. package/src/plugins/_generated/server-bindings.ts +47 -0
  292. package/src/plugins/accounting/Preview.vue +106 -0
  293. package/src/plugins/accounting/View.vue +632 -0
  294. package/src/plugins/accounting/actions.ts +34 -0
  295. package/src/plugins/accounting/api.ts +301 -0
  296. package/src/plugins/accounting/components/AccountEditor.vue +250 -0
  297. package/src/plugins/accounting/components/AccountRow.vue +50 -0
  298. package/src/plugins/accounting/components/AccountsList.vue +102 -0
  299. package/src/plugins/accounting/components/AccountsModal.vue +300 -0
  300. package/src/plugins/accounting/components/BalanceSheet.vue +186 -0
  301. package/src/plugins/accounting/components/BookSettings.vue +284 -0
  302. package/src/plugins/accounting/components/BookSwitcher.vue +78 -0
  303. package/src/plugins/accounting/components/DateRangePicker.vue +140 -0
  304. package/src/plugins/accounting/components/JournalEntryForm.vue +504 -0
  305. package/src/plugins/accounting/components/JournalList.vue +553 -0
  306. package/src/plugins/accounting/components/Ledger.vue +206 -0
  307. package/src/plugins/accounting/components/NewBookForm.vue +211 -0
  308. package/src/plugins/accounting/components/OpeningBalancesForm.vue +271 -0
  309. package/src/plugins/accounting/components/ProfitLoss.vue +160 -0
  310. package/src/plugins/accounting/components/accountDraft.ts +13 -0
  311. package/src/plugins/accounting/components/accountNumbering.ts +103 -0
  312. package/src/plugins/accounting/components/accountValidation.ts +75 -0
  313. package/src/plugins/accounting/components/useLatestRequest.ts +44 -0
  314. package/src/plugins/accounting/countries.ts +158 -0
  315. package/src/plugins/accounting/currencies.ts +64 -0
  316. package/src/plugins/accounting/dates.ts +51 -0
  317. package/src/plugins/accounting/definition.ts +199 -0
  318. package/src/plugins/accounting/fiscalYear.ts +136 -0
  319. package/src/plugins/accounting/index.ts +49 -0
  320. package/src/plugins/accounting/meta.ts +91 -0
  321. package/src/plugins/accounting/timeSeriesEnums.ts +16 -0
  322. package/src/plugins/api.ts +125 -0
  323. package/src/plugins/canvas/View.vue +38 -28
  324. package/src/plugins/canvas/definition.ts +10 -8
  325. package/src/plugins/canvas/index.ts +15 -8
  326. package/src/plugins/canvas/meta.ts +12 -0
  327. package/src/plugins/chart/Preview.vue +1 -1
  328. package/src/plugins/chart/View.vue +2 -2
  329. package/src/plugins/chart/definition.ts +12 -2
  330. package/src/plugins/chart/index.ts +15 -7
  331. package/src/plugins/chart/meta.ts +18 -0
  332. package/src/plugins/editImages/definition.ts +44 -0
  333. package/src/plugins/editImages/index.ts +43 -0
  334. package/src/plugins/editImages/meta.ts +5 -0
  335. package/src/plugins/generateImage/View.vue +3 -1
  336. package/src/plugins/generateImage/definition.ts +2 -0
  337. package/src/plugins/generateImage/index.ts +13 -5
  338. package/src/plugins/generateImage/meta.ts +5 -0
  339. package/src/plugins/index.ts +35 -0
  340. package/src/plugins/manageRoles/Preview.vue +7 -4
  341. package/src/plugins/manageRoles/View.vue +12 -8
  342. package/src/plugins/manageRoles/definition.ts +6 -0
  343. package/src/plugins/manageRoles/index.ts +7 -6
  344. package/src/plugins/manageSkills/View.vue +11 -7
  345. package/src/plugins/manageSkills/definition.ts +4 -1
  346. package/src/plugins/manageSkills/index.ts +14 -7
  347. package/src/plugins/manageSkills/meta.ts +21 -0
  348. package/src/plugins/manageSource/definition.ts +4 -1
  349. package/src/plugins/manageSource/index.ts +15 -7
  350. package/src/plugins/manageSource/meta.ts +21 -0
  351. package/src/plugins/markdown/Preview.vue +10 -8
  352. package/src/plugins/markdown/View.vue +84 -17
  353. package/src/plugins/markdown/definition.ts +7 -1
  354. package/src/plugins/markdown/index.ts +15 -8
  355. package/src/plugins/markdown/meta.ts +16 -0
  356. package/src/plugins/meta-types.ts +97 -0
  357. package/src/plugins/metas.ts +224 -0
  358. package/src/plugins/presentForm/Preview.vue +4 -15
  359. package/src/plugins/presentForm/View.vue +35 -78
  360. package/src/plugins/presentForm/definition.ts +7 -6
  361. package/src/plugins/presentForm/index.ts +12 -5
  362. package/src/plugins/presentForm/meta.ts +11 -0
  363. package/src/plugins/presentForm/plugin.ts +8 -9
  364. package/src/plugins/presentForm/types.ts +0 -24
  365. package/src/plugins/presentHtml/Preview.vue +1 -8
  366. package/src/plugins/presentHtml/View.vue +401 -30
  367. package/src/plugins/presentHtml/definition.ts +8 -5
  368. package/src/plugins/presentHtml/index.ts +15 -8
  369. package/src/plugins/presentHtml/meta.ts +14 -0
  370. package/src/plugins/presentMulmoScript/View.vue +327 -107
  371. package/src/plugins/presentMulmoScript/definition.ts +34 -7
  372. package/src/plugins/presentMulmoScript/helpers.ts +4 -5
  373. package/src/plugins/presentMulmoScript/index.ts +20 -7
  374. package/src/plugins/presentMulmoScript/meta.ts +52 -0
  375. package/src/plugins/scheduler/AutomationsPreview.vue +2 -8
  376. package/src/plugins/scheduler/Preview.vue +5 -2
  377. package/src/plugins/scheduler/TasksTab.vue +16 -36
  378. package/src/plugins/scheduler/View.vue +22 -54
  379. package/src/plugins/scheduler/automationsDefinition.ts +14 -9
  380. package/src/plugins/scheduler/automationsMeta.ts +5 -0
  381. package/src/plugins/scheduler/calendarDefinition.ts +4 -7
  382. package/src/plugins/scheduler/calendarMeta.ts +28 -0
  383. package/src/plugins/scheduler/formatSchedule.ts +6 -24
  384. package/src/plugins/scheduler/index.ts +26 -52
  385. package/src/plugins/scope.ts +57 -0
  386. package/src/plugins/server-bindings-types.ts +38 -0
  387. package/src/plugins/server.ts +32 -0
  388. package/src/plugins/skill/Preview.vue +25 -0
  389. package/src/plugins/skill/View.vue +125 -0
  390. package/src/plugins/skill/definition.ts +23 -0
  391. package/src/plugins/skill/index.ts +36 -0
  392. package/src/plugins/skill/plugin.ts +31 -0
  393. package/src/plugins/skill/types.ts +21 -0
  394. package/src/plugins/spreadsheet/Preview.vue +1 -3
  395. package/src/plugins/spreadsheet/View.vue +29 -49
  396. package/src/plugins/spreadsheet/cellHighlights.ts +2 -3
  397. package/src/plugins/spreadsheet/definition.ts +5 -2
  398. package/src/plugins/spreadsheet/index.ts +15 -8
  399. package/src/plugins/spreadsheet/keyboardNav.ts +38 -0
  400. package/src/plugins/spreadsheet/meta.ts +14 -0
  401. package/src/plugins/textResponse/Preview.vue +9 -1
  402. package/src/plugins/textResponse/View.vue +59 -8
  403. package/src/plugins/textResponse/index.ts +11 -3
  404. package/src/plugins/textResponse/plugin.ts +8 -10
  405. package/src/plugins/textResponse/types.ts +28 -0
  406. package/src/plugins/wiki/Preview.vue +6 -4
  407. package/src/plugins/wiki/View.vue +463 -254
  408. package/src/plugins/wiki/components/WikiPageBody.vue +159 -0
  409. package/src/plugins/wiki/helpers.ts +17 -0
  410. package/src/plugins/wiki/history/HistoryDetail.vue +325 -0
  411. package/src/plugins/wiki/history/HistoryTab.vue +167 -0
  412. package/src/plugins/wiki/history/RestoreConfirm.vue +63 -0
  413. package/src/plugins/wiki/history/api.ts +52 -0
  414. package/src/plugins/wiki/history/diff.ts +145 -0
  415. package/src/plugins/wiki/index.ts +42 -32
  416. package/src/plugins/wiki/meta.ts +10 -0
  417. package/src/plugins/wiki/pageEditLoader.ts +53 -0
  418. package/src/plugins/wiki/route.ts +8 -0
  419. package/src/router/guards.ts +2 -1
  420. package/src/router/index.ts +19 -0
  421. package/src/router/pageRoutes.ts +1 -0
  422. package/src/tools/index.ts +50 -51
  423. package/src/tools/runtimeLoader.ts +141 -0
  424. package/src/tools/types.ts +44 -1
  425. package/src/types/notification.ts +23 -0
  426. package/src/types/pastedFile.ts +10 -0
  427. package/src/types/session.ts +61 -3
  428. package/src/types/sse.ts +21 -6
  429. package/src/utils/agent/eventDispatch.ts +12 -9
  430. package/src/utils/agent/pastedAttachment.ts +35 -0
  431. package/src/utils/agent/request.ts +32 -3
  432. package/src/utils/agent/toolCalls.ts +7 -1
  433. package/src/utils/api.ts +1 -1
  434. package/src/utils/chat/exportMarkdown.ts +243 -0
  435. package/src/utils/errors.ts +10 -2
  436. package/src/utils/files/expandedDirs.ts +1 -1
  437. package/src/utils/filesPreview/todoPreview.ts +13 -2
  438. package/src/utils/format/date.ts +1 -3
  439. package/src/utils/format/jsonSyntax.ts +5 -0
  440. package/src/utils/html/iframeHeightReporterScript.ts +62 -0
  441. package/src/utils/html/previewCsp.ts +29 -2
  442. package/src/utils/image/htmlSrcAttrs.ts +122 -0
  443. package/src/utils/image/imageRepairInlineScript.ts +115 -0
  444. package/src/utils/image/resolve.ts +17 -3
  445. package/src/utils/image/rewriteMarkdownImageRefs.ts +62 -9
  446. package/src/utils/markdown/frontmatter.ts +125 -0
  447. package/src/utils/markdown/taskList.ts +7 -2
  448. package/src/utils/plugin/runtime.ts +132 -0
  449. package/src/utils/session/mergeSessions.ts +40 -37
  450. package/src/utils/session/sessionEntries.ts +74 -18
  451. package/src/utils/session/sessionHelpers.ts +54 -10
  452. package/src/utils/tools/result.ts +76 -14
  453. package/src/vite-env.d.ts +6 -0
  454. package/client/assets/html2canvas-Cx501zZr-Bug0qRNv.js +0 -5
  455. package/client/assets/index-CY-WpQUm.css +0 -2
  456. package/client/assets/index-DbTz2Mfs.js +0 -4911
  457. package/client/assets/material-symbols-outlined-NzYEeyps.woff2 +0 -0
  458. package/server/api/routes/html.ts +0 -114
  459. package/server/api/routes/todos.ts +0 -293
  460. package/server/api/routes/todosColumnsHandlers.ts +0 -333
  461. package/server/api/routes/todosHandlers.ts +0 -274
  462. package/server/api/routes/todosItemsHandlers.ts +0 -386
  463. package/server/utils/files/todos-io.ts +0 -29
  464. package/src/components/NotificationToast.vue +0 -75
  465. package/src/plugins/editImage/definition.ts +0 -27
  466. package/src/plugins/editImage/index.ts +0 -37
  467. package/src/plugins/presentHtml/helpers.ts +0 -72
  468. package/src/plugins/scheduler/LegacySchedulerView.vue +0 -32
  469. package/src/plugins/scheduler/legacyShape.ts +0 -34
  470. package/src/plugins/todo/Preview.vue +0 -68
  471. package/src/plugins/todo/View.vue +0 -378
  472. package/src/plugins/todo/composables/useTodos.ts +0 -179
  473. package/src/plugins/todo/definition.ts +0 -45
  474. package/src/plugins/todo/index.ts +0 -62
  475. package/src/plugins/todo/labels.ts +0 -163
  476. package/src/plugins/todo/priority.ts +0 -98
  477. package/src/plugins/todo/viewModes.ts +0 -19
  478. package/src/plugins/wiki/definition.ts +0 -25
  479. package/src/tools/legacyPluginNames.ts +0 -13
  480. package/src/utils/format/frontmatter.ts +0 -80
  481. package/src/utils/image/rewriteHtmlImageRefs.ts +0 -50
  482. package/src/utils/notification/dispatch.ts +0 -58
  483. /package/client/assets/{purify.es-Fx1Nqyry-BwJECkqS.js → purify.es-Fx1Nqyry-BSVNht6S.js} +0 -0
  484. /package/src/plugins/{editImage → editImages}/Preview.vue +0 -0
  485. /package/src/plugins/{editImage → editImages}/View.vue +0 -0
  486. /package/src/{config/schedulerActions.ts → plugins/scheduler/actions.ts} +0 -0
@@ -0,0 +1,206 @@
1
+ <template>
2
+ <div class="flex flex-col gap-3" data-testid="accounting-ledger">
3
+ <div class="flex flex-wrap items-end gap-3">
4
+ <label class="text-xs text-gray-500 flex flex-col gap-1">
5
+ {{ t("pluginAccounting.ledger.selectAccount") }}
6
+ <select v-model="accountCode" class="h-8 px-2 rounded border border-gray-300 text-sm bg-white" data-testid="accounting-ledger-account">
7
+ <option value="">{{ DASH }}</option>
8
+ <option v-for="account in selectableAccounts" :key="account.code" :value="account.code">{{ formatAccountLabel(account) }}</option>
9
+ </select>
10
+ </label>
11
+ <DateRangePicker v-model="range" :fiscal-year-end="resolvedFiscalYearEnd" :opening-date="openingDate" />
12
+ <button class="h-8 px-2.5 rounded border border-gray-300 text-sm text-gray-600 hover:bg-gray-50" @click="refresh">
13
+ <span class="material-icons text-base align-middle">refresh</span>
14
+ </button>
15
+ </div>
16
+ <p v-if="loading" class="text-xs text-gray-400">{{ t("pluginAccounting.common.loading") }}</p>
17
+ <p v-else-if="error" class="text-xs text-red-500">{{ t("pluginAccounting.common.error", { error }) }}</p>
18
+ <template v-else-if="ledger">
19
+ <table class="w-full text-sm" :data-testid="showTaxRegistrationColumn ? 'accounting-ledger-table-with-tax-id' : 'accounting-ledger-table'">
20
+ <thead>
21
+ <tr class="text-xs text-gray-500 border-b border-gray-200">
22
+ <th class="text-left py-1 px-2">{{ t("pluginAccounting.ledger.columns.date") }}</th>
23
+ <th class="text-left py-1 px-2">{{ t("pluginAccounting.ledger.columns.memo") }}</th>
24
+ <th v-if="showTaxRegistrationColumn" class="text-left py-1 px-2 w-40">
25
+ {{ t("pluginAccounting.ledger.columns.taxRegistrationId") }}
26
+ </th>
27
+ <th class="text-right py-1 px-2 w-28">{{ t("pluginAccounting.ledger.columns.debit") }}</th>
28
+ <th class="text-right py-1 px-2 w-28">{{ t("pluginAccounting.ledger.columns.credit") }}</th>
29
+ <th class="text-right py-1 px-2 w-28">{{ t("pluginAccounting.ledger.columns.balance") }}</th>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ <tr
34
+ v-for="row in ledger.rows"
35
+ :key="`${row.entryId}-${row.date}`"
36
+ :class="row.kind === 'void' || row.kind === 'void-marker' ? 'text-gray-400 line-through' : ''"
37
+ class="border-b border-gray-100"
38
+ >
39
+ <td class="py-1 px-2 whitespace-nowrap">{{ row.date }}</td>
40
+ <td class="py-1 px-2">
41
+ <span v-if="row.memo">{{ row.memo }}</span>
42
+ </td>
43
+ <td v-if="showTaxRegistrationColumn" class="py-1 px-2 font-mono text-xs">
44
+ <span v-if="row.taxRegistrationId">{{ row.taxRegistrationId }}</span>
45
+ </td>
46
+ <td class="py-1 px-2 text-right">
47
+ <span v-if="row.debit">{{ formatAmount(row.debit) }}</span>
48
+ </td>
49
+ <td class="py-1 px-2 text-right">
50
+ <span v-if="row.credit">{{ formatAmount(row.credit) }}</span>
51
+ </td>
52
+ <td class="py-1 px-2 text-right font-mono">{{ formatAmount(row.runningBalance) }}</td>
53
+ </tr>
54
+ </tbody>
55
+ <tfoot>
56
+ <tr class="font-semibold border-t border-gray-300">
57
+ <td :colspan="showTaxRegistrationColumn ? 5 : 4" class="py-1 px-2 text-right">
58
+ {{ t("pluginAccounting.ledger.closingBalance") }}
59
+ </td>
60
+ <td class="py-1 px-2 text-right">{{ formatAmount(ledger.closingBalance) }}</td>
61
+ </tr>
62
+ </tfoot>
63
+ </table>
64
+ </template>
65
+ </div>
66
+ </template>
67
+
68
+ <script setup lang="ts">
69
+ import { computed, ref, watch } from "vue";
70
+ import { useI18n } from "vue-i18n";
71
+ import { getLedger, type Account, type Ledger, type ReportPeriod } from "../api";
72
+ import { formatAmount as formatAmountWithCurrency } from "../currencies";
73
+ import { currentFiscalYearRange, resolveFiscalYearEnd, type DateRange, type FiscalYearEnd } from "../fiscalYear";
74
+ import { isTaxAccountCode } from "./accountNumbering";
75
+ import { useLatestRequest } from "./useLatestRequest";
76
+ import DateRangePicker from "./DateRangePicker.vue";
77
+
78
+ const { t } = useI18n();
79
+
80
+ const props = defineProps<{
81
+ bookId: string;
82
+ accounts: Account[];
83
+ currency: string;
84
+ version: number;
85
+ fiscalYearEnd?: FiscalYearEnd;
86
+ /** Opening-balance date for the active book — drives the "Lifetime"
87
+ * shortcut in the date picker (from = openingDate, to = today).
88
+ * When absent, the picker hides Lifetime; "All" still works. */
89
+ openingDate?: string;
90
+ /** Optional account to preselect (Accounts tab → click). Updates
91
+ * via the watcher below — assigning to the local `accountCode`
92
+ * ref keeps the dropdown's v-model authoritative for user edits. */
93
+ preselectAccountCode?: string;
94
+ }>();
95
+
96
+ const DASH = "—";
97
+ const accountCode = ref("");
98
+ const ledger = ref<Ledger | null>(null);
99
+ const loading = ref(false);
100
+ const error = ref<string | null>(null);
101
+ const { begin: beginRequest, isCurrent } = useLatestRequest();
102
+
103
+ const resolvedFiscalYearEnd = computed<FiscalYearEnd>(() => resolveFiscalYearEnd(props.fiscalYearEnd));
104
+
105
+ // Default range = current fiscal year. Re-evaluated when bookId or
106
+ // fiscalYearEnd changes (see watcher) so switching books resets to a
107
+ // sensible window rather than carrying the prior book's custom edits.
108
+ const range = ref<DateRange>(currentFiscalYearRange(resolvedFiscalYearEnd.value));
109
+
110
+ function formatAmount(value: number): string {
111
+ return formatAmountWithCurrency(value, props.currency);
112
+ }
113
+
114
+ function formatAccountLabel(account: Account): string {
115
+ // Name first so type-to-search in the <select> matches the
116
+ // human-meaningful word; the code goes in trailing parens.
117
+ return `${account.name} (${account.code})`;
118
+ }
119
+
120
+ // Hide deactivated accounts from the ledger picker; historical
121
+ // entries on a soft-deleted account are still inspectable via
122
+ // the journal-list filter (which intentionally shows every code
123
+ // so the past stays queryable).
124
+ const selectableAccounts = computed<Account[]>(() => props.accounts.filter((account) => account.active !== false));
125
+
126
+ // Surface the T-number column when the active account is in the
127
+ // input-tax band (14xx — e.g. 1400 Input Tax Receivable).
128
+ // Convention-driven so any custom account a user adds in the band
129
+ // participates without an opt-in flag. 24xx (Sales Tax Payable
130
+ // and friends) intentionally doesn't get the column — the
131
+ // counterparty registration ID matters for input-tax-credit
132
+ // eligibility on purchases, not for the seller-side liability.
133
+ const showTaxRegistrationColumn = computed<boolean>(() => {
134
+ if (!ledger.value) return false;
135
+ return isTaxAccountCode(ledger.value.accountCode);
136
+ });
137
+
138
+ // Build a ReportPeriod from the current range. Both ends empty = no
139
+ // filter (full history); either end alone gets a sentinel on the
140
+ // other side so the server-side range filter still applies.
141
+ function periodFromRange(value: DateRange): ReportPeriod | undefined {
142
+ if (value.from === "" && value.to === "") return undefined;
143
+ return { kind: "range", from: value.from || "0000-01-01", to: value.to || "9999-12-31" };
144
+ }
145
+
146
+ async function refresh(): Promise<void> {
147
+ const token = beginRequest();
148
+ if (!accountCode.value) {
149
+ ledger.value = null;
150
+ error.value = null;
151
+ loading.value = false;
152
+ return;
153
+ }
154
+ loading.value = true;
155
+ error.value = null;
156
+ try {
157
+ const result = await getLedger(accountCode.value, periodFromRange(range.value), props.bookId);
158
+ // Drop the result if a newer refresh started (bookId or
159
+ // accountCode changed under us) — otherwise a slower earlier
160
+ // request could overwrite the fresh ledger.
161
+ if (!isCurrent(token)) return;
162
+ if (!result.ok) {
163
+ error.value = result.error;
164
+ ledger.value = null;
165
+ return;
166
+ }
167
+ ledger.value = result.data.ledger;
168
+ } finally {
169
+ if (isCurrent(token)) loading.value = false;
170
+ }
171
+ }
172
+
173
+ // Reset to current-year window AND drop the selected account
174
+ // whenever the active book or its fiscal-year end changes. Without
175
+ // the accountCode reset, switching from book A (cash=1000) to book
176
+ // B (which may not even define 1000) fires a getLedger for a
177
+ // missing code and surfaces an avoidable 404. The range reset
178
+ // follows the same logic — a custom window from book A is
179
+ // meaningless against book B's entries.
180
+ watch(
181
+ () => [props.bookId, resolvedFiscalYearEnd.value],
182
+ () => {
183
+ accountCode.value = "";
184
+ range.value = currentFiscalYearRange(resolvedFiscalYearEnd.value);
185
+ },
186
+ );
187
+
188
+ // Apply parent-supplied preselection (Accounts tab → click). The
189
+ // watcher fires on both initial mount (with `immediate`) and on
190
+ // every prop change so re-clicking the same account from the
191
+ // Accounts tab while already on the Ledger still routes through.
192
+ // Resets the range to the current fiscal year on each preselect so
193
+ // a stale custom window the user left behind on the Ledger doesn't
194
+ // hide the entries the Accounts tab handed off.
195
+ watch(
196
+ () => props.preselectAccountCode,
197
+ (next) => {
198
+ if (!next) return;
199
+ accountCode.value = next;
200
+ range.value = currentFiscalYearRange(resolvedFiscalYearEnd.value);
201
+ },
202
+ { immediate: true },
203
+ );
204
+
205
+ watch(() => [props.bookId, props.version, accountCode.value, range.value.from, range.value.to], refresh, { immediate: true });
206
+ </script>
@@ -0,0 +1,211 @@
1
+ <template>
2
+ <!-- Form for creating a new book. Two layouts share one body:
3
+ • modal (default) — used by BookSwitcher's "+ New book…"
4
+ sentinel option. Backdrop click cancels.
5
+ • fullPage — used by View.vue on the first-run flow when
6
+ the workspace has zero books. No backdrop, no cancel:
7
+ the user MUST create their first book to proceed.
8
+ The submit calls createBook directly; on success it emits
9
+ the new book and its id, leaving the parent to update its
10
+ current selection / refetch. -->
11
+ <div :class="wrapperClass" data-testid="accounting-new-book-modal" @click.self="onBackdropClick">
12
+ <form class="bg-white p-4 rounded shadow-lg w-96 flex flex-col gap-3" data-testid="accounting-new-book-form" @submit.prevent="onSubmit">
13
+ <h3 class="text-base font-semibold">{{ t("pluginAccounting.bookSwitcher.newBook") }}</h3>
14
+ <p v-if="firstRun" class="text-xs text-gray-500" data-testid="accounting-new-book-firstrun">{{ t("pluginAccounting.bookSwitcher.firstRunHint") }}</p>
15
+ <label class="text-sm flex flex-col gap-1">
16
+ {{ t("pluginAccounting.bookSwitcher.nameLabel") }}
17
+ <input ref="nameInput" v-model="name" required class="h-8 px-2 rounded border border-gray-300 text-sm" data-testid="accounting-new-book-name" />
18
+ </label>
19
+ <label class="text-sm flex flex-col gap-1">
20
+ {{ t("pluginAccounting.bookSwitcher.currencyLabel") }}
21
+ <select v-model="currency" class="h-8 px-2 rounded border border-gray-300 text-sm bg-white" data-testid="accounting-new-book-currency">
22
+ <option v-for="opt in options" :key="opt.code" :value="opt.code">{{ opt.label }}</option>
23
+ </select>
24
+ </label>
25
+ <label class="text-sm flex flex-col gap-1">
26
+ {{ t("pluginAccounting.bookSwitcher.countryLabel") }}
27
+ <select v-model="country" class="h-8 px-2 rounded border border-gray-300 text-sm bg-white" data-testid="accounting-new-book-country">
28
+ <option value="">{{ t("pluginAccounting.bookSwitcher.countryPlaceholder") }}</option>
29
+ <option v-for="opt in countryOptions" :key="opt.code" :value="opt.code">{{ opt.label }}</option>
30
+ </select>
31
+ </label>
32
+ <p class="text-xs text-gray-500">{{ t("pluginAccounting.bookSwitcher.countryHint") }}</p>
33
+ <label class="text-sm flex flex-col gap-1">
34
+ {{ t("pluginAccounting.bookSwitcher.fiscalYearEndLabel") }}
35
+ <select
36
+ v-model="fiscalYearEnd"
37
+ required
38
+ class="h-8 px-2 rounded border border-gray-300 text-sm bg-white"
39
+ data-testid="accounting-new-book-fiscal-year-end"
40
+ >
41
+ <option v-for="opt in fiscalYearEndOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</option>
42
+ </select>
43
+ </label>
44
+ <p class="text-xs text-gray-500">{{ t("pluginAccounting.bookSwitcher.fiscalYearEndHint") }}</p>
45
+ <p v-if="error" class="text-xs text-red-500" data-testid="accounting-new-book-error">{{ error }}</p>
46
+ <div class="flex justify-end gap-2 mt-1">
47
+ <button v-if="showCancel" type="button" class="h-8 px-2.5 rounded border border-gray-300 text-sm text-gray-700 hover:bg-gray-50" @click="onCancel">
48
+ {{ t("pluginAccounting.common.cancel") }}
49
+ </button>
50
+ <button
51
+ type="submit"
52
+ class="h-8 px-2.5 rounded bg-blue-600 hover:bg-blue-700 text-white text-sm"
53
+ :disabled="creating"
54
+ data-testid="accounting-new-book-submit"
55
+ >
56
+ {{ creating ? t("pluginAccounting.common.loading") : t("pluginAccounting.bookSwitcher.create") }}
57
+ </button>
58
+ </div>
59
+ </form>
60
+ </div>
61
+ </template>
62
+
63
+ <script setup lang="ts">
64
+ import { computed, nextTick, onMounted, ref } from "vue";
65
+ import { useI18n } from "vue-i18n";
66
+ import { createBook, type BookSummary } from "../api";
67
+ import { SUPPORTED_CURRENCY_CODES, localizedCurrencyName } from "../currencies";
68
+ import { SUPPORTED_COUNTRY_CODES, localizedCountryName, type SupportedCountryCode } from "../countries";
69
+ import { DEFAULT_FISCAL_YEAR_END, FISCAL_YEAR_ENDS, type FiscalYearEnd } from "../fiscalYear";
70
+
71
+ const { t, locale } = useI18n();
72
+
73
+ function regionFromLocaleTag(tag: string): SupportedCountryCode | "" {
74
+ try {
75
+ const { region } = new Intl.Locale(tag).maximize();
76
+ if (region && (SUPPORTED_COUNTRY_CODES as readonly string[]).includes(region)) {
77
+ return region as SupportedCountryCode;
78
+ }
79
+ } catch {
80
+ /* fall through */
81
+ }
82
+ return "";
83
+ }
84
+
85
+ function guessDefaultCountry(uiLocaleTag: string): SupportedCountryCode | "" {
86
+ // Try the active vue-i18n locale first (the user's *app* language
87
+ // setting, e.g. "ja-JP"), then fall back to the browser's
88
+ // navigator.language. Either may produce a region segment that maps
89
+ // to a curated `SupportedCountryCode`. If neither does, leave the
90
+ // field unset rather than silently picking a default — the
91
+ // dropdown's "(choose a country)" option lets the user finish the
92
+ // selection themselves so an unsupported locale doesn't quietly
93
+ // become a US-jurisdiction book.
94
+ const fromUi = regionFromLocaleTag(uiLocaleTag);
95
+ if (fromUi !== "") return fromUi;
96
+ const browserTag = typeof navigator !== "undefined" && typeof navigator.language === "string" ? navigator.language : "";
97
+ return regionFromLocaleTag(browserTag);
98
+ }
99
+
100
+ const props = withDefaults(
101
+ defineProps<{
102
+ firstRun?: boolean;
103
+ cancelable?: boolean;
104
+ fullPage?: boolean;
105
+ }>(),
106
+ { firstRun: false, cancelable: true, fullPage: false },
107
+ );
108
+
109
+ const emit = defineEmits<{
110
+ cancel: [];
111
+ created: [book: BookSummary];
112
+ }>();
113
+
114
+ const name = ref("");
115
+ const currency = ref<string>("USD");
116
+ const country = ref<SupportedCountryCode | "">(guessDefaultCountry(locale.value));
117
+ const fiscalYearEnd = ref<FiscalYearEnd>(DEFAULT_FISCAL_YEAR_END);
118
+ const creating = ref(false);
119
+ const error = ref<string | null>(null);
120
+ const nameInput = ref<HTMLInputElement | null>(null);
121
+
122
+ onMounted(() => {
123
+ // Land focus in Name on open — the only required field; the
124
+ // currency select defaults to USD and the user usually leaves
125
+ // it. Without this the user has to click into the field before
126
+ // typing, which is friction for what should be a one-tap flow.
127
+ void nextTick(() => nameInput.value?.focus());
128
+ });
129
+
130
+ interface CurrencyOption {
131
+ code: string;
132
+ label: string;
133
+ }
134
+
135
+ const options = computed<CurrencyOption[]>(() =>
136
+ SUPPORTED_CURRENCY_CODES.map((code) => ({
137
+ code,
138
+ label: `${code} — ${localizedCurrencyName(code, locale.value)}`,
139
+ })),
140
+ );
141
+
142
+ interface CountryOption {
143
+ code: string;
144
+ label: string;
145
+ }
146
+
147
+ const countryOptions = computed<CountryOption[]>(() =>
148
+ SUPPORTED_COUNTRY_CODES.map((code) => ({
149
+ code,
150
+ label: `${code} — ${localizedCountryName(code, locale.value)}`,
151
+ })),
152
+ );
153
+
154
+ interface FiscalYearEndOption {
155
+ value: FiscalYearEnd;
156
+ label: string;
157
+ }
158
+
159
+ const fiscalYearEndOptions = computed<FiscalYearEndOption[]>(() =>
160
+ FISCAL_YEAR_ENDS.map((value) => ({
161
+ value,
162
+ label: t(`pluginAccounting.bookSwitcher.fiscalYearEnd${value}`),
163
+ })),
164
+ );
165
+
166
+ // Full-page mode replaces the AccountingApp chrome — fill the
167
+ // parent flex column with the form centered, no backdrop. Modal
168
+ // mode keeps the original viewport overlay behaviour.
169
+ const wrapperClass = computed(() =>
170
+ props.fullPage ? "flex-1 bg-white flex items-center justify-center p-6 overflow-auto" : "fixed inset-0 z-50 bg-black/20 flex items-center justify-center",
171
+ );
172
+
173
+ // Cancel is hidden in full-page mode regardless of `cancelable`
174
+ // — the first-run flow forces the user to create a book.
175
+ const showCancel = computed(() => props.cancelable && !props.fullPage);
176
+
177
+ function onBackdropClick(): void {
178
+ if (props.fullPage) return;
179
+ onCancel();
180
+ }
181
+
182
+ function onCancel(): void {
183
+ if (!props.cancelable) return;
184
+ emit("cancel");
185
+ }
186
+
187
+ async function onSubmit(): Promise<void> {
188
+ if (creating.value) return;
189
+ creating.value = true;
190
+ error.value = null;
191
+ try {
192
+ // Only forward `country` when the user actually picked one — the
193
+ // empty string is the dropdown's "(choose a country)" sentinel
194
+ // and must not land on disk as a literal "" value.
195
+ const pickedCountry: SupportedCountryCode | undefined = country.value === "" ? undefined : country.value;
196
+ const result = await createBook({
197
+ name: name.value.trim(),
198
+ currency: currency.value,
199
+ country: pickedCountry,
200
+ fiscalYearEnd: fiscalYearEnd.value,
201
+ });
202
+ if (!result.ok) {
203
+ error.value = result.error;
204
+ return;
205
+ }
206
+ emit("created", result.data.book);
207
+ } finally {
208
+ creating.value = false;
209
+ }
210
+ }
211
+ </script>