chainlesschain 0.162.12 → 0.162.14

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 (170) hide show
  1. package/README.md +29 -24
  2. package/package.json +5 -2
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-C3TDNq29.js → AIOps-D34d_Nh1.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-C9fE18pE.js → ActionButton-Br7HxCnl.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-wnZF602C.js → Analytics-bVKq79Xd.js} +1 -1
  7. package/src/assets/web-panel/assets/{AppLayout-BjgTMK7O.js → AppLayout-CWSLIbAz.js} +2 -2
  8. package/src/assets/web-panel/assets/{Audit-BBL0BW5_.js → Audit-Cmnu1qqa.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-BKLqYCWU.js → Backup-Rok20-TL.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-BGSzMCZs.js → BaseInput-BJzs_ZtT.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-CQWzZWEY.js → Chat-CSYapbcq.js} +1 -1
  12. package/src/assets/web-panel/assets/{Checkbox-BkTri12Q.js → Checkbox-BEa7Sr7e.js} +1 -1
  13. package/src/assets/web-panel/assets/{Codegen-BH1m09EO.js → Codegen-C9M4e7ne.js} +1 -1
  14. package/src/assets/web-panel/assets/{Col-BXnBuqIa.js → Col-DU9NoUIi.js} +1 -1
  15. package/src/assets/web-panel/assets/{Community-C_Nr4XCx.js → Community-DA9uz_jP.js} +1 -1
  16. package/src/assets/web-panel/assets/{Compact-Du6GwLrj.js → Compact-3_bEraVw.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compliance-66M0oi1Q.js → Compliance-BtF8jWUQ.js} +1 -1
  18. package/src/assets/web-panel/assets/{Cowork-DQrkZRNd.js → Cowork-BqvA7oaM.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cron-CwdIFH_v.js → Cron-CxZy7Mzg.js} +1 -1
  20. package/src/assets/web-panel/assets/{Crosschain-DqlcrQ9L.js → Crosschain-1DB-XRGu.js} +1 -1
  21. package/src/assets/web-panel/assets/{DID-OmPLKf7L.js → DID-B6Ezp1pt.js} +1 -1
  22. package/src/assets/web-panel/assets/{Dashboard-D_dampTL.js → Dashboard-QDJ6VVsn.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dropdown-CA1W7jAn.js → Dropdown-CovsWjxG.js} +1 -1
  24. package/src/assets/web-panel/assets/{Federation-Chlk9a7s.js → Federation-DbRxS4Y4.js} +1 -1
  25. package/src/assets/web-panel/assets/{FormItemContext-t0UqYFLq.js → FormItemContext-9E9dNGtx.js} +1 -1
  26. package/src/assets/web-panel/assets/{Git-CEq0raYm.js → Git-CqEpyxRZ.js} +2 -2
  27. package/src/assets/web-panel/assets/{Governance-C06CX7Ge.js → Governance-On47KtGq.js} +1 -1
  28. package/src/assets/web-panel/assets/{Inference-6VIFHxIP.js → Inference-RZcjcyaq.js} +1 -1
  29. package/src/assets/web-panel/assets/{KnowledgeGraph-BCJPjMBQ.js → KnowledgeGraph-C-1rRAM9.js} +1 -1
  30. package/src/assets/web-panel/assets/{Logs-BBpOYFct.js → Logs-BuunmG_r.js} +1 -1
  31. package/src/assets/web-panel/assets/{Marketplace-BFH6jMWt.js → Marketplace-CromymyA.js} +1 -1
  32. package/src/assets/web-panel/assets/{McpTools-uCFvRqGs.js → McpTools-5XlFExh7.js} +1 -1
  33. package/src/assets/web-panel/assets/{Memory-B0Kux_KT.js → Memory-DjnUT7YM.js} +1 -1
  34. package/src/assets/web-panel/assets/{MobileBridge-DHow2jiK.js → MobileBridge-BrYIgLg6.js} +1 -1
  35. package/src/assets/web-panel/assets/{MobileProjects-BFo9YQZp.js → MobileProjects-CL5V3fTm.js} +1 -1
  36. package/src/assets/web-panel/assets/{Mtc-riOh1G_F.js → Mtc-CHYJq6zK.js} +1 -1
  37. package/src/assets/web-panel/assets/{MtcAudit-Bm-hE2SP.js → MtcAudit-BZxUO0qt.js} +1 -1
  38. package/src/assets/web-panel/assets/{Multisig-DfUQxh5a.js → Multisig-FZTmJgW1.js} +2 -2
  39. package/src/assets/web-panel/assets/{NLProgramming-DuNvLBEq.js → NLProgramming-C9Mhefph.js} +1 -1
  40. package/src/assets/web-panel/assets/{Notes-DB20wd3c.js → Notes-W7usj-Ar.js} +1 -1
  41. package/src/assets/web-panel/assets/{NotificationSettings-CB-GkOWR.js → NotificationSettings-PBuYv_Bh.js} +1 -1
  42. package/src/assets/web-panel/assets/{Organization-3bU7PZuG.js → Organization-CuYCE-rF.js} +4 -4
  43. package/src/assets/web-panel/assets/{Overflow-BGCPP_0Y.js → Overflow-Dojx-kzE.js} +1 -1
  44. package/src/assets/web-panel/assets/{OverrideContext-x9ZzjLwk.js → OverrideContext-C_4H9tGA.js} +1 -1
  45. package/src/assets/web-panel/assets/{P2P-BHgAe1oC.js → P2P-BgIaSrLX.js} +1 -1
  46. package/src/assets/web-panel/assets/{Permissions-BuOD4xwc.js → Permissions-Byj2dkF_.js} +1 -1
  47. package/src/assets/web-panel/assets/PersonalDataHub-CMOOI13-.js +1 -0
  48. package/src/assets/web-panel/assets/PersonalDataHub-Dvaa8niQ.css +1 -0
  49. package/src/assets/web-panel/assets/{Pipeline-DBS5U4LB.js → Pipeline-CWwEOF09.js} +1 -1
  50. package/src/assets/web-panel/assets/{Privacy-UNjIc5El.js → Privacy-VT7gldcN.js} +1 -1
  51. package/src/assets/web-panel/assets/{ProjectInit-CicqCJGy.js → ProjectInit-7UH3c3p7.js} +1 -1
  52. package/src/assets/web-panel/assets/{ProjectSettings-CIxAbt4Y.js → ProjectSettings-DqLp-72a.js} +1 -1
  53. package/src/assets/web-panel/assets/{Projects-BJycZScO.js → Projects-B_54eDhH.js} +1 -1
  54. package/src/assets/web-panel/assets/{Providers-DxXvprme.js → Providers-BIrNfNpc.js} +1 -1
  55. package/src/assets/web-panel/assets/{QuickAsk-rrqjU8_Y.js → QuickAsk-BbYPwCso.js} +1 -1
  56. package/src/assets/web-panel/assets/{Recommend-BEwHMhI7.js → Recommend-BF4qBssF.js} +1 -1
  57. package/src/assets/web-panel/assets/{Reputation-DoVKCCMn.js → Reputation-DPEzlC2V.js} +1 -1
  58. package/src/assets/web-panel/assets/{Row-F5XcDhHr.js → Row-DjHxhH1L.js} +1 -1
  59. package/src/assets/web-panel/assets/{RssFeed-cZrRG7k8.js → RssFeed-D0_j678P.js} +1 -1
  60. package/src/assets/web-panel/assets/{Search-B9ctZjqx.js → Search-DctfGehu.js} +1 -1
  61. package/src/assets/web-panel/assets/{Security-Z62hl1mc.js → Security-BFHggeYM.js} +1 -1
  62. package/src/assets/web-panel/assets/{Services-CQf5XqgZ.js → Services-CmrFMukV.js} +1 -1
  63. package/src/assets/web-panel/assets/{Skeleton-DuCKw2Eh.js → Skeleton-DR4vn_nS.js} +1 -1
  64. package/src/assets/web-panel/assets/{Skills-qVkhva0s.js → Skills-DlXG2yyV.js} +1 -1
  65. package/src/assets/web-panel/assets/{Sla-BQbatr7s.js → Sla-4PPGL3SE.js} +1 -1
  66. package/src/assets/web-panel/assets/{SpeechSettings-DLFBzAgD.js → SpeechSettings-D9EhJOqm.js} +1 -1
  67. package/src/assets/web-panel/assets/{SyncSettings-CrzETZMW.js → SyncSettings-Dasmbi0p.js} +1 -1
  68. package/src/assets/web-panel/assets/{Tasks-D_EQ1nJ7.js → Tasks-vilEiuPA.js} +1 -1
  69. package/src/assets/web-panel/assets/{Templates-D4y-dGRc.js → Templates-Ca9Rvktn.js} +1 -1
  70. package/src/assets/web-panel/assets/{Tenant-2XI0jkPn.js → Tenant-CEZb9gfK.js} +1 -1
  71. package/src/assets/web-panel/assets/{Terminal-fUi5V2Z9.js → Terminal-DanCBdbD.js} +1 -1
  72. package/src/assets/web-panel/assets/{Tokens-BuUNB2mg.js → Tokens-SPkClW2d.js} +1 -1
  73. package/src/assets/web-panel/assets/{Trigger-7DqLLuej.js → Trigger-B645yL7g.js} +1 -1
  74. package/src/assets/web-panel/assets/{Trust-CeACvTYx.js → Trust-D9sM_Ig0.js} +1 -1
  75. package/src/assets/web-panel/assets/{UkeySign-mDP9EXHq.js → UkeySign-B_Nr2K-u.js} +1 -1
  76. package/src/assets/web-panel/assets/{VideoEditing-veWlKclv.js → VideoEditing-U01Lea8j.js} +1 -1
  77. package/src/assets/web-panel/assets/{Wallet-Cd2Hheb8.js → Wallet-6xBySVV8.js} +1 -1
  78. package/src/assets/web-panel/assets/{WebAuthn-DyL7ZiHX.js → WebAuthn-DbgMoBu6.js} +3 -3
  79. package/src/assets/web-panel/assets/{WorkflowEditor-C7-7LJH9.js → WorkflowEditor-Bz-Y6IR2.js} +1 -1
  80. package/src/assets/web-panel/assets/{chat-DXomZMuo.js → chat-BC_O9hag.js} +1 -1
  81. package/src/assets/web-panel/assets/{collapseMotion-CjFH_Jop.js → collapseMotion-DfnRZex1.js} +1 -1
  82. package/src/assets/web-panel/assets/{colors-DlU92QNs.js → colors-ChlOGOvr.js} +1 -1
  83. package/src/assets/web-panel/assets/{compact-item-sBiTL8mX.js → compact-item-BSbAYGGF.js} +1 -1
  84. package/src/assets/web-panel/assets/{createContext-DZXEnzum.js → createContext-CFcZly5M.js} +1 -1
  85. package/src/assets/web-panel/assets/{echarts-Bq-n0MtJ.js → echarts-Dj_pBaVI.js} +1 -1
  86. package/src/assets/web-panel/assets/{hasIn-CpCHBZ2M.js → hasIn-BomYwwYE.js} +1 -1
  87. package/src/assets/web-panel/assets/{icons-CLQTHa5-.js → icons-BOPtEWK4.js} +4 -4
  88. package/src/assets/web-panel/assets/{index-B0Qbxr57.js → index-5Ewm6KZA.js} +1 -1
  89. package/src/assets/web-panel/assets/{index-CjXSvceY.js → index-B6LJHQoE.js} +1 -1
  90. package/src/assets/web-panel/assets/{index-CD3iljXs.js → index-BEJ6YiLI.js} +1 -1
  91. package/src/assets/web-panel/assets/{index-BK2AFy44.js → index-BGUbtM3R.js} +1 -1
  92. package/src/assets/web-panel/assets/{index-Di1_EQ-X.js → index-BHGsFwYW.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-B23tuoo9.js → index-BHi69MHF.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DUlPMzoM.js → index-BI1jAWcc.js} +1 -1
  95. package/src/assets/web-panel/assets/index-BIRYt1of.js +1 -0
  96. package/src/assets/web-panel/assets/{index-B3k9UPHc.js → index-BYDvb1pi.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CwbWZubA.js → index-BZGdjNLA.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-ThrAiEF9.js → index-BwFykZ5U.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CUe5t5Aa.js → index-ByZQNO0A.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-Dn8m1d1f.js → index-C0rr1X9W.js} +2 -2
  101. package/src/assets/web-panel/assets/{index-C6SDf50u.js → index-CBhoZhCO.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-ClN_JuFa.js → index-CCRSz2cR.js} +1 -1
  103. package/src/assets/web-panel/assets/index-CZfySmWX.js +1 -0
  104. package/src/assets/web-panel/assets/{index-Dq5Rn5VS.js → index-Cj47XwJQ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-ChahjdYE.js → index-Cmzh8gKL.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Dyg6ikIL.js → index-CnxlKTDK.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Dj9Nvz6S.js → index-CoF95pYK.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-TwQZkVGh.js → index-Ctx97mH-.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-s8tvk-fF.js → index-D0vX9jQA.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-X48zYgZ6.js → index-DNkth8dM.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DygNvCeR.js → index-DRp5_Xns.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-D_MzScPM.js → index-DW-Ji07y.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BqnhEJls.js → index-DXgE2VW6.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-CDyzZ8_O.js → index-D_0B3CiU.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C59FgSkU.js → index-Dbf5YmDX.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-_zyXBoS7.js → index-DsNQ2hqI.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CJ7XYa5K.js → index-EY733h9z.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-ibFHnqHz.js → index-QD_n54XT.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CivbS-57.js → index-T5Y_9IPv.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-C52udT0_.js → index-b8GbH2Yi.js} +4 -4
  121. package/src/assets/web-panel/assets/{index-XI6772AD.js → index-gUACAWbM.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-F9cBucYf.js → index-onW325hZ.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DKe9jmKG.js → index-ozVPr1gj.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D_IgY63-.js → index-slYX2rCE.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-B_-RETt0.js → index-t9u2bHpH.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DeGnHcp5.js → index-za1GUJBG.js} +1 -1
  127. package/src/assets/web-panel/assets/{initDefaultProps-DEi92ZnZ.js → initDefaultProps-DnadEaxu.js} +1 -1
  128. package/src/assets/web-panel/assets/{motion-BtYKzpOc.js → motion-CC_Na0Tl.js} +1 -1
  129. package/src/assets/web-panel/assets/{move-Cb3A1-v-.js → move-C2d9Mkk9.js} +1 -1
  130. package/src/assets/web-panel/assets/{omit-B6qPDdOf.js → omit-QvpKbF8p.js} +1 -1
  131. package/src/assets/web-panel/assets/{pickAttrs-DDyeQMUc.js → pickAttrs-Dm8r3X1_.js} +1 -1
  132. package/src/assets/web-panel/assets/{placementArrow-BPV6VO47.js → placementArrow-DaqaVfoX.js} +1 -1
  133. package/src/assets/web-panel/assets/{responsiveObserve-DJ1ra4dT.js → responsiveObserve-Iida9fIn.js} +1 -1
  134. package/src/assets/web-panel/assets/{slide-D6v8tHvB.js → slide-YqHexXQD.js} +1 -1
  135. package/src/assets/web-panel/assets/{statusUtils-DulKcQLZ.js → statusUtils-BGKLoeEt.js} +1 -1
  136. package/src/assets/web-panel/assets/{styleChecker-Bne7zwMt.js → styleChecker-aI-gsQO8.js} +1 -1
  137. package/src/assets/web-panel/assets/useFlexGapSupport-BiOsz4rc.js +1 -0
  138. package/src/assets/web-panel/assets/{useFs-CR-iLa4Z.js → useFs-CZy7Zo2X.js} +1 -1
  139. package/src/assets/web-panel/assets/{useMergedState-O7QXt4P5.js → useMergedState-WwedrFR0.js} +1 -1
  140. package/src/assets/web-panel/assets/{useRefs-0J6m8UWN.js → useRefs-Cdq8EWeF.js} +1 -1
  141. package/src/assets/web-panel/assets/{useState-CSzR8F8O.js → useState-DGS1NOyn.js} +1 -1
  142. package/src/assets/web-panel/assets/{vendor-M5lGV-wr.js → vendor-DhFY8mDK.js} +1 -1
  143. package/src/assets/web-panel/assets/{vnode-yL9axxBy.js → vnode-B6WqjmE4.js} +1 -1
  144. package/src/assets/web-panel/assets/{zoom-B-VCMXSD.js → zoom-DTeTrJ2z.js} +1 -1
  145. package/src/assets/web-panel/index.html +3 -3
  146. package/src/commands/__tests__/android.test.js +260 -0
  147. package/src/commands/__tests__/hub-aichat.test.js +277 -0
  148. package/src/commands/__tests__/hub-wechat.test.js +243 -0
  149. package/src/commands/android.js +284 -0
  150. package/src/commands/hub.js +457 -0
  151. package/src/commands/sync-providers.js +436 -0
  152. package/src/gateways/ws/personal-data-hub-protocol.js +88 -0
  153. package/src/index.js +6 -0
  154. package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +209 -0
  155. package/src/lib/__tests__/sync-credentials.test.js +265 -0
  156. package/src/lib/__tests__/sync-engine-cli.test.js +293 -0
  157. package/src/lib/cc-android-bridge.js +162 -0
  158. package/src/lib/personal-data-hub-aichat-wizard.js +242 -0
  159. package/src/lib/personal-data-hub-wiring.js +258 -13
  160. package/src/lib/sync-cli-db.js +194 -0
  161. package/src/lib/sync-credentials.js +225 -0
  162. package/src/lib/sync-engine-cli.js +406 -0
  163. package/src/lib/sync-oss-client.js +273 -0
  164. package/src/lib/sync-webdav-client.js +194 -0
  165. package/src/lib/web-ui-server.js +2 -1
  166. package/src/assets/web-panel/assets/PersonalDataHub--WA-aZAJ.js +0 -1
  167. package/src/assets/web-panel/assets/PersonalDataHub-BK7I0Rsb.css +0 -1
  168. package/src/assets/web-panel/assets/index-CcRX6BlT.js +0 -1
  169. package/src/assets/web-panel/assets/index-z6h6tqP3.js +0 -1
  170. package/src/assets/web-panel/assets/useFlexGapSupport-C1miTomM.js +0 -1
