@forsion/unit 2.13.5 → 2.13.6

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 (179) hide show
  1. package/README.md +2 -2
  2. package/main.mjs +20 -4
  3. package/package.json +1 -1
  4. package/release.json +6 -5
  5. package/web/assets/{ArtificialView-BD1yHz1N.js → ArtificialView-DHqb9CTL.js} +1 -1
  6. package/web/assets/{AutomationBuilder-B09c-5Bi.js → AutomationBuilder-CzBKmOiw.js} +1 -1
  7. package/web/assets/{CalendarConfigView-Bd-ZDGPO.js → CalendarConfigView-Blw47NCs.js} +1 -1
  8. package/web/assets/CalendarSide-CFSzme3H.js +1 -0
  9. package/web/assets/CalendarView-B8sQfgZt.js +3 -0
  10. package/web/assets/{CapabilityMenu-DyHTEYLr.js → CapabilityMenu-Dzn6RbB1.js} +1 -1
  11. package/web/assets/{Chrome-C7F6fdDp.js → Chrome-owLewFu4.js} +1 -1
  12. package/web/assets/{CodeView-BGOnrGhB.js → CodeView-E18NDilX.js} +3 -3
  13. package/web/assets/{CtxMenuButtons-BYjrbUKS.js → CtxMenuButtons-CAiwQkOK.js} +1 -1
  14. package/web/assets/DashboardGridView-CBbYKcCo.js +25 -0
  15. package/web/assets/EventCard-D9uQe7g4.js +1 -0
  16. package/web/assets/{ExcalidrawCanvas-lwJCN6uB.js → ExcalidrawCanvas-BSOERegJ.js} +1 -1
  17. package/web/assets/{FloatingToc-DO7SH8Ku.js → FloatingToc-iK08Qpjc.js} +1 -1
  18. package/web/assets/GitCloneDialog-DfY0kqhP.js +1 -0
  19. package/web/assets/{HomepageView-CHJEhf9c.js → HomepageView-BCqFe1Ym.js} +3 -3
  20. package/web/assets/{ImageStudioPanels-CgVf0wiq.js → ImageStudioPanels-DdwihAkT.js} +2 -2
  21. package/web/assets/ImageStudioView-gJSYrmu1.js +1 -0
  22. package/web/assets/{InlineAiPanel-CdIPINsA.js → InlineAiPanel-CjYOW0_0.js} +1 -1
  23. package/web/assets/InlineFiles-3g2jMUeA.js +1 -0
  24. package/web/assets/{MarkdownBlock-DSItkLhu.js → MarkdownBlock-DjsGkPZ_.js} +24 -24
  25. package/web/assets/{ModelPill--CU3XTIQ.js → ModelPill-DgyXBsL9.js} +2 -2
  26. package/web/assets/MuseLibraryView-D_HBijmU.js +2 -0
  27. package/web/assets/{MuseView-CvsO62Fo.js → MuseView-BVDlmM6i.js} +3 -3
  28. package/web/assets/{PageHistoryPanel-CDh7nm78.js → PageHistoryPanel-B1EAPZeX.js} +2 -2
  29. package/web/assets/{PdfAnnotator-DafvjP3U.js → PdfAnnotator-bdB9evsY.js} +1 -1
  30. package/web/assets/{PenRow-CEy-s6SF.js → PenRow-DCOIGlfY.js} +1 -1
  31. package/web/assets/PluginToolCard-BXE5vA1h.js +2 -0
  32. package/web/assets/{ProductView-AUqnTwmQ.js → ProductView-l5Q7uBy6.js} +1 -1
  33. package/web/assets/{SettingsPage-B9mmkWaM.js → SettingsPage-fjxfS_Mt.js} +2 -2
  34. package/web/assets/{StudioGuestSurface-OOhRA8nt.js → StudioGuestSurface-360CWUwf.js} +1 -1
  35. package/web/assets/TodoListView-BsPt2GUU.js +1 -0
  36. package/web/assets/{Tooltip-DOYi44eY.js → Tooltip-CuXpWtdJ.js} +1 -1
  37. package/web/assets/UnifiedPage-6xbFLtXT.js +712 -0
  38. package/web/assets/{ViewSelectionBar-WmSWMFsR.js → ViewSelectionBar-C5FDh7fO.js} +2 -2
  39. package/web/assets/{appStore-DDOkzWDA.js → appStore-BskcSDl6.js} +114 -115
  40. package/web/assets/{arrow-up-right-BptN64d-.js → arrow-up-right-DEykpgsH.js} +1 -1
  41. package/web/assets/{astryxBridge-BL56QfEv.js → astryxBridge-B2IZdPvo.js} +1 -1
  42. package/web/assets/automationListSource-Cm09JKkK.js +1 -0
  43. package/web/assets/{boardSurface-CP4HNmcm.js → boardSurface-Dv-aVaUJ.js} +1 -1
  44. package/web/assets/{calendarNavStore-DCi7VBmM.js → calendarNavStore-FKStA7Hh.js} +1 -1
  45. package/web/assets/{canvasPrefs-ArsX3NFO.js → canvasPrefs-CMulOS0k.js} +1 -1
  46. package/web/assets/{chatBoxSurface-DRsDr-MT.js → chatBoxSurface-BR_G6cxG.js} +1 -1
  47. package/web/assets/{chevron-up-ChXNh14u.js → chevron-up-C_EDOZzI.js} +1 -1
  48. package/web/assets/{client-fKy9CWk0.js → client-DD5czSuF.js} +1 -1
  49. package/web/assets/{code-xml-DCCD9eCS.js → code-xml-vTB4LtTf.js} +1 -1
  50. package/web/assets/{codeStudioStore-BgLfCDK2.js → codeStudioStore-OswE1_s0.js} +1 -1
  51. package/web/assets/{contextMenuSurface-BF593l2M.js → contextMenuSurface-DqdYEGuH.js} +1 -1
  52. package/web/assets/{copy-plus-ClKrSgM7.js → copy-plus-CVHqDNny.js} +1 -1
  53. package/web/assets/create-DZWy4zBR.js +14 -0
  54. package/web/assets/{dashboardSurface-C6cbR3oG.js → dashboardSurface-Co4byEQm.js} +1 -1
  55. package/web/assets/dbStore-Bc2lC8ZI.js +2 -0
  56. package/web/assets/deskCapture-BfTzH2aO.js +1 -0
  57. package/web/assets/{diff2html-Di8qIz6O.js → diff2html-0MkNy2ws.js} +1 -1
  58. package/web/assets/{docx-preview-B-URZXdP.js → docx-preview-CwNWZegI.js} +1 -1
  59. package/web/assets/{draft-CBSW5tHx.js → draft-DTzuTatQ.js} +2 -2
  60. package/web/assets/{drawingStore-CGvTqqYW.js → drawingStore-BD5m2eqn.js} +1 -1
  61. package/web/assets/{file-down-Z913cCyQ.js → file-down-Cjo_T6By.js} +1 -1
  62. package/web/assets/{floatingTocSurface-DGwTiqvU.js → floatingTocSurface-D3IIVNnq.js} +1 -1
  63. package/web/assets/{foldActions-DGIPTmE1.js → foldActions-utwZpRrA.js} +1 -1
  64. package/web/assets/{folder-1OJQeDI1.js → folder-DiaFWdCg.js} +1 -1
  65. package/web/assets/{folder-minus-D_j1SwHu.js → folder-minus-DUEOcs12.js} +1 -1
  66. package/web/assets/{folder-plus-DP9sFr26.js → folder-plus-Cmhq0GcR.js} +1 -1
  67. package/web/assets/{gestures-ZhFAENNZ.js → gestures-Bx9M0le5.js} +1 -1
  68. package/web/assets/{git-branch-BMajF2cu.js → git-branch-DzGWffyD.js} +1 -1
  69. package/web/assets/{homeCardStatus-5R7XkxFL.js → homeCardStatus-NAk4A77P.js} +1 -1
  70. package/web/assets/{i18n.generated-DW_l6CkR.js → i18n.generated-D4-Wu9Wh.js} +1 -1
  71. package/web/assets/imageStudio-D67oElIb.js +4 -0
  72. package/web/assets/{index-COzdD7mZ.js → index-3VWZ1rsL.js} +1 -1
  73. package/web/assets/{index-bF04pF8q.js → index-58wBjkHy.js} +1 -1
  74. package/web/assets/{index-Cg1FWM_p.js → index-B9_zH7f5.js} +1 -1
  75. package/web/assets/index-BQrMYjou.js +1 -0
  76. package/web/assets/{index-D-ClOPbg.js → index-BWrWMYua.js} +1 -1
  77. package/web/assets/{index-C--E96Ul.js → index-BdLJBf4-.js} +1 -1
  78. package/web/assets/{index-CI2esW1X.js → index-Bf3W92Hb.js} +1 -1
  79. package/web/assets/{index-B8A3nKeL.js → index-BjmPaLFA.js} +1 -1
  80. package/web/assets/{index-BeW45J9J.js → index-Bv-vJTzF.js} +1 -1
  81. package/web/assets/{index-BnJguNqI.js → index-C7yb62gg.js} +1 -1
  82. package/web/assets/{index-CtRdzpNh.js → index-C9gBBMYv.js} +1 -1
  83. package/web/assets/index-CiQ59Kib.js +1 -0
  84. package/web/assets/{index-DfhEDV2T.js → index-CzTUjEMt.js} +1 -1
  85. package/web/assets/{index-BYKR7EVg.js → index-D4Qx6o3E.js} +1 -1
  86. package/web/assets/{index-jzlU5luC.js → index-DDBcn3UD.js} +1 -1
  87. package/web/assets/{index-CtCYv9bF.js → index-DEADY94l.js} +1 -1
  88. package/web/assets/{index-CWXpOSI2.js → index-DGTKsPAQ.js} +1 -1
  89. package/web/assets/{index-SpegRFQV.js → index-DRwDqvjf.js} +1 -1
  90. package/web/assets/{index-BDZIQnEx.js → index-DexVkoxH.js} +1 -1
  91. package/web/assets/{index-uhvJ8AiJ.js → index-IMOhRWY8.js} +1 -1
  92. package/web/assets/{index-Dr6YmrrT.js → index-XjvpYHIo.js} +1 -1
  93. package/web/assets/{index-fDB1l4d-.js → index-YuejkHoJ.js} +51 -37
  94. package/web/assets/{index-CVLDDD5Z.js → index-pH0266gX.js} +1 -1
  95. package/web/assets/{index-BniT-A2n.js → index-sQl_bGM_.js} +1 -1
  96. package/web/assets/{index-CPfmhZ3Z.js → index-vbNFy5lS.js} +1 -1
  97. package/web/assets/{invitePage-iOT1zBvp.js → invitePage-BT_rFfab.js} +1 -1
  98. package/web/assets/{ipc-SAPDwyQ4.js → ipc-8cxXGSZK.js} +1 -1
  99. package/web/assets/{jszip.min-B3n1FGCb.js → jszip.min-By4OI3XR.js} +1 -1
  100. package/web/assets/launchpad-BX4jQyF4.js +2 -0
  101. package/web/assets/{layout-grid-oIyIGbc5.js → layout-grid-CzxXbCDa.js} +1 -1
  102. package/web/assets/{linkFollow-uke1Xtit.js → linkFollow-J2c0wSgB.js} +4 -4
  103. package/web/assets/{listFold-BeNv2v6M.js → listFold-B_2Xqxn_.js} +1 -1
  104. package/web/assets/{lock-open-D2nMg0ga.js → lock-open-DVWCLSZm.js} +1 -1
  105. package/web/assets/{log-out-D70NCXC4.js → log-out-CdKTS7HC.js} +1 -1
  106. package/web/assets/{magnet-Cqmm97W8.js → magnet-BmVcZ9U4.js} +1 -1
  107. package/web/assets/main-CForzSFD.js +15 -0
  108. package/web/assets/{markdownEditorSurface-zUzFity2.js → markdownEditorSurface-Bs8FJNHu.js} +1 -1
  109. package/web/assets/{mediaPlayer-DB4KUvua.js → mediaPlayer-O9pVRl_k.js} +1 -1
  110. package/web/assets/{message-square-plus-BvUfAAZm.js → message-square-plus-CspBv9iG.js} +1 -1
  111. package/web/assets/{messages-GQUjmbwW.js → messages-CG7ywZ-K.js} +1 -1
  112. package/web/assets/{minimize-2-CMhzL6ZW.js → minimize-2-Bq4vUin-.js} +1 -1
  113. package/web/assets/mobileEntry-CptXQ4Ov.js +13 -0
  114. package/web/assets/modelPickerSurface-C0SkjaPL.js +1 -0
  115. package/web/assets/{nativeDownload-DsGyUSJ5.js → nativeDownload-DlnT8U-y.js} +1 -1
  116. package/web/assets/{nativeSheetMenu--iihXNVd.js → nativeSheetMenu-CVC51DzC.js} +1 -1
  117. package/web/assets/{pageStore-ys8L4rjF.css → pageStore-BC6Z18n7.css} +1 -1
  118. package/web/assets/{pageStore-CyvNZEYX.js → pageStore-D_fKLv-o.js} +7 -7
  119. package/web/assets/{pageTree-Ci2qzrs1.js → pageTree-DtDKozTg.js} +3 -3
  120. package/web/assets/{pen-line-DC3lbEY1.js → pen-line-ho1GgAe2.js} +1 -1
  121. package/web/assets/{pen-tool-DD5_N4lZ.js → pen-tool-CV-FKFEZ.js} +1 -1
  122. package/web/assets/{pencil--sWwxHdP.js → pencil-BgF4Kiqp.js} +1 -1
  123. package/web/assets/{phoneList-DKRMxQHf.js → phoneList-BLVdQcXY.js} +1 -1
  124. package/web/assets/pluginChat-C6t6DWhY.js +2 -0
  125. package/web/assets/{react-b7FrqRQR.js → react-DOzedx9n.js} +1 -1
  126. package/web/assets/recordSurface-C9SRNjy4.js +1 -0
  127. package/web/assets/{redo-2-CqlqhWrI.js → redo-2-DWZTaEz-.js} +1 -1
  128. package/web/assets/{rotate-ccw-D8kni6Ni.js → rotate-ccw-CyZpL7MX.js} +1 -1
  129. package/web/assets/{selectionActions-DIq0xDm8.js → selectionActions-C2a8ImJm.js} +1 -1
  130. package/web/assets/selectionBarSurface-DaXlyy1s.js +1 -0
  131. package/web/assets/{sessionTitle-Ctp4iNKu.js → sessionTitle-BtZ1BteL.js} +1 -1
  132. package/web/assets/settingsPageSurface-Cg8FNZq3.js +1 -0
  133. package/web/assets/{sharePage-CY04XCAf.js → sharePage-vnghra3Q.js} +2 -2
  134. package/web/assets/{shareViewer-DweNF8Ch.js → shareViewer-CWJQHiV-.js} +1 -1
  135. package/web/assets/{star-B0sZEmbj.js → star-ZEpUQwnX.js} +1 -1
  136. package/web/assets/tableSurface-DfEdzVDn.js +1 -0
  137. package/web/assets/{tanguProbe-B8Qv2vcm.js → tanguProbe-BboOas-a.js} +6 -6
  138. package/web/assets/{terminalView-BLGdmdl7.js → terminalView-xp8ARBLi.js} +1 -1
  139. package/web/assets/{type-Dt7RNB9g.js → type-CMyP4cKt.js} +1 -1
  140. package/web/assets/{undo-2-QimgpLBn.js → undo-2-C4ZCsMsx.js} +1 -1
  141. package/web/assets/{unitAccount-DL3jfd84.js → unitAccount-DNxfGo3c.js} +1 -1
  142. package/web/assets/{unitBridge-BSsCy1zP.js → unitBridge-Bq0n1ZM6.js} +1 -1
  143. package/web/assets/{unitCloudTransport-CI_6H0TU.js → unitCloudTransport-CErylgEO.js} +1 -1
  144. package/web/assets/{unitOwnerAccess-CiQ7nD7E.js → unitOwnerAccess-7s-3dfNM.js} +1 -1
  145. package/web/assets/{unitShim-Dl2ksNp-.js → unitShim-BfheyIG8.js} +3 -3
  146. package/web/assets/{upload-Dy7svciS.js → upload-VtCrluEO.js} +1 -1
  147. package/web/assets/userSpaces-BpeYjLni.js +1 -0
  148. package/web/assets/viewportLock-cVUalJAI.js +738 -0
  149. package/web/assets/{zoom-in-DDEtY_Go.js → zoom-in-C7R8s9x-.js} +1 -1
  150. package/web/index.html +2 -2
  151. package/web/assets/CalendarSide-B0RVbOsg.js +0 -1
  152. package/web/assets/CalendarView-BHio-n_r.js +0 -3
  153. package/web/assets/DashboardGridView-CR-R_qV8.js +0 -25
  154. package/web/assets/EventCard-QyYorE1_.js +0 -1
  155. package/web/assets/GitCloneDialog-CbW-RJak.js +0 -1
  156. package/web/assets/ImageStudioView-4WcX0_V4.js +0 -1
  157. package/web/assets/InlineFiles-CAIyTk1n.js +0 -1
  158. package/web/assets/MuseLibraryView-PlS7HAlV.js +0 -2
  159. package/web/assets/PluginToolCard-DCzLhsCA.js +0 -2
  160. package/web/assets/TodoListView-BkgMe44I.js +0 -1
  161. package/web/assets/UnifiedPage-s7-tDSwG.js +0 -712
  162. package/web/assets/automationListSource-B1jz6q0t.js +0 -1
  163. package/web/assets/create-DYmVT68X.js +0 -14
  164. package/web/assets/dbStore-BIG5Mfh2.js +0 -1
  165. package/web/assets/deskCapture-q-jRDIcc.js +0 -1
  166. package/web/assets/imageStudio-DC_syDtx.js +0 -4
  167. package/web/assets/index-CIKPZc3Q.js +0 -1
  168. package/web/assets/index-CmsN2Zm2.js +0 -1
  169. package/web/assets/launchpad-CcmSwlJl.js +0 -2
  170. package/web/assets/main-B9aT0WXG.js +0 -15
  171. package/web/assets/mobileEntry-BnHzrdoC.js +0 -13
  172. package/web/assets/modelPickerSurface-Dtz40Ae2.js +0 -1
  173. package/web/assets/pluginChat-82zZt47Y.js +0 -2
  174. package/web/assets/recordSurface-vUX25Z8R.js +0 -1
  175. package/web/assets/selectionBarSurface-B94e5JW_.js +0 -1
  176. package/web/assets/settingsPageSurface-C9TA3mJg.js +0 -1
  177. package/web/assets/tableSurface-CSBYBw5P.js +0 -1
  178. package/web/assets/userSpaces-oMHIWgYe.js +0 -1
  179. package/web/assets/viewportLock-BZq5PTeN.js +0 -738
@@ -1,12 +1,12 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./appStore-DDOkzWDA.js","./react-b7FrqRQR.js","./pageStore-CyvNZEYX.js","./client-fKy9CWk0.js","./pageStore-ys8L4rjF.css","./ipc-SAPDwyQ4.js","./nativeDownload-DsGyUSJ5.js","./dbStore-BIG5Mfh2.js","./drawingStore-CGvTqqYW.js","./appStore-iy8_Tmac.css","./mobileEntry-BnHzrdoC.js","./viewportLock-BZq5PTeN.js","./UnifiedPage-s7-tDSwG.js","./MarkdownBlock-DSItkLhu.js","./index-CmsN2Zm2.js","./linkFollow-uke1Xtit.js","./selectionActions-DIq0xDm8.js","./listFold-BeNv2v6M.js","./FloatingToc-DO7SH8Ku.js","./MarkdownBlock-Cqfk5DhC.css","./type-Dt7RNB9g.js","./upload-Dy7svciS.js","./arrow-up-right-BptN64d-.js","./Chrome-C7F6fdDp.js","./magnet-Cqmm97W8.js","./canvasPrefs-ArsX3NFO.js","./InlineAiPanel-CdIPINsA.js","./InlineAiPanel-DZZijfif.css","./foldActions-DGIPTmE1.js","./undo-2-QimgpLBn.js","./code-xml-DCCD9eCS.js","./message-square-plus-BvUfAAZm.js","./UnifiedPage-CTmQpf2T.css","./ModelPill--CU3XTIQ.js","./nativeSheetMenu--iihXNVd.js","./ModelPill-BiUsuhy3.css","./MuseView-CvsO62Fo.js","./automationListSource-B1jz6q0t.js","./messages-GQUjmbwW.js","./rotate-ccw-D8kni6Ni.js","./git-branch-BMajF2cu.js","./mediaPlayer-DB4KUvua.js","./CapabilityMenu-DyHTEYLr.js","./CapabilityMenu-CTIzmTJB.css","./folder-plus-DP9sFr26.js","./userSpaces-oMHIWgYe.js","./star-B0sZEmbj.js","./layout-grid-oIyIGbc5.js","./folder-1OJQeDI1.js","./DashboardGridView-CR-R_qV8.js","./pageTree-Ci2qzrs1.js","./pluginExt-Byb64tQO.js","./CtxMenuButtons-BYjrbUKS.js","./phoneList-DKRMxQHf.js","./phoneList-BpLxxdq6.css","./pen-tool-DD5_N4lZ.js","./pencil--sWwxHdP.js","./folder-minus-D_j1SwHu.js","./redo-2-CqlqhWrI.js","./file-down-Z913cCyQ.js","./DashboardGridView-RoVFSkNO.css","./SettingsPage-B9mmkWaM.js","./lock-open-D2nMg0ga.js","./AutomationBuilder-B09c-5Bi.js","./gestures-ZhFAENNZ.js","./tanguProbe-B8Qv2vcm.js","./sessionTitle-Ctp4iNKu.js","./index-CIKPZc3Q.js","./create-DYmVT68X.js","./create-BgE3edmZ.css","./launchpad-CcmSwlJl.js","./launchpad-C9U9hpWJ.css","./pdf.worker.min-CGb3BKV9.js","./zoom-in-DDEtY_Go.js","./minimize-2-CMhzL6ZW.js","./InlineFiles-CAIyTk1n.js","./PluginToolCard-DCzLhsCA.js","./PluginToolCard-BmTRr5JT.css","./codeStudioStore-BgLfCDK2.js","./chevron-up-ChXNh14u.js","./pen-line-DC3lbEY1.js","./ViewSelectionBar-WmSWMFsR.js","./GitCloneDialog-CbW-RJak.js","./GitCloneDialog-DOxZk2K0.css","./i18n.generated-DW_l6CkR.js","./i18n-CAf4PT1o.css","./log-out-D70NCXC4.js","./StudioGuestSurface-OOhRA8nt.js","./viewportLock-B0l1GU_k.css","./codingNavigation-BrkLENBZ.css","./mobileEntry-6u7TYC4s.css","./main-B9aT0WXG.js","./main-BlVApHpj.css","./invitePage-iOT1zBvp.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./appStore-BskcSDl6.js","./dbStore-Bc2lC8ZI.js","./pageStore-D_fKLv-o.js","./react-DOzedx9n.js","./client-DD5czSuF.js","./pageStore-BC6Z18n7.css","./ipc-8cxXGSZK.js","./nativeDownload-DlnT8U-y.js","./drawingStore-BD5m2eqn.js","./appStore-iy8_Tmac.css","./mobileEntry-CptXQ4Ov.js","./viewportLock-cVUalJAI.js","./UnifiedPage-6xbFLtXT.js","./MarkdownBlock-DjsGkPZ_.js","./index-CiQ59Kib.js","./linkFollow-J2c0wSgB.js","./selectionActions-C2a8ImJm.js","./listFold-B_2Xqxn_.js","./FloatingToc-iK08Qpjc.js","./MarkdownBlock-Cqfk5DhC.css","./type-CMyP4cKt.js","./upload-VtCrluEO.js","./arrow-up-right-DEykpgsH.js","./Chrome-owLewFu4.js","./magnet-BmVcZ9U4.js","./canvasPrefs-CMulOS0k.js","./InlineAiPanel-CjYOW0_0.js","./InlineAiPanel-DZZijfif.css","./foldActions-utwZpRrA.js","./undo-2-C4ZCsMsx.js","./code-xml-vTB4LtTf.js","./message-square-plus-CspBv9iG.js","./UnifiedPage-CTmQpf2T.css","./ModelPill-DgyXBsL9.js","./nativeSheetMenu-CVC51DzC.js","./ModelPill-BiUsuhy3.css","./MuseView-BVDlmM6i.js","./automationListSource-Cm09JKkK.js","./messages-CG7ywZ-K.js","./rotate-ccw-CyZpL7MX.js","./git-branch-DzGWffyD.js","./mediaPlayer-O9pVRl_k.js","./CapabilityMenu-Dzn6RbB1.js","./CapabilityMenu-CTIzmTJB.css","./folder-plus-Cmhq0GcR.js","./userSpaces-BpeYjLni.js","./star-ZEpUQwnX.js","./layout-grid-CzxXbCDa.js","./folder-DiaFWdCg.js","./DashboardGridView-CBbYKcCo.js","./pageTree-DtDKozTg.js","./pluginExt-Byb64tQO.js","./CtxMenuButtons-CAiwQkOK.js","./phoneList-BLVdQcXY.js","./phoneList-BpLxxdq6.css","./pen-tool-CV-FKFEZ.js","./pencil-BgF4Kiqp.js","./folder-minus-DUEOcs12.js","./redo-2-DWZTaEz-.js","./file-down-Cjo_T6By.js","./DashboardGridView-RoVFSkNO.css","./SettingsPage-fjxfS_Mt.js","./lock-open-DVWCLSZm.js","./AutomationBuilder-CzBKmOiw.js","./gestures-Bx9M0le5.js","./tanguProbe-BboOas-a.js","./sessionTitle-BtZ1BteL.js","./index-BQrMYjou.js","./create-DZWy4zBR.js","./create-BgE3edmZ.css","./launchpad-BX4jQyF4.js","./launchpad-C9U9hpWJ.css","./pdf.worker.min-CGb3BKV9.js","./zoom-in-C7R8s9x-.js","./minimize-2-Bq4vUin-.js","./InlineFiles-3g2jMUeA.js","./PluginToolCard-BXE5vA1h.js","./PluginToolCard-BmTRr5JT.css","./codeStudioStore-OswE1_s0.js","./chevron-up-C_EDOZzI.js","./pen-line-ho1GgAe2.js","./ViewSelectionBar-C5FDh7fO.js","./GitCloneDialog-DfY0kqhP.js","./GitCloneDialog-DOxZk2K0.css","./i18n.generated-D4-Wu9Wh.js","./i18n-CAf4PT1o.css","./log-out-CdKTS7HC.js","./StudioGuestSurface-360CWUwf.js","./viewportLock-B0l1GU_k.css","./codingNavigation-BrkLENBZ.css","./mobileEntry-6u7TYC4s.css","./main-CForzSFD.js","./main-BlVApHpj.css","./invitePage-BT_rFfab.js"])))=>i.map(i=>d[i]);
2
2
  function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&&!Array.isArray(i)){for(const o in i)if(o!=="default"&&!(o in e)){const s=Object.getOwnPropertyDescriptor(i,o);s&&Object.defineProperty(e,o,s.get?s:{enumerable:!0,get:()=>i[o]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))i(o);new MutationObserver(o=>{for(const s of o)if(s.type==="childList")for(const a of s.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&i(a)}).observe(document,{childList:!0,subtree:!0});function n(o){const s={};return o.integrity&&(s.integrity=o.integrity),o.referrerPolicy&&(s.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?s.credentials="include":o.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function i(o){if(o.ep)return;o.ep=!0;const s=n(o);fetch(o.href,s)}})();const eh="modulepreload",th=function(e,t){return new URL(e,t).href},Ha={},yt=function(t,n,i){let o=Promise.resolve();if(n&&n.length>0){let c=function(d){return Promise.all(d.map(u=>Promise.resolve(u).then(p=>({status:"fulfilled",value:p}),p=>({status:"rejected",reason:p}))))};const a=document.getElementsByTagName("link"),r=document.querySelector("meta[property=csp-nonce]"),l=r?.nonce||r?.getAttribute("nonce");o=c(n.map(d=>{if(d=th(d,i),d in Ha)return;Ha[d]=!0;const u=d.endsWith(".css"),p=u?'[rel="stylesheet"]':"";if(i)for(let m=a.length-1;m>=0;m--){const g=a[m];if(g.href===d&&(!u||g.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${d}"]${p}`))return;const h=document.createElement("link");if(h.rel=u?"stylesheet":eh,u||(h.as="script"),h.crossOrigin="",h.href=d,l&&h.setAttribute("nonce",l),document.head.appendChild(h),u)return new Promise((m,g)=>{h.addEventListener("load",m),h.addEventListener("error",()=>g(new Error(`Unable to preload CSS for ${d}`)))})}))}function s(a){const r=new Event("vite:preloadError",{cancelable:!0});if(r.payload=a,window.dispatchEvent(r),!r.defaultPrevented)throw a}return o.then(a=>{for(const r of a||[])r.status==="rejected"&&s(r.reason);return t().catch(s)})};let ps;function nh(e){ps=e}function $i(e){return ps?`${e}:account:${encodeURIComponent(ps)}`:e}function ih(e,t){try{const n=new URL(e);if(n.protocol!=="https:"&&n.protocol!=="http:")return null;const i=t.split(".")[1];if(!i)return null;const o=i.replace(/-/g,"+").replace(/_/g,"/"),s=Uint8Array.from(atob(o),l=>l.charCodeAt(0)),a=JSON.parse(new TextDecoder().decode(s)),r=a.userId??a.sub;return typeof r!="string"&&typeof r!="number"||!String(r).trim()?null:`${n.origin}${n.pathname.replace(/\/+$/,"")}::${String(r)}`}catch{return null}}const gs="forsion.cloudCacheAccount",oh=e=>!e.includes(":account:")&&(e==="tangu2_named_layouts"||/^tangu2_layout_(?:v[34]|detached_.+)$/.test(e)||/^lcl_sc_(?:layout|named_layouts)_v1(?:_.+)?$/.test(e));function Nl(){try{for(const e of Object.keys(localStorage))e.includes(":account:")||(e==="amadeus_tree_snap"||e==="amadeus.cloudVaultId"||e.startsWith("amadeus_last_page:")||e==="forsion.deskBySession"||e==="forsion_tangu_unread_sessions"||oh(e))&&localStorage.removeItem(e);localStorage.removeItem(gs)}catch{}}function ni(e,t){return ih(e,t)}function Yi(e,t){const n=ni(e,t);nh(n??`anonymous:${Date.now()}:${Math.random().toString(36).slice(2)}`);try{(!n||localStorage.getItem(gs)!==n)&&Nl(),n&&localStorage.setItem(gs,n)}catch{}}const sh=`# Forsion 更新日志
3
3
 
4
- ## 2.13.5 (2026-10-20)
4
+ ## 2.13.6 (2026-10-21)
5
5
 
6
- - **对话可以分支,也能铺成画布**:
6
+ - **Tangu 画布与对话分支**:
7
+ - 对话列顶上可以切到「画布」。每一轮拆成提问卡和回答卡,缺省竖排、可以改横排;长回答在卡里露一段预览,双击卡片在右边开阅读栏,↑↓ 翻这一支的上一轮、下一轮。悬停回答卡下面的 ⊕ 能从那里分出一支接着问,提问卡旁边的 ⊕ 是换个问法再问。卡片和空白处都有右键菜单:分支、复制、顺便问、只看这一支、收起下面的卡(收成「+N」)、给一支改名或归档。生成时画布跟着新回答走,滚开后点箭头就能飞回去。
7
8
  - 回答下面的操作多了「接着问」:从这一条分出一支新对话,分叉之前的内容和原对话一样。分支挂在左栏主线下面,Tangu 也知道这段对话分过几支、各支说到了哪里。分支最后一条回答可以「带回这里」,回到原来那支,并把这条回答作为引用挂到输入框上。
8
9
  - 「顺便问」开在对话右侧,问过的会保存下来;划选文字后的「在侧栏提问」并进了「顺便问」。每条回答下面列出从这里分出去的分支、顺便问和子会话。
9
- - 对话列顶上可以切到「画布」。每一轮拆成提问卡和回答卡,缺省竖排、可以改横排;长回答在卡里露一段预览,双击卡片在右边开阅读栏,↑↓ 翻这一支的上一轮、下一轮。悬停回答卡下面的 ⊕ 能从那里分出一支接着问,提问卡旁边的 ⊕ 是换个问法再问。卡片和空白处都有右键菜单:分支、复制、顺便问、只看这一支、收起下面的卡(收成「+N」)、给一支改名或归档。生成时画布跟着新回答走,滚开后点箭头就能飞回去。
10
10
  - **子会话与任务卡**:Tangu 可以开几个看得见的子会话分头做事(同时最多 4 个),各自做完把结果交回主会话,主会话接着往下做。左栏里子会话挂在主会话下面,行尾标出状态:在跑、等你回复、做完了还没看。开出子会话的那条回答下面有一块列出它们,等你回复的那行可以「去回复」或「让 Tangu 回答」。回答以问句收尾时,这段对话标成「等你」。任务卡上多了「开个子会话」。
11
11
  - **Muse 私聊和收件箱分工**:Muse 要你回话或拍板的事、它记下的待办、后台要你批准的操作,都发在和它的私聊里;做好的成品照旧进收件箱。Tangu 图标上的角标是有新消息或在等你的私聊个数,有人在等你时换成醒目的颜色;私聊变成「等你」时弹系统通知。「设置 → 通知」里来信的发送方式改成「日报:每天一封 / 不发」。
12
12
  - **对话里的卡片能自己算**:房贷计算器、AA 分账、单位换算、单词闪卡、分步指引这类回答,卡片里改数字当场出结果,不用再问一次模型;卡片里可以放大号数字和表格,追问时会带上你在卡里改过的值。对话里的网页卡片统一叫 Intelligent UI。手机上暂时还是原来的卡片。
@@ -17,13 +17,15 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
17
17
  - 发出的消息从输入框升起;系统开着「减弱动态效果」时只淡入。
18
18
  - 改图不用重新拖图:这一轮没带图时,改图会用上一条消息里的图,也能接着改刚生成的那张。拖进聊天的图片会进图片附件(本机会话里照旧同时给出文件路径)。带图的对话里改图和生图更省额度。
19
19
  - 支持 DeepSeek V4.1 Flash、Gemini 4 和 StepFun 的思考档位。模型不支持所选的那一档时,自动换到相近的一档(先往低,没有再往高),实际用的那一档显示在「思考档位」旁边。
20
- - **蓬洲云**:
21
- - Ribbon 上新增「蓬洲云」Space,打开先是用量概览。左栏按智库同步、Amadeus Cloud、应用文件、导出和回收站列出你存在云端的东西,可以下载、改名、移动、移到回收站、看历史版本和恢复(同步库只看和下载);同步库里的文件能看到是哪台设备写的。
22
- - 「我的云盘」:上传文件和整个文件夹、新建文件夹,也能从访达直接拖进来;单个文件最大 50 MB,算在应用文件的 10 GB 里。上传和下载在后台排队,切到别的 Space 也不停,右下角的浮动卡里能看进度、暂停、取消和重试;Ribbon 上的图标挂着进度环,还有文件在传时退出会先问一次。
23
- - 「同步」页:智库、Agents 与记忆、插件数据三项同步的开关、状态和在同步的设备都在这一页。登录并走完引导后会弹出「把这台电脑同步到蓬洲云」,三项缺省勾上,点「开始同步」就开;已经登录的用户升级后也会看到一次。
24
- - 另一台电脑登录、云端已经有一份智库而这台有不一样的文件时,先不开智库同步,在「同步」页选「合并两边」「用云端那份」(这台不一样的文件先挪进旁边的备份文件夹,不删)或「这台先不同步智库」。额度不够时小文件先传,放不下的留在本机,只提醒一次。
20
+ - Tangu 工作区里的离线设备默认收进「离线设备 N」,点击可展开;设备重新上线后自动回到列表,正在查看的远端设备保持可见。
21
+ - **蓬洲云与我的云盘**:
22
+ - Ribbon 上新增「蓬洲云」Space,随包更新 Forsion Extend 0.9.2。「我的云盘」作为统一入口,按来源分文件夹:我上传的、Amadeus 各库、智库同步、Agents、我的资料、各应用、插件数据和导出。同步库、Agents 和资料只看和下载,普通应用文件按来源权限管理,插件数据查看摘要;同步文件还能看到是哪台设备写的。
23
+ - 在「我上传的」里上传文件或整个文件夹、新建文件夹,也能从访达直接拖入;支持下载、改名、移动、移到回收站、查看与恢复历史版本。单个文件最大 50 MB。上传和下载在后台排队,切到别的 Space 也不停,右下角浮动卡里能看进度、暂停、取消和重试;Ribbon 图标挂进度环,还有文件在传时退出会先问一次。导出文件可以下载、改名和删除。
24
+ - 统一用量按账号权益显示上限,现存文件与回收站计入,历史版本单列,当前不计入统一额度。云端升级后启用统一计量与通知:先提醒,确认后的宽限期至少 30 天,是否限制新增写入以账户提示为准。云端尚未升级时仍能访问已有文件,用量未知不会显示成零;额度不足也不再误报为单个文件过大。
25
+ - 「同步」页集中放智库、Agents 与记忆、插件数据的开关、设备和状态,并显示上次同步、失败、冲突副本和待上传情况。登录并走完引导后会弹出「把这台电脑同步到蓬洲云」,三项缺省勾上,点「开始同步」就开;已经登录的用户升级后也会看到一次。
26
+ - 另一台电脑登录、云端已经有一份智库而这台有不同文件时,先不开智库同步,在「同步」页选「合并两边」「用云端那份」(不同的本地文件先挪进旁边的备份文件夹,不删)或「这台先不同步智库」。同步受额度限制时,小文件可以先传,放不下的文件留在本机,不会删除。
25
27
  - **使用指南**:新增「使用指南」Space,是 Forsion 的说明书:按等级逐章解锁,任务就是平时的操作,做过的直接算数;每章导语下面有一张示意图,标出要找的地方在哪儿。「带我去」切到对应的地方,在真界面上圈出要点的那一处,你自己点,做完圈会挪到下一步。右栏的「问 Tangu」就是 Tangu 的对话,本章内容挂在输入框上方当引用。每升一级,收件箱来一封「接下来试试这几件事」。
26
- - **「我」**:Agents 名册顶上多了一行「我」,点开是所有 Agent 共用的、关于你的资料,分协作说明、画像、记忆三栏。协作说明里上面是你写给所有 Agent 的要求,下面是你和 Agent 们的共识;每一份都可以直接改,有修改记录,可以撤销。对话里协作说明的更新卡可以「查看说明」或「修改」直接跳过来,Agent 详情的「协作」页底下也有链接指过来。开着「Agents 与记忆」同步时,这份资料在你的几台电脑之间同步,两台都改过会先逐行合并;Agent 自己排的日程也一起同步,到点的自动任务只在排它的那台电脑上跑。
28
+ - **「我」**:Agents 名册顶上多了一行「我」,点开是所有 Agent 共用的、关于你的资料,分协作说明、画像、记忆三栏。协作说明里上面是你写给所有 Agent 的要求,下面是你和 Agent 们的共识;每一份都可以直接改,有修改记录,可以撤销。对话里协作说明的更新卡可以「查看说明」或「修改」直接跳过来,Agent 详情的「协作」页底下也有链接指过来。打开「Agents 与记忆」总开关后,human 资料文件夹在你的几台电脑之间同步,两台都改过会先逐行合并;Agent 自己排的日程也一起同步,到点的自动任务只在排它的那台电脑上跑。
27
29
  - **主页**:
28
30
  - 新的主题背景:星轨、日行、素笺、字阵,扶桑环也回来了。星轨和日行会缓缓地动,可以在壁纸面板或「设置 → 外观 → 主页壁纸动效」里关掉;「字阵」是满屏淡字,打字时从光标处漾开一圈,点空白处、发送消息时也会漾开。
29
31
  - 输入框下面换成近况卡片(桌面):缺省 4 张,右键可以选 1–6 张,日历卡显示下一条日程、收件箱卡显示未读数;问候和日期合成一行。
@@ -37,9 +39,10 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
37
39
  - Agent Desk 和 Mini 卡片的顶栏换成悬浮胶囊:右侧 Agent Desk 展开后,顶上是两颗胶囊,左边是条目名,可以切换条目;右边是视图按钮、「⋯」和清空 / 收起;内容从胶囊下面滚过。Mini 卡片的顶栏和手机上一样:左边是 Space 和标题下拉(切换会话或笔记),右边是新建、在主面板显示和关闭。
38
40
  - **右栏跟着主视图走**:主区前台换成哪种视图,右栏就换成和它配套的那一组:对话配详情、文件和大纲,笔记配对话、大纲、反链和关系图,PDF、图片、白板这类配对话,日历配待办。同一种视图换个文件不动右栏;你自己放进右栏的和 Space 固定的不会被关掉,你关掉的重启后也不会补回来。
39
41
  - **日历与待办**:
42
+ - 新增独立的待办 Space,与 Calendar 右栏共用同一套待办视图。日历与待办由核心插件 \`@forsion/calendar\` 提供,随包安装并检查更新;原 Calendar Space 与自定义布局保留。默认日历使用 \`human/CALENDAR.db\`,可随个人资料同步。
40
43
  - 日历换了布局:左栏是小月历和日历列表(点颜色方块就能显示或隐藏那个日历),右栏是待办;事件是浅色块加左边一条色线,过去的变淡。以前从没改过布局的日历 Space 会换成新布局,改过的保持原样。
41
44
  - 单击空白格,直接在格子里写标题,就建好一小时的日程;按住拖出时长,全天行横拖建跨几天的事件。拖动事件按 15 分钟对齐,⌥ 拖是复制;改期和删除可以 ⌘Z 撤销。快捷键:C 新建、T 回到今天、D / W / 3 / M 切视图。
42
- - 点开事件在旁边弹出编辑卡。待办的快速添加挪到顶部,认得「明天下午3点」「下周一」这类说法;待办可以直接拖进时间格。
45
+ - 点开事件在旁边弹出编辑卡。待办的快速添加挪到顶部,输入一行、回车就能连续添加,日期可选;认得「明天下午3点」「下周一」这类说法,没有清单时可以直接创建。完成待办后可撤销,移动端有轻触反馈;待办也能直接拖进时间格。列表、工具栏和日历显示菜单采用紧凑布局。
43
46
  - 事件有了右键菜单(也可以按 Shift+F10,或点编辑卡上的「事件操作」):复制、剪切、克隆(⌘D)、粘贴、删除、复制摘要,可以撤销和重做最近 20 步。克隆笔记型的事件会连笔记正文一起复制。选中的事件拖上下边缘就能改开始和结束时间。
44
47
  - 手机上点事件从底部弹出抽屉,看详情、精确改时间、删除都在这里;以前点短事件的边缘会被当成拖动、什么都打不开,现在不会了。选中之后才出现拖动把手,拖的时候实时显示起止时间。
45
48
  - 待办视图单独开成标签时是宽版:顶上可以按「今天 / 计划 / 全部」和清单筛选;新建时可以选落到哪个清单,按 N 新建;把待办拖到「明天」这类分组上就改了日期(可以撤销);↑ / ↓ 换行,空格勾选。在日历右栏和 Mini 卡片里是紧凑版。
@@ -49,8 +52,8 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
49
52
  - **笔记**:
50
53
  - @ 提及面板加了分类:全部、Agent、日期、笔记,按 ← / → 切换。
51
54
  - 页面里的 forsion:// 链接直接在应用里打开(编辑区里要按住 ⌘ / Ctrl 再点)。
52
- - 打字或删字时,折叠块的箭头不再抽动,下面的内容也不再上下跳。
53
- - 挪动笔记或文件夹时接着打字,打的字不再落进原文件夹里的冲突副本,原位置也不会再冒出一篇旧笔记。
55
+ - 打字或删字时,折叠块的箭头不再抽动,下面的内容也不再上下跳;修复折叠块内连续回车后的编辑行为。
56
+ - 挪动笔记或文件夹时接着打字,保住交接期间的最后输入;文字不再落进原文件夹里的冲突副本,原位置也不会再冒出一篇旧笔记。
54
57
  - Cloud 侧的同步库分区头标出是哪几台设备在同步它(这台写「本机」),同步库分区排在「Cloud工作区」前面;根文件夹右键可以设为同步库分区,旧版留下的分区也能取消。
55
58
  - **设置**:
56
59
  - 「设置 → 模型」重新整理成三块。「默认模型」按对话、图像、语音、翻译分组,每一项标出来源,可以一键恢复跟随;朗读、语音通话、语音输入的模型也挪到这里。「模型库」按六类列出全部模型,云端模型也能在本机隐藏。「提供方」里每个模型可以单独标类型和「纯文本」,也可以手填模型名。
@@ -63,6 +66,7 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
63
66
  - 商店里的插件页分成内容介绍、评论、版本三栏,可以评论和回复,作者在收件箱里收到;安装前先核对 Forsion 版本和平台。在对话里可以让 Tangu 搜商店,结果显示成插件卡片,点一下就装。
64
67
  - 插件投稿页加了详细描述、标签、Forsion 版本要求和支持的平台;插件名字可以和别的插件重复。
65
68
  - 插件详情页列出它申请的能力(比如「读写你的多维表、读写笔记里的 @ 任务、读取前台窗口」);「设置 → Hooks」里插件带来的 hook 标「来自插件 · 只观察」。
69
+ - 支持迁移的插件使用稳定的英文 ID 数据文件夹,保留原目录与迁移记录,避免改显示名称后找不到已有数据;自定义目录保持原样。
66
70
  - **从系统打开文件**:PDF 和 Markdown 可以用 Forsion 打开(Finder 里的「打开方式」、拖到程序坞图标,或在 Windows 上双击)。笔记库外的文件开在临时标签页里预览,Markdown 可以直接编辑、自动存回原文件,不会被导入笔记库;笔记库里的文件照常在笔记里打开。
67
71
  - **Chrome 扩展换成 Forsion Clip**:
68
72
  - 原来的 Tangu for Chrome 并进了网页剪藏扩展 Forsion Clip,装一个就够:既能把网页剪藏进智库,Tangu 也照旧能在你正在用的 Chrome 里、在自己的「Tangu」标签组后台操作。扩展 ID 和文件夹都没变,更新后在 Chrome 的扩展页点一下「重新加载」(或重启 Chrome)即可,之前配好的连接会保留。
@@ -73,6 +77,7 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
73
77
  - **更新**:
74
78
  - 发现新版本时弹出两栏的「更新内容」:左边是版本列表(历史版本也能点开看),右边是官网更新动态里那一版的文章和实录;官网连不上时显示更新日志。「设置 → 关于」里可以随时打开。应用开着时每 6 小时、以及电脑从睡眠中唤醒后也会检查新版本。
75
79
  - 有没有新版本以官网下载页为准,官网还没上的版本不再提前提示。安装包在中国大陆默认从官网下,其他地区从 GitHub 下,一边下不动会自动换另一边;下载中也可以手动换,「设置 → 关于 → 下载来源」可以固定成官网或 GitHub。macOS 上「下载安装包」直接在浏览器里下载这一版的 .dmg,不用再去 Releases 页找。
80
+ - 桌面与引擎独立编号:本版桌面为 2.13.6,内置引擎为 2.13.7。热更新按真实桌面版本检查兼容性。
76
81
  - **Android**:
77
82
  - 停在 Tangu 时退出、下次启动,不再丢掉开着的标签;「启动时进入」设成别的 Space 时,不再带着上一个 Space 的标签和面板。
78
83
  - 平板和手机横屏时,Space 换到左侧一条通高的竖条:主页排第一,放不下时置顶的优先、最后一格是「全部」,头像在底部;竖屏照旧用底部 Dock。标题胶囊挪进主区,平板上主页那一列居中。白板铺满整屏高,菜单和工具栏挪进胶囊那一排;用手指时平移提示换成「双指拖动或捏合」。
@@ -84,16 +89,18 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
84
89
  - **Windows**:
85
90
  - 快速拖动 Mini 卡片的边角调大小时,不再出现完全没变化的情况。
86
91
  - Mini 卡片贴边折叠和展开有了动画;换主题后不再露出方角;贴在两块屏幕相接的那条边上时,折叠后不再跑到另一块屏幕上。
87
- - 笔记路径统一了写法,同一篇笔记不再被当成两篇:标签跟随、未保存的草稿、置顶和日历设置都能对上,老版本留下的记录会自动转过来。
88
- - 审批:「询问」档下只有 cmd 的 \`dir\` / \`type\` 这类只读写法免审批,其余命令一律要批(\`git status\` 也要批);Muse 读自己的日志和资料改用不需要审批的读文件工具,不再排一串审批卡。
92
+ - 笔记路径统一了写法,同一路径不同大小写会复用标签,不再被当成两篇:标签跟随、未保存的草稿、置顶和日历设置都能对上,老版本留下的记录会自动转过来。
93
+ - 审批:「询问」档下,受限的 cmd 只读目录查询和文本搜索可以组合执行而不反复审批;写操作、凭证读取和其他程序仍需审批(\`git status\` 也要批)。Muse 读自己的日志和资料改用不需要审批的读文件工具,不再排一串审批卡。
94
+ - 窗口按钮和标签栏的点击区域不再重叠;安装与卸载保留其他程序的文件关联。
89
95
  - **网页版**(网页版更新后生效):
90
96
  - 在手机和平板的浏览器里打开时,布局和交互跟 Android 一致:竖屏用底部 Dock,平板横屏用左侧竖条;iPad 横着打开或刷新也是这套布局,不再变成桌面版。
91
97
  - 接上了 Forsion 账号页、商店(会员、积分、物品和插件投稿)、公告和蓬洲云,蓬洲云里可以浏览、上传和下载文件。
92
- - **插件**(面向作者):插件开发技能 forsion-plugin 更新到 1.59.0。
98
+ - **插件**(面向作者):插件开发技能 forsion-plugin 更新到 1.60.1。
93
99
  - 视图与界面:插件视图可以用 \`view.close()\` 从自己的内容里关掉自己(桌面浮窗和网页浮层同一个接口);\`ctx.ui.mountSettingsPage\` / \`mountSettingsItem\` 按数据画出和宿主一样的设置页,手机上按控件自动排版;\`ctx.ui.setViewModes\` 在插件视图顶行放看法切换;\`ctx.registerToolResultRenderer\` 给自己引擎半身的工具挂原生结果卡片,可以在对话和 Agent Desk 之间挪;\`ctx.ui.contextMenu\` 加了 \`opts.keepOpen\` 和句柄 \`update(items)\`,勾选清单可以连勾,菜单限高可滚、最多 200 项;另有 \`ctx.ui.mountModelPicker\` 和按次指定模型;设置项写 \`secret: true\` 显示成密码框(只遮挡、不加密)。
94
- - 布局与 Ribbon:\`registerView\` 写 \`rightCompanions\`,声明这个视图到前台时右栏要的那一组;\`ctx.app.setSpaceDot\` / \`setSpaceProgress\` 在 Ribbon 上给自己的 Space 挂红点或进度环;\`ctx.spaces.mountIcon\` 跟着 Space 走,同一个 id 重新注册换了图标会原地重画;\`ctx.closeView(id, { collapse: true })\` 收起整侧;\`ctx.app.queuePopup\` 让自己弹出的弹窗排进宿主的队列;Space 配方 \`layout.main\` 的一项可以写 \`"mainPage": true\`,作为进 Space 时的默认主页。
100
+ - 布局与 Ribbon:\`registerView\` 写 \`rightCompanions\`,声明这个视图到前台时右栏要的那一组;\`mainCompanions\` 与 \`setCompanionsVisible\` 支持主区伴随视图;\`ctx.app.setSpaceDot\` / \`setSpaceProgress\` 在 Ribbon 上给自己的 Space 挂红点或进度环;\`ctx.spaces.mountIcon\` 跟着 Space 走,同一个 id 重新注册换了图标会原地重画;\`ctx.closeView(id, { collapse: true })\` 收起整侧;\`ctx.app.queuePopup\` 让自己弹出的弹窗排进宿主的队列;Space 配方 \`layout.main\` 的一项可以写 \`"mainPage": true\`,作为进 Space 时的默认主页。
95
101
  - 数据与事件:\`ctx.databases\` / \`ctx.noteTasks\` 读写多维表和笔记里的 @ 任务;\`ctx.calendar\` 的 \`calendar\` 档(叠加日历源、日历设置、.ics 管理)、\`ctx.ui.mountRecord\`、\`openNote\` 跳到标题、通知带操作按钮;\`ctx.app.onVaultEvent\` 收到库里的新建、删除、改名和外部修改;命令回执可以带 \`result\` 交给模型;manifest 写 \`"syncData": true\`,插件数据跟着账号在桌面和手机之间同步;另有 \`ctx.spaces\`、\`ctx.tangu.mountComposer\`、\`ctx.app.openSpace\` / \`openLink\` / \`watchAccountName\`、\`ctx.wallpaper.bing\`、\`ctx.achievements\`。
96
102
  - 引擎插件:manifest 可以声明随包的 stdio MCP(\`mcpServers\`)和只观察、不拦截的 \`hooks\`,随插件启停;工具上下文公开 \`presentDesk\` / \`runId\`;插件详情页会列出 manifest 声明的能力。
103
+ - 工作目录与个人日历:新插件 ID 使用稳定的英文标识;按业务 schema 接入 \`workFolder\` / \`migrateWorkFolder\` 的一次性迁移,保留原数据和每库记录。具备 \`databases\` 与 \`calendar\` 两项能力的本机插件可通过宿主提供的 \`human://CALENDAR.db\` 引用访问个人日历;不要把它当作文件路径。
97
104
  - **修复**:
98
105
  - DeepSeek V4.1 Flash 发图时看不到图(之前图会先被转成文字描述)。
99
106
  - 长对话和长笔记里点目录或搜索结果,跳转后被拉回底部或落点偏开。
@@ -104,7 +111,7 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
104
111
  - 日历开在标签里时,切到别的标签再切回来,周视图会跳到 8 月、月视图跳到别的月份。
105
112
  - 英文界面下,日历的事件卡和新建卡上日期显示成「7月8日」「全天」。
106
113
  - 英文对话有时被自动起成中文标题、写成中文摘要。
107
- - 笔记里在折叠块正文的行首按 ← 或退格,正文会被拆到折叠块外面,收起时只藏得住前面几段。
114
+ - 笔记里在折叠块正文的行首按 ←、退格或连续按两次回车后,正文不再被拆到折叠块外面,收起时能藏住完整内容。
108
115
 
109
116
  ## 2.13.4 (2026-10-14)
110
117
 
@@ -1591,12 +1598,12 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
1591
1598
 
1592
1599
  <!-- English edition of CHANGELOG.md: same "## <version> (<date>)" headings, one bullet per Chinese bullet. Add both when releasing. -->
1593
1600
 
1594
- ## 2.13.5 (2026-10-20)
1601
+ ## 2.13.6 (2026-10-21)
1595
1602
 
1596
- - **Branch a chat, or lay it out as a canvas**:
1603
+ - **Tangu canvas and chat branches**:
1604
+ - Switch to Canvas at the top of the chat column. Each turn becomes a question card and an answer card, stacked vertically by default or laid out side by side. Long answers show a preview on the card: double-click a card to open a reading pane on the right, and use ↑ ↓ to move to the previous or next turn of that branch. Hover the ⊕ under an answer to branch off from there and keep asking, or the ⊕ beside a question to ask it another way. Cards and empty space have right-click menus: branch, copy, By the way, show only this branch, collapse the cards below (they fold into "+N"), and rename or archive a branch. The canvas follows a new answer while it's written, and if you scroll away, an arrow takes you back.
1597
1605
  - Answers have a new Continue from here action that starts a branch from that message; everything before the fork stays the same as in the original chat. Branches sit under the main thread in the left panel, and Tangu knows how many branches the chat has and where each one got to. From the last answer in a branch, Bring back returns you to the original thread with that answer attached to the input as a quote.
1598
1606
  - By the way opens on the right of the chat and keeps what you asked there; Ask in sidebar on selected text is now part of By the way. Under each answer you see the branches, side questions and child sessions that started from it.
1599
- - Switch to Canvas at the top of the chat column. Each turn becomes a question card and an answer card, stacked vertically by default or laid out side by side. Long answers show a preview on the card: double-click a card to open a reading pane on the right, and use ↑ ↓ to move to the previous or next turn of that branch. Hover the ⊕ under an answer to branch off from there and keep asking, or the ⊕ beside a question to ask it another way. Cards and empty space have right-click menus: branch, copy, By the way, show only this branch, collapse the cards below (they fold into "+N"), and rename or archive a branch. The canvas follows a new answer while it's written, and if you scroll away, an arrow takes you back.
1600
1607
  - **Child sessions and task cards**: Tangu can open several visible child sessions to split up the work (up to 4 at a time). Each one hands its result back to the main chat when it's done, and the main chat carries on. In the left panel, child sessions sit under their parent with a status at the end of the row: running, waiting for you, or done but not yet viewed. The answer that started them lists them underneath, and a row that's waiting for you offers Reply or Let Tangu answer. When an answer ends with a question, the chat is marked as waiting for you. Task cards have a new Start child session action.
1601
1608
  - **Muse's chat and the inbox each have a job**: anything Muse needs you to answer or decide, the to-dos it notes down and background actions that need your approval all come to your chat with Muse; finished work still goes to the inbox. The badge on the Tangu icon counts chats with new messages or waiting for you, and turns a stronger color when one is waiting. A chat that starts waiting for you also sends a system notification. In Settings → Notifications, letters now come as a Daily digest: one a day, or none.
1602
1609
  - **Cards in chat do their own math**: for answers such as a mortgage calculator, splitting a bill, unit conversion, vocabulary flashcards or step-by-step guides, change a number in the card and the result updates on the spot, without asking the model again. Cards can show large figures and tables, and a follow-up question carries the values you changed in the card. Web cards in chat are now called Intelligent UI everywhere. Phones still show the previous cards for now.
@@ -1607,13 +1614,15 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
1607
1614
  - Sent messages rise out of the input box; with Reduce motion turned on in your system, they just fade in.
1608
1615
  - No need to drag an image in again to edit it: when this turn has no image, image editing uses the one from the previous message, and it can keep working on the image it just generated. Images dragged into a chat become image attachments (local chats still get the file path too). Editing and generating images in chats that already contain images uses less quota.
1609
1616
  - Thinking levels now work with DeepSeek V4.1 Flash, Gemini 4 and StepFun. When a model doesn't support the level you picked, it uses the nearest one (lower first, then higher), and the level actually used is shown next to Thinking effort.
1610
- - **Penzor Cloud**:
1611
- - A new Penzor Cloud Space on the Ribbon opens on a usage overview. The left panel lists what you keep in the cloud under Vault sync, Amadeus Cloud, App files, Exports and Trash. You can download, rename, move, move to trash, browse earlier versions and restore (synced vaults are view and download only), and synced files show which device wrote them.
1612
- - My drive: upload files and whole folders, create folders, or drag files straight in from Finder. Files can be up to 50 MB each and count toward the 10 GB for app files. Uploads and downloads queue in the background and keep going when you switch Spaces; a floating card at the bottom right shows progress and lets you pause, cancel and retry. The Ribbon icon shows a progress ring, and quitting while something is still transferring asks first.
1613
- - The Sync page gathers the switches, status and syncing devices for your notes vault, Agents & memory and plugin data. Once you sign in and finish onboarding, a "Sync this computer to Penzor Cloud" card appears with all three checked; click Start syncing to turn them on. If you're already signed in, you'll see the card once after updating.
1614
- - When you sign in on another computer and the cloud already has a vault with files that differ from this one, vault sync waits for you on the Sync page: Merge both, Use the cloud copy (this computer's differing files move to a backup folder next to the vault first, nothing is deleted), or Don't sync notes on this computer yet. If you run out of space, smaller files go first, files that don't fit stay on this computer, and you're told once.
1617
+ - Offline devices in the Tangu workspace collapse into an Offline devices group with a count. Expand it to view them; devices return to the list when they reconnect. The remote device you are viewing stays visible.
1618
+ - **Penzor Cloud and My drive**:
1619
+ - A new Penzor Cloud Space appears on the Ribbon, with Forsion Extend 0.9.2 included. My drive is the single entry point, grouped by source: My uploads, Amadeus vaults, vault sync, Agents, My profile, apps, plugin data and exports. Synced vaults, Agents and profile files can be viewed and downloaded but are read-only here. Ordinary app files can be managed according to their source permissions, and plugin data is shown as a summary. Synced files also show which device wrote them.
1620
+ - In My uploads, upload files or whole folders, create folders, or drag files in from Finder. Download, rename, move, move to trash, and view or restore previous versions. Each file can be up to 50 MB. Uploads and downloads queue in the background even when you switch Spaces; a floating card at the bottom right shows progress, pause, cancel and retry. The Ribbon icon has a progress ring, and quitting with transfers running asks first. Exports can be downloaded, renamed and deleted.
1621
+ - Unified usage shows the limit for your account's entitlements, counts current files and trash, and lists history separately without counting it toward the unified quota for now. Unified accounting and notices become available after the cloud service update: a notice comes first, followed by at least 30 days of grace after acknowledgment. Your account notice states whether new writes are restricted. Existing files remain accessible before the server update, and unknown usage is never shown as zero. Storage quota errors no longer appear as a single-file size limit.
1622
+ - Sync puts the switches, devices and status for vaults, Agents & memory and plugin data on one page, including the last run, failures, conflict copies and pending uploads. After sign-in and onboarding, Sync this computer to Penzor Cloud offers all three switches selected by default; click Start syncing to enable them. Existing signed-in users see it once after upgrading too.
1623
+ - If another computer signs in with files that differ from an existing cloud vault, vault sync waits for you to choose Merge both, Use the cloud copy (different local files are moved to a nearby backup folder, not deleted), or Don't sync vaults on this computer yet. When a quota limit prevents syncing, smaller files can go first; files that do not fit stay on this computer and are not deleted.
1615
1624
  - **Guide**: a new Guide Space is Forsion's manual. Chapters unlock level by level, the tasks are things you do anyway, and whatever you've done already counts. Each chapter has a diagram under its intro that shows where to look. Take me there switches to the right place and rings the spot to click on the actual screen; you click it yourself, and the ring moves on to the next step. Ask Tangu in the right panel is Tangu's own chat, with the current chapter attached above the input as a quote. Each new level brings an inbox letter with things to try next.
1616
- - **Me**: the Agents list has a new Me row at the top. It opens the profile all your agents share about you, in three sections: Collaboration, Portrait and Memory. Collaboration shows what you ask of every agent on top and what you and your agents have agreed on below. You can edit each one directly, with a change history and undo. Collaboration update cards in a chat take you there with View handbook or Revise, and an agent's Collaboration tab links to it as well. With Agents & memory sync on, this profile syncs across your computers, and if two computers change it, the edits are merged line by line first. Schedules your agents set up sync too, and each automatic task still runs only on the computer that scheduled it.
1625
+ - **Me**: the Agents list has a new Me row at the top. It opens the profile all your agents share about you, in three sections: Collaboration, Portrait and Memory. Collaboration shows what you ask of every agent on top and what you and your agents have agreed on below. You can edit each one directly, with a change history and undo. Collaboration update cards in a chat take you there with View handbook or Revise, and an agent's Collaboration tab links to it as well. With the Agents & memory master switch on, the human profile folder syncs across your computers, and if two computers change it, the edits are merged line by line first. Schedules your agents set up sync too, and each automatic task still runs only on the computer that scheduled it.
1617
1626
  - **Home**:
1618
1627
  - New theme backgrounds: Orbit, Sun path, Paper and Glyphs, and Forsion rings is back. Orbit and Sun path drift slowly; turn the motion off in the wallpaper panel or in Settings → Appearance → Home wallpaper motion. Glyphs fills the screen with faint characters that ripple out from the cursor as you type, and also when you click an empty spot or send a message.
1619
1628
  - Recent-activity cards now sit below the input box (desktop): 4 by default, 1 to 6 from the right-click menu. The calendar card shows your next event and the inbox card your unread count, and the greeting and date share one line.
@@ -1626,10 +1635,11 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
1626
1635
  - One switcher for view modes: Chat / Canvas, Note / Canvas, the calendar's Day / Week / 3 days / Month and similar switches all sit at the far left of the view's top row. ⌥⌘V (Ctrl+Alt+V on Windows) moves to the next mode, and "View mode" is searchable in the command palette. In a narrow view only the icons remain, and narrower still it turns into a dropdown. Code Studio, workspace files and the file preview window use it too.
1627
1636
  - The Agent Desk and Mini cards have floating capsules instead of top bars. With the Agent Desk on the right expanded, two capsules sit on top: the item name on the left, which also switches items, and the view buttons, "⋯" and Clear / Collapse on the right; content scrolls underneath. A Mini card's top bar now matches the phone: the Space and a title dropdown (to switch chats or notes) on the left, New, Show in main window and Close on the right.
1628
1637
  - **The right panel follows the main view**: whichever kind of view is in front in the main area, the right panel switches to the set that goes with it: details, files and outline for a chat; chat, outline, backlinks and graph for a note; chat for PDFs, images, whiteboards and the like; to-dos for the calendar. Opening another file of the same kind leaves the right panel alone. Views you put in the right panel yourself and ones the Space pins are never closed, and ones you close don't come back after a restart.
1629
- - **Calendar and to-dos**:
1638
+ - **Calendar and tasks**:
1639
+ - A dedicated Tasks Space shares its task view with Calendar’s right panel. The core plugin \`@forsion/calendar\` provides both, is installed with the app and checks for updates. The existing Calendar Space and customized layouts stay in place. The default calendar uses \`human/CALENDAR.db\` and can sync with your profile.
1630
1640
  - The calendar has a new layout: a mini month and your list of calendars on the left (click a color square to show or hide that calendar), to-dos on the right. Events are light blocks with a colored line on the left, and past ones fade. Calendar Spaces whose layout you never changed switch to the new one; customized layouts stay as they are.
1631
1641
  - Click an empty slot and type a title right there to create a one-hour event; press and drag to set its length, or drag across the all-day row for an event spanning several days. Dragged events snap to 15 minutes, ⌥-drag makes a copy, and moving or deleting an event can be undone with ⌘Z. Shortcuts: C for new, T for today, D / W / 3 / M to switch views.
1632
- - Clicking an event opens an edit card beside it. Quick add for to-dos moved to the top and understands phrases like "tomorrow 3pm" or "next Monday", and you can drag a to-do straight into the time grid.
1642
+ - Clicking an event opens an edit card beside it. Quick add for tasks moved to the top: type a line and press Enter to keep adding, with an optional date. It understands phrases like "tomorrow 3pm" or "next Monday", and you can create the first list directly. Completing a task offers undo and native mobile touch feedback; tasks can also be dragged into the time grid. Lists, toolbars and calendar display settings use a compact layout.
1633
1643
  - Events have a right-click menu (or press Shift+F10, or use Event actions on the edit card): copy, cut, clone (⌘D), paste, delete and copy summary, with undo and redo for the last 20 steps. Cloning an event that is a note copies the note's text too. Drag the top or bottom edge of a selected event to change its start or end time.
1634
1644
  - On phones, tapping an event opens a drawer at the bottom with its details, precise time editing and delete. Tapping near the edge of a short event used to count as a drag and open nothing; it opens the drawer now. Drag handles appear only once an event is selected, and the start and end times update live while you drag.
1635
1645
  - Opened as its own tab, the to-do view is the full version: filter by Today / Scheduled / All and by list at the top, choose which list a new to-do goes into and press N to add one, drag a to-do onto a group such as Tomorrow to change its date (undoable), move with ↑ / ↓ and check it off with Space. In the calendar's right panel and in Mini cards it's the compact version.
@@ -1639,8 +1649,8 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
1639
1649
  - **Notes**:
1640
1650
  - The @ mention panel has categories: All, Agents, Dates and Notes; switch with ← / →.
1641
1651
  - forsion:// links in a page open inside the app (in the editor, hold ⌘ / Ctrl while you click).
1642
- - Typing or deleting no longer makes fold arrows twitch or the content below jump.
1643
- - If you keep typing while a note or folder is being moved, your text no longer lands in a conflict copy in the old folder, and an old copy of the note no longer reappears where it used to be.
1652
+ - Typing or deleting no longer makes fold arrows twitch or the content below jump. Editing after consecutive Enter presses inside a folded block is also fixed.
1653
+ - If you keep typing while a note or folder is being moved, the last input during the handoff is preserved. Your text no longer lands in a conflict copy in the old folder, and an old copy of the note no longer reappears where it used to be.
1644
1654
  - On the Cloud side, synced vault sections show which devices sync them ("This device" for this one) and come before the Cloud vault section. Right-click a top-level folder to show it as a synced vault, or remove a section left behind by older versions.
1645
1655
  - **Settings**:
1646
1656
  - Settings → Models is reorganized into three parts. Default models are grouped into chat, image, voice and translation, each showing where its value comes from, with one click to go back to following it; read-aloud, voice call and voice input models moved here too. Model library lists every model in six types, and cloud models can be hidden on this computer. Under Providers, you can set each model's type and Text only flag, or type in a model name.
@@ -1653,6 +1663,7 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
1653
1663
  - A plugin's page in the Store has Overview, Comments and Versions. You can comment and reply, and authors get comments in their inbox. Forsion version and platform are checked before installing. In a chat, you can ask Tangu to search the Store; results come as plugin cards that install with one click.
1654
1664
  - The Submissions page adds a detailed description, tags, Forsion requirements and supported platforms, and plugin names may repeat.
1655
1665
  - A plugin's details page lists the capabilities it asks for (such as "read and write your databases, read and write @ tasks in notes, read the foreground window"). In Settings → Hooks, hooks that come with a plugin are marked "From plugin · observe only".
1666
+ - Migration-aware plugins use stable English ID data folders while retaining the original folders and migration records, so changing a display name does not hide existing data. Custom folders stay as they are.
1656
1667
  - **Open files from your system**: PDF and Markdown files can be opened with Forsion (Open With in Finder, dropping onto the Dock icon, or double-clicking on Windows). Files outside your notes vault open in a temporary tab for preview; Markdown can be edited there and is saved back to the original file without being imported into the vault. Files inside the vault open as notes as usual.
1657
1668
  - **The Chrome extension is now Forsion Clip**:
1658
1669
  - Tangu for Chrome has been merged into the Forsion Clip web clipper, so one extension does both: clip pages into your vault, and let Tangu keep working in the Chrome you use, in its own "Tangu" tab group in the background. The extension ID and folder are unchanged: after updating, click Reload on Chrome's extensions page (or restart Chrome) and your existing pairing is kept.
@@ -1663,6 +1674,7 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
1663
1674
  - **Updates**:
1664
1675
  - When a new version is available, a two-column What's new window opens: versions on the left (earlier versions included) and that version's post from the website's release notes on the right. If the website can't be reached, the changelog is shown instead. Open it anytime from Settings → About. While the app is open, Forsion also checks for updates every 6 hours and after the computer wakes from sleep.
1665
1676
  - A new version is offered only once it is on the website's download page. In mainland China the installer downloads from the website by default, elsewhere from GitHub, and it switches to the other one if a download stalls; you can also switch while downloading, or pin one in Settings → About → Download from. On macOS, Download installer starts this version's .dmg download in your browser instead of opening the Releases page.
1677
+ - Desktop and engine versions are independent: Desktop 2.13.6 includes engine 2.13.7, and hot updates check compatibility against the actual desktop version.
1666
1678
  - **Android**:
1667
1679
  - Quitting while you're in Tangu no longer loses your open tabs on the next launch, and when Start in is set to another Space, that Space no longer opens with the previous Space's tabs and panels.
1668
1680
  - On tablets and on phones in landscape, Spaces move to a full-height bar on the left: Home comes first, pinned Spaces take priority when they don't all fit and the last slot is All, and your avatar sits at the bottom; in portrait the bottom Dock stays. The title capsule moves into the main area, and Home is centered on tablets. Whiteboards fill the whole screen height with their menu and toolbar in the capsule row, and with a finger the pan hint now says to drag or pinch with two fingers.
@@ -1674,16 +1686,18 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
1674
1686
  - **Windows**:
1675
1687
  - Quickly dragging a Mini card's edge or corner to resize it no longer sometimes does nothing.
1676
1688
  - Mini cards now animate when they fold against the screen edge and when they expand, no longer show square corners after a theme change, and stay on their own monitor when folded against an edge shared with another monitor.
1677
- - Note paths are now written one way, so the same note is no longer treated as two: tab following, unsaved drafts, pins and calendar settings all line up, and records from older versions convert automatically.
1678
- - Approvals: in Ask mode, only read-only cmd forms such as \`dir\` and \`type\` skip approval, and every other command needs approval (\`git status\` too). Muse now reads its own logs and files with a file-reading tool that needs no approval, instead of queuing a string of approval cards.
1689
+ - Note paths are now written one way and case-equivalent paths reuse a tab, so the same note is no longer treated as two: tab following, unsaved drafts, pins and calendar settings all line up, and records from older versions convert automatically.
1690
+ - Approvals: in Ask mode, bounded read-only cmd directory queries and text searches can be combined without repeated approval. Writes, credential reads and other programs still require approval (\`git status\` too). Muse reads its own logs and files with a file-reading tool that needs no approval, instead of queuing a string of approval cards.
1691
+ - Window buttons no longer overlap the tab bar, and installation and removal preserve other apps’ file associations.
1679
1692
  - **Web** (takes effect once the web version is updated):
1680
1693
  - Opened in a phone or tablet browser, the web version now looks and works like the Android app: a bottom Dock in portrait and a bar on the left on tablets in landscape. An iPad opened or refreshed in landscape gets this layout too, instead of the desktop one.
1681
1694
  - Your Forsion account page, the Store (membership, points, items and plugin submissions), announcements and Penzor Cloud are now on the web, and Penzor Cloud can browse, upload and download files.
1682
- - **Plugins** (for authors): the forsion-plugin skill is now 1.59.0.
1695
+ - **Plugins** (for authors): the forsion-plugin skill is now 1.60.1.
1683
1696
  - Views and UI: a plugin view can close itself from its own content with \`view.close()\` (the same API for desktop floating panels and Web overlays); \`ctx.ui.mountSettingsPage\` / \`mountSettingsItem\` draw settings pages like the host's from data, laid out by control on phones; \`ctx.ui.setViewModes\` puts a view mode switcher in a plugin view's top row; \`ctx.registerToolResultRenderer\` gives your engine half's tools native result cards that can move between the chat and the Agent Desk; \`ctx.ui.contextMenu\` adds \`opts.keepOpen\` and a handle with \`update(items)\`, so checklists can be ticked several times in a row, and long menus scroll (up to 200 items); \`ctx.ui.mountModelPicker\` and per-call model choice are new too; a setting with \`secret: true\` shows as a password field (masked, not encrypted).
1684
- - Layout and Ribbon: \`rightCompanions\` on \`registerView\` declares the right panel set a view wants when it's in front; \`ctx.app.setSpaceDot\` / \`setSpaceProgress\` put a dot or a progress ring on your Space in the Ribbon; \`ctx.spaces.mountIcon\` follows the Space, so re-registering the same id with a new icon redraws it in place; \`ctx.closeView(id, { collapse: true })\` collapses a whole side; \`ctx.app.queuePopup\` puts your own pop-ups in the host's queue; an item in a Space recipe's \`layout.main\` can set \`"mainPage": true\` to be the page you land on in that Space.
1697
+ - Layout and Ribbon: \`rightCompanions\` on \`registerView\` declares the right panel set a view wants when it's in front; \`mainCompanions\` and \`setCompanionsVisible\` support companion views in the main area; \`ctx.app.setSpaceDot\` / \`setSpaceProgress\` put a dot or a progress ring on your Space in the Ribbon; \`ctx.spaces.mountIcon\` follows the Space, so re-registering the same id with a new icon redraws it in place; \`ctx.closeView(id, { collapse: true })\` collapses a whole side; \`ctx.app.queuePopup\` puts your own pop-ups in the host's queue; an item in a Space recipe's \`layout.main\` can set \`"mainPage": true\` to be the page you land on in that Space.
1685
1698
  - Data and events: \`ctx.databases\` / \`ctx.noteTasks\` read and write databases and @ tasks in notes; the \`calendar\` tier of \`ctx.calendar\` (overlay calendar sources, calendar settings, .ics management), \`ctx.ui.mountRecord\`, \`openNote\` jumping to a heading, and notifications with action buttons; \`ctx.app.onVaultEvent\` reports creates, deletes, renames and outside changes in the vault; a command receipt can carry a \`result\` for the model; \`"syncData": true\` in the manifest syncs plugin data with the account across desktop and phone; plus \`ctx.spaces\`, \`ctx.tangu.mountComposer\`, \`ctx.app.openSpace\` / \`openLink\` / \`watchAccountName\`, \`ctx.wallpaper.bing\` and \`ctx.achievements\`.
1686
1699
  - Engine plugins: the manifest can declare a bundled stdio MCP server (\`mcpServers\`) and observe-only \`hooks\` that never block, started and stopped with the plugin; the tool context exposes \`presentDesk\` / \`runId\`; a plugin's details page lists the capabilities its manifest declares.
1700
+ - Work folders and the personal calendar: new plugin IDs use stable English identifiers. Use the schema-aware \`workFolder\` / \`migrateWorkFolder\` migration once, preserving original data and per-vault records. Local plugins with both \`databases\` and \`calendar\` capabilities can access the personal calendar through the host-provided \`human://CALENDAR.db\` reference; never treat it as a filesystem path.
1687
1701
  - **Fixes**:
1688
1702
  - DeepSeek V4.1 Flash couldn't see images you sent (they were turned into a text description first).
1689
1703
  - In long chats and long notes, jumping from the outline or a search result got pulled back to the bottom or landed in the wrong place.
@@ -1694,7 +1708,7 @@ function Xd(e,t){for(var n=0;n<t.length;n++){const i=t[n];if(typeof i!="string"&
1694
1708
  - With the calendar open in a tab, switching to another tab and back made the week view jump to August and the month view to a different month.
1695
1709
  - In the English interface, calendar event cards and the new-event card showed dates in Chinese.
1696
1710
  - English chats were sometimes given Chinese titles and summaries.
1697
- - In notes, pressing ← or Backspace at the start of a line inside a fold block split the text out of the block, so collapsing it only hid the paragraphs before.
1711
+ - In notes, pressing ← or Backspace at the start of a line inside a fold block, or pressing Enter twice, no longer splits content out of the block; collapsing it hides the complete content.
1698
1712
 
1699
1713
  ## 2.13.4 (2026-10-14)
1700
1714
 
@@ -3395,4 +3409,4 @@ ${o}`:`${c}
3395
3409
  `)}function TA(e,t){const n=e.split(`
3396
3410
  `);let i=null;for(let o=0;o<n.length;o++){const s=ho.exec(n[o]);if(s&&(!i||s[1][0]===i)){i=i?null:s[1][0];continue}if(i)continue;const a=/^(#{1,6})\s+(.*?)\s*#*\s*$/.exec(n[o]);if(!a||a[2].trim().toLowerCase()!==t)continue;const r=a[1].length,l=[n[o]];let c=null;for(let d=o+1;d<n.length;d++){const u=ho.exec(n[d]);if(u&&(!c||u[1][0]===c)){c=c?null:u[1][0],l.push(n[d]);continue}if(!c){const p=/^(#{1,6})\s/.exec(n[d]);if(p&&p[1].length<=r)break}l.push(n[d])}return l.join(`
3397
3411
  `).trimEnd()}return null}function Ld(e,t){const n=ha(e);for(const i of Ul(n))if(i.id&&i.id.toLowerCase()===t)return AA(e)?i.content:CA(i.content);return TA(n,t)}function IA(e){const t=e.fetch??((...h)=>fetch(...h)),n=`${e.apiBase}/amadeus/public/shares/${encodeURIComponent(e.token)}`,i=h=>()=>Promise.reject(new vA(h)),o=()=>()=>{},s=()=>e.tree().pages,a=new Map,r=h=>{let m=a.get(h);return m||(m=(async()=>{const g=await t(`${n}/file?path=${encodeURIComponent(h)}`);if(g.status===404)return null;if(!g.ok)throw new Error(`share file ${g.status}`);const y=await g.json();return typeof y.content=="string"?y.content:""})(),a.set(h,m),m.catch(()=>a.delete(h))),m},l=(h,m)=>{const g=new URLSearchParams({ref:h});return m&&g.set("page",m),`${n}/asset?${g.toString()}`},c=async(h,m)=>{const g=await t(l(h,m));if(g.status===404)return null;if(!g.ok)throw new Error(`share asset ${g.status}`);return g},d=async h=>{const m=await r(h);if(m==null)throw new Error(`not found: ${h}`);return ji(h,m,SA())},u=()=>({root:`share:${e.token}`,pages:s(),folders:e.tree().folders});return{openVault:async()=>u(),restoreVault:async()=>u(),listPages:async()=>s(),listFiles:async()=>[],listFolders:async()=>e.tree().folders,loadPage:d,readPage:d,reconcilePage:h=>d(h),newPage:i("newPage"),savePage:i("savePage"),renamePage:i("renamePage"),saveAsset:i("saveAsset"),saveVaultBytes:i("saveVaultBytes"),readVaultBytes:async h=>{const m=await c(h,e.currentPage());if(!m)throw new Error(`not found: ${h}`);return new Uint8Array(await m.arrayBuffer())},saveAttachment:i("saveAttachment"),openAttachment:async(h,m)=>{window.open(l(m,h),"_blank","noopener")},openVaultFile:async h=>{window.open(l(h,null),"_blank","noopener")},exportPdf:async()=>(window.print(),null),onExternalChange:o,onStructureChange:o,onDbExternalChange:o,search:async()=>[],backlinks:async()=>[],reindex:async()=>{},listTags:async()=>[],pagesByTag:async()=>[],deletePage:i("deletePage"),movePage:i("movePage"),resolveEmbed:async h=>{const{noteKey:m,id:g}=xA(h);if(!g)return null;const y=e.currentPage(),b=s(),C=m?b.filter(S=>gn(S)===m):[...y&&b.includes(y)?[y]:[],...b.filter(S=>S!==y)];for(const S of C){const T=await r(S);if(T==null)continue;const O=Ld(T,g);if(O!==null)return{owner:S,content:O,type:"markdown"}}return null},blockBacklinks:async()=>[],createFolder:i("createFolder"),renameFolder:i("renameFolder"),deleteFolder:i("deleteFolder"),moveFolder:i("moveFolder"),listPlugins:async()=>[],openPluginsFolder:async()=>{},scaffoldSamplePlugin:async()=>{},revealInFileManager:async()=>{},readDatabase:async(h,m)=>{const g=await c(m,h);if(!g)return{status:"missing"};const y=Sl(h,m),b=Ou(await g.text());return b.ok?{status:"ok",path:y,data:b.data}:{status:"corrupt",path:y,message:b.error}},writeDatabase:i("writeDatabase"),readDrawing:async(h,m)=>{for(const g of/\.md$/i.test(m)?[m]:[m,`${m}.md`]){const y=await c(g,h);if(y)return{status:"ok",path:Sl(h,g),source:await y.text()}}return{status:"missing"}},writeDrawing:i("writeDrawing"),readTextFile:h=>r(h),writeTextFile:i("writeTextFile"),listPageProps:async h=>{const m=h.replace(/\\/g,"/").replace(/^\/+|\/+$/g,""),g=s().filter(b=>Nd(b)===m),y=[];for(const b of g){const C=await r(b);C!=null&&y.push({path:b,title:jl(b),fm:hu(C)})}return y},setPageFrontmatter:i("setPageFrontmatter"),renamePageFile:i("renamePageFile"),renameDbFile:i("renameDbFile")}}function zC(e){const t=IA(e);return Au((n,i)=>{const o=new URLSearchParams({ref:it(n)||n}),s=i?null:e.currentPage();return s&&o.set("page",s),`${e.apiBase}/amadeus/public/shares/${encodeURIComponent(e.token)}/asset?${o.toString()}`}),typeof window<"u"&&(window.amadeus=t),t}const EA=e=>{const t=e.search(/\\\||[#|]/);return t<0?{note:e,suffix:""}:{note:e.slice(0,t),suffix:e.slice(t)}},_A=e=>(e.split("/").pop()??e).replace(/\.md$/i,"");function PA(e,t,n,i){if(!e.includes("[["))return e;const o=i.pagesBefore,s=i.pagesAfter;return Fn(e,a=>a.replace(/(!?)\[\[([^\]\n]+)\]\]/g,(r,l,c)=>{const{note:d,suffix:u}=EA(c),p=d.trim();if(!p)return r;const h=Ui(p,o,t);if(!h)return r;const m=i.pairs.get(h)??h;if(Ui(p,s,n)===m)return r;const g=_A(m),b=!/[\\/]/.test(p)&&Ui(g,s,n)===m?g:m.replace(/\.md$/i,"");return`${l}[[${b}${u}]]`}))}const FA=e=>{const[t,n]=(e??[]).map(i=>i.replace(/\\/g,"/").replace(/\/+$/,""));return i=>t&&(i===t||i.startsWith(`${t}/`))?n+i.slice(t.length):i};async function OA(e,t,n,i={}){const o={rewritten:[],failed:[]},s=b=>b.replace(/\\/g,"/"),a=new Map(Object.entries(t).map(([b,C])=>[s(b),s(C)]).filter(([b,C])=>b!==C));if(!a.size&&!i.folder)return o;const r=new Map([...a].map(([b,C])=>[C,b])),l=n.map(s).sort(),c=l.map(b=>a.get(b)??b).sort(),d={pairs:a,pagesBefore:l,pagesAfter:c},u=Math.max(1,i.attempts??3),p=i.folder?FA(i.folder):null,h=e.exists?.bind(e),m=async b=>{try{let C=await e.read(b);if(C==null){o.failed.push({path:b,error:"gone"});return}const S=new Set;for(let T=0;T<u;T++){const O=r.get(b)??b,v=PA(C,O,b,d),I=h?await wx(v,O,b,p,h,T?{only:S}:{seen:S}):v;if(I===C)return;const P=await e.write(b,I,cn(C));if(P==="gone"){o.failed.push({path:b,error:"gone"});return}if(!P||P.ok){o.rewritten.push(b);return}if(P.current==null){o.failed.push({path:b,error:"gone"});return}C=P.current}o.failed.push({path:b,error:"conflict"})}catch(C){o.failed.push({path:b,error:C instanceof Error?C.message:String(C)})}},g=[...c],y=Array.from({length:Math.max(1,Math.min(i.concurrency??6,g.length))},async()=>{for(let b=g.shift();b!==void 0;b=g.shift())await m(b)});return await Promise.all(y),o.rewritten.sort(),o}const NA=["renamePage","renamePageFile","movePage","renameFolder","moveFolder","deletePage","deleteFolder","trashEntry","restoreTrash"];function LA(e){const t=e;let n=Promise.resolve();for(const i of NA){const o=t[i];typeof o=="function"&&(t[i]=(...s)=>{const a=n.then(()=>o(...s));return n=a.catch(()=>{}),a})}return e}var us={exports:{}},Vn={};var Al;function MA(){if(Al)return Vn;Al=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.fragment");function n(i,o,s){var a=null;if(s!==void 0&&(a=""+s),o.key!==void 0&&(a=""+o.key),"key"in o){s={};for(var r in o)r!=="key"&&(s[r]=o[r])}else s=o;return o=s.ref,{$$typeof:e,type:i,key:a,ref:o!==void 0?o:null,props:s}}return Vn.Fragment=t,Vn.jsx=n,Vn.jsxs=n,Vn}var Cl;function RA(){return Cl||(Cl=1,us.exports=MA()),us.exports}var No=RA();const DA=wo(No),jC=Xd({__proto__:null,default:DA},[No]);var ds={exports:{}},oe={};var Tl;function $A(){if(Tl)return oe;Tl=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),i=Symbol.for("react.strict_mode"),o=Symbol.for("react.profiler"),s=Symbol.for("react.consumer"),a=Symbol.for("react.context"),r=Symbol.for("react.forward_ref"),l=Symbol.for("react.suspense"),c=Symbol.for("react.memo"),d=Symbol.for("react.lazy"),u=Symbol.for("react.activity"),p=Symbol.iterator;function h(E){return E===null||typeof E!="object"?null:(E=p&&E[p]||E["@@iterator"],typeof E=="function"?E:null)}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,y={};function b(E,_,w){this.props=E,this.context=_,this.refs=y,this.updater=w||m}b.prototype.isReactComponent={},b.prototype.setState=function(E,_){if(typeof E!="object"&&typeof E!="function"&&E!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,E,_,"setState")},b.prototype.forceUpdate=function(E){this.updater.enqueueForceUpdate(this,E,"forceUpdate")};function C(){}C.prototype=b.prototype;function S(E,_,w){this.props=E,this.context=_,this.refs=y,this.updater=w||m}var T=S.prototype=new C;T.constructor=S,g(T,b.prototype),T.isPureReactComponent=!0;var O=Array.isArray;function v(){}var I={H:null,A:null,T:null,S:null},P=Object.prototype.hasOwnProperty;function W(E,_,w){var $=w.ref;return{$$typeof:e,type:E,key:_,ref:$!==void 0?$:null,props:w}}function L(E,_){return W(E.type,_,E.props)}function U(E){return typeof E=="object"&&E!==null&&E.$$typeof===e}function B(E){var _={"=":"=0",":":"=2"};return"$"+E.replace(/[=:]/g,function(w){return _[w]})}var ee=/\/+/g;function ae(E,_){return typeof E=="object"&&E!==null&&E.key!=null?B(""+E.key):_.toString(36)}function te(E){switch(E.status){case"fulfilled":return E.value;case"rejected":throw E.reason;default:switch(typeof E.status=="string"?E.then(v,v):(E.status="pending",E.then(function(_){E.status==="pending"&&(E.status="fulfilled",E.value=_)},function(_){E.status==="pending"&&(E.status="rejected",E.reason=_)})),E.status){case"fulfilled":return E.value;case"rejected":throw E.reason}}throw E}function ue(E,_,w,$,q){var H=typeof E;(H==="undefined"||H==="boolean")&&(E=null);var X=!1;if(E===null)X=!0;else switch(H){case"bigint":case"string":case"number":X=!0;break;case"object":switch(E.$$typeof){case e:case t:X=!0;break;case d:return X=E._init,ue(X(E._payload),_,w,$,q)}}if(X)return q=q(E),X=$===""?"."+ae(E,0):$,O(q)?(w="",X!=null&&(w=X.replace(ee,"$&/")+"/"),ue(q,_,w,"",function(ye){return ye})):q!=null&&(U(q)&&(q=L(q,w+(q.key==null||E&&E.key===q.key?"":(""+q.key).replace(ee,"$&/")+"/")+X)),_.push(q)),1;X=0;var ne=$===""?".":$+":";if(O(E))for(var ge=0;ge<E.length;ge++)$=E[ge],H=ne+ae($,ge),X+=ue($,_,w,H,q);else if(ge=h(E),typeof ge=="function")for(E=ge.call(E),ge=0;!($=E.next()).done;)$=$.value,H=ne+ae($,ge++),X+=ue($,_,w,H,q);else if(H==="object"){if(typeof E.then=="function")return ue(te(E),_,w,$,q);throw _=String(E),Error("Objects are not valid as a React child (found: "+(_==="[object Object]"?"object with keys {"+Object.keys(E).join(", ")+"}":_)+"). If you meant to render a collection of children, use an array instead.")}return X}function he(E,_,w){if(E==null)return E;var $=[],q=0;return ue(E,$,"","",function(H){return _.call(w,H,q++)}),$}function be(E){if(E._status===-1){var _=E._result;_=_(),_.then(function(w){(E._status===0||E._status===-1)&&(E._status=1,E._result=w)},function(w){(E._status===0||E._status===-1)&&(E._status=2,E._result=w)}),E._status===-1&&(E._status=0,E._result=_)}if(E._status===1)return E._result.default;throw E._result}var ce=typeof reportError=="function"?reportError:function(E){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var _=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof E=="object"&&E!==null&&typeof E.message=="string"?String(E.message):String(E),error:E});if(!window.dispatchEvent(_))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",E);return}console.error(E)},A={map:he,forEach:function(E,_,w){he(E,function(){_.apply(this,arguments)},w)},count:function(E){var _=0;return he(E,function(){_++}),_},toArray:function(E){return he(E,function(_){return _})||[]},only:function(E){if(!U(E))throw Error("React.Children.only expected to receive a single React element child.");return E}};return oe.Activity=u,oe.Children=A,oe.Component=b,oe.Fragment=n,oe.Profiler=o,oe.PureComponent=S,oe.StrictMode=i,oe.Suspense=l,oe.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE=I,oe.__COMPILER_RUNTIME={__proto__:null,c:function(E){return I.H.useMemoCache(E)}},oe.cache=function(E){return function(){return E.apply(null,arguments)}},oe.cacheSignal=function(){return null},oe.cloneElement=function(E,_,w){if(E==null)throw Error("The argument must be a React element, but you passed "+E+".");var $=g({},E.props),q=E.key;if(_!=null)for(H in _.key!==void 0&&(q=""+_.key),_)!P.call(_,H)||H==="key"||H==="__self"||H==="__source"||H==="ref"&&_.ref===void 0||($[H]=_[H]);var H=arguments.length-2;if(H===1)$.children=w;else if(1<H){for(var X=Array(H),ne=0;ne<H;ne++)X[ne]=arguments[ne+2];$.children=X}return W(E.type,q,$)},oe.createContext=function(E){return E={$$typeof:a,_currentValue:E,_currentValue2:E,_threadCount:0,Provider:null,Consumer:null},E.Provider=E,E.Consumer={$$typeof:s,_context:E},E},oe.createElement=function(E,_,w){var $,q={},H=null;if(_!=null)for($ in _.key!==void 0&&(H=""+_.key),_)P.call(_,$)&&$!=="key"&&$!=="__self"&&$!=="__source"&&(q[$]=_[$]);var X=arguments.length-2;if(X===1)q.children=w;else if(1<X){for(var ne=Array(X),ge=0;ge<X;ge++)ne[ge]=arguments[ge+2];q.children=ne}if(E&&E.defaultProps)for($ in X=E.defaultProps,X)q[$]===void 0&&(q[$]=X[$]);return W(E,H,q)},oe.createRef=function(){return{current:null}},oe.forwardRef=function(E){return{$$typeof:r,render:E}},oe.isValidElement=U,oe.lazy=function(E){return{$$typeof:d,_payload:{_status:-1,_result:E},_init:be}},oe.memo=function(E,_){return{$$typeof:c,type:E,compare:_===void 0?null:_}},oe.startTransition=function(E){var _=I.T,w={};I.T=w;try{var $=E(),q=I.S;q!==null&&q(w,$),typeof $=="object"&&$!==null&&typeof $.then=="function"&&$.then(v,ce)}catch(H){ce(H)}finally{_!==null&&w.types!==null&&(_.types=w.types),I.T=_}},oe.unstable_useCacheRefresh=function(){return I.H.useCacheRefresh()},oe.use=function(E){return I.H.use(E)},oe.useActionState=function(E,_,w){return I.H.useActionState(E,_,w)},oe.useCallback=function(E,_){return I.H.useCallback(E,_)},oe.useContext=function(E){return I.H.useContext(E)},oe.useDebugValue=function(){},oe.useDeferredValue=function(E,_){return I.H.useDeferredValue(E,_)},oe.useEffect=function(E,_){return I.H.useEffect(E,_)},oe.useEffectEvent=function(E){return I.H.useEffectEvent(E)},oe.useId=function(){return I.H.useId()},oe.useImperativeHandle=function(E,_,w){return I.H.useImperativeHandle(E,_,w)},oe.useInsertionEffect=function(E,_){return I.H.useInsertionEffect(E,_)},oe.useLayoutEffect=function(E,_){return I.H.useLayoutEffect(E,_)},oe.useMemo=function(E,_){return I.H.useMemo(E,_)},oe.useOptimistic=function(E,_){return I.H.useOptimistic(E,_)},oe.useReducer=function(E,_,w){return I.H.useReducer(E,_,w)},oe.useRef=function(E){return I.H.useRef(E)},oe.useState=function(E){return I.H.useState(E)},oe.useSyncExternalStore=function(E,_,w){return I.H.useSyncExternalStore(E,_,w)},oe.useTransition=function(){return I.H.useTransition()},oe.version="19.2.7",oe}var Il;function zA(){return Il||(Il=1,ds.exports=$A()),ds.exports}var ot=zA();const BC=wo(ot),UC="xyra",jA="forsion_tangu_smooth_caret",BA="forsion_selection_bar_order",UA="forsion_ui_zoom",pi="tangu_locale",HA="forsion_tangu_font_ui",WA="forsion_tangu_font_body",qA="forsion_tangu_font_mono",VA=[HA,WA,qA,jA,BA,UA,pi],GA=/^theme\.[A-Za-z0-9._-]{1,64}\.--[a-z0-9-]{1,64}$/i;let $s=!1;function HC(e){$s=!0;try{e()}finally{$s=!1}}const El=e=>{try{return localStorage.getItem(e)}catch{return null}};function ZA(){const e={};for(const t of VA)e[t]=El(t);try{const t=document.documentElement.dataset.theme||"";for(let n=0;n<localStorage.length;n++){const i=localStorage.key(n);i&&GA.test(i)&&i.startsWith(`theme.${t}.`)&&(e[i]=El(i))}}catch{}return e}function KA(){if(!$s)try{window.tangu?.broadcastUi?.({prefs:ZA()})}catch{}}function YA(e){const t=typeof e?.cloudApiBase=="string"?e.cloudApiBase.trim():"";if(t)return t.replace(/\/+$/,"");const n=typeof e?.cloudUrl=="string"?e.cloudUrl.trim().replace(/\/+$/,""):"";return n?`${n}/api`:""}const zs="forsion_region";function Md(){try{const e=navigator.languages?.length?navigator.languages:[navigator.language];for(const t of e){const n=String(t||"").toLowerCase();if(n)return n.startsWith("zh")?"zh":"en"}}catch{}return null}function Rd(){try{const t=localStorage.getItem(pi);if(t==="en"||t==="zh")return t}catch{}const e=Md();if(e==="zh")return"zh";try{const t=localStorage.getItem(zs);if(t)return t==="CN"?"zh":"en"}catch{}return e??"zh"}async function JA(){if(Md()==="zh")return;try{if(localStorage.getItem(pi)||localStorage.getItem(zs))return}catch{return}let e="";try{e=YA(await window.tangu?.getConfig?.())}catch{}if(!e)return;const t=`${e}/auth/region`;try{const n=new AbortController,i=setTimeout(()=>n.abort(),3e3),o=await fetch(t,{signal:n.signal}).finally(()=>clearTimeout(i));if(!o.ok)return;const s=(await o.json())?.country;if(!s)return;try{localStorage.setItem(zs,s)}catch{}const a=s==="CN"?"zh":"en";a!==Bs()&&Bd(a)}catch{}}const Oa={"common.save":"保存","settings.python.label":"Python","settings.python.bundled":"内置(推荐)","settings.python.system":"系统","settings.python.hint":"内置:免安装、与你自己的 Python 隔离;系统:用你已装的 python(改动后重启后端生效)。","settings.mirror.label":"网络镜像","settings.mirror.toggle":"使用中国大陆镜像源","settings.mirror.recommend":"检测到你的系统环境可能位于中国大陆,建议开启镜像源以加速下载。","settings.mirror.hint":"开启后,引导安装、pip 装包、Agent 运行的 npx/git 与商店下载走国内镜像(清华/npmmirror/多站 GitHub 代理)。仅对 Forsion 发起的命令注入环境变量,不修改任何系统配置文件,可随时关闭;pip/npm/git 部分需「内置后端」模式。","settings.mirror.test":"测试连通","settings.mirror.unreachable":"不可达","settings.test.canceled":"已取消","settings.test.timeout":"✗ 连接超时","onboarding.env.mirrorLabel":"网络环境","onboarding.env.pythonBundled":"Python 已内置,无需单独安装。","onboarding.env.recheck":"重新检测","onboarding.env.installOk":"{tool} 安装成功 · {version}","onboarding.env.installedButMissing":"命令已执行完成,但仍未检测到 {tool}。可能需要重启应用或新开终端后生效,也可点「重新检测」再试。","onboarding.env.installFail":"{tool} 安装失败(exit {code}),请查看下方日志。","onboarding.env.copyCmd":"复制命令","onboarding.env.copied":"⤷ 已复制到剪贴板,请打开「终端」粘贴执行(需要输入系统密码):{command}","sidebar.newChat":"新会话","sidebar.memory":"记忆","sidebar.agents":"后台 Agent","sidebar.viewMore":"查看更多","tip.folder":"{files} 个文件,{folders} 个文件夹","tip.modified":"修改:{t}","tip.created":"创建:{t}","input.project.label":"项目","input.project.none":"不在项目中","input.project.dontWork":"不在项目中工作","input.project.search":"搜索项目","input.project.noMatches":"没有匹配的项目","input.project.add":"添加本地项目","input.project.clone":"从 Git 克隆…","input.project.addCloud":"新建云端项目","input.project.cloudName":"项目名称,回车创建","settings.advanced.sessionLimit":"侧栏每个项目显示的会话数","settings.mcpServer.label":"对外 MCP 端点(给外部 Agent 用)","settings.mcpServer.hint":"开启后本机起一个本地 HTTP MCP 端点,外部 Agent(Claude Code / Codex / OpenCode 等)可通过它调用 Forsion Desktop 的能力(当前:发消息到收件箱)。仅监听 127.0.0.1,带令牌鉴权。","settings.mcpServer.enable":"开放给外部 Agent(Claude Code / Codex / OpenCode 等)","settings.mcpServer.connectHint":"选择你的 Agent,复制配置接入(令牌已内嵌):","settings.mcpServer.endpoint":"端点","settings.mcpServer.generic":"通用 JSON","settings.mcpServer.genericNote":"任意支持 Streamable HTTP MCP 的客户端(Cursor / Windsurf / Cline 等)用「通用」配置填 url + Authorization 头即可。","settings.mcpServer.copy":"复制","settings.mcpServer.notRunning":"端点未能启动,请查看日志或重启应用。","common.cancel":"取消","common.retry":"重试","workbench.sessions":"工作会话","space.home":"主页","space.tangu":"Tangu","space.amadeus":"笔记","space.calendar":"日历","view.todo":"待办清单","view.calendar":"日历","view.calendarConfig":"日历设置","view.db":"多维表","view.drawing":"白板","space.coding":"编码工作室","view.codeStudio":"编码工作室","space.artificial":"造物","view.artificial":"造物","view.product":"作品","space.public":"发布","view.publicHub":"发布管理","public.title":"发布管理","public.subtitle":"集中管理你已发布的网站与笔记","public.needLogin":"登录 Forsion 账号后查看已发布内容","public.refresh":"刷新","public.empty":"暂无内容","public.open":"打开","public.copy":"复制链接","public.copied":"已复制","public.unpublish":"下架","public.revoke":"撤销","public.confirm":"确认?","public.sites":"我的网站","public.sitesDesc":"Forsion Connect 托管的网页应用","public.published":"公开发布的笔记","public.publishedDesc":"任何人可只读访问的分享链接","public.shared":"协作共享的笔记","public.sharedDesc":"邀请他人编辑 / 查看的页面","public.disabled":"已停用","public.unavailable":"此功能在当前环境不可用","coding.code":"代码","coding.preview":"预览","coding.reload":"刷新预览","coding.noEntry":"暂无入口页面","coding.noFile":"未选择文件","coding.pickFile":"在右侧文件树点选一个文件来编辑","coding.emptyPreview":"还没有可预览的页面。让左侧的 Coding Agent 生成一个 index.html 吧。","coding.projects":"项目","coding.newProject":"新建项目","coding.publish":"发布","coding.publishTitle":"发布到 Forsion","coding.publishDesc":"把这个网页应用发布成公开链接。应用内可用 window.forsion 调用 Forsion AI —— 访客登录自己的 Forsion 账号、消耗自己的额度。","coding.publishName":"应用名称","coding.publishSlug":"链接标识","coding.publishSlugHint":"3-32 位小写字母 / 数字 / 中划线","coding.publishEntry":"入口页面","coding.publishSlots":"已发布 {used}/{limit} 个({tier})","coding.publishBtn":"发布","coding.publishUpdate":"更新发布","coding.publishing":"发布中…","coding.unpublish":"下架","coding.unpublishConfirm":"确认下架?","coding.publishNeedLogin":"发布需要登录 Forsion 账号","coding.loginNow":"登录 Forsion","coding.loginWaiting":"等待浏览器完成授权…","coding.copyLink":"复制链接","coding.copied":"已复制","coding.openLink":"打开","coding.publishHint":"资源请用相对路径引用;.ts/.tsx 发布时自动转译,无需构建。","coding.publishNoEntry":"项目里还没有 .html 入口,先让 AI 生成页面再发布。","coding.listingTitle":"商店","coding.listingHint":"上架后会在商店「网站应用」中公开展示,需要平台审核。","coding.listingNone":"未上架","coding.listingPending":"审核中","coding.listingApproved":"已上架","coding.listingRejected":"已驳回","coding.listingNoteLabel":"驳回原因:{note}","coding.listingApply":"申请上架","coding.listingReapply":"重新申请","coding.listingWithdraw":"撤回申请","coding.listingDelist":"下架","coding.listingSummaryPh":"一句话介绍这个应用(审核后展示在商店的卡片上,300 字内)","coding.listingSubmit":"提交申请","coding.termsTitle":"发布为公开页面","coding.termsIntro":"发布后,任何获得链接的人均可查看该页面,页面也可能被转发或被搜索引擎收录。请确认:","coding.termsLi1":"你有权发布页面中的文字、图片、音视频及其他内容;","coding.termsLi2":"页面不包含违法信息、侵权内容或未经许可披露的个人信息;","coding.termsLi3":"你将对自己发布的内容承担相应责任。","coding.termsManage":"平台将依据法律法规及《内容发布规范》对公开内容进行管理,并可能对违规内容采取限制访问、停止展示或删除等措施。","coding.termsAgreePre":"我已阅读并同意","coding.termsGuidelines":"《内容发布规范》","coding.termsConfirm":"确认发布","coding.cancel":"取消","coding.projectName":"项目名称","coding.create":"创建","coding.noProjects":"还没有项目。点「新建项目」创建第一个。","coding.switchProject":"切换项目","coding.generating":"生成中…","space.inbox":"收件箱","inbox.list":"消息列表","inbox.reader":"消息阅读","inbox.filter.unread":"未读","inbox.filter.archived":"已归档","inbox.reader.empty":"选择一封消息开始阅读","inbox.sender.system":"系统","inbox.sender.automation":"自动化","inbox.action.markRead":"标为已读","inbox.action.markUnread":"标为未读","inbox.action.readAll":"全部已读","inbox.action.archive":"归档","inbox.action.unarchive":"取消归档","inbox.action.delete":"删除","inbox.action.refresh":"拉取新消息","inbox.action.chat":"与 {name} 聊天","inbox.deleteConfirm":"删除消息「{title}」?","time.justNow":"刚刚","net.unavailable":"网络不可用,请稍后再试","inbox.pullOk":"已拉取 {n} 条新消息","inbox.pullNone":"没有新消息","inbox.opFail":"操作失败:{e}","inbox.attach.title":"附带物品","inbox.attach.claim":"领取","inbox.approval.title":"请求批准","inbox.approval.waiting":"等你决定","inbox.approval.loading":"读取审批记录…","inbox.approval.missing":"找不到这条审批记录(可能已过期或已清理)","inbox.approval.approved":"已批准并执行","inbox.approval.rejected":"已拒绝","inbox.approval.executing":"执行中…","inbox.approval.failed":"已批准,但执行失败","inbox.approval.loadFail":"读取审批记录失败","inbox.approval.retry":"重试","inbox.approval.reason.customAsk":"你的审批规则要求","inbox.approval.reason.rule":"审批规则「{rule}」","inbox.approval.reason.escalate":"写工作区以外的文件","inbox.approval.reason.mode":"审批档要求批准","inbox.approval.reason.control":"设置无人值守工作","inbox.attach.claiming":"领取中…","inbox.attach.claimed":"已领取","inbox.attach.expired":"已过期,无法领取","inbox.claim.ok":"已领取,物品已入账","inbox.claim.already":"之前已领取过","inbox.claim.fail":"领取失败","inbox.claim.unmet":"未满足领取条件,暂时领不了","inbox.attach.unmet":"未满足领取条件","inbox.req.title":"领取条件","inbox.req.version":"客户端 {v} 及以上","inbox.req.tiers":"{tiers}","inbox.req.currentVersion":"当前版本 {v}","inbox.req.currentTier":"当前:{tier}","inbox.req.other":"另有条件(以领取时服务端校验为准)","inbox.feedback.title":"反馈线程","inbox.feedback.event.created":"新的用户反馈","inbox.feedback.event.user_reply":"用户回复了反馈","inbox.feedback.event.admin_reply":"你的反馈有了回复","inbox.feedback.loading":"读取反馈线程…","inbox.feedback.loadFail":"读不到反馈线程","inbox.feedback.signIn":"登录 Forsion 账号后可查看与回复","inbox.feedback.missing":"这条反馈已不存在","inbox.feedback.retry":"重试","inbox.feedback.you":"你","inbox.feedback.support":"Forsion 支持","inbox.feedback.user":"用户","inbox.feedback.replyPh":"回复…","inbox.feedback.attach":"添加附件","inbox.feedback.attachHint":"图片 / 文本 / JSON,单个 ≤5MB,最多 5 个","inbox.feedback.remove":"移除","inbox.feedback.send":"发送","inbox.feedback.sending":"发送中…","inbox.feedback.sendFail":"发送失败:{e}","inbox.feedback.tooMany":"最多 5 个附件","inbox.feedback.tooBig":"{name} 超过 5MB 或为空","inbox.feedback.badType":"{name} 类型不支持(只收图片 / 文本 / JSON)","inbox.feedback.download":"下载","inbox.feedback.status.open":"待处理","inbox.feedback.status.in_progress":"处理中","inbox.feedback.status.resolved":"已解决","inbox.feedback.status.closed":"已关闭","inbox.tier.free":"免费用户","inbox.tier.plus":"Plus 会员","inbox.tier.pro":"Pro 会员","inbox.expiresAt":"有效期至 {d}","inbox.expired":"已过期","settings.inbox.title":"收件箱","settings.inbox.notifyLabel":"新消息系统通知","settings.inbox.notifyHint":"收到新消息时弹系统通知(点击可直达收件箱);关闭后仅保留图标角标。","amadeus.pages":"智库","amadeus.editor":"编辑器","amadeus.outline":"大纲","amadeus.backlinks":"反链","amadeus.search":"搜索","amadeus.tags":"标签","amadeus.graph":"关系图","chat.action.copied":"已复制","chat.action.resend":"发送","input.slash.branch":"从最近一条回复分支新会话(继承历史)","app.sessionExpired":"登录已过期,请重新登录 Forsion 账号","onboarding.connect.syncTitle":"同步到蓬洲云","onboarding.connect.sync.notes":"这台电脑的智库","onboarding.connect.sync.agents":"Agents 与记忆","onboarding.connect.sync.plugins":"插件数据","onboarding.connect.cloudSyncHint":"和你的其他设备保持一致。以后在「蓬洲云 › 同步」里随时关。","common.confirm":"确定","extendView.close":"关闭扩展视图","extendView.failed":"扩展视图加载失败","extendView.back":"返回","common.close":"关闭","common.back":"返回","common.refresh":"刷新","common.loading":"加载中…","common.listSep":"、","common.delete":"删除","common.edit":"编辑","common.open":"打开","common.language":"语言","common.copyCode":"复制代码","common.enabled":"开启","common.disabled":"关闭","locale.zh":"中文","locale.en":"English","locale.toggleTitle":"切换语言","feedback.title":"反馈","achievements.title":"成就","achievements.unlocked":"成就达成","achievements.claim":"领取","achievements.claimed":"已领取","achievements.pts":"{n} 点","achievements.seriesPts":"{n}/{total} 点","achievements.pluginGroup":"插件","achievements.cloudGroup":"云端成就","achievements.localGroup":"本机成就","achievements.cloudTag":"云端 · 跟账号走","achievements.claimedOn":"已在 {device} 上领取","achievements.signInToClaim":"登录后领取","achievements.expired":"已过期","achievements.claimFailed":"领取失败:{msg}","achievements.claimErr.notCompleted":"还没有达成","achievements.claimErr.expired":"已过领取期限","achievements.claimErr.notFound":"这条成就已下架","achievements.claimErr.grantFailed":"奖励没能发出,已登记待补发,请联系客服","achievements.claimErr.signedOut":"登录已失效,请重新登录","achievements.claimErr.network":"连不上服务器,请稍后再试","achievements.claimErr.unknown":"服务器出错了,请稍后再试","achievements.claimable":"有可领取的成就","achievements.medal.bronze":"铜牌","achievements.medal.silver":"银牌","achievements.medal.gold":"金牌","achievements.s.starter":"初识","achievements.s.chat":"对话","achievements.s.notes":"笔记","achievements.s.agents":"Agent","achievements.a.first-login.title":"Forsion is All You Need","achievements.a.first-login.desc":"登录 Forsion 账号","achievements.a.theme-change.title":"焕然一新","achievements.a.theme-change.desc":"更换一次主题或配色","achievements.a.market-install.title":"超级武装","achievements.a.market-install.desc":"从商店安装一个项目","achievements.a.space-save.title":"Space 之力","achievements.a.space-save.desc":"把当前布局另存为 Space","achievements.a.first-message.title":"Hello Agent!","achievements.a.first-message.desc":"向 Agent 发出第一条消息","achievements.a.chat-10.title":"畅所欲言","achievements.a.chat-10.desc":"累计发出 10 条消息","achievements.a.chat-100.title":"滔滔不绝","achievements.a.chat-100.desc":"累计发出 100 条消息","achievements.a.group-chat.title":"圆桌会议","achievements.a.group-chat.desc":"发起一次团队协作","achievements.a.first-note.title":"妙笔生花","achievements.a.first-note.desc":"创建第一篇笔记","achievements.a.notes-10.title":"笔耕不辍","achievements.a.notes-10.desc":"累计创建 10 篇笔记","achievements.a.notes-100.title":"著作等身","achievements.a.notes-100.desc":"累计创建 100 篇笔记","achievements.a.first-base.title":"数据雏形","achievements.a.first-base.desc":"创建第一个 Base 多维表","achievements.a.first-agent.title":"造物主","achievements.a.first-agent.desc":"创建你的第一个 Agent","achievements.a.agents-3.title":"智囊团","achievements.a.agents-3.desc":"累计创建 3 个 Agent","achievements.a.special-agent.title":"幕后协作","achievements.a.special-agent.desc":"开启后台 Agent Muse 或 Historian","achievements.a.first-image.title":"妙笔生花","achievements.a.first-image.desc":"让 Agent 生成第一张图片","achievements.a.debug-toast.title":"这都被你发现了?","achievements.a.debug-toast.desc":"??????","settings.developer.achToastLabel":"成就弹窗","settings.developer.achToast":"触发成就弹窗","settings.developer.achToastHint":"调试成就达成动画,可重复触发;它本身也是一个隐藏成就(奖励只发一次)。","settings.developer.activityLabel":"活动日志","settings.developer.activityExport":"导出活动日志","settings.developer.activityEnable":"记录应用内活动","settings.developer.activityHint":"在本机记录你的操作(开会话/改笔记/建任务等),供后台 Agent Muse 理解你在做什么;仅存本地 activity 目录,保留 30 天。导出可用于排查问题。","settings.developer.activityViewCmd":"活动日志实时视图命令","settings.developer.activityViewCmdHint":"开启后命令面板(⌘K)多一条「打开活动日志」:在主区标签页实时查看活动记录(2 秒刷新,可过滤/暂停)。","command.openActivityLog":"打开活动日志","view.activityLog":"活动日志","activityView.filter":"过滤(子串匹配)…","activityView.pause":"暂停","activityView.resume":"继续","activityView.count":"{n} 行","activityView.empty":"还没有活动记录。请确认开发者选项里「记录应用内活动」处于开启,然后随便操作几下。","command.openActiveWindow":"前台窗口采样","view.activeWindow":"前台窗口采样","activeWindowView.on":"接缝已开启","activeWindowView.off":"接缝未开启","activeWindowView.offHint":"前台窗口采样默认关闭。到 设置 → 开发者选项 打开「前台窗口采样」后,这里会实时显示当前焦点所在的应用。","activeWindowView.noSample":"开着但探不到前台窗口。Linux 上 Wayland 会话拿不到(与 ActivityWatch 同样的天花板),X11 需要 xprop。","activeWindowView.noTitle":"(本平台不提供:macOS 的窗口标题属于「屏幕录制」权限)","activeWindowView.idleMark":"挂机","activeWindowView.clear":"清空","activeWindowView.segEmpty":"正在采样。切到别的应用待一会儿再回来,下面会出现折好的焦点段(挂机段会变灰)。","space.automation":"自动化","view.automationList":"自动化列表","view.automationDetail":"自动化详情","view.automationRuns":"触发记录","automation.group.system":"系统自动化","automation.group.watches":"盯任务规则","automation.group.buttons":"按钮","automation.group.schedules":"Agent 日程","automation.group.finished":"已结束 ({n})","automation.finished":"已结束","automation.finishedHint":"一次性,时刻已过——编辑可改期重开","automation.fact.status":"状态:","automation.schedule.every":"每 {ivl}","automation.schedule.once":"一次性","automation.fact.desc":"描述:","automation.sched.name":"名称","automation.sched.date":"日期","automation.sched.dateHint":"YYYY-MM-DD 或 YYYY-MM-DDTHH:mm,可带 /结束时刻","automation.sched.repeat":"重复","automation.sched.repeatHint":"留空=一次性;如 24h / 7d,从锚点滚动","automation.builder.expiredReset":"原时刻已过,已重置为下一整点——保存即改期重开。","automation.builder.atPast":"一次性时刻已过,请重新设定时间。","automation.muse.title":"Muse 巡检","automation.muse.trigger":"每 {min} 分钟巡检","automation.muse.action":"思考可为用户做什么 → 产出 TODO","automation.historian.title":"Historian 记忆维护","automation.historian.trigger":"每 {n} 轮对话后","automation.historian.action":"总结会话、维护日志与记忆","automation.watches.empty":"还没有盯任务规则——点下方新建,或在聊天里说「帮我盯着…」。","automation.enabled":"已启用(点击停用)","automation.disabled":"已停用(点击启用)","automation.new":"新建自动化","automation.cond.daily":"每天 {time}","automation.cond.event":"活动含「{match}」","automation.cond.file":"{path} 满 {n} 字","automation.cond.at":"一次 · {time}","automation.cond.every":"每 {ivl}","automation.cond.manual":"手动 · 按钮","automation.cond.dbRow":"{path} 新增行","automation.cond.dbCell":"{path} 单元格变化","automation.cond.dbWhereN":"条件 ×{n}","automation.nextRun":"下次 {time}","automation.detail.empty":"在左侧选择一个自动化","automation.detail.latest":"最近运行","automation.detail.recent":"近期活动","automation.deepConfig":"深度配置","automation.fact.trigger":"触发:","automation.fact.action":"动作:","automation.fact.actions":"动作链:","automation.fact.runner":"执行:","automation.fact.prompt":"指令:","automation.fact.cooldown":"冷却:","automation.fact.where":"条件:","automation.fact.columns":"监听列:","automation.fact.noCooldown":"无(0h)","automation.fact.disabledReason":"已被引擎自动停用:{reason}","automation.fact.lastRun":"上次运行:","automation.fact.nextRun":"下次触发:","automation.fire.btn":"试跑","automation.fire.hint":"立即执行一次动作链(不影响正常触发节奏)","automation.fire.ok":"试跑完成({status})","automation.fire.fail":"试跑失败({status})","automation.exec.manual":"试跑","automation.exec.steps":"{n} 步完成","automation.step.notify":"通知","automation.step.agent_run":"跑 Agent","automation.step.db_row_add":"表格加行","automation.step.db_row_edit":"表格改行","automation.step.tool_call":"调工具","automation.transcript.empty":"还没有运行内容","automation.transcript.trigger":"触发输入","automation.transcript.agent":"Agent","automation.transcript.tools":"工具调用 {n} 次","automation.trigger.neverFired":"还没触发过——命中后这里会出现该次运行","automation.trigger.museNote":"该规则命中会唤醒 Muse,运行内容见","automation.runs.empty":"暂无记录","automation.runs.pick":"选中一条自动化后,这里显示它的运行记录","automation.builder.title":"新建自动化","automation.builder.editTitle":"编辑自动化","automation.builder.trigger":"触发","automation.builder.desc":"名称","automation.builder.descPh":"一句话描述这个自动化","automation.builder.condType":"触发方式","automation.builder.condTimer":"定时","automation.builder.condEvent":"事件","automation.builder.condFile":"文件达标","automation.builder.condManual":"手动(按钮)","automation.builder.condDb":"多维表","automation.builder.manualHint":"不会自动触发。在笔记里插入「按钮」块并选中这条规则,由你点击执行。","automation.builder.unsupported":"这条规则含有当前构建器还不认识的动作类型。用聊天里的 manage_automation 修改(在这里保存会把那部分抹掉,所以不给编辑)。","automation.builder.dbPath":"哪张多维表(.db)","automation.builder.dbPickDb":"选择多维表…","automation.builder.dbEvent":"监听事件","automation.builder.dbEventRow":"新增行","automation.builder.dbEventCell":"单元格变化","automation.builder.dbColumn":"监听列(可多选)","automation.builder.dbColumnsHint":"勾选多列时任一列变化即触发;「新值等于」按变化的那一列比。","automation.builder.dbPickCol":"选择列…","automation.builder.dbColsLoading":"表读取中…","automation.builder.dbEquals":"且新值等于(可选)","automation.builder.dbEqualsPh":"留空 = 任意变化都触发","automation.builder.dbHint":"表内容变化后由引擎按游标比对触发;规则钉在建立时的智库,切换智库不误伤同名表。","automation.builder.dbRowId":"行 id","automation.builder.dbRowIdPh":"留空 = 触发命中的那一行","automation.builder.dbRowIdRequired":"必填(当前触发方式没有「触发行」可缺省)","automation.builder.dbCells":"写入字段","automation.builder.dbCellKey":"列名或列 id","automation.builder.dbCellVal":"值(可用 {{row.列名}} 模板)","automation.builder.dbCellAdd":"添加字段","automation.builder.dbCellsHint":"多维表触发时,值里的 {{row.列名}} 会替换成触发行对应单元格。","automation.builder.dbCellValPh":"{{= {target.数量} - {row.出库数量} }}","automation.builder.dbWhere":"附加条件(可选)","automation.builder.dbWhereAdd":"添加条件","automation.builder.dbWhereOpEq":"等于","automation.builder.dbWhereOpNe":"不等于","automation.builder.dbWhereOpEmpty":"为空","automation.builder.dbWhereOpNotEmpty":"不为空","automation.builder.dbWhereValPh":"值","automation.builder.dbWhereHint":"与上面的条件 AND;比对触发行物化后的值,公式/引用列也可比;最多 10 条。","automation.builder.dbRowFrom":"沿关联列取目标行(可选)","automation.builder.dbRowFromPh":"触发表里的关联列名或列 id;留空 = 用上面的行 id","automation.builder.dbMatch":"按列值匹配多行(可选)","automation.builder.dbMatchValPh":"值,可用 {{row.id}} 模板","automation.builder.dbTargetHint":"目标行优先级:行 id > 关联列 > 列值匹配 > 触发命中的那一行。","automation.builder.dbSkipIfEmpty":"此字段为空则跳过(可选)","automation.builder.dbSkipIfEmptyPh":"填一个上面的列名/列 id","automation.builder.cooldownDbHint":"多维表触发的纯动作链可设 0 = 不冷却(链式规则需要)","automation.builder.dbNoteView":"选中的是「笔记视图」库(行来自文件夹里的笔记)——自动化只支持经典多维表,请换一张。","automation.builder.timerMode":"定时方式","automation.builder.timerDaily":"每天","automation.builder.timerOnce":"一次","automation.builder.timerEvery":"间隔","automation.builder.time":"每天时刻","automation.builder.datetime":"触发时刻","automation.builder.onceHint":"到点执行一次后自动停用(留在列表里,改期+启用即可复用)。","automation.builder.interval":"重复间隔","automation.builder.everyHint":"从创建时刻起按间隔滚动;停机错过只补最近一次。含跑 Agent 步骤时下限 1 小时。","automation.builder.unitM":"分钟","automation.builder.unitH":"小时","automation.builder.unitD":"天","automation.builder.match":"活动日志匹配串","automation.builder.matchPh":"如 note.edit、文件名或 plugin: 事件","automation.builder.matchHint":"匹配新出现的活动日志行(子串)。可盯插件事件(plugin:插件id:事件)或 run.done agent=xx。","automation.builder.path":"文件路径(绝对路径或 ~ 开头)","automation.builder.chars":"非空白字符数","automation.builder.stepN":"步骤 {n}","automation.builder.moveUp":"上移","automation.builder.moveDown":"下移","automation.builder.notifyTitle":"通知标题","automation.builder.notifyTitlePh":"收件箱消息标题","automation.builder.notifyBody":"通知正文(可选)","automation.builder.notifyHint":"直接投递到收件箱(0 token),已接微信/TG 等通道会一并推送。","automation.builder.runner":"执行者","automation.builder.runnerPick":"选择 Agent…","automation.builder.tool":"工具","automation.builder.toolPick":"选择工具…","automation.builder.dangerous":"⚠ 高危工具:参数即保存即批准,请确认内容","automation.builder.toolCatalogEmpty":"引擎未提供动作目录(需新版引擎)","automation.builder.museFallback":"唤醒 Muse(默认)","automation.builder.museFallbackHint":"不加步骤时,命中会唤醒 Muse 把这件事整理成给你的提醒/TODO。添加步骤则改为按步骤执行。","automation.builder.prompt":"执行指令","automation.builder.promptPh":"命中后让它做什么(英文最佳)","automation.builder.cooldown":"冷却(小时)","automation.builder.cooldownHint":"两次触发的最小间隔,单位小时(纯通知/工具链下限 0.25=15 分钟)","automation.builder.cooldownAgentHint":"含跑 Agent 步骤,下限 1 小时(无人值守自激护栏)","market.title":"商店","market.subtitle":"发现社区构建的工作流、能力与界面扩展","market.navSubtitle":"社区扩展与工作流","market.group.discover":"发现","market.group.categories":"分类","market.group.manage":"管理","market.tab.discover":"商店首页","market.tab.skills":"技能","market.tab.agents":"Agent","market.tab.plugins":"插件","market.tab.spaces":"Space","market.tab.themes":"主题","market.tab.webapps":"网站应用","market.tab.installed":"已安装","market.searchPlaceholder":"搜索名称、作者或标签","market.clearSearch":"清除搜索","market.sort.label":"排序","market.sort.popular":"热门","market.sort.latest":"最近","market.sort.name":"名称","market.sectionSubtitle":"浏览{section}并管理安装状态","market.pluginsSubtitle":"浏览插件、Space 与 Agent,并管理安装状态","market.detailSubtitle":"详情、来源与安装信息","market.webOpen":"打开","market.webHint":"用户用 Coding Space 构建并上架的网页应用,在内置浏览器中打开;AI 功能消耗访客自己的账号额度。","market.tab.updates":"可更新","market.tab.submit":"投稿","market.author":"作者","market.downloads":"{n} 次下载","market.downloadsShort":"{n} 下载","market.install":"安装","market.installing":"安装中…","market.installed":"已安装","market.reinstall":"重新安装","market.desktopOnly":"仅桌面","market.desktopOnlyInstall":"仅桌面可用","market.desktopOnlyHint":"这个插件要用到电脑上才有的功能,手机上装不了","market.platform":"平台","market.uninstall":"卸载","market.uninstallConfirm":"卸载「{name}」?将删除它的安装目录。","market.uninstallWarnAgent":"⚠️ 这是一个 Agent:它落地后有自己的记忆与日志,卸载会一并删除,且无法恢复。","market.uninstallWarnSkill":"⚠️ 若你改过这份技能,你的改动会一并删除。","market.uninstalled":"已卸载「{name}」","market.uninstalledNeedsRestart":"已卸载「{name}」· 重启后端后它的工具才会真正消失","market.uninstallFail":"卸载失败:{e}","market.openSettings":"打开设置","market.update":"更新","market.updateTitle":"更新 v{from} → v{to}","market.allUpToDate":"已安装的内容都是最新版本","market.allUpToDateHint":"发现新版本时会自动出现在这里。","market.detailBack":"返回列表","market.empty":"这个分类还没有内容","market.emptyHint":"社区内容通过审核后会出现在这里。","market.noInstalled":"还没有从商店安装内容","market.noResults":"没有找到匹配内容","market.noResultsHint":"换一个名称、作者或标签试试。","market.browse":"浏览商店","market.retry":"重新加载","market.loadFailShort":"商店暂时无法加载","market.loadFail":"加载失败:{e}","market.summaryFallback":"作者暂未提供简介。","market.searchResults":"搜索结果","market.resultCount":"共 {n} 项内容","market.featured":"社区精选","market.viewDetails":"查看详情","market.recent":"最近上架","market.recentHint":"看看社区刚刚带来了什么。","market.popular":"热门内容","market.popularHint":"按真实安装量排序。","market.overview":"内容介绍","market.reviewed":"已通过上架审核","market.reviewedHint":"表示内容符合发布要求,不代表 Forsion 为第三方代码提供担保。","market.type":"类型","market.version":"版本","market.source":"安装来源","market.sourceUpload":"Forsion 托管包","market.updated":"最近更新","market.unknown":"未知","market.installOk":"已安装「{name}」","market.spaceInstalled":"已安装 Space「{name}」并加入功能栏","market.themeInstalled":"已安装「{name}」,可在 设置 → 外观 中选用","market.amadeusPluginInstalled":"Forsion 插件「{name}」已安装并加载","market.pluginInstalledOk":"插件已安装并启用","market.pluginInstalledRestartHint":"插件已安装,重启后端后才完整生效","market.pluginInstalledWaiting":"插件已安装,但还需要先安装或启用:{list}","market.amadeusPluginNeedsDeps":"Forsion 插件「{name}」已安装,但还需要先安装或启用:{list}","market.restartBackend":"重启后端","market.restartBackendHint":"只需几秒;正在运行的对话会被中断","market.backendRestarting":"正在重启后端…","market.backendRestarted":"后端已重启,改动已生效","market.backendRestartFailed":"后端没能重启,请稍后重试或重启应用","market.installFail":"安装失败:{e}","market.installFailNamed":"「{name}」安装失败:{e}","market.installHintGithub":"这个项目从 GitHub 下载,部分网络下连不上。可以开启系统代理后重试,或在「设置 → 常规 → 连接」打开「使用中国大陆镜像源」,改走国内代理线路。","market.installRetry":"重试","market.phase.resolve":"准备中…","market.phase.connect":"连接中…","market.phase.connectN":"连接中 {n}/{m}…","market.phase.percent":"下载中 {n}%","market.phase.bytes":"已下载 {size}","market.openRepo":"查看 GitHub 仓库","market.readmeEmpty":"(暂无详情)","market.submitHint":"支持 GitHub 仓库、npm 公开包和 ZIP 上传。在个人中心提交,审核通过后上架。","market.submitOpen":"前往投稿页","market.submitKicker":"开发者中心","market.submitTitle":"把你的工作流带给更多人","market.submitArtTitle":"统一审核与版本管理","market.submitArtHint":"Skills、Agents、Plugins、Spaces 与 Themes 使用同一条发布管线。","feedback.label":"遇到的问题 / 想反馈的内容","feedback.placeholder":"描述你遇到的问题或建议……提交后会自动附带本次会话日志,便于我们排查。","feedback.logAttached":"将自动附带本次会话日志({name})","feedback.noSession":"当前无会话,仅提交文字反馈","feedback.submit":"提交反馈","feedback.diagnoseViaChat":"让 Tangu 帮我诊断","feedback.diagnoseViaChatHint":"把问题描述发给当前会话的 Agent,就地帮你排查","feedback.ok":"已提交,感谢你的反馈!","feedback.okNoLog":"已提交(会话日志超过 5MB,本次未附带)","feedback.errEmpty":"请先填写反馈内容","feedback.errFail":"提交失败:{err}","feedback.errNotLoggedIn":"未登录 Forsion,无法提交","feedback.errUnavailable":"当前环境不支持提交反馈","sidebar.account.login":"登录 Forsion","sidebar.account.loginHint":"登录后可用云端记忆 / 技能 / 托管模型(不登录也能正常使用)","sidebar.account.loggingIn":"登录中…","sidebar.account.logout":"退出登录","sidebar.account.menu.weekly":"本周","sidebar.account.menu.daily":"今日","sidebar.account.menu.unlimited":"不限","sidebar.account.menu.loading":"加载中…","sidebar.account.menu.quotaFail":"额度加载失败","settings.provider.loginBusy":"在浏览器里完成登录后,本地引擎会自动重启加载该 provider,模型列表随后自动刷新(约几秒)。","sidebar.account.loginFail":"登录失败:{e}","sidebar.account.loginSub":"点击登录","sidebar.account.engineDown":"引擎未运行 · 点击重启","sidebar.account.engineStarting":"引擎启动中…","sidebar.settings":"设置 (Ctrl+,)","header.theme":"深浅模式","header.browser":"浏览器","header.browserEnabled":"浏览器工具已开启","header.browserDisabled":"浏览器工具已关闭","settings.tab.about":"关于","about.version":"版本","about.checkUpdates":"前往官网","about.update.check":"检查更新","about.update.checking":"检查中…","about.update.upToDate":"已是最新版本","about.update.available":"发现新版本 v{version}","about.update.download":"下载更新","about.update.downloading":"下载中 {percent}%","about.update.install":"重启并安装","about.update.goToDownload":"前往下载","about.update.error":"更新失败:{error}","about.update.unsupported":"开发环境不支持自动更新","about.update.unreachable":"连不上更新服务器,稍后再试","about.update.downloadInstaller":"下载安装包","about.update.from":"从 {host} 下载","about.update.fromSize":"从 {host} 下载 · {size}","about.update.fromProgress":"从 {host} 下载 · {done} / {total}","about.update.useGithub":"换 GitHub","about.update.useWebsite":"换官网","about.update.fellBackToGithub":"官网下不动,已改从 GitHub 重新下","about.update.fellBackToWebsite":"GitHub 下不动,已改从官网重新下","about.update.downloadedFrom":"已从 {host} 下完,校验通过","about.update.macOpened":"安装包在浏览器里下载。下完打开 .dmg,把 Forsion 拖进「应用程序」替换旧版","about.update.source":"下载来源","about.update.sourceAuto":"自动","about.update.sourceWebsite":"官网","about.update.sourceGithub":"GitHub","about.update.sourceHint":"有没有新版本以 forsion.net 为准,这里只管安装包从哪儿下。自动:在中国大陆从官网下,其他地区从 GitHub 下。下不动时自动换另一边重新下。","about.update.regionMainland":"这台电脑现在识别为中国大陆。","about.update.regionAbroad":"这台电脑现在识别为海外。","about.update.beta":"接收测试版更新","about.update.betaHint":"打开后会收到 x.y.z-beta.N 这类预发布版本(功能更早、也更可能有问题)。关着则完全看不到它们。正式版永远优先:测试版之后发的正式版照常推送。","app.update.bannerTitle":"发现新版本 v{version}","app.update.bannerAction":"前往更新","app.update.bannerDismiss":"忽略","about.changelogTitle":"最新更新","about.builtWith":"Forsion Desktop · 扶桑","about.builtWithMobile":"Forsion 移动端 · 扶桑","about.complianceTitle":"备案与协议","about.appFiling":"App 备案号","about.privacy":"隐私政策","about.terms":"服务条款","settings.cloud.envOnly":"Forsion 云端地址由环境变量 TANGU_CLOUD_URL 设置(此处只读)。","settings.cloud.label":"Forsion 云端地址(大脑:记忆/技能/托管模型)","settings.cloud.unset":"(未设置,用内置默认)","model.group.forsion":"Forsion 云端","picker.ungrouped":"未分组","model.group.direct":"本地","model.collapseAll":"全部折叠","model.expandAll":"全部展开","model.empty":"暂无模型","model.searchPlaceholder":"搜索模型…","settings.tab.developer":"开发者选项","settings.tab.browser":"浏览器控制","settings.tab.computerUse":"电脑操作","settings.search.strictBackground":"严格后台(绝不抢前台)","settings.search.jev":"Jev 实验加速","settings.tab.channels":"通道","channel.name.wechat":"微信","channel.name.telegram":"Telegram","channel.name.qq":"QQ","channels.intro":"把 Tangu 接进你的 IM:连接即新建一个通道会话,消息即聊即答;收件箱转发可独立开启,两者互不影响。","channels.loadingTitle":"正在加载通道","channels.loadingHint":"正在读取本机通道能力与连接状态。","channels.notAvailable":"通道功能需要内置本地后端(桌面版)。","channels.notAvailableHint":"确认本机后端已启动后重试;外部后端模式暂不提供此设置。","channels.enable":"启用","channels.status.connected":"已连接","channels.status.notConnected":"未连接","channels.status.disabled":"已停用","channels.connect":"连接","channels.scanConnect":"扫码连接","channels.disconnect":"断开连接","channels.disconnected":"已断开。","channels.connectedAs":"已连接:{label}","channels.connectedMsg":"微信已连接,已新建通道会话。","channels.connectFailed":"操作失败:{e}","channels.qrExpired":"二维码已过期,请重新扫码。","channels.scanQrHint":"用微信「扫一扫」确认登录。","qr.failed":"二维码生成失败,请重试。","qr.alt":"登录二维码","channels.newSessionHint":"连接即新建会话;之后的消息发往该会话。在 IM 里可用 /new 新建、/list /switch 切换会话,/help 查看全部命令。","channels.botToken":"Bot Token","channels.botTokenHint":"在 Telegram 找 @BotFather 创建机器人获取 token,填入后点「连接」。","channels.qqHint":"在 QQ 开放平台(q.qq.com)创建机器人获取 AppID / AppSecret。","channels.secretSaved":"已保存(输入可更换)","channels.sessionsSec":"通道会话","channels.sessions":"启用通道会话","channels.sessionsHint":"收到的消息驱动 Agent 会话并回复;关闭后仅收件箱转发在工作。","channels.approval":"远程审批","channels.approval.readonly":"询问我批准","channels.approval.autoEdit":"替我批准","channels.approval.fullAuto":"完全放行","channels.defaultAgent":"默认 Agent","channels.defaultModel":"默认模型","channels.imageModel":"画图模型","channels.ttsModel":"语音模型","channels.ttsModelPlaceholder":"空=沿用「语音朗读」设置","channels.ttsVoice":"音色","channels.followDefault":"跟随全局默认","channels.followGlobal":"跟随全局设置","channels.forwardSec":"收件箱转发","channels.forward":"转发收件箱消息到此通道","channels.forwardHint":"收件箱有新消息时推送到你的 IM(与通道会话相互独立)。","channels.forwardSenders":"允许的发件人","channels.forwardAll":"全部","channels.waitingPeer":"已连接,等待对方发来第一条消息以绑定联系人。","channels.senderSystem":"系统","channels.senderServer":"Forsion 云端","settings.tab.notes":"笔记","settings.tab.sync":"同步","settings.sync.cloudSec":"在线同步","settings.sync.remoteSec":"本地智库远程同步","settings.notes.storageTitle":"文件与附件","settings.notes.storageDescription":"集中设置附件落点与日记目录。","settings.notes.behaviorTitle":"编辑与安全","settings.notes.behaviorDescription":"控制导入、链接兼容与删除附件时的保护策略。","settings.notes.modeLabel":"附件存放方式","settings.notes.modeAttachments":"笔记同目录下的 attachments 文件夹","settings.notes.modeSame":"与笔记同目录","settings.notes.modeVault":"智库内固定文件夹","settings.notes.modeHint":"拖入笔记的文件保存到哪里。attachments 模式会在笔记所在目录自动创建 attachments 子文件夹(不存在则新建)。","settings.notes.folderLabel":"智库相对文件夹","settings.notes.folderHint":"相对智库根目录,如 assets。所有附件集中存放于此(需在智库内才能内联预览)。","settings.notes.previewLabel":"导入文件默认开启预览","settings.notes.previewHint":"开启:插入 ![[文件]] 预览块(图片内联,其它显示可点开的文件卡片)。关闭:插入 [文件名](相对路径) 链接。","settings.notes.upgradeV4Label":"打开旧笔记时升级为 v4 纯 Markdown 格式","settings.notes.upgradeV4Hint":"默认开启:v3 块标记笔记在编辑时转为纯 Markdown(无标记、标准分段)。升级仅在你真正编辑后落盘;若还有设备停留在 2.7.8 以前,可暂时关闭。","settings.notes.dailyLabel":"日记文件夹","settings.notes.dailyPlaceholder":"留空 = 智库根目录","settings.notes.dailyHint":"「打开今天的日记」创建 YYYY-MM-DD.md 的位置(智库相对路径);若存在 templates/daily.md 会自动套用为模板。","settings.notes.wikiFilesLabel":"双链补全包含附件与多维表","settings.notes.wikiFilesHint":"开启:输入 [[ 时除笔记外也补全附件、多维表(.db)、画板等文件。关闭:只补全笔记。","settings.notes.canvasDoubleClickFocusLabel":"双击聚焦画布卡片","settings.notes.canvasDoubleClickFocusHint":"双击卡片一律进入编辑并把光标落到点击处。开启:进编辑的同时还把它平滑移到画面中心并缩放到适合阅读的比例;关闭:只进编辑,视口不动。单击只选中;空格也可进编辑。","settings.notes.canvasOverviewZLabel":"画布简略标题的触发比例","settings.notes.canvasOverviewZHint":"画布缩小到这个比例或更小时,卡片正文换成标题摘要。默认 25% = 只在缩到底那一档才简略;调高则更早换成摘要。画布右下角的开关可以整个关掉简略显示。","settings.notes.deleteAssetsLabel":"删除笔记时连带删除独占附件","settings.notes.deleteAssetsAsk":"每次询问","settings.notes.deleteAssetsYes":"记住:一并删除","settings.notes.deleteAssetsNo":"记住:保留附件","settings.notes.deleteAssetsHint":"只处理「仅被这条笔记引用」的附件;被别的笔记也引用的一律保留。","settings.remote.saved":"远程设置已保存。托管后端可能会重启以应用配置。","settings.browser.title":"浏览器控制","settings.browser.agentBrowser":"Agent 浏览器","settings.browser.hint":"Tangu 会优先使用 browser_search 与 browser_* 交互工具完成网页任务;web_search 保留兼容。","settings.browser.engine":"浏览器引擎","settings.browser.engineHint":"自动模式会按可用性选择浏览器实现。","settings.browser.searchEngine":"搜索引擎","settings.browser.timeout":"超时","settings.browser.timeoutHint":"单次浏览器命令的最长等待时间(毫秒)。","settings.browser.allowPrivate":"允许浏览器工具打开私网/本机 URL","settings.browser.allowPrivateHint":"默认关闭;browser_navigate 会阻止 localhost、RFC1918 与 link-local 地址。","settings.tab.spaces":"Space","settings.spaces.hint":"管理 ribbon 顶部的 Space。内置 Space 随应用提供、不可移除;你自建或从商店安装的 Space 可卸载(删除其磁盘布局配方)。","settings.spaces.builtin":"内置","settings.spaces.user":"自建/商店","settings.spaces.uninstall":"卸载","settings.spaces.uninstalled":"已卸载「{name}」","settings.spaces.empty":"还没有任何 Space。","settings.spaces.startupTitle":"启动位置","settings.spaces.startupLabel":"打开应用时进入","settings.spaces.startupHint":"默认进入 ribbon 主位槽指着的那个 Space;也可以回到上次退出的 Space 并恢复标签页,或固定进入某一个。","settings.spaces.lastExit":"上次退出的 Space(连同标签页)","settings.spaces.homeSlotStartup":"主位槽的 Space(默认 · 当前是「{name}」)","settings.spaces.homeSlotLabel":"Ribbon 主位槽","settings.spaces.homeSlotHint":"ribbon 竖条正中那一格。默认放主页,也可以换成任何一个 Space;在那一格上右键同样能换。","settings.spaces.hintPhone":"内置 Space 随应用提供、不可移除;你自建或从市场安装的 Space 可卸载(删除其磁盘布局配方)。","settings.spaces.startupHintPhone":"选择打开应用时先进哪个 Space:默认的那个、上次退出的,或固定某一个。","settings.spaces.homeSlotStartupPhone":"默认(当前是「{name}」)","settings.spaces.libraryTitle":"已安装的 Space · {count}","settings.tab.plugins":"插件","settings.tab.amadeusPlugins":"插件","settings.amadeusPlugins.builtinTitle":"内置插件","settings.amadeusPlugins.builtinHint":"随 App 发行、默认开启的能力(浏览器/终端/日历是宿主原生视图,其余是编辑器增强)。关闭即从工作台、命令面板与编辑器中移除 —— 日历连同它的 Space 一起撤下。","settings.amadeusPlugins.externalTitle":"外置插件","settings.amadeusPlugins.changelog":"更新日志","settings.amadeusPlugins.hint":"启用/禁用即时生效,点击插件可查看详情。插件目录:~/.forsion/plugins/(商店安装位置)。插件可捆绑引擎插件/Agent/技能/Space(捆绑包),随本插件一并识别、启停与卸载。","settings.amadeusPlugins.openFolder":"打开插件文件夹","settings.amadeusPlugins.reload":"重新加载","settings.amadeusPlugins.scaffold":"创建示例插件","settings.amadeusPlugins.builtin":"内置","settings.amadeusPlugins.external":"外部","settings.amadeusPlugins.agentOwned":"{agent} 自建 Space","settings.amadeusPlugins.blockedInvalid":"插件清单无效:{reason}","settings.amadeusPlugins.uninstall":"卸载","settings.amadeusPlugins.uninstallConfirm":"确定卸载插件「{name}」?其文件夹将被整体删除;内嵌的引擎插件/Space 一并移除(已播种的 Agent 会保留,可在 Agents 页手动删)。","settings.amadeusPlugins.uninstalled":"已卸载「{name}」","settings.amadeusPlugins.uninstalledRestartPending":"「{name}」文件已删除,但引擎重启未完成——内嵌工具可能仍在运行,请手动重启后端","settings.amadeusPlugins.bundleEngine":"引擎插件 ×{n}","settings.amadeusPlugins.bundleAgents":"Agent ×{n}","settings.amadeusPlugins.bundleSkills":"技能 ×{n}","settings.amadeusPlugins.bundleSpaces":"Space ×{n}","settings.amadeusPlugins.bundleTitle":"捆绑内容","settings.amadeusPlugins.bundleEngineList":"引擎插件:{list}","settings.amadeusPlugins.bundleAgentsList":"Agent:{list}","settings.amadeusPlugins.bundleSkillsList":"技能:{list}","settings.amadeusPlugins.bundleSpacesList":"Space:{list}","settings.amadeusPlugins.bundleHint":"内嵌引擎插件与 Space 随本插件启停/卸载;Agent 首次发现时播种进引擎,之后独立存在(升级不覆盖、卸载保留)。","settings.amadeusPlugins.blockedApi":"需要插件 API v{v},与当前应用不兼容","settings.amadeusPlugins.blockedMinApp":"需要应用版本 ≥ {v}","settings.amadeusPlugins.empty":"还没有任何插件。","settings.amadeusPlugins.back":"返回列表","settings.amadeusPlugins.dep":"依赖应用","settings.amadeusPlugins.depConnected":"已连接 {v}","settings.amadeusPlugins.depMissing":"未检测到,需要安装并运行","settings.amadeusPlugins.depCheck":"检测连接","settings.amadeusPlugins.depInstall":"一键安装","settings.amadeusPlugins.depInstalling":"安装中…","settings.amadeusPlugins.depFail":"安装未完成,可打开官网手动安装","settings.amadeusPlugins.depHomepage":"打开官网","settings.amadeusPlugins.commands":"命令","settings.amadeusPlugins.settings":"设置","plugin.onboarding.title":"插件引导 — {name}","plugin.onboarding.stepsTitle":"就绪步骤","plugin.onboarding.settingsTitle":"必要设置","plugin.onboarding.recommendsTitle":"配套推荐","plugin.onboarding.install":"安装","plugin.onboarding.installed":"已装","plugin.onboarding.installing":"安装中…","plugin.onboarding.notFound":"未在商店上架","plugin.onboarding.later":"稍后","plugin.onboarding.done":"完成","plugin.onboarding.laterHint":"跳过后随时可回 设置 → Forsion 插件,点该插件的「运行引导」继续;前置条件全部满足后「待引导」标记会自己消失。","plugin.onboarding.requiresTitle":"开始前需要","plugin.onboarding.req.ok":"已就绪","plugin.onboarding.req.unmet":"未完成","plugin.onboarding.req.unknown":"暂时无法检查","plugin.onboarding.req.timeout":"检查超时,稍后再试一次。","plugin.onboarding.req.inactive":"启用插件后才能检查这一项。","plugin.onboarding.recheck":"重新检查","plugin.onboarding.checking":"检查中…","plugin.onboarding.allReady":"全部就绪,可以开始用了。","plugin.onboarding.someUnknown":"没有发现未完成的项;另有 {n} 项此刻无法检查。","plugin.onboarding.guideTitle":"使用说明","plugin.onboarding.badge":"待引导","plugin.onboarding.run":"运行引导","plugin.onboarding.nudgeTitle":"「{name}」插件还差几步就绪","plugin.onboarding.nudgeBody":"「{name}」还有前置条件没满足。打开 设置 → Forsion 插件 → {name},点「运行引导」查看缺哪一项。","settings.plugins.npmInstallTitle":"从 npm 安装引擎插件","settings.plugins.npmInstallHint":"输入包名(如 npm:@forsion/tangu-computer-use)。插件以你的完整系统权限运行,只安装信任的来源。","settings.plugins.npmInstallConfirm":"即将从 npm 安装「{spec}」。插件以你的完整系统权限运行,装前请确认来源可信。继续?","settings.plugins.preferMirror":"国内镜像优先","settings.plugins.installBtn":"安装","settings.plugins.installing":"安装中…","settings.plugins.installed":"已安装 {id}@{version}","settings.plugins.empty":"暂无插件","settings.plugins.secForsion":"Forsion 插件","settings.plugins.secEngine":"Tangu 引擎插件","settings.plugins.bundleOwnedHint":"另有 {n} 个引擎插件由上方 Forsion 插件捆绑提供,在对应插件卡片中随插件统一启停。","settings.plugins.selectHint":"选择左侧插件查看其设置","settings.plugins.builtin":"内置","settings.plugins.folder":"文件夹","settings.plugins.needsRestart":"需重启","settings.plugins.needsRestartHint":"新版本已在磁盘上,但它的入口引用了相对路径模块,需重启后端才会运行新版","settings.plugins.waitingDeps":"等待前置插件","settings.plugins.loadFailed":"加载失败","settings.plugins.settling":"正在收尾","settings.plugins.settlingHint":"上一次启动或停用还没结束,结束后会按开关自动生效","settings.plugins.needsDepsToEnable":"需要先安装并启用:{list}","settings.plugins.disableDependents":"停用「{name}」后,依赖它的插件也会暂停:{list}。重新启用后它们会自动恢复。继续吗?","settings.plugins.uninstallDependents":"以下插件依赖「{name}」,卸载后将无法运行:{list}。","settings.plugins.openFolder":"打开插件文件夹","settings.plugins.rescan":"重载插件","settings.plugins.rescanning":"重扫中…","settings.plugins.rescanAdded":"重扫完成:{n} 个插件有变化(新装、更新或移除)","settings.plugins.rescanNone":"重扫完成:没有变化","settings.plugins.rescanHint":"新装入、更新或移除的插件即时生效;入口引用相对路径模块的插件更新后仍需重启后端","settings.plugins.uninstall":"卸载","settings.plugins.uninstallConfirm":"卸载「{name}」?将删除插件文件与全部设置。","settings.plugins.uninstalled":"已卸载「{name}」","settings.plugins.scope":"作用域","settings.plugins.scopeGlobal":"全局","settings.plugins.scopeAgent":"按 Agent","settings.plugins.selectAgent":"选择 Agent","settings.plugins.noSettings":"该插件无可配置项","settings.plugins.saved":"已保存","settings.plugins.import":"导入图片","settings.plugins.deleteConfirm":"删除「{name}」?","settings.plugins.onlyImage":"只能导入图片(png/jpg/gif/webp)","about.versionClickHint":"再点 {n} 次开启开发者模式","about.devUnlocked":"开发者模式已开启","settings.developer.note":"以下选项面向高级用户/调试,一般无需修改。","settings.developer.cloudUrlLabel":"Forsion 云端地址","settings.developer.cloudUrlHint":"大脑服务(记忆/技能/托管模型)的地址。留空则用环境变量 TANGU_CLOUD_URL 或内置默认。托管模式下保存会重启后端使其生效。","settings.developer.cloudUrlPlaceholder":"https://api.forsion.net","settings.developer.saveCloudUrl":"保存","settings.developer.savedRestarting":"已保存,正在重启后端…","settings.developer.saved":"已保存","settings.developer.relaunchLabel":"引导界面","settings.developer.relaunchHint":"重新进入首次安装的引导流程(主题 / 连接 / 模型 / 项目目录)。","settings.developer.relaunch":"重新进入引导","settings.developer.disable":"关闭开发者模式","settings.developer.showSystemPrompt":"回复前显示 system prompt","settings.developer.showSystemPromptHint":"开启后,每条 AI 回复前会显示本条消息发送给模型的完整 system prompt(可展开检查内容与结构);仅本机调试,关闭开发者模式时自动一并关闭。","settings.developer.activeWindow":"前台窗口采样(接缝)","settings.developer.activeWindowHint":"开启后,声明了 activeWindow 能力的插件可以读到「现在焦点在哪个应用」——用来替掉 ActivityWatch 这类外部依赖。数据只留本机。命令面板(⌘K)会多一条「前台窗口采样」调试面板。默认关闭,关闭开发者模式时自动一并关闭。","settings.developer.mobileUiPreview":"移动端 UI 预览命令","settings.developer.mobileUiPreviewHint":"开启后命令面板(⌘K)多一条「切换到移动端 UI」,运行时把桌面壳换成单列移动壳预览(会刷新页面);web 端同样可用。仅本机调试,关闭开发者模式时自动一并关闭。","command.switchToMobileUi":"切换到移动端 UI","command.switchToDesktopUi":"切换回桌面 UI","command.zoomIn":"放大页面","command.zoomOut":"缩小页面","command.zoomReset":"重置页面缩放","onboarding.brand.caption":"AI 工作台","onboarding.progress.label":"设置进度","onboarding.phase.connect":"连接账号","onboarding.phase.appearance":"选择外观","onboarding.phase.capabilities":"配置能力","onboarding.phase.workspace":"准备项目目录","onboarding.welcome.kicker":"首次设置","onboarding.welcome.subtitle":"把模型、Agent、知识和本地工具放进同一个应用。","onboarding.welcome.railLabel":"从这里开始","onboarding.welcome.railTitle":"让 Forsion 适合你的工作方式。","onboarding.welcome.railBody":"几分钟内完成基础设置。每一项之后都可以在设置中修改。","onboarding.welcome.promiseModels":"连接 Forsion 或你自己的模型","onboarding.welcome.promiseAgents":"准备可随时切换的 Agent","onboarding.welcome.promiseLocal":"保留本地文件与执行控制权","onboarding.step.connect.title":"连接模型与账号","onboarding.step.connect.description":"登录 Forsion、使用订阅额度,或接入自己的 OpenAI 兼容服务。","onboarding.step.theme.title":"选择界面外观","onboarding.step.theme.description":"设计语言决定结构,主题色决定强调色,背景色决定底色,三者可以自由组合。","onboarding.step.model.title":"选择默认模型","onboarding.step.model.description":"先选一个日常模型,之后可以在每次对话中随时切换。","onboarding.step.speech.title":"配置语音输入","onboarding.step.speech.description":"选择语音识别模型,也可以保持默认并稍后配置。","onboarding.step.agents.title":"认识你的 Agent","onboarding.step.agents.description":"查看现有名册,按需创建一个有专属人格和记忆的助手。","onboarding.step.workspace.title":"选择工作目录","onboarding.step.workspace.description":"为本地会话指定默认目录,Forsion 只在你授权的范围内工作。","onboarding.step.env.title":"检查本机环境","onboarding.step.env.description":"确认编码任务所需工具,并按当前网络环境选择下载源。","onboarding.step.done.title":"一切准备就绪","onboarding.step.done.description":"基础配置已经完成,现在可以进入 Forsion 开始工作。","onboarding.done.cloudLine1":"· 输入栏可随时切换模型与思考档位;笔记、日历与自动化都在 Forsion 里","onboarding.done.cloudLine2":"· 设置 → 外观可随时改主题与语言;桌面版还能连接本机文件与工具","onboarding.connect.modeLabel":"连接方式","onboarding.model.choiceLabel":"默认对话模型","onboarding.speech.choiceLabel":"语音输入","onboarding.workspace.choiceLabel":"默认工作目录","onboarding.connect.forsionHint":"用 Forsion 账号登录(云端地址由环境变量配置,无需填写);也可在上方切换为自带 API Key。","onboarding.connect.skipForNow":"暂时跳过","onboarding.theme.stepLabel":"选择主题外观","onboarding.theme.modeLabel":"明暗模式","onboarding.theme.light":"浅色","onboarding.theme.dark":"深色","onboarding.theme.hint":"随时可在 设置 → 外观 中更改。","onboarding.theme.customSeedLabel":"自定义主题色","settings.theme.system":"跟随系统","settings.theme.modeLocked":"该主题固定跟随系统明暗","settings.theme.modeLockedHint":"Glass 等主题的明暗由系统决定,不可手动切换。","settings.theme.zoomLabel":"界面大小","settings.theme.zoomHint":"缩放整个界面,当前 {percent}%。也可用 ⌘/Ctrl + +/− 按 10% 微调。","settings.theme.zoomPresetLabel":"界面大小预设","settings.theme.zoomSmall":"小","settings.theme.zoomStandard":"标准","settings.theme.zoomLarge":"大","settings.theme.smoothCaret":"丝滑光标","settings.theme.smoothCaretHint":"编辑器与聊天输入框的文字光标平滑滑动到新位置(Word 手感)。默认关闭,需要时手动打开。","settings.promptSuggest":"输入建议","settings.promptSuggestHint":"一轮结束后,在空输入框里用灰字猜你的下一句,按 Tab 填进输入框。每轮会多请求一次模型(复用缓存,开销很小)。默认开启。","settings.promptSuggestEnable":"启用输入建议","settings.theme.chatAvatars":"聊天头像","settings.theme.chatAvatarsHint":"在对话里显示 Agent 与你的头像。关掉后消息更素净,Agent 名字仍保留。","settings.theme.calmDim":"外围淡出","settings.theme.calmDimHint":"Ribbon、未选中的标签、左侧栏和对话右侧的卡片平时淡一些,指针移过去或键盘焦点进来就恢复。","settings.theme.calmReading":"宽松正文","settings.theme.calmReadingHint":"笔记和对话正文的行距、段距放宽,笔记每行短一些。界面字号和控件大小不变。","settings.theme.calmMotion":"舒缓过渡","settings.theme.calmMotionHint":"切换视图、外围恢复时慢一点。","settings.theme.ribbonAutoHome":"Ribbon 滚动后自动归位","settings.theme.ribbonAutoHomeHint":"用滚轮翻过 Ribbon 以后,点别处或点开一个图标,稍后自动滑回原位。关掉后停在翻到的位置。","settings.theme.ribbonRecent":"Ribbon 中间显示最近使用的 Space","settings.theme.ribbonRecentHint":"在 Ribbon 中间的空当里列出最近用过的几个 Space,最近的在上。位置不够时自动少显示,直到一个不显示。","settings.theme.ribbonRecentOff":"不显示","settings.theme.fontUi":"界面字体","settings.theme.fontBody":"正文字体","settings.theme.fontMono":"等宽字体","settings.theme.fontFollow":"跟随主题","settings.theme.fontSystem":"系统默认","settings.theme.fontHint":"预设字体随应用内置,不依赖本机是否装过,每台设备观感一致。选「跟随主题」则用当前主题自带的字体栈。","settings.theme.fontPreset.inter":"Inter(现代无衬线)","settings.theme.fontPreset.notoSans":"思源黑体 Noto Sans","settings.theme.fontPreset.wenkai":"霞鹜文楷(阅读)","settings.theme.fontPreset.jetbrains":"JetBrains Mono","settings.theme.fontPreset.system":"系统默认","settings.theme.fontGroupBuiltin":"内置","settings.theme.fontGroupPlugin":"插件提供","settings.theme.customSeedLabel":"自定义主题色","settings.theme.signalLabel":"强调色","settings.theme.signalFollow":"跟随主题色","settings.theme.signalBlue":"柔蓝","settings.theme.customSignalLabel":"自定义强调色","settings.theme.signalHint":"拖拽落点、云同步、勾选、开关、选中框和双链用这支色。跟随主题色时:经典、墨色配柔蓝,其余配色就用主题色本身。","settings.theme.customBgLabel":"自定义背景色","settings.theme.customBgFollow":"跟随主题色","settings.theme.customBgClear":"恢复跟随","settings.theme.customBgHint":"不设置时背景由主题色微染;设置后将所选色作为独立氛围种子,并自动调至当前明暗模式的可读范围。","settings.theme.langLabel":"设计语言","settings.theme.visuals":"Intelligent UI","settings.theme.visualsOpt.auto":"自动","settings.theme.visualsOpt.less":"少一点","settings.theme.visualsOpt.off":"关闭","settings.theme.visuals.auto":"按问题组织图文、来源与交互控件,简单问题保持文字回答。","settings.theme.visuals.less":"只在你明确要求图片、图表或交互界面时使用;下一轮生效。","settings.theme.visuals.off":"只用文字回答,不再画卡片;下一次对话起生效。","settings.theme.openFolder":"打开主题文件夹","settings.theme.reload":"重载主题","settings.theme.dropHint":"把 theme.json + theme.css 放进 ~/.forsion/themes/<id>/ 即可装第三方主题,放好后点「重载主题」。","settings.theme.options":"{name} 选项","settings.theme.optionsReset":"重置","settings.theme.skinLabel":"配色","settings.theme.accentLabel":"主题色","settings.theme.bgLabel":"背景色","settings.theme.skin.cream":"经典","settings.theme.skin.coral":"陶土","settings.theme.skin.teal":"柔青","settings.theme.skin.lavender":"暮紫","settings.theme.skin.zhi":"雾蓝","settings.theme.skin.sage":"苔绿","settings.theme.skin.ink":"墨色","settings.theme.skin.custom":"自定义","settings.group.appearance":"外观","settings.group.account":"账户","settings.group.model":"模型","settings.group.agents":"Agent","settings.group.extensions":"扩展","settings.group.appearanceAbout":"外观·关于","settings.group.plugins":"插件","settings.group.advanced":"高级","settings.group.options":"选项","settings.group.workspace":"工作区","settings.group.ai":"AI","settings.group.system":"系统","settings.group.tools":"工具","settings.group.corePlugins":"核心插件","settings.group.communityPlugins":"社区插件","settings.tab.general":"常规","settings.page.generalDescription":"管理工作目录、运行环境与 Forsion 连接状态。","settings.page.spacesDescription":"选择启动位置,查看或移除已安装的 Space。","settings.page.notesDescription":"统一管理附件位置、笔记行为与删除安全选项。","settings.page.syncDescription":"把本地智库同步到远程存储(Dropbox、S3、WebDAV 等)。","settings.page.themeDescription":"预览并组合设计语言、配色、明暗、界面大小与字体。","settings.page.shortcutsDescription":"搜索命令并录制、解绑或恢复快捷键。","settings.page.notificationsDescription":"控制通知出口,以及每类事件与插件是否提醒。","settings.page.statusbarDescription":"选择底部状态项,并拖动调整显示顺序。","settings.page.modelDescription":"选择默认模型,管理提供商、联网搜索与语音能力。","settings.page.agentsDescription":"管理 Agent 名册、后台 Agent 与本机 Agent CLI。","settings.page.skillsDescription":"浏览技能库,导入其他工具中的技能与 MCP 配置。","settings.page.mcpDescription":"连接、启停并维护外部 MCP 工具服务器。","settings.page.hooksDescription":"管理 Agent 运行前后的自动化钩子。","settings.page.channelsDescription":"连接消息通道并集中查看其运行状态。","settings.page.browserDescription":"选择浏览器与搜索引擎,并调整访问安全边界。","settings.page.computerUseDescription":"Agent 看着屏幕点按、输入来操作桌面应用。这里设置它能不能抢前台、Jev 加速和浏览器工具。","settings.page.pluginsDescription":"管理核心能力与已安装插件,查看设置和更新。","settings.page.pluginDescription":"调整该插件提供的功能与运行选项。","settings.page.advancedDescription":"管理本机服务、界面行为、日志与数据安全。","settings.page.developerDescription":"用于调试界面、活动日志与内部功能的开发选项。","settings.page.aboutDescription":"查看版本、更新通道、语言与完整更新日志。","settings.overview.label":"当前状态","settings.overview.mode":"运行模式","settings.overview.backend":"后端服务","settings.overview.account":"Forsion 账号","settings.overview.signedIn":"已登录","settings.overview.signedOut":"未登录","settings.overview.readyTitle":"工作环境运行正常","settings.overview.readyDescription":"后端已连接,可以继续调整工作目录和本机运行选项。","settings.overview.attentionTitle":"工作环境尚未就绪","settings.overview.attentionDescription":"检查后端连接与运行方式,保存后会在这里显示最新状态。","settings.backend.modeDescription":"选择由 Forsion 管理本机服务,或连接你已经部署的后端。","settings.backend.modeManagedDescription":"开箱即用,由桌面端负责启动、检查和重启。","settings.backend.modeExternalDescription":"适合局域网、容器或远程部署的现有服务。","settings.workspace.summary":"新建本地会话时默认使用的位置。","settings.runtime.title":"本机运行环境","settings.runtime.description":"配置代码沙箱、Python 和下载网络,修改后重启后端生效。","settings.runtime.details":"了解 Python 与网络镜像的影响","settings.external.title":"外部后端连接","settings.external.description":"填写服务地址和访问凭证,先测试连接再保存。","settings.theme.previewLabel":"实时外观预览","settings.theme.previewChat":"对话","settings.theme.previewWorkspace":"Forsion","settings.theme.previewTitle":"让想法保持连贯","settings.theme.previewMessage":"当前的设计语言、配色、字体和质感会实时应用到这块预览。","settings.theme.previewInput":"问问 Forsion,或输入 / 使用能力","settings.theme.langDescription":"选择界面的结构、圆角、排版和整体气质。","settings.theme.skinDescription":"主题色与背景色分开选,布局不变;两边选同一个 = 原来的整套配色。","settings.theme.behaviorTitle":"显示与动效","settings.theme.behaviorDescription":"调整明暗、界面大小、层次质感和输入时的反馈。","settings.theme.flatLabel":"阴影","settings.theme.flatOff":"立体","settings.theme.flatOn":"扁平","settings.theme.flatDescription":"立体使用淡阴影,扁平隐藏装饰阴影。","settings.theme.glassDescription":"为支持的表面加入半透明模糊效果。","settings.theme.ambient":"外壳随内容取色","settings.theme.ambientHint":"Genesis 的外围磨砂玻璃跟随当前可见内容的颜色,需要开着毛玻璃。滚动和切换页面时会多占一些性能。","settings.theme.homeMotion":"主页壁纸动效","settings.theme.homeMotionHint":"星轨的行星公转、日行的日月光晕、字阵的涟漪;系统打开「减弱动态效果」时不动。和主页壁纸面板里的开关是同一个","settings.theme.typographyTitle":"字体","settings.sub.connection":"连接","settings.sub.models":"模型","settings.sub.providers":"自定义提供方","settings.sub.webSearch":"联网搜索","settings.sub.voice":"语音","settings.sub.specialAgents":"后台 Agent","settings.sub.mcpServer":"对外 MCP","settings.sub.uiSession":"界面与会话","settings.sub.data":"数据","settings.sub.skillLibrary":"技能库","settings.group.about":"关于","settings.plugins.openSettings":"设置","onboarding.agents.stepLabel":"Agent","onboarding.agents.intro":"Agent 是有自己名字、人格与专属记忆的对话角色——默认 Agent 已就绪,你也可以养一群:工作助手、翻译、陪聊各司其职,聊天时随时切换。之后可在主界面的 Agents 完整管理(头像/模型/工具等)。","onboarding.agents.rosterLabel":"当前名册","onboarding.agents.rosterEmpty":"名册为空(默认 Agent 将在首次对话时就绪)。","onboarding.agents.systemBadge":"后台","onboarding.agents.createLabel":"快速新建(可选)","onboarding.agents.namePlaceholder":"名字,如 秦车","onboarding.agents.personaPlaceholder":"一句话人格与口吻,如 严谨的中文技术编辑,惜字如金","onboarding.agents.createBtn":"创建","onboarding.agents.createHint":"只需名字即可创建;人格描述会成为它的初始设定,之后随时可改。","onboarding.agents.created":"已创建「{name}」,聊天时可在输入框上方切换。","onboarding.agents.createFail":"创建失败:{e}","onboarding.agents.historianTitle":"后台 Agent:Historian(史官)","onboarding.agents.historianDesc":"开启后每隔几轮自动为会话起标题、整理日志与长期记忆——独立模式全自动托管;辅助模式则作为档案助手进入后台子讨论,与你的 Agent 商量后再写。","onboarding.agents.historianSaveFail":"Historian 设置保存失败:{e}","onboarding.agents.moreHint":"触发轮次、提示词与另一位后台 Agent Muse,在 设置 → 后台 Agent 里配置。","onboarding.workspace.stepLabel":"选择默认本地文件夹","onboarding.workspace.hint":"Agent 新建本机会话时的默认工作目录;留空则用智库内的 Sessions 文件夹(无智库时 ~/Forsion)。","onboarding.workspace.placeholder":"~/Forsion(默认)","onboarding.workspace.pick":"浏览文件夹","onboarding.workspace.clear":"清除","settings.advanced.agentDesk":"Agent Desk 演出面板","settings.advanced.agentDeskHint":"聊天右侧的 Agent 演出区,默认开启。Agent 编辑文件时自动在旁边展示正在改的文件;Agent 也可主动把文件、笔记、导图摆上面板给你看,并截图核对自己做的效果。可拖宽度,可收成卡片。","settings.advanced.agentDeskEnable":"启用 Agent Desk","settings.advanced.summaryOpenIn":"任务概览里点文件时","settings.advanced.summaryOpenInHint":"右侧「任务概览」卡片里的来源/产物,点一下开在哪。","settings.advanced.summaryOpenIn.tab":"在新标签页打开","settings.advanced.summaryOpenIn.desk":"在 Agent Desk 展开","desk.close":"关闭面板","sketch.mobileUnavailable":"此卡片在移动端 App 暂不可用(请在桌面或网页端查看)。","sketch.expand":"展开卡片","sketch.collapse":"收起卡片","settings.advanced.exportLogs":"导出会话日志","settings.advanced.exportLogsHint":"将当前会话的全部对话内容、界面实际状态与动作轨迹、渲染端错误、后端运行日志打包成一个 JSON 文件,便于开发者排查问题。","settings.advanced.exportBtn":"导出为 JSON","settings.advanced.exportNoSession":"当前没有打开的会话,请先选择一个会话再导出。","settings.advanced.exportOk":"已导出到 {path}","settings.advanced.exportCanceled":"已取消导出","settings.advanced.exportFailed":"导出失败:{err}","settings.clearData.label":"清空数据 / 卸载","settings.clearData.hint":"删除本机上的 Forsion 数据。此操作不可恢复,完成后应用会重启为全新状态。","settings.clearData.tangu":"Tangu 数据与项目目录(账号、设置、Agent、会话、~/Forsion)","settings.clearData.desktop":"桌面设置(窗口与 Amadeus 壳层配置)","settings.clearData.btn":"清空并重启","settings.clearData.confirm":"确定要清空所选数据吗?此操作不可恢复,应用将重启。","settings.clearData.macNote":"这只清除数据;要彻底卸载 Forsion,请把「应用程序」里的 Forsion 拖入废纸篓。","view.changelog":"更新","changelog.newVersion":"发现新版本 {version}","changelog.newest":"最新","changelog.zhOnly":"这一版的更新说明只有中文。","settings.developer.testUpdateLabel":"更新弹窗测试","settings.developer.testUpdate":"打开更新弹窗(测试)","settings.developer.testUpdateHint":"强制弹出 What's new 弹窗,用于验证版本更新弹窗渲染是否生效(不依赖真的有新版本)。","ctx.windowSource.override":"窗口值:手动覆盖表","ctx.windowSource.model":"窗口值:模型自报","ctx.windowSource.family":"窗口值:按模型族推断(非模型自报)","ctx.windowSource.learned":"窗口值:从上游超长报错回学到的真实上限","ctx.windowSource.default":"窗口值:272k 默认兜底(未知模型,可在设置 → 模型里手填)","ctx.windowCapped":"模型最大 {max},默认只用到 {n}","approval.why.customAsk":"按你的审批规则「{rule}」,这一步必须问你","approval.why.escalate":"要写工作区以外的文件 —— 这一档下每次都要你确认(「总允许」对它无效)","approval.why.protected":"要改凭据或 Forsion 本机配置 —— 每次都要你确认(完全通行和「总允许」都不跳过)","approval.why.always":"这个操作每次都要你本人确认(完全通行和「总允许」都不跳过)","approval.why.mode":"当前审批档「{mode}」下,这类操作需要你批准","approval.why.control":"这会设置或修改之后可在你不在场时运行的工作,需要你逐次确认(「总允许」对它无效)","inbox.approval.withdrawnSystem":"系统已撤回这条请求(它存下的内容无法完整显示,或已被同一动作的新请求取代),不能在这里批准。需要的话让 Agent 重新发起。","approval.previewScrollHint":"内容较长,请滚动看完再批准。","pill.thinkUnsupported":"(本模型不支持,自动换到相近档位)","input.compact":"压缩上下文","input.slash.voiceOn":"切到语音消息(该 Agent 回复变语音)","input.slash.voiceOff":"切回文字消息","input.slash.stop":"停止当前运行","input.slash.agent":"选用 Normal Agent(自定义人格)","input.engineDefault":"Tangu","input.engineChipTitle":"运行引擎","input.engineSection":"运行引擎","engine.pickTitle":"选择运行此对话的 Agent","engine.warming":"正在启动 {name}…","pill.more":"更多(翻页)","header.currentAgent":"当前 Agent","settings.tab.agentClis":"本机 Agent CLI","settings.agentClis.title":"外部 Agent CLI","settings.agentClis.hint":"检测到的第三方 Agent(Claude Code / Codex 等);可设默认模型。新会话开始时才能选用它们。","settings.agentClis.detected":"已检测到","settings.agentClis.needsSignin":"需登录","settings.agentClis.notDetected":"未检测到","settings.agentClis.notDetectedHint":"安装并登录该 Agent 后自动出现。","settings.agentClis.defaultModel":"默认模型","settings.agentClis.modelDefault":"(用引擎默认)","settings.agentClis.loadingModels":"加载模型…","settings.agentClis.empty":"无外部 Agent 引擎(仅本机形态可用)。","settings.agentClis.importHint":"导入后复制成 Tangu 自有技能/MCP(卸载该 CLI 也不丢);MCP 默认不启用,到 MCP 设置里开启。","settings.agentClis.skillsLabel":"已装技能","settings.agentClis.mcpLabel":"已装 MCP","settings.agentClis.importBtn":"导入","settings.agentClis.imported":"已导入","settings.tab.agents":"Agent","settings.agents.title":"Normal Agent(自定义人格)","settings.agents.hint":"为不同任务定义可复用的对话人格(system prompt + 模型 + 设置)。也可让 Agent 用 manage_agent 工具自创建。","settings.agents.new":"新建 Agent","settings.agents.createViaChat":"让 AI 帮我配置","settings.agents.createViaChatHint":"开一个新会话,用对话的方式让 Agent 帮你把新 Agent 建出来","settings.agents.empty":"暂无 Agent,点「新建 Agent」创建一个。","settings.agents.name":"名称","settings.agents.namePlaceholder":"如:代码审查员","settings.agents.desc":"简介","settings.agents.model":"模型(留空=用会话模型)","settings.agents.modelDefault":"(用会话模型)","settings.agents.systemPrompt":"开发指令(做什么 / 怎么做 / 必读什么)","settings.agents.systemPromptPlaceholder":"你是一位严谨的代码审查员……","settings.agents.thinking":"思考档位","settings.agents.maxIter":"最大循环轮数","settings.agents.approval":"审批档","settings.agents.inherit":"(继承)","settings.agents.byAgent":"Agent 创建","agent.badge.system":"后台","settings.agents.deleteConfirm":"删除 Agent「{name}」?","settings.agents.saveFail":"保存失败:{e}","settings.agents.cloudOnly":"Normal Agent 仅在本地(桌面/TUI)可用。","settings.agents.soul":"人格设定(SOUL)","settings.agents.soulPlaceholder":'沉静、专注;说话简洁,默认中文……(语气与价值观,区别于"做什么"的开发指令)',"settings.agents.shareMemory":"共用默认 Agent 的记忆和日志","settings.agents.shareMemoryHint":"开启后该 Agent 读写默认 Agent 的记忆/日志;默认关闭=有专属自己的记忆/日志。","settings.agents.cloudSync":"云同步(跨设备镜像)","settings.agents.cloudSyncHint":"开启后该 Agent 的全部文件(定义/记忆/日志/Library)在你的设备间完全镜像,新内容覆盖旧的;默认关闭=纯本地。","settings.agents.cloudSyncOn":"云同步:已开启","settings.agents.cloudSyncOff":"云同步:已关闭","settings.agents.activityAccess":"允许读取活动日志","settings.agents.activityAccessHint":"授权该 Agent 使用 read_activity 查看你的应用内操作记录;默认关闭=仅 Muse 可读。","settings.agents.toolPolicy":"工具黑白名单","settings.agents.toolPolicyNone":"不限制(全部可用)","settings.agents.toolPolicyDeny":"黑名单:取消勾选=禁用,引擎新增工具默认可用","settings.agents.toolPolicyAllow":"白名单:仅勾选的可用,引擎新增工具默认禁用","settings.agents.toolPolicyHint":"勾选=允许使用。仅约束下列常规工具;带权限门禁的工具(如 read_activity)不受名单影响。","settings.agents.toolPolicyEmpty":"工具目录不可用(需本地引擎在运行)。","settings.agents.avatar":"头像","settings.agents.avatarHint":"点击上传,≤1MB(PNG/JPG/GIF/WebP);存入该 Agent 的 Library。","settings.agents.avatarPick":"上传头像","settings.agents.avatarRemove":"删除头像","settings.agents.avatarTooLarge":"图片超过 1MB,请换更小的。","settings.agents.avatarSaveFirst":"请先保存 Agent,再设置头像。","settings.tab.shortcuts":"快捷键","settings.shortcuts.desc":"点击某条右侧的快捷键开始录制,按下组合键即设定;Esc 取消,⌫ 解绑。要占用别的命令的组合键时会先问你。","settings.shortcuts.commands":"命令与快捷键 · {count}","settings.shortcuts.searchPlaceholder":"搜索命令或快捷键","settings.shortcuts.resultCount":"显示 {count} 项","settings.shortcuts.noResults":"没有匹配的命令。","settings.shortcuts.commandPalette":"命令面板","settings.shortcuts.record":"点击录制快捷键","settings.shortcuts.recording":"按下组合键…","settings.shortcuts.reset":"恢复默认","settings.shortcuts.clear":"解绑","settings.shortcuts.unbound":"未设置","settings.shortcuts.resetAll":"全部恢复默认","settings.shortcuts.keyMode":"按键","settings.shortcuts.keyModeTitle":"按下组合键,看它现在在哪里被用着","settings.shortcuts.keyResult":"{key} · {count} 处在用","settings.shortcuts.groupCommands":"Forsion 命令","settings.shortcuts.groupElsewhere":"其他地方","settings.shortcuts.noCommandUses":"没有命令使用 {key}","settings.shortcuts.layerEditor":"笔记编辑器 · 光标在正文里时","settings.shortcuts.layerSystem":"系统保留","settings.shortcuts.editorHint":"把 {key} 绑给某个命令可以,但光标在笔记正文里时它仍是「{action}」,命令收不到。","settings.shortcuts.editorShadowSaved":"已设置。光标在笔记正文里时 {key} 仍是「{action}」。","settings.shortcuts.conflictCount":"{count} 处冲突","settings.shortcuts.conflictWith":"与「{name}」冲突","settings.shortcuts.conflictWithMany":"与 {count} 个命令冲突","settings.shortcuts.pendingConflict":"{key} 已用于{names},改绑后那边会变成「未设置」。","settings.shortcuts.pendingSystem":"{key} 留给系统的「{action}」,不能绑定。","settings.shortcuts.tryAnother":"换一个","settings.shortcuts.reassignHere":"改绑到这里","settings.shortcuts.quoted":"「{name}」","settings.shortcuts.listSep":"、","settings.shortcuts.editor.bold":"加粗","settings.shortcuts.editor.italic":"斜体","settings.shortcuts.editor.inlineCode":"行内代码","settings.shortcuts.editor.quote":"引用","settings.shortcuts.editor.codeBlock":"代码块","settings.shortcuts.editor.strike":"删除线","settings.shortcuts.editor.duplicateBlock":"复制块","settings.shortcuts.editor.heading":"标题","settings.shortcuts.editor.list":"列表","settings.shortcuts.system.copy":"复制","settings.shortcuts.system.paste":"粘贴","settings.shortcuts.system.cut":"剪切","settings.shortcuts.system.selectAll":"全选","settings.shortcuts.system.undo":"撤销","settings.shortcuts.system.redo":"重做","settings.shortcuts.system.quit":"退出应用","settings.shortcuts.system.hide":"隐藏应用","settings.shortcuts.system.minimize":"最小化窗口","settings.shortcuts.system.switchApp":"切换应用","settings.shortcuts.system.spotlight":"Spotlight 搜索","settings.shortcuts.system.forceQuit":"强制退出","settings.shortcuts.system.screenshot":"截屏","settings.shortcuts.system.closeWindow":"关闭窗口","settings.shortcuts.system.startMenu":"开始菜单","settings.shortcuts.system.taskManager":"任务管理器","settings.shortcuts.system.securityOptions":"安全选项","settings.shortcuts.system.miniWindow":"打开 Mini 窗口(全局)","settings.agents.isDefault":"默认","settings.agents.setDefault":"设为默认","settings.agents.viewMem":"查看大脑(记忆 / 日志 / 资料库)","settings.agents.brainSection":"大脑(记忆 / 日志 / 资料库)","settings.agents.brainSectionHint":"查看与编辑该 Agent 的长期记忆、按日日志和资料库文件。","settings.agents.openBrain":"打开大脑","settings.agents.memTitle":"{name} · Agent 大脑","settings.agents.memory":"长期记忆(MEMORY.md,可编辑)","settings.agents.memSaved":"已保存","settings.agents.log":"日志(LOG,可编辑)","settings.agents.noLog":"暂无日志","settings.agents.tabMemory":"记忆","settings.agents.tabLog":"日志","settings.agents.tabLibrary":"资料库","settings.agents.library":"资料库(Library/,参考资料 + 头像)","settings.agents.libraryEmpty":"暂无文件","settings.agents.libraryUpload":"上传文件","settings.agents.librarySelectHint":"点击文件查看 / 编辑","settings.agents.libraryBinaryHint":"二进制文件,仅预览","settings.agents.libraryDeleteConfirm":"删除文件「{name}」?","settings.agents.libraryTooLarge":"文件超过 5MB","settings.agents.userProfile":"用户画像(USER.md,所有 Agent 可见)","settings.agents.userProfileHint":"记录你的名字、偏好、水平、长期需求;所有 Agent 都会读到。","settings.agents.tabHarness":"进化史","settings.agents.harnessHint":"进化记录是 Agent 自我进化的内容:它从工作中自己总结的做法,以及它收起的装备。它自己写入立即生效,对话里会出现一张可撤销的更新卡;后台复盘和 Muse 的用量巡检也会直接写入,条目上标着来源,都可以在这里撤销。每次运行都会带上。","settings.agents.harnessEmpty":"还没有进化记录。Agent 自己摸索出的耐久做法会记在这里(它当场写,或由后台复盘写入);也可以在它的会话里输入 /refine 让它专门复盘一次。","settings.agents.harnessEvidence":"证据:{text}","settings.agents.harnessKindNote":"笔记","settings.agents.harnessKindRecipe":"做法","settings.agents.harnessKindEquip":"装备","settings.agents.harnessShelvedTools":"收起的工具:{names}","settings.agents.harnessShelvedSkills":"收起的技能:{names}","settings.agents.harnessCount":"{count} / {max} 条进化记录","settings.agents.harnessLastChange":"最近进化:{time}","settings.agents.harnessRefine":"复盘本次对话","settings.agents.harnessRefineSent":"已开始复盘,进度在对话里。","settings.agents.harnessShowAll":"显示全部 {count} 条","settings.agents.harnessLoading":"正在读取进化记录…","settings.agents.harnessLocalOnly":"进化记录仅在本机引擎可用。","settings.agents.harnessHistory":"编辑历史(本机)","settings.agents.harnessRollback":"撤销最近一次改动","settings.agents.harnessRestore":"恢复","settings.agents.harnessRollbackConfirm":"撤销「{title}」的最近一次改动?(再次撤销可还原)","settings.agents.harnessActCreate":"新建","settings.agents.harnessActUpdate":"修改","settings.agents.harnessActDelete":"删除","settings.agents.harnessActRollback":"回滚","settings.agents.harnessByHistorian":"后台复盘写入","settings.agents.harnessByMuse":"Muse 代为收起","settings.agents.harnessByUser":"你采纳的候选","settings.agents.harnessCandidates":"{count} 条候选","settings.agents.harnessCandidateNeedsYou":"等你确认","settings.agents.harnessCandidateAdopt":"采纳","settings.agents.harnessCandidateDismiss":"丢弃","settings.agents.harnessCandidateAdopted":"已采纳,写进了进化记录。","settings.agents.harnessCandidateDismissed":"已丢弃。","settings.agents.harnessCandidateGone":"这条候选已经不在了,已重新载入。","settings.agents.harnessCandidateFull":"进化记录已满({max} 条)。先撤掉或合并几条,再采纳。","settings.agents.harnessCandidateTooLong":"这条候选太长,一条记录放不下。可以丢弃,或让 Agent 自己改写后再记。","settings.agents.harnessCandidatesHint":"Historian 提名、但没有直接写进进化记录的做法。带网址、命令或权限字眼的由你逐条决定:采纳就写入,丢弃就删掉;其余的在复盘时由 Agent 逐条审阅,你也可以直接采纳或丢弃。","agent.pickTitle":"选择 Agent","settings.tab.special":"后台 Agent","settings.special.title":"后台特殊 Agent(Special Agents)","settings.special.hint":"默认开启;手动关闭后不会被自动打开。不选模型时跟随云端默认;其记录隔离存于本地,不进会话列表。","settings.special.pickModelFirst":"请先选模型再开启","settings.special.followCloudDefault":"跟随云端默认({model})","settings.model.imageCloudDefaultTag":"云端默认","settings.model.imageFollowingDefault":"未手动选择,当前跟随云端生图默认:{model}。点击任一模型可改为手动指定,再点一次取消。","settings.special.model":"模型","settings.special.enable":"启用","settings.special.historian":"Historian(历史员)","settings.special.historianDesc":"每 X 轮总结会话标题;每 Y 轮判断并更新你的 LOG 与记忆。","settings.special.muse":"Muse(缪斯)","settings.special.museDesc":"后台常驻:按心跳、日程、规则醒来,在自己的 Library 里做事;越界操作按权限档处理,产出进收件箱和 Muse Space。","settings.special.h.rounds":"每几轮维护(标题+记忆)","settings.special.h.firstRound":"首轮必触发","settings.special.h.harnessCandidates":"自进化自动档","settings.special.h.harnessCandidatesHint":"判官从对话里提名 Agent 自己摸索出的做法:像一条工作方法的直接写进它的进化记录;带网址、命令或权限、凭据字眼的留在候选里,等你在详情「进化」里逐条采纳或丢弃。写进去时正在看的会话会弹通知,可在详情「进化」里查看或撤销。","settings.special.h.prompt":"记忆判断提示词(留空=默认)","settings.special.m.maxIter":"每周期最多轮数","settings.special.m.maxTodos":"每窗口最多 TODO","settings.special.m.activeHours":"运行时段(本机时间)","settings.special.m.activeAllDay":"全天","settings.special.m.persona":"人格与指令在 Agent 名册的「Muse」里编辑。","settings.special.m.folders":"额外文件夹(每行一个绝对路径)","settings.special.m.foldersHintAsk":"审批 / 代批档:只是提示 Muse 去看这些目录,写入仍按权限档排队审批。","settings.special.m.foldersHintAuto":"全开档:这些目录可直接读写。","settings.special.m.secRhythm":"节奏","settings.special.m.budget":"预算","settings.special.m.budgetWindow":"预算窗口(小时)","settings.special.m.maxCycles":"每窗口最多周期","settings.special.h.mode":"工作模式","settings.special.h.modeIndependent":"独立","settings.special.h.modeAssist":"辅助","settings.special.h.modeFork":"分身","settings.special.h.modeHintIndependent":"Historian 用上方模型读取最近对话记录,自行判断并维护标题、摘要、日志与记忆。","settings.special.h.modeHintAssist":"到点后分支出一场简短的后台讨论,与该会话的 Agent 商议,由主 Agent 自己决定并写入;标题/摘要仍由 Historian 维护,首轮始终独立。","settings.special.h.modeHintFork":"用会话模型在完整上下文的尾部分叉一次补全来做判断——上下文缓存可命中,比独立模式看得更全;失败自动回落独立模式。上方模型仅用于回落判断与记忆整固。","settings.special.h.fallbackModel":"回落 / 整固模型","settings.special.saved":"已保存","settings.special.saveFail":"保存失败:{e}","settings.special.on":"启用","settings.special.off":"关闭","settings.special.custom":"自定义","settings.special.sectionTitle":"后台 Agent(Special Agents)","settings.agents.sectionTitle":"Normal Agent(自定义人格)","settings.agents.starterTemplate":"你是……(在此描述这个 Agent 的身份、专长与说话风格,以及它应如何完成任务)。","sidebar.special.title":"后台 Agent","special.muse.title":"Muse 工作区","special.muse.thinking":"当前思考","special.muse.idle":"Muse 空闲中","special.muse.running":"Muse 思考中…","special.muse.disabled":"Muse 未开启(在设置 → 后台 Agent 中开启并选模型)。","special.muse.todos":"Muse TODO 清单","special.muse.todosEmpty":"暂无 TODO。Muse 会在后台思考后提交高价值待办。","special.muse.selectAll":"全选","special.muse.inject":"注入所选到会话并运行","special.muse.pickSession":"选择目标会话…","special.muse.injected":"已注入 {n} 条到会话并开始运行","special.muse.dismiss":"忽略","special.muse.markDone":"标记完成","special.muse.injectFail":"注入失败:{e}","special.muse.watches":"盯任务","special.muse.watchesAll":"全部自动化 →","special.muse.watchesHint":"在任意聊天里说「帮我盯着 xxx.md 写满 100 字」即可设定;条件命中时 Muse 会被唤醒并提出待办。","special.muse.trigFile":"「{path}」达到 {n} 字","special.muse.trigEvent":"活动包含「{match}」","special.muse.trigDaily":"每天 {time}","special.muse.trigFired":"上次触发 {t}","special.muse.watchDelete":"删除规则","special.muse.approvals":"待批准","special.muse.approvalsEmpty":"没有等待你批准的操作。","special.muse.approve":"批准并执行","special.muse.reject":"拒绝","special.muse.approveFail":"批准失败:{e}","special.muse.approvalNote":"默认 Agent 代批意见:{note}","special.muse.runNew":"新会话执行所选","special.muse.injectPrefix":"请处理以下来自 Muse 的待办:","muse.lib.openEditor":"在编辑器中打开","special.muse.tracks":"追踪中","special.muse.tracksEmpty":"没有正在追踪的任务。在聊天里的任务卡上点「交给 Muse 追踪」即可添加。","special.muse.trackDelete":"停止追踪","special.muse.modeLabel":"权限档","special.muse.pending":"{n} 项待批","space.muse":"Muse","muse.builtinDesc":"Muse Space:Muse 自建的 Space(它自己写的 Forsion 插件,逐周期迭代),右栏批准它的越界操作;还没搭建时显示它的工作区。","view.museLibrary":"Muse 工作区","view.museHome":"Muse Space","muse.openLibrary":"打开 Muse 工作区","view.musePanel":"Muse","muse.lib.empty":"Muse 还没写任何东西。开启 Muse 后,它的笔记、草稿和每日工作日志会出现在这里。","muse.lib.refresh":"刷新","special.muse.actionFail":"操作失败:{e}","special.muse.execFailed":"已批准,但执行失败:{e}","settings.special.m.mode":"权限档","settings.special.m.modeAsk":"审批(越界操作排队等你批准)","settings.special.m.modeAgent":"代批(默认 Agent 替你裁决一次)","settings.special.m.modeAuto":"全开(完全自动)","settings.special.m.modeDesc":"只管 Muse 在后台自己跑的时候;你和它聊天时按那条会话的审批模式。三档都能在它自己的 Library 和 Space 里自由工作,插件安装始终需要你确认。","settings.special.m.modeHintAsk":"越界写入和命令排进待批,你点头后由引擎按原参数执行。你批准过的 TODO,执行时越界的那一步仍会再问一次。","settings.special.m.modeHintAgent":"默认 Agent 先替你看一眼:确定符合你的习惯、在你的工作区内、可撤销的才放行。跑命令、它拿不准的、改 Agent / 设置 / 自动化的,仍排队等你。","settings.special.m.modeHintAuto":"越界写入和命令不再排队等你。两类动作仍不会自动做:写凭据或应用配置文件,以及必须你当场确认的操作,Muse 会跳过。","settings.special.m.heartbeat":"心跳间隔(分钟,0=只按日程/规则醒来)","settings.special.m.heartbeatHint":"比巡检更细时巡检自动跟着缩到这个粒度;实际次数仍受预算里「每窗口最多周期」封顶。","settings.special.m.notify":"通知","settings.special.m.notifyMode":"日报","settings.special.m.notifyImmediate":"不发","settings.special.m.notifyDigest":"每天一封","settings.special.m.escalateTo":"难活交给","settings.special.m.escalateNone":"不指定","settings.customProvider.fetchModels":"拉取模型","settings.customProvider.fetchEmpty":"未发现模型(端点未返回列表)","sidebar.search.placeholder":"搜索会话…","sidebar.search.noResults":"无匹配会话","chat.selection.actions":"选中文本操作","chat.err.quota":"AI 额度已用尽:点左下角头像可查看用量、使用重置卡立即恢复,或升级会员提高上限","workbench.chat":"对话","workbench.leftSidebar":"左侧栏","workbench.rightSidebar":"右侧栏","theme.changeSkin":"切换主题色","theme.changeMode":"切换明暗模式","theme.changeLanguage":"切换主题外观","command.palette":"命令面板 (⌘K)","command.toggleSmoothCaret":"开关丝滑光标","command.toggleLeft":"切换左侧栏","command.toggleRight":"切换右侧栏","command.toggleBottom":"切换底部面板","panel.emptyTitle":"空面板","panel.empty":"这个面板是空的,把标签页拖进来试试。","command.splitRight":"分屏到右侧","command.resetLayout":"恢复默认布局","command.stop":"停止当前运行","command.compact":"压缩上下文","command.branch":"从最近回复分支","command.saveLayout":"保存命名布局","command.applyLayout":"恢复命名布局","layout.namePrompt":"布局名称","layout.saved":"已保存布局「{name}」","layout.none":"还没有已保存的命名布局","layout.applyPrompt":"输入要恢复的布局名称:{names}","status.context":"上下文","header.connecting":"连接中…","command.placeholder":"运行命令…","command.empty":"没有命令","command.select":"选择","command.run":"运行","command.count":"{count} 条命令","special.agents.title":"后台 Agent","special.memory.title":"记忆","sidebar.special.historianSub":"总结标题 · 维护记忆","sidebar.special.museSub":"后台思考 · 产出 TODO","preview.close":"关闭","preview.expand":"展开","preview.collapse":"收起","preview.download":"下载","preview.notFound":"文件不存在","preview.loadFailed":"加载失败","preview.notAvailable":"此文件类型无法预览","preview.tooLarge":"文件过大({size}),不支持预览","preview.htmlPreview":"预览","view.wsfile":"文件预览","preview.openWithDefault":"用默认应用打开","preview.unsupportedAsk":"无法预览此类型,用系统默认应用打开?","preview.expired":"预览内容已过期(此类预览不随重启保留),请从来源重新打开","preview.mdEdit":"编辑","preview.openInAmadeus":"在 Amadeus 中打开","preview.mdConflict":"文件已被外部修改","preview.mdReload":"重新加载","preview.mdOverwrite":"覆盖写入","preview.mdSaveFail":"保存失败:{err}","preview.mdSalvaged":"文件已被外部修改,你的编辑已另存为「{file}」","panel.action.newFolder":"新建文件夹","preview.htmlCode":"源码","preview.reload":"重新加载","preview.openInBrowser":"在浏览器中打开(同一预览服务器,可用本人账号调 Forsion AI)","preview.csvTruncated":"仅显示前 {shown} 行(共 {total} 行)","preview.slide":"幻灯片 {n}","preview.wrap":"自动换行","preview.zoomIn":"放大","preview.zoomOut":"缩小","preview.fit":"适应","preview.diffSideBySide":"并排","preview.diffLineByLine":"逐行","preview.pdfPages":"仅渲染前 {n} 页(共 {total} 页),下载查看全部","panel.action.preview":"预览","panel.action.deleteN":"删除 {n} 项","panel.confirm.trashN":"把选中的 {n} 项移到回收站?","panel.confirm.delete":"删除「{name}」?","panel.confirm.deleteN":"删除选中的 {n} 个文件?","panel.toast.copied":"已复制 {n} 项到工作区","panel.toast.copyFail":"复制失败:{err}","panel.toast.moveFail":"移动失败:{err}","settings.tab.notifications":"通知","settings.tab.statusbar":"状态栏","ntf.enable":"启用通知","ntf.delivery":"通知方式","ntf.enableHint":"右上角弹出的悬浮小卡片;关闭后所有通知静默(错误也不弹)。","ntf.osEnable":"系统通知","ntf.osEnableHint":"应用切到后台时,同步弹一条系统通知(所有通知类型,不止收件箱)。","ntf.sendTest":"发送测试通知","ntf.testBody":"这是一条测试通知 👋","ntf.events":"通知事件","ntf.eventsHint":"只保留需要关注的事件,减少无效打扰。","ntf.event.system":"系统消息","ntf.event.syncError":"同步失败 / 冲突","ntf.event.syncDone":"远程同步完成","ntf.event.syncDoneOnline":"在线同步完成","ntf.event.agentDone":"后台会话完成","ntf.event.inbox":"收件箱里的审批请求与自动化提醒","ntf.event.dmWaiting":"私聊里等你回复或拍板","ntf.event.noteReminder":"笔记提醒(@remind:)","ntf.event.harnessCandidates":"进化记录的后台更新与候选","ntf.event.projectCandidates":"项目记忆里等你确认的候选","ntf.event.projectCompacted":"项目记忆写满后被压缩","ntf.pluginEvents":"插件通知","ntf.pluginEventsHint":"每个插件一个开关(ctx.notify 的来源;关掉即静音该插件)。","ntf.view":"查看","ntf.dmWaiting":"在等你回复或拍板","ntf.syncError":"在线同步失败:{e}","ipcerr.notLoggedIn":"未登录 Forsion 账号","ipcerr.loginExpired":"登录已失效,请重新登录 Forsion 账号","ipcerr.vaultMissing":"智库目录不存在:{detail}","ipcerr.mirrorMissing":"镜像目录不存在(已有同步记录,不会自动新建空目录):{detail}","ipcerr.scanFailed":"本地目录读取失败,本轮不推断删除:{detail}","ipcerr.invalidSpaceId":"非法的 Space 标识","ipcerr.invalidPluginId":"非法的插件标识","ipcerr.notUserPlugin":"插件不在用户目录(内置 / 首方插件不可卸载)","ipcerr.pluginNotFound":"插件不存在","ipcerr.mcpNameReserved":"MCP 服务名「{detail}」是保留名:dev 与 dev_ 开头的名字留给设备工具,请换一个名字","settings.discovery.mcpReserved":"未导入 {names}:dev 与 dev_ 开头的 MCP 服务名留给设备工具。换个名字后可在 MCP 页手动添加。","ntf.syncDone":"在线同步完成","ntf.noteReminder":"提醒 · {src}","ntf.remoteSyncDone":"远程同步完成:{n} 项变更","ntf.remoteSyncFail":"远程同步失败:{e}","ntf.remoteSyncQuota":"智库超过了蓬洲云的额度:{n} 个文件没传,留在这台电脑上,没有删除。","ntf.syncView":"查看","ntf.remoteSyncConflicts":"远程同步冲突:{n} 项待处理","ntf.remoteSyncPendingDel":"远程同步:{n} 项删除待确认","ntf.actionReview":"去处理","ntf.agentDone":"「{name}」已完成","ntf.agentFail":"「{name}」运行失败","sb.enable":"显示状态栏","sb.display":"显示方式","sb.enableHint":"窗口底部一条细栏,按当前视图显示同步 / 反链 / 字数等信息。默认关闭;同步出错时会临时出现,只显示同步状态。","sb.items":"状态栏","sb.itemsHint":"取消勾选即隐藏;拖动调整顺序(插件项启用后自动出现在列表里)。","sb.side.left":"前","sb.side.right":"后","sb.item.space":"当前 Space","sb.item.agentRunning":"运行中的会话","sb.item.sync":"同步状态","sb.item.backlinks":"反向链接","sb.item.wordCount":"字数统计","sb.item.inbox":"收件箱未读","sb.agentRunning":"{n} 个运行中","sb.synced":"已同步","sb.syncing":"同步中 · {n}","sb.syncingPlain":"同步中…","sb.syncProgress":"同步 {done}/{total}","sb.syncError":"同步异常","sb.syncOffline":"离线","sb.chars":"{n} 字","sb.backlinks":"{n} 反链","amadeus.default.note":"未命名","amadeus.default.dashboard":"未命名仪表盘","amadeus.default.drawing":"未命名白板","amadeus.default.database":"未命名多维表","amadeus.default.folder":"新文件夹","amadeus.default.section":"新分区","amadeus.default.pdfBookmark":"第 {page} 页","amadeus.new.note":"新建笔记","amadeus.new.childNote":"新建子笔记","amadeus.new.dashboard":"新建仪表盘","amadeus.new.dashboardIn":"在「{folder}」中新建仪表盘","amadeus.new.drawing":"新建白板","amadeus.new.drawingIn":"在「{folder}」中新建白板","amadeus.new.folder":"新建文件夹","amadeus.new.folderIn":"在「{folder}」中新建文件夹","amadeus.new.database":"新建 Base","amadeus.new.databaseIn":"在「{folder}」中新建 Base","amadeus.exists":"「{name}」已存在","amadeus.cmd.quickSwitch":"快速切换笔记","amadeus.cmd.search":"搜索笔记(全文)","amadeus.cmd.tutorial":"打开使用教程","amadeus.cmd.manual":"打开使用手册","amadeus.cmd.dailyNote":"打开今天的日记","amadeus.cmd.toggleStar":"收藏 / 取消收藏当前笔记","amadeus.cmd.toggleSource":"切换 源码 / 可视 编辑","amadeus.cmd.openVault":"打开智库…","amadeus.cmd.reveal":"在文件管理器中显示当前笔记","amadeus.cmd.reindex":"重建全文索引","amadeus.cmd.toggleWikiFiles":"切换 双链补全是否包含附件与多维表","amadeus.cmd.wikiFilesOn":"双链补全已包含附件与多维表","amadeus.cmd.wikiFilesOff":"双链补全只包含笔记"},Dd={"common.save":"Save","settings.python.label":"Python","settings.python.bundled":"Bundled (recommended)","settings.python.system":"System","settings.python.hint":"Bundled: no install, isolated from your own Python. System: use your installed python (restart backend to apply).","settings.mirror.label":"Network mirror","settings.mirror.toggle":"Use China mainland mirrors","settings.mirror.recommend":"Your system locale suggests mainland China — enabling mirrors is recommended for faster downloads.","settings.mirror.hint":"When on, guided installs, pip installs, agent-run npx/git and store downloads use domestic mirrors (Tsinghua/npmmirror/multi-proxy GitHub). Env vars are injected only into commands Forsion spawns — no system config files are modified; turn off anytime. pip/npm/git parts require managed backend mode.","settings.mirror.test":"Test connection","settings.mirror.unreachable":"unreachable","settings.test.canceled":"Canceled","settings.test.timeout":"✗ Connection timed out","onboarding.env.mirrorLabel":"Network","onboarding.env.recheck":"Re-check","onboarding.env.installOk":"{tool} installed · {version}","onboarding.env.installedButMissing":'Command finished, but {tool} is still not detected. A restart of the app or a new terminal may be required — or hit "Re-check".',"onboarding.env.installFail":"{tool} install failed (exit {code}) — check the log below.","onboarding.env.pythonBundled":"Python is bundled — no separate install needed.","onboarding.env.copyCmd":"Copy command","onboarding.env.copied":"⤷ Copied — paste and run it in Terminal (requires your password): {command}","sidebar.newChat":"New session","sidebar.memory":"Memory","sidebar.agents":"Background agents","sidebar.viewMore":"View more","tip.folder":"{files} files, {folders} folders","tip.modified":"Modified: {t}","tip.created":"Created: {t}","input.project.label":"Project","input.project.none":"No project","input.project.dontWork":"Don’t work in a project","input.project.search":"Search projects","input.project.noMatches":"No matching projects","input.project.add":"Add local project","input.project.clone":"Clone from Git…","input.project.addCloud":"New cloud project","input.project.cloudName":"Project name, Enter to create","settings.advanced.sessionLimit":"Sessions shown per project in sidebar","settings.mcpServer.label":"External MCP endpoint (for other agents)","settings.mcpServer.hint":"When on, a local HTTP MCP endpoint runs on this machine so external agents (Claude Code / Codex / OpenCode, etc.) can call Forsion Desktop capabilities (currently: send to inbox). Listens on 127.0.0.1 only, token-authenticated.","settings.mcpServer.enable":"Expose to external agents (Claude Code / Codex / OpenCode, etc.)","settings.mcpServer.connectHint":"Pick your agent and copy the config to connect (token embedded):","settings.mcpServer.endpoint":"Endpoint","settings.mcpServer.generic":"Generic JSON","settings.mcpServer.genericNote":"Any Streamable HTTP MCP client (Cursor / Windsurf / Cline, etc.) works with the Generic config — url + Authorization header.","settings.mcpServer.copy":"Copy","settings.mcpServer.notRunning":"Endpoint failed to start. Check logs or restart the app.","common.cancel":"Cancel","common.retry":"Retry","workbench.sessions":"Sessions","space.home":"Home","space.tangu":"Tangu","space.amadeus":"Note","space.calendar":"Calendar","view.todo":"To-do list","view.calendar":"Calendar","view.calendarConfig":"Calendar settings","view.db":"Database","view.drawing":"Whiteboard","space.coding":"Coding Studio","view.codeStudio":"Coding Studio","space.artificial":"Creations","view.artificial":"Creations","view.product":"Creation","space.public":"Publish","view.publicHub":"Published","public.title":"Published","public.subtitle":"Manage your published sites and notes in one place","public.needLogin":"Sign in to Forsion to see your published content","public.refresh":"Refresh","public.empty":"Nothing yet","public.open":"Open","public.copy":"Copy link","public.copied":"Copied","public.unpublish":"Unpublish","public.revoke":"Revoke","public.confirm":"Confirm?","public.sites":"My sites","public.sitesDesc":"Web apps hosted by Forsion Connect","public.published":"Published notes","public.publishedDesc":"Public read-only share links","public.shared":"Shared notes","public.sharedDesc":"Pages you invited others to edit / view","public.disabled":"Disabled","public.unavailable":"Not available in this environment","coding.code":"Code","coding.preview":"Preview","coding.reload":"Reload preview","coding.noEntry":"No entry page","coding.noFile":"No file selected","coding.pickFile":"Pick a file from the tree on the right to edit","coding.emptyPreview":"Nothing to preview yet. Ask the Coding Agent on the left to generate an index.html.","coding.projects":"Projects","coding.newProject":"New project","coding.publish":"Publish","coding.publishTitle":"Publish to Forsion","coding.publishDesc":"Publish this web app as a public link. Inside the app, window.forsion gives access to Forsion AI — visitors sign in with their own Forsion account and spend their own quota.","coding.publishName":"App name","coding.publishSlug":"Link slug","coding.publishSlugHint":"3-32 chars: lowercase letters / digits / hyphens","coding.publishEntry":"Entry page","coding.publishSlots":"Published {used}/{limit} ({tier})","coding.publishBtn":"Publish","coding.publishUpdate":"Update","coding.publishing":"Publishing…","coding.unpublish":"Unpublish","coding.unpublishConfirm":"Confirm unpublish?","coding.publishNeedLogin":"Publishing requires a Forsion account","coding.loginNow":"Sign in to Forsion","coding.loginWaiting":"Waiting for browser authorization…","coding.copyLink":"Copy link","coding.copied":"Copied","coding.openLink":"Open","coding.publishHint":"Use relative paths for assets; .ts/.tsx are transpiled on publish, no build step.","coding.publishNoEntry":"No .html entry in this project yet — generate a page first.","coding.listingTitle":"Store","coding.listingHint":'Listed apps appear publicly under "Web apps" in the store after platform review.',"coding.listingNone":"Not listed","coding.listingPending":"In review","coding.listingApproved":"Listed","coding.listingRejected":"Rejected","coding.listingNoteLabel":"Reason: {note}","coding.listingApply":"Apply to list","coding.listingReapply":"Re-apply","coding.listingWithdraw":"Withdraw","coding.listingDelist":"Delist","coding.listingSummaryPh":"One sentence about this app (shown on its store card after review, ≤300 chars)","coding.listingSubmit":"Submit","coding.termsTitle":"Publish as a public page","coding.termsIntro":"Once published, anyone with the link can view this page, and it may be shared or indexed by search engines. Please confirm:","coding.termsLi1":"You have the right to publish all text, images, audio, video, and other content on the page;","coding.termsLi2":"The page contains no illegal information, infringing content, or personal information disclosed without permission;","coding.termsLi3":"You take responsibility for the content you publish.","coding.termsManage":"The platform manages public content per applicable laws and the Content Publishing Guidelines, and may restrict access to, stop displaying, or remove violating content.","coding.termsAgreePre":"I have read and agree to the ","coding.termsGuidelines":"Content Publishing Guidelines","coding.termsConfirm":"Confirm & publish","coding.cancel":"Cancel","coding.projectName":"Project name","coding.create":"Create","coding.noProjects":'No projects yet. Click "New project" to create your first one.',"coding.switchProject":"Switch project","coding.generating":"Generating…","space.inbox":"Inbox","inbox.list":"Messages","inbox.reader":"Message","inbox.filter.unread":"Unread","inbox.filter.archived":"Archived","inbox.reader.empty":"Select a message to read","inbox.sender.system":"System","inbox.sender.automation":"Automation","inbox.action.markRead":"Mark as read","inbox.action.markUnread":"Mark as unread","inbox.action.readAll":"Mark all read","inbox.action.archive":"Archive","inbox.action.unarchive":"Unarchive","inbox.action.delete":"Delete","inbox.action.refresh":"Check for new","inbox.action.chat":"Chat with {name}","inbox.deleteConfirm":'Delete "{title}"?',"time.justNow":"just now","net.unavailable":"Network unavailable. Try again later.","inbox.pullOk":"Pulled {n} new messages","inbox.pullNone":"No new messages","inbox.opFail":"Operation failed: {e}","inbox.attach.title":"Attached items","inbox.attach.claim":"Claim","inbox.approval.title":"Approval request","inbox.approval.waiting":"Needs your decision","inbox.approval.loading":"Loading the approval record…","inbox.approval.missing":"This approval record was not found (it may have expired or been cleaned up)","inbox.approval.approved":"Approved and executed","inbox.approval.rejected":"Rejected","inbox.approval.executing":"Executing…","inbox.approval.failed":"Approved, but the run failed","inbox.approval.loadFail":"Could not load the approval record","inbox.approval.retry":"Retry","inbox.approval.reason.customAsk":"Required by your approval rules","inbox.approval.reason.rule":'Approval rule "{rule}"',"inbox.approval.reason.escalate":"Writes outside the workspace","inbox.approval.reason.mode":"Required by the approval mode","inbox.approval.reason.control":"Sets up unattended work","inbox.attach.claiming":"Claiming…","inbox.attach.claimed":"Claimed","inbox.attach.expired":"Expired — cannot claim","inbox.claim.ok":"Claimed — items added to your account","inbox.claim.already":"Already claimed before","inbox.claim.fail":"Claim failed","inbox.claim.unmet":"Requirements not met, so this reward cannot be claimed yet","inbox.attach.unmet":"Requirements not met","inbox.req.title":"Requirements","inbox.req.version":"App {v} or later","inbox.req.tiers":"{tiers} plan","inbox.req.currentVersion":"Current version {v}","inbox.req.currentTier":"Current: {tier}","inbox.req.other":"Other requirements (checked when you claim)","inbox.feedback.title":"Feedback thread","inbox.feedback.event.created":"New user feedback","inbox.feedback.event.user_reply":"A user replied to feedback","inbox.feedback.event.admin_reply":"Your feedback got a reply","inbox.feedback.loading":"Loading feedback thread…","inbox.feedback.loadFail":"Could not load the feedback thread","inbox.feedback.signIn":"Sign in to your Forsion account to view and reply","inbox.feedback.missing":"This feedback ticket no longer exists","inbox.feedback.retry":"Retry","inbox.feedback.you":"You","inbox.feedback.support":"Forsion support","inbox.feedback.user":"User","inbox.feedback.replyPh":"Write a reply…","inbox.feedback.attach":"Add attachment","inbox.feedback.attachHint":"Images, text or JSON, up to 5MB each, 5 files max","inbox.feedback.remove":"Remove","inbox.feedback.send":"Send","inbox.feedback.sending":"Sending…","inbox.feedback.sendFail":"Send failed: {e}","inbox.feedback.tooMany":"At most 5 attachments","inbox.feedback.tooBig":"{name} exceeds 5MB or is empty","inbox.feedback.badType":"{name} is not a supported type (images, text or JSON only)","inbox.feedback.download":"Download","inbox.feedback.status.open":"Open","inbox.feedback.status.in_progress":"In progress","inbox.feedback.status.resolved":"Resolved","inbox.feedback.status.closed":"Closed","inbox.tier.free":"Free","inbox.tier.plus":"Plus","inbox.tier.pro":"Pro","inbox.expiresAt":"Valid until {d}","inbox.expired":"Expired","settings.inbox.title":"Inbox","settings.inbox.notifyLabel":"System notifications for new messages","settings.inbox.notifyHint":"Notify when new messages arrive (click jumps to Inbox); badges stay on when off.","amadeus.pages":"Vault","amadeus.editor":"Editor","amadeus.outline":"Outline","amadeus.backlinks":"Backlinks","amadeus.search":"Search","amadeus.tags":"Tags","amadeus.graph":"Graph","chat.action.copied":"Copied","chat.action.resend":"Send","input.slash.branch":"Branch a new session from the latest reply (inherits history)","app.sessionExpired":"Session expired — please sign in to your Forsion account again","onboarding.connect.syncTitle":"Sync to Penzor Cloud","onboarding.connect.sync.notes":"Notes vault on this computer","onboarding.connect.sync.agents":"Agents & memory","onboarding.connect.sync.plugins":"Plugin data","onboarding.connect.cloudSyncHint":"Kept the same on your other devices. Turn any of these off later in Penzor Cloud › Sync.","common.confirm":"OK","extendView.close":"Close extension","extendView.failed":"Extension failed to load","extendView.back":"Back","common.close":"Close","common.back":"Back","common.refresh":"Refresh","common.loading":"Loading…","common.listSep":", ","common.delete":"Delete","common.edit":"Edit","common.open":"Open","common.language":"Language","common.copyCode":"Copy code","common.enabled":"Enabled","common.disabled":"Disabled","locale.zh":"中文","locale.en":"English","locale.toggleTitle":"Switch language","feedback.title":"Feedback","achievements.title":"Achievements","achievements.unlocked":"Achievement unlocked","achievements.claim":"Claim","achievements.claimed":"Claimed","achievements.pts":"{n} pts","achievements.seriesPts":"{n}/{total} pts","achievements.pluginGroup":"Plugins","achievements.cloudGroup":"Cloud achievements","achievements.localGroup":"On this device","achievements.cloudTag":"Cloud · follows your account","achievements.claimedOn":"Claimed on {device}","achievements.signInToClaim":"Sign in to claim","achievements.expired":"Expired","achievements.claimFailed":"Couldn’t claim: {msg}","achievements.claimErr.notCompleted":"not completed yet","achievements.claimErr.expired":"the claim period has ended","achievements.claimErr.notFound":"this achievement is no longer available","achievements.claimErr.grantFailed":"the reward couldn’t be sent. It’s been logged for a manual grant, so please contact support","achievements.claimErr.signedOut":"you’re signed out. Sign in again","achievements.claimErr.network":"couldn’t reach the server. Try again later","achievements.claimErr.unknown":"something went wrong on the server. Try again later","achievements.claimable":"Achievements ready to claim","achievements.medal.bronze":"Bronze","achievements.medal.silver":"Silver","achievements.medal.gold":"Gold","achievements.s.starter":"First Steps","achievements.s.chat":"Conversation","achievements.s.notes":"Notes","achievements.s.agents":"Agents","achievements.a.first-login.title":"Forsion is All You Need","achievements.a.first-login.desc":"Sign in to your Forsion account","achievements.a.theme-change.title":"Fresh Coat","achievements.a.theme-change.desc":"Switch the theme or color scheme once","achievements.a.market-install.title":"Gear Up","achievements.a.market-install.desc":"Install an item from the store","achievements.a.space-save.title":"Power of Space","achievements.a.space-save.desc":"Save the current layout as a Space","achievements.a.first-message.title":"Hello Agent!","achievements.a.first-message.desc":"Send your first message to an agent","achievements.a.chat-10.title":"Talkative","achievements.a.chat-10.desc":"Send 10 messages in total","achievements.a.chat-100.title":"Unstoppable","achievements.a.chat-100.desc":"Send 100 messages in total","achievements.a.group-chat.title":"Round Table","achievements.a.group-chat.desc":"Start a team","achievements.a.first-note.title":"Blooming Ink","achievements.a.first-note.desc":"Create your first note","achievements.a.notes-10.title":"Diligent Writer","achievements.a.notes-10.desc":"Create 10 notes in total","achievements.a.notes-100.title":"Prolific Author","achievements.a.notes-100.desc":"Create 100 notes in total","achievements.a.first-base.title":"Data Sprout","achievements.a.first-base.desc":"Create your first Base","achievements.a.first-agent.title":"Creator","achievements.a.first-agent.desc":"Create your first agent","achievements.a.agents-3.title":"Think Tank","achievements.a.agents-3.desc":"Create 3 agents in total","achievements.a.special-agent.title":"Behind the Scenes","achievements.a.special-agent.desc":"Enable Muse or Historian","achievements.a.first-image.title":"Picture This","achievements.a.first-image.desc":"Have an agent generate an image","achievements.a.debug-toast.title":"You Found This?!","achievements.a.debug-toast.desc":"??????","settings.developer.achToastLabel":"Achievement toast","settings.developer.achToast":"Fire achievement toast","settings.developer.achToastHint":"Debug the unlock animation, repeatable; secretly an achievement itself (reward granted once).","settings.developer.activityLabel":"Activity log","settings.developer.activityExport":"Export activity log","settings.developer.activityEnable":"Record in-app activity","settings.developer.activityHint":"Locally journals your actions (new chats, note edits, tasks…) so the background agent Muse understands what you are doing; stored only in the local activity folder, kept 30 days. Export to troubleshoot issues.","settings.developer.activityViewCmd":"Activity log live view command","settings.developer.activityViewCmdHint":'Adds an "Open activity log" entry to the command palette (⌘K): a main-area tab tailing the activity journal in real time (2s refresh, filter/pause).',"command.openActivityLog":"Open activity log","view.activityLog":"Activity log","activityView.filter":"Filter (substring)…","activityView.pause":"Pause","activityView.resume":"Resume","activityView.count":"{n} lines","activityView.empty":'No activity recorded yet. Make sure "Record in-app activity" is enabled in developer options, then do something.',"command.openActiveWindow":"Active window sampling","view.activeWindow":"Active window","activeWindowView.on":"Seam enabled","activeWindowView.off":"Seam disabled","activeWindowView.offHint":'Active-window sampling is off by default. Turn on "Active window sampling" in Settings → Developer options and the app you are focused on will show up here live.',"activeWindowView.noSample":"Enabled, but no active window could be read. Wayland sessions cannot report it (same ceiling as ActivityWatch); X11 needs xprop.","activeWindowView.noTitle":"(not available on this platform: window titles on macOS require Screen Recording)","activeWindowView.idleMark":"idle","activeWindowView.clear":"Clear","activeWindowView.segEmpty":"Sampling. Switch to another app for a moment and come back — folded focus segments will appear below (idle ones greyed out).","space.automation":"Automation","view.automationList":"Automations","view.automationDetail":"Automation detail","view.automationRuns":"Run history","automation.group.system":"System automations","automation.group.watches":"Watch rules","automation.group.buttons":"Buttons","automation.group.schedules":"Agent schedules","automation.group.finished":"Finished ({n})","automation.finished":"Finished","automation.finishedHint":"One-off, time has passed — edit to reschedule","automation.fact.status":"Status: ","automation.schedule.every":"every {ivl}","automation.schedule.once":"one-off","automation.fact.desc":"Notes:","automation.sched.name":"Name","automation.sched.date":"Date","automation.sched.dateHint":"YYYY-MM-DD or YYYY-MM-DDTHH:mm, optional /end","automation.sched.repeat":"Repeat","automation.sched.repeatHint":"Empty = one-off; e.g. 24h / 7d, rolling from the anchor","automation.builder.expiredReset":"Original time has passed — reset to the next hour; saving reschedules and re-enables.","automation.builder.atPast":"The one-time datetime has passed — pick a new time.","automation.muse.title":"Muse patrol","automation.muse.trigger":"Patrols every {min} min","automation.muse.action":"Thinks about what to do for you → creates TODOs","automation.historian.title":"Historian memory upkeep","automation.historian.trigger":"After every {n} rounds","automation.historian.action":"Summarizes sessions, maintains logs & memory","automation.watches.empty":'No watch rules yet — create one below, or just ask in chat ("keep an eye on…").',"automation.enabled":"Enabled (click to disable)","automation.disabled":"Disabled (click to enable)","automation.new":"New automation","automation.cond.daily":"Daily at {time}","automation.cond.event":'Activity contains "{match}"',"automation.cond.file":"{path} reaches {n} chars","automation.cond.at":"Once · {time}","automation.cond.every":"Every {ivl}","automation.cond.manual":"Manual · button","automation.cond.dbRow":"Row added to {path}","automation.cond.dbCell":"Cell changed in {path}","automation.cond.dbWhereN":"{n} condition(s)","automation.nextRun":"next {time}","automation.detail.empty":"Select an automation on the left","automation.detail.latest":"Latest run","automation.detail.recent":"Recent activity","automation.deepConfig":"Configure","automation.fact.trigger":"Trigger:","automation.fact.action":"Action:","automation.fact.actions":"Steps:","automation.fact.runner":"Runs:","automation.fact.prompt":"Prompt:","automation.fact.cooldown":"Cooldown:","automation.fact.where":"Conditions:","automation.fact.columns":"Watched columns:","automation.fact.noCooldown":"none (0h)","automation.fact.disabledReason":"Auto-disabled by the engine: {reason}","automation.fact.lastRun":"Last run:","automation.fact.nextRun":"Next run:","automation.fire.btn":"Test run","automation.fire.hint":"Execute the action chain once now (does not affect the normal schedule)","automation.fire.ok":"Test run finished ({status})","automation.fire.fail":"Test run failed ({status})","automation.exec.manual":"test","automation.exec.steps":"{n} step(s)","automation.step.notify":"Notify","automation.step.agent_run":"Run agent","automation.step.db_row_add":"Add table row","automation.step.db_row_edit":"Edit table row","automation.step.tool_call":"Run tool","automation.transcript.empty":"No runs yet","automation.transcript.trigger":"Trigger input","automation.transcript.agent":"Agent","automation.transcript.tools":"{n} tool calls","automation.trigger.neverFired":"Not fired yet — runs will appear here once it does","automation.trigger.museNote":"This rule wakes Muse; see its runs under","automation.runs.empty":"No records","automation.runs.pick":"Select an automation to see its runs here","automation.builder.title":"New automation","automation.builder.editTitle":"Edit automation","automation.builder.trigger":"Trigger","automation.builder.desc":"Name","automation.builder.descPh":"Describe this automation in one line","automation.builder.condType":"Trigger type","automation.builder.condTimer":"Timer","automation.builder.condEvent":"Event","automation.builder.condFile":"File threshold","automation.builder.condManual":"Manual (button)","automation.builder.condDb":"Database","automation.builder.manualHint":"Never fires on its own. Insert a Button block in a note, point it at this rule, and click to run it.","automation.builder.unsupported":"This rule uses an action type this builder does not understand yet. Edit it via manage_automation in chat — saving here would silently drop that part, so editing is disabled.","automation.builder.dbPath":"Which database (.db)","automation.builder.dbPickDb":"Pick a database…","automation.builder.dbEvent":"Event","automation.builder.dbEventRow":"Row added","automation.builder.dbEventCell":"Cell changed","automation.builder.dbColumn":"Watched columns","automation.builder.dbColumnsHint":"With several columns checked, a change in any of them fires; “new value equals” is compared on the column that changed.","automation.builder.dbPickCol":"Pick a column…","automation.builder.dbColsLoading":"Loading table…","automation.builder.dbEquals":"And new value equals (optional)","automation.builder.dbEqualsPh":"Leave empty to fire on any change","automation.builder.dbHint":"The engine detects changes by cursor comparison after each save; the rule is pinned to the vault it was created in.","automation.builder.dbRowId":"Row id","automation.builder.dbRowIdPh":"Leave empty = the row that fired the trigger","automation.builder.dbRowIdRequired":"Required (this trigger type has no “triggering row” to default to)","automation.builder.dbCells":"Fields to write","automation.builder.dbCellKey":"Column name or id","automation.builder.dbCellVal":"Value ({{row.Column}} templates allowed)","automation.builder.dbCellAdd":"Add field","automation.builder.dbCellsHint":"With a database trigger, {{row.Column}} in values is replaced from the triggering row.","automation.builder.dbCellValPh":"{{= {target.qty} - {row.out_qty} }}","automation.builder.dbWhere":"Extra conditions (optional)","automation.builder.dbWhereAdd":"Add condition","automation.builder.dbWhereOpEq":"equals","automation.builder.dbWhereOpNe":"not equals","automation.builder.dbWhereOpEmpty":"is empty","automation.builder.dbWhereOpNotEmpty":"is not empty","automation.builder.dbWhereValPh":"value","automation.builder.dbWhereHint":"ANDed with the condition above; compared against the materialised row, so formula/lookup columns work too; up to 10.","automation.builder.dbRowFrom":"Target rows via relation column (optional)","automation.builder.dbRowFromPh":"A relation column (name or id) of the triggering table; empty = use the row id above","automation.builder.dbMatch":"Match rows by column value (optional)","automation.builder.dbMatchValPh":"value, {{row.id}} templates allowed","automation.builder.dbTargetHint":"Target precedence: row id > relation column > column match > the triggering row.","automation.builder.dbSkipIfEmpty":"Skip when this field is empty (optional)","automation.builder.dbSkipIfEmptyPh":"One of the column names/ids above","automation.builder.cooldownDbHint":"Pure action chains on a database trigger may use 0 = no cooldown (needed for chained rules)","automation.builder.dbNoteView":"That is a note-view database (rows come from notes in a folder) — automations only work on classic tables, pick another.","automation.builder.timerMode":"Timer mode","automation.builder.timerDaily":"Daily","automation.builder.timerOnce":"Once","automation.builder.timerEvery":"Interval","automation.builder.time":"Time of day","automation.builder.datetime":"Fire at","automation.builder.onceHint":"Runs once, then disables itself (stays in the list; reschedule + enable to reuse).","automation.builder.interval":"Repeat every","automation.builder.everyHint":"Rolls from creation time; only the most recent miss is caught up. Min 1h with agent steps.","automation.builder.unitM":"minutes","automation.builder.unitH":"hours","automation.builder.unitD":"days","automation.builder.match":"Activity match text","automation.builder.matchPh":"e.g. note.edit, a file name, or a plugin: event","automation.builder.matchHint":"Substring match on new activity lines. Watch plugin events (plugin:<id>:<event>) or run.done agent=xx.","automation.builder.path":"File path (absolute or ~ prefixed)","automation.builder.chars":"Non-whitespace characters","automation.builder.stepN":"Step {n}","automation.builder.moveUp":"Move up","automation.builder.moveDown":"Move down","automation.builder.notifyTitle":"Notification title","automation.builder.notifyTitlePh":"Inbox message title","automation.builder.notifyBody":"Body (optional)","automation.builder.notifyHint":"Delivered straight to your inbox (0 tokens); pushed to connected channels (WeChat/TG…).","automation.builder.runner":"Runner","automation.builder.runnerPick":"Pick an agent…","automation.builder.tool":"Tool","automation.builder.toolPick":"Pick a tool…","automation.builder.dangerous":"⚠ High-risk tool: saving approves these exact arguments","automation.builder.toolCatalogEmpty":"Engine has no action catalog (update the engine)","automation.builder.museFallback":"Wake Muse (default)","automation.builder.museFallbackHint":"With no steps, firing wakes Muse to turn this into a reminder/TODO for you. Add steps to run them instead.","automation.builder.prompt":"Prompt","automation.builder.promptPh":"What should it do when the rule fires (English preferred)","automation.builder.cooldown":"Cooldown (hours)","automation.builder.cooldownHint":"Minimum gap between fires, in hours (floor 0.25 = 15 min for pure notify/tool chains)","automation.builder.cooldownAgentHint":"Has agent steps — min 1 hour (unattended self-excitation guard)","market.title":"Store","market.subtitle":"Discover community-built workflows, capabilities and interface extensions","market.navSubtitle":"Community extensions","market.group.discover":"Discover","market.group.categories":"Categories","market.group.manage":"Manage","market.tab.discover":"Store home","market.tab.skills":"Skills","market.tab.agents":"Agents","market.tab.plugins":"Plugins","market.tab.spaces":"Spaces","market.tab.themes":"Themes","market.tab.webapps":"Web apps","market.tab.installed":"Installed","market.searchPlaceholder":"Search names, authors or tags","market.clearSearch":"Clear search","market.sort.label":"Sort","market.sort.popular":"Popular","market.sort.latest":"Recent","market.sort.name":"Name","market.sectionSubtitle":"Browse {section} and manage installs","market.pluginsSubtitle":"Browse plugins, Spaces and Agents, and manage installs","market.detailSubtitle":"Details, source and install information","market.webOpen":"Open","market.webHint":"Web apps built with Coding Space and listed by users. Opens in the built-in browser; AI features spend the visitor's own account quota.","market.tab.updates":"Updates","market.tab.submit":"Submit","market.author":"by","market.downloads":"{n} downloads","market.downloadsShort":"{n} installs","market.install":"Install","market.installing":"Installing…","market.installed":"Installed","market.reinstall":"Reinstall","market.desktopOnly":"Desktop only","market.desktopOnlyInstall":"Desktop only","market.desktopOnlyHint":"This plugin relies on features that exist on a computer only, so it cannot be installed on a phone","market.platform":"Platform","market.uninstall":"Uninstall","market.uninstallConfirm":'Uninstall "{name}"? Its install directory will be deleted.',"market.uninstallWarnAgent":"⚠️ This is an agent: once installed it keeps its own memory and logs. Uninstalling deletes them too, and that cannot be undone.","market.uninstallWarnSkill":"⚠️ If you have edited this skill, your edits will be deleted with it.","market.uninstalled":'Uninstalled "{name}"',"market.uninstalledNeedsRestart":'Uninstalled "{name}" · its tools only go away after a backend restart',"market.uninstallFail":"Uninstall failed: {e}","market.openSettings":"Open settings","market.update":"Update","market.updateTitle":"Update v{from} → v{to}","market.allUpToDate":"Everything installed is up to date","market.allUpToDateHint":"New versions will appear here automatically.","market.detailBack":"Back to list","market.empty":"Nothing here yet","market.emptyHint":"Community content appears here after review.","market.noInstalled":"Nothing installed from the store yet","market.noResults":"No matching content found","market.noResultsHint":"Try another name, author or tag.","market.browse":"Browse store","market.retry":"Reload","market.loadFailShort":"The store is temporarily unavailable","market.loadFail":"Failed to load: {e}","market.summaryFallback":"The author has not provided a summary.","market.searchResults":"Search results","market.resultCount":"{n} items","market.featured":"Community pick","market.viewDetails":"View details","market.recent":"Recently added","market.recentHint":"See what the community just published.","market.popular":"Popular","market.popularHint":"Ordered by real install count.","market.overview":"Overview","market.reviewed":"Reviewed for listing","market.reviewedHint":"The listing meets publication requirements. Forsion does not guarantee third-party code.","market.type":"Type","market.version":"Version","market.source":"Install source","market.sourceUpload":"Forsion hosted package","market.updated":"Updated","market.unknown":"Unknown","market.installOk":'Installed "{name}"',"market.spaceInstalled":'Installed Space "{name}" and added it to the ribbon',"market.themeInstalled":'Installed "{name}". Pick it in Settings → Appearance',"market.amadeusPluginInstalled":'Forsion plugin "{name}" installed and loaded',"market.pluginInstalledOk":"Plugin installed and enabled","market.pluginInstalledRestartHint":"Plugin installed. Restart the backend for it to take full effect","market.pluginInstalledWaiting":"Plugin installed, but it needs these first: {list}","market.amadeusPluginNeedsDeps":'Forsion plugin "{name}" installed, but it needs these first: {list}',"market.restartBackend":"Restart backend","market.restartBackendHint":"Takes a few seconds; any running conversation will be interrupted","market.backendRestarting":"Restarting the backend…","market.backendRestarted":"Backend restarted — changes are now in effect","market.backendRestartFailed":"The backend didn't restart. Try again, or restart the app","market.installFail":"Install failed: {e}","market.installFailNamed":"Couldn’t install {name}: {e}","market.installHintGithub":"This item downloads from GitHub, which is unreachable on some networks. Turn on a system proxy and retry, or enable “Use China mainland mirrors” in Settings → General → Connection to download through domestic mirrors.","market.installRetry":"Retry","market.phase.resolve":"Preparing…","market.phase.connect":"Connecting…","market.phase.connectN":"Connecting {n}/{m}…","market.phase.percent":"Downloading {n}%","market.phase.bytes":"Downloaded {size}","market.openRepo":"View GitHub repo","market.readmeEmpty":"(No details)","market.submitHint":"Submit a GitHub repository, public npm package or ZIP through your account. Submissions appear after review.","market.submitOpen":"Open submission page","market.submitKicker":"Developer center","market.submitTitle":"Share your workflow with more people","market.submitArtTitle":"One review and version pipeline","market.submitArtHint":"Skills, Agents, Plugins, Spaces and Themes use the same publication flow.","feedback.label":"Issue or feedback","feedback.placeholder":"Describe the problem or suggestion… the current session log is attached automatically to help us debug.","feedback.logAttached":"Current session log will be attached ({name})","feedback.noSession":"No active session — submitting text only","feedback.submit":"Send feedback","feedback.diagnoseViaChat":"Diagnose in chat","feedback.diagnoseViaChatHint":"Send the description to the current session’s agent to troubleshoot it in place","feedback.ok":"Submitted — thank you for your feedback!","feedback.okNoLog":"Submitted (session log over 5MB, not attached this time)","feedback.errEmpty":"Please enter your feedback","feedback.errFail":"Submit failed: {err}","feedback.errNotLoggedIn":"Not logged into Forsion","feedback.errUnavailable":"Feedback not available here","sidebar.account.login":"Sign in to Forsion","sidebar.account.loginHint":"Sign in for cloud memory / skills / hosted models (works fine without signing in too)","sidebar.account.loggingIn":"Signing in…","sidebar.account.logout":"Sign out","sidebar.account.menu.weekly":"This week","sidebar.account.menu.daily":"Today","sidebar.account.menu.unlimited":"Unlimited","sidebar.account.menu.loading":"Loading…","sidebar.account.menu.quotaFail":"Failed to load usage","settings.provider.loginBusy":"After you finish signing in the browser, the local engine restarts to load this provider and the model list refreshes automatically (a few seconds).","sidebar.account.loginFail":"Sign-in failed: {e}","sidebar.account.loginSub":"Click to sign in","sidebar.account.engineDown":"Engine not running · click to restart","sidebar.account.engineStarting":"Engine starting…","sidebar.settings":"Settings (Ctrl+,)","header.theme":"Light / dark","header.browser":"Browser","header.browserEnabled":"Browser tools enabled","header.browserDisabled":"Browser tools disabled","settings.tab.about":"About","about.version":"Version","about.checkUpdates":"Visit website","about.update.check":"Check for updates","about.update.checking":"Checking…","about.update.upToDate":"You're up to date","about.update.available":"Update available v{version}","about.update.download":"Download update","about.update.downloading":"Downloading {percent}%","about.update.install":"Restart & install","about.update.goToDownload":"Go to download","about.update.error":"Update failed: {error}","about.update.unsupported":"Auto-update unavailable in dev","about.update.unreachable":"Could not reach the update server, try again later","about.update.downloadInstaller":"Download installer","about.update.from":"Downloading from {host}","about.update.fromSize":"Downloading from {host} · {size}","about.update.fromProgress":"Downloading from {host} · {done} / {total}","about.update.useGithub":"Use GitHub instead","about.update.useWebsite":"Use the website instead","about.update.fellBackToGithub":"The website download stalled, so it restarted from GitHub","about.update.fellBackToWebsite":"The GitHub download stalled, so it restarted from the website","about.update.downloadedFrom":"Downloaded from {host} and verified","about.update.macOpened":"The installer is downloading in your browser. When it finishes, open the .dmg and drag Forsion into Applications to replace the old version","about.update.source":"Download from","about.update.sourceAuto":"Auto","about.update.sourceWebsite":"Website","about.update.sourceGithub":"GitHub","about.update.sourceHint":"Whether a new version is out always follows forsion.net; this only picks where the installer comes from. Auto uses the website in mainland China and GitHub elsewhere, and switches to the other one if a download stalls.","about.update.regionMainland":"This computer is currently detected in mainland China.","about.update.regionAbroad":"This computer is currently detected outside mainland China.","about.update.beta":"Receive beta updates","about.update.betaHint":"Get pre-release builds like x.y.z-beta.N — newer features, more likely to break. With this off they are invisible to you. Stable always wins: a stable release published after a beta is still offered.","app.update.bannerTitle":"New version v{version} available","app.update.bannerAction":"Update now","app.update.bannerDismiss":"Dismiss","about.changelogTitle":"What's new","about.builtWith":"Forsion Desktop","about.builtWithMobile":"Forsion Mobile","about.complianceTitle":"Compliance","about.appFiling":"App filing number","about.privacy":"Privacy policy","about.terms":"Terms of service","settings.cloud.envOnly":"The Forsion cloud URL is set via the TANGU_CLOUD_URL environment variable (read-only here).","settings.cloud.label":"Forsion cloud URL (brain: memory/skills/hosted models)","settings.cloud.unset":"(unset — using built-in default)","model.group.forsion":"Forsion Cloud","picker.ungrouped":"Ungrouped","model.group.direct":"Local","model.collapseAll":"Collapse all","model.expandAll":"Expand all","model.empty":"No models","model.searchPlaceholder":"Search models…","settings.tab.developer":"Developer","settings.tab.browser":"Browser control","settings.tab.computerUse":"Computer Use","settings.search.strictBackground":"Strict background (never take foreground)","settings.search.jev":"Jev experimental acceleration","settings.tab.channels":"Channels","channel.name.wechat":"WeChat","channel.name.telegram":"Telegram","channel.name.qq":"QQ","channels.intro":"Bring Tangu into your IM: connecting creates a fresh channel session and messages get answered in chat; inbox forwarding can be enabled independently.","channels.loadingTitle":"Loading channels","channels.loadingHint":"Reading local channel capabilities and connection status.","channels.notAvailable":"Channels require the built-in local backend (desktop).","channels.notAvailableHint":"Start the local backend and retry. These settings are not available in external-backend mode.","channels.enable":"Enable","channels.status.connected":"Connected","channels.status.notConnected":"Not connected","channels.status.disabled":"Disabled","channels.connect":"Connect","channels.scanConnect":"Scan to connect","channels.disconnect":"Disconnect","channels.disconnected":"Disconnected.","channels.connectedAs":"Connected: {label}","channels.connectedMsg":"WeChat connected; a new channel session was created.","channels.connectFailed":"Operation failed: {e}","channels.qrExpired":"QR code expired, please scan again.","channels.scanQrHint":"Scan with WeChat to confirm login.","qr.failed":"Failed to generate QR code, please retry.","qr.alt":"Login QR code","channels.newSessionHint":"Connecting creates a new session; later messages go to it. In the IM use /new, /list, /switch to manage sessions and /help for all commands.","channels.botToken":"Bot token","channels.botTokenHint":"Create a bot via @BotFather on Telegram to get a token, then press Connect.","channels.qqHint":"Create a bot on the QQ Open Platform (q.qq.com) to get AppID / AppSecret.","channels.secretSaved":"Saved (type to replace)","channels.sessionsSec":"Channel sessions","channels.sessions":"Enable channel sessions","channels.sessionsHint":"Incoming messages drive an agent session and get replies; when off, only inbox forwarding works.","channels.approval":"Remote approval","channels.approval.readonly":"Ask for approval","channels.approval.autoEdit":"Approve for me","channels.approval.fullAuto":"Full access","channels.defaultAgent":"Default agent","channels.defaultModel":"Default model","channels.imageModel":"Image model","channels.ttsModel":"Voice model","channels.ttsModelPlaceholder":"Empty = follow Voice settings","channels.ttsVoice":"Voice","channels.followDefault":"Follow global default","channels.followGlobal":"Follow global setting","channels.forwardSec":"Inbox forwarding","channels.forward":"Forward inbox messages to this channel","channels.forwardHint":"Push new inbox messages to your IM (independent of channel sessions).","channels.forwardSenders":"Allowed senders","channels.forwardAll":"All","channels.waitingPeer":"Connected; waiting for the first incoming message to bind the contact.","channels.senderSystem":"System","channels.senderServer":"Forsion cloud","settings.tab.notes":"Notes","settings.tab.sync":"Sync","settings.sync.cloudSec":"Online sync","settings.sync.remoteSec":"Vault remote sync","settings.notes.storageTitle":"Files and attachments","settings.notes.storageDescription":"Keep attachment and daily-note locations together.","settings.notes.behaviorTitle":"Editing and safety","settings.notes.behaviorDescription":"Control imports, link compatibility and attachment deletion safeguards.","settings.notes.modeLabel":"Attachment location","settings.notes.modeAttachments":"attachments/ folder next to the note","settings.notes.modeSame":"Same folder as the note","settings.notes.modeVault":"Fixed folder in the vault","settings.notes.modeHint":"Where dragged-in files are saved. “attachments” auto-creates an attachments/ subfolder beside the note.","settings.notes.folderLabel":"Vault-relative folder","settings.notes.folderHint":"Relative to the vault root, e.g. assets. All attachments live here (must be inside the vault for inline preview).","settings.notes.previewLabel":"Preview imported files by default","settings.notes.previewHint":"On: insert an ![[file]] preview block (images inline, others as a clickable file card). Off: insert a [name](path) link.","settings.notes.upgradeV4Label":"Upgrade legacy notes to v4 plain Markdown on open","settings.notes.upgradeV4Hint":"On by default: v3 marker-based notes convert to plain Markdown when you edit them. The upgrade is written only after a real edit; turn this off temporarily if some device still runs a version older than 2.7.8.","settings.notes.dailyLabel":"Daily notes folder","settings.notes.dailyPlaceholder":"Empty = vault root","settings.notes.dailyHint":`Where "Open today's daily note" creates YYYY-MM-DD.md (vault-relative); templates/daily.md is applied automatically if present.`,"settings.notes.wikiFilesLabel":"Suggest attachments and databases in [[ ]]","settings.notes.wikiFilesHint":"On: typing [[ also completes attachments, databases (.db) and drawings. Off: notes only.","settings.notes.canvasDoubleClickFocusLabel":"Focus canvas cards on double-click","settings.notes.canvasDoubleClickFocusHint":"Double-clicking a card always enters editing with the caret at the click. On: it also smoothly centers the card at a readable zoom; off: it edits in place and the viewport stays put. A single click only selects; Space also enters editing.","settings.notes.canvasOverviewZLabel":"Zoom that collapses cards to titles","settings.notes.canvasOverviewZHint":"At this zoom level or below, canvas cards show a title summary instead of their body. The default 25% only collapses at the furthest zoom-out; a higher value collapses sooner. The toggle in the canvas HUD turns the summary off entirely.","settings.notes.deleteAssetsLabel":"Delete exclusive attachments with the note","settings.notes.deleteAssetsAsk":"Ask every time","settings.notes.deleteAssetsYes":"Remembered: delete them","settings.notes.deleteAssetsNo":"Remembered: keep them","settings.notes.deleteAssetsHint":"Only attachments referenced by this note alone; anything another note links to is kept.","settings.remote.saved":"Remote settings saved. The managed backend may restart to apply them.","settings.browser.title":"Browser control","settings.browser.agentBrowser":"Agent browser","settings.browser.hint":"Tangu prefers browser_search and browser_* interaction tools for web work; web_search remains available for compatibility.","settings.browser.engine":"Browser engine","settings.browser.engineHint":"Auto picks an available browser implementation for each task.","settings.browser.searchEngine":"Search engine","settings.browser.timeout":"Timeout","settings.browser.timeoutHint":"Maximum wait for a browser command, in milliseconds.","settings.browser.allowPrivate":"Allow browser tools to open private/local network URLs","settings.browser.allowPrivateHint":"Off by default; browser_navigate blocks localhost, RFC1918 and link-local addresses.","settings.tab.spaces":"Spaces","settings.spaces.hint":"Manage the Spaces in the ribbon. Built-in Spaces ship with the app and cannot be removed; Spaces you created or installed from the store can be uninstalled (their on-disk layout recipe is deleted).","settings.spaces.builtin":"Built-in","settings.spaces.user":"Custom/store","settings.spaces.uninstall":"Uninstall","settings.spaces.uninstalled":'Uninstalled "{name}"',"settings.spaces.empty":"No Spaces yet.","settings.spaces.startupTitle":"Startup location","settings.spaces.startupLabel":"Open the app in","settings.spaces.startupHint":"Opens the Space in the ribbon home slot by default; you can also return to your last Space with its tabs, or pin a specific one.","settings.spaces.lastExit":"Last Space on exit (with its tabs)","settings.spaces.homeSlotStartup":"Space in the home slot (default — now “{name}”)","settings.spaces.homeSlotLabel":"Ribbon home slot","settings.spaces.homeSlotHint":"The centred cell on the ribbon. Home by default; swap it for any Space here or by right-clicking the cell.","settings.spaces.hintPhone":"Built-in Spaces ship with the app and cannot be removed; Spaces you created or installed from the market can be uninstalled (their on-disk layout recipe is deleted).","settings.spaces.startupHintPhone":"Choose which Space the app opens in: the default one, the last one you were in, or a specific one.","settings.spaces.homeSlotStartupPhone":"Default (now “{name}”)","settings.spaces.libraryTitle":"Installed Spaces · {count}","settings.tab.plugins":"Plugins","settings.tab.amadeusPlugins":"Plugins","settings.amadeusPlugins.builtinTitle":"Built-in plugins","settings.amadeusPlugins.builtinHint":"Ships with the app and is on by default (browser, terminal and calendar are native host views; the rest are editor add-ons). Turning one off removes it from the workbench, command palette and editor — calendar takes its Space with it.","settings.amadeusPlugins.externalTitle":"External plugins","settings.amadeusPlugins.changelog":"What's new","settings.amadeusPlugins.hint":"Toggle takes effect instantly; click a plugin for details. Plugin folder: ~/.forsion/plugins/ (store installs). A plugin may bundle engine plugins / agents / skills / Spaces — they are discovered, toggled and uninstalled together with it.","settings.amadeusPlugins.openFolder":"Open plugins folder","settings.amadeusPlugins.reload":"Reload","settings.amadeusPlugins.scaffold":"Create sample plugin","settings.amadeusPlugins.builtin":"Built-in","settings.amadeusPlugins.external":"External","settings.amadeusPlugins.agentOwned":"Space built by {agent}","settings.amadeusPlugins.blockedInvalid":"Invalid manifest: {reason}","settings.amadeusPlugins.uninstall":"Uninstall","settings.amadeusPlugins.uninstallConfirm":'Uninstall "{name}"? Its folder will be deleted; bundled engine plugins/Spaces go with it (seeded agents are kept — delete them on the Agents page if needed).',"settings.amadeusPlugins.uninstalled":'Uninstalled "{name}"',"settings.amadeusPlugins.uninstalledRestartPending":'"{name}" files were deleted, but the engine restart did not complete — bundled tools may still be running; restart the backend manually',"settings.amadeusPlugins.bundleEngine":"Engine plugins ×{n}","settings.amadeusPlugins.bundleAgents":"Agents ×{n}","settings.amadeusPlugins.bundleSkills":"Skills ×{n}","settings.amadeusPlugins.bundleSpaces":"Spaces ×{n}","settings.amadeusPlugins.bundleTitle":"Bundled content","settings.amadeusPlugins.bundleEngineList":"Engine plugins: {list}","settings.amadeusPlugins.bundleAgentsList":"Agents: {list}","settings.amadeusPlugins.bundleSkillsList":"Skills: {list}","settings.amadeusPlugins.bundleSpacesList":"Spaces: {list}","settings.amadeusPlugins.bundleHint":"Bundled engine plugins and Spaces follow this plugin's enable/uninstall state; agents are seeded into the engine once on first discovery and then live independently (upgrades never overwrite, uninstall keeps them).","settings.amadeusPlugins.blockedApi":"Requires plugin API v{v}, incompatible with this app","settings.amadeusPlugins.blockedMinApp":"Requires app version ≥ {v}","settings.amadeusPlugins.empty":"No plugins yet.","settings.amadeusPlugins.back":"Back to list","settings.amadeusPlugins.dep":"Companion app","settings.amadeusPlugins.depConnected":"Connected {v}","settings.amadeusPlugins.depMissing":"Not detected — needs to be installed and running","settings.amadeusPlugins.depCheck":"Check connection","settings.amadeusPlugins.depInstall":"Install","settings.amadeusPlugins.depInstalling":"Installing…","settings.amadeusPlugins.depFail":"Install did not finish — open the website to install manually","settings.amadeusPlugins.depHomepage":"Open website","settings.amadeusPlugins.commands":"Commands","settings.amadeusPlugins.settings":"Settings","plugin.onboarding.title":"Set up — {name}","plugin.onboarding.stepsTitle":"Steps","plugin.onboarding.settingsTitle":"Required settings","plugin.onboarding.recommendsTitle":"Recommended companions","plugin.onboarding.install":"Install","plugin.onboarding.installed":"Installed","plugin.onboarding.installing":"Installing…","plugin.onboarding.notFound":"Not in store","plugin.onboarding.later":"Later","plugin.onboarding.done":"Done","plugin.onboarding.laterHint":'You can come back anytime from Settings → Forsion plugins → this plugin → "Run setup". The "Setup pending" badge clears on its own once every requirement is met.',"plugin.onboarding.requiresTitle":"Before you start","plugin.onboarding.req.ok":"Ready","plugin.onboarding.req.unmet":"Not done yet","plugin.onboarding.req.unknown":"Can't check right now","plugin.onboarding.req.timeout":"The check timed out. Try again in a moment.","plugin.onboarding.req.inactive":"Enable the plugin to check this.","plugin.onboarding.recheck":"Check again","plugin.onboarding.checking":"Checking…","plugin.onboarding.allReady":"All set — you're ready to go.","plugin.onboarding.someUnknown":"Nothing is missing; {n} item(s) can't be checked right now.","plugin.onboarding.guideTitle":"How to use","plugin.onboarding.badge":"Setup pending","plugin.onboarding.run":"Run setup","plugin.onboarding.nudgeTitle":'Plugin "{name}" needs a quick setup',"plugin.onboarding.nudgeBody":`"{name}" still has unmet requirements. Open Settings → Forsion plugins → {name} and click "Run setup" to see what's missing.`,"settings.plugins.npmInstallTitle":"Install engine plugin from npm","settings.plugins.npmInstallHint":"Enter a package spec (e.g. npm:@forsion/tangu-computer-use). Plugins run with your full system permissions — only install sources you trust.","settings.plugins.npmInstallConfirm":'Install "{spec}" from npm? Plugins run with your full system permissions; confirm the source is trustworthy before continuing.',"settings.plugins.preferMirror":"Prefer CN mirror","settings.plugins.installBtn":"Install","settings.plugins.installing":"Installing…","settings.plugins.installed":"Installed {id}@{version}","settings.plugins.empty":"No plugins","settings.plugins.secForsion":"Forsion plugins","settings.plugins.secEngine":"Tangu engine plugins","settings.plugins.bundleOwnedHint":"{n} more engine plugin(s) are bundled by Forsion plugins above and toggle together with them.","settings.plugins.selectHint":"Select a plugin to configure","settings.plugins.builtin":"Built-in","settings.plugins.folder":"Folder","settings.plugins.needsRestart":"Restart needed","settings.plugins.needsRestartHint":"The new version is on disk, but its entry imports relative modules. Restart the backend to run it","settings.plugins.waitingDeps":"Waiting for required plugins","settings.plugins.loadFailed":"Failed to load","settings.plugins.settling":"Finishing up","settings.plugins.settlingHint":"The previous start or stop is still finishing; your setting takes effect once it ends","settings.plugins.needsDepsToEnable":"Install and turn on these first: {list}","settings.plugins.disableDependents":'Turning off "{name}" also pauses the plugins that require it: {list}. They resume when you turn it back on. Continue?',"settings.plugins.uninstallDependents":'These plugins require "{name}" and stop working once it is uninstalled: {list}.',"settings.plugins.openFolder":"Open plugins folder","settings.plugins.rescan":"Reload plugins","settings.plugins.rescanning":"Rescanning…","settings.plugins.rescanAdded":"Rescan done: {n} plugin(s) added, updated or removed","settings.plugins.rescanNone":"Rescan done: nothing changed","settings.plugins.rescanHint":"Picks up plugins added, updated or removed in the folder right away. A plugin whose entry imports relative modules still needs a backend restart after an update","settings.plugins.uninstall":"Uninstall","settings.plugins.uninstallConfirm":'Uninstall "{name}"? This deletes the plugin files and all its settings.',"settings.plugins.uninstalled":'Uninstalled "{name}"',"settings.plugins.scope":"Scope","settings.plugins.scopeGlobal":"Global","settings.plugins.scopeAgent":"Per agent","settings.plugins.selectAgent":"Select agent","settings.plugins.noSettings":"This plugin has no settings","settings.plugins.saved":"Saved","settings.plugins.import":"Import image","settings.plugins.deleteConfirm":"Delete “{name}”?","settings.plugins.onlyImage":"Images only (png/jpg/gif/webp)","about.versionClickHint":"{n} more taps to enable developer mode","about.devUnlocked":"Developer mode enabled","settings.developer.note":"These options are for advanced users / debugging — normally no need to change them.","settings.developer.cloudUrlLabel":"Forsion cloud URL","settings.developer.cloudUrlHint":"Address of the brain service (memory/skills/hosted models). Leave empty to use the TANGU_CLOUD_URL env var or the built-in default. In managed mode, saving restarts the backend to take effect.","settings.developer.cloudUrlPlaceholder":"https://api.forsion.net","settings.developer.saveCloudUrl":"Save","settings.developer.savedRestarting":"Saved, restarting backend…","settings.developer.saved":"Saved","settings.developer.relaunchLabel":"Onboarding","settings.developer.relaunchHint":"Re-run the first-install setup flow (theme / connection / model / project folder).","settings.developer.relaunch":"Re-run onboarding","settings.developer.disable":"Disable developer mode","settings.developer.showSystemPrompt":"Show system prompt before each reply","settings.developer.showSystemPromptHint":"When on, each AI reply is preceded by the full system prompt sent to the model for that message (expand to inspect its content and structure). Local debugging only; cleared automatically when you disable developer mode.","settings.developer.activeWindow":"Active window sampling (seam)","settings.developer.activeWindowHint":'Lets plugins that declare the activeWindow capability read which app you are focused on — so they can drop external dependencies like ActivityWatch. Data never leaves this machine. Adds an "Active window sampling" debug panel to the command palette (⌘K). Off by default; turned off automatically when you leave developer mode.',"settings.developer.mobileUiPreview":"Mobile UI preview command","settings.developer.mobileUiPreviewHint":'Adds a "Switch to mobile UI" entry to the command palette (⌘K) that swaps the desktop shell for the single-column mobile shell at runtime (reloads the page). Works on web too. Local debugging only; cleared when you disable developer mode.',"command.switchToMobileUi":"Switch to mobile UI","command.switchToDesktopUi":"Switch back to desktop UI","command.zoomIn":"Zoom in","command.zoomOut":"Zoom out","command.zoomReset":"Reset zoom","onboarding.brand.caption":"AI workspace","onboarding.progress.label":"Setup progress","onboarding.phase.connect":"Connect account","onboarding.phase.appearance":"Choose appearance","onboarding.phase.capabilities":"Configure capabilities","onboarding.phase.workspace":"Prepare project folder","onboarding.welcome.kicker":"First-time setup","onboarding.welcome.subtitle":"Bring models, agents, knowledge and local tools into one app.","onboarding.welcome.railLabel":"Start here","onboarding.welcome.railTitle":"Make Forsion fit the way you work.","onboarding.welcome.railBody":"Finish the essentials in a few minutes. Every choice can be changed later in Settings.","onboarding.welcome.promiseModels":"Connect Forsion or your own models","onboarding.welcome.promiseAgents":"Prepare agents you can switch anytime","onboarding.welcome.promiseLocal":"Keep control of local files and execution","onboarding.step.connect.title":"Connect models and account","onboarding.step.connect.description":"Sign in to Forsion, use subscription access, or connect an OpenAI-compatible service.","onboarding.step.theme.title":"Choose your appearance","onboarding.step.theme.description":"Design language controls structure, the accent controls highlight color, the background controls the base palette. Mix them freely.","onboarding.step.model.title":"Choose a default model","onboarding.step.model.description":"Pick a daily model now. You can switch it in any conversation later.","onboarding.step.speech.title":"Configure voice input","onboarding.step.speech.description":"Choose a speech recognition model, or keep the default and configure it later.","onboarding.step.agents.title":"Meet your agents","onboarding.step.agents.description":"Review the roster and optionally create an assistant with its own persona and memory.","onboarding.step.workspace.title":"Choose a working directory","onboarding.step.workspace.description":"Set the default folder for local sessions. Forsion works only within the scope you allow.","onboarding.step.env.title":"Check the local environment","onboarding.step.env.description":"Verify tools needed for coding tasks and choose downloads for your current network.","onboarding.step.done.title":"You’re all set","onboarding.step.done.description":"The essentials are configured. Enter Forsion and start working.","onboarding.done.cloudLine1":"· Switch models and thinking effort anytime from the input bar; notes, calendar and automation all live in Forsion","onboarding.done.cloudLine2":"· Settings → Appearance changes the theme and language anytime; the desktop app adds local files and tools","onboarding.connect.modeLabel":"Connection method","onboarding.model.choiceLabel":"Default chat model","onboarding.speech.choiceLabel":"Voice input","onboarding.workspace.choiceLabel":"Default working directory","onboarding.connect.forsionHint":"Sign in with your Forsion account (the cloud URL is set via an environment variable — nothing to enter here). Or switch to your own API key above.","onboarding.connect.skipForNow":"Skip for now","onboarding.theme.stepLabel":"Choose a theme","onboarding.theme.modeLabel":"Light / dark","onboarding.theme.light":"Light","onboarding.theme.dark":"Dark","onboarding.theme.hint":"You can change this anytime in Settings → Appearance.","onboarding.theme.customSeedLabel":"Custom accent color","settings.theme.system":"Follow system","settings.theme.modeLocked":"This theme follows the system appearance","settings.theme.modeLockedHint":"Themes like Glass take light/dark from the system; it can’t be switched manually.","settings.theme.zoomLabel":"Interface size","settings.theme.zoomHint":"Scales the whole interface. Currently {percent}%. You can also fine-tune it in 10% steps with ⌘/Ctrl + +/−.","settings.theme.zoomPresetLabel":"Interface size presets","settings.theme.zoomSmall":"Small","settings.theme.zoomStandard":"Standard","settings.theme.zoomLarge":"Large","settings.theme.smoothCaret":"Smooth caret","settings.theme.smoothCaretHint":"The text caret glides smoothly to its new position in the editor and chat input (Word-style). Off by default; turn it on if you want it.","settings.promptSuggest":"Input suggestions","settings.promptSuggestHint":"After each turn, the empty input box shows a greyed-out guess at your next message. Press Tab to fill it in. Adds one small cached model request per turn. On by default.","settings.promptSuggestEnable":"Enable input suggestions","settings.theme.chatAvatars":"Chat avatars","settings.theme.chatAvatarsHint":"Show agent and user avatars in conversations. Turn off for a cleaner message view; agent names stay.","settings.theme.calmDim":"Dim surroundings","settings.theme.calmDimHint":"The ribbon, inactive tabs, the left sidebar, and the cards beside a chat fade while you work. They come back when you point at them or move keyboard focus there.","settings.theme.calmReading":"Relaxed text","settings.theme.calmReadingHint":"Looser line and paragraph spacing in notes and chats, and a slightly narrower note column. Interface text and controls stay the same size.","settings.theme.calmMotion":"Gentle transitions","settings.theme.calmMotionHint":"Slow down view changes and the fade when surroundings come back.","settings.theme.ribbonAutoHome":"Reset ribbon after scrolling","settings.theme.ribbonAutoHomeHint":"After you scroll the ribbon, clicking elsewhere or opening an item slides it back a moment later. Turn off to keep it where you scrolled.","settings.theme.ribbonRecent":"Recent Spaces on the ribbon","settings.theme.ribbonRecentHint":"Lists your most recently used Spaces in the gap in the middle of the ribbon, newest first. Fewer are shown when there is not enough room.","settings.theme.ribbonRecentOff":"Off","settings.theme.fontUi":"Interface font","settings.theme.fontBody":"Body font","settings.theme.fontMono":"Monospace font","settings.theme.fontFollow":"Follow theme","settings.theme.fontSystem":"System default","settings.theme.fontHint":'Preset fonts ship with the app, so they render the same on every machine regardless of what is installed locally. Pick "Follow theme" to use the current theme’s own stack.',"settings.theme.fontPreset.inter":"Inter (modern sans)","settings.theme.fontPreset.notoSans":"Noto Sans SC","settings.theme.fontPreset.wenkai":"LXGW WenKai (reading)","settings.theme.fontPreset.jetbrains":"JetBrains Mono","settings.theme.fontPreset.system":"System default","settings.theme.fontGroupBuiltin":"Built-in","settings.theme.fontGroupPlugin":"From plugins","settings.theme.customSeedLabel":"Custom accent color","settings.theme.signalLabel":"Highlight","settings.theme.signalFollow":"Match accent","settings.theme.signalBlue":"Soft blue","settings.theme.customSignalLabel":"Custom highlight color","settings.theme.signalHint":"Used for drop lines, cloud sync, checkboxes, switches, selection outlines and wikilinks. When matching the accent, Classic and Ink pair with soft blue; every other palette uses its own accent.","settings.theme.customBgLabel":"Custom background","settings.theme.customBgFollow":"Follows accent","settings.theme.customBgClear":"Reset","settings.theme.customBgHint":"Unset: the accent softly tints the background. Set: use this hue as an independent ambience seed, adjusted into the current mode’s readable range.","settings.theme.langLabel":"Design language","settings.theme.visuals":"Intelligent UI","settings.theme.visualsOpt.auto":"Auto","settings.theme.visualsOpt.less":"Less","settings.theme.visualsOpt.off":"Off","settings.theme.visuals.auto":"Organize images, sources and controls around your question. Simple answers stay in prose.","settings.theme.visuals.less":"Use only when you ask for images, charts or an interactive view. Applies from the next turn.","settings.theme.visuals.off":"Text only, no cards; takes effect from the next turn.","settings.theme.openFolder":"Open themes folder","settings.theme.reload":"Reload themes","settings.theme.dropHint":"Drop theme.json + theme.css into ~/.forsion/themes/<id>/ to install a third-party theme, then click “Reload themes”.","settings.theme.options":"{name} options","settings.theme.optionsReset":"Reset","settings.theme.skinLabel":"Color scheme","settings.theme.accentLabel":"Accent","settings.theme.bgLabel":"Background","settings.theme.skin.cream":"Classic","settings.theme.skin.coral":"Clay","settings.theme.skin.teal":"Teal","settings.theme.skin.lavender":"Dusk","settings.theme.skin.zhi":"Mist","settings.theme.skin.sage":"Sage","settings.theme.skin.ink":"Ink","settings.theme.skin.custom":"Custom","settings.group.appearance":"Appearance","settings.group.account":"Account","settings.group.model":"Models","settings.group.agents":"Agents","settings.group.extensions":"Extensions","settings.group.appearanceAbout":"Appearance & about","settings.group.plugins":"Extensions","settings.group.advanced":"Advanced","settings.group.about":"About","settings.group.options":"Options","settings.group.workspace":"Workspace","settings.group.ai":"AI","settings.group.system":"System","settings.group.tools":"Tools","settings.group.corePlugins":"Core plugins","settings.group.communityPlugins":"Community plugins","settings.tab.general":"General","settings.page.generalDescription":"Manage your working directory, runtime and Forsion connection status.","settings.page.spacesDescription":"Choose a startup location and manage installed Spaces.","settings.page.notesDescription":"Manage attachment locations, note behavior and deletion safeguards.","settings.page.syncDescription":"Sync your local vault to remote storage (Dropbox, S3, WebDAV, and more).","settings.page.themeDescription":"Preview and combine design language, color, appearance mode, interface size and typography.","settings.page.shortcutsDescription":"Find commands and record, unbind or restore shortcuts.","settings.page.notificationsDescription":"Control delivery and choose which events and plugins can notify you.","settings.page.statusbarDescription":"Choose bottom-bar items and drag them into display order.","settings.page.modelDescription":"Choose default models and manage providers, web search and voice.","settings.page.agentsDescription":"Manage the agent roster, background agents and local agent CLIs.","settings.page.skillsDescription":"Browse skills and import skills or MCP settings from other tools.","settings.page.mcpDescription":"Connect, toggle and maintain external MCP tool servers.","settings.page.hooksDescription":"Manage automations that run around agent activity.","settings.page.channelsDescription":"Connect messaging channels and review their status in one place.","settings.page.browserDescription":"Choose browser and search engines, and set network safety boundaries.","settings.page.computerUseDescription":"The agent operates desktop apps by looking at the screen, clicking and typing. Choose whether it may take the foreground, Jev acceleration and the browser tools.","settings.page.pluginsDescription":"Manage core features and installed plugins, their settings and updates.","settings.page.pluginDescription":"Adjust the features and runtime options provided by this plugin.","settings.page.advancedDescription":"Manage local services, interface behavior, logs and data safety.","settings.page.developerDescription":"Internal options for UI debugging, activity logs and feature testing.","settings.page.aboutDescription":"Review the version, update channel, language and full changelog.","settings.overview.label":"Current status","settings.overview.mode":"Runtime mode","settings.overview.backend":"Backend service","settings.overview.account":"Forsion account","settings.overview.signedIn":"Signed in","settings.overview.signedOut":"Not signed in","settings.overview.readyTitle":"Workspace services are ready","settings.overview.readyDescription":"The backend is connected. You can continue adjusting the workspace and local runtime.","settings.overview.attentionTitle":"Workspace services need attention","settings.overview.attentionDescription":"Check the backend connection and runtime mode. The latest status will appear here after saving.","settings.backend.modeDescription":"Let Forsion manage its local service, or connect to a backend you already run.","settings.backend.modeManagedDescription":"Ready out of the box. The desktop app starts, checks and restarts it.","settings.backend.modeExternalDescription":"For an existing LAN, container or remote deployment.","settings.workspace.summary":"The default location used when creating a local session.","settings.runtime.title":"Local runtime","settings.runtime.description":"Configure the code sandbox, Python and download network. Restart the backend to apply changes.","settings.runtime.details":"About Python and network mirror behavior","settings.external.title":"External backend connection","settings.external.description":"Enter the service URL and credentials, test the connection, then save.","settings.theme.previewLabel":"Live appearance preview","settings.theme.previewChat":"Chat","settings.theme.previewWorkspace":"Forsion","settings.theme.previewTitle":"Keep ideas in flow","settings.theme.previewMessage":"Your design language, color scheme, typography and material are applied to this preview in real time.","settings.theme.previewInput":"Ask Forsion, or type / for capabilities","settings.theme.langDescription":"Choose the structure, radius, typography and overall character of the interface.","settings.theme.skinDescription":"Pick accent and background separately; same id on both = the original combined scheme.","settings.theme.behaviorTitle":"Display and motion","settings.theme.behaviorDescription":"Adjust appearance mode, interface size, depth and typing feedback.","settings.theme.flatLabel":"Shadows","settings.theme.flatOff":"Raised","settings.theme.flatOn":"Flat","settings.theme.flatDescription":"Raised adds subtle shadows. Flat hides decorative shadows.","settings.theme.glassDescription":"Add translucent blur to surfaces that support it.","settings.theme.ambient":"Tint chrome from content","settings.theme.ambientHint":"Genesis frosted chrome follows the colors of visible content. Needs frosted glass turned on. Uses more resources while scrolling and switching pages.","settings.theme.homeMotion":"Home wallpaper motion","settings.theme.homeMotionHint":"The Orbit planet circles, the Sun path glow breathes, and Glyphs ripple. Stays still when Reduce motion is on in your system. Same switch as in the Home wallpaper panel.","settings.theme.typographyTitle":"Typography","settings.sub.connection":"Connection","settings.sub.models":"Models","settings.sub.providers":"Custom providers","settings.sub.webSearch":"Web search","settings.sub.voice":"Voice","settings.sub.specialAgents":"Background agents","settings.sub.mcpServer":"MCP endpoint","settings.sub.uiSession":"UI & sessions","settings.sub.data":"Data","settings.sub.skillLibrary":"Skill library","settings.plugins.openSettings":"Settings","onboarding.agents.stepLabel":"Agents","onboarding.agents.intro":"Agents are chat personas with their own name, personality and private memory — the default agent is ready to go, and you can raise a whole roster: a work assistant, a translator, a companion, switching anytime mid-chat. Manage them fully (avatar/model/tools) later in the Agents Space.","onboarding.agents.rosterLabel":"Current roster","onboarding.agents.rosterEmpty":"Roster is empty (the default agent is created on first chat).","onboarding.agents.systemBadge":"background","onboarding.agents.createLabel":"Quick create (optional)","onboarding.agents.namePlaceholder":"Name, e.g. Qinche","onboarding.agents.personaPlaceholder":"One-line persona, e.g. a meticulous technical editor of few words","onboarding.agents.createBtn":"Create","onboarding.agents.createHint":"A name is enough; the persona line becomes its initial instructions and can be changed anytime.","onboarding.agents.created":'Created "{name}" — switch agents above the chat input.',"onboarding.agents.createFail":"Create failed: {e}","onboarding.agents.historianTitle":"Background agent: Historian","onboarding.agents.historianDesc":"Every few rounds it automatically titles the session and maintains logs & long-term memory — independent mode is fully automated; assist mode joins a background side-discussion as an archivist and lets your agent decide what to write.","onboarding.agents.historianSaveFail":"Failed to save Historian settings: {e}","onboarding.agents.moreHint":"Trigger cadence, prompt and the other background agent (Muse) live in Settings → Background agents.","onboarding.workspace.stepLabel":"Choose a default local folder","onboarding.workspace.hint":"Default working directory for new local sessions; leave empty to use the Sessions folder inside your notes library (or ~/Forsion without one).","onboarding.workspace.placeholder":"~/Forsion (default)","onboarding.workspace.pick":"Browse folder","onboarding.workspace.clear":"Clear","settings.advanced.agentDesk":"Agent Desk stage panel","settings.advanced.agentDeskHint":"A stage area beside the chat, on by default. Files the agent edits show up there automatically, and the agent can deliberately stage files, notes and mindmaps for you — and screenshot them to check its own work. Drag to resize, collapse to a card.","settings.advanced.agentDeskEnable":"Enable Agent Desk","settings.advanced.summaryOpenIn":"Clicking a file in the task overview","settings.advanced.summaryOpenInHint":"Where sources and outputs in the task overview card open.","settings.advanced.summaryOpenIn.tab":"Open in a new tab","settings.advanced.summaryOpenIn.desk":"Show in Agent Desk","desk.close":"Close panel","sketch.mobileUnavailable":"This card isn't available in the mobile app (open it on desktop or web).","sketch.expand":"Expand card","sketch.collapse":"Collapse card","settings.advanced.exportLogs":"Export session logs","settings.advanced.exportLogsHint":"Bundle this session’s full conversation, the actual interface state and action trail, renderer errors and the backend runtime logs into one JSON file for developer debugging.","settings.advanced.exportBtn":"Export as JSON","settings.advanced.exportNoSession":"No active session — open a session first, then export.","settings.advanced.exportOk":"Exported to {path}","settings.advanced.exportCanceled":"Export canceled","settings.advanced.exportFailed":"Export failed: {err}","settings.clearData.label":"Clear data / Uninstall","settings.clearData.hint":"Delete Forsion data on this machine. This cannot be undone; the app restarts fresh afterward.","settings.clearData.tangu":"Tangu data & project folders (account, settings, agents, sessions, ~/Forsion)","settings.clearData.desktop":"Desktop settings (window & Amadeus shell config)","settings.clearData.btn":"Clear & restart","settings.clearData.confirm":"Clear the selected data? This cannot be undone and the app will restart.","settings.clearData.macNote":"This only clears data. To fully uninstall Forsion, drag it from Applications to the Trash.","view.changelog":"What's new","changelog.newVersion":"New version {version} available","changelog.newest":"Latest","changelog.zhOnly":"Release notes for this version are available in Chinese only.","settings.developer.testUpdateLabel":"Update popup test","settings.developer.testUpdate":"Open update popup (test)","settings.developer.testUpdateHint":"Force-open the What's new popup to verify it renders (no real new version required).","ctx.windowSource.override":"Window: manual override table","ctx.windowSource.model":"Window: model-reported","ctx.windowSource.family":"Window: inferred from model family (not model-reported)","ctx.windowSource.learned":"Window: learned from the provider's own overflow error","ctx.windowSource.default":"Window: 272k default fallback (unknown model; set it under Settings → Models)","ctx.windowCapped":"The model supports up to {max}; {n} is used by default","approval.why.customAsk":'Your approval rule "{rule}" requires asking you for this step',"approval.why.escalate":'Writes outside the workspace — this mode confirms every time ("always allow" does not apply)',"approval.why.protected":`Changes credentials or Forsion's local configuration — confirmed every time (full access and "always allow" do not skip it)`,"approval.why.always":'This action needs your confirmation every time (full access and "always allow" do not skip it)',"approval.why.mode":'The current approval mode "{mode}" requires your approval for this kind of action',"approval.why.control":'This sets up or changes work that can later run without you watching, so each call needs your confirmation ("always allow" does not apply)',"inbox.approval.withdrawnSystem":"The system withdrew this request (its stored details cannot be shown in full, or a newer request for the same action replaced it), so it cannot be approved here. Ask the agent to request it again if needed.","approval.previewScrollHint":"This is long; scroll to read all of it before approving.","pill.thinkUnsupported":"(unsupported by this model, uses the nearest level)","input.compact":"Compact context","input.slash.voiceOn":"Switch to voice messages (this Agent replies as voice)","input.slash.voiceOff":"Switch back to text messages","input.slash.stop":"Stop the current run","input.slash.agent":"Use a normal agent (custom persona)","input.engineDefault":"Tangu","input.engineChipTitle":"Run engine","input.engineSection":"Run engine","engine.pickTitle":"Choose the agent for this chat","engine.warming":"Starting {name}…","pill.more":"More (next page)","header.currentAgent":"Current agent","settings.tab.agentClis":"Local agent CLIs","settings.agentClis.title":"Agent CLIs","settings.agentClis.hint":"Detected third-party agents (Claude Code / Codex …). Set a default model. New chats can pick them.","settings.agentClis.detected":"Detected","settings.agentClis.needsSignin":"Needs sign-in","settings.agentClis.notDetected":"Not detected","settings.agentClis.notDetectedHint":"Install & sign in to this agent to enable it.","settings.agentClis.defaultModel":"Default model","settings.agentClis.modelDefault":"(engine default)","settings.agentClis.loadingModels":"Loading models…","settings.agentClis.empty":"No external agent engines (host-only feature).","settings.agentClis.importHint":"Importing copies it into Tangu as your own skill/MCP (survives uninstalling the CLI). MCP imports start disabled — enable them in MCP settings.","settings.agentClis.skillsLabel":"Installed skills","settings.agentClis.mcpLabel":"Installed MCP","settings.agentClis.importBtn":"Import","settings.agentClis.imported":"Imported","settings.tab.agents":"Agents","settings.agents.title":"Normal agents (custom personas)","settings.agents.hint":"Define reusable conversational personas (system prompt + model + settings) for different tasks. Agents can also self-author via the manage_agent tool.","settings.agents.new":"New agent","settings.agents.brainSection":"Brain (memory / journal / library)","settings.agents.brainSectionHint":"View and edit this agent's long-term memory, daily log and library files.","settings.agents.openBrain":"Open brain","settings.agents.createViaChat":"Create with AI","settings.agents.createViaChatHint":"Open a new chat and let an agent build the new agent for you","settings.agents.empty":'No agents yet — click "New agent" to create one.',"settings.agents.name":"Name","settings.agents.namePlaceholder":"e.g. Code Reviewer","settings.agents.desc":"Description","settings.agents.model":"Model (empty = use session model)","settings.agents.modelDefault":"(use session model)","settings.agents.systemPrompt":"Developer instructions (what / how / must-read)","settings.agents.systemPromptPlaceholder":"You are a meticulous code reviewer…","settings.agents.thinking":"Thinking effort","settings.agents.maxIter":"Max iterations","settings.agents.approval":"Approval","settings.agents.inherit":"(inherit)","settings.agents.byAgent":"agent-authored","agent.badge.system":"Background","settings.agents.deleteConfirm":'Delete agent "{name}"?',"settings.agents.saveFail":"Save failed: {e}","settings.agents.cloudOnly":"Normal Agents are only available locally (desktop/TUI).","settings.agents.soul":"Persona (SOUL)","settings.agents.soulPlaceholder":'Calm, focused; concise replies… (tone & values, distinct from the "what to do" instructions)',"settings.agents.shareMemory":"Share the default agent's memory & log","settings.agents.shareMemoryHint":"When on, this agent reads/writes the default agent's memory & log; off (default) = its own.","settings.agents.cloudSync":"Cloud sync (mirror across devices)","settings.agents.cloudSyncHint":"When on, all of this agent's files (definition/memory/log/Library) mirror across your devices, newest wins; off (default) = local only.","settings.agents.cloudSyncOn":"Cloud sync: on","settings.agents.cloudSyncOff":"Cloud sync: off","settings.agents.activityAccess":"Allow reading the activity log","settings.agents.activityAccessHint":"Grants this agent read_activity to view your in-app activity; off (default) = Muse only.","settings.agents.toolPolicy":"Tool allow/deny list","settings.agents.toolPolicyNone":"No restriction (all tools)","settings.agents.toolPolicyDeny":"Denylist: unchecked = disabled; new engine tools allowed by default","settings.agents.toolPolicyAllow":"Allowlist: only checked tools usable; new engine tools disabled by default","settings.agents.toolPolicyHint":"Checked = usable. Governs the regular tools below only; permission-gated tools (e.g. read_activity) are unaffected.","settings.agents.toolPolicyEmpty":"Tool catalog unavailable (local engine must be running).","settings.agents.avatar":"Avatar","settings.agents.avatarHint":"Click to upload, ≤1MB (PNG/JPG/GIF/WebP); stored in this agent's Library.","settings.agents.avatarPick":"Upload avatar","settings.agents.avatarRemove":"Remove avatar","settings.agents.avatarTooLarge":"Image exceeds 1MB, please pick a smaller one.","settings.agents.avatarSaveFirst":"Save the agent first, then set an avatar.","settings.tab.shortcuts":"Shortcuts","settings.shortcuts.desc":"Click a shortcut to record, then press the key combo; Esc cancels, Backspace unbinds. You will be asked before taking a combo from another command.","settings.shortcuts.commands":"Commands and shortcuts · {count}","settings.shortcuts.searchPlaceholder":"Search commands or shortcuts","settings.shortcuts.resultCount":"Showing {count}","settings.shortcuts.noResults":"No matching commands.","settings.shortcuts.commandPalette":"Command palette","settings.shortcuts.record":"Click to record shortcut","settings.shortcuts.recording":"Press keys…","settings.shortcuts.reset":"Reset to default","settings.shortcuts.clear":"Unbind","settings.shortcuts.unbound":"Not set","settings.shortcuts.resetAll":"Reset all to default","settings.shortcuts.keyMode":"Keys","settings.shortcuts.keyModeTitle":"Press a key combo to see where it is used","settings.shortcuts.keyResult":"{key} · used in {count}","settings.shortcuts.groupCommands":"Forsion commands","settings.shortcuts.groupElsewhere":"Elsewhere","settings.shortcuts.noCommandUses":"No command uses {key}","settings.shortcuts.layerEditor":"Note editor · while typing in a note","settings.shortcuts.layerSystem":"Reserved by the system","settings.shortcuts.editorHint":'You can bind {key} to a command, but while typing in a note it still does "{action}" and the command will not run.',"settings.shortcuts.editorShadowSaved":'Saved. While typing in a note, {key} still does "{action}".',"settings.shortcuts.conflictCount":"{count} conflicts","settings.shortcuts.conflictWith":'Conflicts with "{name}"',"settings.shortcuts.conflictWithMany":"Conflicts with {count} commands","settings.shortcuts.pendingConflict":"{key} is already used by {names}; reassigning will leave it unset there.","settings.shortcuts.pendingSystem":"{key} is reserved for the system ({action}) and cannot be bound.","settings.shortcuts.tryAnother":"Try another","settings.shortcuts.reassignHere":"Reassign here","settings.shortcuts.quoted":'"{name}"',"settings.shortcuts.listSep":", ","settings.shortcuts.editor.bold":"Bold","settings.shortcuts.editor.italic":"Italic","settings.shortcuts.editor.inlineCode":"Inline code","settings.shortcuts.editor.quote":"Quote","settings.shortcuts.editor.codeBlock":"Code block","settings.shortcuts.editor.strike":"Strikethrough","settings.shortcuts.editor.duplicateBlock":"Duplicate block","settings.shortcuts.editor.heading":"Heading","settings.shortcuts.editor.list":"List","settings.shortcuts.system.copy":"Copy","settings.shortcuts.system.paste":"Paste","settings.shortcuts.system.cut":"Cut","settings.shortcuts.system.selectAll":"Select all","settings.shortcuts.system.undo":"Undo","settings.shortcuts.system.redo":"Redo","settings.shortcuts.system.quit":"Quit app","settings.shortcuts.system.hide":"Hide app","settings.shortcuts.system.minimize":"Minimize window","settings.shortcuts.system.switchApp":"Switch apps","settings.shortcuts.system.spotlight":"Spotlight","settings.shortcuts.system.forceQuit":"Force quit","settings.shortcuts.system.screenshot":"Screenshot","settings.shortcuts.system.closeWindow":"Close window","settings.shortcuts.system.startMenu":"Start menu","settings.shortcuts.system.taskManager":"Task Manager","settings.shortcuts.system.securityOptions":"Security options","settings.shortcuts.system.miniWindow":"Open Mini window (global)","settings.agents.isDefault":"default","settings.agents.setDefault":"Set as default","settings.agents.viewMem":"View brain (memory / log / library)","settings.agents.memTitle":"{name} · Agent brain","settings.agents.memory":"Long-term memory (MEMORY.md, editable)","settings.agents.memSaved":"Saved","settings.agents.log":"Log (LOG, editable)","settings.agents.noLog":"No log yet","settings.agents.tabMemory":"Memory","settings.agents.tabLog":"Logs","settings.agents.tabLibrary":"Library","settings.agents.library":"Library (Library/, reference docs + avatar)","settings.agents.libraryEmpty":"No files yet","settings.agents.libraryUpload":"Upload","settings.agents.librarySelectHint":"Click a file to view / edit","settings.agents.libraryBinaryHint":"Binary file — preview only","settings.agents.libraryDeleteConfirm":'Delete file "{name}"?',"settings.agents.libraryTooLarge":"File exceeds 5MB","settings.agents.userProfile":"User profile (USER.md, visible to all agents)","settings.agents.userProfileHint":"Your name, preferences, level, long-term needs; every agent reads it.","settings.agents.tabHarness":"Evolution","settings.agents.harnessHint":"The evolution record holds how the agent evolves: methods it distilled from its own work and the equipment it shelved. Its own changes apply immediately and show an update card you can undo; background review and Muse's usage review also write here directly, each entry says where it came from, and all of them can be undone on this tab. Every run loads them.","settings.agents.harnessEmpty":"Nothing in the evolution record yet. Durable methods the agent works out for itself land here, written by the agent on the spot or by background review; you can also type /refine in a session with it to reflect on that conversation.","settings.agents.harnessEvidence":"Evidence: {text}","settings.agents.harnessKindNote":"Note","settings.agents.harnessKindRecipe":"Recipe","settings.agents.harnessKindEquip":"Equipment","settings.agents.harnessShelvedTools":"Shelved tools: {names}","settings.agents.harnessShelvedSkills":"Shelved skills: {names}","settings.agents.harnessCount":"Evolution record: {count} of {max} entries","settings.agents.harnessLastChange":"Last evolved {time}","settings.agents.harnessRefine":"Reflect on this conversation","settings.agents.harnessRefineSent":"Reflection started. Follow along in the conversation.","settings.agents.harnessShowAll":"Show all {count}","settings.agents.harnessLoading":"Loading the evolution record…","settings.agents.harnessLocalOnly":"The evolution record is available with the local engine only.","settings.agents.harnessHistory":"Edit history (this device)","settings.agents.harnessRollback":"Undo last change","settings.agents.harnessRestore":"Restore","settings.agents.harnessRollbackConfirm":'Undo the last change to "{title}"? (Undo again to bring it back)',"settings.agents.harnessActCreate":"Created","settings.agents.harnessActUpdate":"Edited","settings.agents.harnessActDelete":"Deleted","settings.agents.harnessActRollback":"Rolled back","settings.agents.harnessByHistorian":"Added by background review","settings.agents.harnessByMuse":"Shelved by Muse","settings.agents.harnessByUser":"Candidate you adopted","settings.agents.harnessCandidates":"Candidates: {count}","settings.agents.harnessCandidateNeedsYou":"Needs your decision","settings.agents.harnessCandidateAdopt":"Adopt","settings.agents.harnessCandidateDismiss":"Dismiss","settings.agents.harnessCandidateAdopted":"Adopted into the evolution record.","settings.agents.harnessCandidateDismissed":"Candidate dismissed.","settings.agents.harnessCandidateGone":"That candidate is no longer waiting. The list was reloaded.","settings.agents.harnessCandidateFull":"The evolution record is full ({max} entries). Remove or merge a few before adopting.","settings.agents.harnessCandidateTooLong":"This candidate is too long for one entry. Dismiss it, or ask the agent to rewrite it.","settings.agents.harnessCandidatesHint":"Methods the Historian nominated but did not write straight into the evolution record. Ones that carry a URL, a command or wording about permissions are yours to decide one by one: Adopt writes the entry, Dismiss removes the candidate. The agent reviews the rest during reflection, and you can adopt or dismiss those too.","agent.pickTitle":"Choose agent","settings.tab.special":"Background agents","settings.special.title":"Special Agents (background)","settings.special.hint":"On by default; once you turn one off, it stays off. Leave the model empty to follow the cloud default; records are isolated locally and never appear in the session list.","settings.special.pickModelFirst":"Pick a model before enabling","settings.special.followCloudDefault":"Follow cloud default ({model})","settings.model.imageCloudDefaultTag":"Cloud default","settings.model.imageFollowingDefault":"No manual pick — following the cloud image default: {model}. Click a model to pin your own choice; click again to unpin.","settings.special.model":"Model","settings.special.enable":"Enable","settings.special.historian":"Historian","settings.special.historianDesc":"Summarizes the session title every X rounds; reviews & updates your LOG and memory every Y rounds.","settings.special.muse":"Muse","settings.special.museDesc":"Resident background agent: wakes on heartbeat, schedules and rules and works inside its own Library; out-of-scope actions follow its permission tier, output lands in the inbox and Muse Space.","settings.special.h.rounds":"Maintain every N rounds","settings.special.h.firstRound":"Always trigger on first round","settings.special.h.harnessCandidates":"Self-evolution auto-collect","settings.special.h.harnessCandidatesHint":"The judge nominates methods an agent worked out for itself. One that reads like a working method goes straight into its evolution record; one that carries a URL, a command, or wording about permissions or credentials waits as a candidate until you adopt or dismiss it on the Evolution tab. A notification appears in the conversation you are viewing when an entry is added, and you can view or undo it on the Evolution tab.","settings.special.h.prompt":"Memory-judgment prompt (empty = default)","settings.special.m.maxIter":"Max iterations / cycle","settings.special.m.maxTodos":"Max TODOs / window","settings.special.m.activeHours":"Active hours (device local time)","settings.special.m.activeAllDay":"All day","settings.special.m.persona":'Edit its persona and instructions under "Muse" in the agent roster.',"settings.special.m.folders":"Extra folders (one absolute path per line)","settings.special.m.foldersHintAsk":"Ask / agent tiers: only a hint telling Muse to look there; writes still queue for approval per tier.","settings.special.m.foldersHintAuto":"Full auto: these folders are directly readable and writable.","settings.special.m.secRhythm":"Rhythm","settings.special.m.budget":"Budget","settings.special.m.budgetWindow":"Budget window (hours)","settings.special.m.maxCycles":"Max cycles / window","settings.special.h.mode":"Mode","settings.special.h.modeIndependent":"Independent","settings.special.h.modeAssist":"Assist","settings.special.h.modeFork":"Fork","settings.special.h.modeHintIndependent":"Historian reads the recent transcript with the model above and maintains the title, summary, log and memory on its own.","settings.special.h.modeHintAssist":"When due, branches a short background discussion with the session's agent; the main agent decides and writes itself. Title/summary are still maintained by Historian; the first round is always independent.","settings.special.h.modeHintFork":"Judges via a single tail-fork completion of the full live context using the session model (prompt-cache friendly, sees far more than Independent; falls back to Independent on failure). The model above is only used for fallback judging and memory consolidation.","settings.special.h.fallbackModel":"Fallback / consolidation model","settings.special.saved":"Saved","settings.special.saveFail":"Save failed: {e}","settings.special.on":"On","settings.special.off":"Off","settings.special.custom":"Custom","settings.special.sectionTitle":"Background agents (special)","settings.agents.sectionTitle":"Normal agents (custom personas)","settings.agents.starterTemplate":"You are … (describe this agent's identity, expertise, tone, and how it should approach tasks).","sidebar.special.title":"Background agents","special.muse.title":"Muse workspace","special.muse.thinking":"Current thinking","special.muse.idle":"Muse is idle","special.muse.running":"Muse is thinking…","special.muse.disabled":"Muse is off (enable it and pick a model in Settings → Background agents).","special.muse.todos":"Muse TODO list","special.muse.todosEmpty":"No TODOs yet. Muse proposes high-value tasks after thinking in the background.","special.muse.selectAll":"Select all","special.muse.inject":"Inject selected into a session & run","special.muse.pickSession":"Pick target session…","special.muse.injected":"Injected {n} into a session and started running","special.muse.dismiss":"Dismiss","special.muse.markDone":"Mark done","special.muse.injectFail":"Inject failed: {e}","special.muse.watches":"Watch rules","special.muse.watchesAll":"All automations →","special.muse.watchesHint":'Say "keep an eye on xxx.md until it reaches 100 chars" in any chat to set one; when a rule fires, Muse wakes up and proposes a todo.',"special.muse.trigFile":'"{path}" reaches {n} chars',"special.muse.trigEvent":'activity contains "{match}"',"special.muse.trigDaily":"daily at {time}","special.muse.trigFired":"last fired {t}","special.muse.watchDelete":"Delete rule","special.muse.approvals":"Pending approvals","special.muse.approvalsEmpty":"Nothing is waiting for your approval.","special.muse.approve":"Approve & run","special.muse.reject":"Reject","special.muse.approveFail":"Could not approve: {e}","special.muse.approvalNote":"Your agent's verdict: {note}","special.muse.runNew":"Run selected in a new session","special.muse.injectPrefix":"Please handle these todos from Muse:","muse.lib.openEditor":"Open in editor","special.muse.tracks":"Tracking","special.muse.tracksEmpty":'No tracked tasks. Use "Hand to Muse" on a task card in chat to add one.',"special.muse.trackDelete":"Stop tracking","special.muse.modeLabel":"Tier","special.muse.pending":"{n} pending approval","space.muse":"Muse","muse.builtinDesc":"Muse Space: the Space Muse builds itself (a Forsion plugin it writes and improves each cycle); approve its out-of-scope actions in the side panel. Shows its workspace until it has built one.","view.museLibrary":"Muse workspace","view.museHome":"Muse Space","muse.openLibrary":"Open Muse workspace","view.musePanel":"Muse","muse.lib.empty":"Muse has not written anything yet. Once enabled, its notes, drafts and daily journal appear here.","muse.lib.refresh":"Refresh","special.muse.actionFail":"Action failed: {e}","special.muse.execFailed":"Approved, but the execution failed: {e}","settings.special.m.mode":"Permission tier","settings.special.m.modeAsk":"Ask (out-of-scope actions queue for your approval)","settings.special.m.modeAgent":"Agent approves (your default agent decides once on your behalf)","settings.special.m.modeAuto":"Full auto","settings.special.m.modeDesc":"Applies only while Muse runs on its own in the background; when you chat with it, that conversation's approval mode applies. All tiers work freely inside its own Library and Space, and plugin installs always need your confirmation.","settings.special.m.modeHintAsk":"Out-of-scope writes and commands wait in the approval queue and run with their original arguments once you approve. A todo you approved still asks again for any step that goes out of scope.","settings.special.m.modeHintAgent":"Your default agent checks first and lets through only what clearly fits your habits, stays in your workspaces and can be undone. Shell commands, anything it is unsure about, and changes to agents, settings or automations still wait for you.","settings.special.m.modeHintAuto":"Out-of-scope writes and commands no longer wait for you. Two kinds of action are still never done automatically: writing credentials or app configuration files, and actions that need you to confirm on the spot. Muse skips them.","settings.special.m.heartbeat":"Heartbeat interval (minutes; 0 = wake only for schedules and rules)","settings.special.m.heartbeatHint":'The supervisor poll shrinks to match a finer heartbeat; the actual cycle count is still capped by "Max cycles / window" under Budget.',"settings.special.m.notify":"Notifications","settings.special.m.notifyMode":"Daily digest","settings.special.m.notifyImmediate":"Off","settings.special.m.notifyDigest":"One a day","settings.special.m.escalateTo":"Hand hard work to","settings.special.m.escalateNone":"None","settings.customProvider.fetchModels":"Fetch models","settings.customProvider.fetchEmpty":"No models found (endpoint returned no list)","sidebar.search.placeholder":"Search chats…","sidebar.search.noResults":"No matching chats","chat.selection.actions":"Selected text actions","chat.err.quota":"AI quota used up — click your avatar (bottom-left) to check usage, use a reset card to restore it now, or upgrade your plan","workbench.chat":"Chat","workbench.leftSidebar":"Left sidebar","workbench.rightSidebar":"Right sidebar","theme.changeSkin":"Change accent color","theme.changeMode":"Toggle light/dark mode","theme.changeLanguage":"Switch theme style","command.palette":"Command palette (⌘K)","command.toggleSmoothCaret":"Toggle smooth caret","command.toggleLeft":"Toggle left sidebar","command.toggleRight":"Toggle right sidebar","command.toggleBottom":"Toggle bottom panel","panel.emptyTitle":"Empty panel","panel.empty":"This panel is empty, try dragging a tab here.","command.splitRight":"Split right","command.resetLayout":"Reset layout","command.stop":"Stop current run","command.compact":"Compact context","command.branch":"Branch from latest reply","command.saveLayout":"Save named layout","command.applyLayout":"Restore named layout","layout.namePrompt":"Layout name","layout.saved":"Saved layout “{name}”","layout.none":"No named layouts saved yet","layout.applyPrompt":"Enter a layout to restore: {names}","status.context":"Context","header.connecting":"Connecting…","command.placeholder":"Run a command…","command.empty":"No commands","command.select":"Select","command.run":"Run","command.count":"{count} commands","special.agents.title":"Background agents","special.memory.title":"Memory","sidebar.special.historianSub":"Summarizes titles · curates memory","sidebar.special.museSub":"Background thinking · TODOs","preview.close":"Close","preview.expand":"Expand","preview.collapse":"Collapse","preview.download":"Download","preview.notFound":"File not found","preview.loadFailed":"Failed to load","preview.notAvailable":"No preview for this file type","preview.tooLarge":"File too large ({size}) to preview","preview.htmlPreview":"Preview","view.wsfile":"File preview","preview.openWithDefault":"Open with default app","preview.unsupportedAsk":"Can't preview this file type. Open it with the system default app?","preview.expired":"Preview content expired (this kind of preview does not survive restarts). Reopen it from its source.","preview.mdEdit":"Edit","preview.openInAmadeus":"Open in Amadeus","preview.mdConflict":"File was modified externally","preview.mdReload":"Reload","preview.mdOverwrite":"Overwrite","preview.mdSaveFail":"Save failed: {err}","preview.mdSalvaged":'File was modified externally; your edits were saved as "{file}"',"panel.action.newFolder":"New folder","preview.htmlCode":"Source","preview.reload":"Reload","preview.openInBrowser":"Open in browser (same preview server; Forsion AI works with your account)","preview.csvTruncated":"Showing first {shown} of {total} rows","preview.slide":"Slide {n}","preview.wrap":"Wrap","preview.zoomIn":"Zoom in","preview.zoomOut":"Zoom out","preview.fit":"Fit","preview.diffSideBySide":"Side by side","preview.diffLineByLine":"Line by line","preview.pdfPages":"Showing first {n} of {total} pages — download to view all","panel.action.preview":"Preview","panel.action.deleteN":"Delete {n}","panel.confirm.trashN":"Move {n} selected items to trash?","panel.confirm.delete":'Delete "{name}"?',"panel.confirm.deleteN":"Delete {n} selected files?","panel.toast.copied":"Copied {n} item(s) to workspace","panel.toast.copyFail":"Copy failed: {err}","panel.toast.moveFail":"Move failed: {err}","settings.tab.notifications":"Notifications","settings.tab.statusbar":"Status bar","ntf.enable":"Enable notifications","ntf.delivery":"Delivery","ntf.enableHint":"Floating cards popping from the top-right; when off, everything (errors included) is silenced.","ntf.osEnable":"System notifications","ntf.osEnableHint":"Also pop an OS notification when the app is in the background (all types, not just Inbox).","ntf.sendTest":"Send test notification","ntf.testBody":"This is a test notification 👋","ntf.events":"Notification events","ntf.eventsHint":"Keep only the events worth your attention to reduce noise.","ntf.event.system":"System messages","ntf.event.syncError":"Sync failures / conflicts","ntf.event.syncDone":"Remote sync completed","ntf.event.syncDoneOnline":"Online sync completed","ntf.event.agentDone":"Background session finished","ntf.event.inbox":"Inbox approval requests and automation reminders","ntf.event.dmWaiting":"Direct chats waiting for your reply or decision","ntf.event.noteReminder":"Note reminders (@remind:)","ntf.event.harnessCandidates":"Background evolution-record updates and candidates","ntf.event.projectCandidates":"Project-memory candidates awaiting your decision","ntf.event.projectCompacted":"Project memory compacted when full","ntf.pluginEvents":"Plugin notifications","ntf.pluginEventsHint":"One switch per plugin (the source of ctx.notify; turn off to mute that plugin).","ntf.view":"View","ntf.dmWaiting":"Waiting for your reply or decision","ntf.syncError":"Online sync failed: {e}","ipcerr.notLoggedIn":"Not signed in to Forsion","ipcerr.loginExpired":"Your Forsion sign-in has expired. Sign in again","ipcerr.vaultMissing":"Vault folder not found: {detail}","ipcerr.mirrorMissing":"Mirror folder not found (it has sync history, so an empty one won't be created): {detail}","ipcerr.scanFailed":"Couldn't read the local folder, so this round won't treat missing files as deleted: {detail}","ipcerr.invalidSpaceId":"Invalid Space identifier","ipcerr.invalidPluginId":"Invalid plugin identifier","ipcerr.notUserPlugin":"This plugin isn't in the user plugins folder (built-in plugins can't be uninstalled)","ipcerr.pluginNotFound":"Plugin not found","ipcerr.mcpNameReserved":'The MCP server name "{detail}" is reserved: names that are dev or start with dev_ belong to device tools. Pick another name',"settings.discovery.mcpReserved":"Not imported: {names}. MCP server names that are dev or start with dev_ belong to device tools. Rename them and add them by hand on the MCP page.","ntf.syncDone":"Online sync completed","ntf.noteReminder":"Reminder · {src}","ntf.remoteSyncDone":"Remote sync done: {n} change(s)","ntf.remoteSyncFail":"Remote sync failed: {e}","ntf.remoteSyncQuota":"Your notes vault is over the Penzor Cloud limit. {n} files weren't uploaded; they stay on this computer and nothing is deleted.","ntf.syncView":"View","ntf.remoteSyncConflicts":"Remote sync conflicts: {n} pending","ntf.remoteSyncPendingDel":"Remote sync: {n} deletion(s) awaiting confirmation","ntf.actionReview":"Review","ntf.agentDone":'"{name}" finished',"ntf.agentFail":'"{name}" failed',"sb.enable":"Show status bar","sb.display":"Display","sb.enableHint":"A slim bar at the bottom showing sync / backlinks / word count per current view. Off by default; it appears with just the sync status while sync is failing.","sb.items":"Status bar","sb.itemsHint":"Uncheck to hide; drag to reorder (plugin items appear here once enabled).","sb.side.left":"Front","sb.side.right":"Back","sb.item.space":"Current Space","sb.item.agentRunning":"Running sessions","sb.item.sync":"Sync status","sb.item.backlinks":"Backlinks","sb.item.wordCount":"Word count","sb.item.inbox":"Inbox unread","sb.agentRunning":"{n} running","sb.synced":"Synced","sb.syncing":"Syncing · {n}","sb.syncingPlain":"Syncing…","sb.syncProgress":"Syncing {done}/{total}","sb.syncError":"Sync error","sb.syncOffline":"Offline","sb.chars":"{n} chars","sb.backlinks":"{n} backlinks","amadeus.default.note":"Untitled","amadeus.default.dashboard":"Untitled dashboard","amadeus.default.drawing":"Untitled whiteboard","amadeus.default.database":"Untitled database","amadeus.default.folder":"New folder","amadeus.default.section":"New section","amadeus.default.pdfBookmark":"Page {page}","amadeus.new.note":"New note","amadeus.new.childNote":"New sub-note","amadeus.new.dashboard":"New dashboard","amadeus.new.dashboardIn":"New dashboard in “{folder}”","amadeus.new.drawing":"New whiteboard","amadeus.new.drawingIn":"New whiteboard in “{folder}”","amadeus.new.folder":"New folder","amadeus.new.folderIn":"New folder in “{folder}”","amadeus.new.database":"New base","amadeus.new.databaseIn":"New base in “{folder}”","amadeus.exists":"“{name}” already exists","amadeus.cmd.quickSwitch":"Quick switch note","amadeus.cmd.search":"Search notes (full text)","amadeus.cmd.tutorial":"Open the tutorial","amadeus.cmd.manual":"Open the user manual","amadeus.cmd.dailyNote":"Open today's daily note","amadeus.cmd.toggleStar":"Star / unstar current note","amadeus.cmd.toggleSource":"Toggle source / visual editing","amadeus.cmd.openVault":"Open vault…","amadeus.cmd.reveal":"Reveal current note in file manager","amadeus.cmd.reindex":"Rebuild full-text index","amadeus.cmd.toggleWikiFiles":"Toggle attachments & databases in wikilink autocomplete","amadeus.cmd.wikiFilesOn":"Wikilink autocomplete now includes attachments and databases","amadeus.cmd.wikiFilesOff":"Wikilink autocomplete now covers notes only"},js={zh:Oa,en:Dd};function Na(e){for(const[t,n]of Object.entries(e))n.zh!=null&&(Oa[t]=n.zh),n.en!=null&&(Dd[t]=n.en)}const QA={"app.defaultWorkspace":["Tangu Default Workspace","Tangu 默认工作区","Tangu default workspace"],"app.cloudWorkspace":["Cloud Workspace","Cloud 工作区","Cloud workspace"]};function WC(e){const t=Object.values(js).map(n=>n[e]).filter(n=>!!n);return[...new Set([...t,...QA[e]??[]])]}function Lo(e,t,n){return $d(js[e][t]??js.zh[t]??t,n)}function ie(e,t){return Lo(Jt,e,t)}function qC(e,t,n){return Lo(e,t,n)}function $d(e,t){return t?e.replace(/\{(\w+)\}/g,(n,i)=>i in t?String(t[i]):`{${i}}`):e}const La=ot.createContext(null);let Jt=Rd(),vn=null;function VC(){vn?.(Jt==="zh"?"en":"zh")}function Bs(){return Jt}const Us=new Set;function XA(e){return Us.add(e),()=>{Us.delete(e)}}function zd(e){if(Jt!==e){Jt=e,KA(),jd(e);for(const t of Array.from(Us))try{t(e)}catch(n){typeof globalThis.reportError=="function"?globalThis.reportError(n):console.error("[i18n] locale subscriber failed",n)}}}function jd(e=Jt){try{window.tangu?.reportUiLocale?.(e)}catch{}}function Bd(e){if(vn){vn(e);return}try{localStorage.setItem(pi,e)}catch{}try{document.documentElement.lang=e==="zh"?"zh-CN":"en"}catch{}zd(e)}const GC=({children:e})=>{const[t,n]=ot.useState(Rd),i=ot.useCallback(s=>{n(s);try{localStorage.setItem(pi,s)}catch{}try{document.documentElement.lang=s==="zh"?"zh-CN":"en"}catch{}zd(s)},[]);ot.useEffect(()=>(vn=i,Jt=t,()=>{vn===i&&(vn=null)}),[i,t]),ot.useEffect(()=>{jd(t)},[t]),ot.useEffect(()=>{try{document.documentElement.lang=t==="zh"?"zh-CN":"en"}catch{}},[t]),ot.useEffect(()=>{JA()},[]);const o=ot.useMemo(()=>({locale:t,setLocale:i,t:(s,a)=>Lo(t,s,a)}),[t,i]);return No.jsx(La.Provider,{value:o,children:e})},ZC=({children:e})=>{const t=ot.useSyncExternalStore(XA,Bs,Bs),n=ot.useMemo(()=>({locale:t,setLocale:Bd,t:(i,o)=>Lo(t,i,o)}),[t]);return No.jsx(La.Provider,{value:n,children:e})};function KC(){const e=ot.useContext(La);return e||{locale:"zh",setLocale:()=>{},t:(t,n)=>$d(Oa[t]??t,n)}}Na({"amxlinks.rewriteFailed":{zh:"已改名 / 移动,但有 {n} 篇笔记里指向它的链接没能跟着更新:{names}。请打开这些笔记检查链接。",en:"Renamed or moved, but links to it in {n} notes could not be updated: {names}. Open those notes and check the links."},"amxlinks.nameSep":{zh:"、",en:", "}});const e1=e=>(e.split("/").pop()??e).replace(/\.md$/i,"");function t1(e){if(!e.length||typeof window>"u")return;const t=e.slice(0,5).map(e1).join(ie("amxlinks.nameSep")),n=e.length>5?`${t} …`:t;window.dispatchEvent(new CustomEvent("amadeus:toast",{detail:{text:ie("amxlinks.rewriteFailed",{n:e.length,names:n}),level:"error",dedupeKey:"amxlinks.rewriteFailed"}}))}Na({"amxbridge.pageNameEmpty":{zh:"页面名不能为空",en:"Page name can't be empty"},"amxbridge.pageExists":{zh:"目标页面已存在",en:"A page with that name already exists"},"amxbridge.fileExistsAtTarget":{zh:"目标位置已存在同名文件",en:"A file with the same name already exists there"},"amxbridge.folderNameEmpty":{zh:"文件夹名不能为空",en:"Folder name can't be empty"},"amxbridge.folderExists":{zh:"同名文件夹已存在",en:"A folder with the same name already exists"},"amxbridge.folderPathEmpty":{zh:"文件夹路径不能为空",en:"Folder path can't be empty"},"amxbridge.moveIntoSelf":{zh:"不能移动到自身内部",en:"Can't move a folder into itself"},"amxbridge.folderExistsAtTarget":{zh:"目标位置已存在同名文件夹",en:"A folder with the same name already exists there"},"amxbridge.noteNameEmpty":{zh:"笔记名不能为空",en:"Note name can't be empty"},"amxbridge.noteExists":{zh:"目标笔记已存在",en:"A note with that name already exists"},"amxbridge.nameEmpty":{zh:"名称不能为空",en:"Name can't be empty"},"amxbridge.fileExists":{zh:"目标文件已存在",en:"A file with that name already exists"},"amxbridge.desktopOnly":{zh:"此操作仅桌面端可用",en:"This action is only available in the desktop app"},"amxbridge.conflictReloaded":{zh:"云端已有更新,已加载最新版本(本次未保存的修改被覆盖)",en:"A newer version was in the cloud, so it was loaded (your unsaved edits were overwritten)"},"amxbridge.renamedElsewhere":{zh:"这篇笔记已在别处改名为「{name}」,本次修改已保存到新名字",en:"This note was renamed to “{name}” elsewhere; your edits were saved under the new name"},"amxbridge.deletedElsewhere":{zh:"这篇笔记已在别处被删除或移走,本次修改没有写到云端(请另存为新笔记)",en:"This note was deleted or moved elsewhere, so your edits weren't saved to the cloud (save them as a new note)"},"amxbridge.deletedElsewhereSaved":{zh:"这篇笔记已在别处被删除或移走,本端未保存的修改已另存为「{name}」",en:"This note was deleted or moved elsewhere; your unsaved edits were saved as “{name}”"},"amxbridge.connectFailed":{zh:"云端连接失败,内容可能不是最新 —— 请刷新页面",en:"Lost the connection to the cloud, so content may be out of date — please refresh the page"},"amxbridge.tooLarge":{zh:"笔记过大,云端拒绝保存",en:"The note is too large for the cloud to save"},"amxbridge.imageNameFailed":{zh:"无法为图片分配文件名",en:"Couldn't pick a file name for the image"},"amxbridge.attachmentNameFailed":{zh:"无法为附件分配文件名",en:"Couldn't pick a file name for the attachment"},"amxbridge.invalidPath":{zh:"无效路径",en:"Invalid path"},"amxbridge.trashMissing":{zh:"回收站条目不存在",en:"This item is no longer in the trash"},"amxbridge.pathOutsideVault":{zh:"路径越出智库",en:"The path is outside the vault"},"amxbridge.readFailed":{zh:"读取文件失败(HTTP {status})",en:"Couldn't read the file (HTTP {status})"},"amxbridge.notText":{zh:"不是文本文件",en:"Not a text file"},"amxbridge.timeout":{zh:"请求超时({s}s),请检查网络后重试",en:"The request timed out ({s}s). Check your network and try again"},"amxbridge.network":{zh:"网络错误:{msg}",en:"Network error: {msg}"},"amxbridge.deviceTimeout":{zh:"设备请求超时,请检查与对方设备的连接",en:"The device didn't respond in time. Check the connection to it"},"amxbridge.deviceUnreachable":{zh:"设备不可达:{msg}",en:"Can't reach the device: {msg}"},"amxbridge.deviceRevoked":{zh:"连接权限已被对方移除",en:"The other device removed your access"},"amxbridge.deviceTooLarge":{zh:"内容过大:服务器中转通道上限 10MB,同一局域网内直连不受限",en:"Too large: the server relay is limited to 10 MB (a direct connection on the same local network has no limit)"},"amxbridge.deviceHttpError":{zh:"设备端错误(HTTP {status})",en:"Device error (HTTP {status})"},"amxbridge.deviceCallFailed":{zh:"设备端调用失败",en:"The call on the device failed"},"amxbridge.remoteOnly":{zh:"{what}:请在对方设备上操作",en:"{what}: do this on the other device"},"amxbridge.op.openPluginsFolder":{zh:"打开插件文件夹",en:"Open plugins folder"},"amxbridge.op.scaffoldSamplePlugin":{zh:"创建示例插件",en:"Create sample plugin"},"amxbridge.op.uninstallPlugin":{zh:"卸载插件",en:"Uninstall plugin"},"amxbridge.op.reveal":{zh:"在文件管理器中显示",en:"Show in file manager"}});class Re extends Error{constructor(t,n,i){super(i??`HTTP ${t}`),this.status=t,this.body=n,this.name="HttpError"}status;body}const Ne=e=>e instanceof Re&&e.status===404,Te=e=>e instanceof Re&&e.status===409,_l=e=>{let t=0;return e.forEach(n=>{typeof n!="string"&&(t+=n.size)}),12e4+Math.ceil(t/256)};function n1(e){const t=e.getToken(),n=ni(e.apiBase,t),i=()=>{const a=e.getToken();if(e.signal?.aborted||!a||(n?ni(e.apiBase,a)!==n:a!==t))throw new Re(409,{code:"ACCOUNT_CHANGED"},"Cloud account changed");return a},o=async(a,r,l)=>{const c=l?.query?`?${new URLSearchParams(l.query).toString()}`:"",d={Authorization:`Bearer ${i()}`};a!=="GET"&&(d["X-Amadeus-Client"]=e.clientId);let u;l?.form?u=l.form:l?.json!==void 0&&(d["Content-Type"]="application/json",u=JSON.stringify(l.json));const p=l?.form?_l(l.form):3e4,h=new AbortController,m=()=>h.abort(e.signal?.reason);e.signal?.addEventListener("abort",m,{once:!0});const g=setTimeout(()=>h.abort(),p);let y;try{y=await(e.request??fetch)(`${e.apiBase}${r}${c}`,{method:a,headers:d,body:u,signal:h.signal})}catch(S){throw new Re(0,null,h.signal.aborted?ie("amxbridge.timeout",{s:Math.round(p/1e3)}):ie("amxbridge.network",{msg:S instanceof Error?S.message:String(S)}))}finally{clearTimeout(g),e.signal?.removeEventListener("abort",m)}if(i(),y.status===401)throw e.onUnauthorized(),new Re(401,null);const b=await y.text().catch(()=>"");i();let C;try{C=b?JSON.parse(b):void 0}catch{C=b}if(!y.ok)throw new Re(y.status,C);return C},s=(a,r,l)=>new Promise((c,d)=>{const u=new XMLHttpRequest,p=i(),h=()=>u.abort(),m=()=>e.signal?.removeEventListener("abort",h);u.open("POST",`${e.apiBase}${a}`),u.setRequestHeader("Authorization",`Bearer ${p}`),u.setRequestHeader("X-Amadeus-Client",e.clientId),u.upload.onprogress=g=>{try{i(),g.lengthComputable&&l(g.loaded,g.total)}catch(y){u.abort(),d(y)}},u.onload=()=>{m();try{i()}catch(y){d(y);return}if(u.status===401){e.onUnauthorized(),d(new Re(401,null));return}let g;try{g=u.responseText?JSON.parse(u.responseText):void 0}catch{g=u.responseText}if(u.status<200||u.status>=300){d(new Re(u.status,g));return}c(g)},u.onerror=()=>{m(),d(new Re(0,null,"network error"))},u.ontimeout=()=>{m(),d(new Re(0,null,"timeout"))},u.onabort=()=>{m(),d(new Re(409,{code:"ACCOUNT_CHANGED"},"Cloud request cancelled"))},u.timeout=_l(r),e.signal?.addEventListener("abort",h,{once:!0}),u.send(r)});return{get:(a,r)=>o("GET",a,{query:r}),post:(a,r)=>o("POST",a,{json:r??{}}),postForm:(a,r,l)=>l?s(a,r,l):o("POST",a,{form:r}),put:(a,r)=>o("PUT",a,{json:r}),del:(a,r)=>o("DELETE",a,{query:r})}}const i1=/structure|create|delete|remove|move|rename|mkdir|rmdir|folder|binary|upload/;function o1(e){let t=null,n=e.signal?.aborted??!1,i=1e3,o=null,s=null,a=null;const r=()=>{s||(s=setTimeout(()=>{s=null,!n&&e.onStructureChange()},300))},l=()=>{if(!n){r();for(const h of new Set([e.lastLoadedPage(),...e.openPages?.()??[]]))h&&e.onPageChange(h)}},c=h=>{if(n)return;let m;try{m=JSON.parse(h)}catch{return}const g=typeof m.seq=="number"?m.seq:null;g!==null&&(a=Math.max(a??0,g));const y=typeof m.path=="string"?m.path:"",b=`${typeof m.op=="string"?m.op:""} ${typeof m.kind=="string"?m.kind:""}`.toLowerCase();if((!y||i1.test(b))&&r(),!y)return;const C=typeof m.op=="string"?m.op:"",S=typeof m.newPath=="string"&&m.newPath?m.newPath:null,T=typeof m.origin?.client=="string"&&m.origin.client===e.clientId;if(C==="move"&&S){e.onPageMoved?.(y,S,typeof m.fileSeq=="number"?m.fileSeq:null,T);return}if(C==="delete"){e.onPageDeleted?.(y);return}if((C==="rename-folder"||C==="move-folder")&&S){e.onFolderMoved?.(y,S,T);return}if(C==="delete-folder"){e.onFolderDeleted?.(y);return}const O=typeof m.origin?.client=="string"&&m.origin.client===e.clientId,v=e.knownSeq(y),I=g!==null&&v!==void 0&&g<=v;O||I||(/\.md$/i.test(y)?e.onPageChange(y):/\.db$/i.test(y)&&e.onDbChange(y))},d=()=>{if(n)return;const h=a;let m=null,g;try{const y=e.url();g=new EventSource(h===null?y:`${y}${y.includes("?")?"&":"?"}since=${h}`)}catch{u();return}t=g,g.onopen=()=>{n||(i=1e3)},g.addEventListener("hello",y=>{if(n)return;let b=null;try{const C=JSON.parse(y.data);typeof C.seq=="number"&&(b=C.seq)}catch{}h!==null&&b!==null?b<h?(a=b,l()):b>h&&(m=b):b!==null&&(a=Math.max(a??0,b))}),g.addEventListener("change",y=>c(y.data)),g.addEventListener("reset",()=>{l(),m!==null&&(a=Math.max(a??0,m)),m=null}),g.addEventListener("presence",y=>{if(!n)try{e.onPresence?.(JSON.parse(y.data))}catch{}}),g.addEventListener("presence-roster",y=>{if(!n)try{e.onPresenceRoster?.(JSON.parse(y.data))}catch{}}),g.onerror=()=>{g.close(),t===g&&(t=null),u()}},u=()=>{if(n||o)return;const h=i+Math.random()*i*.3;i=Math.min(i*2,3e4),o=setTimeout(()=>{o=null,d()},h)},p=()=>{n=!0,t?.close(),t=null,o&&clearTimeout(o),s&&clearTimeout(s),e.signal?.removeEventListener("abort",p)};return e.signal?.addEventListener("abort",p,{once:!0}),d(),p}const Ge=new Set;let Ud=0;const Hs=new Set;function Pl(){Ud++;for(const e of Hs)e()}function s1(){return Ud}function a1(e){return Hs.add(e),()=>Hs.delete(e)}function r1(e){return Ge.add(e),Pl(),()=>{Ge.delete(e),Pl()}}function He(e){const t=[];let n=0;for(const i of Ge)(e==null||i.path===e)&&t.push({h:i,at:i.lastActive?.()??0,i:n++});return t.sort((i,o)=>o.at-i.at||i.i-o.i).map(i=>i.h)}function l1(e){return He(e)[0]?.scope??null}function c1(e,t){for(const n of[...Ge])n.path===e&&n.owner!==t&&n.peerWrote?.()}function u1(e,t){const n=He(e).filter(s=>s.patchFm);n.sort((s,a)=>+!!a.dirty?.()-+!!s.dirty?.());let i=null;const o=[];for(const s of n)i?o.push(s):i=s.patchFm(t);if(i)for(const s of o)s.patchFm(t,!0);return i}async function d1(e=!1){await Promise.all([...Ge].map(t=>e?t.flush(!0):t.flush().catch(()=>{})))}async function h1(e,t=!1){await Promise.all([...Ge].filter(n=>n.path===e).map(n=>t?n.flush(!0):n.flush().catch(()=>{})))}function p1(){for(const e of Ge)e.retire()}function g1(e,t){for(const n of He(e))if(n.insertFiles&&n.insertFiles(t)!==!1)return!0;return!1}function m1(e,t="file",n){for(const i of Ge)Ma(i.path,e,t)&&i.retire(n?t==="file"?n:n+i.path.slice(e.length):void 0)}function Ma(e,t,n="file"){const i=e.replace(/\\/g,"/"),o=t.replace(/\\/g,"/");return i===o||n==="prefix"&&i.startsWith(`${o}/`)}async function f1(e,t="file"){const n=[...Ge].filter(i=>i.hold&&i.release&&Ma(i.path,e,t));return await Promise.all(n.map(i=>i.hold().catch(()=>{}))),async i=>{for(const o of n)await o.release(i==null?void 0:t==="file"?i:i+o.path.slice(e.length),t==="prefix").catch(()=>{})}}function Hd(){return[...new Set([...Ge].map(e=>e.path))]}function w1(e,t){for(const n of Ge)if(n.path===e&&(n.scope??null)===t)return!0;return!1}function b1(e){for(const t of Ge)if(t.path===e)return!0;return!1}function y1(e){for(const t of He(e))if(t.bodyNow)return t.bodyNow();return null}function k1(e){for(const t of He(e))if(t.statsNow)return t.statsNow();return null}let Wd=0;const Ws=new Set;function v1(){Wd++;for(const e of Ws)e()}function S1(){return Wd}function x1(e){return Ws.add(e),()=>Ws.delete(e)}function A1(e){for(const t of He(e))if(t.headings)return t.headings();return null}function C1(e){for(const t of He(e))if(t.fmNow)return t.fmNow();return null}function T1(e,t,n){for(const i of He(e))if(i.insertMarkdown?.(t,n))return!0;return!1}function I1(){return Ge.size>0}function E1(){for(const e of Ge)if(e.insertReply)return!0;return!1}function _1(e,t){if(t)for(const n of He(t.path)){const i=n.insertReply?.(e,t.anchor??null);if(i)return{path:n.path,undo:i.undo}}for(const n of He()){const i=n.insertReply?.(e,null);if(i)return{path:n.path,undo:i.undo}}return null}function P1(e){for(const t of He(e))if(t.focusBody)return t.focusBody();return!1}function F1(e){for(const t of He(e))if(t.fmNow)return t.fmNow();return null}function O1(e,t,n=!1){for(const i of He(e))if(i.revealBlock)return i.revealBlock(t,n);return!1}function N1(e,t,n){for(const i of He(e))if(i.revealText)return i.revealText(t,n);return!1}function L1(e,t,n,i=!1){for(const o of He(e))if(o.revealHeading)return o.revealHeading(t,n,i),!0;return!1}const YC=Object.freeze(Object.defineProperty({__proto__:null,announceUnifiedWrite:c1,bumpUnifiedStats:v1,flushUnifiedPath:h1,flushUnifiedScopes:d1,hasUnifiedInstance:b1,holdUnifiedPath:f1,insertFilesForPath:g1,pathHit:Ma,registerUnifiedPipe:r1,retireAllUnifiedScopes:p1,retireUnifiedPath:m1,subscribeUnified:a1,subscribeUnifiedStats:x1,unifiedBody:y1,unifiedFm:C1,unifiedFmNow:F1,unifiedFocusBody:P1,unifiedGen:s1,unifiedHasAny:I1,unifiedHasReplyTarget:E1,unifiedHeadings:A1,unifiedInsertMarkdown:T1,unifiedInsertReply:_1,unifiedPatchFm:u1,unifiedPaths:Hd,unifiedRevealBlock:O1,unifiedRevealHeading:L1,unifiedRevealText:N1,unifiedScopeFor:l1,unifiedScopeLive:w1,unifiedStats:k1,unifiedStatsVer:S1},Symbol.toStringTag,{value:"Module"})),M1=7e4,Sn=new Map,qs=new Set;function qd(){const e=Date.now();for(const[t,n]of Sn)e-n.at>M1&&Sn.delete(t);return[...Sn.values()]}function Vd(){const e=qd();for(const t of qs)try{t(e)}catch{}}function R1(e){const t=e;!t||typeof t.userId!="string"||(Sn.set(t.userId,{userId:t.userId,username:String(t.username??"user"),page:typeof t.page=="string"?t.page:null,at:Number(t.at)||Date.now()}),Vd())}function hs(e){if(Sn.clear(),Array.isArray(e))for(const t of e){const n=t;n&&typeof n.userId=="string"&&Sn.set(n.userId,n)}Vd()}function D1(e){return qs.add(e),e(qd()),()=>{qs.delete(e)}}let Lt=null;function po(e,t,n){if(!Lt)return e;const i=new URLSearchParams;i.set("ref",e);const o=t===void 0?Lt.activePage():t;o&&i.set("page",o),n&&i.set("lit",n);const s=Lt.assetToken();return s&&i.set("at",s),`${Lt.apiBase}/amadeus/vaults/${encodeURIComponent(Lt.vaultId())}/asset?${i.toString()}`}function $1(e){if(!Lt||e.includes("#"))return null;const t=e.indexOf("?");if(t<0||!/^(https?:\/\/|\/)/.test(e)||!e.slice(0,t).endsWith(`/amadeus/vaults/${encodeURIComponent(Lt.vaultId())}/asset`))return null;const n=new URLSearchParams(e.slice(t+1)),i=n.get("ref")||null,o=n.get("lit");return i&&o&&it(o)===it(i)?o:i}function z1(e,t){const n=it(e);return!n||n===e?po(e,t?null:void 0):po(n.includes("/")?n:`${n}/`,t?null:void 0,e)}function j1(e){Lt=e,Au(z1,$1)}let Gd=()=>{};function B1(e){Gd=e}const At=(e,t=!1)=>{try{Gd(e,t)}catch{}},Ri=()=>new Date().toISOString(),Zd="amadeus.cloudVaultId";let ti=null;function U1(){return ti?ti():Promise.resolve("default")}function H1(e){const t=$i(Zd),n=$i("amadeus_tree_snap"),i=$i("amadeus_last_page"),o=typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`web-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`,s=n1({apiBase:e.apiBase,getToken:e.getToken,clientId:o,onUnauthorized:e.onAuthError,request:e.request,signal:e.signal});let a=null,r=null;const l=()=>a??"default";async function c(){return a||r||(r=(async()=>{const f=await s.get("/amadeus/vaults");let k=null;try{k=localStorage.getItem(t)}catch{}if(k&&!f.vaults.some(F=>F.id===k))try{if((await s.get("/amadeus/shared-with-me")).items.some(M=>M.vaultId===k))return a=k,k}catch{}return a=((k?f.vaults.find(F=>F.id===k):void 0)??f.vaults.find(F=>F.id==="default")??f.vaults[0])?.id??"default",a})(),r.catch(()=>{r=null}),r)}ti=c,e.signal&&hs([]);const d=50,u=new Map,p=(f,k)=>{u.delete(f),u.set(f,k),u.size>d&&u.delete(u.keys().next().value)},h=new Map,m=new Map,g=(f,k)=>{const x=m.get(f);return x&&x.seq===k&&h.get(f)===k?x.fp:void 0},y=new Set,b=new Map,C=new Set;class S extends Error{constructor(k){super(`vanished elsewhere: ${k}`),this.path=k}path}const T=(f,k)=>{h.set(f,k),y.add(f),b.delete(f)},O=f=>{h.delete(f),u.delete(f),y.delete(f)},v=(f,k,x)=>{const F=x??h.get(f);h.delete(f),F!==void 0&&(h.set(k,F),y.add(k)),u.delete(f),u.delete(k)},I=async f=>{const k=W(f);return k!==f&&!C.has(f)&&(C.add(f),At(ie("amxbridge.renamedElsewhere",{name:k.split("/").pop()}))),{target:k,base:await le(k)}},P=f=>{C.has(f)||(C.add(f),At(ie("amxbridge.deletedElsewhere"),!0))},W=f=>{let k=f;const x=new Set([f]);for(let F=0;F<16;F++){const M=b.get(k);if(!M||x.has(M))break;x.add(M),k=M}return k},L=f=>{const k=W(f);return k===f?[f]:[f,k]},U=f=>{for(const k of[...b.keys()])W(k)===f&&b.delete(k)},B=(f,k,x)=>f.includes(k)?x():ne([k],x),ee=async(f,k,x)=>{if(!x)return P(f),null;const F=new Date,M=V=>String(V).padStart(2,"0"),N=`${F.getFullYear()}-${M(F.getMonth()+1)}-${M(F.getDate())} ${M(F.getHours())}${M(F.getMinutes())}`,j=f.replace(/\.md$/i,"");for(let V=0;V<5;V++){const G=`${j} (recovered ${N}${V?`-${V+1}`:""}).md`;try{await K(G,k,0)}catch(Z){if(Te(Z))continue;throw Z}return b.set(f,G),ce(),C.has(f)||(C.add(f),At(ie("amxbridge.deletedElsewhereSaved",{name:G.split("/").pop()}),!0)),G}throw P(f),new S(f)},ae=(f,k)=>{const x=`${f}/`;for(const[F,M]of[...h])F.startsWith(x)&&(h.delete(F),h.set(`${k}/${F.slice(x.length)}`,M));for(const F of[...u.keys()])F.startsWith(x)&&u.delete(F);for(const F of[...y]){if(!F.startsWith(x)||b.has(F))continue;const M=`${k}/${F.slice(x.length)}`;y.add(M),b.set(F,M)}},te=f=>{const k=`${f}/`;for(const x of[...h.keys()])(x===f||x.startsWith(k))&&h.delete(x);for(const x of[...u.keys()])(x===f||x.startsWith(k))&&u.delete(x);for(const x of[...y])(x===f||x.startsWith(k))&&(y.delete(x),U(x))},ue=f=>{const k=`${f}/`;for(const x of[...h.keys()])(x===f||x.startsWith(k))&&(h.delete(x),u.delete(x),U(x))},he=6e4;let be=null;const ce=()=>{be=null};async function A(f=!1){const k=Date.now();if(!f&&be&&(!be.settled||k-be.at<he))return be.promise;const x=await c(),F={at:Date.now(),promise:s.get(`/amadeus/vaults/${encodeURIComponent(x)}/tree`),settled:!1};return be=F,F.promise.then(M=>{F.settled=!0,E(x,M),window.amadeusCloudMaxFileBytes=M.maxFileBytes},()=>{be===F&&(be=null)}),F.promise}const E=(f,k)=>{try{localStorage.setItem(n,JSON.stringify({v:f,tree:k}))}catch{}},_=()=>{try{const f=localStorage.getItem(n);if(!f)return null;const k=JSON.parse(f);if(typeof k.v!="string"||!k.tree||!Array.isArray(k.tree.pages)||!Array.isArray(k.tree.files)||!Array.isArray(k.tree.folders))return null;const x=localStorage.getItem(t);return x&&x!==k.v?null:k}catch{return null}},w=f=>[...f.pages,...f.files.map(k=>k.path)],$=f=>!f.split("/").some(k=>k.startsWith(".")),q=f=>{const k=e.pluginExts?.()??[];if(!k.length)return!1;const x=f.toLowerCase();return k.some(F=>x.endsWith(F))},H=f=>$(f)&&!q(f),X=new Map;function ne(f,k){const F=Promise.allSettled(f.map(N=>X.get(N)??Promise.resolve())).then(()=>k()),M=F.then(()=>{},()=>{});for(const N of f)X.set(N,M);return M.then(()=>{for(const N of f)X.get(N)===M&&X.delete(N)}),F}const ge=new Set,ye=new Set,We=new Set,Ce=f=>{for(const k of[...ge])try{k(f)}catch{}},De=()=>{for(const f of[...ye])try{f()}catch{}},Xt=f=>{for(const k of[...We])try{k(f)}catch{}},en=new Set,jn=f=>{for(const k of[...en])try{k(f)}catch{}};let et=null;const Bn=(f=l())=>`${i}:${f}`,gt=f=>{et=f;try{localStorage.setItem(Bn(),f)}catch{}},gi=()=>{try{return localStorage.getItem(Bn())||void 0}catch{return}};let Un="",mt=null;async function tn(){if(!e.signal?.aborted){mt&&(clearTimeout(mt),mt=null);try{const f=await c(),k=await s.post(`/amadeus/vaults/${encodeURIComponent(f)}/asset-token`);if(e.signal?.aborted)return;Un=k.token;const x=Math.max(60,k.ttlSec||600);mt=setTimeout(()=>{tn()},x/2*1e3)}catch{e.signal?.aborted||(mt=setTimeout(()=>{tn()},3e4))}}}j1({apiBase:e.apiBase,vaultId:l,assetToken:()=>Un,activePage:()=>et}),window.amadeusCloudVaults=async()=>{const f=await A();return kx([...f.pages,...f.files.map(k=>k.path)])},window.amadeusCloudVaultDevices=async f=>{const k=await c(),x=Object.create(null);return await Promise.all(f.map(async F=>{try{const M=await s.get(`/amadeus/vaults/${encodeURIComponent(k)}/file`,{path:bx(F)}),N=yx(M.content);N?.length&&(x[F]=N)}catch{}})),x};let jt=null;e.signal?.addEventListener("abort",()=>{mt&&clearTimeout(mt),mt=null,Un="",jt?.(),jt=null,ti===c&&(ti=null,hs([]))},{once:!0});function mi(f){jt||e.signal?.aborted||(jt=o1({signal:e.signal,url:()=>`${e.apiBase}/amadeus/vaults/${encodeURIComponent(f)}/events?token=${encodeURIComponent(e.getToken())}`,clientId:o,knownSeq:k=>h.get(k),lastLoadedPage:()=>et,openPages:Hd,onPageChange:k=>{u.delete(k),Ce(k)},onDbChange:k=>Xt(k),onPageMoved:(k,x,F,M)=>{b.set(k,x),v(k,x,F??void 0),M||jn({from:k,kind:"file",to:x,root:`cloud://${f}`})},onPageDeleted:k=>{h.delete(k),u.delete(k),U(k)},onFolderMoved:(k,x,F)=>{ae(k,x),F||jn({from:k,kind:"prefix",to:x,root:`cloud://${f}`})},onFolderDeleted:k=>ue(k),onStructureChange:()=>{ce(),u.clear(),De()},onPresence:R1,onPresenceRoster:hs}),window.addEventListener("beforeunload",()=>{jt?.()}))}const R=()=>`/amadeus/vaults/${encodeURIComponent(l())}/file`,z=async f=>{const k=await s.get(R(),{path:f});return T(f,k.seq),m.set(f,{seq:k.seq,fp:cn(k.content)}),k},K=async(f,k,x,F=!1)=>{const M=await s.put(R(),{path:f,content:k,baseSeq:x,...F?{force:!0}:{}});return T(f,M.seq),m.set(f,{seq:M.seq,fp:cn(k)}),u.delete(f),M},le=async f=>{const k=h.get(f);if(k!==void 0)return k;try{return(await z(f)).seq}catch(x){if(!Ne(x))throw x;if(y.has(f))throw new S(f);return 0}},pe=async f=>{const k=await z(f),x=ji(f,k.content,Ri());return p(f,x),x},Ye=async f=>{try{const k=h.get(f),x=await z(f);if(x.seq===k)return;p(f,ji(f,x.content,Ri())),Ce(f)}catch{}},ft=async f=>{const k=[],F=await YS({readFile:async()=>{throw new Error("not found")},writeFile:async(M,N)=>{k.push({name:M,data:N})},deleteFile:async()=>{},exists:async()=>!1,listDir:async()=>[]},f,Ri());for(const M of k){const N=Hi(Ct(f),M.name);try{await K(N,M.data,0)}catch(j){if(Te(j))return pe(N);throw j}}return ce(),p(f,F),F},tt=async f=>{try{return await pe(f)}catch(k){if(Ne(k)){if(y.has(f))throw new S(f);return ft(f)}throw k}};async function xt(f,k){const x=bl(k);if(!x)return[];if(x.includes("/")){const N=it(Hi(Ct(f),wl(x))),j=it(wl(x));return[...new Set([N,j])].filter(V=>!!V)}const F=await A(),M=yl(w(F),x)??yl(w(await A(!0)),x);return M?[M]:[]}const Je=async(f,k,x,F,M,N)=>{const j=new FormData;j.append("file",new Blob([x]),k),j.append("path",f),F&&j.append("ifAbsent","1"),N!==void 0&&j.append("baseSeq",String(N));const V=await s.postForm(`/amadeus/vaults/${encodeURIComponent(l())}/binary`,j,M);return T(V.path??f,V.seq),ce(),V},Me=async f=>{const k=await c();for(let x=0;;x++){const F=new AbortController,M=setTimeout(()=>F.abort(),3e4);let N;try{N=await(e.request??fetch)(`${e.apiBase}/amadeus/vaults/${encodeURIComponent(k)}/asset?ref=${encodeURIComponent(`${f}/`)}`,{headers:{Authorization:`Bearer ${e.getToken()}`},signal:F.signal})}catch(j){throw new Re(0,null,F.signal.aborted?ie("amxbridge.timeout",{s:30}):ie("amxbridge.network",{msg:j instanceof Error?j.message:String(j)}))}finally{clearTimeout(M)}if(N.ok)return N;if(N.status!==404)throw new Re(N.status,null,ie("amxbridge.readFailed",{status:N.status}));try{await s.get(R(),{path:f})}catch(j){if(Ne(j))return null;if(!(j instanceof Re&&j.body?.code==="BINARY"))throw j}if(x>=1)throw new Error(ie("amxbridge.readFailed",{status:404}))}},nt=async f=>{const k=await Me(f);return k?new TextDecoder("utf-8",{ignoreBOM:!0}).decode(await k.arrayBuffer()):null},ut=(f,k,x)=>{const F=it(f.replace(/\\/g,"/"))?.normalize("NFC");return F?ne([F],async()=>{await c();const M=new TextEncoder().encode(k),N=Qe(F),j=async Z=>{if(!Te(Z))throw Z;return{ok:!1,current:await nt(F)}};if(x?.create)return Je(F,N,M,!0).then(()=>({ok:!0}),j);if(typeof x?.base!="string"){await Je(F,N,M,!1);return}const V=(await A(!0)).entries?.find(Z=>Z.path===F)?.seq??0,G=await nt(F);return cn(G??"")!==x.base?{ok:!1,current:G}:Je(F,N,M,!1,void 0,V).then(()=>({ok:!0}),j)}):Promise.reject(new Error(ie("amxbridge.pathOutsideVault")))},Oe=".trash",wt=`${Oe}/.meta.json`,nn=Qe(wt),Ra=f=>{try{const k=JSON.parse(f.replace(/^\uFEFF/,""));return!k||typeof k!="object"||Array.isArray(k)?null:Object.values(k).every(x=>!!x&&typeof x.original=="string")?k:null}catch{return null}},Yd=async()=>{const f=await nt(wt);return(f?Ra(f):null)??{}},fi=f=>ne([wt],async()=>{let k=h.get(wt)??(await A()).entries?.find(x=>x.path===wt)?.seq??0;for(let x=0;;x++){const F=await nt(wt);let M=F?Ra(F):{};M||(await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:wt,to:`${Oe}/${Date.now().toString(36)}-${nn}`}).catch(j=>{if(!Ne(j))throw j}),h.delete(wt),ce(),M={},k=0);const N=JSON.stringify(M);if(f(M),JSON.stringify(M)===N)return;try{await Je(wt,nn,new TextEncoder().encode(`${JSON.stringify(M,null,2)}
3398
- `),!1,void 0,k);return}catch(j){if(!Te(j)||x>=3)throw j;k=Number(j.body?.seq)||0}}}),Da=async f=>w(f).includes(wt)?Yd():{},wi=f=>{const k=new Set;for(const x of[...w(f),...f.folders])x.startsWith(`${Oe}/`)&&k.add(x.slice(Oe.length+1).split("/")[0]);return k.delete(nn),k},$a=(f,k,x)=>{if(!wi(f).has(x))return null;const F=f.folders.includes(`${Oe}/${x}`);return Object.prototype.hasOwnProperty.call(k,x)?{...k[x],dir:F}:{original:x,deletedAt:0,dir:F}};let Jd=0,bi=null;const za=async()=>{const f=_();if(f){await tn(),(async()=>{for(let V=0;;V++){if(e.signal?.aborted)return;try{const G=await c();await A(!0),mi(G),De();return}catch{if(e.signal?.aborted)return;if(V>=2){At(ie("amxbridge.connectFailed"),!0);return}await new Promise(G=>{const Z=()=>{clearTimeout(Pe),e.signal?.removeEventListener("abort",Z),G()},Pe=setTimeout(Z,[3e3,1e4][V]);e.signal?.addEventListener("abort",Z,{once:!0}),e.signal?.aborted&&Z()})}}})();let N;try{N=localStorage.getItem(Bn(f.v))||void 0}catch{}const j=f.tree.pages.filter(H);return{root:`cloud://${f.v}`,pages:j,folders:f.tree.folders.filter($),lastPage:N&&j.includes(N)?N:void 0}}const k=await c(),[x]=await Promise.all([A(!0),tn()]);mi(k);const F=gi(),M=x.pages.filter(H);return{root:`cloud://${k}`,pages:M,folders:x.folders.filter($),lastPage:F&&M.includes(F)?F:void 0}},Qd=(f,k,x)=>ne([f],async()=>{await c();for(let F=0;F<3;F++){let M;try{M=await z(f)}catch(N){if(Ne(N))return"gone";throw N}if(cn(M.content)!==x)return{ok:!1,current:M.content};try{return await K(f,k,M.seq),{ok:!0}}catch(N){if(!Te(N))throw N}}throw new Error("conflict")}),Hn=async(f,k,x)=>{let F=null;const M=await OA({exists:async N=>(await(F??=A(!0).then(j=>new Set(j.files.map(V=>V.path))))).has(N),read:async N=>{try{return(await z(N)).content}catch(j){if(Ne(j))return null;throw j}},write:Qd},f,k,{folder:x});for(const N of M.rewritten)Ce(N);t1(M.failed.map(N=>N.path))},ja=(f,k)=>f.pages.some(x=>x.startsWith(`${k}/`))||f.files.some(x=>x.path.startsWith(`${k}/`)),Ba=(f,k,x)=>{const F=`${k}/`,M={};for(const N of f)N.startsWith(F)&&(M[N]=`${x}/${N.slice(F.length)}`);return M};return LA({openVault:()=>za(),restoreVault:()=>za(),listPages:async()=>(await A()).pages.filter(H),listFiles:async()=>{const f=await A(),k=f.files.map(F=>F.path).filter($),x=f.pages.filter(F=>$(F)&&q(F));return x.length?[...k,...x].sort():k},listFolders:async()=>(await A()).folders.filter($),loadPage:async f=>{await c();const k=u.get(f);if(k)return gt(f),Ye(f),k;const x=await tt(f);return gt(f),x},readPage:async f=>{await c();try{return await pe(f)}catch(k){throw Ne(k)?new Error(`note not found: ${f}`):k}},newPage:async f=>{await c();const k=await ne([f],()=>ft(f));return gt(f),k},savePage:(f,k,x)=>{const F=L(f);return ne(F,async()=>{await c();const M=_s(k,x),N=Object.values(x).some(G=>typeof G=="string"&&G.trim().length>0);let j,V;try{({target:j,base:V}=await I(f))}catch(G){if(G instanceof S){await ee(f,M,N);return}throw G}await B(F,j,async()=>{try{await K(j,M,V),p(j,ji(j,M,Ri()))}catch(G){if(Te(G)){const Z=G.body;if(Z?.code==="CONFLICT"&&Z.seq===0){h.delete(j),await ee(f,M,N);return}Z&&typeof Z.seq=="number"&&T(j,Z.seq),u.delete(f),At(ie("amxbridge.conflictReloaded"),!0),setTimeout(()=>Ce(f),0);return}throw G instanceof Re&&G.status===413&&At(ie("amxbridge.tooLarge"),!0),G}})})},renamePage:(f,k,x,F)=>{let M=null;return ne([f,Di(f,k,ie("amxbridge.pageNameEmpty"))],async()=>{await c();const N=Di(f,k,ie("amxbridge.pageNameEmpty"));if(N===f)return{newPath:f,page:await pe(f)};const j=await A(!0);if(M=j.pages.filter(H),w(j).includes(N)||j.folders.includes(N))throw new Error(ie("amxbridge.pageExists"));const V=_s(x,F);await K(f,V,await le(f),!0);let G;try{G=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:f,to:N})}catch(Z){throw Te(Z)?new Error(ie("amxbridge.pageExists")):Z}return v(f,N,G.seq),ce(),gt(N),{newPath:N,page:null}}).then(async N=>N.page?{newPath:N.newPath,page:N.page}:(M&&await Hn({[f]:N.newPath},M),{newPath:N.newPath,page:await pe(N.newPath)}))},reconcilePage:async f=>(await c(),tt(f)),saveAsset:async(f,k,x,F)=>{await c();const M=Ds(k),N=(M||".png").toLowerCase().replace(/[^.a-z0-9]/g,""),j=Qe(k).slice(0,Qe(k).length-M.length).replace(/[^a-zA-Z0-9_-]/g,"").slice(0,24)||"img";for(let V=0;V<5;V++){const G=`${j}-${Date.now().toString(36)}-${(Jd++).toString(36)}${N||".png"}`,Z=it(Hi(Ct(f),`.amadeus/${G}`));if(Z===null)throw new Error("Asset escapes vault");try{return await Je(Z,G,x,!0,F),`.amadeus/${G}`}catch(Pe){if(Te(Pe))continue;throw Pe}}throw new Error(ie("amxbridge.imageNameFailed"))},saveAttachment:async(f,k,x,F,M)=>{await c();const N=(Qe(k)||"file").replace(/[\\/]/g,""),{destDirRel:j}=kl(f,N,F),V=await A(!0),G=new Set(w(V).filter(Ae=>Ct(Ae)===j).map(Ae=>Qe(Ae).toLowerCase()));let Z=vl(G,N);const Pe=cs(N);for(let Ae=0;Ae<20;Ae++){const{fileVaultRel:Ft,pageRel:on}=kl(f,Z,F),Mo=it(Ft);if(Mo===null)throw new Error("Asset escapes vault");try{return Pe?await K(Mo,new TextDecoder().decode(x),0):await Je(Mo,Z,x,!0,M),{pageRel:on,base:Z}}catch(Ua){if(Te(Ua)){G.add(Z.toLowerCase()),Z=vl(G,N);continue}throw Ua}}throw new Error(ie("amxbridge.attachmentNameFailed"))},openAttachment:async(f,k)=>{await c(),window.open(po(bl(k),f),"_blank","noopener")},openVaultFile:async f=>{await c(),window.open(po(f,null),"_blank","noopener")},exportPdf:async()=>(window.print(),null),onExternalChange:f=>(ge.add(f),()=>{ge.delete(f)}),onStructureChange:f=>(ye.add(f),()=>{ye.delete(f)}),onDbExternalChange:f=>(We.add(f),()=>{We.delete(f)}),onPathGone:f=>(en.add(f),()=>{en.delete(f)}),search:async f=>(await c(),(await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/search`,{q:f})).filter(x=>$(x.path))),backlinks:async f=>(await c(),s.get(`/amadeus/vaults/${encodeURIComponent(l())}/backlinks`,{path:f})),reindex:async()=>{await c(),await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/reindex`)},listTags:async()=>(await c(),s.get(`/amadeus/vaults/${encodeURIComponent(l())}/tags`)),pagesByTag:async f=>(await c(),(await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/tags/pages`,{tag:f})).paths),resolveEmbed:async(f,k)=>{await c();const{note:x,subpath:F}=hA(f),M=(await A()).pages.filter(H).sort(),N=x?Ui(x,M,k):k&&M.includes(k)?k:null;if(N){let G=null;try{G=(await z(N)).content}catch(Z){if(!Ne(Z))throw Z}if(G!=null){if(!F)return{owner:N,content:Qr(G),type:"markdown"};const Z=Ld(G,F.trim().replace(/\.block$/i,"").toLowerCase())??yA(Qr(G),F);return Z==null?null:{owner:N,content:Z,type:"markdown"}}}const j=F?`${x}#${F}`:x;return j?await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/embed`,{target:j})??null:null},blockBacklinks:async f=>(await c(),s.get(`/amadeus/vaults/${encodeURIComponent(l())}/block-backlinks`,{target:f})),deletePage:f=>ne([f],async()=>{await c(),await s.del(R(),{path:f}),O(f),ce()}),movePage:(f,k)=>{let x=null;return ne([f],async()=>{await c();const F=Bl(f),M=k.replace(/\\/g,"/").replace(/^\/+|\/+$/g,""),N=M?`${M}/${F}`:F;if(N===f)return f;N.endsWith(".md")&&(x=(await A(!0)).pages.filter(H));let j;try{j=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:f,to:N})}catch(V){throw Te(V)?new Error(ie("amxbridge.fileExistsAtTarget")):V}return v(f,N,j.seq),ce(),N.endsWith(".md")&&gt(N),N}).then(async F=>(F!==f&&x&&await Hn({[f]:F},x),F))},createFolder:async(f,k)=>{await c();const x=k.trim().replace(/[\\/]/g,"");if(!x)throw new Error(ie("amxbridge.folderNameEmpty"));const F=f.replace(/\\/g,"/").replace(/^\/+|\/+$/g,"");try{const M=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders`,{parent:F,name:x});return ce(),M.path}catch(M){throw Te(M)?new Error(ie("amxbridge.folderExists")):M}},renameFolder:async(f,k)=>{await c();const x=k.trim().replace(/[\\/]/g,"");if(!x)throw new Error(ie("amxbridge.folderNameEmpty"));const F=Ct(f);if((F?`${F}/${x}`:x)===f)return f;const N=await A(!0),j=N.pages.filter(H),V=ja(N,f);let G;try{G=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/rename`,{path:f,newName:x})}catch(Z){throw Te(Z)?new Error(ie("amxbridge.folderExists")):Z}return ae(f,G.path),et&&et.startsWith(`${f}/`)&&gt(`${G.path}${et.slice(f.length)}`),ce(),await Hn(Ba(j,f,G.path),j,V?[f,G.path]:void 0),G.path},deleteFolder:async f=>{await c(),await s.del(`/amadeus/vaults/${encodeURIComponent(l())}/folders`,{path:f}),te(f),ce()},moveFolder:async(f,k)=>{await c();const x=f.replace(/\\/g,"/").replace(/^\/+|\/+$/g,""),F=Qe(x);if(!F)throw new Error(ie("amxbridge.folderPathEmpty"));const M=k.replace(/\\/g,"/").replace(/^\/+|\/+$/g,"");if((M?`${M}/${F}`:F)===x)return x;if(M===x||M.startsWith(`${x}/`))throw new Error(ie("amxbridge.moveIntoSelf"));const j=await A(!0),V=j.pages.filter(H),G=ja(j,x);let Z;try{Z=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/move`,{path:x,dest:M})}catch(Pe){throw Te(Pe)?new Error(ie("amxbridge.folderExistsAtTarget")):Pe}return ae(x,Z.path),et&&et.startsWith(`${x}/`)&&gt(`${Z.path}${et.slice(x.length)}`),ce(),await Hn(Ba(V,x,Z.path),V,G?[x,Z.path]:void 0),Z.path},trashEntry:async f=>{await c();const k=f.replace(/\\/g,"/").replace(/^\/+|\/+$/g,"");if(!k||k===Oe||k.startsWith(`${Oe}/`))throw new Error(ie("amxbridge.invalidPath"));const x=await A(!0),F=x.folders.includes(k),M=Date.now().toString(36);try{if(F){let N=k,j=Qe(k);if(j===nn||x.folders.includes(`${Oe}/${j}`)){const V=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/rename`,{path:k,newName:`${j} (${M})`});N=V.path,j=Qe(V.path)}await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/move`,{path:N,dest:Oe}),te(k),await fi(V=>{V[j]={original:k,deletedAt:Date.now(),dir:!0}})}else{let N=k.replace(/\//g,"__");(N===nn||w(x).includes(`${Oe}/${N}`))&&(N=`${M}-${N}`),await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:k,to:`${Oe}/${N}`}),O(k),await fi(j=>{j[N]={original:k,deletedAt:Date.now(),dir:!1}})}}finally{ce()}},listTrash:async()=>{await c();const f=await A(),k=await Da(f);return[...wi(f)].map(x=>({name:x,...$a(f,k,x)})).sort((x,F)=>F.deletedAt-x.deletedAt)},restoreTrash:async f=>{await c();const k=await A(!0),x=$a(k,await Da(k),f);if(!x)throw new Error(ie("amxbridge.trashMissing"));const F=N=>w(k).includes(N)||k.folders.includes(N);let M=x.original;for(let N=2;F(M);N++)if(x.dir)M=`${x.original} (${N})`;else{const j=Ds(x.original);M=`${x.original.slice(0,x.original.length-j.length)} (${N})${j}`}if(x.dir){const N=`${Oe}/${f}`,j=Qe(M),V=Ct(M),G=(Z,Pe)=>s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/${Z}`,Pe);f===j?await G("move",{path:N,dest:V}):j!==nn&&!wi(k).has(j)?await G("move",{path:(await G("rename",{path:N,newName:j})).path,dest:V}):(await G("move",{path:N,dest:V}),await G("rename",{path:V?`${V}/${f}`:f,newName:j}))}else await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:`${Oe}/${f}`,to:M});return await fi(N=>{delete N[f]}),ce(),M},deleteTrashEntry:async f=>{await c();const k=await A(!0);wi(k).has(f)&&(k.folders.includes(`${Oe}/${f}`)?await s.del(`/amadeus/vaults/${encodeURIComponent(l())}/folders`,{path:`${Oe}/${f}`}).catch(x=>{if(!Ne(x))throw x}):await s.del(R(),{path:`${Oe}/${f}`}).catch(x=>{if(!Ne(x))throw x})),await fi(x=>{delete x[f]}),ce()},emptyTrash:async()=>{await c(),await s.del(`/amadeus/vaults/${encodeURIComponent(l())}/folders`,{path:Oe}).catch(f=>{if(!Ne(f))throw f}),te(Oe),ce()},saveVaultBytes:async(f,k)=>{await c();const x=it(f.replace(/\\/g,"/"));if(!x)throw new Error(ie("amxbridge.pathOutsideVault"));await Je(x,Qe(x),k,!1)},readVaultBytes:async f=>{const k=it(f.replace(/\\/g,"/")),x=k?await Me(k):null;if(!x)throw new Error(ie("amxbridge.readFailed",{status:404}));return new Uint8Array(await x.arrayBuffer())},fetchLinkMeta:async f=>{try{return await s.get("/amadeus/link-meta",{url:f})}catch{return null}},searchImages:async f=>{const k=f.trim();if(!k)return[];const x=await fetch(`https://api.openverse.org/v1/images/?q=${encodeURIComponent(k)}&page_size=20`,{headers:{accept:"application/json"}});if(!x.ok)throw new Error(`openverse HTTP ${x.status}`);return((await x.json()).results??[]).map(M=>({thumb:M.thumbnail??"",full:M.url??"",author:M.creator})).filter(M=>M.thumb&&M.full)},listPlugins:async()=>[],openPluginsFolder:async()=>{At(ie("amxbridge.desktopOnly"))},scaffoldSamplePlugin:async()=>{At(ie("amxbridge.desktopOnly"))},revealInFileManager:async()=>{At(ie("amxbridge.desktopOnly"))},hostCaps:{revealInFileManager:!1},readDatabase:async(f,k)=>{await c();for(const x of await xt(f,k)){let F;try{F=await z(x)}catch(N){if(Ne(N))continue;if(N instanceof Re&&N.status===400)return{status:"corrupt",path:x,message:ie("amxbridge.notText")};throw N}const M=Ou(F.content);return M.ok?{status:"ok",path:x,data:M.data}:{status:"corrupt",path:x,message:M.error}}return{status:"missing"}},writeDatabase:(f,k)=>ne([f],async()=>{await c();const x=Fu.parse(k),F=Tx(x),M=await le(f);try{await K(f,F,M)}catch(N){if(Te(N)){try{await z(f)}catch{}setTimeout(()=>Xt(f),0);return}throw N}}),readDrawing:async(f,k)=>{await c();const x=await xt(f,k),F=x.length?x:await xt(f,`${k}.md`);for(const M of F.flatMap(N=>N.endsWith(".md")?[N]:[N,`${N}.md`]))try{const N=await z(M);return{status:"ok",path:M,source:N.content}}catch(N){if(!Ne(N))throw N}return{status:"missing"}},writeDrawing:(f,k)=>ne([f],async()=>{await c();const x=await le(f);try{await K(f,k,x)}catch(F){if(!Te(F))throw F;try{const N=await z(f),j=nl(k),V=nl(N.content),G=j?JSON.parse(j.sceneJson):null,Z=V?JSON.parse(V.sceneJson):null;if(G&&Z){const Pe=Ex(N.content,JSON.stringify(Lx(G,Z)));if(Pe){await K(f,Pe,N.seq);return}}}catch{}const M=F.body;M&&typeof M.seq=="number"&&T(f,M.seq),await K(f,k,h.get(f)??0,!0)}}),readTextFile:async f=>{if(await c(),!cs(f)){const k=it(f.replace(/\\/g,"/"));return k?nt(k):null}try{return(await z(f)).content}catch(k){if(Ne(k))return null;throw k}},writeTextFile:(f,k,x)=>{if(!cs(f))return ut(f,k,x);const F=L(f),M=typeof x?.base=="string"?x.base:null,N=()=>M!=null?{ok:!0}:void 0;return ne(F,async()=>{if(await c(),x?.create){try{return await K(f,k,0),b.delete(f),ce(),{ok:!0}}catch(Z){if(!Te(Z))throw Z}try{return{ok:!1,current:(await z(f)).content}}catch(Z){if(Ne(Z))return{ok:!1,current:null};throw Z}}const j=k.trim().length>0;let V,G;try{({target:V,base:G}=await I(f))}catch(Z){if(Z instanceof S)return await ee(f,k,j),N();throw Z}if(M!=null){const Z=M;return B(F,V,async()=>{const Pe=async()=>{let Ae;try{Ae=await z(V)}catch(Ft){if(Ne(Ft))return"vanished";throw Ft}return cn(Ae.content)===Z?Ae.seq:{ok:!1,current:Ae.content}};if(G>0&&g(V,G)!==Z){const Ae=await Pe();if(Ae==="vanished")return await ee(f,k,j),N();if(typeof Ae!="number")return Ae;G=Ae}for(let Ae=0;;Ae++)try{return await K(V,k,G),{ok:!0}}catch(Ft){if(!Te(Ft))throw Ft;const on=await Pe();if(on==="vanished")return await ee(f,k,j),N();if(typeof on!="number")return on;if(Ae>=2)throw Ft;G=on}})}await B(F,V,async()=>{try{await K(V,k,G)}catch(Z){if(!Te(Z))throw Z;let Pe;try{Pe=await z(V)}catch(Ae){if(Ne(Ae)){await ee(f,k,j);return}throw Ae}await K(V,k,Pe.seq,!0)}})})},listPageProps:async f=>(await c(),(await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/page-props`,{folder:f})).map(x=>({path:x.path,title:x.title,fm:gl(x.fmExtra||"")}))),pageIcons:async()=>{await c();const f=await A();if(bi&&bi.seq===f.seq)return bi.icons;const k=await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/page-props`,{folder:"",all:"1"}),x={};for(const F of k){const M=gl(F.fmExtra||"").icon;typeof M=="string"&&M&&(x[F.path]=M)}return bi={seq:f.seq,icons:x},x},setPageFrontmatter:(f,k)=>ne([f],async()=>{await c();const x=async()=>{let F;try{F=await z(f)}catch(N){if(Ne(N))return"ok";throw N}const M=V0(F.content,k);if(M===F.content)return"ok";try{return await K(f,M,F.seq),"ok"}catch(N){if(Te(N))return"conflict";throw N}};if(await x()==="conflict")try{await x()}catch{}}),renamePageFile:(f,k)=>{let x=null;return ne([f,Di(f,k,ie("amxbridge.noteNameEmpty"))],async()=>{await c();const F=Di(f,k,ie("amxbridge.noteNameEmpty"));if(F===f)return f;x=(await A(!0)).pages.filter(H);let M;try{M=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:f,to:F})}catch(N){throw Te(N)?new Error(ie("amxbridge.noteExists")):N}return v(f,F,M.seq),ce(),F}).then(async F=>(F!==f&&x&&await Hn({[f]:F},x),F))},renameDbFile:(f,k)=>ne([f],async()=>{await c();const x=f.replace(/\\/g,"/");let F=k.trim().replace(/[\\/]/g,"");if(F.toLowerCase().endsWith(".db")&&(F=F.slice(0,-3)),!F)throw new Error(ie("amxbridge.nameEmpty"));const M=Ct(x),N=M?`${M}/${F}.db`:`${F}.db`;if(N===x)return{newPath:N,rewrittenPages:[]};let j;try{j=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:x,to:N})}catch(V){throw Te(V)?new Error(ie("amxbridge.fileExists")):V}return v(x,N,j.seq),ce(),{newPath:N,rewrittenPages:[]}})})}function Di(e,t,n){const i=Ct(e);let o=t.trim().replace(/[\\/]/g,"");if(!o)throw new Error(n);return o.toLowerCase().endsWith(".md")&&(o=o.slice(0,-3)),i?`${i}/${o}.md`:`${o}.md`}const W1=async e=>{if(!e.ok){let t=null;try{t=await e.json()}catch{}const n=new Error(t?.detail||`http ${e.status}`);throw n.status=e.status,n.code=t?.code,n}return e.json()};function q1(e){const t=$i(Zd),n=e.getToken(),i=ni(e.apiBase,n),o=()=>{const g=e.getToken();if(e.signal?.aborted||!g||(i?ni(e.apiBase,g)!==i:g!==n))throw new Error("Cloud account changed");return g},s=async(g,y,b)=>{const C=o(),S=new AbortController,T=()=>S.abort(e.signal?.reason);e.signal?.addEventListener("abort",T,{once:!0});const O=setTimeout(()=>S.abort(),2e4);try{const v=await W1(await(e.request??fetch)(`${e.apiBase}/amadeus${y}`,{method:g,headers:{Authorization:`Bearer ${C}`,...b!==void 0?{"Content-Type":"application/json"}:{}},body:b!==void 0?JSON.stringify(b):void 0,signal:S.signal}));return o(),v}finally{clearTimeout(O),e.signal?.removeEventListener("abort",T)}},a=()=>U1();let r=e.linkBase?.replace(/\/+$/,"")||null;const l=async()=>{if(r)return r;try{r=((await s("GET","/collab/link-base")).webOrigin??"").trim().replace(/\/+$/,"")||location.origin}catch{r=location.origin}return r},c=()=>r??location.origin;e.signal?.aborted||l();const d=()=>{if(o(),e.getUserId)return e.getUserId();try{const g=e.getToken().split(".")[1],y=JSON.parse(atob(g.replace(/-/g,"+").replace(/_/g,"/")));return typeof y.userId=="string"?y.userId:null}catch{return null}};let u=null,p=null;const h=()=>{u&&(clearInterval(u),u=null)};e.signal?.addEventListener("abort",h,{once:!0});const m=()=>{e.signal?.aborted||a().then(g=>s("POST",`/vaults/${encodeURIComponent(g)}/presence`,{page:p})).catch(()=>{})};window.amadeusCollab={listVaults:()=>s("GET","/vaults").then(g=>g.vaults),activeVaultId:a,switchVault(g){o();try{localStorage.setItem(t,g)}catch{}location.reload()},pageShare:async g=>s("GET",`/vaults/${encodeURIComponent(await a())}/page-shares?path=${encodeURIComponent(g)}`),createPageShare:async(g,y)=>s("POST",`/vaults/${encodeURIComponent(await a())}/page-shares`,{path:g,...y}),updatePageShare:async(g,y)=>s("PATCH",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}`,y),revokePageShare:async g=>{await s("DELETE",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}`)},setParticipantRole:async(g,y,b)=>{await s("PATCH",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}/members/${encodeURIComponent(y)}`,{role:b})},removeParticipant:async(g,y)=>{await s("DELETE",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}/members/${encodeURIComponent(y)}`)},sharedWithMe:()=>s("GET","/shared-with-me").then(g=>g.items),leaveShare:async g=>{const y=d();y&&await s("DELETE",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}/members/${encodeURIComponent(y)}`)},inviteUrl:g=>`${c()}/invite/${g}`,publishes:async()=>s("GET",`/vaults/${encodeURIComponent(await a())}/shares`),createPublish:async(g,y)=>{const b=await s("POST",`/vaults/${encodeURIComponent(await a())}/shares`,{mode:g,path:y});return{...b,url:`${c()}/share/${b.token}`}},revokePublish:async g=>{await s("DELETE",`/vaults/${encodeURIComponent(await a())}/shares/${encodeURIComponent(g)}`)},publishUrl:g=>`${c()}/share/${g}`,revokePublishIn:async(g,y)=>{await s("DELETE",`/vaults/${encodeURIComponent(g)}/shares/${encodeURIComponent(y)}`)},revokePageShareIn:async(g,y)=>{await s("DELETE",`/vaults/${encodeURIComponent(g)}/page-shares/${encodeURIComponent(y)}`)},listAllShares:async()=>{const g=(await s("GET","/vaults")).vaults||[],y=d(),b=[],C=[];for(const S of g){try{const T=await s("GET",`/vaults/${encodeURIComponent(S.id)}/shares`);for(const O of T.shares||[])b.push({...O,vaultId:S.id,vaultName:S.name||""})}catch{}try{const T=await s("GET",`/vaults/${encodeURIComponent(S.id)}/page-shares`),O=T?.shares||T?.pageShares||(Array.isArray(T)?T:[]);for(const v of O){const I=v.created_by??v.createdBy;(!y||!I||I===y)&&C.push({...v,vaultId:S.id,vaultName:S.name||""})}}catch{}}return{publishes:b,pageShares:C,linkBase:await l()}},heartbeat(g){o(),p=g,m(),u||(u=setInterval(m,3e4))},stopHeartbeat:h,onPresence:g=>D1(g),myUserId:d}}Na({"unit.bootError.title":{zh:"暂时无法打开此 Unit",en:"Unable to open this Unit"},"unit.bootError.detail":{zh:"请检查连接后重试。",en:"Check your connection and try again."},"unit.bootError.retry":{zh:"重试",en:"Try again"}});function Kd(){const e=document.getElementById("root")??document.body.appendChild(document.createElement("main")),t=document.createElement("section");t.setAttribute("role","alert");const n=document.documentElement.dataset.mode==="dark";t.style.cssText='max-width:440px;margin:15vh auto;padding:24px;font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',t.style.color=`var(--text,${n?"#f2efe8":"#1c1c1c"})`,t.style.colorScheme=n?"dark":"light";const i=document.createElement("h1");i.textContent=ie("unit.bootError.title"),i.style.cssText="font-size:20px;font-weight:600;margin:0 0 8px";const o=document.createElement("p");o.textContent=ie("unit.bootError.detail"),o.style.cssText="margin:0 0 20px;color:var(--text-muted,inherit)";const s=document.createElement("button");s.type="button",s.textContent=ie("unit.bootError.retry"),s.style.cssText="font:inherit;padding:7px 16px;cursor:pointer",s.addEventListener("click",()=>location.reload()),t.append(i,o,s),e.replaceChildren(t),s.focus()}function V1(e,t){if(e.origin!==t.origin||!e.pathname.startsWith(t.pathname))return null;const n=/^(share|invite)\/([^/]+)\/?$/.exec(e.pathname.slice(t.pathname.length));return n?{kind:n[1],token:decodeURIComponent(n[2])}:null}const Fl=()=>yt(async()=>{const{useApp:e}=await import("./appStore-DDOkzWDA.js").then(t=>t.rF);return{useApp:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]),import.meta.url).then(({useApp:e})=>{B1((t,n)=>e.getState().toast(t,n))}),G1={mobile:()=>yt(()=>import("./mobileEntry-BnHzrdoC.js"),__vite__mapDeps([10,3,11,2,1,4,12,13,0,5,6,7,8,9,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]),import.meta.url),desktop:()=>yt(()=>import("./main-B9aT0WXG.js"),__vite__mapDeps([91,3,11,2,1,4,12,13,0,5,6,7,8,9,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,92]),import.meta.url)};function Ol(e){return G1[e?"mobile":"desktop"]()}async function Z1(){const e=location.pathname;if(window.__FORSION_UNIT_PAGE__){const t=window.__FORSION_UNIT_PAGE__,n=new URL(".",document.baseURI),i=V1(new URL(location.href),n);if(i&&t.capabilities?.amadeus){const o=new URL(t.capabilities.amadeus.apiBase,location.origin).href.replace(/\/+$/,"");if(i.kind==="share"){const{mountSharePage:s}=await yt(async()=>{const{mountSharePage:a}=await import("./sharePage-CY04XCAf.js");return{mountSharePage:a}},[],import.meta.url);s(i.token,{apiBase:o})}else{if(!t.account)throw new Error("Invitations require an account provider");const{installUnitAccount:s}=await yt(async()=>{const{installUnitAccount:l}=await import("./unitAccount-DL3jfd84.js");return{installUnitAccount:l}},[],import.meta.url),a=await s({instanceId:t.instanceId,account:t.account},n);if(!a.account.getIdentity()){await a.login();return}const{mountInvitePage:r}=await yt(async()=>{const{mountInvitePage:l}=await import("./invitePage-iOT1zBvp.js");return{mountInvitePage:l}},__vite__mapDeps([93,3]),import.meta.url);r(i.token,{apiBase:o,getToken:a.account.getToken,request:a.capability.request,appBase:n.href})}return}yt(()=>import("./unitShim-Dl2ksNp-.js"),[],import.meta.url).then(async o=>{if(!await o.installUnitShim())return;let s=!1;try{s=(new URLSearchParams(location.search).get("ui")||localStorage.getItem("lcl.uiMode"))==="mobile"}catch{}await Ol(s),t.capabilities?.amadeus&&await Fl()}).catch(o=>{console.error("[unit-page] bootstrap failed:",o),Kd()})}else if(e.startsWith("/share/"))yt(()=>import("./sharePage-CY04XCAf.js"),[],import.meta.url).then(t=>t.mountSharePage(decodeURIComponent(e.slice(7)).replace(/\/+$/,""))).catch(t=>console.error("[tangu-web] share page failed:",t));else if(e.startsWith("/invite/"))await ph()&&yt(()=>import("./invitePage-iOT1zBvp.js"),__vite__mapDeps([93,3]),import.meta.url).then(t=>t.mountInvitePage(decodeURIComponent(e.slice(8)).replace(/\/+$/,""))).catch(t=>console.error("[tangu-web] invite page failed:",t));else if(await gh()){window.amadeus=H1({apiBase:An(),getToken:Wa,onAuthError:$l}),q1({apiBase:An(),getToken:Wa});const{usePageStore:t}=await yt(async()=>{const{usePageStore:i}=await import("./pageStore-CyvNZEYX.js").then(o=>o.dI);return{usePageStore:i}},__vite__mapDeps([2,1,3,4]),import.meta.url);t.setState({vaultSide:"cloud"});let n=!1;try{n=(new URLSearchParams(location.search).get("ui")||localStorage.getItem("lcl.uiMode"))==="mobile"}catch{}Ol(n).then(Fl).catch(i=>console.error("[tangu-web] bootstrap failed:",i))}}Z1().catch(e=>{console.error("[tangu-web] Account bootstrap failed:",e),window.__FORSION_UNIT_PAGE__&&Kd()});export{fh as $,ms as A,cu as B,Bs as C,WC as D,XA as E,VC as F,zC as G,ZC as H,An as I,dh as J,rn as K,GC as L,nh as M,Wa as N,$i as O,Zd as P,kc as Q,BC as R,Uy as S,uu as T,hu as U,oA as V,Ul as W,ha as X,pu as Y,kw as Z,yt as _,Na as a,u1 as a$,mh as a0,_s as a1,uC as a2,Wi as a3,tC as a4,oC as a5,h1 as a6,c1 as a7,y1 as a8,m1 as a9,yo as aA,Xe as aB,Zy as aC,de as aD,Q as aE,ko as aF,jc as aG,rk as aH,Yr as aI,OC as aJ,cA as aK,MC as aL,RC as aM,uA as aN,Gs as aO,qC as aP,s1 as aQ,A1 as aR,L1 as aS,x1 as aT,S1 as aU,k1 as aV,dC as aW,LC as aX,H0 as aY,zn as aZ,fC as a_,g1 as aa,Tx as ab,gC as ac,T1 as ad,ji as ae,hC as af,es as ag,Ve as ah,YA as ai,ih as aj,qA as ak,WA as al,HA as am,UA as an,jA as ao,HC as ap,BA as aq,pi as ar,Bd as as,J1 as at,Ke as au,ck as av,Mw as aw,Q1 as ax,fe as ay,st as az,Rd as b,lC as b$,AC as b0,qa as b1,Ah as b2,gl as b3,F1 as b4,US as b5,So as b6,je as b7,Zt as b8,Le as b9,Sh as bA,Qi as bB,vh as bC,d1 as bD,SC as bE,f1 as bF,zA as bG,nl as bH,Lx as bI,Ex as bJ,Kr as bK,V0 as bL,Sd as bM,pa as bN,v1 as bO,vC as bP,xd as bQ,q0 as bR,rC as bS,PA as bT,X0 as bU,Fn as bV,Su as bW,ao as bX,dA as bY,$C as bZ,hA as b_,Y as ba,wc as bb,xC as bc,Ou as bd,bC as be,yC as bf,aA as bg,O1 as bh,nA as bi,N1 as bj,zl as bk,l1 as bl,P1 as bm,b1 as bn,pC as bo,CC as bp,Cx as bq,Hi as br,DC as bs,jl as bt,C1 as bu,Yk as bv,ma as bw,TC as bx,IC as by,xh as bz,uh as c,cC as c0,hx as c1,r1 as c2,w1 as c3,aC as c4,mC as c5,eA as c6,ca as c7,In as c8,rx as c9,X1 as ca,Cu as cb,sC as cc,Qr as cd,eC as ce,ix as cf,nx as cg,iC as ch,nC as ci,UC as cj,yh as ck,jC as cl,FC as cm,Nx as cn,kC as co,Y1 as cp,hh as cq,H1 as cr,q1 as cs,Hd as ct,Au as cu,K1 as cv,YC as cw,KA as d,NC as e,Ui as f,wo as g,_C as h,wC as i,No as j,Q0 as k,ox as l,gn as m,Ma as n,EC as o,PC as p,Xr as q,ot as r,Pd as s,ie as t,KC as u,cn as v,a1 as w,I1 as x,E1 as y,_1 as z};
3412
+ `),!1,void 0,k);return}catch(j){if(!Te(j)||x>=3)throw j;k=Number(j.body?.seq)||0}}}),Da=async f=>w(f).includes(wt)?Yd():{},wi=f=>{const k=new Set;for(const x of[...w(f),...f.folders])x.startsWith(`${Oe}/`)&&k.add(x.slice(Oe.length+1).split("/")[0]);return k.delete(nn),k},$a=(f,k,x)=>{if(!wi(f).has(x))return null;const F=f.folders.includes(`${Oe}/${x}`);return Object.prototype.hasOwnProperty.call(k,x)?{...k[x],dir:F}:{original:x,deletedAt:0,dir:F}};let Jd=0,bi=null;const za=async()=>{const f=_();if(f){await tn(),(async()=>{for(let V=0;;V++){if(e.signal?.aborted)return;try{const G=await c();await A(!0),mi(G),De();return}catch{if(e.signal?.aborted)return;if(V>=2){At(ie("amxbridge.connectFailed"),!0);return}await new Promise(G=>{const Z=()=>{clearTimeout(Pe),e.signal?.removeEventListener("abort",Z),G()},Pe=setTimeout(Z,[3e3,1e4][V]);e.signal?.addEventListener("abort",Z,{once:!0}),e.signal?.aborted&&Z()})}}})();let N;try{N=localStorage.getItem(Bn(f.v))||void 0}catch{}const j=f.tree.pages.filter(H);return{root:`cloud://${f.v}`,pages:j,folders:f.tree.folders.filter($),lastPage:N&&j.includes(N)?N:void 0}}const k=await c(),[x]=await Promise.all([A(!0),tn()]);mi(k);const F=gi(),M=x.pages.filter(H);return{root:`cloud://${k}`,pages:M,folders:x.folders.filter($),lastPage:F&&M.includes(F)?F:void 0}},Qd=(f,k,x)=>ne([f],async()=>{await c();for(let F=0;F<3;F++){let M;try{M=await z(f)}catch(N){if(Ne(N))return"gone";throw N}if(cn(M.content)!==x)return{ok:!1,current:M.content};try{return await K(f,k,M.seq),{ok:!0}}catch(N){if(!Te(N))throw N}}throw new Error("conflict")}),Hn=async(f,k,x)=>{let F=null;const M=await OA({exists:async N=>(await(F??=A(!0).then(j=>new Set(j.files.map(V=>V.path))))).has(N),read:async N=>{try{return(await z(N)).content}catch(j){if(Ne(j))return null;throw j}},write:Qd},f,k,{folder:x});for(const N of M.rewritten)Ce(N);t1(M.failed.map(N=>N.path))},ja=(f,k)=>f.pages.some(x=>x.startsWith(`${k}/`))||f.files.some(x=>x.path.startsWith(`${k}/`)),Ba=(f,k,x)=>{const F=`${k}/`,M={};for(const N of f)N.startsWith(F)&&(M[N]=`${x}/${N.slice(F.length)}`);return M};return LA({openVault:()=>za(),restoreVault:()=>za(),listPages:async()=>(await A()).pages.filter(H),listFiles:async()=>{const f=await A(),k=f.files.map(F=>F.path).filter($),x=f.pages.filter(F=>$(F)&&q(F));return x.length?[...k,...x].sort():k},listFolders:async()=>(await A()).folders.filter($),loadPage:async f=>{await c();const k=u.get(f);if(k)return gt(f),Ye(f),k;const x=await tt(f);return gt(f),x},readPage:async f=>{await c();try{return await pe(f)}catch(k){throw Ne(k)?new Error(`note not found: ${f}`):k}},newPage:async f=>{await c();const k=await ne([f],()=>ft(f));return gt(f),k},savePage:(f,k,x)=>{const F=L(f);return ne(F,async()=>{await c();const M=_s(k,x),N=Object.values(x).some(G=>typeof G=="string"&&G.trim().length>0);let j,V;try{({target:j,base:V}=await I(f))}catch(G){if(G instanceof S){await ee(f,M,N);return}throw G}await B(F,j,async()=>{try{await K(j,M,V),p(j,ji(j,M,Ri()))}catch(G){if(Te(G)){const Z=G.body;if(Z?.code==="CONFLICT"&&Z.seq===0){h.delete(j),await ee(f,M,N);return}Z&&typeof Z.seq=="number"&&T(j,Z.seq),u.delete(f),At(ie("amxbridge.conflictReloaded"),!0),setTimeout(()=>Ce(f),0);return}throw G instanceof Re&&G.status===413&&At(ie("amxbridge.tooLarge"),!0),G}})})},renamePage:(f,k,x,F)=>{let M=null;return ne([f,Di(f,k,ie("amxbridge.pageNameEmpty"))],async()=>{await c();const N=Di(f,k,ie("amxbridge.pageNameEmpty"));if(N===f)return{newPath:f,page:await pe(f)};const j=await A(!0);if(M=j.pages.filter(H),w(j).includes(N)||j.folders.includes(N))throw new Error(ie("amxbridge.pageExists"));const V=_s(x,F);await K(f,V,await le(f),!0);let G;try{G=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:f,to:N})}catch(Z){throw Te(Z)?new Error(ie("amxbridge.pageExists")):Z}return v(f,N,G.seq),ce(),gt(N),{newPath:N,page:null}}).then(async N=>N.page?{newPath:N.newPath,page:N.page}:(M&&await Hn({[f]:N.newPath},M),{newPath:N.newPath,page:await pe(N.newPath)}))},reconcilePage:async f=>(await c(),tt(f)),saveAsset:async(f,k,x,F)=>{await c();const M=Ds(k),N=(M||".png").toLowerCase().replace(/[^.a-z0-9]/g,""),j=Qe(k).slice(0,Qe(k).length-M.length).replace(/[^a-zA-Z0-9_-]/g,"").slice(0,24)||"img";for(let V=0;V<5;V++){const G=`${j}-${Date.now().toString(36)}-${(Jd++).toString(36)}${N||".png"}`,Z=it(Hi(Ct(f),`.amadeus/${G}`));if(Z===null)throw new Error("Asset escapes vault");try{return await Je(Z,G,x,!0,F),`.amadeus/${G}`}catch(Pe){if(Te(Pe))continue;throw Pe}}throw new Error(ie("amxbridge.imageNameFailed"))},saveAttachment:async(f,k,x,F,M)=>{await c();const N=(Qe(k)||"file").replace(/[\\/]/g,""),{destDirRel:j}=kl(f,N,F),V=await A(!0),G=new Set(w(V).filter(Ae=>Ct(Ae)===j).map(Ae=>Qe(Ae).toLowerCase()));let Z=vl(G,N);const Pe=cs(N);for(let Ae=0;Ae<20;Ae++){const{fileVaultRel:Ft,pageRel:on}=kl(f,Z,F),Mo=it(Ft);if(Mo===null)throw new Error("Asset escapes vault");try{return Pe?await K(Mo,new TextDecoder().decode(x),0):await Je(Mo,Z,x,!0,M),{pageRel:on,base:Z}}catch(Ua){if(Te(Ua)){G.add(Z.toLowerCase()),Z=vl(G,N);continue}throw Ua}}throw new Error(ie("amxbridge.attachmentNameFailed"))},openAttachment:async(f,k)=>{await c(),window.open(po(bl(k),f),"_blank","noopener")},openVaultFile:async f=>{await c(),window.open(po(f,null),"_blank","noopener")},exportPdf:async()=>(window.print(),null),onExternalChange:f=>(ge.add(f),()=>{ge.delete(f)}),onStructureChange:f=>(ye.add(f),()=>{ye.delete(f)}),onDbExternalChange:f=>(We.add(f),()=>{We.delete(f)}),onPathGone:f=>(en.add(f),()=>{en.delete(f)}),search:async f=>(await c(),(await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/search`,{q:f})).filter(x=>$(x.path))),backlinks:async f=>(await c(),s.get(`/amadeus/vaults/${encodeURIComponent(l())}/backlinks`,{path:f})),reindex:async()=>{await c(),await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/reindex`)},listTags:async()=>(await c(),s.get(`/amadeus/vaults/${encodeURIComponent(l())}/tags`)),pagesByTag:async f=>(await c(),(await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/tags/pages`,{tag:f})).paths),resolveEmbed:async(f,k)=>{await c();const{note:x,subpath:F}=hA(f),M=(await A()).pages.filter(H).sort(),N=x?Ui(x,M,k):k&&M.includes(k)?k:null;if(N){let G=null;try{G=(await z(N)).content}catch(Z){if(!Ne(Z))throw Z}if(G!=null){if(!F)return{owner:N,content:Qr(G),type:"markdown"};const Z=Ld(G,F.trim().replace(/\.block$/i,"").toLowerCase())??yA(Qr(G),F);return Z==null?null:{owner:N,content:Z,type:"markdown"}}}const j=F?`${x}#${F}`:x;return j?await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/embed`,{target:j})??null:null},blockBacklinks:async f=>(await c(),s.get(`/amadeus/vaults/${encodeURIComponent(l())}/block-backlinks`,{target:f})),deletePage:f=>ne([f],async()=>{await c(),await s.del(R(),{path:f}),O(f),ce()}),movePage:(f,k)=>{let x=null;return ne([f],async()=>{await c();const F=Bl(f),M=k.replace(/\\/g,"/").replace(/^\/+|\/+$/g,""),N=M?`${M}/${F}`:F;if(N===f)return f;N.endsWith(".md")&&(x=(await A(!0)).pages.filter(H));let j;try{j=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:f,to:N})}catch(V){throw Te(V)?new Error(ie("amxbridge.fileExistsAtTarget")):V}return v(f,N,j.seq),ce(),N.endsWith(".md")&&gt(N),N}).then(async F=>(F!==f&&x&&await Hn({[f]:F},x),F))},createFolder:async(f,k)=>{await c();const x=k.trim().replace(/[\\/]/g,"");if(!x)throw new Error(ie("amxbridge.folderNameEmpty"));const F=f.replace(/\\/g,"/").replace(/^\/+|\/+$/g,"");try{const M=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders`,{parent:F,name:x});return ce(),M.path}catch(M){throw Te(M)?new Error(ie("amxbridge.folderExists")):M}},renameFolder:async(f,k)=>{await c();const x=k.trim().replace(/[\\/]/g,"");if(!x)throw new Error(ie("amxbridge.folderNameEmpty"));const F=Ct(f);if((F?`${F}/${x}`:x)===f)return f;const N=await A(!0),j=N.pages.filter(H),V=ja(N,f);let G;try{G=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/rename`,{path:f,newName:x})}catch(Z){throw Te(Z)?new Error(ie("amxbridge.folderExists")):Z}return ae(f,G.path),et&&et.startsWith(`${f}/`)&&gt(`${G.path}${et.slice(f.length)}`),ce(),await Hn(Ba(j,f,G.path),j,V?[f,G.path]:void 0),G.path},deleteFolder:async f=>{await c(),await s.del(`/amadeus/vaults/${encodeURIComponent(l())}/folders`,{path:f}),te(f),ce()},moveFolder:async(f,k)=>{await c();const x=f.replace(/\\/g,"/").replace(/^\/+|\/+$/g,""),F=Qe(x);if(!F)throw new Error(ie("amxbridge.folderPathEmpty"));const M=k.replace(/\\/g,"/").replace(/^\/+|\/+$/g,"");if((M?`${M}/${F}`:F)===x)return x;if(M===x||M.startsWith(`${x}/`))throw new Error(ie("amxbridge.moveIntoSelf"));const j=await A(!0),V=j.pages.filter(H),G=ja(j,x);let Z;try{Z=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/move`,{path:x,dest:M})}catch(Pe){throw Te(Pe)?new Error(ie("amxbridge.folderExistsAtTarget")):Pe}return ae(x,Z.path),et&&et.startsWith(`${x}/`)&&gt(`${Z.path}${et.slice(x.length)}`),ce(),await Hn(Ba(V,x,Z.path),V,G?[x,Z.path]:void 0),Z.path},trashEntry:async f=>{await c();const k=f.replace(/\\/g,"/").replace(/^\/+|\/+$/g,"");if(!k||k===Oe||k.startsWith(`${Oe}/`))throw new Error(ie("amxbridge.invalidPath"));const x=await A(!0),F=x.folders.includes(k),M=Date.now().toString(36);try{if(F){let N=k,j=Qe(k);if(j===nn||x.folders.includes(`${Oe}/${j}`)){const V=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/rename`,{path:k,newName:`${j} (${M})`});N=V.path,j=Qe(V.path)}await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/move`,{path:N,dest:Oe}),te(k),await fi(V=>{V[j]={original:k,deletedAt:Date.now(),dir:!0}})}else{let N=k.replace(/\//g,"__");(N===nn||w(x).includes(`${Oe}/${N}`))&&(N=`${M}-${N}`),await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:k,to:`${Oe}/${N}`}),O(k),await fi(j=>{j[N]={original:k,deletedAt:Date.now(),dir:!1}})}}finally{ce()}},listTrash:async()=>{await c();const f=await A(),k=await Da(f);return[...wi(f)].map(x=>({name:x,...$a(f,k,x)})).sort((x,F)=>F.deletedAt-x.deletedAt)},restoreTrash:async f=>{await c();const k=await A(!0),x=$a(k,await Da(k),f);if(!x)throw new Error(ie("amxbridge.trashMissing"));const F=N=>w(k).includes(N)||k.folders.includes(N);let M=x.original;for(let N=2;F(M);N++)if(x.dir)M=`${x.original} (${N})`;else{const j=Ds(x.original);M=`${x.original.slice(0,x.original.length-j.length)} (${N})${j}`}if(x.dir){const N=`${Oe}/${f}`,j=Qe(M),V=Ct(M),G=(Z,Pe)=>s.post(`/amadeus/vaults/${encodeURIComponent(l())}/folders/${Z}`,Pe);f===j?await G("move",{path:N,dest:V}):j!==nn&&!wi(k).has(j)?await G("move",{path:(await G("rename",{path:N,newName:j})).path,dest:V}):(await G("move",{path:N,dest:V}),await G("rename",{path:V?`${V}/${f}`:f,newName:j}))}else await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:`${Oe}/${f}`,to:M});return await fi(N=>{delete N[f]}),ce(),M},deleteTrashEntry:async f=>{await c();const k=await A(!0);wi(k).has(f)&&(k.folders.includes(`${Oe}/${f}`)?await s.del(`/amadeus/vaults/${encodeURIComponent(l())}/folders`,{path:`${Oe}/${f}`}).catch(x=>{if(!Ne(x))throw x}):await s.del(R(),{path:`${Oe}/${f}`}).catch(x=>{if(!Ne(x))throw x})),await fi(x=>{delete x[f]}),ce()},emptyTrash:async()=>{await c(),await s.del(`/amadeus/vaults/${encodeURIComponent(l())}/folders`,{path:Oe}).catch(f=>{if(!Ne(f))throw f}),te(Oe),ce()},saveVaultBytes:async(f,k)=>{await c();const x=it(f.replace(/\\/g,"/"));if(!x)throw new Error(ie("amxbridge.pathOutsideVault"));await Je(x,Qe(x),k,!1)},readVaultBytes:async f=>{const k=it(f.replace(/\\/g,"/")),x=k?await Me(k):null;if(!x)throw new Error(ie("amxbridge.readFailed",{status:404}));return new Uint8Array(await x.arrayBuffer())},fetchLinkMeta:async f=>{try{return await s.get("/amadeus/link-meta",{url:f})}catch{return null}},searchImages:async f=>{const k=f.trim();if(!k)return[];const x=await fetch(`https://api.openverse.org/v1/images/?q=${encodeURIComponent(k)}&page_size=20`,{headers:{accept:"application/json"}});if(!x.ok)throw new Error(`openverse HTTP ${x.status}`);return((await x.json()).results??[]).map(M=>({thumb:M.thumbnail??"",full:M.url??"",author:M.creator})).filter(M=>M.thumb&&M.full)},listPlugins:async()=>[],openPluginsFolder:async()=>{At(ie("amxbridge.desktopOnly"))},scaffoldSamplePlugin:async()=>{At(ie("amxbridge.desktopOnly"))},revealInFileManager:async()=>{At(ie("amxbridge.desktopOnly"))},hostCaps:{revealInFileManager:!1},readDatabase:async(f,k)=>{await c();for(const x of await xt(f,k)){let F;try{F=await z(x)}catch(N){if(Ne(N))continue;if(N instanceof Re&&N.status===400)return{status:"corrupt",path:x,message:ie("amxbridge.notText")};throw N}const M=Ou(F.content);return M.ok?{status:"ok",path:x,data:M.data}:{status:"corrupt",path:x,message:M.error}}return{status:"missing"}},writeDatabase:(f,k)=>ne([f],async()=>{await c();const x=Fu.parse(k),F=Tx(x),M=await le(f);try{await K(f,F,M)}catch(N){if(Te(N)){try{await z(f)}catch{}setTimeout(()=>Xt(f),0);return}throw N}}),readDrawing:async(f,k)=>{await c();const x=await xt(f,k),F=x.length?x:await xt(f,`${k}.md`);for(const M of F.flatMap(N=>N.endsWith(".md")?[N]:[N,`${N}.md`]))try{const N=await z(M);return{status:"ok",path:M,source:N.content}}catch(N){if(!Ne(N))throw N}return{status:"missing"}},writeDrawing:(f,k)=>ne([f],async()=>{await c();const x=await le(f);try{await K(f,k,x)}catch(F){if(!Te(F))throw F;try{const N=await z(f),j=nl(k),V=nl(N.content),G=j?JSON.parse(j.sceneJson):null,Z=V?JSON.parse(V.sceneJson):null;if(G&&Z){const Pe=Ex(N.content,JSON.stringify(Lx(G,Z)));if(Pe){await K(f,Pe,N.seq);return}}}catch{}const M=F.body;M&&typeof M.seq=="number"&&T(f,M.seq),await K(f,k,h.get(f)??0,!0)}}),readTextFile:async f=>{if(await c(),!cs(f)){const k=it(f.replace(/\\/g,"/"));return k?nt(k):null}try{return(await z(f)).content}catch(k){if(Ne(k))return null;throw k}},writeTextFile:(f,k,x)=>{if(!cs(f))return ut(f,k,x);const F=L(f),M=typeof x?.base=="string"?x.base:null,N=()=>M!=null?{ok:!0}:void 0;return ne(F,async()=>{if(await c(),x?.create){try{return await K(f,k,0),b.delete(f),ce(),{ok:!0}}catch(Z){if(!Te(Z))throw Z}try{return{ok:!1,current:(await z(f)).content}}catch(Z){if(Ne(Z))return{ok:!1,current:null};throw Z}}const j=k.trim().length>0;let V,G;try{({target:V,base:G}=await I(f))}catch(Z){if(Z instanceof S)return await ee(f,k,j),N();throw Z}if(M!=null){const Z=M;return B(F,V,async()=>{const Pe=async()=>{let Ae;try{Ae=await z(V)}catch(Ft){if(Ne(Ft))return"vanished";throw Ft}return cn(Ae.content)===Z?Ae.seq:{ok:!1,current:Ae.content}};if(G>0&&g(V,G)!==Z){const Ae=await Pe();if(Ae==="vanished")return await ee(f,k,j),N();if(typeof Ae!="number")return Ae;G=Ae}for(let Ae=0;;Ae++)try{return await K(V,k,G),{ok:!0}}catch(Ft){if(!Te(Ft))throw Ft;const on=await Pe();if(on==="vanished")return await ee(f,k,j),N();if(typeof on!="number")return on;if(Ae>=2)throw Ft;G=on}})}await B(F,V,async()=>{try{await K(V,k,G)}catch(Z){if(!Te(Z))throw Z;let Pe;try{Pe=await z(V)}catch(Ae){if(Ne(Ae)){await ee(f,k,j);return}throw Ae}await K(V,k,Pe.seq,!0)}})})},listPageProps:async f=>(await c(),(await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/page-props`,{folder:f})).map(x=>({path:x.path,title:x.title,fm:gl(x.fmExtra||"")}))),pageIcons:async()=>{await c();const f=await A();if(bi&&bi.seq===f.seq)return bi.icons;const k=await s.get(`/amadeus/vaults/${encodeURIComponent(l())}/page-props`,{folder:"",all:"1"}),x={};for(const F of k){const M=gl(F.fmExtra||"").icon;typeof M=="string"&&M&&(x[F.path]=M)}return bi={seq:f.seq,icons:x},x},setPageFrontmatter:(f,k)=>ne([f],async()=>{await c();const x=async()=>{let F;try{F=await z(f)}catch(N){if(Ne(N))return"ok";throw N}const M=V0(F.content,k);if(M===F.content)return"ok";try{return await K(f,M,F.seq),"ok"}catch(N){if(Te(N))return"conflict";throw N}};if(await x()==="conflict")try{await x()}catch{}}),renamePageFile:(f,k)=>{let x=null;return ne([f,Di(f,k,ie("amxbridge.noteNameEmpty"))],async()=>{await c();const F=Di(f,k,ie("amxbridge.noteNameEmpty"));if(F===f)return f;x=(await A(!0)).pages.filter(H);let M;try{M=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:f,to:F})}catch(N){throw Te(N)?new Error(ie("amxbridge.noteExists")):N}return v(f,F,M.seq),ce(),F}).then(async F=>(F!==f&&x&&await Hn({[f]:F},x),F))},renameDbFile:(f,k)=>ne([f],async()=>{await c();const x=f.replace(/\\/g,"/");let F=k.trim().replace(/[\\/]/g,"");if(F.toLowerCase().endsWith(".db")&&(F=F.slice(0,-3)),!F)throw new Error(ie("amxbridge.nameEmpty"));const M=Ct(x),N=M?`${M}/${F}.db`:`${F}.db`;if(N===x)return{newPath:N,rewrittenPages:[]};let j;try{j=await s.post(`/amadeus/vaults/${encodeURIComponent(l())}/move`,{from:x,to:N})}catch(V){throw Te(V)?new Error(ie("amxbridge.fileExists")):V}return v(x,N,j.seq),ce(),{newPath:N,rewrittenPages:[]}})})}function Di(e,t,n){const i=Ct(e);let o=t.trim().replace(/[\\/]/g,"");if(!o)throw new Error(n);return o.toLowerCase().endsWith(".md")&&(o=o.slice(0,-3)),i?`${i}/${o}.md`:`${o}.md`}const W1=async e=>{if(!e.ok){let t=null;try{t=await e.json()}catch{}const n=new Error(t?.detail||`http ${e.status}`);throw n.status=e.status,n.code=t?.code,n}return e.json()};function q1(e){const t=$i(Zd),n=e.getToken(),i=ni(e.apiBase,n),o=()=>{const g=e.getToken();if(e.signal?.aborted||!g||(i?ni(e.apiBase,g)!==i:g!==n))throw new Error("Cloud account changed");return g},s=async(g,y,b)=>{const C=o(),S=new AbortController,T=()=>S.abort(e.signal?.reason);e.signal?.addEventListener("abort",T,{once:!0});const O=setTimeout(()=>S.abort(),2e4);try{const v=await W1(await(e.request??fetch)(`${e.apiBase}/amadeus${y}`,{method:g,headers:{Authorization:`Bearer ${C}`,...b!==void 0?{"Content-Type":"application/json"}:{}},body:b!==void 0?JSON.stringify(b):void 0,signal:S.signal}));return o(),v}finally{clearTimeout(O),e.signal?.removeEventListener("abort",T)}},a=()=>U1();let r=e.linkBase?.replace(/\/+$/,"")||null;const l=async()=>{if(r)return r;try{r=((await s("GET","/collab/link-base")).webOrigin??"").trim().replace(/\/+$/,"")||location.origin}catch{r=location.origin}return r},c=()=>r??location.origin;e.signal?.aborted||l();const d=()=>{if(o(),e.getUserId)return e.getUserId();try{const g=e.getToken().split(".")[1],y=JSON.parse(atob(g.replace(/-/g,"+").replace(/_/g,"/")));return typeof y.userId=="string"?y.userId:null}catch{return null}};let u=null,p=null;const h=()=>{u&&(clearInterval(u),u=null)};e.signal?.addEventListener("abort",h,{once:!0});const m=()=>{e.signal?.aborted||a().then(g=>s("POST",`/vaults/${encodeURIComponent(g)}/presence`,{page:p})).catch(()=>{})};window.amadeusCollab={listVaults:()=>s("GET","/vaults").then(g=>g.vaults),activeVaultId:a,switchVault(g){o();try{localStorage.setItem(t,g)}catch{}location.reload()},pageShare:async g=>s("GET",`/vaults/${encodeURIComponent(await a())}/page-shares?path=${encodeURIComponent(g)}`),createPageShare:async(g,y)=>s("POST",`/vaults/${encodeURIComponent(await a())}/page-shares`,{path:g,...y}),updatePageShare:async(g,y)=>s("PATCH",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}`,y),revokePageShare:async g=>{await s("DELETE",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}`)},setParticipantRole:async(g,y,b)=>{await s("PATCH",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}/members/${encodeURIComponent(y)}`,{role:b})},removeParticipant:async(g,y)=>{await s("DELETE",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}/members/${encodeURIComponent(y)}`)},sharedWithMe:()=>s("GET","/shared-with-me").then(g=>g.items),leaveShare:async g=>{const y=d();y&&await s("DELETE",`/vaults/${encodeURIComponent(await a())}/page-shares/${encodeURIComponent(g)}/members/${encodeURIComponent(y)}`)},inviteUrl:g=>`${c()}/invite/${g}`,publishes:async()=>s("GET",`/vaults/${encodeURIComponent(await a())}/shares`),createPublish:async(g,y)=>{const b=await s("POST",`/vaults/${encodeURIComponent(await a())}/shares`,{mode:g,path:y});return{...b,url:`${c()}/share/${b.token}`}},revokePublish:async g=>{await s("DELETE",`/vaults/${encodeURIComponent(await a())}/shares/${encodeURIComponent(g)}`)},publishUrl:g=>`${c()}/share/${g}`,revokePublishIn:async(g,y)=>{await s("DELETE",`/vaults/${encodeURIComponent(g)}/shares/${encodeURIComponent(y)}`)},revokePageShareIn:async(g,y)=>{await s("DELETE",`/vaults/${encodeURIComponent(g)}/page-shares/${encodeURIComponent(y)}`)},listAllShares:async()=>{const g=(await s("GET","/vaults")).vaults||[],y=d(),b=[],C=[];for(const S of g){try{const T=await s("GET",`/vaults/${encodeURIComponent(S.id)}/shares`);for(const O of T.shares||[])b.push({...O,vaultId:S.id,vaultName:S.name||""})}catch{}try{const T=await s("GET",`/vaults/${encodeURIComponent(S.id)}/page-shares`),O=T?.shares||T?.pageShares||(Array.isArray(T)?T:[]);for(const v of O){const I=v.created_by??v.createdBy;(!y||!I||I===y)&&C.push({...v,vaultId:S.id,vaultName:S.name||""})}}catch{}}return{publishes:b,pageShares:C,linkBase:await l()}},heartbeat(g){o(),p=g,m(),u||(u=setInterval(m,3e4))},stopHeartbeat:h,onPresence:g=>D1(g),myUserId:d}}Na({"unit.bootError.title":{zh:"暂时无法打开此 Unit",en:"Unable to open this Unit"},"unit.bootError.detail":{zh:"请检查连接后重试。",en:"Check your connection and try again."},"unit.bootError.retry":{zh:"重试",en:"Try again"}});function Kd(){const e=document.getElementById("root")??document.body.appendChild(document.createElement("main")),t=document.createElement("section");t.setAttribute("role","alert");const n=document.documentElement.dataset.mode==="dark";t.style.cssText='max-width:440px;margin:15vh auto;padding:24px;font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif',t.style.color=`var(--text,${n?"#f2efe8":"#1c1c1c"})`,t.style.colorScheme=n?"dark":"light";const i=document.createElement("h1");i.textContent=ie("unit.bootError.title"),i.style.cssText="font-size:20px;font-weight:600;margin:0 0 8px";const o=document.createElement("p");o.textContent=ie("unit.bootError.detail"),o.style.cssText="margin:0 0 20px;color:var(--text-muted,inherit)";const s=document.createElement("button");s.type="button",s.textContent=ie("unit.bootError.retry"),s.style.cssText="font:inherit;padding:7px 16px;cursor:pointer",s.addEventListener("click",()=>location.reload()),t.append(i,o,s),e.replaceChildren(t),s.focus()}function V1(e,t){if(e.origin!==t.origin||!e.pathname.startsWith(t.pathname))return null;const n=/^(share|invite)\/([^/]+)\/?$/.exec(e.pathname.slice(t.pathname.length));return n?{kind:n[1],token:decodeURIComponent(n[2])}:null}const Fl=()=>yt(async()=>{const{useApp:e}=await import("./appStore-BskcSDl6.js").then(t=>t.ra);return{useApp:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]),import.meta.url).then(({useApp:e})=>{B1((t,n)=>e.getState().toast(t,n))}),G1={mobile:()=>yt(()=>import("./mobileEntry-CptXQ4Ov.js"),__vite__mapDeps([10,4,11,2,3,5,12,13,0,1,6,7,8,9,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]),import.meta.url),desktop:()=>yt(()=>import("./main-CForzSFD.js"),__vite__mapDeps([91,4,11,2,3,5,12,13,0,1,6,7,8,9,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,92]),import.meta.url)};function Ol(e){return G1[e?"mobile":"desktop"]()}async function Z1(){const e=location.pathname;if(window.__FORSION_UNIT_PAGE__){const t=window.__FORSION_UNIT_PAGE__,n=new URL(".",document.baseURI),i=V1(new URL(location.href),n);if(i&&t.capabilities?.amadeus){const o=new URL(t.capabilities.amadeus.apiBase,location.origin).href.replace(/\/+$/,"");if(i.kind==="share"){const{mountSharePage:s}=await yt(async()=>{const{mountSharePage:a}=await import("./sharePage-vnghra3Q.js");return{mountSharePage:a}},[],import.meta.url);s(i.token,{apiBase:o})}else{if(!t.account)throw new Error("Invitations require an account provider");const{installUnitAccount:s}=await yt(async()=>{const{installUnitAccount:l}=await import("./unitAccount-DNxfGo3c.js");return{installUnitAccount:l}},[],import.meta.url),a=await s({instanceId:t.instanceId,account:t.account},n);if(!a.account.getIdentity()){await a.login();return}const{mountInvitePage:r}=await yt(async()=>{const{mountInvitePage:l}=await import("./invitePage-BT_rFfab.js");return{mountInvitePage:l}},__vite__mapDeps([93,4]),import.meta.url);r(i.token,{apiBase:o,getToken:a.account.getToken,request:a.capability.request,appBase:n.href})}return}yt(()=>import("./unitShim-BfheyIG8.js"),[],import.meta.url).then(async o=>{if(!await o.installUnitShim())return;let s=!1;try{s=(new URLSearchParams(location.search).get("ui")||localStorage.getItem("lcl.uiMode"))==="mobile"}catch{}await Ol(s),t.capabilities?.amadeus&&await Fl()}).catch(o=>{console.error("[unit-page] bootstrap failed:",o),Kd()})}else if(e.startsWith("/share/"))yt(()=>import("./sharePage-vnghra3Q.js"),[],import.meta.url).then(t=>t.mountSharePage(decodeURIComponent(e.slice(7)).replace(/\/+$/,""))).catch(t=>console.error("[tangu-web] share page failed:",t));else if(e.startsWith("/invite/"))await ph()&&yt(()=>import("./invitePage-BT_rFfab.js"),__vite__mapDeps([93,4]),import.meta.url).then(t=>t.mountInvitePage(decodeURIComponent(e.slice(8)).replace(/\/+$/,""))).catch(t=>console.error("[tangu-web] invite page failed:",t));else if(await gh()){window.amadeus=H1({apiBase:An(),getToken:Wa,onAuthError:$l}),q1({apiBase:An(),getToken:Wa});const{usePageStore:t}=await yt(async()=>{const{usePageStore:i}=await import("./pageStore-D_fKLv-o.js").then(o=>o.dL);return{usePageStore:i}},__vite__mapDeps([2,3,4,5]),import.meta.url);t.setState({vaultSide:"cloud"});let n=!1;try{n=(new URLSearchParams(location.search).get("ui")||localStorage.getItem("lcl.uiMode"))==="mobile"}catch{}Ol(n).then(Fl).catch(i=>console.error("[tangu-web] bootstrap failed:",i))}}Z1().catch(e=>{console.error("[tangu-web] Account bootstrap failed:",e),window.__FORSION_UNIT_PAGE__&&Kd()});export{fh as $,ms as A,cu as B,Bs as C,WC as D,XA as E,VC as F,zC as G,ZC as H,An as I,dh as J,rn as K,GC as L,nh as M,Wa as N,$i as O,Zd as P,kc as Q,BC as R,Uy as S,uu as T,hu as U,oA as V,Ul as W,ha as X,pu as Y,kw as Z,yt as _,Na as a,qa as a$,mh as a0,_s as a1,uC as a2,Wi as a3,tC as a4,oC as a5,h1 as a6,c1 as a7,y1 as a8,m1 as a9,Zy as aA,de as aB,Q as aC,ko as aD,jc as aE,rk as aF,Yr as aG,OC as aH,cA as aI,MC as aJ,RC as aK,uA as aL,Gs as aM,qC as aN,s1 as aO,A1 as aP,L1 as aQ,x1 as aR,S1 as aS,k1 as aT,dC as aU,LC as aV,H0 as aW,zn as aX,fC as aY,u1 as aZ,AC as a_,g1 as aa,Tx as ab,gC as ac,T1 as ad,ji as ae,hC as af,es as ag,Ve as ah,qA as ai,WA as aj,HA as ak,UA as al,jA as am,HC as an,BA as ao,pi as ap,Bd as aq,J1 as ar,Ke as as,ck as at,Mw as au,Q1 as av,fe as aw,st as ax,yo as ay,Xe as az,Rd as b,lC as b$,Ah as b0,gl as b1,F1 as b2,US as b3,So as b4,je as b5,Zt as b6,Le as b7,Y as b8,wc as b9,vh as bA,d1 as bB,SC as bC,f1 as bD,YA as bE,ih as bF,zA as bG,nl as bH,Lx as bI,Ex as bJ,Kr as bK,V0 as bL,Sd as bM,pa as bN,v1 as bO,vC as bP,xd as bQ,q0 as bR,rC as bS,PA as bT,X0 as bU,Fn as bV,Su as bW,ao as bX,dA as bY,$C as bZ,hA as b_,xC as ba,Ou as bb,bC as bc,yC as bd,aA as be,O1 as bf,nA as bg,N1 as bh,zl as bi,l1 as bj,P1 as bk,b1 as bl,pC as bm,CC as bn,Cx as bo,Hi as bp,DC as bq,jl as br,C1 as bs,Yk as bt,ma as bu,TC as bv,IC as bw,xh as bx,Sh as by,Qi as bz,uh as c,cC as c0,hx as c1,r1 as c2,w1 as c3,aC as c4,mC as c5,eA as c6,ca as c7,In as c8,rx as c9,X1 as ca,Cu as cb,sC as cc,Qr as cd,eC as ce,ix as cf,nx as cg,iC as ch,nC as ci,UC as cj,yh as ck,jC as cl,FC as cm,Nx as cn,kC as co,Y1 as cp,hh as cq,H1 as cr,q1 as cs,Hd as ct,Au as cu,K1 as cv,YC as cw,KA as d,NC as e,Ui as f,wo as g,_C as h,wC as i,No as j,Q0 as k,ox as l,gn as m,Ma as n,EC as o,PC as p,Xr as q,ot as r,Pd as s,ie as t,KC as u,cn as v,a1 as w,I1 as x,E1 as y,_1 as z};