chainlesschain 0.162.2 → 0.162.7

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 (151) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-D69_XwQf.js → AIOps-BXQ92dvI.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-COVVHNnK.js → ActionButton-DjmolmAS.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-m0Cuoraq.js → Analytics-LUUOS78B.js} +2 -2
  6. package/src/assets/web-panel/assets/{AppLayout-BEZq_CS0.css → AppLayout-BLCe1k8m.css} +1 -1
  7. package/src/assets/web-panel/assets/AppLayout-DeAq-Waa.js +3 -0
  8. package/src/assets/web-panel/assets/{Audit-DB5RNs9K.js → Audit-De_86BpN.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DD9SgVtq.js → Backup-CAqIbrb5.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CS2Y4V0O.js → BaseInput-CwTVDavS.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-Cvw48zqw.js → Chat-BnihAKiI.js} +1 -1
  12. package/src/assets/web-panel/assets/{Checkbox-DElRJpAL.js → Checkbox-BDrCuC9m.js} +1 -1
  13. package/src/assets/web-panel/assets/{Codegen-CHdMYssy.js → Codegen-DWqN0jpL.js} +1 -1
  14. package/src/assets/web-panel/assets/{Col-BDk4BXjN.js → Col-B7rIr4g3.js} +1 -1
  15. package/src/assets/web-panel/assets/{Community-ByDrN94M.js → Community-YYEO8SY3.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compact-D4E0roed.js → Compact-DZHWn-_j.js} +1 -1
  17. package/src/assets/web-panel/assets/Compliance-CCYzk_rt.js +1 -0
  18. package/src/assets/web-panel/assets/{Cowork-CMn6mzHv.js → Cowork-D9G6khOx.js} +3 -3
  19. package/src/assets/web-panel/assets/{Cron-CARdrrMM.js → Cron-IbwddEeZ.js} +2 -2
  20. package/src/assets/web-panel/assets/{Crosschain-2pnRIGVn.js → Crosschain-Bct133LN.js} +1 -1
  21. package/src/assets/web-panel/assets/{DID-BRo55XlY.js → DID-32J0mXoS.js} +2 -2
  22. package/src/assets/web-panel/assets/{Dashboard-DfNjjw7V.js → Dashboard-TaPAK2WV.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dropdown-BDTTlG70.js → Dropdown-Df4hUeIm.js} +1 -1
  24. package/src/assets/web-panel/assets/{Federation-CKkeJ169.js → Federation-C0xfKoZr.js} +1 -1
  25. package/src/assets/web-panel/assets/{FormItemContext-C6DJ0oHT.js → FormItemContext-CoacTa1H.js} +1 -1
  26. package/src/assets/web-panel/assets/{Git-DDQd8pDl.js → Git-DZZF1lrY.js} +2 -2
  27. package/src/assets/web-panel/assets/{Governance-DZTuAASB.js → Governance-Bo-P_BP3.js} +1 -1
  28. package/src/assets/web-panel/assets/{Inference-CIbj0XmL.js → Inference-agx6qPl9.js} +1 -1
  29. package/src/assets/web-panel/assets/KnowledgeGraph-Dc8YZGiO.js +1 -0
  30. package/src/assets/web-panel/assets/{Logs-BrLBwq1m.js → Logs-njAOFc0W.js} +1 -1
  31. package/src/assets/web-panel/assets/{Marketplace-q9X5VK92.js → Marketplace-Yu-RUTN2.js} +1 -1
  32. package/src/assets/web-panel/assets/{McpTools-DfxuLN57.js → McpTools-BuzdmOwR.js} +1 -1
  33. package/src/assets/web-panel/assets/{Memory-DND9vjBx.js → Memory-DJyWxXM0.js} +2 -2
  34. package/src/assets/web-panel/assets/{MobileBridge-Ba2jSFl0.js → MobileBridge-CIKfLcfn.js} +1 -1
  35. package/src/assets/web-panel/assets/{MobileProjects-CdclN769.js → MobileProjects-B1OZ0_b1.js} +1 -1
  36. package/src/assets/web-panel/assets/{Mtc-BNKpFjlY.js → Mtc-CJHI9qG0.js} +4 -4
  37. package/src/assets/web-panel/assets/{MtcAudit-BlZJm1Tf.js → MtcAudit-cSrqcG3H.js} +1 -1
  38. package/src/assets/web-panel/assets/{Multisig-DcX0uBmT.js → Multisig-DTVo9GFR.js} +2 -2
  39. package/src/assets/web-panel/assets/{NLProgramming-dDIA3V_a.js → NLProgramming-NqfB2jLI.js} +1 -1
  40. package/src/assets/web-panel/assets/{Notes-BDsTuZ5O.js → Notes-MuMFfs67.js} +3 -3
  41. package/src/assets/web-panel/assets/{NotificationSettings-DzGuAAKt.js → NotificationSettings-B5ECNQNW.js} +1 -1
  42. package/src/assets/web-panel/assets/{Organization-DFfncYaU.js → Organization-Dn98sbrZ.js} +4 -4
  43. package/src/assets/web-panel/assets/{Overflow-O5JDtvyx.js → Overflow-Sl5FJV2c.js} +1 -1
  44. package/src/assets/web-panel/assets/{P2P-BTLl5rnf.js → P2P-58-TvQSE.js} +2 -2
  45. package/src/assets/web-panel/assets/{Permissions-M-jmJa1X.js → Permissions-BFtHCNck.js} +4 -4
  46. package/src/assets/web-panel/assets/PersonalDataHub-CVH9NAfL.css +1 -0
  47. package/src/assets/web-panel/assets/PersonalDataHub-Cu--XeWZ.js +1 -0
  48. package/src/assets/web-panel/assets/{Pipeline-DyXoKp_J.js → Pipeline-DWt_M98L.js} +1 -1
  49. package/src/assets/web-panel/assets/{Privacy-Cvv_9eBQ.js → Privacy-BUX3yRZc.js} +1 -1
  50. package/src/assets/web-panel/assets/{ProjectInit-BS2s_sxy.js → ProjectInit-wYWMWfxy.js} +2 -2
  51. package/src/assets/web-panel/assets/{ProjectSettings-CGfEpOL1.js → ProjectSettings-CIRbqu0F.js} +1 -1
  52. package/src/assets/web-panel/assets/{Projects-BkuTxL3o.js → Projects-CDFkiEL3.js} +1 -1
  53. package/src/assets/web-panel/assets/{Providers-CkhZ5eii.js → Providers-CnPu1q45.js} +1 -1
  54. package/src/assets/web-panel/assets/{QuickAsk-CvGT4zj2.js → QuickAsk-mwOI7Tc-.js} +1 -1
  55. package/src/assets/web-panel/assets/{Recommend-C-gDvXw6.js → Recommend-Ct6SM2HV.js} +1 -1
  56. package/src/assets/web-panel/assets/{Reputation-5zAdCzHT.js → Reputation-D7D6rp3d.js} +1 -1
  57. package/src/assets/web-panel/assets/{Row-BsuDvMpO.js → Row-CX03nw4D.js} +1 -1
  58. package/src/assets/web-panel/assets/{RssFeed-2QQb8p5X.js → RssFeed-BRyNIOp0.js} +3 -3
  59. package/src/assets/web-panel/assets/{Search-CFT_6Ljj.js → Search-Dh-jwNaq.js} +1 -1
  60. package/src/assets/web-panel/assets/{Security-BrK_KNJK.js → Security-C53OqK_S.js} +3 -3
  61. package/src/assets/web-panel/assets/Services-nXK7991F.js +2 -0
  62. package/src/assets/web-panel/assets/{Skeleton--WjfL2Ay.js → Skeleton-mVGGUSnx.js} +1 -1
  63. package/src/assets/web-panel/assets/{Skills-1GWFYMGg.js → Skills-AVICQyr7.js} +1 -1
  64. package/src/assets/web-panel/assets/{Sla-508cBkmT.js → Sla-BO-jiswJ.js} +1 -1
  65. package/src/assets/web-panel/assets/{SpeechSettings-DIeNRX6V.js → SpeechSettings-CQ73BtGw.js} +1 -1
  66. package/src/assets/web-panel/assets/{SyncSettings-BQDW6gsX.js → SyncSettings-ozTu_ihm.js} +1 -1
  67. package/src/assets/web-panel/assets/{Tasks-D39SBKyi.js → Tasks-CwTiFnau.js} +1 -1
  68. package/src/assets/web-panel/assets/{Templates-tsObCBe6.js → Templates-PJ-SYUEg.js} +1 -1
  69. package/src/assets/web-panel/assets/{Tenant-Ccpw-S6R.js → Tenant-DeckYbHe.js} +1 -1
  70. package/src/assets/web-panel/assets/Terminal-CIn4gdxj.js +3 -0
  71. package/src/assets/web-panel/assets/Tokens-Bc40cdFh.js +1 -0
  72. package/src/assets/web-panel/assets/{Trigger-D4yonKuU.js → Trigger-BERtmWcc.js} +1 -1
  73. package/src/assets/web-panel/assets/{Trust-DHDcLjma.js → Trust-_ktoDZt-.js} +1 -1
  74. package/src/assets/web-panel/assets/{UkeySign-DBpW0j1p.js → UkeySign-DecT3_Zy.js} +1 -1
  75. package/src/assets/web-panel/assets/{VideoEditing-BPr_46Py.js → VideoEditing-AqPQa7a7.js} +1 -1
  76. package/src/assets/web-panel/assets/{Wallet-4lfplIJV.js → Wallet-CL303fn9.js} +4 -4
  77. package/src/assets/web-panel/assets/{WebAuthn-DI13wkez.js → WebAuthn-Bwy0YO-u.js} +4 -4
  78. package/src/assets/web-panel/assets/{WorkflowEditor-CYbHpkQy.js → WorkflowEditor-Bbewn3S4.js} +1 -1
  79. package/src/assets/web-panel/assets/{chat-BOH4vNJ7.js → chat-CDIxA8Km.js} +1 -1
  80. package/src/assets/web-panel/assets/{colors-qxXJ45GU.js → colors-rQIxLS12.js} +1 -1
  81. package/src/assets/web-panel/assets/{compact-item-Cjb446yk.js → compact-item-1jZiKenx.js} +1 -1
  82. package/src/assets/web-panel/assets/{createContext-CulBut34.js → createContext-B3FjOuaT.js} +1 -1
  83. package/src/assets/web-panel/assets/{hasIn-DCnwRrNq.js → hasIn-dZ195iTN.js} +1 -1
  84. package/src/assets/web-panel/assets/{icons-DY9VpXfa.js → icons-BFHq5fEF.js} +1 -1
  85. package/src/assets/web-panel/assets/{index-C7reeGYU.js → index--NxZmEUk.js} +1 -1
  86. package/src/assets/web-panel/assets/{index-BAy0ks7N.js → index-19d37fVJ.js} +4 -4
  87. package/src/assets/web-panel/assets/{index-CRsnuDGC.js → index-AHCOz9NC.js} +1 -1
  88. package/src/assets/web-panel/assets/{index-CV_vlbaU.js → index-BByVZ5fI.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-CjJUQvIU.js → index-BC6wcYy3.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-Bp4_7Kow.js → index-BDZd1181.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-DG1F9RZd.js → index-BOiuM69x.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-DpzjQM4w.js → index-Bq8fsYQ6.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-DC38ymaH.js → index-Br6-EXdw.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-BA8bUOYK.js → index-BsUXzEb2.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CW7a8O5w.js → index-BwIwGE8Y.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-D80IlXq1.js → index-Bx15E0JQ.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BOFep_rA.js → index-BxnEM3za.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-C_029Hie.js → index-C0YzTiiB.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BKNbteyC.js → index-C3SVypM3.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-D3bXm2aZ.js → index-C3rYUvdl.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-PP5MLidC.js → index-C4jmdcCs.js} +1 -1
  102. package/src/assets/web-panel/assets/index-C5Ifo5EH.js +1 -0
  103. package/src/assets/web-panel/assets/{index-Bb1KdW4J.js → index-C8IGQbfQ.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BBWR20mC.js → index-CDL_WWYl.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DQXojJvN.js → index-CDkCJPtr.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-hca2ku7U.js → index-D0DtKH7N.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DkYY9W4x.js → index-D3QDmYBa.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-oGqObYfs.js → index-DP5rV4eS.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BCr0xH2Q.js → index-DQXt91YA.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Cv2hQG7c.js → index-DRIQpe4j.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-C3ImsNgP.js → index-DWJ5GzxU.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BO-vFfxc.js → index-Dvg5ymRK.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-SHmkRPZ_.js → index-DxwYB7eB.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Clxp_Rc0.js → index-U5Y4YNZC.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DNooejFX.js → index-XDvSQBl5.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-cP5FNe0q.js → index-aaHXeryL.js} +1 -1
  117. package/src/assets/web-panel/assets/index-efjrWv6y.js +1 -0
  118. package/src/assets/web-panel/assets/{index-DK5iJriy.js → index-hNSGbn-4.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-6xtj6SRQ.js → index-kg4NgBuP.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Civlun-X.js → index-lSnZsO_d.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-XMsNvoaz.js → index-sygYO1j4.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-D6-3yvOU.js → index-uL0KmFyf.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CFw2RtQ_.js → index-xKOyC0Cx.js} +1 -1
  124. package/src/assets/web-panel/assets/{initDefaultProps-Dp93Vlbv.js → initDefaultProps-GbvcoqYL.js} +1 -1
  125. package/src/assets/web-panel/assets/{motion-yBy7l6Td.js → motion-VM5YQ6Mf.js} +1 -1
  126. package/src/assets/web-panel/assets/{move-P6GgC8ZU.js → move-CJvGLYlg.js} +1 -1
  127. package/src/assets/web-panel/assets/{omit-BMF4_2X_.js → omit-3oHJWwWB.js} +1 -1
  128. package/src/assets/web-panel/assets/{pickAttrs-C1bUV-iL.js → pickAttrs-BWBtl13u.js} +1 -1
  129. package/src/assets/web-panel/assets/{placementArrow-CpNGMWxW.js → placementArrow-CVESPqrs.js} +1 -1
  130. package/src/assets/web-panel/assets/{responsiveObserve-Bt3UzGUn.js → responsiveObserve-BOvUPufq.js} +1 -1
  131. package/src/assets/web-panel/assets/{slide-B5t0Lgse.js → slide-W_P685Dw.js} +1 -1
  132. package/src/assets/web-panel/assets/{statusUtils-nHmUS8yg.js → statusUtils-BnIQmxwT.js} +1 -1
  133. package/src/assets/web-panel/assets/{styleChecker-DgazP1mu.js → styleChecker-BMXx5Ie5.js} +1 -1
  134. package/src/assets/web-panel/assets/{useFlexGapSupport-BQ4jJS_s.js → useFlexGapSupport-DSJ4Pl17.js} +1 -1
  135. package/src/assets/web-panel/assets/{useFs-C8aeIQfU.js → useFs-BPbHm7Yn.js} +1 -1
  136. package/src/assets/web-panel/assets/{vnode-DMH0ymoP.js → vnode-HDTJKu2B.js} +1 -1
  137. package/src/assets/web-panel/assets/{zoom-DRmMxFNC.js → zoom-BqKDJys9.js} +1 -1
  138. package/src/assets/web-panel/index.html +2 -2
  139. package/src/commands/ui.js +21 -3
  140. package/src/gateways/ws/message-dispatcher.js +68 -0
  141. package/src/gateways/ws/personal-data-hub-protocol.js +264 -0
  142. package/src/lib/personal-data-hub-wiring.js +425 -0
  143. package/src/runtime/agent-runtime.js +85 -11
  144. package/src/assets/web-panel/assets/AppLayout-BzzvYjpq.js +0 -3
  145. package/src/assets/web-panel/assets/Compliance-DCkF4hfd.js +0 -1
  146. package/src/assets/web-panel/assets/KnowledgeGraph-nTHxy0Fw.js +0 -1
  147. package/src/assets/web-panel/assets/Services-DAmjLm-1.js +0 -2
  148. package/src/assets/web-panel/assets/Terminal-CgFg09NA.js +0 -3
  149. package/src/assets/web-panel/assets/Tokens-BBWOiqLq.js +0 -1
  150. package/src/assets/web-panel/assets/index-B0YFQoW_.js +0 -1
  151. package/src/assets/web-panel/assets/index-BX7snsTz.js +0 -1
