chainlesschain 0.162.112 → 0.162.114
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/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-D5-YJKoN.js → AIOps-0-uMzHS0.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Dk_4drjU.js → ActionButton-DIZPfP0j.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BsvD2oq2.js → Analytics-D0XaT-HY.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DN-McO3E.js → AppLayout-BTRaqYvd.js} +5 -5
- package/src/assets/web-panel/assets/{Audit-aefwgTP9.js → Audit-CNf5Kaoi.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BHhJOdYB.js → Backup-BAo4Hi0L.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Dwuvhn6L.js → BaseInput-Cvl0T59f.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-AmCFCgt4.js → Chat-Cun14ni3.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Btfp4AhA.js → ChatBubbleRenderer-CVSvw44R.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DiqdvF8g.js → Checkbox-DJdTjyls.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Dii5apOL.js → Codegen-Bz_l_yn_.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BQEwtCpd.js → Col-Bht2QpqM.js} +1 -1
- package/src/assets/web-panel/assets/{Community-C1QIOwPY.js → Community-7KcO0kT1.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DN6Alh_k.js → Compact-B7rBvHIs.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-NeWI_3Mx.js → Compliance-BuxUJTnd.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-W7Ehca-3.js → Cowork-CJdjs2tJ.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CaXC-e_q.js → Cron-BZFJ7-YN.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BlzqApQU.js → Crosschain-BKsLLmuh.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Dzb92lQA.js → DID-BxRlZh9g.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-_72Ud513.js → Dashboard-B6RppX5d.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DRmDou35.js → Dropdown-DKtl6tbR.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DVFkRLM_.js → EmailListRenderer-BRyFvNHM.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-_lYBcnoY.js → FamilyGuardDashboard-C99TnWli.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CfJywi0p.js → Federation-lC9Io-Wx.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-nDkRTvQo.js → FormItemContext-kTzkIiAH.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DbwQOgKc.js → GenericCardRenderer-ffjSPeHn.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Dt1_K90g.js → Git-Ch-eo0ft.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C9rKuC3B.js → Governance-CSlXyDt9.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CIvFHSgW.js → Inference-innJ4CHB.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CEhLtSoG.js → KnowledgeGraph-BoKWXlKH.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-EB-9QMre.js → Logs-Bvu1ZVlJ.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-1o-qH1w6.js → Marketplace-Bz5plU9l.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-LA_KYh8b.js → McpTools-Ce2O172z.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-CW7J6_1u.js → Memory-CVTPzpDT.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-S4tPG0Ba.js → MobileBridge-DroRONe3.js} +2 -2
- package/src/assets/web-panel/assets/MobileProjects-Bfp8_lJh.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-B_z-P5eG.js → Mtc-BLe-_MDX.js} +6 -6
- package/src/assets/web-panel/assets/{MtcAudit-CqkMfPLz.js → MtcAudit-Cx6CIX_g.js} +6 -6
- package/src/assets/web-panel/assets/{Multisig-ByZ1RbjK.js → Multisig-OEeP6h30.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BJWczKc1.js → NLProgramming-B79aNNrY.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Dgbn9eAU.js → Notes-BzKbClTh.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-0hO1FTaS.js → NotificationSettings-6BcdjMJk.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DWbDOs7E.js → OrderTableRenderer-BdA4JzRg.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DBUZefzg.js → Organization-B_g6tN2h.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Dedhgbfn.js → Overflow-BPeDct0h.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DY5Uw2Ia.js → P2P-AbEH8Ad6.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-ChtX-zv3.js → PdhVaultBrowser-DTYIEFuT.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-Dgb0A1Dg.js → Permissions-Mtl6DRWC.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Bk6BcgxL.js → PersonalDataHub-CrfCdPgN.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-XTT0YUkh.js → Pipeline-Znd89-so.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-7Z7g_lgV.js → Privacy-1QK70XJJ.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DiwZ2oHT.js → ProjectInit-Dbh6fHo4.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DQP7mvM0.js → ProjectSettings-CtqWEUUX.js} +2 -2
- package/src/assets/web-panel/assets/Projects-C1vdepHb.js +1 -0
- package/src/assets/web-panel/assets/{Providers-BJYbpaJC.js → Providers-VRTSkt2N.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BdpeMXsV.js → QuickAsk-CP2dz_95.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BlhwuL7Q.js → Recommend-Bc81SmNo.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-DyIEa8eK.js → Reputation-cRunHZiV.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CcEPZJXB.js → Row-BwL7ApAT.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B8rGohFx.js → RssFeed-BVbyxvzm.js} +3 -3
- package/src/assets/web-panel/assets/{Search-B2qNi_vM.js → Search-D5PgTvOP.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DPeJ-uj5.js → Security-Ddt1DCcC.js} +4 -4
- package/src/assets/web-panel/assets/{Services-oh3XLHP7.js → Services-6UaJxmZU.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BuBnG-FL.js → Skeleton-DFRbEQwp.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BDHB_StS.js → Skills-5yq43K-X.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Dfj7IJ1M.js → Sla-yMroQlH9.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BrjNiNdy.js → SpeechSettings-B2S3Iamq.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DPiXTu-c.js → SyncSettings-BkKtXU71.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CwHx1NQg.js → Tasks-CBtNUwgq.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BPVQAUmL.js → Templates-C2drh0s2.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CbAtEvmi.js → Tenant-BLk2CVEv.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-lzSxpDKJ.js → Terminal-mElJ0fhK.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DMgwpq2x.js → TimelineRenderer-D4E9FDsp.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-B1fJ_0FO.js → Tokens-Cgmf0-_P.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-CcH8MCn9.js → Trigger-BRlJLDbx.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-cEy5Cv7s.js → Trust-C6RUSQhG.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-93daBtXV.js → UkeySign-Chi7u_hM.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BcqpfQCW.js → VideoEditing-4-bo8EmV.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-C3lPJuFG.js → Wallet-B2hSD9eY.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CIncm_eO.js → WebAuthn-D8xa8fun.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-C7QbGIC6.js → WorkflowEditor-Db9dxskT.js} +1 -1
- package/src/assets/web-panel/assets/{chat-_BGiBidF.js → chat-CXYLRZpi.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CqkIBVqp.js → colors-CaKoXOVA.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DDGiqXQp.js → compact-item-Br5NvOwQ.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C2sxnTAB.js → createContext-B-yHAw0V.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-B9dp57_Q.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-ADHC1pW8.js → hasIn-CqrdCz3g.js} +1 -1
- package/src/assets/web-panel/assets/{index-CYS85njA.js → index-1jqJ37zO.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9LBuvwe.js → index-8ghdlyXM.js} +1 -1
- package/src/assets/web-panel/assets/{index-XliCDQFQ.js → index-B1IlWIb6.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9enldZH.js → index-BQcTQlrC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnLh1mEV.js → index-BRlkm8k6.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfPDAlO3.js → index-BWxntLTd.js} +1 -1
- package/src/assets/web-panel/assets/{index-C6vR4EY-.js → index-BbZxkCWu.js} +1 -1
- package/src/assets/web-panel/assets/index-Bd3PIxeQ.js +1 -0
- package/src/assets/web-panel/assets/{index-Bn4gVM4t.js → index-BeE50mEy.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-batZVW.js → index-BeQiNau_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRssBAk_.js → index-BjAkyQXg.js} +1 -1
- package/src/assets/web-panel/assets/{index-BUqSQfe-.js → index-BmV-MOO5.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZpeHDG9.js → index-BrruO38Y.js} +3 -3
- package/src/assets/web-panel/assets/{index-B9gFEsuM.js → index-Byv9CEgj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLMJ-Zwl.js → index-BzpkjYz4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DD1ntIl_.js → index-CIZKEANZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-9_or8rsE.js → index-CMecOYUY.js} +1 -1
- package/src/assets/web-panel/assets/{index-f_7tVfQN.js → index-CQDhGgK-.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2X8QuZn.js → index-CVt4C93w.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGLwuyVE.js → index-CuaLeS0m.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKYSl45n.js → index-CvFe9Qyg.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9TmuLEi.js → index-CvJruKpV.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_2cn75G.js → index-D39l1vpr.js} +1 -1
- package/src/assets/web-panel/assets/{index-syq6WxjO.js → index-D6ngQeA0.js} +1 -1
- package/src/assets/web-panel/assets/{index-eF5qSZFy.js → index-D98MYD3m.js} +1 -1
- package/src/assets/web-panel/assets/{index-DwLTX_IW.js → index-DE2mB1ae.js} +1 -1
- package/src/assets/web-panel/assets/{index-CW-8fA2E.js → index-DGtE2LX-.js} +1 -1
- package/src/assets/web-panel/assets/{index-CSTrqDF5.js → index-DHwefCFJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-nWnefDZq.js → index-DZ9ISv1n.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZwfbVI0.js → index-DaQkxUNc.js} +1 -1
- package/src/assets/web-panel/assets/{index-2hSe8r-u.js → index-DbrcBvEd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhkXH2-c.js → index-DirWkR61.js} +1 -1
- package/src/assets/web-panel/assets/{index-PQ5M2zy0.js → index-Ds4JSZQz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNjShHol.js → index-KRKDnsR0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSDmPMlb.js → index-W_LrSwhD.js} +1 -1
- package/src/assets/web-panel/assets/index-WpnbyTfq.js +1 -0
- package/src/assets/web-panel/assets/{index-BfsOYXaR.js → index-ZB70zTAh.js} +1 -1
- package/src/assets/web-panel/assets/{index-Chof4NeM.js → index-hsgVTIGX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgXXKWeh.js → index-nT_CmIwR.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Df7mcMp7.js → initDefaultProps-CikG-5bi.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BT8UUoVr.js → motion--tkkEE3m.js} +1 -1
- package/src/assets/web-panel/assets/{move-D4ti8GiP.js → move-D6xAZefU.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DhvwGkZD.js → omit-CsD8Wwta.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DAWblJD8.js → pickAttrs-D4qa94u9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BIcwHC1D.js → placementArrow-9fx4sI6E.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Cow45GkA.js → responsiveObserve-DwYJKWhG.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DhNh5mZd.js → slide-DFxU8IG1.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CDmgb05N.js → statusUtils-DPAkc9NC.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B8HoJol7.js → styleChecker-D-ByG8n4.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CNESbv-e.js → useFlexGapSupport-DwVLaYMd.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BGkOBM9Y.js → useFs-CSyqOEiA.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-B4h_mNgo.js → usePersonalDataHub-B7qEu3ar.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-vfzdFP3R.js → vnode-4YgwyfPJ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D-IzQshP.js → zoom-CPUWjtMS.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/audit.js +21 -3
- package/src/commands/browse.js +18 -3
- package/src/commands/compliance.js +7 -1
- package/src/commands/cost.js +9 -1
- package/src/commands/hub.js +8 -0
- package/src/commands/mcp.js +15 -2
- package/src/commands/note.js +53 -25
- package/src/lib/hub-llm-client.js +248 -0
- package/src/lib/permission-rules.cjs +33 -0
- package/src/lib/personal-data-hub-wiring.js +20 -4
- package/src/assets/web-panel/assets/MobileProjects-CKsCtJtE.js +0 -1
- package/src/assets/web-panel/assets/Projects-fN6yqMZg.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DkTISuFY.js +0 -1
- package/src/assets/web-panel/assets/index-Bkf7pbci.js +0 -1
- package/src/assets/web-panel/assets/index-C4lFS6nf.js +0 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hub-llm-client — build a hub LLMClient from the user's cc config / env so
|
|
3
|
+
* standalone `cc hub ask` can use a configured CLOUD provider instead of the
|
|
4
|
+
* Ollama-only default.
|
|
5
|
+
*
|
|
6
|
+
* Why this exists: the standalone CLI hub (personal-data-hub-wiring.js
|
|
7
|
+
* `initHub`) hard-binds OllamaClient unless a caller injects an override.
|
|
8
|
+
* Only the desktop web-shell does that (CcLLMAdapter wrapping LLMManager), so
|
|
9
|
+
* a machine without Ollama installed can't run `cc hub ask` at all — the RAG
|
|
10
|
+
* retrieval works but the final LLM call fails. This adapter gives the CLI the
|
|
11
|
+
* same "honor the user's active provider" behavior the desktop has.
|
|
12
|
+
*
|
|
13
|
+
* Privacy: OPT-IN ONLY via env `CC_HUB_LLM`. When unset, this returns null and
|
|
14
|
+
* the caller keeps the safe local-Ollama default (the §11.2 privacy promise:
|
|
15
|
+
* personal data stays on-device unless the user explicitly opts in). The
|
|
16
|
+
* client always reports `isLocal: false`, so the AnalysisEngine still refuses
|
|
17
|
+
* to USE it unless the `ask` command is given `--accept-non-local`
|
|
18
|
+
* (or env `CC_HUB_ALLOW_NON_LOCAL`). Two independent gates: this one chooses
|
|
19
|
+
* the backend, that one authorizes sending data off-device.
|
|
20
|
+
*
|
|
21
|
+
* CC_HUB_LLM unset / ollama / local / off / 0 -> null (local Ollama default)
|
|
22
|
+
* CC_HUB_LLM = config | auto | on | 1 -> config.llm.{provider,model,baseUrl,apiKey}
|
|
23
|
+
* CC_HUB_LLM = <provider> -> that provider; reuse config
|
|
24
|
+
* creds when config.llm.provider
|
|
25
|
+
* matches, else provider default
|
|
26
|
+
* baseUrl + key from env/config
|
|
27
|
+
*
|
|
28
|
+
* Returns null (→ caller falls back to OllamaClient) when it can't build a
|
|
29
|
+
* usable cloud client: provider resolves to ollama, or a cloud provider has no
|
|
30
|
+
* API key. Never throws at build time — a bad CC_HUB_LLM just keeps the local
|
|
31
|
+
* default rather than bricking `cc hub`.
|
|
32
|
+
*
|
|
33
|
+
* Contract (mirrors pdh OllamaClient): `{ name, isLocal, chat(messages, opts)
|
|
34
|
+
* -> { text, usage?, model? } }`. messages = [{ role, content }] (the hub
|
|
35
|
+
* stitches system + user-with-facts and hands them off opaque).
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
"use strict";
|
|
39
|
+
|
|
40
|
+
import { BUILT_IN_PROVIDERS } from "./llm-providers.js";
|
|
41
|
+
|
|
42
|
+
const LOCAL_SENTINELS = new Set([
|
|
43
|
+
"",
|
|
44
|
+
"ollama",
|
|
45
|
+
"local",
|
|
46
|
+
"off",
|
|
47
|
+
"0",
|
|
48
|
+
"false",
|
|
49
|
+
"no",
|
|
50
|
+
]);
|
|
51
|
+
const CONFIG_SENTINELS = new Set(["config", "auto", "on", "1", "true", "yes"]);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {{config?: object, env?: object}} [args]
|
|
55
|
+
* @returns {{name:string,isLocal:boolean,chat:Function}|null}
|
|
56
|
+
*/
|
|
57
|
+
export function buildCliHubLLM({ config = {}, env = process.env } = {}) {
|
|
58
|
+
const raw = String(env.CC_HUB_LLM || "")
|
|
59
|
+
.trim()
|
|
60
|
+
.toLowerCase();
|
|
61
|
+
if (LOCAL_SENTINELS.has(raw)) return null;
|
|
62
|
+
|
|
63
|
+
const cfgLlm = (config && config.llm) || {};
|
|
64
|
+
let provider, model, baseUrl, apiKey;
|
|
65
|
+
|
|
66
|
+
if (CONFIG_SENTINELS.has(raw)) {
|
|
67
|
+
provider = String(cfgLlm.provider || "").toLowerCase();
|
|
68
|
+
model = cfgLlm.model;
|
|
69
|
+
baseUrl = cfgLlm.baseUrl;
|
|
70
|
+
apiKey = cfgLlm.apiKey;
|
|
71
|
+
} else {
|
|
72
|
+
provider = raw;
|
|
73
|
+
// Reuse the saved credentials only when they belong to the requested
|
|
74
|
+
// provider; otherwise fall back to provider defaults + env key.
|
|
75
|
+
const sameProvider =
|
|
76
|
+
String(cfgLlm.provider || "").toLowerCase() === provider;
|
|
77
|
+
model = sameProvider ? cfgLlm.model : null;
|
|
78
|
+
baseUrl = sameProvider ? cfgLlm.baseUrl : null;
|
|
79
|
+
apiKey = sameProvider ? cfgLlm.apiKey : null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!provider || provider === "ollama") return null;
|
|
83
|
+
|
|
84
|
+
const def = BUILT_IN_PROVIDERS[provider] || null;
|
|
85
|
+
const resolvedBase = baseUrl || (def && def.baseUrl) || null;
|
|
86
|
+
const resolvedModel = model || (def && def.models && def.models[0]) || null;
|
|
87
|
+
const resolvedKey =
|
|
88
|
+
apiKey || (def && def.apiKeyEnv ? env[def.apiKeyEnv] : null) || null;
|
|
89
|
+
|
|
90
|
+
if (!resolvedBase || !resolvedModel) return null;
|
|
91
|
+
if (!resolvedKey) return null; // every supported cloud provider needs a key
|
|
92
|
+
|
|
93
|
+
const isAnthropic = provider === "anthropic";
|
|
94
|
+
return {
|
|
95
|
+
name: `${provider}:${resolvedModel}`,
|
|
96
|
+
isLocal: false,
|
|
97
|
+
async chat(messages, opts = {}) {
|
|
98
|
+
if (isAnthropic) {
|
|
99
|
+
return anthropicChat({
|
|
100
|
+
base: resolvedBase,
|
|
101
|
+
key: resolvedKey,
|
|
102
|
+
model: resolvedModel,
|
|
103
|
+
messages,
|
|
104
|
+
opts,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return openAiCompatChat({
|
|
108
|
+
base: resolvedBase,
|
|
109
|
+
key: resolvedKey,
|
|
110
|
+
model: resolvedModel,
|
|
111
|
+
messages,
|
|
112
|
+
opts,
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function trimBase(base) {
|
|
119
|
+
return String(base).replace(/\/+$/, "");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function normUsage(u) {
|
|
123
|
+
if (!u) return undefined;
|
|
124
|
+
return {
|
|
125
|
+
promptTokens: u.prompt_tokens ?? u.promptTokens,
|
|
126
|
+
completionTokens: u.completion_tokens ?? u.completionTokens,
|
|
127
|
+
totalTokens: u.total_tokens ?? u.totalTokens,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* OpenAI-compatible /chat/completions (openai, volcengine, deepseek,
|
|
133
|
+
* dashscope, mistral, gemini-compat, and any custom baseUrl that speaks it).
|
|
134
|
+
*/
|
|
135
|
+
export async function openAiCompatChat({
|
|
136
|
+
base,
|
|
137
|
+
key,
|
|
138
|
+
model,
|
|
139
|
+
messages,
|
|
140
|
+
opts = {},
|
|
141
|
+
fetchImpl = fetch,
|
|
142
|
+
}) {
|
|
143
|
+
const body = { model, messages };
|
|
144
|
+
if (typeof opts.temperature === "number") body.temperature = opts.temperature;
|
|
145
|
+
const maxTokens = opts.maxTokens ?? opts.max_tokens;
|
|
146
|
+
if (Number.isFinite(maxTokens)) body.max_tokens = maxTokens;
|
|
147
|
+
|
|
148
|
+
const resp = await fetchImpl(`${trimBase(base)}/chat/completions`, {
|
|
149
|
+
method: "POST",
|
|
150
|
+
headers: {
|
|
151
|
+
"Content-Type": "application/json",
|
|
152
|
+
Authorization: `Bearer ${key}`,
|
|
153
|
+
},
|
|
154
|
+
body: JSON.stringify(body),
|
|
155
|
+
});
|
|
156
|
+
if (!resp.ok) {
|
|
157
|
+
const t = await resp.text().catch(() => "");
|
|
158
|
+
throw new Error(
|
|
159
|
+
`hub LLM (${model}): HTTP ${resp.status} ${resp.statusText} ${t.slice(0, 300)}`.trim(),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const data = await resp.json();
|
|
163
|
+
if (data && data.error) {
|
|
164
|
+
const m = data.error.message || JSON.stringify(data.error);
|
|
165
|
+
throw new Error(`hub LLM (${model}): ${m}`);
|
|
166
|
+
}
|
|
167
|
+
const msg =
|
|
168
|
+
data && data.choices && data.choices[0] && data.choices[0].message;
|
|
169
|
+
// Some providers (doubao reasoning models) put the answer in `content`;
|
|
170
|
+
// fall back to `reasoning_content` only if content is empty.
|
|
171
|
+
const text = (msg && (msg.content || msg.reasoning_content)) || "";
|
|
172
|
+
return {
|
|
173
|
+
text,
|
|
174
|
+
model: (data && data.model) || model,
|
|
175
|
+
usage: normUsage(data && data.usage),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Anthropic native /v1/messages — system extracted from the messages array,
|
|
181
|
+
* which Anthropic takes as a top-level `system` field.
|
|
182
|
+
*/
|
|
183
|
+
export async function anthropicChat({
|
|
184
|
+
base,
|
|
185
|
+
key,
|
|
186
|
+
model,
|
|
187
|
+
messages,
|
|
188
|
+
opts = {},
|
|
189
|
+
fetchImpl = fetch,
|
|
190
|
+
}) {
|
|
191
|
+
const system = messages
|
|
192
|
+
.filter((m) => m.role === "system")
|
|
193
|
+
.map((m) => m.content)
|
|
194
|
+
.join("\n\n");
|
|
195
|
+
const turns = messages
|
|
196
|
+
.filter((m) => m.role !== "system")
|
|
197
|
+
.map((m) => ({
|
|
198
|
+
role: m.role === "assistant" ? "assistant" : "user",
|
|
199
|
+
content: m.content,
|
|
200
|
+
}));
|
|
201
|
+
|
|
202
|
+
const body = {
|
|
203
|
+
model,
|
|
204
|
+
messages: turns,
|
|
205
|
+
max_tokens: Number.isFinite(opts.maxTokens ?? opts.max_tokens)
|
|
206
|
+
? (opts.maxTokens ?? opts.max_tokens)
|
|
207
|
+
: 2048,
|
|
208
|
+
};
|
|
209
|
+
if (system) body.system = system;
|
|
210
|
+
if (typeof opts.temperature === "number") body.temperature = opts.temperature;
|
|
211
|
+
|
|
212
|
+
const resp = await fetchImpl(`${trimBase(base)}/messages`, {
|
|
213
|
+
method: "POST",
|
|
214
|
+
headers: {
|
|
215
|
+
"Content-Type": "application/json",
|
|
216
|
+
"x-api-key": key,
|
|
217
|
+
"anthropic-version": "2023-06-01",
|
|
218
|
+
},
|
|
219
|
+
body: JSON.stringify(body),
|
|
220
|
+
});
|
|
221
|
+
if (!resp.ok) {
|
|
222
|
+
const t = await resp.text().catch(() => "");
|
|
223
|
+
throw new Error(
|
|
224
|
+
`hub LLM (${model}): HTTP ${resp.status} ${resp.statusText} ${t.slice(0, 300)}`.trim(),
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
const data = await resp.json();
|
|
228
|
+
if (data && data.error) {
|
|
229
|
+
const m = data.error.message || JSON.stringify(data.error);
|
|
230
|
+
throw new Error(`hub LLM (${model}): ${m}`);
|
|
231
|
+
}
|
|
232
|
+
const text = ((data && data.content) || [])
|
|
233
|
+
.filter((b) => b && b.type === "text")
|
|
234
|
+
.map((b) => b.text)
|
|
235
|
+
.join("");
|
|
236
|
+
const u = data && data.usage;
|
|
237
|
+
return {
|
|
238
|
+
text,
|
|
239
|
+
model: (data && data.model) || model,
|
|
240
|
+
usage: u
|
|
241
|
+
? {
|
|
242
|
+
promptTokens: u.input_tokens,
|
|
243
|
+
completionTokens: u.output_tokens,
|
|
244
|
+
totalTokens: (u.input_tokens || 0) + (u.output_tokens || 0),
|
|
245
|
+
}
|
|
246
|
+
: undefined,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
* input parameter, incl. arbitrary MCP tool args;
|
|
19
19
|
* `*` crosses `/` here, unlike path globs)
|
|
20
20
|
* mcp__db__query(table:users) → that MCP tool whose `table` arg is "users"
|
|
21
|
+
* Agent(Explore) → spawn_sub_agent whose type (profile/agent/role) is
|
|
22
|
+
* "Explore" (CC 2.1.186 `Agent(type)`; case-insensitive
|
|
23
|
+
* identifiers, globs ok)
|
|
24
|
+
* Agent(Explore,Plan) → spawn_sub_agent whose type is Explore OR Plan
|
|
25
|
+
* (CC 2.1.186 `Agent(x,y)` allowed/denied-types list)
|
|
21
26
|
* Bash → every run_shell call
|
|
22
27
|
* * → every tool call (Claude-Code deny-all idiom)
|
|
23
28
|
* Bash(*) → every run_shell call (lone-`*` pattern = match-all)
|
|
@@ -54,6 +59,7 @@ const TOOL_GROUPS = Object.freeze({
|
|
|
54
59
|
webfetch: ["web_fetch"],
|
|
55
60
|
websearch: ["web_search"],
|
|
56
61
|
task: ["spawn_sub_agent"],
|
|
62
|
+
agent: ["spawn_sub_agent"],
|
|
57
63
|
skill: ["run_skill", "list_skills"],
|
|
58
64
|
runcode: ["run_code"],
|
|
59
65
|
git: ["git"],
|
|
@@ -73,6 +79,8 @@ const PATH_TOOLS = new Set([
|
|
|
73
79
|
]);
|
|
74
80
|
/** Tools whose match target is a URL. */
|
|
75
81
|
const URL_TOOLS = new Set(["web_fetch"]);
|
|
82
|
+
/** Tools whose positional pattern is a sub-agent TYPE list (CC `Agent(type)`). */
|
|
83
|
+
const SUBAGENT_TOOLS = new Set(["spawn_sub_agent"]);
|
|
76
84
|
|
|
77
85
|
/**
|
|
78
86
|
* Does a rule's tool token apply to the concrete tool being evaluated?
|
|
@@ -254,6 +262,30 @@ function matchPattern(pattern, actualTool, args, cwd) {
|
|
|
254
262
|
if (pv && Object.prototype.hasOwnProperty.call(args || {}, pv[1])) {
|
|
255
263
|
return matchParamValue(pv[2].trim(), (args || {})[pv[1]]);
|
|
256
264
|
}
|
|
265
|
+
// Claude-Code 2.1.186: `Agent(type)` / `Agent(typeA,typeB)` — restrict the
|
|
266
|
+
// spawn_sub_agent tool by sub-agent TYPE. A call's type identity is its
|
|
267
|
+
// `profile`, named `agent`, or `role` (whichever are present). The pattern is
|
|
268
|
+
// a comma-separated list; it matches when ANY listed type matches ANY of the
|
|
269
|
+
// call's identities (case-insensitive identifiers; `*`/`?` globs allowed).
|
|
270
|
+
// The `Tool(param:value)` branch above still handles `Task(profile:explorer)`;
|
|
271
|
+
// this adds the bare positional spelling Claude-Code settings.json uses.
|
|
272
|
+
if (SUBAGENT_TOOLS.has(actualTool)) {
|
|
273
|
+
const a = args || {};
|
|
274
|
+
const ids = [a.profile, a.agent, a.role].filter(
|
|
275
|
+
(x) => x != null && String(x) !== "",
|
|
276
|
+
);
|
|
277
|
+
if (!ids.length) return false;
|
|
278
|
+
const wanted = pattern
|
|
279
|
+
.split(",")
|
|
280
|
+
.map((s) => s.trim())
|
|
281
|
+
.filter(Boolean);
|
|
282
|
+
if (!wanted.length) return false;
|
|
283
|
+
return wanted.some((w) =>
|
|
284
|
+
ids.some((id) =>
|
|
285
|
+
matchParamValue(w.toLowerCase(), String(id).toLowerCase()),
|
|
286
|
+
),
|
|
287
|
+
);
|
|
288
|
+
}
|
|
257
289
|
const target = extractTarget(actualTool, args, cwd);
|
|
258
290
|
if (target.kind === "command") {
|
|
259
291
|
return target.value ? matchCommand(pattern, target.value) : false;
|
|
@@ -367,6 +399,7 @@ module.exports = {
|
|
|
367
399
|
COMMAND_TOOLS,
|
|
368
400
|
PATH_TOOLS,
|
|
369
401
|
URL_TOOLS,
|
|
402
|
+
SUBAGENT_TOOLS,
|
|
370
403
|
toolMatches,
|
|
371
404
|
parseRule,
|
|
372
405
|
globToRegExp,
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
import { join } from "node:path";
|
|
28
28
|
import { mkdirSync } from "node:fs";
|
|
29
29
|
import { rewritePdhLoadError } from "./pdh-load-error.js";
|
|
30
|
+
import { loadConfig } from "./config-manager.js";
|
|
31
|
+
import { buildCliHubLLM } from "./hub-llm-client.js";
|
|
30
32
|
// Test seam (mirrors _atomicWriteJson600): re-exported so the existing
|
|
31
33
|
// pdh-wiring-load-error suite can keep importing it from here.
|
|
32
34
|
export { rewritePdhLoadError as _rewritePdhLoadError } from "./pdh-load-error.js";
|
|
@@ -369,12 +371,26 @@ async function initHub() {
|
|
|
369
371
|
const vault = new LocalVault({ path: join(hubDir, "vault.db"), key });
|
|
370
372
|
vault.open();
|
|
371
373
|
|
|
372
|
-
// LLM
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
//
|
|
374
|
+
// LLM resolution order:
|
|
375
|
+
// 1. caller-injected override (desktop web-shell wires CcLLMAdapter
|
|
376
|
+
// wrapping LLMManager so PDH honors the user's saved active provider).
|
|
377
|
+
// 2. CLI cloud client built from cc config / env — OPT-IN via CC_HUB_LLM,
|
|
378
|
+
// so a machine without Ollama can run `cc hub ask` against the user's
|
|
379
|
+
// configured provider (volcengine/anthropic/...). Reports isLocal=false;
|
|
380
|
+
// the AnalysisEngine still refuses to use it unless `ask` is given
|
|
381
|
+
// --accept-non-local (privacy gate stays intact). Default (unset) → null.
|
|
382
|
+
// 3. standalone OllamaClient — connects to localhost:11434 (the privacy
|
|
383
|
+
// promise default). Override via env CC_HUB_OLLAMA_URL / _OLLAMA_MODEL.
|
|
384
|
+
let cliCloudLlm = null;
|
|
385
|
+
try {
|
|
386
|
+
cliCloudLlm = buildCliHubLLM({ config: loadConfig(), env: process.env });
|
|
387
|
+
} catch {
|
|
388
|
+
// fail-open: a bad CC_HUB_LLM / unreadable config must never brick the hub.
|
|
389
|
+
cliCloudLlm = null;
|
|
390
|
+
}
|
|
376
391
|
const llm =
|
|
377
392
|
_llmOverride ||
|
|
393
|
+
cliCloudLlm ||
|
|
378
394
|
new OllamaClient({
|
|
379
395
|
baseUrl: process.env.CC_HUB_OLLAMA_URL || "http://localhost:11434",
|
|
380
396
|
model: process.env.CC_HUB_OLLAMA_MODEL || "qwen2.5:7b-instruct",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as n,J as g,c as l,K as r,N as u,P as h,U as o,R as t,Q as b}from"./vendor-BvqAck49.js";import{_ as v,b as m}from"./index-CZpeHDG9.js";import{a7 as y,M as B}from"./icons-DP3uiYxy.js";const M={__name:"MobileProjects",setup(p,{expose:i}){i();const c=u(),{t:e}=m();function a(){c.push("/projects")}function _(){c.push("/mobile-bridge")}const s={router:c,t:e,goToProjects:a,goToMobileBridge:_,get useRouter(){return u},get useI18n(){return m},get MobileOutlined(){return B},get FolderOutlined(){return y}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},x={class:"mobile-projects-placeholder"},O={class:"title"},w={class:"subtitle"},T={class:"explainer"};function k(p,i,c,e,a,_){const s=n("a-alert"),d=n("a-button"),f=n("a-space"),P=n("a-empty"),j=n("a-card");return h(),g("div",x,[l(j,null,{default:r(()=>[l(P,{description:!1},{image:r(()=>[l(e.MobileOutlined,{style:{fontSize:"64px",color:"#bfbfbf"}})]),default:r(()=>[o("h2",O,t(e.t("mobileProjects.title")),1),o("p",w,t(e.t("mobileProjects.subtitle")),1),l(s,{message:e.t("mobileProjects.v02Banner"),type:"info","show-icon":"",class:"banner"},null,8,["message"]),o("div",T,[o("h3",null,t(e.t("mobileProjects.currentDirection")),1),o("p",null,t(e.t("mobileProjects.currentDirectionBody")),1),o("ul",null,[o("li",null,t(e.t("mobileProjects.stepPhone")),1),o("li",null,t(e.t("mobileProjects.stepTap")),1),o("li",null,t(e.t("mobileProjects.stepPull")),1)]),o("h3",null,t(e.t("mobileProjects.reverseDirection")),1),o("p",null,t(e.t("mobileProjects.reverseDirectionBody")),1)]),l(f,{class:"actions"},{default:r(()=>[l(d,{type:"primary",onClick:e.goToProjects},{default:r(()=>[l(e.FolderOutlined),b(" "+t(e.t("mobileProjects.viewLocalProjects")),1)]),_:1}),l(d,{onClick:e.goToMobileBridge},{default:r(()=>[l(e.MobileOutlined),b(" "+t(e.t("mobileProjects.checkBridge")),1)]),_:1})]),_:1})]),_:1})]),_:1})])}const N=v(M,[["render",k],["__scopeId","data-v-9262cc45"],["__file","/tmp/cc-web-panel-wTPIBh/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{N as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as i,J as h,U as A,R as s,Q as r,c as t,K as a,V as _,S as x,o as oe,b as ee,r as u,P as p,F as ne,a2 as ge}from"./vendor-BvqAck49.js";import{_ as we,b as re,u as ie,d}from"./index-CZpeHDG9.js";import{u as de}from"./useShellMode-CgR0wCYM.js";import{aM as ke,aN as Fe,aO as be,f as je,a4 as Ce,a7 as xe,as as Oe,R as Se}from"./icons-DP3uiYxy.js";const Pe={__name:"Projects",setup(se,{expose:l}){l();const{t:te}=re(),e=ie(),{isEmbedded:W}=de();async function w(o,f,ye,ae=8e3){if(W){const Z=await e.sendRaw({...f,type:o},ae);if(!Z?.ok){const $=Z?.error;throw new Error(typeof $=="string"?$:$?.message||`${o} failed`)}return Z.result}return e.executeJson(ye,ae)}const B=u(!1),y=u([]),O=u(""),S=u(""),P=u(!1),v=u(null),U=u([]),k=u(!1),E=u(!1),L=u(!1),F=u({name:"",description:"",type:"document",rootPath:""}),z=[{title:"ID",key:"id",width:110},{title:"名称",key:"name"},{title:"类型",key:"project_type",width:120},{title:"状态",key:"status",width:100},{title:"同步",key:"sync_status",width:100},{title:"更新",key:"updated_at",width:160},{title:"操作",key:"actions",width:180,fixed:"right"}],M=ee(()=>{const o={active:0,draft:0,completed:0,archived:0};for(const f of y.value)o[f.status]!==void 0&&(o[f.status]+=1);return o}),J=ee(()=>y.value.filter(o=>!(O.value&&o.status!==O.value||S.value&&!o.name.toLowerCase().includes(S.value.toLowerCase()))));function g(o){switch(o){case"active":return"green";case"draft":return"default";case"completed":return"cyan";case"archived":return"gold";default:return"default"}}function K(o){switch(o){case"synced":return"green";case"pending":return"orange";case"conflict":return"red";case"error":return"red";default:return"default"}}function Q(o){return!o&&o!==0?"-":new Date(typeof o=="number"?o:parseInt(o,10)).toLocaleString("zh-CN",{hour12:!1})}async function C(){B.value=!0;try{const o=await w("project.list",{limit:500},"project list --limit 500 --json",1e4);y.value=Array.isArray(o?.projects)?o.projects:Array.isArray(o)?o:[]}catch(o){d.error("加载失败: "+(o.message||o)),y.value=[]}finally{B.value=!1}}function G(o){return{onClick:()=>V(o)}}async function V(o){v.value=o,P.value=!0,k.value=!0,U.value=[];try{const f=await w("project.listFiles",{projectId:o.id,limit:200},`project list-files ${o.id} --json`,8e3);U.value=Array.isArray(f?.files)?f.files:[]}catch{U.value=[]}finally{k.value=!1}}async function H(o){try{(await w("project.delete",{id:o.id},`project delete ${o.id} --json`,8e3))?.ok?(d.success(`已删除项目 '${o.name}'`),P.value=!1,await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}function X(){F.value={name:"",description:"",type:"document",rootPath:""},E.value=!0}async function T(){if(!F.value.name.trim()){d.warning("请输入项目名称");return}L.value=!0;try{const o=await w("project.init",{name:F.value.name.trim(),description:F.value.description||null,projectType:F.value.type,rootPath:F.value.rootPath||null},`project init "${F.value.name.trim()}" --type ${F.value.type} --json`,8e3);o?.id?(d.success(`已创建项目 '${o.name}'`),E.value=!1,await C()):d.error("创建失败")}catch(o){d.error(o.message||String(o))}finally{L.value=!1}}const b=u(!1),D=u(!1),j=u({path:"",content:""}),I=u(!1),m=u(!1),R=u({path:""}),n=u(!1),c=u(null),q=u(""),Y=u(!1);function ue(){j.value={path:"",content:""},b.value=!0}function ce(){R.value={path:""},I.value=!0}async function N(){if(v.value){k.value=!0;try{const o=await w("project.listFiles",{projectId:v.value.id,limit:200},`project list-files ${v.value.id} --json`,8e3);U.value=Array.isArray(o?.files)?o.files:[]}catch(o){d.error("刷新文件失败: "+(o.message||o))}finally{k.value=!1}}}async function fe(){if(!j.value.path.trim()){d.warning("请输入文件路径");return}if(v.value){D.value=!0;try{const o=await w("project.createFile",{projectId:v.value.id,filePath:j.value.path.trim(),content:j.value.content||""},`project create-file ${v.value.id} "${j.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件 '${o.file_name}'`),b.value=!1,await N(),await C()):d.error("创建文件失败")}catch(o){d.error(o.message||String(o))}finally{D.value=!1}}}async function pe(){if(!R.value.path.trim()){d.warning("请输入文件夹路径");return}if(v.value){m.value=!0;try{const o=await w("project.createFolder",{projectId:v.value.id,folderPath:R.value.path.trim()},`project create-folder ${v.value.id} "${R.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件夹 '${o.file_name}'`),I.value=!1,await N(),await C()):d.error("创建文件夹失败")}catch(o){d.error(o.message||String(o))}finally{m.value=!1}}}async function ve(o){try{(await w("project.deleteFile",{fileId:o.id},`project delete-file ${o.id} --json`,8e3))?.deleted?(d.success(`已删除 '${o.file_name}'`),await N(),await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}async function me(o){if(o.is_folder){d.info("文件夹无内容可编辑");return}try{const f=await w("project.getFile",{fileId:o.id},`project get-file ${o.id} --json`,8e3);c.value=o,q.value=f?.content||"",n.value=!0}catch(f){d.error("读取文件失败: "+(f.message||f))}}async function _e(){if(c.value){Y.value=!0;try{(await w("project.writeFile",{fileId:c.value.id,content:q.value},`project write-file ${c.value.id} --json`,8e3))?.id?(d.success("已保存"),n.value=!1,await N()):d.error("保存失败")}catch(o){d.error(o.message||String(o))}finally{Y.value=!1}}}oe(()=>{C()});const le={t:te,ws:e,isEmbedded:W,callProjectTopic:w,loading:B,projects:y,statusFilter:O,nameFilter:S,detailOpen:P,detail:v,files:U,filesLoading:k,createOpen:E,creating:L,newProject:F,columns:z,countByStatus:M,filteredProjects:J,statusColor:g,syncColor:K,formatTime:Q,loadAll:C,onRowClick:G,openDetail:V,onDelete:H,onShowCreate:X,onCreate:T,createFileOpen:b,creatingFile:D,newFile:j,createFolderOpen:I,creatingFolder:m,newFolder:R,editFileOpen:n,editingFile:c,editFileContent:q,savingFile:Y,openCreateFile:ue,openCreateFolder:ce,refreshFiles:N,onCreateFile:fe,onCreateFolder:pe,onDeleteFile:ve,openEditFile:me,onSaveFile:_e,ref:u,computed:ee,onMounted:oe,get ReloadOutlined(){return Se},get PlusOutlined(){return Oe},get FolderOutlined(){return xe},get FileTextOutlined(){return Ce},get CheckCircleOutlined(){return je},get CheckSquareOutlined(){return be},get FileAddOutlined(){return Fe},get FolderAddOutlined(){return ke},get message(){return d},get useI18n(){return re},get useWsStore(){return ie},get useShellMode(){return de}};return Object.defineProperty(le,"__isScriptSetup",{enumerable:!1,value:!0}),le}},ze={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},Ie={class:"page-title"},he={class:"page-sub"},Ae={class:"filter-bar",style:{"margin-bottom":"12px",display:"flex",gap:"12px","align-items":"center"}},Ue={key:0,style:{"font-size":"12px",color:"#888"}},De={key:0,style:{color:"#888","font-size":"12px"}},Re={key:0},Te={key:1,style:{color:"#888"}},Be=["onClick"],Ee={key:0,style:{color:"#888","font-size":"12px"}};function Le(se,l,te,e,W,w){const B=i("router-link"),y=i("a-button"),O=i("a-space"),S=i("a-statistic"),P=i("a-card"),v=i("a-col"),U=i("a-row"),k=i("a-radio-button"),E=i("a-radio-group"),L=i("a-input-search"),F=i("a-alert"),z=i("a-tag"),M=i("a-popconfirm"),J=i("a-table"),g=i("a-descriptions-item"),K=i("a-descriptions"),Q=i("a-divider"),C=i("a-empty"),G=i("a-list-item"),V=i("a-list"),H=i("a-spin"),X=i("a-drawer"),T=i("a-input"),b=i("a-form-item"),D=i("a-textarea"),j=i("a-form"),I=i("a-modal"),m=i("a-select-option"),R=i("a-select");return p(),h("div",null,[A("div",ze,[A("div",null,[A("h2",Ie,s(e.t("projects.title")),1),A("p",he,[l[17]||(l[17]=r("桌面 / CLI / 手机 三端共享同一份项目数据,Phase 3d sync 自动同步 (",-1)),t(B,{to:"/project-init"},{default:a(()=>[...l[16]||(l[16]=[r("项目初始化 / 环境设置",-1)])]),_:1}),l[18]||(l[18]=r(")",-1))])]),t(O,null,{default:a(()=>[t(y,{loading:e.loading,onClick:e.loadAll},{icon:a(()=>[t(e.ReloadOutlined)]),default:a(()=>[l[19]||(l[19]=r(" 刷新 ",-1))]),_:1},8,["loading"]),t(y,{type:"primary",onClick:e.onShowCreate},{icon:a(()=>[t(e.PlusOutlined)]),default:a(()=>[l[20]||(l[20]=r(" 新建项目 ",-1))]),_:1})]),_:1})]),_(" Stats "),t(U,{gutter:[16,16],style:{"margin-bottom":"20px"}},{default:a(()=>[t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"总项目",value:e.projects.length,"value-style":{color:"#1677ff",fontSize:"20px"}},{prefix:a(()=>[t(e.FolderOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"活跃",value:e.countByStatus.active,"value-style":{color:"#52c41a",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckCircleOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"草稿",value:e.countByStatus.draft,"value-style":{color:"#8c8c8c",fontSize:"20px"}},{prefix:a(()=>[t(e.FileTextOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"已完成",value:e.countByStatus.completed,"value-style":{color:"#13c2c2",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckSquareOutlined)]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),_(" Filter "),A("div",Ae,[t(E,{value:e.statusFilter,"onUpdate:value":l[0]||(l[0]=n=>e.statusFilter=n),size:"small","button-style":"solid"},{default:a(()=>[t(k,{value:""},{default:a(()=>[...l[21]||(l[21]=[r("全部",-1)])]),_:1}),t(k,{value:"active"},{default:a(()=>[...l[22]||(l[22]=[r("活跃",-1)])]),_:1}),t(k,{value:"draft"},{default:a(()=>[...l[23]||(l[23]=[r("草稿",-1)])]),_:1}),t(k,{value:"completed"},{default:a(()=>[...l[24]||(l[24]=[r("已完成",-1)])]),_:1}),t(k,{value:"archived"},{default:a(()=>[...l[25]||(l[25]=[r("已归档",-1)])]),_:1})]),_:1},8,["value"]),t(L,{value:e.nameFilter,"onUpdate:value":l[1]||(l[1]=n=>e.nameFilter=n),placeholder:"按名称过滤",style:{"max-width":"260px"},"allow-clear":""},null,8,["value"])]),!e.projects.length&&!e.loading?(p(),x(F,{key:0,type:"info",message:"还没有项目",description:'运行 `cc project init <name>` 或点击右上角"新建项目"按钮创建。桌面 / CLI / 手机三端共享同一份数据。',"show-icon":"",style:{"margin-bottom":"16px"}})):_("v-if",!0),e.projects.length||e.loading?(p(),x(J,{key:1,columns:e.columns,"data-source":e.filteredProjects,loading:e.loading,pagination:{pageSize:20,showSizeChanger:!0},"row-key":"id","custom-row":e.onRowClick},{bodyCell:a(({column:n,record:c})=>[n.key==="id"?(p(),h("code",Ue,s(c.id.slice(0,8))+"…",1)):n.key==="name"?(p(),h(ne,{key:1},[A("strong",null,s(c.name),1),c.description?(p(),h("div",De,s(c.description),1)):_("v-if",!0)],64)):n.key==="project_type"?(p(),x(z,{key:2},{default:a(()=>[r(s(c.project_type),1)]),_:2},1024)):n.key==="status"?(p(),x(z,{key:3,color:e.statusColor(c.status)},{default:a(()=>[r(s(c.status),1)]),_:2},1032,["color"])):n.key==="sync_status"?(p(),x(z,{key:4,color:e.syncColor(c.sync_status)},{default:a(()=>[r(s(c.sync_status||"unknown"),1)]),_:2},1032,["color"])):n.key==="updated_at"?(p(),h(ne,{key:5},[r(s(e.formatTime(c.updated_at)),1)],64)):n.key==="actions"?(p(),x(O,{key:6,onClick:l[2]||(l[2]=ge(()=>{},["stop"]))},{default:a(()=>[t(y,{size:"small",onClick:q=>e.openDetail(c)},{default:a(()=>[...l[26]||(l[26]=[r("详情",-1)])]),_:1},8,["onClick"]),t(M,{title:`删除项目 '${c.name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:q=>e.onDelete(c)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[27]||(l[27]=[r("删除",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)):_("v-if",!0)]),_:1},8,["data-source","loading"])):_("v-if",!0),_(" Detail drawer "),t(X,{open:e.detailOpen,"onUpdate:open":l[3]||(l[3]=n=>e.detailOpen=n),title:e.detail?.name||"项目详情",width:"640",placement:"right"},{default:a(()=>[e.detail?(p(),x(K,{key:0,column:1,bordered:"",size:"small"},{default:a(()=>[t(g,{label:"ID"},{default:a(()=>[A("code",null,s(e.detail.id),1)]),_:1}),t(g,{label:"名称"},{default:a(()=>[r(s(e.detail.name),1)]),_:1}),t(g,{label:"描述"},{default:a(()=>[r(s(e.detail.description||"-"),1)]),_:1}),t(g,{label:"类型"},{default:a(()=>[t(z,null,{default:a(()=>[r(s(e.detail.project_type),1)]),_:1})]),_:1}),t(g,{label:"状态"},{default:a(()=>[t(z,{color:e.statusColor(e.detail.status)},{default:a(()=>[r(s(e.detail.status),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"同步状态"},{default:a(()=>[t(z,{color:e.syncColor(e.detail.sync_status)},{default:a(()=>[r(s(e.detail.sync_status||"unknown"),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"用户"},{default:a(()=>[r(s(e.detail.user_id),1)]),_:1}),t(g,{label:"根路径"},{default:a(()=>[e.detail.root_path?(p(),h("code",Re,s(e.detail.root_path),1)):(p(),h("span",Te,"(无)"))]),_:1}),t(g,{label:"文件数"},{default:a(()=>[r(s(e.detail.file_count||0),1)]),_:1}),t(g,{label:"创建"},{default:a(()=>[r(s(e.formatTime(e.detail.created_at)),1)]),_:1}),t(g,{label:"更新"},{default:a(()=>[r(s(e.formatTime(e.detail.updated_at)),1)]),_:1})]),_:1})):_("v-if",!0),t(Q,null,{default:a(()=>[...l[28]||(l[28]=[r("文件",-1)])]),_:1}),_(" Sub-phase 7.3 (2026-05-17): 文件 CRUD toolbar "),t(O,{style:{"margin-bottom":"12px"}},{default:a(()=>[t(y,{size:"small",type:"primary",disabled:!e.detail,onClick:e.openCreateFile},{default:a(()=>[t(e.FileAddOutlined),l[29]||(l[29]=r(" 新建文件 ",-1))]),_:1},8,["disabled"]),t(y,{size:"small",disabled:!e.detail,onClick:e.openCreateFolder},{default:a(()=>[t(e.FolderAddOutlined),l[30]||(l[30]=r(" 新建文件夹 ",-1))]),_:1},8,["disabled"])]),_:1}),t(H,{spinning:e.filesLoading},{default:a(()=>[!e.files.length&&!e.filesLoading?(p(),x(C,{key:0,description:"无文件 (点上方按钮新建)"})):(p(),x(V,{key:1,size:"small","data-source":e.files},{renderItem:a(({item:n})=>[t(G,null,{extra:a(()=>[t(O,null,{default:a(()=>[n.file_size?(p(),h("span",Ee,s(n.file_size)+" B",1)):_("v-if",!0),t(M,{title:`删除 ${n.is_folder?"文件夹":"文件"} '${n.file_name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:c=>e.onDeleteFile(n)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[31]||(l[31]=[r("×",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)]),default:a(()=>[A("span",{style:{cursor:"pointer"},onClick:c=>e.openEditFile(n)},s(n.is_folder?"📁":"📄")+" "+s(n.file_path),9,Be)]),_:2},1024)]),_:1},8,["data-source"]))]),_:1},8,["spinning"])]),_:1},8,["open","title"]),_(" Sub-phase 7.3: Create file modal "),t(I,{open:e.createFileOpen,"onUpdate:open":l[6]||(l[6]=n=>e.createFileOpen=n),title:"新建文件","confirm-loading":e.creatingFile,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFile},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"文件路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFile.path,"onUpdate:value":l[4]||(l[4]=n=>e.newFile.path=n),placeholder:"例如 README.md 或 src/main.kt"},null,8,["value"])]),_:1}),t(b,{label:"初始内容(可选)"},{default:a(()=>[t(D,{value:e.newFile.content,"onUpdate:value":l[5]||(l[5]=n=>e.newFile.content=n),rows:6,placeholder:"留空创建空文件"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Create folder modal "),t(I,{open:e.createFolderOpen,"onUpdate:open":l[8]||(l[8]=n=>e.createFolderOpen=n),title:"新建文件夹","confirm-loading":e.creatingFolder,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFolder},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"文件夹路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFolder.path,"onUpdate:value":l[7]||(l[7]=n=>e.newFolder.path=n),placeholder:"例如 src/utils"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Edit file content modal "),t(I,{open:e.editFileOpen,"onUpdate:open":l[10]||(l[10]=n=>e.editFileOpen=n),title:`编辑 ${e.editingFile?.file_name||""}`,"confirm-loading":e.savingFile,"ok-text":"保存","cancel-text":"取消",onOk:e.onSaveFile,width:"720"},{default:a(()=>[t(D,{value:e.editFileContent,"onUpdate:value":l[9]||(l[9]=n=>e.editFileContent=n),rows:18,"auto-size":{minRows:12,maxRows:24},style:{"font-family":"monospace"}},null,8,["value"])]),_:1},8,["open","title","confirm-loading"]),_(" Create modal "),t(I,{open:e.createOpen,"onUpdate:open":l[15]||(l[15]=n=>e.createOpen=n),title:"新建项目","confirm-loading":e.creating,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreate},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(b,{label:"项目名称",required:""},{default:a(()=>[t(T,{value:e.newProject.name,"onUpdate:value":l[11]||(l[11]=n=>e.newProject.name=n),placeholder:"例如:旅行计划-上海"},null,8,["value"])]),_:1}),t(b,{label:"描述"},{default:a(()=>[t(D,{value:e.newProject.description,"onUpdate:value":l[12]||(l[12]=n=>e.newProject.description=n),rows:2},null,8,["value"])]),_:1}),t(b,{label:"类型"},{default:a(()=>[t(R,{value:e.newProject.type,"onUpdate:value":l[13]||(l[13]=n=>e.newProject.type=n)},{default:a(()=>[t(m,{value:"document"},{default:a(()=>[...l[32]||(l[32]=[r("文档 (document)",-1)])]),_:1}),t(m,{value:"data"},{default:a(()=>[...l[33]||(l[33]=[r("数据 (data)",-1)])]),_:1}),t(m,{value:"web"},{default:a(()=>[...l[34]||(l[34]=[r("Web",-1)])]),_:1}),t(m,{value:"app"},{default:a(()=>[...l[35]||(l[35]=[r("应用 (app)",-1)])]),_:1}),t(m,{value:"presentation"},{default:a(()=>[...l[36]||(l[36]=[r("演示文稿",-1)])]),_:1}),t(m,{value:"spreadsheet"},{default:a(()=>[...l[37]||(l[37]=[r("表格",-1)])]),_:1}),t(m,{value:"design"},{default:a(()=>[...l[38]||(l[38]=[r("设计",-1)])]),_:1}),t(m,{value:"code"},{default:a(()=>[...l[39]||(l[39]=[r("代码",-1)])]),_:1}),t(m,{value:"workflow"},{default:a(()=>[...l[40]||(l[40]=[r("工作流",-1)])]),_:1}),t(m,{value:"knowledge"},{default:a(()=>[...l[41]||(l[41]=[r("知识库",-1)])]),_:1})]),_:1},8,["value"])]),_:1}),t(b,{label:"根路径 (可选)"},{default:a(()=>[t(T,{value:e.newProject.rootPath,"onUpdate:value":l[14]||(l[14]=n=>e.newProject.rootPath=n),placeholder:"留空则仅元数据"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"])])}const We=we(Pe,[["render",Le],["__scopeId","data-v-019ac5aa"],["__file","/tmp/cc-web-panel-wTPIBh/repo/packages/web-panel/src/views/Projects.vue"]]);export{We as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{O as r}from"./index-CZpeHDG9.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as o}from"./Row-CcEPZJXB.js";import{U as t}from"./index-CZpeHDG9.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-Cow45GkA.js";import"./useFlexGapSupport-CNESbv-e.js";import"./styleChecker-B8HoJol7.js";import"./index-CnLh1mEV.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{C as o}from"./Col-BQEwtCpd.js";import{U as t}from"./index-CZpeHDG9.js";import"./vendor-BvqAck49.js";import"./index-CnLh1mEV.js";import"./icons-DP3uiYxy.js";const s=t(o);export{s as default};
|