chainlesschain 0.162.101 → 0.162.103
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 +1 -1
- package/package.json +2 -2
- package/scripts/postinstall.mjs +33 -3
- package/src/assets/web-panel/assets/{AIOps-NeD6mA1O.js → AIOps-BpJ5yCcV.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Bhp7A7vO.js → ActionButton-B1uBfxnA.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DgdI84Jy.js → Analytics-0ubw5quf.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-Qw29caa7.js → AppLayout-go-GyyM_.js} +4 -4
- package/src/assets/web-panel/assets/{Audit-DgkzhBjz.js → Audit-CdUfoUnM.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CiWEQoW5.js → Backup-CBn0xtsa.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BWNbkeDF.js → BaseInput-a9fqTkvL.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CUcj4Vyd.js → Chat-D-d_IatD.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-bAMNCgEj.js → ChatBubbleRenderer-Co9h0SbA.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B0uZTW8f.js → Checkbox-CiKEjtXm.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BPk7b-Xa.js → Codegen-OQxW_9Z2.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C2cV_dw4.js → Col-BZHXUEnZ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CDN6Yggb.js → Community-D3xno9fj.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-C4WPtW_V.js → Compact-D62jpZk_.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BGUfeH-3.js → Compliance-D4jFTAcQ.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CsnVgF-o.js → Cowork-BOU_wir4.js} +3 -3
- package/src/assets/web-panel/assets/{Cron--rGanASk.js → Cron-Cr9BlJA7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-D_CLrd-0.js → Crosschain-L9M--CXb.js} +1 -1
- package/src/assets/web-panel/assets/{DID-iYkbVc8W.js → DID-xFu3-VWT.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CuFMU98t.js → Dashboard--ax48T3j.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BPSjv_Ye.js → Dropdown-CTOS8daR.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DBmk7czO.js → EmailListRenderer-CNLSX81U.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BaCArN11.js → FamilyGuardDashboard-5EjFynBc.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DsTV-8Ca.js → Federation-CoPyIWIu.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C6fRr_6F.js → FormItemContext-BbzCNbYy.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-AfuZCfyv.js → GenericCardRenderer-8_9_uXY0.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CAFIrGhb.js → Git-Bz_qlVPg.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C-NaxDs4.js → Governance-7eepNCeD.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BPfeNZP7.js → Inference-DlBx5l1g.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DDUBte_m.js → KnowledgeGraph-BPkc--rM.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DWysA6JP.js → Logs-BQw4nPvS.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CAK68hXc.js → Marketplace-Cil3SdgN.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CNmmoDAk.js → McpTools-Bnch7KrG.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-D_KmFoui.js → Memory-assQ3Suc.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CaY-6kjj.js → MobileBridge-D5mE8c-z.js} +2 -2
- package/src/assets/web-panel/assets/MobileProjects-C4MiDXw1.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-YnLrtuXT.js → Mtc-CumojeLk.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-D38v836u.js → MtcAudit-3tTBc_fw.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-Dv3ad9S4.js → Multisig-Dl4IJBsl.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-MYTh2eWC.js → NLProgramming-DHN_cV9x.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DYO-0Hva.js → Notes-DeyTvwYk.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-D39gOb3h.js → NotificationSettings-BUkj8mTj.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CXdO0z3I.js → OrderTableRenderer-BMpEXTki.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DOYTwQwt.js → Organization-B6Ogmkpz.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Cm-go0yU.js → Overflow-DRUE-2Wz.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CakGtorw.js → P2P-CnMUkd64.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BlmbHJnb.js → PdhVaultBrowser-B3nFxT3b.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-C_podo04.js → Permissions-CyG1FR7v.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-nBbehIKp.js → PersonalDataHub-BmN6YMb5.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-CGzQUoKv.js → Pipeline-BZcamAnH.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BuD-Dd9m.js → Privacy-D7_zsaY3.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CLcFmGXU.js → ProjectInit-DNa7XQjg.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BxXTR0dH.js → ProjectSettings-KH2Dm09G.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DkpBjAfd.js → Projects-T-WqR3D6.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DwHK42ht.js → Providers-8GtQ6GgR.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-idJPKErk.js → QuickAsk-BuBM5Zpg.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BvJj0Nu2.js → Recommend-DvH95W1b.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-BK9l4Rcf.js → Reputation-BHCpMEP6.js} +1 -1
- package/src/assets/web-panel/assets/{Row-rLxg7xk5.js → Row-BnMPysBm.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Cw6ZcHBY.js → RssFeed-C-T8B5VU.js} +3 -3
- package/src/assets/web-panel/assets/{Search-D8mKp506.js → Search-CioiZGkX.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CXunojmQ.js → Security-zSApKqdd.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BE5DgmPl.js → Services-CQh0UDXC.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CssL5wmE.js → Skeleton-C0dRaEVG.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-zyS_1YrT.js → Skills-BgQRArsa.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DIVn2Roa.js → Sla-BNn7F3jc.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CjNdZWdj.js → SpeechSettings-kvVfKfqv.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BCbu5WQT.js → SyncSettings-BwIkkX1E.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BjFrgXge.js → Tasks-BkcvhBZw.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Cl4Y3lKN.js → Templates-COK0o2pL.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-k1T0F_eH.js → Tenant-DpK87fqo.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-i0tHF8fy.js → Terminal-2g2-XPT_.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-FmPaNyqK.js → TimelineRenderer-B4SJqyqf.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BUWEiyab.js → Tokens-C3iSR8fH.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-9srMXwpo.js → Trigger-D1Oo58Yo.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-hmGor_R2.js → Trust-CUhy4DDc.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Dst7K10a.js → UkeySign-r-kTqSw8.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-D_utUv1u.js → VideoEditing-B8MyBfCX.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BpYTTseI.js → Wallet-CquTfSv0.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CEIw8QrF.js → WebAuthn-BC7TP1H3.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Bkb4bUZ_.js → WorkflowEditor-CELBSNbP.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CTqDgGRH.js → chat-d66mbO2i.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CnJHVFLk.js → colors-D0WRCg20.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-D4-v0ahl.js → compact-item-4__-8TIi.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CYDbnHZX.js → createContext-Dqsf52js.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DUAmX0aE.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CbYwlEz5.js → hasIn-ClTZOS8I.js} +1 -1
- package/src/assets/web-panel/assets/{index-DVKfa-z4.js → index-0Axwx1nN.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cl7-mbsb.js → index-81SaeU6t.js} +1 -1
- package/src/assets/web-panel/assets/{index-CK8nROWH.js → index-B1TGSkBt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BygyTsjr.js → index-B3vrmn5v.js} +1 -1
- package/src/assets/web-panel/assets/{index-B78d_-pR.js → index-BCOpbfAH.js} +1 -1
- package/src/assets/web-panel/assets/index-BLCwqv8j.js +1 -0
- package/src/assets/web-panel/assets/{index-YuO8gxKb.js → index-BNKECBZm.js} +1 -1
- package/src/assets/web-panel/assets/{index-tmNsJzQU.js → index-BwozLU75.js} +1 -1
- package/src/assets/web-panel/assets/{index-dKpwhR5x.js → index-C4_XhCJS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNz3yht2.js → index-C5l6tSky.js} +1 -1
- package/src/assets/web-panel/assets/{index-4767GEls.js → index-CFwkeSun.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCQ4kcL3.js → index-CGf3oqM0.js} +1 -1
- package/src/assets/web-panel/assets/{index-xDe5BkjU.js → index-CJKyF-y8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjFQuno4.js → index-Cg8Qw3Jw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dl_NdY39.js → index-Cops66s2.js} +3 -3
- package/src/assets/web-panel/assets/{index-D8MYVsVB.js → index-Ct5SJenr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CY971z_9.js → index-CxoWS8hl.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVc_5aBF.js → index-D-ya3Ohe.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4chfOjw.js → index-D68tyHYa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BR4facv0.js → index-D9x6i7iV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CxKdSB-p.js → index-DDLjwgva.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-hiXmVK.js → index-DORg0Hps.js} +1 -1
- package/src/assets/web-panel/assets/{index-BR0FfrCL.js → index-DQaGurrQ.js} +1 -1
- package/src/assets/web-panel/assets/index-Db5JRQ6E.js +1 -0
- package/src/assets/web-panel/assets/{index-5NXdAIZK.js → index-DbY1lv1z.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOUSaCsn.js → index-Dm7CYK3j.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxvFrsxl.js → index-DpLhC0nx.js} +1 -1
- package/src/assets/web-panel/assets/{index-qNwkSspX.js → index-P4X9zSF2.js} +1 -1
- package/src/assets/web-panel/assets/{index-OqmUv5QO.js → index-PAiWA2un.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8uhiRML.js → index-PMJ4tBAA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfshMjFN.js → index-Yi5Lr63I.js} +1 -1
- package/src/assets/web-panel/assets/{index-wxz2s6uW.js → index-ZZpfHd4J.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdRtpQFq.js → index-b7a5aEX9.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2fICr5d.js → index-e5zJLrJQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGUOVPjO.js → index-fi2ikHoc.js} +1 -1
- package/src/assets/web-panel/assets/{index-8cmtr1jC.js → index-jAPphbJL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMKNVIqJ.js → index-leuwRsbf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CP-UKwu8.js → index-luisYDBz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaCCLe7i.js → index-we9-1IbF.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-qCQgpAty.js → initDefaultProps-zqDf7qWv.js} +1 -1
- package/src/assets/web-panel/assets/{motion-SkVSGdwu.js → motion-DRqTooll.js} +1 -1
- package/src/assets/web-panel/assets/{move-BpWxaW_x.js → move-N8tkRqS4.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DlZWM2H4.js → omit-Cy01f2vw.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DobtUnVe.js → pickAttrs-C2ycNXNi.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CD6mYRZi.js → placementArrow-D60Xb1j9.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DvIIMTD_.js → responsiveObserve-BF8Y-1HQ.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CVgyUfaA.js → slide-DDi6zYZf.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DrUDnjy_.js → statusUtils-CWPq6UzA.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BNYQS60m.js → styleChecker-D4zVyb4w.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DYv7Tvk0.js → useFlexGapSupport-BEMNO3oR.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DmAD2atJ.js → useFs-DBLO8VR7.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DbLVKA3I.js → usePersonalDataHub-C83ZIrPY.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C3WEt6_P.js → vnode-Dcfyve-7.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CRoSX_oZ.js → zoom-Dg6uoWSc.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/hub-health.test.js +105 -0
- package/src/commands/__tests__/hub-stats.test.js +106 -0
- package/src/commands/a2a.js +2 -1
- package/src/commands/bi.js +4 -3
- package/src/commands/browse.js +3 -2
- package/src/commands/codegen.js +7 -6
- package/src/commands/collab.js +2 -1
- package/src/commands/crosschain.js +5 -4
- package/src/commands/dao.js +10 -10
- package/src/commands/dbevo.js +3 -2
- package/src/commands/economy.js +8 -6
- package/src/commands/evolution.js +10 -8
- package/src/commands/export.js +2 -1
- package/src/commands/federation.js +8 -7
- package/src/commands/fusion.js +4 -3
- package/src/commands/git.js +2 -1
- package/src/commands/governance.js +6 -5
- package/src/commands/hardening.js +3 -2
- package/src/commands/hmemory.js +2 -1
- package/src/commands/hub.js +111 -32
- package/src/commands/inference.js +9 -8
- package/src/commands/infra.js +9 -8
- package/src/commands/instinct.js +66 -0
- package/src/commands/learning.js +66 -0
- package/src/commands/marketplace.js +5 -4
- package/src/commands/matrix.js +2 -1
- package/src/commands/memory.js +66 -0
- package/src/commands/nlprog.js +4 -3
- package/src/commands/nostr.js +4 -3
- package/src/commands/note.js +2 -1
- package/src/commands/ops.js +3 -2
- package/src/commands/perception.js +6 -5
- package/src/commands/privacy.js +13 -12
- package/src/commands/quantization.js +3 -2
- package/src/commands/recommend.js +8 -7
- package/src/commands/reputation.js +4 -3
- package/src/commands/runtime.js +6 -5
- package/src/commands/sandbox.js +5 -4
- package/src/commands/session.js +2 -1
- package/src/commands/sla.js +6 -5
- package/src/commands/social.js +6 -5
- package/src/commands/stress.js +7 -6
- package/src/commands/sync.js +2 -1
- package/src/commands/tenant.js +3 -2
- package/src/commands/trust.js +7 -6
- package/src/commands/wallet.js +2 -1
- package/src/gateways/ws/personal-data-hub-protocol.js +16 -3
- package/src/lib/__tests__/agents.test.js +225 -0
- package/src/lib/__tests__/cowork-observe-html.test.js +141 -0
- package/src/lib/__tests__/logger.test.js +110 -0
- package/src/lib/__tests__/project-inventory.test.js +280 -0
- package/src/lib/__tests__/project-root.test.js +96 -0
- package/src/lib/__tests__/provider-stream.test.js +190 -0
- package/src/lib/cli-arg.js +41 -0
- package/src/lib/cli-numeric.js +12 -3
- package/src/lib/instinct-manager.js +64 -0
- package/src/lib/learning/learning-tables.js +83 -0
- package/src/lib/mcp-oauth.js +10 -2
- package/src/lib/memory-manager.js +67 -0
- package/src/lib/personal-data-hub-wiring.js +135 -7
- package/src/lib/plan-mode.js +3 -2
- package/src/repl/__tests__/mcp-prompt.test.js +155 -0
- package/src/repl/__tests__/slash-macro.test.js +81 -0
- package/src/runtime/__tests__/coding-agent-contract-shared.test.js +136 -0
- package/src/runtime/__tests__/coding-agent-events.test.js +263 -0
- package/src/assets/web-panel/assets/MobileProjects-DhDxrWze.js +0 -1
- package/src/assets/web-panel/assets/devWarning-OhxeajH6.js +0 -1
- package/src/assets/web-panel/assets/index-Bbtoi_47.js +0 -1
- package/src/assets/web-panel/assets/index-Cb8RWwaB.js +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cli-arg — validating commander option coercers.
|
|
3
|
+
*
|
|
4
|
+
* Bare `parseInt` / `parseFloat` / `Number` used as a commander coercer
|
|
5
|
+
* (`.option("--limit <n>", "...", parseInt)`) silently yield NaN on bad input
|
|
6
|
+
* (`--limit abc`), threading NaN into whatever the action does with the option.
|
|
7
|
+
* These factories validate at parse time and raise a commander
|
|
8
|
+
* `InvalidArgumentError`, so a typo fails with the standard
|
|
9
|
+
* `error: option '--limit <n>' argument 'abc' is invalid` message and exit 1 —
|
|
10
|
+
* instead of a silently-corrupt run.
|
|
11
|
+
*
|
|
12
|
+
* Drop-in replacements:
|
|
13
|
+
* .option("--limit <n>", "...", parseInt) -> intArg("--limit")
|
|
14
|
+
* .option("--rate <n>", "...", parseFloat) -> floatArg("--rate")
|
|
15
|
+
* .option("--eps <n>", "...", Number) -> floatArg("--eps")
|
|
16
|
+
*
|
|
17
|
+
* Behaviour for valid and omitted values is identical to the bare coercer
|
|
18
|
+
* (the coercer only runs when the option is supplied with a value); only the
|
|
19
|
+
* NaN-on-bad-input case changes.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} name option label for the message (e.g. "--limit")
|
|
22
|
+
* @param {{min?: number, max?: number}} [opts]
|
|
23
|
+
*/
|
|
24
|
+
import { InvalidArgumentError } from "commander";
|
|
25
|
+
import { numericOption } from "./cli-numeric.js";
|
|
26
|
+
|
|
27
|
+
function makeArg(integer) {
|
|
28
|
+
return (name, opts = {}) =>
|
|
29
|
+
(raw) => {
|
|
30
|
+
try {
|
|
31
|
+
return numericOption(raw, { ...opts, name, integer });
|
|
32
|
+
} catch (err) {
|
|
33
|
+
throw new InvalidArgumentError(err.message);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const intArg = makeArg(true);
|
|
39
|
+
export const floatArg = makeArg(false);
|
|
40
|
+
|
|
41
|
+
export default { intArg, floatArg };
|
package/src/lib/cli-numeric.js
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* @param {*} raw the option value (string from commander, or undefined)
|
|
11
11
|
* @param {object} [opts]
|
|
12
12
|
* @param {string} [opts.name="value"] label for error messages (e.g. "--limit")
|
|
13
|
-
* @param {boolean} [opts.integer=false]
|
|
13
|
+
* @param {boolean} [opts.integer=false] require a whole number (rejects 1.5);
|
|
14
|
+
* parsing is strict either way (Number,
|
|
15
|
+
* not parseInt — "12abc" is rejected)
|
|
14
16
|
* @param {number} [opts.min] inclusive lower bound
|
|
15
17
|
* @param {number} [opts.max] inclusive upper bound
|
|
16
18
|
* @param {number} [opts.fallback] returned for missing/invalid input; when
|
|
@@ -26,8 +28,15 @@ export function numericOption(raw, opts = {}) {
|
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
if (raw == null || raw === "") return fail(`${name} is required`);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
if (typeof raw === "string" && raw.trim() === "")
|
|
32
|
+
return fail(`${name} is required`);
|
|
33
|
+
// Number() (NOT parseInt) so trailing junk is rejected instead of silently
|
|
34
|
+
// truncated: parseInt("12abc") === 12 and parseInt("0x10", 10) === 0 would
|
|
35
|
+
// slip a corrupt value through. Number("12abc") is NaN; whole numbers given
|
|
36
|
+
// via exponent ("1e3" -> 1000) still parse, and a fractional value is
|
|
37
|
+
// rejected in integer mode.
|
|
38
|
+
const n = Number(raw);
|
|
39
|
+
if (!Number.isFinite(n) || (integer && !Number.isInteger(n))) {
|
|
31
40
|
return fail(
|
|
32
41
|
`${name} must be a ${integer ? "whole " : ""}number (got ${JSON.stringify(String(raw))})`,
|
|
33
42
|
);
|
|
@@ -20,6 +20,70 @@ export function ensureInstinctsTable(db) {
|
|
|
20
20
|
`);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/** datetime('now')-style timestamp for rows missing one on import. */
|
|
24
|
+
function _instinctNowSqlite() {
|
|
25
|
+
return new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Export ALL instincts (full dump) for §8.3 cross-device backup. Deterministic
|
|
30
|
+
* order so the same DB exports identically.
|
|
31
|
+
*/
|
|
32
|
+
export function exportInstincts(db) {
|
|
33
|
+
ensureInstinctsTable(db);
|
|
34
|
+
return db
|
|
35
|
+
.prepare(
|
|
36
|
+
`SELECT id, category, pattern, confidence, occurrences, last_seen, created_at
|
|
37
|
+
FROM instincts ORDER BY created_at ASC, id ASC`,
|
|
38
|
+
)
|
|
39
|
+
.all();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Import instincts (§8.3 restore): idempotent upsert by id — preserves created_at,
|
|
44
|
+
* updates category/pattern/confidence/occurrences/last_seen. Never aborts mid-batch.
|
|
45
|
+
*/
|
|
46
|
+
export function importInstincts(db, rows) {
|
|
47
|
+
ensureInstinctsTable(db);
|
|
48
|
+
if (!Array.isArray(rows)) {
|
|
49
|
+
throw new Error("importInstincts: rows must be a JSON array");
|
|
50
|
+
}
|
|
51
|
+
const stmt = db.prepare(
|
|
52
|
+
`INSERT INTO instincts (id, category, pattern, confidence, occurrences, last_seen, created_at)
|
|
53
|
+
VALUES (@id, @category, @pattern, @confidence, @occurrences, @last_seen, @created_at)
|
|
54
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
55
|
+
category = excluded.category,
|
|
56
|
+
pattern = excluded.pattern,
|
|
57
|
+
confidence = excluded.confidence,
|
|
58
|
+
occurrences = excluded.occurrences,
|
|
59
|
+
last_seen = excluded.last_seen`,
|
|
60
|
+
);
|
|
61
|
+
let imported = 0;
|
|
62
|
+
let failed = 0;
|
|
63
|
+
const errors = [];
|
|
64
|
+
for (const r of rows) {
|
|
65
|
+
try {
|
|
66
|
+
if (!r || !r.id || !r.category || !r.pattern) {
|
|
67
|
+
throw new Error("invalid instinct (need id + category + pattern)");
|
|
68
|
+
}
|
|
69
|
+
stmt.run({
|
|
70
|
+
id: String(r.id),
|
|
71
|
+
category: r.category,
|
|
72
|
+
pattern: r.pattern,
|
|
73
|
+
confidence: typeof r.confidence === "number" ? r.confidence : 0.5,
|
|
74
|
+
occurrences: Number.isInteger(r.occurrences) ? r.occurrences : 1,
|
|
75
|
+
last_seen: r.last_seen || _instinctNowSqlite(),
|
|
76
|
+
created_at: r.created_at || _instinctNowSqlite(),
|
|
77
|
+
});
|
|
78
|
+
imported += 1;
|
|
79
|
+
} catch (e) {
|
|
80
|
+
failed += 1;
|
|
81
|
+
if (errors.length < 10) errors.push({ id: r && r.id, error: e.message });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return { ok: failed === 0, imported, failed, errors };
|
|
85
|
+
}
|
|
86
|
+
|
|
23
87
|
function generateId() {
|
|
24
88
|
const hex = () =>
|
|
25
89
|
Math.floor(Math.random() * 0x10000)
|
|
@@ -64,3 +64,86 @@ export function ensureLearningTables(db) {
|
|
|
64
64
|
)
|
|
65
65
|
`);
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
/** datetime('now')-style timestamp for rows missing one on import. */
|
|
69
|
+
function _learningNowSqlite() {
|
|
70
|
+
return new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Export ALL learning trajectories (full dump) for §8.3 cross-device backup.
|
|
75
|
+
* Includes the synthesized_skill linkage (synthesized skills travel with the
|
|
76
|
+
* trajectories that produced them). The learning_trajectory_tags side-table is
|
|
77
|
+
* derived and intentionally not exported in v1.
|
|
78
|
+
*/
|
|
79
|
+
export function exportTrajectories(db) {
|
|
80
|
+
ensureLearningTables(db);
|
|
81
|
+
return db
|
|
82
|
+
.prepare(
|
|
83
|
+
`SELECT id, session_id, user_intent, tool_chain, tool_count, final_response,
|
|
84
|
+
outcome_score, outcome_source, complexity_level, synthesized_skill,
|
|
85
|
+
created_at, completed_at
|
|
86
|
+
FROM learning_trajectories ORDER BY created_at ASC, id ASC`,
|
|
87
|
+
)
|
|
88
|
+
.all();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Import learning trajectories (§8.3 restore): idempotent upsert by id —
|
|
93
|
+
* preserves created_at, updates the rest. Never aborts mid-batch.
|
|
94
|
+
*/
|
|
95
|
+
export function importTrajectories(db, rows) {
|
|
96
|
+
ensureLearningTables(db);
|
|
97
|
+
if (!Array.isArray(rows)) {
|
|
98
|
+
throw new Error("importTrajectories: rows must be a JSON array");
|
|
99
|
+
}
|
|
100
|
+
const stmt = db.prepare(
|
|
101
|
+
`INSERT INTO learning_trajectories
|
|
102
|
+
(id, session_id, user_intent, tool_chain, tool_count, final_response,
|
|
103
|
+
outcome_score, outcome_source, complexity_level, synthesized_skill,
|
|
104
|
+
created_at, completed_at)
|
|
105
|
+
VALUES (@id, @session_id, @user_intent, @tool_chain, @tool_count, @final_response,
|
|
106
|
+
@outcome_score, @outcome_source, @complexity_level, @synthesized_skill,
|
|
107
|
+
@created_at, @completed_at)
|
|
108
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
109
|
+
session_id = excluded.session_id,
|
|
110
|
+
user_intent = excluded.user_intent,
|
|
111
|
+
tool_chain = excluded.tool_chain,
|
|
112
|
+
tool_count = excluded.tool_count,
|
|
113
|
+
final_response = excluded.final_response,
|
|
114
|
+
outcome_score = excluded.outcome_score,
|
|
115
|
+
outcome_source = excluded.outcome_source,
|
|
116
|
+
complexity_level = excluded.complexity_level,
|
|
117
|
+
synthesized_skill = excluded.synthesized_skill,
|
|
118
|
+
completed_at = excluded.completed_at`,
|
|
119
|
+
);
|
|
120
|
+
let imported = 0;
|
|
121
|
+
let failed = 0;
|
|
122
|
+
const errors = [];
|
|
123
|
+
for (const r of rows) {
|
|
124
|
+
try {
|
|
125
|
+
if (!r || !r.id || !r.session_id) {
|
|
126
|
+
throw new Error("invalid trajectory (need id + session_id)");
|
|
127
|
+
}
|
|
128
|
+
stmt.run({
|
|
129
|
+
id: String(r.id),
|
|
130
|
+
session_id: String(r.session_id),
|
|
131
|
+
user_intent: r.user_intent ?? null,
|
|
132
|
+
tool_chain: r.tool_chain ?? "[]",
|
|
133
|
+
tool_count: Number.isInteger(r.tool_count) ? r.tool_count : 0,
|
|
134
|
+
final_response: r.final_response ?? null,
|
|
135
|
+
outcome_score: typeof r.outcome_score === "number" ? r.outcome_score : null,
|
|
136
|
+
outcome_source: r.outcome_source ?? null,
|
|
137
|
+
complexity_level: r.complexity_level ?? "simple",
|
|
138
|
+
synthesized_skill: r.synthesized_skill ?? null,
|
|
139
|
+
created_at: r.created_at || _learningNowSqlite(),
|
|
140
|
+
completed_at: r.completed_at ?? null,
|
|
141
|
+
});
|
|
142
|
+
imported += 1;
|
|
143
|
+
} catch (e) {
|
|
144
|
+
failed += 1;
|
|
145
|
+
if (errors.length < 10) errors.push({ id: r && r.id, error: e.message });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return { ok: failed === 0, imported, failed, errors };
|
|
149
|
+
}
|
package/src/lib/mcp-oauth.js
CHANGED
|
@@ -410,7 +410,7 @@ function defaultOpenBrowser(url) {
|
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
/** Wait for the OAuth redirect on a localhost callback server; resolve {code,state}. */
|
|
413
|
-
function waitForCallback({
|
|
413
|
+
export function waitForCallback({
|
|
414
414
|
port,
|
|
415
415
|
host = "127.0.0.1",
|
|
416
416
|
path = "/callback",
|
|
@@ -446,7 +446,15 @@ function waitForCallback({
|
|
|
446
446
|
server.close();
|
|
447
447
|
reject(new Error("timed out waiting for the OAuth callback"));
|
|
448
448
|
}, timeout);
|
|
449
|
-
|
|
449
|
+
// Backstop timer should never keep the process alive on its own (the
|
|
450
|
+
// listening server does that); the loop exits promptly once it closes.
|
|
451
|
+
timer.unref?.();
|
|
452
|
+
server.on("error", (err) => {
|
|
453
|
+
// Without clearing the timer here, a bind failure (e.g. port in use)
|
|
454
|
+
// left it pending for the full `timeout`, delaying process exit.
|
|
455
|
+
clearTimeout(timer);
|
|
456
|
+
reject(err);
|
|
457
|
+
});
|
|
450
458
|
server.listen(port, host);
|
|
451
459
|
});
|
|
452
460
|
}
|
|
@@ -133,6 +133,73 @@ export function listMemory(db, options = {}) {
|
|
|
133
133
|
.all(limit);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Export ALL memory entries (full dump, no limit) for §8.3 cross-device backup.
|
|
138
|
+
* Returns rows with id/content/category/importance/source/created_at/updated_at,
|
|
139
|
+
* ordered deterministically so the same DB exports identically.
|
|
140
|
+
*/
|
|
141
|
+
export function exportMemory(db) {
|
|
142
|
+
ensureMemoryTable(db);
|
|
143
|
+
return db
|
|
144
|
+
.prepare(
|
|
145
|
+
`SELECT id, content, category, importance, source, created_at, updated_at
|
|
146
|
+
FROM memory_entries ORDER BY created_at ASC, id ASC`,
|
|
147
|
+
)
|
|
148
|
+
.all();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** datetime('now')-style timestamp for entries missing one on import. */
|
|
152
|
+
function _nowSqlite() {
|
|
153
|
+
return new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Import memory entries (§8.3 backup restore): idempotent upsert by id —
|
|
158
|
+
* preserves the original created_at, updates content/category/importance/source/
|
|
159
|
+
* updated_at. Never aborts mid-batch; returns {ok, imported, failed, errors}.
|
|
160
|
+
*/
|
|
161
|
+
export function importMemory(db, entries) {
|
|
162
|
+
ensureMemoryTable(db);
|
|
163
|
+
if (!Array.isArray(entries)) {
|
|
164
|
+
throw new Error("importMemory: entries must be a JSON array");
|
|
165
|
+
}
|
|
166
|
+
const stmt = db.prepare(
|
|
167
|
+
`INSERT INTO memory_entries
|
|
168
|
+
(id, content, category, importance, source, created_at, updated_at)
|
|
169
|
+
VALUES (@id, @content, @category, @importance, @source, @created_at, @updated_at)
|
|
170
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
171
|
+
content = excluded.content,
|
|
172
|
+
category = excluded.category,
|
|
173
|
+
importance = excluded.importance,
|
|
174
|
+
source = excluded.source,
|
|
175
|
+
updated_at = excluded.updated_at`,
|
|
176
|
+
);
|
|
177
|
+
let imported = 0;
|
|
178
|
+
let failed = 0;
|
|
179
|
+
const errors = [];
|
|
180
|
+
for (const e of entries) {
|
|
181
|
+
try {
|
|
182
|
+
if (!e || !e.id || typeof e.content !== "string") {
|
|
183
|
+
throw new Error("invalid memory entry (need id + content)");
|
|
184
|
+
}
|
|
185
|
+
stmt.run({
|
|
186
|
+
id: String(e.id),
|
|
187
|
+
content: e.content,
|
|
188
|
+
category: e.category || "general",
|
|
189
|
+
importance: Number.isInteger(e.importance) ? e.importance : 3,
|
|
190
|
+
source: e.source || "user",
|
|
191
|
+
created_at: e.created_at || _nowSqlite(),
|
|
192
|
+
updated_at: e.updated_at || _nowSqlite(),
|
|
193
|
+
});
|
|
194
|
+
imported += 1;
|
|
195
|
+
} catch (err) {
|
|
196
|
+
failed += 1;
|
|
197
|
+
if (errors.length < 10) errors.push({ id: e && e.id, error: err.message });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return { ok: failed === 0, imported, failed, errors };
|
|
201
|
+
}
|
|
202
|
+
|
|
136
203
|
/**
|
|
137
204
|
* Delete a memory entry
|
|
138
205
|
*/
|
|
@@ -29,11 +29,20 @@ import { mkdirSync } from "node:fs";
|
|
|
29
29
|
// Hub package is CJS; in ESM we default-import then destructure (Node 22
|
|
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
|
-
import
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
// PDH is loaded LAZILY (not a top-level static import) so that merely
|
|
33
|
+
// importing this wiring module — which happens on EVERY `cc` invocation,
|
|
34
|
+
// because index.js statically pulls in commands/hub.js (getHub) AND the
|
|
35
|
+
// agent/chat/serve/ui runtime chain (ws pdh-protocol → this wiring) — does
|
|
36
|
+
// NOT eagerly evaluate the entire personal-data-hub adapter graph. Wins:
|
|
37
|
+
// • Robustness: a partial/corrupt pdh install (e.g. an interrupted
|
|
38
|
+
// `npm i -g` that left adapter files unwritten) no longer bricks
|
|
39
|
+
// unrelated commands like `cc -v` with a cryptic ERR_MODULE_NOT_FOUND.
|
|
40
|
+
// pdh only loads when a `cc hub …` / web-shell hub topic actually runs.
|
|
41
|
+
// • Startup cost: non-hub commands skip loading 50+ adapter modules.
|
|
42
|
+
// The bindings below are populated by ensurePdhLoaded(), which initHub() and
|
|
43
|
+
// initHubMinimal() await before touching any of them.
|
|
44
|
+
let bootstrapWechatAdapter, probeWeChatEnv;
|
|
45
|
+
let LocalVault,
|
|
37
46
|
AdapterRegistry,
|
|
38
47
|
AnalysisEngine,
|
|
39
48
|
MockAdapter,
|
|
@@ -124,8 +133,125 @@ const {
|
|
|
124
133
|
EntityResolverEmbeddingStage,
|
|
125
134
|
EntityResolverLLMStage,
|
|
126
135
|
runAnalysisSkill,
|
|
127
|
-
ANALYSIS_SKILL_NAMES
|
|
128
|
-
|
|
136
|
+
ANALYSIS_SKILL_NAMES;
|
|
137
|
+
|
|
138
|
+
let _pdhLoadPromise = null;
|
|
139
|
+
/**
|
|
140
|
+
* Lazily import the personal-data-hub package + wechat adapter and populate
|
|
141
|
+
* the module-level binding holders above. Memoized so concurrent
|
|
142
|
+
* getHub()/getHubMinimal() callers share one load. Must be awaited by any
|
|
143
|
+
* code path that uses a pdh binding (initHub / initHubMinimal).
|
|
144
|
+
*/
|
|
145
|
+
function ensurePdhLoaded() {
|
|
146
|
+
if (!_pdhLoadPromise) {
|
|
147
|
+
_pdhLoadPromise = (async () => {
|
|
148
|
+
const hubMod = await import("@chainlesschain/personal-data-hub");
|
|
149
|
+
const hub = hubMod.default || hubMod;
|
|
150
|
+
// Composed specifier dodges vite/vitest static import-analysis of
|
|
151
|
+
// subpath exports (same trick as loadAIChatHealthChecker below).
|
|
152
|
+
const wechatSpec =
|
|
153
|
+
"@chainlesschain/personal-data-hub" + "/adapters/wechat";
|
|
154
|
+
const waMod = await import(wechatSpec);
|
|
155
|
+
const wechatAdapterModule = waMod.default || waMod;
|
|
156
|
+
({ bootstrapWechatAdapter, probeWeChatEnv } = wechatAdapterModule);
|
|
157
|
+
({
|
|
158
|
+
LocalVault,
|
|
159
|
+
AdapterRegistry,
|
|
160
|
+
AnalysisEngine,
|
|
161
|
+
MockAdapter,
|
|
162
|
+
OllamaClient,
|
|
163
|
+
CcKgSink,
|
|
164
|
+
CcRagSink,
|
|
165
|
+
FileKeyProvider,
|
|
166
|
+
generateKeyHex,
|
|
167
|
+
EmailAdapter,
|
|
168
|
+
AlipayBillAdapter,
|
|
169
|
+
SystemDataAndroidAdapter,
|
|
170
|
+
BrowserHistoryChromeAdapter,
|
|
171
|
+
BrowserHistoryEdgeAdapter,
|
|
172
|
+
VSCodeAdapter,
|
|
173
|
+
WinRecentAdapter,
|
|
174
|
+
GitActivityAdapter,
|
|
175
|
+
ShellHistoryAdapter,
|
|
176
|
+
LocalFilesAdapter,
|
|
177
|
+
BilibiliAdapter,
|
|
178
|
+
WeiboAdapter,
|
|
179
|
+
ZhihuAdapter,
|
|
180
|
+
DoubanAdapter,
|
|
181
|
+
BossZhipinAdapter,
|
|
182
|
+
CsdnAdapter,
|
|
183
|
+
DongchediAdapter,
|
|
184
|
+
TianyanchaAdapter,
|
|
185
|
+
DouyinAdapter,
|
|
186
|
+
XiaohongshuAdapter,
|
|
187
|
+
ToutiaoAdapter,
|
|
188
|
+
KuaishouAdapter,
|
|
189
|
+
GenshinAdapter,
|
|
190
|
+
HonorOfKingsAdapter,
|
|
191
|
+
ZuoyebangAdapter,
|
|
192
|
+
AlipayAdapter,
|
|
193
|
+
HuaweiLearningAdapter,
|
|
194
|
+
QQAdapter,
|
|
195
|
+
WeChatPcAdapter,
|
|
196
|
+
QQPcAdapter,
|
|
197
|
+
AppleHealthAdapter,
|
|
198
|
+
NeteaseMusicAdapter,
|
|
199
|
+
KugouMusicAdapter,
|
|
200
|
+
QQMusicAdapter,
|
|
201
|
+
XimalayaAdapter,
|
|
202
|
+
FanqieReadingAdapter,
|
|
203
|
+
QimaoReadingAdapter,
|
|
204
|
+
JoyrunAdapter,
|
|
205
|
+
KeepAdapter,
|
|
206
|
+
DidiConsumerAdapter,
|
|
207
|
+
MercedesMeAdapter,
|
|
208
|
+
IqiyiVideoAdapter,
|
|
209
|
+
TencentVideoAdapter,
|
|
210
|
+
XiguaVideoAdapter,
|
|
211
|
+
WeReadAdapter,
|
|
212
|
+
WpsDocAdapter,
|
|
213
|
+
TencentDocsAdapter,
|
|
214
|
+
BaiduNetdiskAdapter,
|
|
215
|
+
CamScannerDocAdapter,
|
|
216
|
+
IXiamenAdapter,
|
|
217
|
+
MeiyouAdapter,
|
|
218
|
+
TaxAdapter,
|
|
219
|
+
CmbcBankAdapter,
|
|
220
|
+
BocBankAdapter,
|
|
221
|
+
BankcommBankAdapter,
|
|
222
|
+
IcbcBankAdapter,
|
|
223
|
+
DcepAdapter,
|
|
224
|
+
Tmri12123Adapter,
|
|
225
|
+
DingTalkPcAdapter,
|
|
226
|
+
FeishuPcAdapter,
|
|
227
|
+
WeWorkPcAdapter,
|
|
228
|
+
BaiduMapAdapter,
|
|
229
|
+
TencentMapAdapter,
|
|
230
|
+
JdAdapter,
|
|
231
|
+
MeituanAdapter,
|
|
232
|
+
ElemeAdapter,
|
|
233
|
+
PinduoduoAdapter,
|
|
234
|
+
DianpingAdapter,
|
|
235
|
+
XianyuAdapter,
|
|
236
|
+
VipshopAdapter,
|
|
237
|
+
Train12306Adapter,
|
|
238
|
+
TaobaoAdapter,
|
|
239
|
+
CtripAdapter,
|
|
240
|
+
TongchengAdapter,
|
|
241
|
+
DidiAdapter,
|
|
242
|
+
AmapAdapter,
|
|
243
|
+
TelegramAdapter,
|
|
244
|
+
WhatsAppAdapter,
|
|
245
|
+
EntityResolver,
|
|
246
|
+
EntityResolverEmbeddingStage,
|
|
247
|
+
EntityResolverLLMStage,
|
|
248
|
+
runAnalysisSkill,
|
|
249
|
+
ANALYSIS_SKILL_NAMES,
|
|
250
|
+
} = hub);
|
|
251
|
+
})();
|
|
252
|
+
}
|
|
253
|
+
return _pdhLoadPromise;
|
|
254
|
+
}
|
|
129
255
|
import {
|
|
130
256
|
readFileSync,
|
|
131
257
|
writeFileSync,
|
|
@@ -209,6 +335,7 @@ export function resolveHubDir() {
|
|
|
209
335
|
}
|
|
210
336
|
|
|
211
337
|
async function initHub() {
|
|
338
|
+
await ensurePdhLoaded();
|
|
212
339
|
// Phase 1c: hoisted so the hub-level `bilibiliAdbSync` method can reuse
|
|
213
340
|
// the same bridge instance the system-data-android adapter wires below.
|
|
214
341
|
// Single bridge per hub keeps `bilibili.cookies` extension state /
|
|
@@ -1490,6 +1617,7 @@ let _hubMinimal = null;
|
|
|
1490
1617
|
let _hubMinimalInitPromise = null;
|
|
1491
1618
|
|
|
1492
1619
|
async function initHubMinimal() {
|
|
1620
|
+
await ensurePdhLoaded();
|
|
1493
1621
|
const hubDir = resolveHubDir();
|
|
1494
1622
|
mkdirSync(hubDir, { recursive: true });
|
|
1495
1623
|
mkdirSync(join(hubDir, "keys"), { recursive: true });
|
package/src/lib/plan-mode.js
CHANGED
|
@@ -31,6 +31,7 @@ export const PlanState = {
|
|
|
31
31
|
APPROVED: "approved",
|
|
32
32
|
EXECUTING: "executing",
|
|
33
33
|
COMPLETED: "completed",
|
|
34
|
+
FAILED: "failed",
|
|
34
35
|
REJECTED: "rejected",
|
|
35
36
|
};
|
|
36
37
|
|
|
@@ -499,10 +500,10 @@ export class PlanModeManager extends EventEmitter {
|
|
|
499
500
|
});
|
|
500
501
|
|
|
501
502
|
const allDone = results.every((r) => r.success);
|
|
502
|
-
this.state = allDone ? PlanState.COMPLETED : PlanState.
|
|
503
|
+
this.state = allDone ? PlanState.COMPLETED : PlanState.FAILED;
|
|
503
504
|
this.currentPlan.status = allDone
|
|
504
505
|
? PlanState.COMPLETED
|
|
505
|
-
: PlanState.
|
|
506
|
+
: PlanState.FAILED;
|
|
506
507
|
|
|
507
508
|
return { results, success: allDone };
|
|
508
509
|
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* mcp-prompt tests (previously untested) — the pure core that surfaces MCP
|
|
5
|
+
* server prompts as `/mcp__<server>__<prompt>` slash commands. Covers
|
|
6
|
+
* parseMcpPromptCommand (server/name split incl. `__` in names, JSON-object args
|
|
7
|
+
* vs non-JSON tail, reject non-mcp / missing parts), renderPromptMessages
|
|
8
|
+
* (text + embedded resource text, ignore binary, single vs array content),
|
|
9
|
+
* expandMcpPrompt (parse -> getPrompt -> render, null for non-mcp, throw when no
|
|
10
|
+
* client) and renderMcpSurface (overview / empty / no-client). No I/O.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, it, expect, vi } from "vitest";
|
|
14
|
+
import {
|
|
15
|
+
parseMcpPromptCommand,
|
|
16
|
+
renderPromptMessages,
|
|
17
|
+
expandMcpPrompt,
|
|
18
|
+
renderMcpSurface,
|
|
19
|
+
} from "../mcp-prompt.js";
|
|
20
|
+
|
|
21
|
+
describe("parseMcpPromptCommand", () => {
|
|
22
|
+
it("returns null for non-mcp lines", () => {
|
|
23
|
+
expect(parseMcpPromptCommand("hello")).toBe(null);
|
|
24
|
+
expect(parseMcpPromptCommand("/other__a__b")).toBe(null);
|
|
25
|
+
expect(parseMcpPromptCommand("")).toBe(null);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("parses server and prompt name with empty args", () => {
|
|
29
|
+
expect(parseMcpPromptCommand("/mcp__github__review")).toEqual({
|
|
30
|
+
server: "github",
|
|
31
|
+
name: "review",
|
|
32
|
+
args: {},
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("keeps '__' inside the prompt name", () => {
|
|
37
|
+
expect(parseMcpPromptCommand("/mcp__srv__deep__name").name).toBe(
|
|
38
|
+
"deep__name",
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("parses a trailing JSON object as args", () => {
|
|
43
|
+
expect(parseMcpPromptCommand('/mcp__s__p {"a":1,"b":"x"}').args).toEqual({
|
|
44
|
+
a: 1,
|
|
45
|
+
b: "x",
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("treats a non-JSON tail as { input: tail }", () => {
|
|
50
|
+
expect(parseMcpPromptCommand("/mcp__s__p just some text").args).toEqual({
|
|
51
|
+
input: "just some text",
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("treats a JSON array tail as { input } (not an object)", () => {
|
|
56
|
+
expect(parseMcpPromptCommand("/mcp__s__p [1,2]").args).toEqual({
|
|
57
|
+
input: "[1,2]",
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("returns null when server or prompt is missing", () => {
|
|
62
|
+
expect(parseMcpPromptCommand("/mcp__srv")).toBe(null); // < 3 parts
|
|
63
|
+
expect(parseMcpPromptCommand("/mcp____p")).toBe(null); // empty server
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("renderPromptMessages", () => {
|
|
68
|
+
it("returns '' when there are no messages", () => {
|
|
69
|
+
expect(renderPromptMessages(null)).toBe("");
|
|
70
|
+
expect(renderPromptMessages({ messages: [] })).toBe("");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("joins text blocks with blank lines", () => {
|
|
74
|
+
const r = renderPromptMessages({
|
|
75
|
+
messages: [
|
|
76
|
+
{ content: [{ type: "text", text: "one" }] },
|
|
77
|
+
{ content: [{ type: "text", text: "two" }] },
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
expect(r).toBe("one\n\ntwo");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("includes embedded resource text and ignores binary/unknown blocks", () => {
|
|
84
|
+
const r = renderPromptMessages({
|
|
85
|
+
messages: [
|
|
86
|
+
{
|
|
87
|
+
content: [
|
|
88
|
+
{ type: "text", text: "T" },
|
|
89
|
+
{ type: "resource", resource: { text: "R" } },
|
|
90
|
+
{ type: "image", data: "..." },
|
|
91
|
+
null,
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
expect(r).toBe("T\n\nR");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("handles content given as a single block (not an array)", () => {
|
|
100
|
+
const r = renderPromptMessages({
|
|
101
|
+
messages: [{ content: { type: "text", text: "solo" } }],
|
|
102
|
+
});
|
|
103
|
+
expect(r).toBe("solo");
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe("expandMcpPrompt", () => {
|
|
108
|
+
it("returns null for a non-mcp line", async () => {
|
|
109
|
+
expect(await expandMcpPrompt("hi", {})).toBe(null);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("throws when no MCP client is connected", async () => {
|
|
113
|
+
await expect(expandMcpPrompt("/mcp__s__p", null)).rejects.toThrow(
|
|
114
|
+
/No MCP servers/,
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("calls getPrompt with parsed args and renders the result", async () => {
|
|
119
|
+
const getPrompt = vi.fn(async () => ({
|
|
120
|
+
messages: [{ content: [{ type: "text", text: "rendered" }] }],
|
|
121
|
+
}));
|
|
122
|
+
const out = await expandMcpPrompt('/mcp__s__p {"k":1}', { getPrompt });
|
|
123
|
+
expect(getPrompt).toHaveBeenCalledWith("s", "p", { k: 1 });
|
|
124
|
+
expect(out).toBe("rendered");
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("renderMcpSurface", () => {
|
|
129
|
+
it("reports when no client is connected", () => {
|
|
130
|
+
expect(renderMcpSurface(null)).toMatch(/No MCP servers/);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("lists resources and prompts with counts", () => {
|
|
134
|
+
const surface = renderMcpSurface({
|
|
135
|
+
listResources: () => [{ uri: "file://x", server: "fs", name: "X" }],
|
|
136
|
+
listPrompts: () => [
|
|
137
|
+
{ server: "gh", name: "review", description: "code review" },
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
expect(surface).toContain("MCP resources (1):");
|
|
141
|
+
expect(surface).toContain("file://x [fs] — X");
|
|
142
|
+
expect(surface).toContain("MCP prompts (1):");
|
|
143
|
+
expect(surface).toContain("/mcp__gh__review — code review");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("notes when servers expose nothing", () => {
|
|
147
|
+
const surface = renderMcpSurface({
|
|
148
|
+
listResources: () => [],
|
|
149
|
+
listPrompts: () => [],
|
|
150
|
+
});
|
|
151
|
+
expect(surface).toContain(
|
|
152
|
+
"(connected servers expose no resources or prompts)",
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
});
|