@@ -0,0 +1,425 @@
1
+ /**
2
+ * Personal Data Hub — CLI / web-shell wiring.
3
+ *
4
+ * Mirror of desktop-app-vue/src/main/personal-data-hub/wiring.js so the
5
+ * SAME vault is reachable from both the Electron app's IPC channels AND
6
+ * the `cc ui` / `cc serve` web-shell's WS topics. Per memory
7
+ * feedback_cross_shell_feature_pattern: any new feature must be reachable
8
+ * via both gateways or the SPA's behavior diverges across shells.
9
+ *
10
+ * Shared vault path: getElectronUserDataDir() + "/.chainlesschain/hub/"
11
+ * — resolves to the same directory that the Electron app uses, so opening
12
+ * either shell sees the same data. Only ONE process should hold the vault
13
+ * at a time (SQLite WAL allows multi-reader / single-writer, but for v0
14
+ * we assume serial access — Phase 4 will add a file-lock).
15
+ *
16
+ * LLM wiring: cli has no llm-manager singleton — it relies on
17
+ * lib/llm-providers.js + per-command HTTP calls. v0 cli-side hub uses a
18
+ * direct OllamaClient (the hub's standalone fallback). To use the same
19
+ * provider the desktop app uses (Volcengine etc.), pass a custom chat
20
+ * function via the env var CC_HUB_LLM_BASE (Ollama URL) or wire it later
21
+ * when cli ↔ desktop LLM sharing is figured out.
22
+ *
23
+ * KG / RAG wiring: same cli modules the desktop uses via dynamic import —
24
+ * but here we're already in cli, so direct import works.
25
+ */
26
+
27
+ import { join } from "node:path";
28
+ import { mkdirSync } from "node:fs";
29
+ // Hub package is CJS; in ESM we default-import then destructure (Node 22
30
+ // won't let us name-import a CJS module unless it ships a separate ESM
31
+ // shim, which we don't).
32
+ import hub from "@chainlesschain/personal-data-hub";
33
+ const {
34
+ LocalVault,
35
+ AdapterRegistry,
36
+ AnalysisEngine,
37
+ MockAdapter,
38
+ OllamaClient,
39
+ CcKgSink,
40
+ CcRagSink,
41
+ FileKeyProvider,
42
+ generateKeyHex,
43
+ EmailAdapter,
44
+ AlipayBillAdapter,
45
+ EntityResolver,
46
+ EntityResolverEmbeddingStage,
47
+ EntityResolverLLMStage,
48
+ } = hub;
49
+ import { readFileSync, writeFileSync, existsSync } from "node:fs";
50
+ import { getElectronUserDataDir } from "./paths.js";
51
+
52
+ // ─── Lazy ESM imports of cli KG / BM25 ───────────────────────────────────
53
+
54
+ let _kgMod = null;
55
+ async function loadKg() {
56
+ if (_kgMod) return _kgMod;
57
+ try {
58
+ _kgMod = await import("./knowledge-graph.js");
59
+ } catch (_err) {
60
+ _kgMod = null;
61
+ }
62
+ return _kgMod;
63
+ }
64
+
65
+ let _bm25Mod = null;
66
+ async function loadBm25() {
67
+ if (_bm25Mod) return _bm25Mod;
68
+ try {
69
+ _bm25Mod = await import("./bm25-search.js");
70
+ } catch (_err) {
71
+ _bm25Mod = null;
72
+ }
73
+ return _bm25Mod;
74
+ }
75
+
76
+ // ─── Hub singleton (CLI process scope) ───────────────────────────────────
77
+
78
+ let _hub = null;
79
+ let _initPromise = null;
80
+ let _bm25 = null;
81
+
82
+ export function resolveHubDir() {
83
+ return join(getElectronUserDataDir(), ".chainlesschain", "hub");
84
+ }
85
+
86
+ async function initHub() {
87
+ const hubDir = resolveHubDir();
88
+ mkdirSync(hubDir, { recursive: true });
89
+ mkdirSync(join(hubDir, "keys"), { recursive: true });
90
+
91
+ const keyProvider = new FileKeyProvider(join(hubDir, "keys"));
92
+ const KEY_NAME = "vault:default";
93
+ let key = await keyProvider.get(KEY_NAME);
94
+ if (!key) {
95
+ key = generateKeyHex();
96
+ await keyProvider.set(KEY_NAME, key);
97
+ }
98
+
99
+ const vault = new LocalVault({ path: join(hubDir, "vault.db"), key });
100
+ vault.open();
101
+
102
+ // LLM: standalone OllamaClient — connects to localhost:11434.
103
+ // Override via env CC_HUB_OLLAMA_URL / CC_HUB_OLLAMA_MODEL.
104
+ const llm = new OllamaClient({
105
+ baseUrl: process.env.CC_HUB_OLLAMA_URL || "http://localhost:11434",
106
+ model: process.env.CC_HUB_OLLAMA_MODEL || "qwen2.5:7b-instruct",
107
+ });
108
+
109
+ // KG sink — direct ESM import works here.
110
+ let kgSink = null;
111
+ const kgMod = await loadKg();
112
+ if (
113
+ kgMod &&
114
+ typeof kgMod.addEntity === "function" &&
115
+ typeof kgMod.addRelation === "function"
116
+ ) {
117
+ kgSink = new CcKgSink({
118
+ addEntity: kgMod.addEntity,
119
+ addRelation: kgMod.addRelation,
120
+ db: null,
121
+ });
122
+ }
123
+
124
+ // RAG sink — instantiate a BM25 per hub.
125
+ let ragSink = null;
126
+ const bm25Mod = await loadBm25();
127
+ if (bm25Mod && typeof bm25Mod.BM25Search === "function") {
128
+ _bm25 = new bm25Mod.BM25Search({ language: "auto" });
129
+ ragSink = new CcRagSink({ bm25: _bm25 });
130
+ }
131
+
132
+ // Phase 8 — EntityResolver pipeline
133
+ const entityResolver = new EntityResolver({ vault });
134
+ try {
135
+ if (llm) {
136
+ const llmStage = new EntityResolverLLMStage({
137
+ llm,
138
+ acceptNonLocal: false,
139
+ });
140
+ entityResolver._llmStage = llmStage.asStageFn();
141
+ }
142
+ const embeddingStage = new EntityResolverEmbeddingStage({
143
+ ollamaUrl: process.env.CC_HUB_OLLAMA_URL || "http://localhost:11434",
144
+ model: process.env.CC_HUB_OLLAMA_EMBED_MODEL || "nomic-embed-text",
145
+ vault,
146
+ });
147
+ entityResolver._embeddingStage = embeddingStage.asStageFn();
148
+ } catch (_err) {
149
+ // Fall back to rule-only — registry still works
150
+ }
151
+
152
+ const registry = new AdapterRegistry({
153
+ vault,
154
+ kgSink: kgSink ? kgSink.write.bind(kgSink) : null,
155
+ ragSink: ragSink ? ragSink.write.bind(ragSink) : null,
156
+ entityResolver,
157
+ });
158
+
159
+ const engine = new AnalysisEngine({
160
+ vault,
161
+ llm,
162
+ ragRetriever: _bm25
163
+ ? async (question) => {
164
+ try {
165
+ const hits = _bm25.search(question, { topK: 10 });
166
+ return Array.isArray(hits)
167
+ ? hits
168
+ .map((h) => ({
169
+ id: h.id || (h.doc && h.doc.id),
170
+ text: "",
171
+ metadata: {},
172
+ }))
173
+ .filter((d) => d.id)
174
+ : [];
175
+ } catch (_e) {
176
+ return [];
177
+ }
178
+ }
179
+ : null,
180
+ });
181
+
182
+ // Phase 5.6: auto-register persisted email accounts.
183
+ const emailAccountsPath = join(hubDir, "email-accounts.json");
184
+ const emailAccounts = loadEmailAccounts(emailAccountsPath);
185
+ for (const cfg of emailAccounts) {
186
+ try {
187
+ const adapter = new EmailAdapter({
188
+ account: cfg.account,
189
+ ...(cfg.opts || {}),
190
+ });
191
+ registry.register(adapter);
192
+ } catch (_err) {
193
+ // Continue boot even if one config is corrupt
194
+ }
195
+ }
196
+
197
+ // Phase 6: auto-register persisted Alipay accounts.
198
+ const alipayAccountsPath = join(hubDir, "alipay-accounts.json");
199
+ const alipayAccounts = loadAlipayAccounts(alipayAccountsPath);
200
+ for (const cfg of alipayAccounts) {
201
+ try {
202
+ const adapter = new AlipayBillAdapter({
203
+ account: cfg.account,
204
+ ...(cfg.opts || {}),
205
+ });
206
+ if (!registry.has(adapter.name)) registry.register(adapter);
207
+ } catch (_err) {
208
+ // Continue boot even if one config is corrupt
209
+ }
210
+ }
211
+
212
+ return {
213
+ vault,
214
+ registry,
215
+ engine,
216
+ llm,
217
+ kgSink,
218
+ ragSink,
219
+ hubDir,
220
+ keyProvider,
221
+ emailAccountsPath,
222
+ alipayAccountsPath,
223
+ entityResolver,
224
+ bm25: _bm25,
225
+ registerMockAdapter(opts = {}) {
226
+ if (registry.has(opts.name || "mock"))
227
+ return registry.get(opts.name || "mock");
228
+ const adapter = new MockAdapter(opts);
229
+ registry.register(adapter);
230
+ return adapter;
231
+ },
232
+
233
+ /** Phase 5.6 — see desktop wiring for full doc */
234
+ async testEmailAuth({ account }) {
235
+ if (!account || typeof account !== "object")
236
+ throw new Error("account required");
237
+ const adapter = new EmailAdapter({ account });
238
+ return await adapter.authenticate();
239
+ },
240
+
241
+ async registerEmailAdapter({ account, opts = {} } = {}) {
242
+ if (!account || typeof account !== "object")
243
+ throw new Error("account required");
244
+ const adapter = new EmailAdapter({ account, ...opts });
245
+ if (registry.has(adapter.name)) {
246
+ throw new Error(`adapter name "${adapter.name}" already registered`);
247
+ }
248
+ registry.register(adapter);
249
+ const accounts = loadEmailAccounts(emailAccountsPath);
250
+ const next = accounts.filter((c) => c.account.email !== account.email);
251
+ next.push({ account, opts, registeredAt: Date.now() });
252
+ saveEmailAccounts(emailAccountsPath, next);
253
+ return {
254
+ name: adapter.name,
255
+ version: adapter.version,
256
+ capabilities: adapter.capabilities,
257
+ sensitivity: adapter.dataDisclosure.sensitivity,
258
+ };
259
+ },
260
+
261
+ async unregisterEmailAdapter(emailAddress) {
262
+ const accounts = loadEmailAccounts(emailAccountsPath);
263
+ const target = accounts.find((c) => c.account.email === emailAddress);
264
+ const next = accounts.filter((c) => c.account.email !== emailAddress);
265
+ saveEmailAccounts(emailAccountsPath, next);
266
+ if (target) registry.unregister("email-imap");
267
+ return { ok: true, removed: !!target };
268
+ },
269
+
270
+ listEmailAccounts() {
271
+ return loadEmailAccounts(emailAccountsPath).map((c) => ({
272
+ email: c.account.email,
273
+ provider: c.account.provider,
274
+ folders: c.account.folders || null,
275
+ registeredAt: c.registeredAt || null,
276
+ pdfPasswordHints:
277
+ c.opts && c.opts.pdfPasswordHints
278
+ ? Object.keys(c.opts.pdfPasswordHints)
279
+ : [],
280
+ }));
281
+ },
282
+
283
+ eventDetail(eventId) {
284
+ const ev = vault.getEvent ? vault.getEvent(eventId) : null;
285
+ if (!ev) return null;
286
+ return {
287
+ event: ev,
288
+ classification:
289
+ ev.extra && ev.extra.classification ? ev.extra.classification : null,
290
+ extraction:
291
+ ev.extra && ev.extra.fields
292
+ ? {
293
+ template: ev.extra.extractionTemplate,
294
+ confidence: ev.extra.extractionConfidence,
295
+ fields: ev.extra.fields,
296
+ warnings: ev.extra.extractionWarnings || [],
297
+ pdfExtraction: ev.extra.pdfExtraction || null,
298
+ }
299
+ : null,
300
+ };
301
+ },
302
+
303
+ // ─── Phase 6 — Alipay bill import ──────────────────────────────────
304
+
305
+ async registerAlipayAdapter({ account, opts = {} } = {}) {
306
+ if (!account || typeof account !== "object")
307
+ throw new Error("account required");
308
+ const adapter = new AlipayBillAdapter({ account, ...opts });
309
+ if (registry.has(adapter.name)) registry.unregister(adapter.name);
310
+ registry.register(adapter);
311
+ const accounts = loadAlipayAccounts(alipayAccountsPath);
312
+ const next = accounts.filter((c) => c.account.email !== account.email);
313
+ next.push({ account, opts, registeredAt: Date.now() });
314
+ saveAlipayAccounts(alipayAccountsPath, next);
315
+ return {
316
+ name: adapter.name,
317
+ version: adapter.version,
318
+ capabilities: adapter.capabilities,
319
+ sensitivity: adapter.dataDisclosure.sensitivity,
320
+ };
321
+ },
322
+
323
+ async unregisterAlipayAdapter(email) {
324
+ const accounts = loadAlipayAccounts(alipayAccountsPath);
325
+ const target = accounts.find((c) => c.account.email === email);
326
+ const next = accounts.filter((c) => c.account.email !== email);
327
+ saveAlipayAccounts(alipayAccountsPath, next);
328
+ if (target) registry.unregister("alipay-bill");
329
+ return { ok: true, removed: !!target };
330
+ },
331
+
332
+ listAlipayAccounts() {
333
+ return loadAlipayAccounts(alipayAccountsPath).map((c) => ({
334
+ email: c.account.email,
335
+ hasZipPassword: !!(
336
+ c.account.zipPassword ||
337
+ (c.opts && c.opts.zipPassword)
338
+ ),
339
+ registeredAt: c.registeredAt || null,
340
+ }));
341
+ },
342
+
343
+ async importAlipayBill({ zipPath, csvPath, zipPassword } = {}) {
344
+ const adapter = registry.get("alipay-bill");
345
+ if (!adapter)
346
+ throw new Error(
347
+ "No Alipay adapter registered — call registerAlipayAdapter first",
348
+ );
349
+ return await registry.syncAdapter("alipay-bill", {
350
+ zipPath,
351
+ csvPath,
352
+ zipPassword,
353
+ });
354
+ },
355
+ };
356
+ }
357
+
358
+ // ─── Email account persistence (Phase 5.6) ───────────────────────────────
359
+
360
+ function loadEmailAccounts(filePath) {
361
+ try {
362
+ if (!existsSync(filePath)) return [];
363
+ const raw = readFileSync(filePath, "utf-8");
364
+ const parsed = JSON.parse(raw);
365
+ return Array.isArray(parsed) ? parsed : [];
366
+ } catch (_err) {
367
+ return [];
368
+ }
369
+ }
370
+
371
+ function saveEmailAccounts(filePath, accounts) {
372
+ writeFileSync(filePath, JSON.stringify(accounts, null, 2), {
373
+ encoding: "utf-8",
374
+ mode: 0o600,
375
+ });
376
+ }
377
+
378
+ // ─── Alipay account persistence (Phase 6) ───────────────────────────────
379
+
380
+ function loadAlipayAccounts(filePath) {
381
+ try {
382
+ if (!existsSync(filePath)) return [];
383
+ const raw = readFileSync(filePath, "utf-8");
384
+ const parsed = JSON.parse(raw);
385
+ return Array.isArray(parsed) ? parsed : [];
386
+ } catch (_err) {
387
+ return [];
388
+ }
389
+ }
390
+
391
+ function saveAlipayAccounts(filePath, accounts) {
392
+ writeFileSync(filePath, JSON.stringify(accounts, null, 2), {
393
+ encoding: "utf-8",
394
+ mode: 0o600,
395
+ });
396
+ }
397
+
398
+ export async function getHub() {
399
+ if (_hub) return _hub;
400
+ if (!_initPromise) {
401
+ _initPromise = initHub()
402
+ .then((h) => {
403
+ _hub = h;
404
+ return h;
405
+ })
406
+ .catch((err) => {
407
+ _initPromise = null;
408
+ throw err;
409
+ });
410
+ }
411
+ return _initPromise;
412
+ }
413
+
414
+ export function close() {
415
+ if (_hub && _hub.vault) {
416
+ try {
417
+ _hub.vault.close();
418
+ } catch (_e) {}
419
+ }
420
+ _hub = null;
421
+ _initPromise = null;
422
+ _bm25 = null;
423
+ _kgMod = null;
424
+ _bm25Mod = null;
425
+ }
@@ -626,6 +626,41 @@ export class AgentRuntime {
626
626
  runtimeLogger.log(
627
627
  ` Auth: ${this.policy.token ? chalk.green("enabled") : chalk.yellow("disabled")}`,
628
628
  );
629
+ // When bound to 0.0.0.0 the user needs a reachable URL — enumerate the
630
+ // non-loopback IPv4 addresses (typically wlan0 on Android, eth0 on a
631
+ // server) so they can copy/paste the full URL onto another device. Also
632
+ // print the auth token here when present so the user doesn't have to dig
633
+ // it out of env vars. NB: this is local-network display only; we never
634
+ // leak the token over the wire beyond ws/http to clients holding it.
635
+ if (host === "0.0.0.0") {
636
+ try {
637
+ const os = await import("os");
638
+ const ifaces = os.networkInterfaces();
639
+ const lanUrls = [];
640
+ for (const [, addrs] of Object.entries(ifaces)) {
641
+ for (const a of addrs || []) {
642
+ if (a.family === "IPv4" && !a.internal) {
643
+ lanUrls.push(`http://${a.address}:${actualHttpPort}`);
644
+ }
645
+ }
646
+ }
647
+ if (lanUrls.length > 0) {
648
+ runtimeLogger.log("");
649
+ runtimeLogger.log(chalk.bold(" LAN access:"));
650
+ for (const u of lanUrls) {
651
+ runtimeLogger.log(` ${chalk.cyan(u)}`);
652
+ }
653
+ }
654
+ } catch (_err) {
655
+ // Best-effort — keep banner working even if os import fails.
656
+ }
657
+ }
658
+ if (this.policy.token) {
659
+ runtimeLogger.log("");
660
+ runtimeLogger.log(
661
+ ` Token: ${chalk.yellow(this.policy.token)} ${chalk.dim("(append as ?token=<TOKEN> or paste into login screen)")}`,
662
+ );
663
+ }
629
664
  runtimeLogger.log("");
630
665
  runtimeLogger.log(chalk.dim(" Press Ctrl+C to stop"));
631
666
  runtimeLogger.log("");
@@ -634,20 +669,59 @@ export class AgentRuntime {
634
669
  this.deps.openBrowser(uiUrl);
635
670
  }
636
671
 
672
+ // Force-exit after this deadline if graceful shutdown stalls (typically
673
+ // httpServer.close hanging on persistent keep-alive / WS connections,
674
+ // which is exactly what makes Ctrl+C feel dead on Android local terminal
675
+ // — the pty never sees the prompt return because node never exits).
676
+ const SHUTDOWN_TIMEOUT_MS = 2000;
677
+ let shuttingDown = false;
637
678
  const shutdown = async () => {
679
+ if (shuttingDown) {
680
+ // Second Ctrl+C while still draining — escalate immediately.
681
+ runtimeLogger.log(chalk.red("\nForce-exiting..."));
682
+ process.exit(130);
683
+ }
684
+ shuttingDown = true;
638
685
  runtimeLogger.log("\n" + chalk.yellow("Shutting down UI server..."));
639
- if (mcpClient && typeof mcpClient.disconnectAll === "function") {
640
- await mcpClient.disconnectAll().catch(() => undefined);
686
+ // NB: do NOT unref() this timer. With unref(), if every other handle
687
+ // clears before the timer fires, the event loop exits and force-exit
688
+ // never runs — exactly the bug we hit on Xiaomi 24115RA8EC 2026-05-19:
689
+ // SIGINT → handler logged "Shutting down" → never exited. We WANT this
690
+ // timer to keep the loop alive through the SHUTDOWN_TIMEOUT_MS window.
691
+ // clearTimeout in the success branches handles graceful exits.
692
+ const forceExit = setTimeout(() => {
693
+ runtimeLogger.log(
694
+ chalk.red(
695
+ `Graceful shutdown stalled after ${SHUTDOWN_TIMEOUT_MS}ms, force-exiting`,
696
+ ),
697
+ );
698
+ process.exit(130);
699
+ }, SHUTDOWN_TIMEOUT_MS);
700
+ try {
701
+ if (mcpClient && typeof mcpClient.disconnectAll === "function") {
702
+ await mcpClient.disconnectAll().catch(() => undefined);
703
+ }
704
+ // Kill all PTY sessions before WS so the SPA gets clean terminal.exit
705
+ // frames; without this, node-pty children would outlive cc ui until
706
+ // their OS parent (the cc ui process) actually exits.
707
+ this._terminalCleanup?.();
708
+ // Force-close any persistent HTTP keep-alive / WS upgrades; without
709
+ // this, httpServer.close waits for every browser tab to close its
710
+ // socket before resolving — which never happens until the user
711
+ // manually closes the tab.
712
+ if (typeof httpServer.closeAllConnections === "function") {
713
+ httpServer.closeAllConnections();
714
+ }
715
+ await Promise.all([
716
+ new Promise((resolve) => httpServer.close(resolve)),
717
+ wsServer.stop(),
718
+ ]);
719
+ clearTimeout(forceExit);
720
+ process.exit(0);
721
+ } catch (_err) {
722
+ clearTimeout(forceExit);
723
+ process.exit(1);
641
724
  }
642
- // Kill all PTY sessions before WS so the SPA gets clean terminal.exit
643
- // frames; without this, node-pty children would outlive cc ui until
644
- // their OS parent (the cc ui process) actually exits.
645
- this._terminalCleanup?.();
646
- await Promise.all([
647
- new Promise((resolve) => httpServer.close(resolve)),
648
- wsServer.stop(),
649
- ]);
650
- process.exit(0);
651
725
  };
652
726
 
653
727
  process.on("SIGINT", shutdown);
@@ -1,3 +0,0 @@
1
- import{f as O,r as K,o as _e,x as pt,K as d,L as c,M as g,c as e,N as t,u as a,R as l,O as i,P as s,Q as C,F as V,Y as ot,Z as J,S as P,I as nt,e as yt,_ as mt,w as ft,H as _t,$ as kt}from"./vendor-M5lGV-wr.js";import{u as ke,_ as ge,E as gt,a as vt,b as ht,T as bt,c as wt,d as G}from"./index-BAy0ks7N.js";import{u as q}from"./useShellMode-CgR0wCYM.js";import{B as fe,R as $t,M as ue,F as Y,G as ee,D as te,h as he,i as ae,j as be,k as oe,A as we,N as $e,l as Le,m as Oe,n as Se,o as Ce,S as Ee,p as Re,q as Ae,r as ne,s as Ne,t as je,u as Te,v as Be,w as Me,x as Pe,y as Ie,P as Ue,z as se,K as ie,H as D,J as De,O as le,Q as Ke,U as ze,W as Fe,V as me,X as re,Y as Ve,Z as qe,_ as ce,$ as We,a0 as He,a1 as Je,a2 as Ge,a3 as Ye,a4 as Ze,a5 as Qe,a6 as Xe,a7 as xe,a8 as et,a9 as Lt,aa as tt,e as Ot}from"./icons-DY9VpXfa.js";import St from"./index-DpzjQM4w.js";import"./KeyCode-D63Tfrq7.js";import"./omit-BMF4_2X_.js";import"./pickAttrs-C1bUV-iL.js";import"./initDefaultProps-Dp93Vlbv.js";import"./motion-yBy7l6Td.js";import"./raf-Deuc0E8-.js";import"./index-cP5FNe0q.js";import"./index-CW7a8O5w.js";import"./isVisible-C7tPsqfj.js";import"./useState-CSzR8F8O.js";import"./devWarning-CNIS3FrJ.js";import"./warning-Pq00owYb.js";import"./compact-item-Cjb446yk.js";import"./createContext-CulBut34.js";import"./Compact-D4E0roed.js";import"./_getTag-BVc6NQ_K.js";import"./styleChecker-DgazP1mu.js";import"./zoom-DRmMxFNC.js";import"./ActionButton-COVVHNnK.js";import"./vnode-DMH0ymoP.js";const Ct=""+new URL("logo-DBCYUiWP.png",import.meta.url).href,L={notifications:K([]),unreadCount:K(0)};function Z(h){if(h&&h.ok===!1)throw new Error(h.error||"notification handler failed");return h?.result??h}function Et(){const h=ke();async function T({limit:r=50,offset:u=0,isRead:_}={}){if(!q().isEmbedded)return L.notifications.value=[],L.unreadCount.value=0,L.notifications.value;const y=await h.sendRaw({type:"notification.list",limit:r,offset:u,isRead:_},15e3),w=Z(y);if(w?.success===!1)throw new Error(w.error||"notification.list failed");return L.notifications.value=Array.isArray(w?.notifications)?w.notifications:[],await E(),L.notifications.value}async function E(){if(!q().isEmbedded)return L.unreadCount.value=0,0;const r=await h.sendRaw({type:"notification.unread-count"},1e4),u=Z(r);return L.unreadCount.value=Number(u?.count)||0,L.unreadCount.value}async function k(r){if(r==null||r==="")throw new Error("id is required");if(!q().isEmbedded)return;const u=await h.sendRaw({type:"notification.mark-read",id:r},1e4),_=Z(u);if(_?.success===!1)throw new Error(_.error||"notification.mark-read failed");const y=L.notifications.value.find(w=>w.id===r);y&&(y.is_read=1),await E()}async function S(){if(!q().isEmbedded)return;const r=await h.sendRaw({type:"notification.mark-all-read"},1e4),u=Z(r);if(u?.success===!1)throw new Error(u.error||"notification.mark-all-read failed");for(const _ of L.notifications.value)_.is_read=1;L.unreadCount.value=0}async function b(r,u=""){if(!q().isEmbedded)throw new Error("桌面通知仅在嵌入式 web-shell 中可用");const _=await h.sendRaw({type:"notification.send-desktop",title:r,body:u},1e4),y=Z(_);if(y?.success===!1)throw new Error(y.error||"notification.send-desktop failed")}return{notifications:O(()=>L.notifications.value),unreadCount:O(()=>L.unreadCount.value),refresh:T,refreshUnreadCount:E,markRead:k,markAllRead:S,sendDesktop:b}}const Rt={class:"notif-toolbar"},At={class:"notif-body"},Nt={key:2,class:"notif-list"},jt=["onClick"],Tt={class:"notif-row"},Bt={class:"notif-title"},Mt={class:"notif-time"},Pt={key:0,class:"notif-message"},It={__name:"NotificationBell",setup(h){const T=K(!1),E=K("all"),k=K(!1),{notifications:S,unreadCount:b,refresh:r,markRead:u,markAllRead:_}=Et();function y(){N()}_e(()=>{window.addEventListener("cc:open-notification-drawer",y)}),pt(()=>{window.removeEventListener("cc:open-notification-drawer",y)});const w=O(()=>E.value==="unread"?S.value.filter(m=>!m.is_read):S.value);async function R(){if(q().isEmbedded){k.value=!0;try{await r({limit:100})}catch{}finally{k.value=!1}}}async function N(){T.value=!0,await R()}async function j(m){if(!m.is_read)try{await u(m.id)}catch{}}async function $(){try{await _()}catch(m){console.warn("[NotificationBell] markAllRead failed:",m?.message||m)}}function A(m){if(!m)return"";const f=typeof m=="string"?Date.parse(m):Number(m);if(!Number.isFinite(f))return String(m);const B=Date.now()-f,z=6e4,I=60*z,W=24*I;return B<z?"刚刚":B<I?`${Math.floor(B/z)} 分钟前`:B<W?`${Math.floor(B/I)} 小时前`:new Date(f).toLocaleDateString()}return(m,f)=>{const B=d("a-badge"),z=d("a-tooltip"),I=d("a-radio-button"),W=d("a-radio-group"),H=d("a-space"),Q=d("a-button"),de=d("a-empty"),pe=d("a-spin"),ye=d("a-drawer");return c(),g(V,null,[e(z,{title:"通知"},{default:t(()=>[e(B,{count:a(b),"overflow-count":99,offset:[-4,4]},{default:t(()=>[l("button",{type:"button",class:"notif-bell-btn","aria-label":"通知",onClick:N},[e(a(fe))])]),_:1},8,["count"])]),_:1}),e(ye,{open:T.value,"onUpdate:open":f[1]||(f[1]=v=>T.value=v),title:"通知中心",placement:"right",width:400,"body-style":{padding:0}},{default:t(()=>[l("div",Rt,[e(H,null,{default:t(()=>[e(W,{value:E.value,"onUpdate:value":f[0]||(f[0]=v=>E.value=v),size:"small","button-style":"solid"},{default:t(()=>[e(I,{value:"all"},{default:t(()=>[i("全部 ("+s(a(S).length)+")",1)]),_:1}),e(I,{value:"unread"},{default:t(()=>[i("未读 ("+s(a(b))+")",1)]),_:1})]),_:1},8,["value"])]),_:1}),e(H,null,{default:t(()=>[e(Q,{size:"small",loading:k.value,onClick:R},{icon:t(()=>[e(a($t))]),_:1},8,["loading"]),e(Q,{size:"small",disabled:a(b)===0,onClick:$},{default:t(()=>[...f[2]||(f[2]=[i(" 全部已读 ",-1)])]),_:1},8,["disabled"])]),_:1})]),l("div",At,[!k.value&&w.value.length===0?(c(),C(de,{key:0,description:"暂无通知",image:a(gt).PRESENTED_IMAGE_SIMPLE,style:{padding:"60px 0"}},null,8,["image"])):k.value?(c(),C(pe,{key:1,style:{display:"block",padding:"60px"}})):(c(),g("ul",Nt,[(c(!0),g(V,null,ot(w.value,v=>(c(),g("li",{key:v.id,class:J(["notif-item",{unread:!v.is_read}]),onClick:n=>j(v)},[l("div",Tt,[l("div",Bt,s(v.title||v.message||"(无标题)"),1),l("span",Mt,s(A(v.created_at)),1)]),v.message&&v.title?(c(),g("div",Pt,s(v.message),1)):P("",!0)],10,jt))),128))]))])]),_:1},8,["open"])],64)}}},Ut=ge(It,[["__scopeId","data-v-af539070"]]),Dt={key:0,class:"mbh-count"},Kt={__name:"MobileBridgeHeaderStatus",setup(h){function T(R){if(!R)return[];try{return JSON.parse(R)}catch{}const N=String(R).split(`
2
- `),j=N.findIndex($=>{const A=$.trim();if(!A)return!1;const m=A[0];if(m!=="["&&m!=="{")return!1;if(A.length===1)return!0;const f=A[1];return!(f>="A"&&f<="Z"||f>="a"&&f<="z")});if(j<0)return[];for(let $=N.length-1;$>=j;$--){const A=N[$].trim();if(/^[\]\}]/.test(A)&&!/^[\]\}][A-Za-z]/.test(A))try{return JSON.parse(N.slice(j,$+1).join(`
3
- `))}catch{return[]}}return[]}const E=nt(),k=ke(),S=K([]);let b=null;const r=O(()=>S.value.length),u=O(()=>r.value===0?"var(--text-muted, #999)":"#52c41a"),_=O(()=>r.value===0?"尚未配对任何手机 — 点击进入配对":`已配对 ${r.value} 台手机 — 点击进入管理`);async function y(){if(k.status==="connected")try{const{output:R}=await k.execute("p2p devices --type mobile --json",1e4);S.value=T(R)||[]}catch{}}function w(){E.push("/mobile-bridge")}return _e(()=>{y(),b=setInterval(y,5e3)}),yt(()=>{b&&(clearInterval(b),b=null)}),(R,N)=>{const j=d("a-badge"),$=d("a-tooltip");return c(),C($,{title:_.value},{default:t(()=>[e(j,{count:r.value,"show-zero":!1,"overflow-count":9,offset:[-2,4]},{default:t(()=>[l("button",{type:"button",class:J(["mbh-btn",{"mbh-btn--active":r.value>0}]),onClick:w},[e(a(ue),{style:mt({color:u.value,fontSize:"14px"})},null,8,["style"]),r.value>0?(c(),g("span",Dt,s(r.value),1)):P("",!0)],2)]),_:1},8,["count"])]),_:1},8,["title"])}}},zt=ge(Kt,[["__scopeId","data-v-05eb475d"]]),Ft=["src"],Vt={key:0,class:"logo-text"},qt={key:0,class:"mode-banner project"},Wt={class:"banner-info"},Ht={class:"banner-name"},Jt={class:"banner-sub"},Gt={key:1,class:"mode-banner global"},Yt={class:"banner-name"},Zt=["title"],Qt={class:"group-label"},Xt={class:"group-label"},xt={class:"group-label"},ea={class:"group-label"},ta={class:"group-label"},aa={class:"group-label"},oa={class:"group-label"},na={class:"group-label"},sa={class:"group-label"},ia={key:0,class:"footer-text"},la={class:"header-left"},ra={class:"header-right"},ca={class:"theme-switcher"},ua=["data-theme-key","onClick"],da=["data-locale"],pa={class:"lang-switch-label"},ya={class:"version-tag"},at="cc.web-panel.sidebar.openKeys",ma={__name:"AppLayout",setup(h){const T=nt(),E=_t(),k=ke(),S=vt(),{t:b}=ht(),r=q(),u=K(!1),_=window.__CC_CONFIG__||{},y=O(()=>_.mode==="project"),w="v5.0.3.65",R=O(()=>S.current),N=O(()=>S.config.vars["--menu-mode"]),j=O(()=>{const n=E.name?.toLowerCase()||"dashboard";return[{mcptools:"mcp",quickask:"quick-ask",ukeysign:"ukey-sign"}[n]||n]}),$=["g-overview","g-config","g-data","g-advanced","g-enterprise","g-social","g-media","g-extension"];function A(){try{const n=localStorage.getItem(at);if(n){const p=JSON.parse(n);if(Array.isArray(p))return p.filter(o=>$.includes(o))}}catch{}return[...$]}const m=K(A());ft(m,n=>{try{localStorage.setItem(at,JSON.stringify(n))}catch{}},{deep:!0});const f=O(()=>k.status),B=O(()=>({connected:"success",connecting:"processing",error:"error",disconnected:"default"})[k.status]||"default"),z=O(()=>{const n=`appLayout.footerStatus.${k.status}`,p=b(n);return p===n?b("appLayout.footerStatus.unknown"):p});function I(n){S.setTheme(n)}const{current:W,supported:H,setLocale:Q}=wt();function de(){const n=H[(H.indexOf(W.value)+1)%H.length];Q(n)}async function pe(n){try{const p=await k.sendRaw({type:"window.open",role:n},1e4);if(p?.ok===!1){G.error(`打开失败:${p.error||"未知"}`);return}const o=p?.result??p;o?.reason==="role_reserved"?G.warning("该窗口角色被保留"):o?.reason}catch(p){G.error(`打开桌面窗口失败:${p.message||p}`)}}async function ye(){St.confirm({title:"切换到桌面壳?",content:"回到 V5/V6 桌面壳。完整 electronAPI 表面(UKey 硬件 / 原生对话框 / 系统设置等)会重新可用,但失去 web-panel 的 SPA 体验。保存后需要重启应用才生效。",okText:"切换并重启",cancelText:"取消",centered:!0,async onOk(){try{const n=await k.sendRaw({type:"shell.switch",target:"desktop"},5e3);if(n?.ok===!1)throw new Error(n.error||"shell.switch returned failure");G.loading({content:"正在重启…",duration:0})}catch(n){const p=n instanceof Error?n.message:String(n);G.error("切换失败:"+p)}}})}function v({key:n}){if(typeof n=="string"&&n.startsWith("desktop:")){pe(n);return}T.push({mcp:"/mcp"}[n]||`/${n}`)}return _e(()=>k.connect()),(n,p)=>{const o=d("a-menu-item"),M=d("a-sub-menu"),F=d("a-menu-divider"),st=d("a-menu"),it=d("a-badge"),lt=d("a-layout-sider"),X=d("a-tooltip"),rt=d("a-tag"),ct=d("a-layout-header"),ut=d("router-view"),dt=d("a-layout-content"),ve=d("a-layout");return c(),C(ve,{class:"app-root"},{default:t(()=>[e(lt,{collapsed:u.value,"onUpdate:collapsed":p[2]||(p[2]=U=>u.value=U),collapsible:"","collapsed-width":56,width:216,class:"sidebar"},{default:t(()=>[l("div",{class:J(["logo",{collapsed:u.value}])},[l("img",{src:a(Ct),alt:"ChainlessChain",class:"logo-icon"},null,8,Ft),u.value?P("",!0):(c(),g("span",Vt,"ChainlessChain"))],2),u.value?(c(),g("div",{key:1,class:"mode-icon-sm",title:y.value?a(_).projectName:n.$t("appLayout.scope.global")},[y.value?(c(),C(a(Y),{key:0,style:{color:"#1677ff"}})):(c(),C(a(ee),{key:1,style:{color:"#722ed1"}}))],8,Zt)):(c(),g(V,{key:0},[y.value?(c(),g("div",qt,[e(a(Y),{class:"banner-icon"}),l("div",Wt,[l("div",Ht,s(a(_).projectName||n.$t("appLayout.scope.fallbackProject")),1),l("div",Jt,s(n.$t("appLayout.scope.projectPanel")),1)])])):(c(),g("div",Gt,[e(a(ee),{class:"banner-icon"}),l("span",Yt,s(n.$t("appLayout.scope.global")),1)]))],64)),e(st,{selectedKeys:j.value,"onUpdate:selectedKeys":p[0]||(p[0]=U=>j.value=U),openKeys:m.value,"onUpdate:openKeys":p[1]||(p[1]=U=>m.value=U),theme:N.value,mode:"inline","inline-collapsed":u.value,class:"side-menu",onClick:v},{default:t(()=>[u.value?(c(),g(V,{key:1},[e(o,{key:"dashboard"},{icon:t(()=>[e(a(te))]),_:1}),e(o,{key:"chat"},{icon:t(()=>[e(a(he))]),_:1}),e(o,{key:"quick-ask"},{icon:t(()=>[e(a(ae))]),_:1}),e(o,{key:"cowork"},{icon:t(()=>[e(a(be))]),_:1}),e(o,{key:"services"},{icon:t(()=>[e(a(oe))]),_:1}),e(o,{key:"aiops"},{icon:t(()=>[e(a(we))]),_:1}),e(o,{key:"tokens"},{icon:t(()=>[e(a($e))]),_:1}),e(o,{key:"logs"},{icon:t(()=>[e(a(Le))]),_:1}),e(F,{class:"divider-sm"}),e(o,{key:"skills"},{icon:t(()=>[e(a(Oe))]),_:1}),e(o,{key:"providers"},{icon:t(()=>[e(a(Se))]),_:1}),e(o,{key:"mcp"},{icon:t(()=>[e(a(Ce))]),_:1}),e(o,{key:"project-settings"},{icon:t(()=>[e(a(Y))]),_:1}),e(o,{key:"speech-settings"},{icon:t(()=>[e(a(Ee))]),_:1}),e(o,{key:"notification-settings"},{icon:t(()=>[e(a(fe))]),_:1}),e(o,{key:"sync-settings"},{icon:t(()=>[e(a(Re))]),_:1}),e(o,{key:"nlprog"},{icon:t(()=>[e(a(Ae))]),_:1}),e(o,{key:"codegen"},{icon:t(()=>[e(a(ne))]),_:1}),e(F,{class:"divider-sm"}),e(o,{key:"notes"},{icon:t(()=>[e(a(Ne))]),_:1}),e(o,{key:"search"},{icon:t(()=>[e(a(je))]),_:1}),e(o,{key:"memory"},{icon:t(()=>[e(a(Te))]),_:1}),e(o,{key:"knowledge"},{icon:t(()=>[e(a(Be))]),_:1}),e(o,{key:"marketplace"},{icon:t(()=>[e(a(Me))]),_:1}),e(o,{key:"cron"},{icon:t(()=>[e(a(Pe))]),_:1}),e(o,{key:"workflow"},{icon:t(()=>[e(a(Ie))]),_:1}),e(o,{key:"pipeline"},{icon:t(()=>[e(a(Ue))]),_:1}),e(o,{key:"tasks"},{icon:t(()=>[e(a(ae))]),_:1}),e(F,{class:"divider-sm"}),e(o,{key:"security"},{icon:t(()=>[e(a(se))]),_:1}),e(o,{key:"ukey-sign"},{icon:t(()=>[e(a(ie))]),_:1}),e(o,{key:"trust"},{icon:t(()=>[e(a(D))]),_:1}),e(o,{key:"audit"},{icon:t(()=>[e(a(De))]),_:1}),e(o,{key:"mtc"},{icon:t(()=>[e(a(D))]),_:1}),e(o,{key:"mtc-audit"},{icon:t(()=>[e(a(D))]),_:1}),e(o,{key:"multisig"},{icon:t(()=>[e(a(le))]),_:1}),e(o,{key:"did"},{icon:t(()=>[e(a(Ke))]),_:1}),e(o,{key:"permissions"},{icon:t(()=>[e(a(ze))]),_:1}),e(o,{key:"p2p"},{icon:t(()=>[e(a(Fe))]),_:1}),e(o,{key:"mobile-bridge"},{icon:t(()=>[e(a(ue))]),_:1}),e(o,{key:"terminal"},{icon:t(()=>[e(a(me))]),_:1}),e(o,{key:"backup"},{icon:t(()=>[e(a(re))]),_:1}),e(o,{key:"git"},{icon:t(()=>[e(a(ne))]),_:1}),e(o,{key:"projects"},{icon:t(()=>[e(a(Ve))]),_:1}),e(o,{key:"crosschain"},{icon:t(()=>[e(a(qe))]),_:1}),e(o,{key:"compliance"},{icon:t(()=>[e(a(D))]),_:1}),e(o,{key:"privacy"},{icon:t(()=>[e(a(ce))]),_:1}),e(o,{key:"inference"},{icon:t(()=>[e(a(We))]),_:1}),e(o,{key:"federation"},{icon:t(()=>[e(a(He))]),_:1}),e(F,{class:"divider-sm"}),e(o,{key:"wallet"},{icon:t(()=>[e(a(Je))]),_:1}),e(o,{key:"organization"},{icon:t(()=>[e(a(le))]),_:1}),e(o,{key:"tenant"},{icon:t(()=>[e(a(Ge))]),_:1}),e(o,{key:"sla"},{icon:t(()=>[e(a(te))]),_:1}),e(o,{key:"analytics"},{icon:t(()=>[e(a(Ye))]),_:1}),e(o,{key:"templates"},{icon:t(()=>[e(a(Ze))]),_:1}),e(F,{class:"divider-sm"}),e(o,{key:"community"},{icon:t(()=>[e(a(Qe))]),_:1}),e(o,{key:"governance"},{icon:t(()=>[e(a(Xe))]),_:1}),e(o,{key:"reputation"},{icon:t(()=>[e(a(xe))]),_:1}),e(o,{key:"recommend"},{icon:t(()=>[e(a(et))]),_:1}),e(F,{class:"divider-sm"}),e(o,{key:"rssfeed"},{icon:t(()=>[e(a(tt))]),_:1}),e(o,{key:"webauthn"},{icon:t(()=>[e(a(ie))]),_:1}),a(r).isEmbedded?(c(),g(V,{key:0},[e(F,{class:"divider-sm"}),e(o,{key:"desktop:hardware-wallet"},{icon:t(()=>[e(a(se))]),_:1}),e(o,{key:"desktop:backup-dashboard"},{icon:t(()=>[e(a(re))]),_:1}),e(o,{key:"desktop:llm-test-chat"},{icon:t(()=>[e(a(ce))]),_:1}),e(o,{key:"desktop:settings"},{icon:t(()=>[e(a(oe))]),_:1})],64)):P("",!0)],64)):(c(),g(V,{key:0},[e(M,{key:"g-overview"},{title:t(()=>[l("span",Qt,s(n.$t("appLayout.groups.overview")),1)]),default:t(()=>[e(o,{key:"dashboard"},{icon:t(()=>[e(a(te))]),default:t(()=>[i(s(n.$t("appLayout.items.dashboard")),1)]),_:1}),e(o,{key:"chat"},{icon:t(()=>[e(a(he))]),default:t(()=>[i(s(n.$t("appLayout.items.chat")),1)]),_:1}),e(o,{key:"quick-ask"},{icon:t(()=>[e(a(ae))]),default:t(()=>[i(s(n.$t("appLayout.items.quickAsk")),1)]),_:1}),e(o,{key:"cowork"},{icon:t(()=>[e(a(be))]),default:t(()=>[i(s(n.$t("appLayout.items.cowork")),1)]),_:1}),e(o,{key:"services"},{icon:t(()=>[e(a(oe))]),default:t(()=>[i(s(n.$t("appLayout.items.services")),1)]),_:1}),e(o,{key:"aiops"},{icon:t(()=>[e(a(we))]),default:t(()=>[i(s(n.$t("appLayout.items.aiops")),1)]),_:1}),e(o,{key:"tokens"},{icon:t(()=>[e(a($e))]),default:t(()=>[i(s(n.$t("appLayout.items.tokens")),1)]),_:1}),e(o,{key:"logs"},{icon:t(()=>[e(a(Le))]),default:t(()=>[i(s(n.$t("appLayout.items.logs")),1)]),_:1})]),_:1}),e(M,{key:"g-config"},{title:t(()=>[l("span",Xt,s(n.$t("appLayout.groups.config")),1)]),default:t(()=>[e(o,{key:"skills"},{icon:t(()=>[e(a(Oe))]),default:t(()=>[i(s(n.$t("appLayout.items.skills")),1)]),_:1}),e(o,{key:"providers"},{icon:t(()=>[e(a(Se))]),default:t(()=>[i(s(n.$t("appLayout.items.providers")),1)]),_:1}),e(o,{key:"mcp"},{icon:t(()=>[e(a(Ce))]),default:t(()=>[i(s(n.$t("appLayout.items.mcp")),1)]),_:1}),e(o,{key:"project-settings"},{icon:t(()=>[e(a(Y))]),default:t(()=>[i(s(n.$t("appLayout.items.projectSettings")),1)]),_:1}),e(o,{key:"speech-settings"},{icon:t(()=>[e(a(Ee))]),default:t(()=>[i(s(n.$t("appLayout.items.speechSettings")),1)]),_:1}),e(o,{key:"notification-settings"},{icon:t(()=>[e(a(fe))]),default:t(()=>[i(s(n.$t("appLayout.items.notificationSettings")),1)]),_:1}),e(o,{key:"sync-settings"},{icon:t(()=>[e(a(Re))]),default:t(()=>[i(s(n.$t("appLayout.items.syncSettings")),1)]),_:1}),e(o,{key:"nlprog"},{icon:t(()=>[e(a(Ae))]),default:t(()=>[i(s(n.$t("appLayout.items.nlprog")),1)]),_:1}),e(o,{key:"codegen"},{icon:t(()=>[e(a(ne))]),default:t(()=>[i(s(n.$t("appLayout.items.codegen")),1)]),_:1})]),_:1}),e(M,{key:"g-data"},{title:t(()=>[l("span",xt,s(n.$t("appLayout.groups.data")),1)]),default:t(()=>[e(o,{key:"notes"},{icon:t(()=>[e(a(Ne))]),default:t(()=>[i(s(n.$t("appLayout.items.notes")),1)]),_:1}),e(o,{key:"search"},{icon:t(()=>[e(a(je))]),default:t(()=>[i(s(n.$t("appLayout.items.search")),1)]),_:1}),e(o,{key:"memory"},{icon:t(()=>[e(a(Te))]),default:t(()=>[i(s(n.$t("appLayout.items.memory")),1)]),_:1}),e(o,{key:"knowledge"},{icon:t(()=>[e(a(Be))]),default:t(()=>[i(s(n.$t("appLayout.items.knowledge")),1)]),_:1}),e(o,{key:"marketplace"},{icon:t(()=>[e(a(Me))]),default:t(()=>[i(s(n.$t("appLayout.items.marketplace")),1)]),_:1}),e(o,{key:"cron"},{icon:t(()=>[e(a(Pe))]),default:t(()=>[i(s(n.$t("appLayout.items.cron")),1)]),_:1}),e(o,{key:"workflow"},{icon:t(()=>[e(a(Ie))]),default:t(()=>[i(s(n.$t("appLayout.items.workflow")),1)]),_:1}),e(o,{key:"pipeline"},{icon:t(()=>[e(a(Ue))]),default:t(()=>[i(s(n.$t("appLayout.items.pipeline")),1)]),_:1}),e(o,{key:"tasks"},{icon:t(()=>[e(a(ae))]),default:t(()=>[i(s(n.$t("appLayout.items.tasks")),1)]),_:1})]),_:1}),e(M,{key:"g-advanced"},{title:t(()=>[l("span",ea,s(n.$t("appLayout.groups.advanced")),1)]),default:t(()=>[e(o,{key:"security"},{icon:t(()=>[e(a(se))]),default:t(()=>[i(s(n.$t("appLayout.items.security")),1)]),_:1}),e(o,{key:"ukey-sign"},{icon:t(()=>[e(a(ie))]),default:t(()=>[i(s(n.$t("appLayout.items.ukeySign")),1)]),_:1}),e(o,{key:"trust"},{icon:t(()=>[e(a(D))]),default:t(()=>[i(s(n.$t("appLayout.items.trust")),1)]),_:1}),e(o,{key:"audit"},{icon:t(()=>[e(a(De))]),default:t(()=>[i(s(n.$t("appLayout.items.audit")),1)]),_:1}),e(o,{key:"mtc"},{icon:t(()=>[e(a(D))]),default:t(()=>[i(s(n.$t("appLayout.items.mtc")),1)]),_:1}),e(o,{key:"mtc-audit"},{icon:t(()=>[e(a(D))]),default:t(()=>[i(s(n.$t("appLayout.items.mtcAudit","MTC 审计")),1)]),_:1}),e(o,{key:"multisig"},{icon:t(()=>[e(a(le))]),default:t(()=>[i(s(n.$t("appLayout.items.multisig","M-of-N 多签")),1)]),_:1}),e(o,{key:"did"},{icon:t(()=>[e(a(Ke))]),default:t(()=>[i(s(n.$t("appLayout.items.did")),1)]),_:1}),e(o,{key:"permissions"},{icon:t(()=>[e(a(ze))]),default:t(()=>[i(s(n.$t("appLayout.items.permissions")),1)]),_:1}),e(o,{key:"p2p"},{icon:t(()=>[e(a(Fe))]),default:t(()=>[i(s(n.$t("appLayout.items.p2p")),1)]),_:1}),e(o,{key:"mobile-bridge"},{icon:t(()=>[e(a(ue))]),default:t(()=>[i(s(n.$t("appLayout.items.mobileBridge","移动桥")),1)]),_:1}),e(o,{key:"mobile-projects"},{icon:t(()=>[e(a(ue))]),default:t(()=>[i(s(n.$t("appLayout.items.mobileProjects","手机项目 (v0.2)")),1)]),_:1}),e(o,{key:"terminal"},{icon:t(()=>[e(a(me))]),default:t(()=>[i(s(n.$t("appLayout.items.terminal","远程终端")),1)]),_:1}),e(o,{key:"backup"},{icon:t(()=>[e(a(re))]),default:t(()=>[i(s(n.$t("appLayout.items.backup")),1)]),_:1}),e(o,{key:"git"},{icon:t(()=>[e(a(ne))]),default:t(()=>[i(s(n.$t("appLayout.items.git")),1)]),_:1}),e(o,{key:"projects"},{icon:t(()=>[e(a(Ve))]),default:t(()=>[i(s(n.$t("appLayout.items.projects")),1)]),_:1}),e(o,{key:"crosschain"},{icon:t(()=>[e(a(qe))]),default:t(()=>[i(s(n.$t("appLayout.items.crosschain")),1)]),_:1}),e(o,{key:"compliance"},{icon:t(()=>[e(a(D))]),default:t(()=>[i(s(n.$t("appLayout.items.compliance")),1)]),_:1}),e(o,{key:"privacy"},{icon:t(()=>[e(a(ce))]),default:t(()=>[i(s(n.$t("appLayout.items.privacy")),1)]),_:1}),e(o,{key:"inference"},{icon:t(()=>[e(a(We))]),default:t(()=>[i(s(n.$t("appLayout.items.inference")),1)]),_:1}),e(o,{key:"federation"},{icon:t(()=>[e(a(He))]),default:t(()=>[i(s(n.$t("appLayout.items.federation")),1)]),_:1})]),_:1}),e(M,{key:"g-enterprise"},{title:t(()=>[l("span",ta,s(n.$t("appLayout.groups.enterprise")),1)]),default:t(()=>[e(o,{key:"wallet"},{icon:t(()=>[e(a(Je))]),default:t(()=>[i(s(n.$t("appLayout.items.wallet")),1)]),_:1}),e(o,{key:"organization"},{icon:t(()=>[e(a(le))]),default:t(()=>[i(s(n.$t("appLayout.items.organization")),1)]),_:1}),e(o,{key:"tenant"},{icon:t(()=>[e(a(Ge))]),default:t(()=>[i(s(n.$t("appLayout.items.tenant")),1)]),_:1}),e(o,{key:"sla"},{icon:t(()=>[e(a(te))]),default:t(()=>[i(s(n.$t("appLayout.items.sla")),1)]),_:1}),e(o,{key:"analytics"},{icon:t(()=>[e(a(Ye))]),default:t(()=>[i(s(n.$t("appLayout.items.analytics")),1)]),_:1}),e(o,{key:"templates"},{icon:t(()=>[e(a(Ze))]),default:t(()=>[i(s(n.$t("appLayout.items.templates")),1)]),_:1})]),_:1}),e(M,{key:"g-social"},{title:t(()=>[l("span",aa,s(n.$t("appLayout.groups.social")),1)]),default:t(()=>[e(o,{key:"community"},{icon:t(()=>[e(a(Qe))]),default:t(()=>[i(s(n.$t("appLayout.items.community")),1)]),_:1}),e(o,{key:"governance"},{icon:t(()=>[e(a(Xe))]),default:t(()=>[i(s(n.$t("appLayout.items.governance")),1)]),_:1}),e(o,{key:"reputation"},{icon:t(()=>[e(a(xe))]),default:t(()=>[i(s(n.$t("appLayout.items.reputation")),1)]),_:1}),e(o,{key:"recommend"},{icon:t(()=>[e(a(et))]),default:t(()=>[i(s(n.$t("appLayout.items.recommend")),1)]),_:1})]),_:1}),e(M,{key:"g-media"},{title:t(()=>[l("span",oa,s(n.$t("appLayout.groups.media")),1)]),default:t(()=>[e(o,{key:"video"},{icon:t(()=>[e(a(Lt))]),default:t(()=>[i(s(n.$t("appLayout.items.video")),1)]),_:1})]),_:1}),e(M,{key:"g-extension"},{title:t(()=>[l("span",na,s(n.$t("appLayout.groups.extension")),1)]),default:t(()=>[e(o,{key:"rssfeed"},{icon:t(()=>[e(a(tt))]),default:t(()=>[i(s(n.$t("appLayout.items.rssfeed")),1)]),_:1}),e(o,{key:"webauthn"},{icon:t(()=>[e(a(ie))]),default:t(()=>[i(s(n.$t("appLayout.items.webauthn")),1)]),_:1})]),_:1}),a(r).isEmbedded?(c(),C(M,{key:"g-desktop"},{title:t(()=>[l("span",sa,s(n.$t("appLayout.groups.desktop")),1)]),default:t(()=>[e(o,{key:"desktop:hardware-wallet"},{icon:t(()=>[e(a(se))]),default:t(()=>[i(s(n.$t("appLayout.items.desktopHardware")),1)]),_:1}),e(o,{key:"desktop:backup-dashboard"},{icon:t(()=>[e(a(re))]),default:t(()=>[i(s(n.$t("appLayout.items.desktopBackup")),1)]),_:1}),e(o,{key:"desktop:llm-test-chat"},{icon:t(()=>[e(a(ce))]),default:t(()=>[i(s(n.$t("appLayout.items.desktopLlmTest")),1)]),_:1}),e(o,{key:"desktop:settings"},{icon:t(()=>[e(a(oe))]),default:t(()=>[i(s(n.$t("appLayout.items.desktopSettings")),1)]),_:1})]),_:1})):P("",!0)],64))]),_:1},8,["selectedKeys","openKeys","theme","inline-collapsed"]),l("div",{class:J(["sidebar-footer",{collapsed:u.value}])},[e(it,{status:B.value},null,8,["status"]),u.value?P("",!0):(c(),g("span",ia,s(z.value),1))],2)]),_:1},8,["collapsed"]),e(ve,{class:"main-area"},{default:t(()=>[e(ct,{class:"app-header"},{default:t(()=>[l("div",la,[l("div",{class:J(["scope-tag",y.value?"project":"global"])},[(c(),C(kt(y.value?a(Y):a(ee)))),l("span",null,s(y.value?a(_).projectName||n.$t("appLayout.scope.fallbackProject"):n.$t("appLayout.scope.global")),1),y.value&&a(_).projectRoot?(c(),C(X,{key:0,title:a(_).projectRoot},{default:t(()=>[e(a(Ot),{class:"info-icon"})]),_:1},8,["title"])):P("",!0)],2)]),l("div",ra,[l("div",ca,[(c(!0),g(V,null,ot(a(bt),(U,x)=>(c(),C(X,{key:x,title:U.label},{default:t(()=>[l("button",{class:J(["theme-btn",{active:R.value===x}]),"data-theme-key":x,onClick:fa=>I(x)},s(U.icon),11,ua)]),_:2},1032,["title"]))),128))]),e(X,{title:n.$t("language.label")},{default:t(()=>[l("button",{class:"lang-switch-btn","data-locale":a(W),onClick:de},[e(a(ee),{class:"lang-switch-icon"}),l("span",pa,s(n.$t("language.switch")),1)],8,da)]),_:1},8,["title"]),e(zt),a(r).isEmbedded?(c(),C(Ut,{key:0})):P("",!0),l("span",ya,s(a(w)),1),a(r).isEmbedded?(c(),C(X,{key:1,title:n.$t("appLayout.shellSwitch")},{default:t(()=>[l("button",{type:"button",class:"shell-switch-btn",onClick:ye},[e(a(me))])]),_:1},8,["title"])):P("",!0),e(rt,{color:f.value==="connected"?"green":f.value==="connecting"?"orange":"red",class:"ws-tag"},{default:t(()=>[i(s(f.value==="connected"?n.$t("appLayout.wsStatus.connected"):f.value==="connecting"?n.$t("appLayout.wsStatus.connecting"):n.$t("appLayout.wsStatus.disconnected")),1)]),_:1},8,["color"])])]),_:1}),e(dt,{class:"page-content"},{default:t(()=>[e(ut)]),_:1})]),_:1})]),_:1})}}},za=ge(ma,[["__scopeId","data-v-488ac0f2"]]);export{za as default};