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.
- package/README.md +29 -24
- package/package.json +5 -2
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-C3TDNq29.js → AIOps-D34d_Nh1.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-C9fE18pE.js → ActionButton-Br7HxCnl.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-wnZF602C.js → Analytics-bVKq79Xd.js} +1 -1
- package/src/assets/web-panel/assets/{AppLayout-BjgTMK7O.js → AppLayout-CWSLIbAz.js} +2 -2
- package/src/assets/web-panel/assets/{Audit-BBL0BW5_.js → Audit-Cmnu1qqa.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BKLqYCWU.js → Backup-Rok20-TL.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BGSzMCZs.js → BaseInput-BJzs_ZtT.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CQWzZWEY.js → Chat-CSYapbcq.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BkTri12Q.js → Checkbox-BEa7Sr7e.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BH1m09EO.js → Codegen-C9M4e7ne.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BXnBuqIa.js → Col-DU9NoUIi.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C_Nr4XCx.js → Community-DA9uz_jP.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Du6GwLrj.js → Compact-3_bEraVw.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-66M0oi1Q.js → Compliance-BtF8jWUQ.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DQrkZRNd.js → Cowork-BqvA7oaM.js} +1 -1
- package/src/assets/web-panel/assets/{Cron-CwdIFH_v.js → Cron-CxZy7Mzg.js} +1 -1
- package/src/assets/web-panel/assets/{Crosschain-DqlcrQ9L.js → Crosschain-1DB-XRGu.js} +1 -1
- package/src/assets/web-panel/assets/{DID-OmPLKf7L.js → DID-B6Ezp1pt.js} +1 -1
- package/src/assets/web-panel/assets/{Dashboard-D_dampTL.js → Dashboard-QDJ6VVsn.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CA1W7jAn.js → Dropdown-CovsWjxG.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Chlk9a7s.js → Federation-DbRxS4Y4.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-t0UqYFLq.js → FormItemContext-9E9dNGtx.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CEq0raYm.js → Git-CqEpyxRZ.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C06CX7Ge.js → Governance-On47KtGq.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-6VIFHxIP.js → Inference-RZcjcyaq.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BCJPjMBQ.js → KnowledgeGraph-C-1rRAM9.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BBpOYFct.js → Logs-BuunmG_r.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BFH6jMWt.js → Marketplace-CromymyA.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-uCFvRqGs.js → McpTools-5XlFExh7.js} +1 -1
- package/src/assets/web-panel/assets/{Memory-B0Kux_KT.js → Memory-DjnUT7YM.js} +1 -1
- package/src/assets/web-panel/assets/{MobileBridge-DHow2jiK.js → MobileBridge-BrYIgLg6.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BFo9YQZp.js → MobileProjects-CL5V3fTm.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-riOh1G_F.js → Mtc-CHYJq6zK.js} +1 -1
- package/src/assets/web-panel/assets/{MtcAudit-Bm-hE2SP.js → MtcAudit-BZxUO0qt.js} +1 -1
- package/src/assets/web-panel/assets/{Multisig-DfUQxh5a.js → Multisig-FZTmJgW1.js} +2 -2
- package/src/assets/web-panel/assets/{NLProgramming-DuNvLBEq.js → NLProgramming-C9Mhefph.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DB20wd3c.js → Notes-W7usj-Ar.js} +1 -1
- package/src/assets/web-panel/assets/{NotificationSettings-CB-GkOWR.js → NotificationSettings-PBuYv_Bh.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-3bU7PZuG.js → Organization-CuYCE-rF.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BGCPP_0Y.js → Overflow-Dojx-kzE.js} +1 -1
- package/src/assets/web-panel/assets/{OverrideContext-x9ZzjLwk.js → OverrideContext-C_4H9tGA.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BHgAe1oC.js → P2P-BgIaSrLX.js} +1 -1
- package/src/assets/web-panel/assets/{Permissions-BuOD4xwc.js → Permissions-Byj2dkF_.js} +1 -1
- package/src/assets/web-panel/assets/PersonalDataHub-CMOOI13-.js +1 -0
- package/src/assets/web-panel/assets/PersonalDataHub-Dvaa8niQ.css +1 -0
- package/src/assets/web-panel/assets/{Pipeline-DBS5U4LB.js → Pipeline-CWwEOF09.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-UNjIc5El.js → Privacy-VT7gldcN.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CicqCJGy.js → ProjectInit-7UH3c3p7.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectSettings-CIxAbt4Y.js → ProjectSettings-DqLp-72a.js} +1 -1
- package/src/assets/web-panel/assets/{Projects-BJycZScO.js → Projects-B_54eDhH.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DxXvprme.js → Providers-BIrNfNpc.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-rrqjU8_Y.js → QuickAsk-BbYPwCso.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BEwHMhI7.js → Recommend-BF4qBssF.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DoVKCCMn.js → Reputation-DPEzlC2V.js} +1 -1
- package/src/assets/web-panel/assets/{Row-F5XcDhHr.js → Row-DjHxhH1L.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-cZrRG7k8.js → RssFeed-D0_j678P.js} +1 -1
- package/src/assets/web-panel/assets/{Search-B9ctZjqx.js → Search-DctfGehu.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Z62hl1mc.js → Security-BFHggeYM.js} +1 -1
- package/src/assets/web-panel/assets/{Services-CQf5XqgZ.js → Services-CmrFMukV.js} +1 -1
- package/src/assets/web-panel/assets/{Skeleton-DuCKw2Eh.js → Skeleton-DR4vn_nS.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-qVkhva0s.js → Skills-DlXG2yyV.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BQbatr7s.js → Sla-4PPGL3SE.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DLFBzAgD.js → SpeechSettings-D9EhJOqm.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CrzETZMW.js → SyncSettings-Dasmbi0p.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-D_EQ1nJ7.js → Tasks-vilEiuPA.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D4y-dGRc.js → Templates-Ca9Rvktn.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-2XI0jkPn.js → Tenant-CEZb9gfK.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-fUi5V2Z9.js → Terminal-DanCBdbD.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BuUNB2mg.js → Tokens-SPkClW2d.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-7DqLLuej.js → Trigger-B645yL7g.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CeACvTYx.js → Trust-D9sM_Ig0.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-mDP9EXHq.js → UkeySign-B_Nr2K-u.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-veWlKclv.js → VideoEditing-U01Lea8j.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Cd2Hheb8.js → Wallet-6xBySVV8.js} +1 -1
- package/src/assets/web-panel/assets/{WebAuthn-DyL7ZiHX.js → WebAuthn-DbgMoBu6.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-C7-7LJH9.js → WorkflowEditor-Bz-Y6IR2.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DXomZMuo.js → chat-BC_O9hag.js} +1 -1
- package/src/assets/web-panel/assets/{collapseMotion-CjFH_Jop.js → collapseMotion-DfnRZex1.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DlU92QNs.js → colors-ChlOGOvr.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-sBiTL8mX.js → compact-item-BSbAYGGF.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DZXEnzum.js → createContext-CFcZly5M.js} +1 -1
- package/src/assets/web-panel/assets/{echarts-Bq-n0MtJ.js → echarts-Dj_pBaVI.js} +1 -1
- package/src/assets/web-panel/assets/{hasIn-CpCHBZ2M.js → hasIn-BomYwwYE.js} +1 -1
- package/src/assets/web-panel/assets/{icons-CLQTHa5-.js → icons-BOPtEWK4.js} +4 -4
- package/src/assets/web-panel/assets/{index-B0Qbxr57.js → index-5Ewm6KZA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjXSvceY.js → index-B6LJHQoE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CD3iljXs.js → index-BEJ6YiLI.js} +1 -1
- package/src/assets/web-panel/assets/{index-BK2AFy44.js → index-BGUbtM3R.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di1_EQ-X.js → index-BHGsFwYW.js} +1 -1
- package/src/assets/web-panel/assets/{index-B23tuoo9.js → index-BHi69MHF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUlPMzoM.js → index-BI1jAWcc.js} +1 -1
- package/src/assets/web-panel/assets/index-BIRYt1of.js +1 -0
- package/src/assets/web-panel/assets/{index-B3k9UPHc.js → index-BYDvb1pi.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwbWZubA.js → index-BZGdjNLA.js} +1 -1
- package/src/assets/web-panel/assets/{index-ThrAiEF9.js → index-BwFykZ5U.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUe5t5Aa.js → index-ByZQNO0A.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dn8m1d1f.js → index-C0rr1X9W.js} +2 -2
- package/src/assets/web-panel/assets/{index-C6SDf50u.js → index-CBhoZhCO.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClN_JuFa.js → index-CCRSz2cR.js} +1 -1
- package/src/assets/web-panel/assets/index-CZfySmWX.js +1 -0
- package/src/assets/web-panel/assets/{index-Dq5Rn5VS.js → index-Cj47XwJQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChahjdYE.js → index-Cmzh8gKL.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dyg6ikIL.js → index-CnxlKTDK.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dj9Nvz6S.js → index-CoF95pYK.js} +1 -1
- package/src/assets/web-panel/assets/{index-TwQZkVGh.js → index-Ctx97mH-.js} +1 -1
- package/src/assets/web-panel/assets/{index-s8tvk-fF.js → index-D0vX9jQA.js} +1 -1
- package/src/assets/web-panel/assets/{index-X48zYgZ6.js → index-DNkth8dM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DygNvCeR.js → index-DRp5_Xns.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_MzScPM.js → index-DW-Ji07y.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqnhEJls.js → index-DXgE2VW6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDyzZ8_O.js → index-D_0B3CiU.js} +1 -1
- package/src/assets/web-panel/assets/{index-C59FgSkU.js → index-Dbf5YmDX.js} +1 -1
- package/src/assets/web-panel/assets/{index-_zyXBoS7.js → index-DsNQ2hqI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJ7XYa5K.js → index-EY733h9z.js} +1 -1
- package/src/assets/web-panel/assets/{index-ibFHnqHz.js → index-QD_n54XT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CivbS-57.js → index-T5Y_9IPv.js} +1 -1
- package/src/assets/web-panel/assets/{index-C52udT0_.js → index-b8GbH2Yi.js} +4 -4
- package/src/assets/web-panel/assets/{index-XI6772AD.js → index-gUACAWbM.js} +1 -1
- package/src/assets/web-panel/assets/{index-F9cBucYf.js → index-onW325hZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKe9jmKG.js → index-ozVPr1gj.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_IgY63-.js → index-slYX2rCE.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_-RETt0.js → index-t9u2bHpH.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeGnHcp5.js → index-za1GUJBG.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DEi92ZnZ.js → initDefaultProps-DnadEaxu.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BtYKzpOc.js → motion-CC_Na0Tl.js} +1 -1
- package/src/assets/web-panel/assets/{move-Cb3A1-v-.js → move-C2d9Mkk9.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B6qPDdOf.js → omit-QvpKbF8p.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DDyeQMUc.js → pickAttrs-Dm8r3X1_.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BPV6VO47.js → placementArrow-DaqaVfoX.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DJ1ra4dT.js → responsiveObserve-Iida9fIn.js} +1 -1
- package/src/assets/web-panel/assets/{slide-D6v8tHvB.js → slide-YqHexXQD.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DulKcQLZ.js → statusUtils-BGKLoeEt.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Bne7zwMt.js → styleChecker-aI-gsQO8.js} +1 -1
- package/src/assets/web-panel/assets/useFlexGapSupport-BiOsz4rc.js +1 -0
- package/src/assets/web-panel/assets/{useFs-CR-iLa4Z.js → useFs-CZy7Zo2X.js} +1 -1
- package/src/assets/web-panel/assets/{useMergedState-O7QXt4P5.js → useMergedState-WwedrFR0.js} +1 -1
- package/src/assets/web-panel/assets/{useRefs-0J6m8UWN.js → useRefs-Cdq8EWeF.js} +1 -1
- package/src/assets/web-panel/assets/{useState-CSzR8F8O.js → useState-DGS1NOyn.js} +1 -1
- package/src/assets/web-panel/assets/{vendor-M5lGV-wr.js → vendor-DhFY8mDK.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-yL9axxBy.js → vnode-B6WqjmE4.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B-VCMXSD.js → zoom-DTeTrJ2z.js} +1 -1
- package/src/assets/web-panel/index.html +3 -3
- package/src/commands/__tests__/android.test.js +260 -0
- package/src/commands/__tests__/hub-aichat.test.js +277 -0
- package/src/commands/__tests__/hub-wechat.test.js +243 -0
- package/src/commands/android.js +284 -0
- package/src/commands/hub.js +457 -0
- package/src/commands/sync-providers.js +436 -0
- package/src/gateways/ws/personal-data-hub-protocol.js +88 -0
- package/src/index.js +6 -0
- package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +209 -0
- package/src/lib/__tests__/sync-credentials.test.js +265 -0
- package/src/lib/__tests__/sync-engine-cli.test.js +293 -0
- package/src/lib/cc-android-bridge.js +162 -0
- package/src/lib/personal-data-hub-aichat-wizard.js +242 -0
- package/src/lib/personal-data-hub-wiring.js +258 -13
- package/src/lib/sync-cli-db.js +194 -0
- package/src/lib/sync-credentials.js +225 -0
- package/src/lib/sync-engine-cli.js +406 -0
- package/src/lib/sync-oss-client.js +273 -0
- package/src/lib/sync-webdav-client.js +194 -0
- package/src/lib/web-ui-server.js +2 -1
- package/src/assets/web-panel/assets/PersonalDataHub--WA-aZAJ.js +0 -1
- package/src/assets/web-panel/assets/PersonalDataHub-BK7I0Rsb.css +0 -1
- package/src/assets/web-panel/assets/index-CcRX6BlT.js +0 -1
- package/src/assets/web-panel/assets/index-z6h6tqP3.js +0 -1
- 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:
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
+
};
|