@@ -30,6 +30,8 @@ import { mkdirSync } from "node:fs";
30
30
  // won't let us name-import a CJS module unless it ships a separate ESM
31
31
  // shim, which we don't).
32
32
  import hub from "@chainlesschain/personal-data-hub";
33
+ import wechatAdapterModule from "@chainlesschain/personal-data-hub/adapters/wechat";
34
+ const { bootstrapWechatAdapter, probeWeChatEnv } = wechatAdapterModule;
33
35
  const {
34
36
  LocalVault,
35
37
  AdapterRegistry,
@@ -42,6 +44,7 @@ const {
42
44
  generateKeyHex,
43
45
  EmailAdapter,
44
46
  AlipayBillAdapter,
47
+ SystemDataAndroidAdapter,
45
48
  EntityResolver,
46
49
  EntityResolverEmbeddingStage,
47
50
  EntityResolverLLMStage,
@@ -51,6 +54,18 @@ const {
51
54
  import { readFileSync, writeFileSync, existsSync } from "node:fs";
52
55
  import { getElectronUserDataDir } from "./paths.js";
53
56
 
57
+ import {
58
+ getAIChatWizard,
59
+ createAccountsStore as createAIChatAccountsStore,
60
+ createVendorAdapterBridge as createAIChatVendorAdapterBridge,
61
+ } from "./personal-data-hub-aichat-wizard.js";
62
+
63
+ async function loadAIChatHealthChecker() {
64
+ const mod =
65
+ await import("@chainlesschain/personal-data-hub/adapters/ai-chat-history/health-checker");
66
+ return (mod.default || mod).createAIChatHealthChecker;
67
+ }
68
+
54
69
  // ─── Lazy ESM imports of cli KG / BM25 ───────────────────────────────────
55
70
 
56
71
  let _kgMod = null;
@@ -81,6 +96,28 @@ let _hub = null;
81
96
  let _initPromise = null;
82
97
  let _bm25 = null;
83
98
 
99
+ // LLM override — see file header. Default cli-side hub uses a direct
100
+ // OllamaClient; when the desktop main process embeds this wiring via
101
+ // ws-cli-loader it can inject a CcLLMAdapter (wrapping LLMManager) so the
102
+ // SAME wiring honors the user's active provider (volcengine / anthropic /
103
+ // etc.) instead of hard-binding Ollama. Must be set BEFORE the first
104
+ // getHub() call — initHub() reads it synchronously at the LLM-wiring step.
105
+ let _llmOverride = null;
106
+
107
+ /**
108
+ * Override the default cli-side OllamaClient with a caller-supplied LLM
109
+ * client conforming to the hub's LLMClient contract ({ chat, name, isLocal }).
110
+ *
111
+ * Used by desktop-app-vue web-shell's ws-cli-loader bootstrap: see
112
+ * desktop-app-vue/src/main/web-shell/ws-cli-loader.js. Calling this on
113
+ * an already-initialized hub does NOT swap the live LLM — the override only
114
+ * applies on the next fresh initHub(). Restart the process if you need to
115
+ * change provider mid-session.
116
+ */
117
+ export function setHubLLMOverride(llm) {
118
+ _llmOverride = llm || null;
119
+ }
120
+
84
121
  export function resolveHubDir() {
85
122
  return join(getElectronUserDataDir(), ".chainlesschain", "hub");
86
123
  }
@@ -101,12 +138,16 @@ async function initHub() {
101
138
  const vault = new LocalVault({ path: join(hubDir, "vault.db"), key });
102
139
  vault.open();
103
140
 
104
- // LLM: standalone OllamaClient connects to localhost:11434.
105
- // Override via env CC_HUB_OLLAMA_URL / CC_HUB_OLLAMA_MODEL.
106
- const llm = new OllamaClient({
107
- baseUrl: process.env.CC_HUB_OLLAMA_URL || "http://localhost:11434",
108
- model: process.env.CC_HUB_OLLAMA_MODEL || "qwen2.5:7b-instruct",
109
- });
141
+ // LLM: prefer caller-injected override (desktop web-shell wires CcLLMAdapter
142
+ // wrapping LLMManager so PDH honors the user's saved active provider).
143
+ // Fallback to standalone OllamaClient — connects to localhost:11434.
144
+ // Override the fallback via env CC_HUB_OLLAMA_URL / CC_HUB_OLLAMA_MODEL.
145
+ const llm =
146
+ _llmOverride ||
147
+ new OllamaClient({
148
+ baseUrl: process.env.CC_HUB_OLLAMA_URL || "http://localhost:11434",
149
+ model: process.env.CC_HUB_OLLAMA_MODEL || "qwen2.5:7b-instruct",
150
+ });
110
151
 
111
152
  // KG sink — direct ESM import works here.
112
153
  let kgSink = null;
@@ -133,20 +174,33 @@ async function initHub() {
133
174
 
134
175
  // Phase 8 — EntityResolver pipeline
135
176
  const entityResolver = new EntityResolver({ vault });
177
+ // Plan A v0.1 — in-APK Android cc has no Ollama on localhost:11434.
178
+ // Every embedding call would TCP-timeout (measured: ~60s extra per sync
179
+ // on Xiaomi 24115RA8EC 2026-05-21). Detect Termux $PREFIX for our APK
180
+ // and skip embedding+LLM stages entirely. Rule-stage still runs; the
181
+ // resolve_queue picks up enqueued pairs later if a host with Ollama is
182
+ // ever attached (e.g. desktop-side replay).
183
+ const isInAppAndroidCc =
184
+ typeof process.env.PREFIX === "string" &&
185
+ process.env.PREFIX.startsWith("/data/data/com.chainlesschain.android");
186
+ const skipEmbeddings =
187
+ isInAppAndroidCc || process.env.CC_HUB_DISABLE_EMBEDDINGS === "1";
136
188
  try {
137
- if (llm) {
189
+ if (llm && !skipEmbeddings) {
138
190
  const llmStage = new EntityResolverLLMStage({
139
191
  llm,
140
192
  acceptNonLocal: false,
141
193
  });
142
194
  entityResolver._llmStage = llmStage.asStageFn();
143
195
  }
144
- const embeddingStage = new EntityResolverEmbeddingStage({
145
- ollamaUrl: process.env.CC_HUB_OLLAMA_URL || "http://localhost:11434",
146
- model: process.env.CC_HUB_OLLAMA_EMBED_MODEL || "nomic-embed-text",
147
- vault,
148
- });
149
- entityResolver._embeddingStage = embeddingStage.asStageFn();
196
+ if (!skipEmbeddings) {
197
+ const embeddingStage = new EntityResolverEmbeddingStage({
198
+ ollamaUrl: process.env.CC_HUB_OLLAMA_URL || "http://localhost:11434",
199
+ model: process.env.CC_HUB_OLLAMA_EMBED_MODEL || "nomic-embed-text",
200
+ vault,
201
+ });
202
+ entityResolver._embeddingStage = embeddingStage.asStageFn();
203
+ }
150
204
  } catch (_err) {
151
205
  // Fall back to rule-only — registry still works
152
206
  }
@@ -196,6 +250,19 @@ async function initHub() {
196
250
  }
197
251
  }
198
252
 
253
+ // Plan A v0.1 — Android on-device system-data adapter. Stateless: the UI
254
+ // produces a snapshot JSON via ContentResolver/PackageManager and passes
255
+ // its path through opts.inputPath at sync-time, so registration is a
256
+ // one-shot wire here. Safe to register on every host (no-op until a sync
257
+ // call provides inputPath); future hosts may filter by platform if useful.
258
+ try {
259
+ const sda = new SystemDataAndroidAdapter();
260
+ if (!registry.has(sda.name)) registry.register(sda);
261
+ } catch (_err) {
262
+ // Boot must continue even if the adapter fails to register; cc hub will
263
+ // surface the absence via list-adapters.
264
+ }
265
+
199
266
  // Phase 6: auto-register persisted Alipay accounts.
200
267
  const alipayAccountsPath = join(hubDir, "alipay-accounts.json");
201
268
  const alipayAccounts = loadAlipayAccounts(alipayAccountsPath);
@@ -211,6 +278,24 @@ async function initHub() {
211
278
  }
212
279
  }
213
280
 
281
+ // Phase 10.3.5 — AIChat HealthChecker (mirror of desktop wiring). cc ui
282
+ // typically only runs while the user has the web-shell open, but the
283
+ // periodic loop still validates persisted cookies so list-aichat-accounts
284
+ // can surface lastHealth reliably.
285
+ const aichatAccountsStore = createAIChatAccountsStore({ hubDir });
286
+ const aichatVendorAdapter = createAIChatVendorAdapterBridge();
287
+ const createAIChatHealthChecker = await loadAIChatHealthChecker();
288
+ const aichatHealthChecker = createAIChatHealthChecker({
289
+ accountsStore: aichatAccountsStore,
290
+ vendorAdapter: aichatVendorAdapter,
291
+ });
292
+ try {
293
+ aichatHealthChecker.start();
294
+ } catch (_err) {
295
+ // Continue boot even if checker fails to schedule
296
+ }
297
+ const aichatWizard = getAIChatWizard({ hubDir });
298
+
214
299
  return {
215
300
  vault,
216
301
  registry,
@@ -223,11 +308,50 @@ async function initHub() {
223
308
  emailAccountsPath,
224
309
  alipayAccountsPath,
225
310
  entityResolver,
311
+ aichatAccountsStore,
312
+ aichatWizard,
313
+ aichatHealthChecker,
226
314
  analysisSkillNames: ANALYSIS_SKILL_NAMES,
227
315
  async runSkill(name, options = {}) {
228
316
  return await runAnalysisSkill({ vault, llm }, name, options);
229
317
  },
230
318
  bm25: _bm25,
319
+
320
+ /** Phase 10.3.5 — see desktop wiring for full doc. */
321
+ async listAIChatAccounts() {
322
+ const entries = await aichatAccountsStore.list();
323
+ return (entries || []).map((e) => ({
324
+ vendor: e.vendor,
325
+ displayName: e.displayName || e.vendor,
326
+ registeredAt: e.registeredAt || null,
327
+ userId: e.userId || null,
328
+ lastSyncAt: e.lastSyncAt || null,
329
+ lastHealth: e.lastHealth || null,
330
+ cookieSpecVersion: e.cookieSpecVersion || null,
331
+ cookieNames: Object.keys(e.cookies || {}),
332
+ }));
333
+ },
334
+
335
+ async unregisterAIChatVendor(vendor) {
336
+ if (!vendor || typeof vendor !== "string") {
337
+ return { ok: false, reason: "VENDOR_REQUIRED" };
338
+ }
339
+ const before = await aichatAccountsStore.get(vendor);
340
+ if (!before) {
341
+ return { ok: false, reason: "NOT_REGISTERED", vendor };
342
+ }
343
+ await aichatAccountsStore.delete(vendor);
344
+ try {
345
+ await aichatWizard.rotateLoginPartition({ vendor });
346
+ } catch (_err) {
347
+ // best-effort
348
+ }
349
+ return { ok: true, vendor };
350
+ },
351
+
352
+ async runAIChatHealthCheckOnce() {
353
+ return await aichatHealthChecker.runOnce();
354
+ },
231
355
  registerMockAdapter(opts = {}) {
232
356
  if (registry.has(opts.name || "mock"))
233
357
  return registry.get(opts.name || "mock");
@@ -358,9 +482,125 @@ async function initHub() {
358
482
  zipPassword,
359
483
  });
360
484
  },
485
+
486
+ // ─── Phase 12.6.8 — WeChat env-probe + register / unregister / list ──
487
+ //
488
+ // cc ui mirror of the desktop wiring. Same JSON file layout
489
+ // (wechat-accounts.json under hubDir, mode 0o600) so the two shells
490
+ // share registrations when run side-by-side on the same machine.
491
+
492
+ async probeWechatEnv(opts = {}) {
493
+ return await probeWeChatEnv({ exec: opts.exec });
494
+ },
495
+
496
+ async registerWechatAdapter(opts = {}) {
497
+ if (!opts || !opts.account || !opts.account.uin) {
498
+ return {
499
+ ok: false,
500
+ reason: "UIN_REQUIRED",
501
+ message: "opts.account.uin required",
502
+ };
503
+ }
504
+ let r;
505
+ try {
506
+ r = await bootstrapWechatAdapter({
507
+ account: opts.account,
508
+ dbPath: opts.dbPath || null,
509
+ wechatDataPath: opts.wechatDataPath || null,
510
+ fridaOpts: opts.fridaOpts || null,
511
+ keyProviderOverride: opts.keyProviderOverride || null,
512
+ exec: opts.exec,
513
+ _probe: opts._probe,
514
+ });
515
+ } catch (err) {
516
+ return {
517
+ ok: false,
518
+ reason: "BOOTSTRAP_THREW",
519
+ message: err && err.message ? err.message : String(err),
520
+ };
521
+ }
522
+ if (!r.ok) return r;
523
+
524
+ if (registry.has(r.adapter.name)) registry.unregister(r.adapter.name);
525
+ registry.register(r.adapter);
526
+
527
+ const wechatAccountsPath = join(hubDir, "wechat-accounts.json");
528
+ const accounts = loadWechatAccounts(wechatAccountsPath);
529
+ const next = accounts.filter(
530
+ (c) => !(c.account && c.account.uin === opts.account.uin),
531
+ );
532
+ next.push({
533
+ account: { uin: opts.account.uin },
534
+ dbPath: opts.dbPath || null,
535
+ wechatDataPath: opts.wechatDataPath || null,
536
+ chosenKeyProvider:
537
+ r.keyProvider && r.keyProvider.name ? r.keyProvider.name : null,
538
+ registeredAt: Date.now(),
539
+ lastSyncAt: null,
540
+ });
541
+ saveWechatAccounts(wechatAccountsPath, next);
542
+
543
+ return {
544
+ ok: true,
545
+ name: r.adapter.name,
546
+ version: r.adapter.version,
547
+ capabilities: r.adapter.capabilities,
548
+ sensitivity: r.adapter.dataDisclosure.sensitivity,
549
+ chosenKeyProvider: r.keyProvider && r.keyProvider.name,
550
+ probe: r.probe,
551
+ registeredAt: next[next.length - 1].registeredAt,
552
+ };
553
+ },
554
+
555
+ async unregisterWechatAdapter(uin) {
556
+ if (!uin || typeof uin !== "string") {
557
+ return { ok: false, reason: "UIN_REQUIRED" };
558
+ }
559
+ const wechatAccountsPath = join(hubDir, "wechat-accounts.json");
560
+ const accounts = loadWechatAccounts(wechatAccountsPath);
561
+ const target = accounts.find((c) => c.account && c.account.uin === uin);
562
+ const next = accounts.filter(
563
+ (c) => !(c.account && c.account.uin === uin),
564
+ );
565
+ saveWechatAccounts(wechatAccountsPath, next);
566
+ if (target && registry.has("wechat")) registry.unregister("wechat");
567
+ return { ok: true, removed: !!target, uin };
568
+ },
569
+
570
+ listWechatAccounts() {
571
+ const wechatAccountsPath = join(hubDir, "wechat-accounts.json");
572
+ return loadWechatAccounts(wechatAccountsPath).map((row) => ({
573
+ uin: row.account ? row.account.uin : null,
574
+ dbPath: row.dbPath || null,
575
+ hasWechatDataPath: !!row.wechatDataPath,
576
+ chosenKeyProvider: row.chosenKeyProvider || null,
577
+ registeredAt: row.registeredAt || null,
578
+ lastSyncAt: row.lastSyncAt || null,
579
+ }));
580
+ },
361
581
  };
362
582
  }
363
583
 
584
+ // ─── Phase 12.6.8 — WeChat account persistence helpers (cli mirror) ──────
585
+
586
+ function loadWechatAccounts(filePath) {
587
+ try {
588
+ if (!existsSync(filePath)) return [];
589
+ const raw = readFileSync(filePath, "utf-8");
590
+ const parsed = JSON.parse(raw);
591
+ return Array.isArray(parsed) ? parsed : [];
592
+ } catch (_err) {
593
+ return [];
594
+ }
595
+ }
596
+
597
+ function saveWechatAccounts(filePath, accounts) {
598
+ writeFileSync(filePath, JSON.stringify(accounts, null, 2), {
599
+ encoding: "utf-8",
600
+ mode: 0o600,
601
+ });
602
+ }
603
+
364
604
  // ─── Email account persistence (Phase 5.6) ───────────────────────────────
365
605
 
366
606
  function loadEmailAccounts(filePath) {
@@ -418,6 +658,11 @@ export async function getHub() {
418
658
  }
419
659
 
420
660
  export function close() {
661
+ if (_hub && _hub.aichatHealthChecker) {
662
+ try {
663
+ _hub.aichatHealthChecker.stop();
664
+ } catch (_e) {}
665
+ }
421
666
  if (_hub && _hub.vault) {
422
667
  try {
423
668
  _hub.vault.close();
@@ -0,0 +1,194 @@
1
+ /**
2
+ * CLI sync vault — better-sqlite3 wrapper exposing dbManager.run/all/get
3
+ * interface matching desktop's engine deps signature.
4
+ *
5
+ * Phase 3c follow-up Phase 2: cc sync run requires SQLite store for cursors,
6
+ * tombstones, and knowledge_items. CLI vault lives at
7
+ * `~/.chainlesschain/cli-vault.db` and is plain SQLite (no SQLCipher) —
8
+ * encryption is at the OS file-permission layer; users wanting strong
9
+ * crypto should use desktop with hardware U-Key.
10
+ *
11
+ * Schema mirrors desktop `database-schema.js` for the 3 sync-relevant
12
+ * tables (auto-initialized on first open):
13
+ * - knowledge_items user notes (source of truth for sync)
14
+ * - sync_external_provider_cursor per-provider state
15
+ * - sync_external_tombstones per-provider delete queue
16
+ * - trg_sync_ext_tombstone_on_delete trigger (auto-fan tombstone on delete)
17
+ */
18
+
19
+ "use strict";
20
+
21
+ import fs from "node:fs";
22
+ import path from "node:path";
23
+ import os from "node:os";
24
+
25
+ function _ccDir() {
26
+ return (
27
+ process.env.CHAINLESSCHAIN_HOME ||
28
+ path.join(os.homedir(), ".chainlesschain")
29
+ );
30
+ }
31
+
32
+ function _vaultPath() {
33
+ return path.join(_ccDir(), "cli-vault.db");
34
+ }
35
+
36
+ const CLI_VAULT_SCHEMA = `
37
+ CREATE TABLE IF NOT EXISTS knowledge_items (
38
+ id TEXT PRIMARY KEY,
39
+ title TEXT NOT NULL,
40
+ type TEXT NOT NULL DEFAULT 'note',
41
+ content TEXT,
42
+ tags TEXT,
43
+ created_at INTEGER NOT NULL,
44
+ updated_at INTEGER NOT NULL
45
+ );
46
+
47
+ CREATE TABLE IF NOT EXISTS sync_external_provider_cursor (
48
+ provider_id TEXT NOT NULL,
49
+ account_key TEXT NOT NULL DEFAULT '',
50
+ last_sync_at INTEGER NOT NULL DEFAULT 0,
51
+ last_item_id TEXT,
52
+ remote_etag_map TEXT NOT NULL DEFAULT '{}',
53
+ remote_filename_map TEXT NOT NULL DEFAULT '{}',
54
+ last_run_status TEXT,
55
+ last_run_error TEXT,
56
+ last_run_duration_ms INTEGER,
57
+ items_pushed INTEGER NOT NULL DEFAULT 0,
58
+ items_skipped INTEGER NOT NULL DEFAULT 0,
59
+ items_deleted INTEGER NOT NULL DEFAULT 0,
60
+ created_at INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000),
61
+ updated_at INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000),
62
+ PRIMARY KEY (provider_id, account_key)
63
+ );
64
+
65
+ CREATE TABLE IF NOT EXISTS sync_external_tombstones (
66
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
67
+ provider_id TEXT NOT NULL,
68
+ account_key TEXT NOT NULL DEFAULT '',
69
+ item_id TEXT NOT NULL,
70
+ resource_type TEXT,
71
+ deleted_at INTEGER NOT NULL,
72
+ retry_count INTEGER NOT NULL DEFAULT 0,
73
+ last_error TEXT,
74
+ UNIQUE(provider_id, account_key, item_id)
75
+ );
76
+
77
+ CREATE TRIGGER IF NOT EXISTS trg_sync_ext_tombstone_on_delete
78
+ AFTER DELETE ON knowledge_items
79
+ FOR EACH ROW
80
+ BEGIN
81
+ INSERT OR IGNORE INTO sync_external_tombstones
82
+ (provider_id, account_key, item_id, resource_type, deleted_at)
83
+ SELECT c.provider_id, c.account_key, OLD.id, 'KNOWLEDGE_ITEM',
84
+ (strftime('%s','now') * 1000)
85
+ FROM sync_external_provider_cursor c;
86
+ END;
87
+ `;
88
+
89
+ /**
90
+ * Wraps better-sqlite3 Database with the {run, all, get} surface that
91
+ * the desktop sync engine's deps.dbManager expects.
92
+ */
93
+ class CliVaultDbManager {
94
+ constructor(db) {
95
+ this.db = db;
96
+ }
97
+
98
+ /** Match desktop dbManager.run(sql, params=[]) */
99
+ run(sql, params = []) {
100
+ this.db.prepare(sql).run(...params);
101
+ }
102
+
103
+ /** Match desktop dbManager.get(sql, params=[]) → row or undefined */
104
+ get(sql, params = []) {
105
+ const row = this.db.prepare(sql).get(...params);
106
+ return row ?? undefined;
107
+ }
108
+
109
+ /** Match desktop dbManager.all(sql, params=[]) → rows */
110
+ all(sql, params = []) {
111
+ return this.db.prepare(sql).all(...params);
112
+ }
113
+
114
+ close() {
115
+ if (this.db && this.db.open) this.db.close();
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Open (or create) the CLI vault. Auto-initializes schema on first open.
121
+ *
122
+ * @returns {Promise<{dbManager: CliVaultDbManager, vaultPath: string}>}
123
+ */
124
+ async function openCliVault() {
125
+ const dir = _ccDir();
126
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
127
+
128
+ // Lazy-import better-sqlite3 — heavy native dep, defer until run-time
129
+ // (so the CLI doesn't even pay the require cost for non-sync commands).
130
+ let Database;
131
+ try {
132
+ Database = (await import("better-sqlite3")).default;
133
+ } catch (err) {
134
+ const e = new Error(
135
+ "CLI vault requires better-sqlite3 npm package. " +
136
+ "Run `npm install -g chainlesschain` to fetch the prebuilt binary, " +
137
+ "or `cd packages/cli && npm install` for the dev workspace. " +
138
+ "Underlying error: " +
139
+ (err?.message || String(err)),
140
+ );
141
+ e.code = "BETTER_SQLITE3_MISSING";
142
+ throw e;
143
+ }
144
+
145
+ const vp = _vaultPath();
146
+ const db = new Database(vp);
147
+ db.exec(CLI_VAULT_SCHEMA);
148
+ return { dbManager: new CliVaultDbManager(db), vaultPath: vp };
149
+ }
150
+
151
+ let _ccDirOverride = null;
152
+ function _setCcDirForTest(dir) {
153
+ _ccDirOverride = dir;
154
+ }
155
+ function _resetCcDirForTest() {
156
+ _ccDirOverride = null;
157
+ }
158
+
159
+ // Re-wrap _ccDir/_vaultPath to honor override (test seam)
160
+ const _originalCcDir = _ccDir;
161
+ function _ccDirEffective() {
162
+ return _ccDirOverride ?? _originalCcDir();
163
+ }
164
+ function _vaultPathEffective() {
165
+ return path.join(_ccDirEffective(), "cli-vault.db");
166
+ }
167
+
168
+ async function openCliVaultT() {
169
+ const dir = _ccDirEffective();
170
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
171
+ let Database;
172
+ try {
173
+ Database = (await import("better-sqlite3")).default;
174
+ } catch (err) {
175
+ const e = new Error(
176
+ "CLI vault requires better-sqlite3 npm package: " + (err?.message || err),
177
+ );
178
+ e.code = "BETTER_SQLITE3_MISSING";
179
+ throw e;
180
+ }
181
+ const vp = _vaultPathEffective();
182
+ const db = new Database(vp);
183
+ db.exec(CLI_VAULT_SCHEMA);
184
+ return { dbManager: new CliVaultDbManager(db), vaultPath: vp };
185
+ }
186
+
187
+ export {
188
+ openCliVaultT as openCliVault,
189
+ CliVaultDbManager,
190
+ CLI_VAULT_SCHEMA,
191
+ _setCcDirForTest,
192
+ _resetCcDirForTest,
193
+ _vaultPathEffective as _vaultPath,
194
+ };